bsnes/higan/sfc/ppu/ppu.cpp

229 lines
4.3 KiB
C++
Raw Normal View History

#include <sfc/sfc.hpp>
namespace SuperFamicom {
PPU ppu;
#include "video.cpp"
#include "memory.cpp"
#include "mmio.cpp"
#include "background/background.cpp"
#include "screen/screen.cpp"
#include "sprite/sprite.cpp"
#include "window/window.cpp"
#include "serialization.cpp"
PPU::PPU() :
bg1(*this, Background::ID::BG1),
bg2(*this, Background::ID::BG2),
bg3(*this, Background::ID::BG3),
bg4(*this, Background::ID::BG4),
sprite(*this),
window(*this),
screen(*this) {
Update to v096r07 release. byuu says: Changelog: - configuration files are now stored in localpath() instead of configpath() - Video gamma/saturation/luminance sliders are gone now, sorry - added Video Filter->Blur Emulation [1] - added Video Filter->Scanline Emulation [2] - improvements to GBA audio emulation (fixes Minish Cap) [Jonas Quinn] [1] For the Famicom, this does nothing. For the Super Famicom, this performs horizontal blending for proper pseudo-hires translucency. For the Game Boy, Game Boy Color, and Game Boy Advance, this performs interframe blending (each frame is the average of the current and previous frame), which is important for things like the GBVideoPlayer. [2] Right now, this only applies to the Super Famicom, but it'll come to the Famicom in the future. For the Super Famicom, this option doesn't just add scanlines, it simulates the phosphor decay that's visible in interlace mode. If you observe an interlaced game like RPM Racing on a real SNES, you'll notice that even on perfectly still screens, the image appears to shake. This option emulates that effect. Note 1: the buffering right now is a little sub-optimal, so there will be a slight speed hit with this new support. Since the core is now generating native ARGB8888 colors, it might as well call out to the interface to lock/unlock/refresh the video, that way it can render directly to the screen. Although ... that might not be such a hot idea, since the GBx interframe blending reads from the target buffer, and that tends to be a catastrophic option for performance. Note 2: the balanced and performance profiles for the SNES are completely busted again. This WIP took 6 1/2 hours, and I'm exhausted. Very much not looking forward to working on those, since those two have all kinds of fucked up speedup tricks for non-interlaced and/or non-hires video modes. Note 3: if you're on Windows and you saved your system folders somewhere else, now'd be a good time to move them to %localappdata%/higan
2016-01-15 10:06:51 +00:00
output = new uint32[512 * 512];
}
PPU::~PPU() {
Update to v096r07 release. byuu says: Changelog: - configuration files are now stored in localpath() instead of configpath() - Video gamma/saturation/luminance sliders are gone now, sorry - added Video Filter->Blur Emulation [1] - added Video Filter->Scanline Emulation [2] - improvements to GBA audio emulation (fixes Minish Cap) [Jonas Quinn] [1] For the Famicom, this does nothing. For the Super Famicom, this performs horizontal blending for proper pseudo-hires translucency. For the Game Boy, Game Boy Color, and Game Boy Advance, this performs interframe blending (each frame is the average of the current and previous frame), which is important for things like the GBVideoPlayer. [2] Right now, this only applies to the Super Famicom, but it'll come to the Famicom in the future. For the Super Famicom, this option doesn't just add scanlines, it simulates the phosphor decay that's visible in interlace mode. If you observe an interlaced game like RPM Racing on a real SNES, you'll notice that even on perfectly still screens, the image appears to shake. This option emulates that effect. Note 1: the buffering right now is a little sub-optimal, so there will be a slight speed hit with this new support. Since the core is now generating native ARGB8888 colors, it might as well call out to the interface to lock/unlock/refresh the video, that way it can render directly to the screen. Although ... that might not be such a hot idea, since the GBx interframe blending reads from the target buffer, and that tends to be a catastrophic option for performance. Note 2: the balanced and performance profiles for the SNES are completely busted again. This WIP took 6 1/2 hours, and I'm exhausted. Very much not looking forward to working on those, since those two have all kinds of fucked up speedup tricks for non-interlaced and/or non-hires video modes. Note 3: if you're on Windows and you saved your system folders somewhere else, now'd be a good time to move them to %localappdata%/higan
2016-01-15 10:06:51 +00:00
delete[] output;
}
auto PPU::step(uint clocks) -> void {
clock += clocks;
}
auto PPU::synchronizeCPU() -> void {
Update to v098r01 release. byuu says: Changelog: - SFC: balanced profile removed - SFC: performance profile removed - SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed - SFC: Coprocessor, Controller (and expansion port) shared Thread code merged to SFC::Cothread - Cothread here just means "Thread with CPU affinity" (couldn't think of a better name, sorry) - SFC: CPU now has vector<Thread*> coprocessors, peripherals; - this is the beginning of work to allow expansion port devices to be dynamically changed at run-time - ruby: all audio drivers default to 48000hz instead of 22050hz now if no frequency is assigned - note: the WASAPI driver can default to whatever the native frequency is; doesn't have to be 48000hz - tomoko: removed the ability to change the frequency from the UI (but it will display the frequency used) - tomoko: removed the timing settings panel - the goal is to work toward smooth video via adaptive sync - the model is broken by not being in control of the audio frequency anyway - it's further broken by PAL running at 50hz and WSC running at 75hz - it was always broken anyway by SNES interlace timing varying from progressive timing - higan: audio/ stub created (for now, it's just nall/dsp/ moved here and included as a header) - higan: video/ stub created - higan/GNUmakefile: now includes build rules for essential components (libco, emulator, audio, video) The audio changes are in preparation to merge wareya's awesome WASAPI work without the need for the nall/dsp resampler.
2016-04-09 03:40:12 +00:00
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
}
auto PPU::Enter() -> void {
while(true) scheduler.synchronize(), ppu.main();
}
auto PPU::main() -> void {
scanline();
addClocks(28);
bg1.begin();
bg2.begin();
bg3.begin();
bg4.begin();
if(vcounter() <= 239) {
for(int pixel = -7; pixel <= 255; pixel++) {
bg1.run(1);
bg2.run(1);
bg3.run(1);
bg4.run(1);
addClocks(2);
bg1.run(0);
bg2.run(0);
bg3.run(0);
bg4.run(0);
if(pixel >= 0) {
sprite.run();
window.run();
screen.run();
}
addClocks(2);
}
addClocks(14);
sprite.tilefetch();
} else {
addClocks(1052 + 14 + 136);
}
addClocks(lineclocks() - 28 - 1052 - 14 - 136);
}
auto PPU::addClocks(uint clocks) -> void {
clocks >>= 1;
while(clocks--) {
tick(2);
step(2);
synchronizeCPU();
}
}
auto PPU::power() -> void {
for(auto& n : vram) n = random(0x00);
for(auto& n : oam) n = random(0x00);
for(auto& n : cgram) n = random(0x00);
}
auto PPU::reset() -> void {
create(Enter, system.cpuFrequency());
PPUcounter::reset();
Update to v096r07 release. byuu says: Changelog: - configuration files are now stored in localpath() instead of configpath() - Video gamma/saturation/luminance sliders are gone now, sorry - added Video Filter->Blur Emulation [1] - added Video Filter->Scanline Emulation [2] - improvements to GBA audio emulation (fixes Minish Cap) [Jonas Quinn] [1] For the Famicom, this does nothing. For the Super Famicom, this performs horizontal blending for proper pseudo-hires translucency. For the Game Boy, Game Boy Color, and Game Boy Advance, this performs interframe blending (each frame is the average of the current and previous frame), which is important for things like the GBVideoPlayer. [2] Right now, this only applies to the Super Famicom, but it'll come to the Famicom in the future. For the Super Famicom, this option doesn't just add scanlines, it simulates the phosphor decay that's visible in interlace mode. If you observe an interlaced game like RPM Racing on a real SNES, you'll notice that even on perfectly still screens, the image appears to shake. This option emulates that effect. Note 1: the buffering right now is a little sub-optimal, so there will be a slight speed hit with this new support. Since the core is now generating native ARGB8888 colors, it might as well call out to the interface to lock/unlock/refresh the video, that way it can render directly to the screen. Although ... that might not be such a hot idea, since the GBx interframe blending reads from the target buffer, and that tends to be a catastrophic option for performance. Note 2: the balanced and performance profiles for the SNES are completely busted again. This WIP took 6 1/2 hours, and I'm exhausted. Very much not looking forward to working on those, since those two have all kinds of fucked up speedup tricks for non-interlaced and/or non-hires video modes. Note 3: if you're on Windows and you saved your system folders somewhere else, now'd be a good time to move them to %localappdata%/higan
2016-01-15 10:06:51 +00:00
memory::fill(output, 512 * 480 * sizeof(uint32));
Update to v098r03 release. byuu says: It took several hours, but I've rebuilt much of the SNES' bus memory mapping architecture. The new design unifies the cartridge string-based mapping ("00-3f,80-bf:8000-ffff") and internal bus.map calls. The map() function now has an accompanying unmap() function, and instead of a fixed 256 callbacks, it'll scan to find the first available slot. unmap() will free slots up when zero addresses reference a given slot. The controllers and expansion port are now both entirely dynamic. Instead of load/unload/power/reset, they only have the constructor (power/reset/load) and destructor (unload). What this means is you can now dynamically change even expansion port devices after the system is loaded. Note that this is incredibly dangerous and stupid, but ... oh well. The whole point of this was for 21fx. There's no way to change the expansion port device prior to loading a game, but if the 21fx isn't active, then the reset vector hijack won't work. Now you can load a 21fx game, change the expansion port device, and simply reset the system to active the device. The unification of design between controller port devices and expansion port devices is nice, and overall this results in a reduction of code (all of the Mapping stuff in Cartridge is gone, replaced with direct bus mapping.) And there's always the potential to expand this system more in the future now. The big missing feature right now is the ability to push/pop mappings. So if you look at how the 21fx does the reset vector, you might vomit a little bit. But ... it works. Also changed exit(0) to _exit(0) in the POSIX version of nall::execute. [The _exit(0) thing is an attempt to make higan not crash when it tries to launch icarus and it's not on $PATH. The theory is that higan forks, then the child tries to exec icarus and fails, so it exits, all the unique_ptrs clean up their resources and tell the X server to free things the parent process is still using. Calling _exit() prevents destructors from running, and seems to prevent the problem. -Ed.]
2016-04-09 10:21:18 +00:00
function<auto (uint24, uint8) -> uint8> reader{&PPU::read, this};
function<auto (uint24, uint8) -> void> writer{&PPU::write, this};
bus.map(reader, writer, "00-3f,80-bf:2100-213f");
regs.ppu1_mdr = random(0xff);
regs.ppu2_mdr = random(0xff);
regs.vram_readbuffer = random(0x0000);
regs.oam_latchdata = random(0x00);
regs.cgram_latchdata = random(0x00);
regs.bgofs_latchdata = random(0x00);
regs.mode7_latchdata = random(0x00);
regs.counters_latched = false;
regs.latch_hcounter = 0;
regs.latch_vcounter = 0;
regs.oam_iaddr = 0x0000;
regs.cgram_iaddr = 0x00;
//$2100 INIDISP
regs.display_disable = true;
regs.display_brightness = 0;
//$2102 OAMADDL
//$2103 OAMADDH
regs.oam_baseaddr = random(0x0000);
regs.oam_addr = random(0x0000);
regs.oam_priority = random(false);
//$2105 BGMODE
regs.bg3_priority = false;
regs.bgmode = 0;
//$210d BG1HOFS
regs.mode7_hoffset = random(0x0000);
//$210e BG1VOFS
regs.mode7_voffset = random(0x0000);
//$2115 VMAIN
regs.vram_incmode = random(1);
regs.vram_mapping = random(0);
regs.vram_incsize = 1;
//$2116 VMADDL
//$2117 VMADDH
regs.vram_addr = random(0x0000);
//$211a M7SEL
regs.mode7_repeat = random(0);
regs.mode7_vflip = random(false);
regs.mode7_hflip = random(false);
//$211b M7A
regs.m7a = random(0x0000);
//$211c M7B
regs.m7b = random(0x0000);
//$211d M7C
regs.m7c = random(0x0000);
//$211e M7D
regs.m7d = random(0x0000);
//$211f M7X
regs.m7x = random(0x0000);
//$2120 M7Y
regs.m7y = random(0x0000);
//$2121 CGADD
regs.cgram_addr = random(0x0000);
//$2133 SETINI
regs.mode7_extbg = random(false);
regs.pseudo_hires = random(false);
regs.overscan = false;
regs.interlace = false;
//$213c OPHCT
regs.hcounter = 0;
//$213d OPVCT
regs.vcounter = 0;
bg1.reset();
bg2.reset();
bg3.reset();
bg4.reset();
sprite.reset();
window.reset();
screen.reset();
video.reset();
frame();
}
auto PPU::scanline() -> void {
if(vcounter() == 0) {
frame();
bg1.frame();
bg2.frame();
bg3.frame();
bg4.frame();
}
bg1.scanline();
bg2.scanline();
bg3.scanline();
bg4.scanline();
sprite.scanline();
window.scanline();
screen.scanline();
if(vcounter() == 241) {
video.refresh();
scheduler.exit(Scheduler::Event::Frame);
}
}
auto PPU::frame() -> void {
sprite.frame();
display.interlace = regs.interlace;
display.overscan = regs.overscan;
}
}