bsnes/higan/sfc/ppu-fast/ppu.hpp

315 lines
7.3 KiB
C++
Raw Normal View History

//performance-focused, scanline-based, parallelized implementation of PPU
//limitations:
//* mid-scanline effects not support
//* vertical mosaic coordinates are not exact
//* (hardware-mod) 128KB VRAM mode not supported
#define PPU PPUfast
#define ppu ppufast
struct PPU : Thread, PPUcounter {
Update to v106r42 release. byuu says: Changelog: - emulator: added `Thread::setHandle(cothread_t)` - icarus: added special heuristics support for the Tengai Maykou Zero fan translation - board identifier is: EXSPC7110-RAM-EPSONRTC (match on SPC7110 + ROM size=56mbit) - board ROM contents are: 8mbit program, 40mbit data, 8mbit expansion (sizes are fixed) - bsnes: show messages on game load, unload, and reset - bsnes: added support for BS Memory and Sufami Turbo games - bsnes: added support for region selection (Auto [default], NTSC, PAL) - bsnes: correct presentation window size from 223/239 to 224/240 - bsnes: add SA-1 internal RAM on cartridges with BS Memory slot - bsnes: fixed recovery state to store inside .bsz archive - bsnes: added support for custom manifests in both game pak and game ROM modes - bsnes: added icarus game database support (manifest → database → heuristics) - bsnes: added flexible SuperFX overclocking - bsnes: added IPS and BPS soft-patching support to all ROM types (sfc,smc,gb,gbc,bs,st) - can load patches inside of ZIP archives (matches first “.ips” or “.bps” file) - bsnes/ppu: cache interlace/overscan/vdisp (277 → 291fps with fast PPU) - hiro/Windows: faster painting of Label widget on expose - hiro/Windows: immediately apply LineEdit::setBackgroundColor changes - hiro/Qt: inherit Window backgroundColor when one is not assigned to Label Errata: - sfc/ppu-fast: remove `renderMode7Hires()` function (the body isn't in the codebase) - bsnes: advanced note label should probably use a lighter text color and/or smaller font size instead of italics I didn't test the soft-patching at all, as I don't have any patches on my dev box. If anyone wants to test, that'd be great. The Tengai Makyou Zero fan translation would be a great test case.
2018-06-26 03:17:26 +00:00
alwaysinline auto interlace() const -> bool;
alwaysinline auto overscan() const -> bool;
alwaysinline auto vdisp() const -> uint;
alwaysinline auto hires() const -> bool;
//ppu.cpp
PPU();
~PPU();
static auto Enter() -> void;
alwaysinline auto step(uint clocks) -> void;
auto main() -> void;
auto scanline() -> void;
auto refresh() -> void;
auto load(Markup::Node) -> bool;
auto power(bool reset) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
public:
struct Source { enum : uint { BG1, BG2, BG3, BG4, OBJ1, OBJ2, COL }; };
struct TileMode { enum : uint { BPP2, BPP4, BPP8, Mode7, Inactive }; };
struct ScreenMode { enum : uint { Above, Below }; };
struct Latch {
//serialization.cpp
auto serialize(serializer&) -> void;
uint1 interlace;
uint1 overscan;
uint1 hires;
uint16 vram;
uint8 oam;
uint8 cgram;
uint10 oamAddress;
uint8 cgramAddress;
uint8 mode7;
uint1 counters;
uint1 hcounter; //hdot
uint1 vcounter;
struct PPU {
//serialization.cpp
auto serialize(serializer&) -> void;
uint8 mdr;
uint8 bgofs;
} ppu1, ppu2;
};
struct IO {
//serialization.cpp
auto serialize(serializer&) -> void;
uint1 displayDisable;
uint4 displayBrightness;
uint10 oamBaseAddress;
uint10 oamAddress;
uint1 oamPriority;
uint1 bgPriority;
uint3 bgMode;
uint4 mosaicSize;
uint1 vramIncrementMode;
uint2 vramMapping;
uint8 vramIncrementSize;
uint16 vramAddress;
uint8 cgramAddress;
uint1 cgramAddressLatch;
uint9 hcounter; //hdot
uint9 vcounter;
uint1 interlace;
uint1 overscan;
uint1 pseudoHires;
uint1 extbg;
struct Mode7 {
//serialization.cpp
auto serialize(serializer&) -> void;
uint1 hflip;
uint1 vflip;
uint2 repeat;
uint16 a;
uint16 b;
uint16 c;
uint16 d;
uint16 x;
uint16 y;
uint16 hoffset;
uint16 voffset;
} mode7;
struct Window {
//serialization.cpp
auto serialize(serializer&) -> void;
uint8 oneLeft;
uint8 oneRight;
uint8 twoLeft;
uint8 twoRight;
} window;
struct WindowLayer {
//serialization.cpp
auto serialize(serializer&) -> void;
uint1 oneEnable;
uint1 oneInvert;
uint1 twoEnable;
uint1 twoInvert;
uint2 mask;
uint1 aboveEnable;
uint1 belowEnable;
};
struct WindowColor {
//serialization.cpp
auto serialize(serializer&) -> void;
uint1 oneEnable;
uint1 oneInvert;
uint1 twoEnable;
uint1 twoInvert;
uint2 mask;
uint2 aboveMask;
uint2 belowMask;
};
struct Background {
//serialization.cpp
auto serialize(serializer&) -> void;
WindowLayer window;
uint1 aboveEnable;
uint1 belowEnable;
uint1 mosaicEnable;
uint15 tiledataAddress;
uint15 screenAddress;
uint2 screenSize;
uint1 tileSize;
uint16 hoffset;
uint16 voffset;
uint3 tileMode;
array<uint4[2]> priority;
} bg1, bg2, bg3, bg4;
struct Object {
//serialization.cpp
auto serialize(serializer&) -> void;
WindowLayer window;
uint1 aboveEnable;
uint1 belowEnable;
uint1 interlace;
uint3 baseSize;
uint2 nameselect;
uint15 tiledataAddress;
uint7 first;
uint1 rangeOver;
uint1 timeOver;
array<uint4[4]> priority;
} obj;
struct Color {
//serialization.cpp
auto serialize(serializer&) -> void;
WindowColor window;
array<uint1[7]> enable;
uint1 directColor;
uint1 blendMode; //0 = fixed; 1 = pixel
uint1 halve;
uint1 mathMode; //0 = add; 1 = sub
uint15 fixedColor;
} col;
};
struct Object {
//serialization.cpp
auto serialize(serializer&) -> void;
uint9 x;
uint8 y;
uint8 character;
uint1 nameselect;
uint1 vflip;
uint1 hflip;
uint2 priority;
uint3 palette;
uint1 size;
};
struct ObjectItem {
uint1 valid;
uint7 index;
uint8 width;
uint8 height;
};
struct ObjectTile {
uint1 valid;
uint9 x;
uint8 y;
uint2 priority;
uint8 palette;
uint1 hflip;
uint11 number;
};
struct Pixel {
uint source;
uint priority;
uint color;
};
//io.cpp
auto latchCounters() -> void;
alwaysinline auto vramAddress() const -> uint15;
alwaysinline auto readVRAM() -> uint16;
alwaysinline auto writeVRAM(uint1 byte, uint8 data) -> void;
alwaysinline auto updateTiledata(uint15 address) -> void;
alwaysinline auto readOAM(uint10 address) -> uint8;
alwaysinline auto writeOAM(uint10 address, uint8 data) -> void;
alwaysinline auto readCGRAM(uint1 byte, uint8 address) -> uint8;
alwaysinline auto writeCGRAM(uint8 address, uint15 data) -> void;
auto readIO(uint24 address, uint8 data) -> uint8;
auto writeIO(uint24 address, uint8 data) -> void;
auto updateVideoMode() -> void;
//object.cpp
auto oamAddressReset() -> void;
auto oamSetFirstObject() -> void;
auto readObject(uint10 address) -> uint8;
auto writeObject(uint10 address, uint8 data) -> void;
//[serialized]
Latch latch;
IO io;
array<uint16[32 * 1024]> vram;
array<uint15[256]> cgram;
array<Object[128]> objects;
//[unserialized]
uint32* output;
array<uint8*[3]> tilecache; //bitplane -> bitmap tiledata
Update to v106r44 release. byuu says: Changelog: - hiro/Windows: use `WS_CLIPSIBLINGS` on Label to prevent resize drawing issues - bsnes: correct viewport resizing - bsnes: speed up window resizing a little bit - bsnes: fix the cheat editor list enable checkbox - bsnes: fix the state manager filename display in game ROM mode - bsnes: fix the state manager save/rename/remove functionality in game ROM mode - bsnes: correct path searching for IPS and BPS patches in game ROM mode - bsnes: patch BS-X town cartridge to disable play limits - bsnes: do not load (program,data,expansion).(rom,flash) from disk in game pak mode - this is required to support soft-patching and ROM hacks - bsnes: added speed mode selection (50%, 75%, 100%, 150%, 200%); maintains proper pitch - bsnes: added icons to the menubar - this is particularly useful to tell game ROMs from game paks in the load recent game menu - bsnes: added emblem at bottom left of status bar to indicate if a game is verified or not - verified means it is in the icarus verified game dump database - the verified diamond is orange; the unverified diamond is blue - bsnes: added an option (which defaults to off) to warn when loading unverified games - working around a bug in GTK, I have to use the uglier MessageWindow instead of MessageDialog - bsnes: added (non-functional) link to <https://doc.byuu.org/bsnes/> to the help menu - bsnes: added GUI setting to toggle memory auto-save feature - bsnes: added GUI setting to toggle capturing a backup save state when closing the emulator - bsnes: made auto-saving states on exit an option - bsnes: added an option to auto-load the auto-saved state on load - basically, the two combined implements auto-resume - bsnes: when firmware is missing, offer to take the user to the online help documentation - bsnes: added fast PPU option to disable the sprite limit - increase from 32 items/line + 34 tiles/line to 128 items/line + 128 tiles/line - technically, 1024 tiles/line are possible with 128 sprites at 64-width - but this is just a waste of cache locality and worst-case performance; it'll never happen Errata: - hiro/Windows: fallthrough on Canvas `WM_ERASEBKGND` to prevent startup flicker
2018-06-28 06:28:27 +00:00
uint ItemLimit;
uint TileLimit;
struct Line {
//line.cpp
static auto flush() -> void;
auto render() -> void;
auto pixel(uint x, Pixel above, Pixel below) const -> uint15;
auto blend(uint x, uint y, bool halve) const -> uint15;
Update to v106r35 release. byuu says: Changelog: - sfc/ppu-fast: fixed overscan crash - sfc/ppu-fast: fixed direct color mode - sfc: reconnected MSU1 support - higan: game.sfc/msu1/data.rom, game.sfc/msu1/track-#.pcm - bsnes: game.msu, game-#.pcm - bsnes: added cheat code editor - bsnes: added cheat code database support - sfc/ppu-fast: clear overscan lines when overscan disabled - sfc: output 223/239 lines instead of 224/240 lines - bsnes: fix aspect correction calculation - bsnes: crop line 224 when overscan masking is enabled - bsnes: exposed Expansion Port menu; but hid “21fx” from the list of devices - bsnes: tools menu is hidden until a game is loaded - ruby/input/keyboard/quartz: fixed compilation error So only bsnes the automated overscan cropping option. In higan, you can crop however many lines you like from the top or bottom of the image. But for bsnes, it automatically eats sixteen lines. My view right now is that if bsnes is meant to be the casual gaming emulator, that it should eat line 224 in this mode. Most games show content here, but because of the way the SNES PPU works, the very last line ends up on its very own tile row (line 0 isn't rendered), if the scroll registers don't account for it. There's a small number of games that will draw junk data to the very last scanline of the frame as a result of this. So I chose, at least for now, to hide it. Users can obviously disable overscan cropping to see this scanline. I'm open to being convinced not to do this, if someone has a compelling reason. We're pretty much screwed one way or the other with no overscan masking. If we output 239 lines, then most games will render 7 blank lines + 224 drawn lines + 8 blank lines, and the black top and bottom aren't centered. But if we output 240 lines to get 8 + 224 + 8, then games that do use overscan will have a blank line at the very bottom of the window. I'm also trying out a modified cheat code file format. It's been forever since I bothered to look at it, and the “cartridge” parent node doesn't match what I'm doing with trying to rename “cartridge” to “game” in manifests. And indeed, the idea of requiring a root node is rather superfluous for a cheat code file. Current format looks like this: cheat description: foo code: 7e2000=20+7e2001=30?40 enabled cheat description: bar code: 7e4000=80 Open to discussing this, and I'd like to sync up with Snes9X before they push out a new release, and I'll agree to finalize and never change this format again. I chose to use .cht for the extension when using game files (eg gamename.cht)
2018-06-03 13:14:42 +00:00
alwaysinline auto directColor(uint paletteIndex, uint paletteColor) const -> uint15;
alwaysinline auto plotAbove(uint x, uint source, uint priority, uint color) -> void;
alwaysinline auto plotBelow(uint x, uint source, uint priority, uint color) -> void;
//background.cpp
auto renderBackground(PPU::IO::Background&, uint source) -> void;
auto getTile(PPU::IO::Background&, uint hoffset, uint voffset) -> uint;
//mode7.cpp
auto renderMode7(PPU::IO::Background&, uint source) -> void;
//object.cpp
auto renderObject(PPU::IO::Object&) -> void;
//window.cpp
auto renderWindow(PPU::IO::WindowLayer&, bool, array<bool[256]>&) -> void;
auto renderWindow(PPU::IO::WindowColor&, uint, array<bool[256]>&) -> void;
//[unserialized]
uint9 y; //constant
IO io;
array<uint15[256]> cgram;
Update to v106r44 release. byuu says: Changelog: - hiro/Windows: use `WS_CLIPSIBLINGS` on Label to prevent resize drawing issues - bsnes: correct viewport resizing - bsnes: speed up window resizing a little bit - bsnes: fix the cheat editor list enable checkbox - bsnes: fix the state manager filename display in game ROM mode - bsnes: fix the state manager save/rename/remove functionality in game ROM mode - bsnes: correct path searching for IPS and BPS patches in game ROM mode - bsnes: patch BS-X town cartridge to disable play limits - bsnes: do not load (program,data,expansion).(rom,flash) from disk in game pak mode - this is required to support soft-patching and ROM hacks - bsnes: added speed mode selection (50%, 75%, 100%, 150%, 200%); maintains proper pitch - bsnes: added icons to the menubar - this is particularly useful to tell game ROMs from game paks in the load recent game menu - bsnes: added emblem at bottom left of status bar to indicate if a game is verified or not - verified means it is in the icarus verified game dump database - the verified diamond is orange; the unverified diamond is blue - bsnes: added an option (which defaults to off) to warn when loading unverified games - working around a bug in GTK, I have to use the uglier MessageWindow instead of MessageDialog - bsnes: added (non-functional) link to <https://doc.byuu.org/bsnes/> to the help menu - bsnes: added GUI setting to toggle memory auto-save feature - bsnes: added GUI setting to toggle capturing a backup save state when closing the emulator - bsnes: made auto-saving states on exit an option - bsnes: added an option to auto-load the auto-saved state on load - basically, the two combined implements auto-resume - bsnes: when firmware is missing, offer to take the user to the online help documentation - bsnes: added fast PPU option to disable the sprite limit - increase from 32 items/line + 34 tiles/line to 128 items/line + 128 tiles/line - technically, 1024 tiles/line are possible with 128 sprites at 64-width - but this is just a waste of cache locality and worst-case performance; it'll never happen Errata: - hiro/Windows: fallthrough on Canvas `WM_ERASEBKGND` to prevent startup flicker
2018-06-28 06:28:27 +00:00
array<ObjectItem[128]> items; //32 on real hardware
array<ObjectTile[128]> tiles; //34 on real hardware; 1024 max (128 * 64-width tiles)
array<Pixel[512]> above; //256 on real hardware
array<Pixel[512]> below; //512 for hires mode 7
array<bool[256]> windowAbove;
array<bool[256]> windowBelow;
//flush()
static uint start;
static uint count;
};
array<Line[240]> lines;
};
extern PPU ppu;
#undef PPU
#undef ppu