From 7df9157abdf878eadff3e2d9ac165d092dc59dc9 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Fri, 3 Sep 2010 21:37:36 +1000 Subject: [PATCH] Update to v068r10 release. (there was no r09 release posted to the WIP thread) byuu says: It is feature-complete, but horizontal mosaic is less accurate. I have an idea for a mosaic color ring buffer to get it equally accurate, but I haven't implemented it yet. For now it's just a simple x & ~(mosaic >> 1) trick that is passable. Hires blending was left out, as it's more processor intensive and blargg's NTSC does a better job with that anyway. There's some OPT vertical positioning issues in the SNES Test Program's character test; Goodbye, Anthrox has some sort of fast CPU DMA issue; etc. Total speedup is a mere 13.5%. Not quite the 50% I wanted in the best case, but I'll take what I can get. 254->289fps in Zelda 3 on my E8400 now. There's another 15% hiding with blargg's SMP and 5-10% with blargg's fast DSP, but they lose too much accuracy. It'd put me at or below Snes9X accuracy, while still being 50% slower. SSE2 was performing worse this time, both on x86 and amd64, so I left that optimization off. So, barring a miracle, this is about the best it's going to get. --- .../alt/ppu-new/background/background.cpp | 137 +++++++++++++----- .../alt/ppu-new/background/background.hpp | 32 +++- bsnes/snes/alt/ppu-new/background/mode7.cpp | 101 +++++++++++++ bsnes/snes/alt/ppu-new/debugger/debugger.cpp | 7 + bsnes/snes/alt/ppu-new/debugger/debugger.hpp | 10 ++ bsnes/snes/alt/ppu-new/mmio/mmio.cpp | 12 +- bsnes/snes/alt/ppu-new/ppu.cpp | 11 +- bsnes/snes/alt/ppu-new/ppu.hpp | 7 +- bsnes/snes/alt/ppu-new/screen/screen.cpp | 69 +++++++-- bsnes/snes/alt/ppu-new/screen/screen.hpp | 14 +- bsnes/snes/alt/ppu-new/sprite/sprite.cpp | 9 +- bsnes/snes/alt/ppu-new/sprite/sprite.hpp | 2 +- bsnes/snes/snes.hpp | 2 +- 13 files changed, 342 insertions(+), 71 deletions(-) create mode 100755 bsnes/snes/alt/ppu-new/background/mode7.cpp create mode 100755 bsnes/snes/alt/ppu-new/debugger/debugger.cpp create mode 100755 bsnes/snes/alt/ppu-new/debugger/debugger.hpp diff --git a/bsnes/snes/alt/ppu-new/background/background.cpp b/bsnes/snes/alt/ppu-new/background/background.cpp index ba18b49c..1d48954c 100755 --- a/bsnes/snes/alt/ppu-new/background/background.cpp +++ b/bsnes/snes/alt/ppu-new/background/background.cpp @@ -1,71 +1,101 @@ #ifdef PPU_CPP -void PPU::Background::render() { - if(regs.mode == Mode::Inactive) return; - if(regs.mode == Mode::Mode7) return; - if(regs.main_enable == false && regs.sub_enable == false) return; +#include "mode7.cpp" - const unsigned opt_valid_bit = (id == ID::BG1 ? 0x2000 : id == ID::BG2 ? 0x4000 : 0x0000); - const unsigned bgpal_index = (self.regs.bgmode == 0 ? id << 5 : 0); +unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) { + unsigned tile_x = hoffset >> tile_width; + unsigned tile_y = voffset >> tile_height; - const unsigned pal_size = 2 << regs.mode; - const unsigned tile_mask = 0x0fff >> regs.mode; - const unsigned tiledata_index = regs.tiledata_addr >> (4 + regs.mode); + unsigned tile_pos = ((tile_y & 0x1f) << 5) + (tile_x & 0x1f); + if(tile_y & 0x20) tile_pos += scy; + if(tile_x & 0x20) tile_pos += scx; - const bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); - const signed width = !hires ? 256 : 512; + const unsigned tiledata_addr = regs.screen_addr + (tile_pos << 1); + return (memory::vram[tiledata_addr + 0] << 0) + (memory::vram[tiledata_addr + 1] << 8); +} - const unsigned tile_height = regs.tile_size ? 4 : 3; - const unsigned tile_width = hires ? 4 : tile_height; +void PPU::Background::offset_per_tile(unsigned x, unsigned &hoffset, unsigned &voffset) { + unsigned opt_x = (x + (hscroll & 7)), hval, vval; + if(opt_x >= 8) { + hval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0); + if(self.regs.bgmode != 4) + vval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8); - unsigned mask_x = (tile_height == 4 ? width << 1 : width); - unsigned mask_y = mask_x; + if(self.regs.bgmode == 4) { + if(hval & opt_valid_bit) { + hoffset = opt_x + (hval & ~7); + } else { + voffset = y + hval; + } + } else { + if(hval & opt_valid_bit) { + hoffset = opt_x + (hval & ~7); + } + if(vval & opt_valid_bit) { + voffset = y + vval; + } + } + } +} + +void PPU::Background::scanline() { + y = mosaic_table[regs.mosaic][self.vcounter()] + (regs.mosaic > 0); + hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); + width = !hires ? 256 : 512; + + tile_height = regs.tile_size ? 4 : 3; + tile_width = hires ? 4 : tile_height; + + mask_x = (tile_height == 4 ? width << 1 : width); + mask_y = mask_x; if(regs.screen_size & 1) mask_x <<= 1; if(regs.screen_size & 2) mask_y <<= 1; mask_x--; mask_y--; - unsigned scy = (regs.screen_size & 2 ? 32 << 5 : 0); - unsigned scx = (regs.screen_size & 1 ? 32 << 5 : 0); + scx = (regs.screen_size & 1 ? 32 << 5 : 0); + scy = (regs.screen_size & 2 ? 32 << 5 : 0); if(regs.screen_size == 3) scy <<= 1; +} - unsigned y = self.vcounter(); - unsigned hscroll = regs.hoffset; - unsigned vscroll = regs.voffset; +void PPU::Background::render() { + if(regs.mode == Mode::Inactive) return; + if(regs.main_enable == false && regs.sub_enable == false) return; + + if(regs.main_enable) window.render(0); + if(regs.sub_enable) window.render(1); + if(regs.mode == Mode::Mode7) return render_mode7(); + + const unsigned bgpal_index = (self.regs.bgmode == 0 ? id << 5 : 0); + const unsigned pal_size = 2 << regs.mode; + const unsigned tile_mask = 0x0fff >> regs.mode; + const unsigned tiledata_index = regs.tiledata_addr >> (4 + regs.mode); + + hscroll = regs.hoffset; + vscroll = regs.voffset; if(hires) { hscroll <<= 1; if(self.regs.interlace) y = (y << 1) + self.field(); } - unsigned hval, vval; unsigned tile_pri, tile_num; unsigned pal_index, pal_num; - unsigned hoffset, voffset, opt_x, col; + unsigned hoffset, voffset, col; bool mirror_x, mirror_y; const bool is_opt_mode = (self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6); const bool is_direct_color_mode = (self.screen.regs.direct_color == true && id == ID::BG1 && (self.regs.bgmode == 3 || self.regs.bgmode == 4)); - window.render(0); - window.render(1); - signed x = 0 - (hscroll & 7); while(x < width) { hoffset = x + hscroll; voffset = y + vscroll; - + if(is_opt_mode) offset_per_tile(x, hoffset, voffset); hoffset &= mask_x; voffset &= mask_y; - unsigned tile_x = hoffset >> tile_width; - unsigned tile_y = voffset >> tile_height; - unsigned tile_pos = ((tile_y & 0x1f) << 5) + (tile_x & 0x1f); - if(tile_y & 0x20) tile_pos += scy; - if(tile_x & 0x20) tile_pos += scx; - const unsigned tiledata_addr = regs.screen_addr + (tile_pos << 1); - - tile_num = (memory::vram[tiledata_addr + 0] << 0) + (memory::vram[tiledata_addr + 1] << 8); + tile_num = get_tile(hoffset, voffset); mirror_y = tile_num & 0x8000; mirror_x = tile_num & 0x4000; tile_pri = tile_num & 0x2000 ? regs.priority1 : regs.priority0; @@ -92,11 +122,26 @@ void PPU::Background::render() { tiledata += ((voffset & 7) * 8); for(unsigned n = 0; n < 8; n++) { - unsigned col = *tiledata++; - if(col && !(plot_x & 256)) { - unsigned color = self.screen.get_palette(pal_index + col); - if(regs.main_enable && !window.main[plot_x]) self.screen.output.plot_main(plot_x, color, tile_pri, id); - if(regs.sub_enable && !window.sub[plot_x]) self.screen.output.plot_sub(plot_x, color, tile_pri, id); + unsigned col = tiledata[n & regs.mosaic_mask]; + if(col && !(plot_x & width)) { + unsigned color; + if(is_direct_color_mode) { + color = self.screen.get_direct_color(pal_num, col); + } else { + color = self.screen.get_palette(pal_index + col); + } + + if(hires == false) { + if(regs.main_enable && !window.main[plot_x]) self.screen.output.plot_main(plot_x, color, tile_pri, id); + if(regs.sub_enable && !window.sub[plot_x]) self.screen.output.plot_sub(plot_x, color, tile_pri, id); + } else { + signed half_x = plot_x >> 1; + if(plot_x & 1) { + if(regs.main_enable && !window.main[half_x]) self.screen.output.plot_main(half_x, color, tile_pri, id); + } else { + if(regs.sub_enable && !window.sub[half_x]) self.screen.output.plot_sub(half_x, color, tile_pri, id); + } + } } plot_x += step; } @@ -106,6 +151,20 @@ void PPU::Background::render() { } PPU::Background::Background(PPU &self, unsigned id) : self(self), id(id) { + opt_valid_bit = (id == ID::BG1 ? 0x2000 : id == ID::BG2 ? 0x4000 : 0x0000); + + mosaic_table = new uint16*[16]; + for(unsigned m = 0; m < 16; m++) { + mosaic_table[m] = new uint16[4096]; + for(unsigned x = 0; x < 4096; x++) { + mosaic_table[m][x] = (x / (m + 1)) * (m + 1); + } + } +} + +PPU::Background::~Background() { + for(unsigned m = 0; m < 16; m++) delete[] mosaic_table[m]; + delete[] mosaic_table; } #endif diff --git a/bsnes/snes/alt/ppu-new/background/background.hpp b/bsnes/snes/alt/ppu-new/background/background.hpp index 3a2d690b..3289e1dc 100755 --- a/bsnes/snes/alt/ppu-new/background/background.hpp +++ b/bsnes/snes/alt/ppu-new/background/background.hpp @@ -11,6 +11,7 @@ class Background { bool tile_size; unsigned mosaic; + unsigned mosaic_mask; unsigned screen_addr; unsigned screen_size; @@ -23,12 +24,37 @@ class Background { bool sub_enable; } regs; - LayerWindow window; - - void render(); + uint16 **mosaic_table; const unsigned id; + unsigned opt_valid_bit; + + unsigned y; + bool hires; + signed width; + + unsigned tile_width; + unsigned tile_height; + + unsigned mask_x; + unsigned mask_y; + + unsigned scx; + unsigned scy; + + unsigned hscroll; + unsigned vscroll; + + LayerWindow window; + + alwaysinline unsigned get_tile(unsigned hoffset, unsigned voffset); + void offset_per_tile(unsigned x, unsigned &hoffset, unsigned &voffset); + void scanline(); + void render(); + void render_mode7(); + Background(PPU &self, unsigned id); + ~Background(); PPU &self; friend class PPU; diff --git a/bsnes/snes/alt/ppu-new/background/mode7.cpp b/bsnes/snes/alt/ppu-new/background/mode7.cpp new file mode 100755 index 00000000..e83b1139 --- /dev/null +++ b/bsnes/snes/alt/ppu-new/background/mode7.cpp @@ -0,0 +1,101 @@ +#ifdef PPU_CPP + +#define Clip(x) (((x) & 0x2000) ? ((x) | ~0x03ff) : ((x) & 0x03ff)) + +void PPU::Background::render_mode7() { + signed px, py; + signed tx, ty, tile, palette; + + signed a = sclip<16>(self.regs.m7a); + signed b = sclip<16>(self.regs.m7b); + signed c = sclip<16>(self.regs.m7c); + signed d = sclip<16>(self.regs.m7d); + + signed cx = sclip<13>(self.regs.m7x); + signed cy = sclip<13>(self.regs.m7y); + signed hofs = sclip<13>(self.regs.mode7_hoffset); + signed vofs = sclip<13>(self.regs.mode7_voffset); + + signed y = (self.regs.mode7_vflip == false ? self.vcounter() : 255 - self.vcounter()); + + uint16 *mosaic_x, *mosaic_y; + if(id == ID::BG1) { + mosaic_x = mosaic_table[self.bg1.regs.mosaic]; + mosaic_y = mosaic_table[self.bg1.regs.mosaic]; + } else { + mosaic_x = mosaic_table[self.bg2.regs.mosaic]; + mosaic_y = mosaic_table[self.bg1.regs.mosaic]; + } + + signed psx = ((a * Clip(hofs - cx)) & ~63) + ((b * Clip(vofs - cy)) & ~63) + ((b * mosaic_y[y]) & ~63) + (cx << 8); + signed psy = ((c * Clip(hofs - cx)) & ~63) + ((d * Clip(vofs - cy)) & ~63) + ((d * mosaic_y[y]) & ~63) + (cy << 8); + for(signed x = 0; x < 256; x++) { + px = (psx + (a * mosaic_x[x])) >> 8; + py = (psy + (c * mosaic_x[x])) >> 8; + + switch(self.regs.mode7_repeat) { + case 0: case 1: { + px &= 1023; + py &= 1023; + tx = ((px >> 3) & 127); + ty = ((py >> 3) & 127); + tile = memory::vram[(ty * 128 + tx) << 1]; + palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + break; + } + + case 2: { + if(px < 0 || px > 1023 || py < 0 || py > 1023) { + palette = 0; + } else { + px &= 1023; + py &= 1023; + tx = ((px >> 3) & 127); + ty = ((py >> 3) & 127); + tile = memory::vram[(ty * 128 + tx) << 1]; + palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + } + break; + } + + case 3: { + if(px < 0 || px > 1023 || py < 0 || py > 1023) { + tile = 0; + } else { + px &= 1023; + py &= 1023; + tx = ((px >> 3) & 127); + ty = ((py >> 3) & 127); + tile = memory::vram[(ty * 128 + tx) << 1]; + } + palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + break; + } + } + + unsigned priority; + if(id == ID::BG1) { + priority = regs.priority0; + } else { + priority = (palette & 0x80 ? regs.priority1 : regs.priority0); + palette &= 0x7f; + } + + if(palette == 0) continue; + unsigned plot_x = (self.regs.mode7_hflip == false ? x : 255 - x); + + unsigned color; + if(self.screen.regs.direct_color && id == ID::BG1) { + color = self.screen.get_direct_color(0, palette); + } else { + color = self.screen.get_palette(palette); + } + + if(regs.main_enable && !window.main[plot_x]) self.screen.output.plot_main(plot_x, color, priority, id); + if(regs.sub_enable && !window.sub[plot_x]) self.screen.output.plot_sub(plot_x, color, priority, id); + } +} + +#undef Clip + +#endif diff --git a/bsnes/snes/alt/ppu-new/debugger/debugger.cpp b/bsnes/snes/alt/ppu-new/debugger/debugger.cpp new file mode 100755 index 00000000..c1a988c4 --- /dev/null +++ b/bsnes/snes/alt/ppu-new/debugger/debugger.cpp @@ -0,0 +1,7 @@ +#ifdef PPU_CPP + +bool PPUDebugger::property(unsigned id, string &name, string &value) { + return false; +} + +#endif diff --git a/bsnes/snes/alt/ppu-new/debugger/debugger.hpp b/bsnes/snes/alt/ppu-new/debugger/debugger.hpp new file mode 100755 index 00000000..d2e3d913 --- /dev/null +++ b/bsnes/snes/alt/ppu-new/debugger/debugger.hpp @@ -0,0 +1,10 @@ +class PPUDebugger : public PPU, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + bool bg1_enabled[2]; + bool bg2_enabled[2]; + bool bg3_enabled[2]; + bool bg4_enabled[2]; + bool oam_enabled[4]; +}; diff --git a/bsnes/snes/alt/ppu-new/mmio/mmio.cpp b/bsnes/snes/alt/ppu-new/mmio/mmio.cpp index 59aaf6ba..9a1de202 100755 --- a/bsnes/snes/alt/ppu-new/mmio/mmio.cpp +++ b/bsnes/snes/alt/ppu-new/mmio/mmio.cpp @@ -8,7 +8,7 @@ void PPU::latch_counters() { bool PPU::interlace() const { return regs.interlace; } bool PPU::overscan() const { return regs.overscan; } -bool PPU::hires() const { return regs.pseudo_hires || (regs.bgmode == 5 || regs.bgmode == 6); } +bool PPU::hires() const { return regs.pseudo_hires || regs.bgmode == 5 || regs.bgmode == 6; } uint16 PPU::get_vram_addr() { uint16 addr = regs.vram_addr; @@ -341,6 +341,10 @@ void PPU::mmio_write(unsigned addr, uint8 data) { bg3.regs.mosaic = (data & 0x04 ? mosaic_size : 0); bg2.regs.mosaic = (data & 0x02 ? mosaic_size : 0); bg1.regs.mosaic = (data & 0x01 ? mosaic_size : 0); + bg4.regs.mosaic_mask = ~(bg4.regs.mosaic >> 1); + bg3.regs.mosaic_mask = ~(bg3.regs.mosaic >> 1); + bg2.regs.mosaic_mask = ~(bg2.regs.mosaic >> 1); + bg1.regs.mosaic_mask = ~(bg1.regs.mosaic >> 1); return; } @@ -527,7 +531,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) { regs.cgram_latchdata = data; } else { cgram_write((regs.cgram_addr & ~1) + 0, regs.cgram_latchdata); - cgram_write((regs.cgram_addr & ~1) + 1, data); + cgram_write((regs.cgram_addr & ~1) + 1, data & 0x7f); } regs.cgram_addr = (regs.cgram_addr + 1) & 0x01ff; return; @@ -650,7 +654,8 @@ void PPU::mmio_write(unsigned addr, uint8 data) { case 0x2131: { //CGADDSUB screen.regs.color_mode = data & 0x80; screen.regs.color_halve = data & 0x40; - screen.regs.color_enable[5] = data & 0x20; + screen.regs.color_enable[6] = data & 0x20; + screen.regs.color_enable[5] = data & 0x10; screen.regs.color_enable[4] = data & 0x10; screen.regs.color_enable[3] = data & 0x08; screen.regs.color_enable[2] = data & 0x04; @@ -860,6 +865,7 @@ void PPU::mmio_reset() { //$2131 screen.regs.color_mode = 0; screen.regs.color_halve = 0; + screen.regs.color_enable[6] = 0; screen.regs.color_enable[5] = 0; screen.regs.color_enable[4] = 0; screen.regs.color_enable[3] = 0; diff --git a/bsnes/snes/alt/ppu-new/ppu.cpp b/bsnes/snes/alt/ppu-new/ppu.cpp index 5812a355..9372f4a3 100755 --- a/bsnes/snes/alt/ppu-new/ppu.cpp +++ b/bsnes/snes/alt/ppu-new/ppu.cpp @@ -3,7 +3,12 @@ #define PPU_CPP namespace SNES { -PPU ppu; +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + PPUDebugger ppu; +#else + PPU ppu; +#endif #include "mmio/mmio.cpp" #include "window/window.cpp" @@ -52,6 +57,10 @@ void PPU::add_clocks(unsigned clocks) { void PPU::render_scanline() { if(regs.display_disable) return screen.render_black(); + bg1.scanline(); + bg2.scanline(); + bg3.scanline(); + bg4.scanline(); screen.scanline(); bg1.render(); bg2.render(); diff --git a/bsnes/snes/alt/ppu-new/ppu.hpp b/bsnes/snes/alt/ppu-new/ppu.hpp index e4072ef9..63d6cc77 100755 --- a/bsnes/snes/alt/ppu-new/ppu.hpp +++ b/bsnes/snes/alt/ppu-new/ppu.hpp @@ -54,4 +54,9 @@ private: friend class Video; }; -extern PPU ppu; +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern PPUDebugger ppu; +#else + extern PPU ppu; +#endif diff --git a/bsnes/snes/alt/ppu-new/screen/screen.cpp b/bsnes/snes/alt/ppu-new/screen/screen.cpp index e15458a9..11c41d14 100755 --- a/bsnes/snes/alt/ppu-new/screen/screen.cpp +++ b/bsnes/snes/alt/ppu-new/screen/screen.cpp @@ -10,6 +10,12 @@ unsigned PPU::Screen::get_palette(unsigned color) { #endif } +unsigned PPU::Screen::get_direct_color(unsigned p, unsigned t) { + return ((t & 7) << 2) | ((p & 1) << 1) | + (((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) | + ((t >> 6) << 13) | ((p >> 2) << 12); +} + uint16 PPU::Screen::addsub(unsigned x, unsigned y, bool halve) { if(!regs.color_mode) { if(!halve) { @@ -31,16 +37,18 @@ uint16 PPU::Screen::addsub(unsigned x, unsigned y, bool halve) { } void PPU::Screen::scanline() { - unsigned color = get_palette(0); + unsigned main_color = get_palette(0); + unsigned sub_color = (self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6) + ? regs.color : main_color; for(unsigned x = 0; x < 256; x++) { - output.main[x].color = color; + output.main[x].color = main_color; output.main[x].priority = 0; - output.main[x].source = 5; + output.main[x].source = 6; - output.sub[x].color = regs.color; + output.sub[x].color = sub_color; output.sub[x].priority = 0; - output.sub[x].source = 5; + output.sub[x].source = 6; } window.render(0); @@ -49,15 +57,16 @@ void PPU::Screen::scanline() { void PPU::Screen::render_black() { uint16 *data = self.output + self.vcounter() * 1024; + if(self.interlace() && self.field()) data += 512; memset(data, 0, self.display.width << 1); } uint16 PPU::Screen::get_pixel_main(unsigned x) { - auto &main = output.main[x]; - auto &sub = output.sub[x]; + auto main = output.main[x]; + auto sub = output.sub[x]; if(!regs.addsub_mode) { - sub.source = 5; + sub.source = 6; sub.color = regs.color; } @@ -68,10 +77,37 @@ uint16 PPU::Screen::get_pixel_main(unsigned x) { main.color = 0x0000; } - if(regs.color_enable[main.source] && window.sub[x]) { + if(main.source != 5 && regs.color_enable[main.source] && window.sub[x]) { bool halve = false; if(regs.color_halve && window.main[x]) { - if(!regs.addsub_mode || sub.source != 5) halve = true; + if(!regs.addsub_mode || sub.source != 6) halve = true; + } + return addsub(main.color, sub.color, halve); + } + + return main.color; +} + +uint16 PPU::Screen::get_pixel_sub(unsigned x) { + auto main = output.sub[x]; + auto sub = output.main[x]; + + if(!regs.addsub_mode) { + sub.source = 6; + sub.color = regs.color; + } + + if(!window.main[x]) { + if(!window.sub[x]) { + return 0x0000; + } + main.color = 0x0000; + } + + if(main.source != 5 && regs.color_enable[main.source] && window.sub[x]) { + bool halve = false; + if(regs.color_halve && window.main[x]) { + if(!regs.addsub_mode || sub.source != 6) halve = true; } return addsub(main.color, sub.color, halve); } @@ -81,9 +117,18 @@ uint16 PPU::Screen::get_pixel_main(unsigned x) { void PPU::Screen::render() { uint16 *data = self.output + self.vcounter() * 1024; + if(self.interlace() && self.field()) data += 512; uint16 *light = light_table[self.regs.display_brightness]; - for(unsigned i = 0; i < 256; i++) { - data[i] = light[get_pixel_main(i)]; + + if(!self.regs.pseudo_hires && self.regs.bgmode != 5 && self.regs.bgmode != 6) { + for(unsigned i = 0; i < 256; i++) { + data[i] = light[get_pixel_main(i)]; + } + } else { + for(unsigned i = 0; i < 256; i++) { + *data++ = light[get_pixel_sub(i)]; + *data++ = light[get_pixel_main(i)]; + } } } diff --git a/bsnes/snes/alt/ppu-new/screen/screen.hpp b/bsnes/snes/alt/ppu-new/screen/screen.hpp index ad7000e1..0ba92a43 100755 --- a/bsnes/snes/alt/ppu-new/screen/screen.hpp +++ b/bsnes/snes/alt/ppu-new/screen/screen.hpp @@ -5,7 +5,7 @@ class Screen { bool color_mode; bool color_halve; - bool color_enable[6]; + bool color_enable[7]; unsigned color_b; unsigned color_g; @@ -20,18 +20,20 @@ class Screen { unsigned source; } main[256], sub[256]; - void plot_main(unsigned x, unsigned color, unsigned priority, unsigned source); - void plot_sub(unsigned x, unsigned color, unsigned priority, unsigned source); + alwaysinline void plot_main(unsigned x, unsigned color, unsigned priority, unsigned source); + alwaysinline void plot_sub(unsigned x, unsigned color, unsigned priority, unsigned source); } output; ColorWindow window; uint16 **light_table; - unsigned get_palette(unsigned color); - uint16 addsub(unsigned x, unsigned y, bool halve); + alwaysinline unsigned get_palette(unsigned color); + unsigned get_direct_color(unsigned palette, unsigned tile); + alwaysinline uint16 addsub(unsigned x, unsigned y, bool halve); void scanline(); void render_black(); - uint16 get_pixel_main(unsigned x); + alwaysinline uint16 get_pixel_main(unsigned x); + alwaysinline uint16 get_pixel_sub(unsigned x); void render(); Screen(PPU &self); ~Screen(); diff --git a/bsnes/snes/alt/ppu-new/sprite/sprite.cpp b/bsnes/snes/alt/ppu-new/sprite/sprite.cpp index be4ff01c..40450d2c 100755 --- a/bsnes/snes/alt/ppu-new/sprite/sprite.cpp +++ b/bsnes/snes/alt/ppu-new/sprite/sprite.cpp @@ -160,16 +160,17 @@ void PPU::Sprite::render() { } } - window.render(0); - window.render(1); + if(regs.main_enable) window.render(0); + if(regs.sub_enable) window.render(1); const unsigned priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 }; for(unsigned x = 0; x < 256; x++) { if(output.priority[x] == 0xff) continue; unsigned priority = priority_table[output.priority[x]]; + unsigned palette = output.palette[x]; unsigned color = self.screen.get_palette(output.palette[x]); - if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, color, priority, 4); - if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, color, priority, 4); + if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, color, priority, 4 + (palette < 192)); + if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, color, priority, 4 + (palette < 192)); } } diff --git a/bsnes/snes/alt/ppu-new/sprite/sprite.hpp b/bsnes/snes/alt/ppu-new/sprite/sprite.hpp index 4ca164bf..279386f7 100755 --- a/bsnes/snes/alt/ppu-new/sprite/sprite.hpp +++ b/bsnes/snes/alt/ppu-new/sprite/sprite.hpp @@ -55,7 +55,7 @@ class Sprite { void update_list(unsigned addr, uint8 data); void address_reset(); void set_first(); - bool on_scanline(unsigned sprite); + alwaysinline bool on_scanline(unsigned sprite); void render(); Sprite(PPU &self); diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 234db8e8..d5498e40 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "068.08"; + static const char Version[] = "068.10"; static const unsigned SerializerVersion = 13; } }