mirror of
https://github.com/devinacker/bsnes-plus.git
synced 2025-04-02 10:52:46 -04:00
- don't clear the display when toggling fullscreen - clear the overscan area when disabling overscan (for PAL window sizes) - always actively draw to the display even when no cart is loaded, rather than relying on the blank canvas widget to always get drawn correctly - properly clear some video drivers' buffer (e.g. OpenGL) on startup
168 lines
3.2 KiB
C++
168 lines
3.2 KiB
C++
#include <snes.hpp>
|
|
|
|
#define PPU_CPP
|
|
namespace SNES {
|
|
|
|
#if defined(DEBUGGER)
|
|
#include "debugger/debugger.cpp"
|
|
PPUDebugger ppu;
|
|
#else
|
|
PPU ppu;
|
|
#endif
|
|
|
|
#include "background/background.cpp"
|
|
#include "mmio/mmio.cpp"
|
|
#include "screen/screen.cpp"
|
|
#include "sprite/sprite.cpp"
|
|
#include "window/window.cpp"
|
|
#include "serialization.cpp"
|
|
|
|
void PPU::step(unsigned clocks) {
|
|
clock += clocks;
|
|
}
|
|
|
|
void PPU::synchronize_cpu() {
|
|
if(CPU::Threaded == true) {
|
|
if(clock >= 0) scheduler.resume(cpu.thread);
|
|
} else {
|
|
while(clock >= 0) cpu.enter();
|
|
}
|
|
}
|
|
|
|
bool PPU::mosaic_enable() const {
|
|
return bg1.regs.mosaic || bg2.regs.mosaic || bg3.regs.mosaic || bg4.regs.mosaic;
|
|
}
|
|
|
|
unsigned PPU::mosaic_vcounter() const {
|
|
return regs.mosaic_size - regs.mosaic_vcounter;
|
|
}
|
|
|
|
void PPU::Enter() { ppu.enter(); }
|
|
|
|
void PPU::enter() {
|
|
while(true) {
|
|
scheduler.synchronize();
|
|
|
|
scanline();
|
|
add_clocks(28);
|
|
|
|
if(vcounter() <= (!regs.overscan ? 224 : 239)) {
|
|
for(signed pixel = -7; pixel <= 255; pixel++) {
|
|
bg1.run(1);
|
|
bg2.run(1);
|
|
bg3.run(1);
|
|
bg4.run(1);
|
|
add_clocks(2);
|
|
|
|
bg1.run(0);
|
|
bg2.run(0);
|
|
bg3.run(0);
|
|
bg4.run(0);
|
|
if(pixel >= 0) {
|
|
oam.run();
|
|
window.run();
|
|
screen.run();
|
|
}
|
|
add_clocks(2);
|
|
}
|
|
|
|
add_clocks(14 + 34*2);
|
|
oam.tilefetch();
|
|
}
|
|
|
|
add_clocks(lineclocks() - hcounter());
|
|
}
|
|
}
|
|
|
|
void PPU::add_clocks(unsigned clocks) {
|
|
clocks >>= 1;
|
|
while(clocks--) {
|
|
tick(2);
|
|
step(2);
|
|
synchronize_cpu();
|
|
}
|
|
}
|
|
|
|
void PPU::power() {
|
|
ppu1_version = config().ppu1.version;
|
|
ppu2_version = config().ppu2.version;
|
|
|
|
for(unsigned i = 0; i < memory::vram.size(); i++) {
|
|
memory::vram.write(i, random(0));
|
|
}
|
|
for(unsigned i = 0; i < memory::cgram.size(); i++) {
|
|
memory::cgram.write(i, random(0));
|
|
}
|
|
memset(memory::oam.data(), 0x00, memory::oam.size());
|
|
|
|
reset();
|
|
}
|
|
|
|
void PPU::reset() {
|
|
create(Enter, system.cpu_frequency());
|
|
PPUcounter::reset();
|
|
memset(surface, 0, 512 * 512 * sizeof(uint16));
|
|
|
|
mmio_reset();
|
|
bg1.reset();
|
|
bg2.reset();
|
|
bg3.reset();
|
|
bg4.reset();
|
|
oam.reset();
|
|
window.reset();
|
|
screen.reset();
|
|
|
|
frame();
|
|
}
|
|
|
|
void PPU::scanline() {
|
|
if(vcounter() == 0) {
|
|
frame();
|
|
bg1.frame();
|
|
bg2.frame();
|
|
bg3.frame();
|
|
bg4.frame();
|
|
}
|
|
|
|
if(vcounter() == 1) {
|
|
regs.mosaic_vcounter = mosaic_enable() ? regs.mosaic_size + 1 : 0;
|
|
}
|
|
if(regs.mosaic_vcounter && !--regs.mosaic_vcounter) {
|
|
regs.mosaic_vcounter = mosaic_enable() ? regs.mosaic_size : 0;
|
|
}
|
|
bg1.scanline();
|
|
bg2.scanline();
|
|
bg3.scanline();
|
|
bg4.scanline();
|
|
oam.scanline();
|
|
window.scanline();
|
|
screen.scanline();
|
|
}
|
|
|
|
void PPU::frame() {
|
|
system.frame();
|
|
oam.frame();
|
|
|
|
display.interlace = regs.interlace;
|
|
if (display.overscan && !regs.overscan)
|
|
memset(output + 225 * 1024, 0, 15 * 1024 * sizeof(uint16));
|
|
display.overscan = regs.overscan;
|
|
}
|
|
|
|
PPU::PPU() :
|
|
bg1(*this, Background::ID::BG1),
|
|
bg2(*this, Background::ID::BG2),
|
|
bg3(*this, Background::ID::BG3),
|
|
bg4(*this, Background::ID::BG4),
|
|
oam(*this),
|
|
window(*this),
|
|
screen(*this) {
|
|
surface = new uint16[512 * 512];
|
|
output = surface + 16 * 512;
|
|
}
|
|
|
|
PPU::~PPU() {
|
|
delete[] surface;
|
|
}
|
|
|
|
}
|