2018-05-29 11:26:48 +00:00
|
|
|
auto PPU::Line::renderObject(PPU::IO::Object& self) -> void {
|
|
|
|
if(io.displayDisable) return;
|
|
|
|
if(!self.aboveEnable && !self.belowEnable) return;
|
|
|
|
|
|
|
|
bool windowAbove[256];
|
|
|
|
bool windowBelow[256];
|
|
|
|
renderWindow(self.window, self.window.aboveEnable, windowAbove);
|
|
|
|
renderWindow(self.window, self.window.belowEnable, windowBelow);
|
|
|
|
|
|
|
|
uint itemCount = 0;
|
|
|
|
uint tileCount = 0;
|
|
|
|
for(auto n : range(32)) items[n].valid = false;
|
|
|
|
for(auto n : range(34)) tiles[n].valid = false;
|
|
|
|
|
|
|
|
for(auto n : range(128)) {
|
|
|
|
ObjectItem item{true, self.first + n};
|
|
|
|
const auto& object = ppu.objects[item.index];
|
|
|
|
|
|
|
|
if(object.size == 0) {
|
|
|
|
static const uint widths[] = { 8, 8, 8, 16, 16, 32, 16, 16};
|
|
|
|
static const uint heights[] = { 8, 8, 8, 16, 16, 32, 32, 32};
|
|
|
|
item.width = widths [self.baseSize];
|
|
|
|
item.height = heights[self.baseSize];
|
|
|
|
if(self.interlace && self.baseSize >= 6) item.height = 16; //hardware quirk
|
|
|
|
} else {
|
|
|
|
static const uint widths[] = {16, 32, 64, 32, 64, 64, 32, 32};
|
|
|
|
static const uint heights[] = {16, 32, 64, 32, 64, 64, 64, 32};
|
|
|
|
item.width = widths [self.baseSize];
|
|
|
|
item.height = heights[self.baseSize];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(object.x > 256 && object.x + item.width - 1 < 512) continue;
|
|
|
|
uint height = item.height >> self.interlace;
|
|
|
|
if((y >= object.y && y < object.y + height)
|
|
|
|
|| (object.y + height >= 256 && y < (object.y + height & 255))
|
|
|
|
) {
|
|
|
|
if(itemCount++ >= 32) break;
|
|
|
|
items[itemCount - 1] = item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int n = 31; n >= 0; n--) {
|
|
|
|
const auto& item = items[n];
|
|
|
|
if(!item.valid) continue;
|
|
|
|
|
|
|
|
const auto& object = ppu.objects[item.index];
|
|
|
|
uint tileWidth = item.width >> 3;
|
|
|
|
int x = object.x;
|
|
|
|
int y = this->y - object.y & 0xff;
|
|
|
|
if(self.interlace) y <<= 1;
|
|
|
|
|
|
|
|
if(object.vflip) {
|
|
|
|
if(item.width == item.height) {
|
|
|
|
y = item.height - 1 - y;
|
|
|
|
} else if(y < item.width) {
|
|
|
|
y = item.width - 1 - y;
|
|
|
|
} else {
|
|
|
|
y = item.width + (item.width - 1) - (y - item.width);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(self.interlace) {
|
|
|
|
y = !object.vflip ? y + ppu.field() : y - ppu.field();
|
|
|
|
}
|
|
|
|
|
|
|
|
x &= 511;
|
|
|
|
y &= 255;
|
|
|
|
|
|
|
|
uint16 tiledataAddress = self.tiledataAddress;
|
|
|
|
if(object.nameselect) tiledataAddress += 1 + self.nameselect << 12;
|
|
|
|
uint16 characterX = object.character.bits(0,3);
|
|
|
|
uint16 characterY = (object.character.bits(4,7) + (y >> 3) & 15) << 4;
|
|
|
|
|
|
|
|
for(uint tileX : range(tileWidth)) {
|
|
|
|
uint objectX = x + (tileX << 3) & 511;
|
|
|
|
if(x != 256 && objectX >= 256 && objectX + 7 < 512) continue;
|
|
|
|
|
|
|
|
ObjectTile tile{true};
|
|
|
|
tile.x = objectX;
|
|
|
|
tile.y = y;
|
|
|
|
tile.priority = object.priority;
|
|
|
|
tile.palette = 128 + (object.palette << 4);
|
|
|
|
tile.hflip = object.hflip;
|
|
|
|
|
|
|
|
uint mirrorX = !object.hflip ? tileX : tileWidth - 1 - tileX;
|
|
|
|
uint address = tiledataAddress + ((characterY + (characterX + mirrorX & 15)) << 4);
|
|
|
|
tile.number = address >> 4;
|
|
|
|
|
|
|
|
if(tileCount++ >= 34) break;
|
|
|
|
tiles[tileCount - 1] = tile;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Update to v106r33 release.
byuu says:
Changelog:
- nall/GNUmakefile: added `openmp=(true,false)` option; can be toggled
when building higan/bsnes
- defaults to disabled on macOS, because Xcode doesn't stupidly
doesn't ship with support for it
- higan/GNUmakefile: forgot to switch target,profile back from
bsnes,fast to higan,accurate
- this is just gonna happen from time to time, sorry
- sfc/dsp: when using the fast profile, the DSP syncs per sample
instead of per clock
- should only negatively impact Koushien 2, but is a fairly
significant speedup otherwise
- sfc/ppc,ppu-fast: optimized the code a bit (ppu 130fps to 133fps)
- sfc/ppu-fast: basic vertical mosaic support (not accurate, but
should look okay hopefully)
- sfc/ppu-fast: added missing mode7 hflip support
- sfc/ppu-fast: added support to render at 256-width and/or 240-height
- gives a decent speed boost, and also allows all of the older
quark shaders to work nicely again
- it does violate the contract of Emulator::Interface, but oh
well, it works fine in the bsnes GUI
- sfc/ppu-fast: use cached CGRAM values for mode7 and sprites
- sfc/ppu-fast: use global range/time over flags in object rendering
- may not actually work as we intended since it's a race condition
even if it's only ORing the flags
- really don't want to have to make those variables atomic if I
don't have to
- sfc/ppu-fast: should fully support interlace and overscan modes now
- hiro/cocoa: updated macOS Gatekeeper disable support to work on
10.13+
- ruby: forgot to fix macOS input driver, sorry
- nall/GNUmakefile: if uname is present, then just default to rm
instead of del (fixes Msys)
Note: blur emulation option will break pretty badly in 256x240 output
mode. I'll fix it later.
2018-05-31 07:06:55 +00:00
|
|
|
ppu.io.obj.rangeOver |= itemCount > 32;
|
|
|
|
ppu.io.obj.timeOver |= tileCount > 34;
|
2018-05-29 11:26:48 +00:00
|
|
|
|
|
|
|
for(uint n : range(34)) {
|
|
|
|
const auto& tile = tiles[n];
|
|
|
|
if(!tile.valid) continue;
|
|
|
|
|
|
|
|
auto tiledata = ppu.tilecache[TileMode::BPP4] + (tile.number << 6) + ((tile.y & 7) << 3);
|
|
|
|
uint tileX = tile.x;
|
|
|
|
uint mirrorX = tile.hflip ? 7 : 0;
|
|
|
|
for(uint x : range(8)) {
|
|
|
|
tileX &= 511;
|
|
|
|
if(tileX < 256) {
|
|
|
|
if(uint color = tiledata[x ^ mirrorX]) {
|
|
|
|
uint source = tile.palette < 192 ? Source::OBJ1 : Source::OBJ2;
|
|
|
|
uint priority = self.priority[tile.priority];
|
Update to v106r33 release.
byuu says:
Changelog:
- nall/GNUmakefile: added `openmp=(true,false)` option; can be toggled
when building higan/bsnes
- defaults to disabled on macOS, because Xcode doesn't stupidly
doesn't ship with support for it
- higan/GNUmakefile: forgot to switch target,profile back from
bsnes,fast to higan,accurate
- this is just gonna happen from time to time, sorry
- sfc/dsp: when using the fast profile, the DSP syncs per sample
instead of per clock
- should only negatively impact Koushien 2, but is a fairly
significant speedup otherwise
- sfc/ppc,ppu-fast: optimized the code a bit (ppu 130fps to 133fps)
- sfc/ppu-fast: basic vertical mosaic support (not accurate, but
should look okay hopefully)
- sfc/ppu-fast: added missing mode7 hflip support
- sfc/ppu-fast: added support to render at 256-width and/or 240-height
- gives a decent speed boost, and also allows all of the older
quark shaders to work nicely again
- it does violate the contract of Emulator::Interface, but oh
well, it works fine in the bsnes GUI
- sfc/ppu-fast: use cached CGRAM values for mode7 and sprites
- sfc/ppu-fast: use global range/time over flags in object rendering
- may not actually work as we intended since it's a race condition
even if it's only ORing the flags
- really don't want to have to make those variables atomic if I
don't have to
- sfc/ppu-fast: should fully support interlace and overscan modes now
- hiro/cocoa: updated macOS Gatekeeper disable support to work on
10.13+
- ruby: forgot to fix macOS input driver, sorry
- nall/GNUmakefile: if uname is present, then just default to rm
instead of del (fixes Msys)
Note: blur emulation option will break pretty badly in 256x240 output
mode. I'll fix it later.
2018-05-31 07:06:55 +00:00
|
|
|
color = cgram[tile.palette + color];
|
2018-05-29 11:26:48 +00:00
|
|
|
if(self.aboveEnable && !windowAbove[x]) plotAbove(tileX, source, priority, color);
|
|
|
|
if(self.belowEnable && !windowBelow[x]) plotBelow(tileX, source, priority, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tileX++;
|
|
|
|
}
|
|
|
|
}
|
2018-05-26 23:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto PPU::oamAddressReset() -> void {
|
2018-05-29 11:26:48 +00:00
|
|
|
io.oamAddress = io.oamBaseAddress;
|
|
|
|
oamSetFirstObject();
|
2018-05-26 23:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto PPU::oamSetFirstObject() -> void {
|
2018-05-29 11:26:48 +00:00
|
|
|
io.obj.first = !io.oamPriority ? 0 : io.oamAddress >> 2;
|
2018-05-26 23:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto PPU::readObject(uint10 address) -> uint8 {
|
2018-05-26 03:29:14 +00:00
|
|
|
if(!address.bit(9)) {
|
|
|
|
uint n = address >> 2; //object#
|
|
|
|
address &= 3;
|
2018-05-29 11:26:48 +00:00
|
|
|
if(address == 0) return objects[n].x.bits(0,7);
|
|
|
|
if(address == 1) return objects[n].y - 1;
|
|
|
|
if(address == 2) return objects[n].character;
|
2018-05-26 03:29:14 +00:00
|
|
|
return (
|
2018-05-29 11:26:48 +00:00
|
|
|
objects[n].nameselect << 0
|
|
|
|
| objects[n].palette << 1
|
|
|
|
| objects[n].priority << 4
|
|
|
|
| objects[n].hflip << 6
|
|
|
|
| objects[n].vflip << 7
|
2018-05-26 03:29:14 +00:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
uint n = (address & 0x1f) << 2; //object#
|
|
|
|
return (
|
2018-05-29 11:26:48 +00:00
|
|
|
objects[n + 0].x.bit(8) << 0
|
|
|
|
| objects[n + 0].size << 1
|
|
|
|
| objects[n + 1].x.bit(8) << 2
|
|
|
|
| objects[n + 1].size << 3
|
|
|
|
| objects[n + 2].x.bit(8) << 4
|
|
|
|
| objects[n + 2].size << 5
|
|
|
|
| objects[n + 3].x.bit(8) << 6
|
|
|
|
| objects[n + 3].size << 7
|
2018-05-26 03:29:14 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-26 23:04:43 +00:00
|
|
|
auto PPU::writeObject(uint10 address, uint8 data) -> void {
|
2018-05-26 03:29:14 +00:00
|
|
|
if(!address.bit(9)) {
|
|
|
|
uint n = address >> 2; //object#
|
2018-05-29 11:26:48 +00:00
|
|
|
address &= 3;
|
|
|
|
if(address == 0) { objects[n].x.bits(0,7) = data; return; }
|
|
|
|
if(address == 1) { objects[n].y = data + 1; return; } //+1 => rendering happens one scanline late
|
|
|
|
if(address == 2) { objects[n].character = data; return; }
|
|
|
|
objects[n].nameselect = data.bit (0);
|
|
|
|
objects[n].palette = data.bits(1,3);
|
|
|
|
objects[n].priority = data.bits(4,5);
|
|
|
|
objects[n].hflip = data.bit (6);
|
|
|
|
objects[n].vflip = data.bit (7);
|
2018-05-26 03:29:14 +00:00
|
|
|
} else {
|
|
|
|
uint n = (address & 0x1f) << 2; //object#
|
2018-05-29 11:26:48 +00:00
|
|
|
objects[n + 0].x.bit(8) = data.bit(0);
|
|
|
|
objects[n + 0].size = data.bit(1);
|
|
|
|
objects[n + 1].x.bit(8) = data.bit(2);
|
|
|
|
objects[n + 1].size = data.bit(3);
|
|
|
|
objects[n + 2].x.bit(8) = data.bit(4);
|
|
|
|
objects[n + 2].size = data.bit(5);
|
|
|
|
objects[n + 3].x.bit(8) = data.bit(6);
|
|
|
|
objects[n + 3].size = data.bit(7);
|
2018-05-26 03:29:14 +00:00
|
|
|
}
|
|
|
|
}
|