Update to v068r14 release.

byuu says:

Holy hell, that was a total brain twister. After hours of crazy bit
twiddling and debug printf's, I finally figured out how to allow both
lores and hires scrolling in the accurate PPU renderer. In the process,
I modified the main loop to run from -7 to 255, regardless of the hires
setting, and perform X adjustment inside the tile fetching. This fixed
a strange main/subscreen misalignment issue, so I was able to restore
the proper sub-then-main rendering for the final screen output stage.
Code looks a good bit cleaner this way overall.

I also added load state and save state menus to the tools menu, so you
can use the menubar to load and save to ten slots. I am thinking that
I should nuke the icons. As pretty as they are, it's getting tiresome
trying to find icons for everything, I have no pictures to represent
loading or saving a slot, nor to represent individual slots. I'll just
stick to radios and checkboxes.
This commit is contained in:
Tim Allen 2010-09-06 09:08:03 +10:00
parent 3f43747474
commit 3a81ac94a5
10 changed files with 91 additions and 52 deletions

View File

@ -1,6 +1,6 @@
include nall/Makefile
snes := snes
profile := performance
profile := accuracy
ui := qt
# compiler

View File

@ -174,6 +174,24 @@ MainWindow::MainWindow() {
tools->addSeparator();
tools_loadState = tools->addMenu("Load Quick State");
for(unsigned i = 0; i < 10; i++) {
QAction *loadAction = new QAction(string("Slot ", i + 1), 0);
loadAction->setData(i);
connect(loadAction, SIGNAL(triggered()), this, SLOT(loadState()));
tools_loadState->addAction(loadAction);
}
tools_saveState = tools->addMenu("Save Quick State");
for(unsigned i = 0; i < 10; i++) {
QAction *saveAction = new QAction(string("Slot ", i + 1), 0);
saveAction->setData(i);
connect(saveAction, SIGNAL(triggered()), this, SLOT(saveState()));
tools_saveState->addAction(saveAction);
}
tools->addSeparator();
tools_cheatEditor = tools->addAction("Cheat &Editor ...");
tools_cheatEditor->setIcon(QIcon(":/16x16/accessories-text-editor.png"));
@ -581,6 +599,20 @@ void MainWindow::saveScreenshot() {
interface.saveScreenshot = true;
}
void MainWindow::loadState() {
QAction *action = dynamic_cast<QAction*>(sender());
if(action == 0) return;
unsigned slot = action->data().toUInt();
state.load(slot);
}
void MainWindow::saveState() {
QAction *action = dynamic_cast<QAction*>(sender());
if(action == 0) return;
unsigned slot = action->data().toUInt();
state.save(slot);
}
void MainWindow::showCheatEditor() { toolsWindow->tab->setCurrentIndex(0); toolsWindow->show(); }
void MainWindow::showCheatFinder() { toolsWindow->tab->setCurrentIndex(1); toolsWindow->show(); }
void MainWindow::showStateManager() { toolsWindow->tab->setCurrentIndex(2); toolsWindow->show(); }

View File

@ -80,6 +80,8 @@ public:
QAction *tools_movies_recordFromPowerOn;
QAction *tools_movies_recordFromHere;
QAction *tools_captureScreenshot;
QMenu *tools_loadState;
QMenu *tools_saveState;
QAction *tools_cheatEditor;
QAction *tools_cheatFinder;
QAction *tools_stateManager;
@ -150,6 +152,8 @@ public slots:
void recordMovieFromPowerOn();
void recordMovieFromHere();
void saveScreenshot();
void loadState();
void saveState();
void showCheatEditor();
void showCheatFinder();
void showStateManager();

View File

@ -7,9 +7,9 @@ void PPU::Background::frame() {
void PPU::Background::scanline() {
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
x = -8 << hires;
x = -7;
y = self.vcounter();
edge = 7 - (regs.hoffset & 7);
tile_counter = (7 - (regs.hoffset & 7)) << hires;
for(unsigned n = 0; n < 8; n++) data[n] = 0;
if(self.vcounter() == 1) {
@ -36,7 +36,7 @@ void PPU::Background::get_tile() {
unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4);
unsigned tile_width = (!hires ? tile_height : 4);
unsigned width = (!hires ? 256 : 512);
unsigned width = 256 << hires;
unsigned mask_x = (tile_height == 3 ? width : (width << 1));
unsigned mask_y = mask_x;
@ -45,7 +45,7 @@ void PPU::Background::get_tile() {
mask_x--;
mask_y--;
unsigned px = x;
unsigned px = x << hires;
unsigned py = mosaic_voffset;
unsigned hscroll = regs.hoffset;
@ -59,24 +59,24 @@ void PPU::Background::get_tile() {
unsigned voffset = vscroll + py;
if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) {
uint16 opt_x = (x + (hscroll & 7));
uint16 offset_x = (x + (hscroll & 7));
if(opt_x >= 8) {
unsigned hval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
unsigned vval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8);
unsigned opt_valid_bit = (id == ID::BG1 ? 0x2000 : 0x4000);
if(offset_x >= 8) {
unsigned hval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
unsigned vval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8);
unsigned valid_mask = (id == ID::BG1 ? 0x2000 : 0x4000);
if(self.regs.bgmode == 4) {
if(hval & opt_valid_bit) {
if(!(hval & 0x8000)) {
hoffset = opt_x + (hval & ~7);
if(hval & valid_mask) {
if((hval & 0x8000) == 0) {
hoffset = offset_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;
if(hval & valid_mask) hoffset = offset_x + (hval & ~7);
if(vval & valid_mask) voffset = y + vval;
}
}
}
@ -84,8 +84,8 @@ void PPU::Background::get_tile() {
hoffset &= mask_x;
voffset &= mask_y;
unsigned screen_x = (regs.screen_size & 1 ? (32 << 5) : 0);
unsigned screen_y = (regs.screen_size & 2 ? (32 << 5) : 0);
unsigned screen_x = (regs.screen_size & 1 ? 32 << 5 : 0);
unsigned screen_y = (regs.screen_size & 2 ? 32 << 5 : 0);
if(regs.screen_size == 3) screen_y <<= 1;
unsigned tx = hoffset >> tile_width;
@ -126,21 +126,21 @@ void PPU::Background::get_tile() {
}
if(mirror_x) for(unsigned n = 0; n < 8; n++) {
//reverse data bits in data[n]: 01234567 -> 76543210
data[n] = ((data[n] >> 4) & 0x0f) | ((data[n] << 4) & 0xf0);
data[n] = ((data[n] >> 2) & 0x33) | ((data[n] << 2) & 0xcc);
data[n] = ((data[n] >> 1) & 0x55) | ((data[n] << 1) & 0xaa);
}
}
void PPU::Background::run() {
void PPU::Background::run(bool screen) {
if(self.vcounter() == 0) return;
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
if((self.hcounter() & 2) == 0) {
if(screen == Screen::Sub) {
output.main.priority = 0;
output.sub.priority = 0;
} else if(hires == false) {
return;
if(hires == false) return;
}
if(regs.mode == Mode::Inactive) return;
@ -148,7 +148,11 @@ void PPU::Background::run() {
if(regs.mode == Mode::Mode7) return run_mode7();
if((x++ & 7) == edge) get_tile();
if(tile_counter-- == 0) {
tile_counter = 7;
get_tile();
}
if(screen == Screen::Main) x++;
uint8 palette = get_tile_color();
if(x >= 0 && mosaic_hcounter++ >= regs.mosaic) {
@ -169,19 +173,17 @@ void PPU::Background::run() {
output.sub.palette = palette_index + mosaic_palette;
output.sub.tile = tile;
}
} else {
if(x & 1) {
if(regs.main_enable) {
output.main.priority = priority;
output.main.palette = palette_index + mosaic_palette;
output.main.tile = tile;
}
} else {
if(regs.sub_enable) {
output.sub.priority = priority;
output.sub.palette = palette_index + mosaic_palette;
output.sub.tile = tile;
}
} else if(screen == Screen::Main) {
if(regs.main_enable) {
output.main.priority = priority;
output.main.palette = palette_index + mosaic_palette;
output.main.tile = tile;
}
} else if(screen == Screen::Sub) {
if(regs.sub_enable) {
output.sub.priority = priority;
output.sub.palette = palette_index + mosaic_palette;
output.sub.tile = tile;
}
}
}
@ -226,7 +228,6 @@ void PPU::Background::reset() {
x = 0;
y = 0;
edge = 0;
mosaic_vcounter = 0;
mosaic_voffset = 0;
@ -234,6 +235,7 @@ void PPU::Background::reset() {
mosaic_hoffset = 0;
mosaic_palette = 0;
tile_counter = 0;
tile = 0;
priority = 0;
palette_number = 0;

View File

@ -5,6 +5,7 @@ class Background {
struct Mode { enum { BPP2, BPP4, BPP8, Mode7, Inactive }; };
struct ScreenSize { enum { Size32x32, Size32x64, Size64x32, Size64x64 }; };
struct TileSize { enum { Size8x8, Size16x16 }; };
struct Screen { enum { Main, Sub }; };
struct Regs {
unsigned tiledata_addr;
@ -35,7 +36,6 @@ class Background {
struct {
signed x;
signed y;
signed edge;
unsigned mosaic_vcounter;
unsigned mosaic_voffset;
@ -43,6 +43,7 @@ class Background {
unsigned mosaic_hoffset;
unsigned mosaic_palette;
unsigned tile_counter;
unsigned tile;
unsigned priority;
unsigned palette_number;
@ -52,7 +53,7 @@ class Background {
void frame();
void scanline();
void run();
void run(bool screen);
void reset();
void get_tile();

View File

@ -16,7 +16,7 @@ void PPU::Background::run_mode7() {
signed hoffset = sclip<13>(self.regs.mode7_hoffset);
signed voffset = sclip<13>(self.regs.mode7_voffset);
if(++Background::x & ~255) return;
if(Background::x++ & ~255) return;
unsigned x = mosaic_hoffset;
unsigned y = self.bg1.mosaic_voffset; //BG2 vertical mosaic uses BG1 mosaic size

View File

@ -43,16 +43,16 @@ void PPU::enter() {
if(vcounter() <= (!regs.overscan ? 224 : 239)) {
add_clocks(4);
for(unsigned pixel = 1; pixel < 8 + 256; pixel++) {
bg1.run();
bg2.run();
bg3.run();
bg4.run();
bg1.run(1);
bg2.run(1);
bg3.run(1);
bg4.run(1);
add_clocks(2);
bg1.run();
bg2.run();
bg3.run();
bg4.run();
bg1.run(0);
bg2.run(0);
bg3.run(0);
bg4.run(0);
if(pixel >= 8) {
oam.run();
window.run();

View File

@ -8,13 +8,13 @@ void PPU::Screen::scanline() {
void PPU::Screen::run() {
uint16 color;
if(self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6) {
color = get_pixel(false);
color = get_pixel(0);
*output++ = color;
*output++ = color;
} else {
color = get_pixel(false);
color = get_pixel(1);
*output++ = color;
color = get_pixel(true);
color = get_pixel(0);
*output++ = color;
}
}

View File

@ -115,7 +115,6 @@ void PPU::Background::serialize(serializer &s) {
s.integer(x);
s.integer(y);
s.integer(edge);
s.integer(mosaic_vcounter);
s.integer(mosaic_voffset);
@ -123,6 +122,7 @@ void PPU::Background::serialize(serializer &s) {
s.integer(mosaic_hoffset);
s.integer(mosaic_palette);
s.integer(tile_counter);
s.integer(tile);
s.integer(priority);
s.integer(palette_number);

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "068.13";
static const char Version[] = "068.14";
static const unsigned SerializerVersion = 13;
}
}