diff --git a/core/libs/prx/libSceAgcDriver/Graphics/include/ColorTargetLayout.hpp b/core/libs/prx/libSceAgcDriver/Graphics/include/ColorTargetLayout.hpp index 8c492a1a0..575de2335 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/include/ColorTargetLayout.hpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/include/ColorTargetLayout.hpp @@ -9,6 +9,8 @@ namespace AgcDriver::Graphics { +struct TextureSwizzleEquation; + enum class ColorTileMode : std::uint32_t { Linear = 0, Standard4KB = 5, @@ -57,6 +59,7 @@ private: // The XOR swizzle is linear over GF(2), so a block offset is xOffsets[x] ^ yOffsets[y]. const std::uint32_t* xOffsets = nullptr; const std::uint32_t* yOffsets = nullptr; + const TextureSwizzleEquation* equation = nullptr; }; class CmaskLayout { diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/ColorTargetLayout.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/ColorTargetLayout.cpp index b4deb5dda..27ee8a4a5 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/ColorTargetLayout.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/ColorTargetLayout.cpp @@ -123,6 +123,7 @@ ColorTargetLayout::ColorTargetLayout(std::uint32_t width, std::uint32_t height, const auto& tables = equationTables(mode, bytesPerElement, blockWidth, blockHeight); xOffsets = tables.x.data(); yOffsets = tables.y.data(); + if (mode == ColorTileMode::RenderTarget) equation = FindTextureSwizzleEquation(static_cast(mode), bytesPerElement); break; } case ColorTileMode::Standard4KB: @@ -149,7 +150,16 @@ ColorTargetLayout::ColorTargetLayout(std::uint32_t width, std::uint32_t height, std::size_t ColorTargetLayout::offset(std::uint32_t x, std::uint32_t y) const { if (mode == ColorTileMode::Linear) return (static_cast(y) * pitch + x) * elementBytes; const auto block = static_cast(y / blockHeight) * (pitch / blockWidth) + x / blockWidth; - return block * Alignment() + (xOffsets[x % blockWidth] ^ yOffsets[y % blockHeight] ^ pipeBankXor); + auto inBlock = xOffsets[x % blockWidth] ^ yOffsets[y % blockHeight]; + if (equation != nullptr) { + const auto highX = (x & ~(blockWidth - 1u)) & 0xfffu; + const auto highY = ((y & ~(blockHeight - 1u)) << 12u) & 0xfff000u; + for (std::uint32_t bit = 0; bit < 16u; ++bit) { + const auto coordinates = (highX & equation->bits[bit]) ^ (highY & equation->bits[bit]); + inBlock |= (parity(coordinates) << bit); + } + } + return block * Alignment() + (inBlock ^ pipeBankXor); } std::size_t ColorTargetLayout::Offset(std::uint32_t x, std::uint32_t y) const { diff --git a/core/libs/prx/libSceAgcDriver/tests/ColorTargetLayout.cpp b/core/libs/prx/libSceAgcDriver/tests/ColorTargetLayout.cpp index d414e2976..4e8193586 100644 --- a/core/libs/prx/libSceAgcDriver/tests/ColorTargetLayout.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/ColorTargetLayout.cpp @@ -51,6 +51,10 @@ void RunColorTargetLayoutTests() { Require(layout.Offset(128, 0) == 65536 && layout.Offset(0, 128) == 3 * 65536, "block raster order is incorrect"); Require(layout.Offset(16, 0) == 0x2200 && layout.Offset(0, 8) == 0x1100, "render-target XOR addressing is incorrect"); Require(layout.Offset(256, 0) == 2 * 65536, "third block address is incorrect"); + const ColorTargetLayout r64(33, 65, ColorTileMode::RenderTarget, 8); + const ColorTargetLayout r128(129, 67, ColorTileMode::RenderTarget, 16); + Require(r64.Offset(0, 64) == 67584, "64 bpp SW_64KB_R_X dropped a cross-block y-coordinate XOR bit"); + Require(r128.Offset(64, 0) == 66560, "128 bpp SW_64KB_R_X dropped a cross-block x-coordinate XOR bit"); Require(DecodeColorTileMode(0x4dc14000) == ColorTileMode::Standard4KB, "4 KiB standard color descriptor was rejected"); const ColorTargetLayout standard(256, 256, ColorTileMode::Standard4KB); Require(standard.Bytes() == ComputeSurfaceSize(ComputeElementMipLayout(TextureTileMode::kStandard4KB, 4, 256, 256, 1), 1) && standard.Alignment() == 4096, "4 KiB standard color layout differs from the texture layout");