diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp index a9eaec3ad..dbf142adb 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp @@ -104,7 +104,7 @@ constexpr std::uint32_t DepthControlMask = ~0x007007f0u; constexpr std::uint32_t ShaderControlMask = ~(0x0000f870u | 0x00020600u | 0x00010000u); constexpr std::uint32_t PixelStageRunsMask = 0x00020747u; constexpr std::uint32_t AlphaToCoverageMask = ~0x0001ff00u; -constexpr std::uint32_t ScanModeMask = ~2u; +constexpr std::uint32_t ScanModeMask = ~0x22u; constexpr std::uint32_t ScanControlMask = ~0x06023fffu; constexpr std::uint32_t ScreenOffsetMask = ~0x01ff01ffu; // Bits 26/27 (ZCLIP_NEAR/FAR_DISABLE) become depth clamping; bit 19 selects the [0, 1] clip space. @@ -272,6 +272,7 @@ std::uint32_t effectiveDepthControl(std::uint32_t depthControl) { } bool colorControlSupported(std::uint32_t colorControl, bool hasColorTarget) { + colorControl &= ~1u; return colorControl == 0xcc0010u || (!hasColorTarget && (colorControl & ~0x70u) == 0xcc0000u); } @@ -435,7 +436,7 @@ ShaderStages DecodeShaderStages(const QueueState& queue) { APS5_LOG_OUT_DEBUG("DecodeShaderStages value=0x%x primitive=%u path=%u vertexWave=%u", value, primitive, static_cast(result.path), result.vertexWaveSize); if (path == ShaderPath::Vertex) { validate((value & 0x2000u) != 0, "legacy vertex routing without PRIMGEN_EN is unsupported"); - validate((value & ~0x02402010u) == 0, "unsupported vertex routing, scheduling or wave-ID state"); + validate((value & ~0x0247a010u) == 0, "unsupported vertex routing, scheduling or wave-ID state"); } else if (path == ShaderPath::Tessellation) { validate((value & 0x00600020u) == 0, "wave32 tessellation or geometry amplification is unsupported"); validate((value & ~0x0007ed0du) == 0 && (value & 3u) == 1u && ((value >> 3u) & 3u) == 1u, "unsupported tessellation routing"); diff --git a/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp b/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp index 070b34a83..2b034c44e 100644 --- a/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp @@ -402,7 +402,7 @@ void ShaderStageTests() { queue.context[0x2d5] = value; expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "reserved"); } - for (const auto bit : {1u, 8u, 0x40u, 0x100u, 0x200u, 0x400u, 0x1000u, 0x4000u, 0x8000u, 0x80000u, 0x200000u, 0x800000u, 0x1000000u}) { + for (const auto bit : {1u, 8u, 0x40u, 0x100u, 0x200u, 0x400u, 0x1000u, 0x4000u, 0x80000u, 0x200000u, 0x800000u, 0x1000000u}) { queue.context[0x2d5] = 0x2000u | bit; expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "unsupported vertex"); } @@ -609,6 +609,33 @@ void DisabledColorTests() { Require(!depthOnly.hasColorTarget && depthOnly.depth && depthOnly.depthTest && depthOnly.depthWrite && depthOnly.renderExtent.height == 64, "COLOR_INVALID discarded a depth-only draw"); } +void TuningFieldTests() { + auto queue = makeState(); + queue.context[0x1b3] = 2; + queue.context[0x1b4] = 2; + const auto baseline = AgcDriver::Graphics::DecodeState(queue); + queue.context[0x292] = 0x22; + auto state = AgcDriver::Graphics::DecodeState(queue); + Require(AgcDriver::Graphics::DrawRejection(queue, false).empty(), "ALTERNATE_RBS_PER_TILE was rejected"); + Require(state.scissor.offset.x == baseline.scissor.offset.x && state.scissor.extent.width == baseline.scissor.extent.width && state.scissor.extent.height == baseline.scissor.extent.height, "ALTERNATE_RBS_PER_TILE changed the scissor"); + queue.context[0x292] = 0x26; + expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "scan conversion mode"); + queue.context[0x292] = 2; + queue.context[0x202] = 0xcc0011; + state = AgcDriver::Graphics::DecodeState(queue); + Require(AgcDriver::Graphics::DrawRejection(queue, false).empty(), "DISABLE_DUAL_QUAD was rejected"); + Require(state.hasColorTarget && state.blend.colorWriteMask == baseline.blend.colorWriteMask, "DISABLE_DUAL_QUAD changed color output"); + queue.context[0x202] = 0xcc0013; + expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "copy ROP"); + queue.context[0x202] = 0xcc0010; + for (const auto groups : {1u, 2u, 15u}) { + queue.context[0x2d5] = 0x2000u | (groups << 15u); + state = AgcDriver::Graphics::DecodeState(queue); + Require(AgcDriver::Graphics::DrawRejection(queue, false).empty(), "MAX_PRIMGRP_IN_WAVE was rejected"); + Require(state.stages.path == AgcDriver::Graphics::ShaderPath::Vertex && state.stages.vertexWaveSize == 64u, "MAX_PRIMGRP_IN_WAVE changed vertex routing"); + } +} + void CompactedExportTests() { alignas(256) static std::array slotFourMemory{}; const auto slotFour = reinterpret_cast(slotFourMemory.data()); @@ -2657,6 +2684,7 @@ int main() { metadataPassTests(); cmaskTests(); ShaderStageTests(); + TuningFieldTests(); PixelInputLayoutTests(); ComputeScratchTests(); InitialContextTests();