Skip to content

Commit

Permalink
gba: implement pixel blend timings (#1695)
Browse files Browse the repository at this point in the history
Separates `dac.run()` into two steps, with the lower layer being
processed two cycles after the upper layer. PRAM fetch timings should
now match [fleroviux's PPU
docs](https://github.com/nba-emu/hw-docs/blob/main/src/ppu/composite.md).
  • Loading branch information
png183 authored Nov 15, 2024
1 parent 675d57b commit 7e5d749
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 33 deletions.
8 changes: 4 additions & 4 deletions ares/gba/ppu/background.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ auto PPU::Background::linear(u32 x, u32 y) -> void {
if(n4 color = ppu.readVRAM_BG(Byte, offset) >> (px & 1 ? 4 : 0)) {
output.enable = true;
output.priority = io.priority;
output.color = ppu.pram[latch.palette << 4 | color];
output.color = latch.palette << 4 | color;
}
} else {
u32 offset = (io.characterBase << 14) + (latch.character << 6) + (py << 3) + (px);
if(n8 color = ppu.readVRAM_BG(Byte, offset)) {
output.enable = true;
output.priority = io.priority;
output.color = ppu.pram[color];
output.color = color;
}
}

Expand Down Expand Up @@ -127,7 +127,7 @@ auto PPU::Background::affine(u32 x, u32 y) -> void {
if(n8 color = ppu.readVRAM_BG(Byte, (io.characterBase << 14) + (character << 6) + (py << 3) + px)) {
output.enable = true;
output.priority = io.priority;
output.color = ppu.pram[color];
output.color = color;
}
}

Expand Down Expand Up @@ -165,7 +165,7 @@ auto PPU::Background::bitmap(u32 x, u32 y) -> void {
n15 color = ppu.readVRAM_BG(mode, baseAddress + (offset << depth));

if(depth || color) { //8bpp color 0 is transparent; 15bpp color is always opaque
if(depth == 0) color = ppu.pram[color];
if(depth) output.directColor = true;
output.enable = true;
output.priority = io.priority;
output.color = color;
Expand Down
59 changes: 35 additions & 24 deletions ares/gba/ppu/dac.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
auto PPU::DAC::run(u32 x, u32 y) -> n15 {
if(ppu.blank()) return 0x7fff;
auto PPU::DAC::upperLayer() -> bool {
if(ppu.blank()) {
color = 0x7fff;
return false;
}

//determine active window
n1 active[6] = {true, true, true, true, true, true}; //enable all layers if no windows are enabled
Expand All @@ -11,16 +14,15 @@ auto PPU::DAC::run(u32 x, u32 y) -> n15 {
}

//priority sorting: find topmost two pixels
Pixel layers[6] = {
ppu.objects.mosaic,
ppu.bg0.mosaic,
ppu.bg1.mosaic,
ppu.bg2.mosaic,
ppu.bg3.mosaic,
{true, 3, ppu.pram[0]},
};
layers[OBJ] = ppu.objects.mosaic;
layers[BG0] = ppu.bg0.mosaic;
layers[BG1] = ppu.bg1.mosaic;
layers[BG2] = ppu.bg2.mosaic;
layers[BG3] = ppu.bg3.mosaic;
layers[SFX] = {true, 3, 0};

u32 aboveLayer = 5, belowLayer = 5;
aboveLayer = 5;
belowLayer = 5;
for(s32 priority = 3; priority >= 0; priority--) {
for(s32 layer = 5; layer >= 0; layer--) {
if(layers[layer].enable && layers[layer].priority == priority && active[layer]) {
Expand All @@ -31,26 +33,35 @@ auto PPU::DAC::run(u32 x, u32 y) -> n15 {
}

auto above = layers[aboveLayer];
auto below = layers[belowLayer];
auto eva = min(16u, (u32)io.blendEVA);
auto evb = min(16u, (u32)io.blendEVB);
auto evy = min(16u, (u32)io.blendEVY);
n15 color = above.color;
color = pramLookup(above);

//color blending
if(active[SFX] || (above.translucent && io.blendBelow[belowLayer])) {
if(above.translucent && io.blendBelow[belowLayer]) {
color = blend(above.color, eva, below.color, evb);
} else if(io.blendMode == 1 && io.blendAbove[aboveLayer] && io.blendBelow[belowLayer]) {
color = blend(above.color, eva, below.color, evb);
if(above.translucent && io.blendBelow[belowLayer]) return true;
if(active[SFX]) {
auto evy = min(16u, (u32)io.blendEVY);
if(io.blendMode == 1 && io.blendAbove[aboveLayer] && io.blendBelow[belowLayer]) {
return true;
} else if(io.blendMode == 2 && io.blendAbove[aboveLayer]) {
color = blend(above.color, 16 - evy, 0x7fff, evy);
color = blend(color, 16 - evy, 0x7fff, evy);
} else if(io.blendMode == 3 && io.blendAbove[aboveLayer]) {
color = blend(above.color, 16 - evy, 0x0000, evy);
color = blend(color, 16 - evy, 0x0000, evy);
}
}

return color;
return false;
}

auto PPU::DAC::lowerLayer() -> void {
auto below = layers[belowLayer];
auto eva = min(16u, (u32)io.blendEVA);
auto evb = min(16u, (u32)io.blendEVB);

color = blend(color, eva, pramLookup(below), evb);
}

inline auto PPU::DAC::pramLookup(Pixel& layer) -> n15 {
if(layer.directColor) return layer.color;
return ppu.pram[layer.color];
}

auto PPU::DAC::blend(n15 above, u32 eva, n15 below, u32 evb) -> n15 {
Expand Down
1 change: 0 additions & 1 deletion ares/gba/ppu/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ auto PPU::Objects::run(u32 x, u32 y) -> void {

auto& buffer = lineBuffers[y & 1];
output = buffer[x];
output.color = ppu.pram[output.color];

//horizontal mosaic
if(!mosaicOffset) {
Expand Down
12 changes: 9 additions & 3 deletions ares/gba/ppu/ppu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,15 @@ auto PPU::main() -> void {
window1.run(x, y);
window2.output = objects.output.window;
window3.output = true;
n15 color = dac.run(x, y);
line[x] = color;
if(accurate) step(4);
bool blending = dac.upperLayer();
if(blending) {
if(accurate) step(2);
dac.lowerLayer();
if(accurate) step(2);
} else {
if(accurate) step(4);
}
line[x] = dac.color;
}
if(!accurate) step(960);
} else {
Expand Down
13 changes: 12 additions & 1 deletion ares/gba/ppu/ppu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ struct PPU : Thread, IO {
n2 priority;
n15 color;

//BG2 only
n1 directColor;

//OBJ only
n1 translucent;
n1 mosaic;
Expand Down Expand Up @@ -216,7 +219,9 @@ struct PPU : Thread, IO {

struct DAC {
//dac.cpp
auto run(u32 x, u32 y) -> n15;
auto upperLayer() -> bool;
auto lowerLayer() -> void;
auto pramLookup(Pixel& layer) -> n15;
auto blend(n15 above, u32 eva, n15 below, u32 evb) -> n15;
auto power() -> void;

Expand All @@ -232,6 +237,12 @@ struct PPU : Thread, IO {
n5 blendEVB;
n5 blendEVY;
} io;

u32 aboveLayer;
u32 belowLayer;
n15 color;

Pixel layers[6];
} dac;

struct Object {
Expand Down

0 comments on commit 7e5d749

Please sign in to comment.