From 27fc7c07df141ed40c475aeb7d3642ee352c7981 Mon Sep 17 00:00:00 2001 From: root <182859762@qq.com> Date: Mon, 13 May 2024 00:35:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=BE=E5=88=B0=E4=BA=86inline=E7=9A=84?= =?UTF-8?q?=E6=BC=8F=E7=BD=91=E4=B9=8B=E9=B1=BC=E4=BA=86=EF=BC=8C=E8=B5=B6?= =?UTF-8?q?=E7=B4=A7=E5=8A=A0=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nba/src/hw/ppu/sprite.cpp | 231 ++++++++++++++++++++++++---------- 1 file changed, 168 insertions(+), 63 deletions(-) diff --git a/src/nba/src/hw/ppu/sprite.cpp b/src/nba/src/hw/ppu/sprite.cpp index 1064f24..6d1ad00 100644 --- a/src/nba/src/hw/ppu/sprite.cpp +++ b/src/nba/src/hw/ppu/sprite.cpp @@ -101,18 +101,18 @@ void PPU::DrawSpriteFetchOAM(uint cycle) { auto& drawer_state = sprite.drawer_state[sprite.state_wr]; - const auto Submit = [&]() { - // Swap the draw states and engage the drawer unit. - sprite.state_rd ^= 1; - sprite.state_wr ^= 1; - sprite.drawing = true; + // const auto Submit = [&]() { + // // Swap the draw states and engage the drawer unit. + // sprite.state_rd ^= 1; + // sprite.state_wr ^= 1; + // sprite.drawing = true; - // Start fetching the next OAM entry - oam_fetch.index++; - oam_fetch.step = 0; - oam_fetch.wait = oam_fetch.pending_wait; - oam_fetch.delay_wait = true; - }; + // // Start fetching the next OAM entry + // oam_fetch.index++; + // oam_fetch.step = 0; + // oam_fetch.wait = oam_fetch.pending_wait; + // oam_fetch.delay_wait = true; + // }; const int step = oam_fetch.step; @@ -237,7 +237,16 @@ void PPU::DrawSpriteFetchOAM(uint cycle) { if(drawer_state.affine) { oam_fetch.step = 2; } else { - Submit(); + //Submit(); + sprite.state_rd ^= 1; + sprite.state_wr ^= 1; + sprite.drawing = true; + + // Start fetching the next OAM entry + oam_fetch.index++; + oam_fetch.step = 0; + oam_fetch.wait = oam_fetch.pending_wait; + oam_fetch.delay_wait = true; } break; } @@ -257,13 +266,52 @@ void PPU::DrawSpriteFetchOAM(uint cycle) { drawer_state.texture_x = (drawer_state.matrix[0] * x0 + drawer_state.matrix[1] * y0) + (drawer_state.width << 7); drawer_state.texture_y = (drawer_state.matrix[2] * x0 + drawer_state.matrix[3] * y0) + (drawer_state.height << 7); - Submit(); + //Submit(); + { + sprite.state_rd ^= 1; + sprite.state_wr ^= 1; + sprite.drawing = true; + + // Start fetching the next OAM entry + oam_fetch.index++; + oam_fetch.step = 0; + oam_fetch.wait = oam_fetch.pending_wait; + oam_fetch.delay_wait = true; + } } break; } } } +ALWAYS_INLINE auto CalculateTileNumber4BPP(int cond, uint base_tile, int width, int block_x, int block_y) -> uint { + // @todo: can the OAM mapping be changed mid-scanline? what would that do? + //if(mmio.dispcnt.oam_mapping_1d) { + if( cond ){ + return (base_tile + block_y * ((uint)width >> 3) + block_x) & 0x3FFU; + } + + return ((base_tile + (block_y << 5)) & 0x3E0U) | ((base_tile + block_x) & 0x1FU); +} + +ALWAYS_INLINE auto CalculateTileNumber8BPP(int cond, uint base_tile, int width, int block_x, int block_y) -> uint { + // @todo: can the OAM mapping be changed mid-scanline? what would that do? + // if(mmio.dispcnt.oam_mapping_1d) { + if( cond ){ + return (base_tile + block_y * ((uint)width >> 2) + (block_x << 1)) & 0x3FFU; + } + + return ((base_tile + (block_y << 5)) & 0x3E0U) | (((base_tile & ~1) + (block_x << 1)) & 0x1FU); +} + +ALWAYS_INLINE auto CalculateAddress4BPP(uint tile, int tile_x, int tile_y) -> uint { + return 0x10000U + (tile << 5) + (tile_y << 2) + (tile_x >> 1); +} + +ALWAYS_INLINE auto CalculateAddress8BPP(uint tile, int tile_x, int tile_y) -> uint { + return 0x10000U + (tile << 5) + (tile_y << 3) + tile_x; +} + void PPU::DrawSpriteFetchVRAM(uint cycle) { if(!sprite.drawing) { return; @@ -276,57 +324,58 @@ void PPU::DrawSpriteFetchVRAM(uint cycle) { const uint base_tile = drawer_state.tile_number; - const auto CalculateTileNumber4BPP = [&](int block_x, int block_y) -> uint { - // @todo: can the OAM mapping be changed mid-scanline? what would that do? - if(mmio.dispcnt.oam_mapping_1d) { - return (base_tile + block_y * ((uint)width >> 3) + block_x) & 0x3FFU; - } + // 这五个函数可以inline也应该inline的,用lambda是暴殄天物 + // const auto CalculateTileNumber4BPP = [&](int block_x, int block_y) -> uint { + // // @todo: can the OAM mapping be changed mid-scanline? what would that do? + // if(mmio.dispcnt.oam_mapping_1d) { + // return (base_tile + block_y * ((uint)width >> 3) + block_x) & 0x3FFU; + // } - return ((base_tile + (block_y << 5)) & 0x3E0U) | ((base_tile + block_x) & 0x1FU); - }; + // return ((base_tile + (block_y << 5)) & 0x3E0U) | ((base_tile + block_x) & 0x1FU); + // }; - const auto CalculateTileNumber8BPP = [&](int block_x, int block_y) -> uint { - // @todo: can the OAM mapping be changed mid-scanline? what would that do? - if(mmio.dispcnt.oam_mapping_1d) { - return (base_tile + block_y * ((uint)width >> 2) + (block_x << 1)) & 0x3FFU; - } + // const auto CalculateTileNumber8BPP = [&](int block_x, int block_y) -> uint { + // // @todo: can the OAM mapping be changed mid-scanline? what would that do? + // if(mmio.dispcnt.oam_mapping_1d) { + // return (base_tile + block_y * ((uint)width >> 2) + (block_x << 1)) & 0x3FFU; + // } - return ((base_tile + (block_y << 5)) & 0x3E0U) | (((base_tile & ~1) + (block_x << 1)) & 0x1FU); - }; + // return ((base_tile + (block_y << 5)) & 0x3E0U) | (((base_tile & ~1) + (block_x << 1)) & 0x1FU); + // }; - const auto CalculateAddress4BPP = [&](uint tile, int tile_x, int tile_y) -> uint { - return 0x10000U + (tile << 5) + (tile_y << 2) + (tile_x >> 1); - }; + // const auto CalculateAddress4BPP = [&](uint tile, int tile_x, int tile_y) -> uint { + // return 0x10000U + (tile << 5) + (tile_y << 2) + (tile_x >> 1); + // }; - const auto CalculateAddress8BPP = [&](uint tile, int tile_x, int tile_y) -> uint { - return 0x10000U + (tile << 5) + (tile_y << 3) + tile_x; - }; + // const auto CalculateAddress8BPP = [&](uint tile, int tile_x, int tile_y) -> uint { + // return 0x10000U + (tile << 5) + (tile_y << 3) + tile_x; + // }; - const auto Plot = [&](int x, uint color) { - if(x < 0 || x >= 240) return; + // const auto Plot = [&](int x, uint color) { + // if(x < 0 || x >= 240) return; - auto& pixel = sprite.buffer_wr[x]; + // auto& pixel = sprite.buffer_wr[x]; - const bool opaque = color != 0U; - const auto mode = drawer_state.mode; - const uint priority = drawer_state.priority; + // const bool opaque = color != 0U; + // const auto mode = drawer_state.mode; + // const uint priority = drawer_state.priority; - /** - * Transparent/outside OBJ window pixels are treated the same as - * normal/semi-transparent sprite pixels, meaning that (unlike opaque/inside OBJ window pixels) they - * update the mosaic and priority attributes. - */ - if(mode == OBJ_WINDOW && opaque) { - pixel.window = 1; - } else if(priority < pixel.priority || pixel.color == 0U) { - if(opaque) { - pixel.color = color; - pixel.alpha = (mode == OBJ_SEMI) ? 1U : 0U; - } - pixel.mosaic = drawer_state.mosaic ? 1U : 0U; - pixel.priority = priority; - } - }; + // /** + // * Transparent/outside OBJ window pixels are treated the same as + // * normal/semi-transparent sprite pixels, meaning that (unlike opaque/inside OBJ window pixels) they + // * update the mosaic and priority attributes. + // */ + // if(mode == OBJ_WINDOW && opaque) { + // pixel.window = 1; + // } else if(priority < pixel.priority || pixel.color == 0U) { + // if(opaque) { + // pixel.color = color; + // pixel.alpha = (mode == OBJ_SEMI) ? 1U : 0U; + // } + // pixel.mosaic = drawer_state.mosaic ? 1U : 0U; + // pixel.priority = priority; + // } + // }; if(drawer_state.affine) { if(sprite.oam_fetch.delay_wait) { @@ -336,8 +385,9 @@ void PPU::DrawSpriteFetchVRAM(uint cycle) { const int texture_x = drawer_state.texture_x >> 8; const int texture_y = drawer_state.texture_y >> 8; - if(texture_x >= 0 && texture_x < width && - texture_y >= 0 && texture_y < height) { + // if(texture_x >= 0 && texture_x < width && + // texture_y >= 0 && texture_y < height) { + if( (texture_x | (width-1-texture_x) | texture_y | (height-1-texture_y) ) > 0 ){ const int tile_x = texture_x & 7; const int tile_y = texture_y & 7; @@ -347,11 +397,11 @@ void PPU::DrawSpriteFetchVRAM(uint cycle) { uint color_index = 0U; if(drawer_state.is_256) { - const uint tile = CalculateTileNumber8BPP(block_x, block_y); + const uint tile = CalculateTileNumber8BPP(mmio.dispcnt.oam_mapping_1d, base_tile, width, block_x, block_y); color_index = FetchVRAM_OBJ(cycle, CalculateAddress8BPP(tile, tile_x, tile_y)); } else { - const uint tile = CalculateTileNumber4BPP(block_x, block_y); + const uint tile = CalculateTileNumber4BPP(mmio.dispcnt.oam_mapping_1d, base_tile, width, block_x, block_y); const u8 data = FetchVRAM_OBJ(cycle, CalculateAddress4BPP(tile, tile_x, tile_y)); if(tile_x & 1U) { @@ -365,7 +415,34 @@ void PPU::DrawSpriteFetchVRAM(uint cycle) { } } - Plot(drawer_state.draw_x, color_index); + // Plot(drawer_state.draw_x, color_index); + { + auto x = drawer_state.draw_x; + auto color = color_index; + if( ( x | ((int)239-x) ) > 0 ) { + auto& pixel = sprite.buffer_wr[x]; + + const bool opaque = color != 0U; + const auto mode = drawer_state.mode; + const uint priority = drawer_state.priority; + + /** + * Transparent/outside OBJ window pixels are treated the same as + * normal/semi-transparent sprite pixels, meaning that (unlike opaque/inside OBJ window pixels) they + * update the mosaic and priority attributes. + */ + if(mode == OBJ_WINDOW && opaque) { + pixel.window = 1; + } else if(priority < pixel.priority || pixel.color == 0U) { + if(opaque) { + pixel.color = color; + pixel.alpha = (mode == OBJ_SEMI) ? 1U : 0U; + } + pixel.mosaic = drawer_state.mosaic ? 1U : 0U; + pixel.priority = priority; + } + } + } } drawer_state.draw_x++; @@ -389,7 +466,7 @@ void PPU::DrawSpriteFetchVRAM(uint cycle) { uint color_indices[2] {0, 0}; if(drawer_state.is_256) { - const uint tile = CalculateTileNumber8BPP(block_x, block_y); + const uint tile = CalculateTileNumber8BPP(mmio.dispcnt.oam_mapping_1d, base_tile, width, block_x, block_y); const u16 data = FetchVRAM_OBJ(cycle, CalculateAddress8BPP(tile, tile_x, tile_y)); if(flip_h) { @@ -402,7 +479,7 @@ void PPU::DrawSpriteFetchVRAM(uint cycle) { palette = 0U; } else { - const uint tile = CalculateTileNumber4BPP(block_x, block_y); + const uint tile = CalculateTileNumber4BPP(mmio.dispcnt.oam_mapping_1d, base_tile, width, block_x, block_y); const u8 data = FetchVRAM_OBJ(cycle, CalculateAddress4BPP(tile, tile_x, tile_y)); if(flip_h) { @@ -423,7 +500,35 @@ void PPU::DrawSpriteFetchVRAM(uint cycle) { color_index |= palette; } - Plot(drawer_state.draw_x++, color_index); + //Plot(drawer_state.draw_x++, color_index); + { + auto x = drawer_state.draw_x++; + auto color = color_index; + if( ( x | ((int)239-x) ) > 0 ) { + auto& pixel = sprite.buffer_wr[x]; + + const bool opaque = color != 0U; + const auto mode = drawer_state.mode; + const uint priority = drawer_state.priority; + + /** + * Transparent/outside OBJ window pixels are treated the same as + * normal/semi-transparent sprite pixels, meaning that (unlike opaque/inside OBJ window pixels) they + * update the mosaic and priority attributes. + */ + if(mode == OBJ_WINDOW && opaque) { + pixel.window = 1; + } else if(priority < pixel.priority || pixel.color == 0U) { + if(opaque) { + pixel.color = color; + pixel.alpha = (mode == OBJ_SEMI) ? 1U : 0U; + } + pixel.mosaic = drawer_state.mosaic ? 1U : 0U; + pixel.priority = priority; + } + } + } + } drawer_state.texture_x += 2;