Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ std::shared_ptr<DrawDecode> Driver::decodeDraw(const QueueState& queue, const Su
product->pixel.dualSourceBlend = product->state.dualSourceBlend;
product->pixel.alphaToCoverage = product->state.alphaToCoverage;
if (product->pixel.ancillary) product->pixel.rasterPrimitive = Graphics::RasterPrimitiveOf(product->state);
if (product->pixel.ancillary) product->pixel.layerBase = product->state.layered || !product->state.hasColorTarget ? 0u : (product->state.color.depth > 1 ? product->state.color.depthSlice : product->state.color.arraySlice);
return product;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void Driver::lookupDraw(const Submission& submission, const std::shared_ptr<Vulk
mix(pixel.interpolatorCount);
for (std::uint32_t i = 0; i < pixel.interpolatorCount; ++i) mix(pixel.interpolatorSettings[i]);
mix(pixel.inputAddr);
for (const bool flag : {pixel.wave32, pixel.hasPerspectiveCenterVgpr, pixel.perspectiveCentroid, pixel.posX, pixel.posY, pixel.posZ, pixel.posW, pixel.frontFace, pixel.ancillary, pixel.sampleShading, pixel.noPerspective, pixel.linearCentroid, pixel.pixelKillEnable, pixel.depthExportEnable, pixel.sampleMaskExportEnable, pixel.earlyZ, pixel.executeOnNoop}) mix(flag);
for (const bool flag : {pixel.wave32, pixel.hasPerspectiveCenterVgpr, pixel.perspectiveCentroid, pixel.posX, pixel.posY, pixel.posZ, pixel.posW, pixel.frontFace, pixel.frontFaceAllBits, pixel.ancillary, pixel.sampleShading, pixel.noPerspective, pixel.linearCentroid, pixel.pixelKillEnable, pixel.depthExportEnable, pixel.sampleMaskExportEnable, pixel.earlyZ, pixel.executeOnNoop}) mix(flag);
mix(static_cast<std::uint64_t>(pixel.conservativeZExport));
mix(pixel.orderedPixelShader);
for (const auto value : pixel.targetOutputMode) mix(value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,14 @@ bool Driver::sameDecode(const DrawDecode& a, const DrawDecode& b) {
if (std::memcmp(&s.viewport, &t.viewport, sizeof(VkViewport)) != 0 || std::memcmp(&s.scissor, &t.scissor, sizeof(VkRect2D)) != 0) return false;
const auto& p = a.pixel;
const auto& q = b.pixel;
if (p.interpolatorCount != q.interpolatorCount || p.interpolatorSettings != q.interpolatorSettings || p.wave32 != q.wave32 || p.inputAddr != q.inputAddr || p.hasPerspectiveCenterVgpr != q.hasPerspectiveCenterVgpr || p.perspectiveCentroid != q.perspectiveCentroid || p.posX != q.posX || p.posY != q.posY || p.posZ != q.posZ || p.posW != q.posW || p.frontFace != q.frontFace || p.ancillary != q.ancillary || p.sampleShading != q.sampleShading || p.noPerspective != q.noPerspective || p.linearCentroid != q.linearCentroid || p.pixelKillEnable != q.pixelKillEnable || p.depthExportEnable != q.depthExportEnable || p.sampleMaskExportEnable != q.sampleMaskExportEnable || p.earlyZ != q.earlyZ || p.executeOnNoop != q.executeOnNoop || p.conservativeZExport != q.conservativeZExport || p.orderedPixelShader != q.orderedPixelShader || p.targetOutputMode != q.targetOutputMode || p.targetExportMapping != q.targetExportMapping) return false;
if (p.interpolatorCount != q.interpolatorCount || p.interpolatorSettings != q.interpolatorSettings || p.wave32 != q.wave32 || p.inputAddr != q.inputAddr || p.hasPerspectiveCenterVgpr != q.hasPerspectiveCenterVgpr || p.perspectiveCentroid != q.perspectiveCentroid || p.posX != q.posX || p.posY != q.posY || p.posZ != q.posZ || p.posW != q.posW || p.frontFace != q.frontFace || p.frontFaceAllBits != q.frontFaceAllBits || p.ancillary != q.ancillary || p.sampleShading != q.sampleShading || p.noPerspective != q.noPerspective || p.linearCentroid != q.linearCentroid || p.pixelKillEnable != q.pixelKillEnable || p.depthExportEnable != q.depthExportEnable || p.sampleMaskExportEnable != q.sampleMaskExportEnable || p.earlyZ != q.earlyZ || p.executeOnNoop != q.executeOnNoop || p.conservativeZExport != q.conservativeZExport || p.orderedPixelShader != q.orderedPixelShader || p.targetOutputMode != q.targetOutputMode || p.targetExportMapping != q.targetExportMapping) return false;
if (a.roles != b.roles || a.programs.size() != b.programs.size()) return false;
for (std::size_t i = 0; i < a.programs.size(); ++i) {
const auto& x = a.programs[i];
const auto& y = b.programs[i];
if (x.binary.stage != y.binary.stage || x.binary.codeAddress != y.binary.codeAddress || x.userDataBase != y.userDataBase || x.firstUserSgpr != y.firstUserSgpr || x.userData != y.userData || x.snapshot != y.snapshot || x.codeOffset != y.codeOffset) return false;
}
if (p.targetExportPacking != q.targetExportPacking || p.dualSourceBlend != q.dualSourceBlend || p.alphaToCoverage != q.alphaToCoverage || p.rasterPrimitive != q.rasterPrimitive) return false;
if (p.targetExportPacking != q.targetExportPacking || p.dualSourceBlend != q.dualSourceBlend || p.alphaToCoverage != q.alphaToCoverage || p.rasterPrimitive != q.rasterPrimitive || p.layerExported != q.layerExported || p.layerBase != q.layerBase) return false;
return true;
}

Expand Down
4 changes: 2 additions & 2 deletions core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ struct DrawKeyRange {
inline constexpr std::array<DrawKeyRange, 49> DrawKeyRegisters{{
{RegisterBank::Context, 0x000, 1}, {RegisterBank::Context, 0x002, 1}, {RegisterBank::Context, 0x005, 1}, {RegisterBank::Context, 0x007, 7}, {RegisterBank::Context, 0x010, 6}, {RegisterBank::Context, 0x01a, 5},
{RegisterBank::Context, 0x080, 4}, {RegisterBank::Context, 0x08c, 4}, {RegisterBank::Context, 0x090, 2}, {RegisterBank::Context, 0x094, 2}, {RegisterBank::Context, 0x0b4, 2}, {RegisterBank::Context, 0x105, 4}, {RegisterBank::Context, 0x10b, 3}, {RegisterBank::Context, 0x10f, 6},
// SPI_PS_INPUT_CNTL_0..31, SPI_PS_INPUT_ENA/ADDR, SPI_PS_IN_CONTROL, SPI_SHADER_POS/Z/COL_FORMAT,
// SPI_PS_INPUT_CNTL_0..31, SPI_PS_INPUT_ENA/ADDR, SPI_PS_IN_CONTROL .. SPI_BARYC_CNTL, SPI_SHADER_POS/Z/COL_FORMAT,
// CB_BLEND0..7_CONTROL, GE_MAX_OUTPUT_PER_SUBGROUP.
{RegisterBank::Context, 0x191, 32}, {RegisterBank::Context, 0x1b3, 2}, {RegisterBank::Context, 0x1b6, 1}, {RegisterBank::Context, 0x1c3, 3}, {RegisterBank::Context, 0x1e0, 8}, {RegisterBank::Context, 0x1ff, 1},
{RegisterBank::Context, 0x191, 32}, {RegisterBank::Context, 0x1b3, 2}, {RegisterBank::Context, 0x1b6, 3}, {RegisterBank::Context, 0x1c3, 3}, {RegisterBank::Context, 0x1e0, 8}, {RegisterBank::Context, 0x1ff, 1},
// DB_DEPTH_CONTROL .. PA_CL_VS_OUT_CNTL, PA_SC_MODE_CNTL_0/1, VGT_GS_MODE, VGT_GS_VERT_ITEMSIZE,
// PA_SU_VTX_CNTL, PA_SC_AA_CONFIG, the sample locations, the sample masks,
// PA_SC_CONSERVATIVE_RASTERIZATION_CNTL.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ constexpr std::uint32_t spiPsInputCntl0 = 0x191;
constexpr std::uint32_t spiPsInputEna = 0x1B3;
constexpr std::uint32_t spiPsInputAddr = 0x1B4;
constexpr std::uint32_t spiPsInControl = 0x1B6;
constexpr std::uint32_t spiBarycCntl = 0x1B8;
constexpr std::uint32_t dbShaderControl = 0x203;
constexpr std::uint32_t spiShaderColFormat = 0x1C5;
constexpr std::uint32_t defaultPixelInputs = 0x2u;
Expand Down Expand Up @@ -134,6 +135,7 @@ ShaderRecompiler::ShaderPixelStageInfo DecodePixelStageInfo(const Registers& con
.posZ = loaded(PixelInput::PositionZ),
.posW = loaded(PixelInput::PositionW),
.frontFace = loaded(PixelInput::FrontFace),
.frontFaceAllBits = loaded(PixelInput::FrontFace) && ((read(context, spiBarycCntl, RegisterBank::Context) >> 24u) & 0x1u) != 0,
.ancillary = loaded(PixelInput::Ancillary),
.sampleShading = loaded(PixelInput::PerspectiveSample) && loaded(PixelInput::LinearSample),
.noPerspective = loaded(PixelInput::LinearCenter),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ Module Inspect(const CompiledShader& compiled, const State& state, const VkPhysi
Require(module.modes.size() == 1, "unsupported tessellation-control execution mode");
} else if (evaluation) {
mode(state.rectList ? spv::ExecutionModeQuads : spv::ExecutionModeTriangles, {});
mode(state.rectList ? spv::ExecutionModeSpacingEqual : spv::ExecutionModeSpacingFractionalOdd, {});
mode(state.rectList || state.stages.tessellation->partitioning == 0u ? spv::ExecutionModeSpacingEqual : state.stages.tessellation->partitioning == 3u ? spv::ExecutionModeSpacingFractionalEven : spv::ExecutionModeSpacingFractionalOdd, {});
mode(spv::ExecutionModeVertexOrderCw, {});
Require(module.modes.size() == 3, "unsupported tessellation-evaluation execution mode");
} else if (geometry) {
Expand Down
2 changes: 1 addition & 1 deletion core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ ShaderStages DecodeShaderStages(const QueueState& queue, bool vertexWorkgroup) {
ShaderRecompiler::TessellationConfiguration tess{(config >> 8u) & 0x3fu, (config >> 14u) & 0x3fu, parameters & 3u, (parameters >> 2u) & 7u, (parameters >> 5u) & 7u};
validate(tess.inputControlPoints != 0 && tess.inputControlPoints <= 32 && tess.outputControlPoints != 0 && tess.outputControlPoints <= 32, "invalid tessellation control-point counts");
if ((parameters & ~0x000600ffu) != 0) Require(false, zeroMessage(0x2db, parameters, "VGT_TF_PARAM donut, factor detection, memory type or reserved state"));
validate(tess.domain == 1 && tess.partitioning == 2 && tess.outputTopology == 2, "only triangular, fractional-odd, clockwise tessellation is supported by the reference path");
validate(tess.domain == 1 && (tess.partitioning == 0 || tess.partitioning == 2 || tess.partitioning == 3) && tess.outputTopology == 2, "only triangular, integer, fractional-even or fractional-odd, clockwise tessellation is supported by the reference path");
Require(readFloat(queue.context, 0x287) <= 1.0f && readFloat(queue.context, 0x286) >= 63.0f, "tessellation level clamps inside the fractional-odd range [1, 63] are unsupported");
result.tessellation = tess;
} else {
Expand Down
11 changes: 10 additions & 1 deletion core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ AgcDriver::QueueState makeState() {
queue.userConfig[0x242] = 4;
queue.context = {
{0x2d5, 0x2000},
{0x1b6, 0}, {0x207, 0}, {0x200, 0}, {0x203, 0x800},
{0x1b6, 0}, {0x1b8, 0}, {0x207, 0}, {0x200, 0}, {0x203, 0x800},
{0x2dc, 0xaa00}, {0x2f8, 0}, {0x292, 2}, {0x293, 0},
{0x80, 0}, {0x8d, 0}, {0x83, 0xffff}, {0x8c, 0xa},
{0x2f9, 0x2d}, {0x313, 0x6000}, {0x30e, 0xffffffff}, {0x30f, 0xffffffff},
Expand Down Expand Up @@ -700,6 +700,10 @@ void ShaderStageTests() {
queue.context[0x2db] = parameters;
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, reason);
}
queue.context[0x2db] = 0x40041;
Require(AgcDriver::Graphics::DecodeState(queue).stages.tessellation->partitioning == 0, "integer-partitioned triangle patches decoded differently");
queue.context[0x2db] = 0x4004d;
Require(AgcDriver::Graphics::DecodeState(queue).stages.tessellation->partitioning == 3, "fractional-even-partitioned triangle patches decoded differently");
queue.context[0x2db] = 0x40049;
for (const auto [maximum, minimum] : {std::pair{0x41100000u, 0x3f800000u}, std::pair{0x42800000u, 0x40000000u}}) {
queue.context[0x286] = maximum;
Expand Down Expand Up @@ -1019,6 +1023,11 @@ void PixelInputLayoutTests() {
Require(PixelInputVgpr(pixel.inputAddr, PixelInput::PerspectiveCenter) == 0u && PixelInputVgpr(pixel.inputAddr, PixelInput::PerspectiveCentroid) == 2u && PixelInputVgpr(pixel.inputAddr, PixelInput::LinearCenter) == 4u && PixelInputVgpr(pixel.inputAddr, PixelInput::PositionX) == 6u && PixelInputVgpr(pixel.inputAddr, PixelInput::PositionY) == 7u, "the centroid layout moved the inputs");
pixel = decode(0x1146u, 0x1146u);
Require(pixel.linearCentroid && !pixel.noPerspective && PixelInputVgpr(pixel.inputAddr, PixelInput::LinearCentroid) == 4u && PixelInputVgpr(pixel.inputAddr, PixelInput::PositionX) == 6u && PixelInputVgpr(pixel.inputAddr, PixelInput::FrontFace) == 7u, "the linear centroid layout moved the inputs");
Require(!pixel.frontFaceAllBits, "FRONT_FACE_ALL_BITS was decoded from a clear SPI_BARYC_CNTL");
queue.context[0x1b8] = 1u << 24u;
Require(decode(0x1146u, 0x1146u).frontFaceAllBits, "SPI_BARYC_CNTL FRONT_FACE_ALL_BITS was not decoded");
Require(!decode(0x326u, 0x326u).frontFaceAllBits, "FRONT_FACE_ALL_BITS was decoded for a pixel program without the front-face input");
queue.context[0x1b8] = 0u;
pixel = decode(0x506u, 0x7afu);
Require(pixel.inputAddr == 0x7afu && !pixel.posY && pixel.posZ && PixelInputVgpr(pixel.inputAddr, PixelInput::PerspectiveCentroid) == 4u && PixelInputVgpr(pixel.inputAddr, PixelInput::PositionX) == 12u && PixelInputVgpr(pixel.inputAddr, PixelInput::PositionZ) == 14u, "ADDR-only inputs did not reserve their VGPRs");
for (const auto bit : {0x8u, 0x4000u}) {
Expand Down
20 changes: 20 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,25 @@ void verifyHalfWaveReduction() {
};
require(reductions(vertex(scan(0xffffffffu, 0x26000000u, 0x83800000u), 32u), spv::OpGroupNonUniformUMin) == 1u, "half-wave reduction: the wave64 vertex UMin scan, whose entry EXEC is every invocation, did not read lane 31 as a subgroup UMin on 32 lanes");
require(halves(vertex(scan(0x80000000u, 0x24000000u, 0x84000000u), 64u), spv::OpGroupNonUniformSMax, 0x80000000u), "half-wave reduction: the wave64 vertex SMax scan did not read lanes 31 and 63 as reductions of host invocations 0-31 and 32-63 on 64 lanes");
const auto domain = [](std::vector<std::uint32_t> code, std::uint32_t subgroupSize) {
*std::find(code.begin(), code.end(), 0xf800180fu) = 0xf80008cfu;
*std::find(code.begin(), code.end(), 0x7e160f00u) = 0x7e160f01u;
RecompileRequest request{};
request.shader = {ShaderStage::TessellationEvaluation, 0x10000u, code, 0, {}};
request.context.waveSize = 64;
request.context.vertex = ShaderVertexStageInfo{};
request.target.vulkanVersion = 0x00401000u;
request.target.spirvVersion = 0x00010300u;
request.target.subgroupSize = subgroupSize;
request.target.supportedCapabilities = capabilities;
request.target.fragmentShaderBarycentricEnabled = false;
request.layout.pushConstantSizeBytes = 128;
request.graphics = GraphicsCompileContext{0u, {}, std::nullopt, TessellationConfiguration{3u, 3u, 1u, 2u, 2u}, {}};
request.useCache = false;
return Recompile(request).spirv;
};
require(reductions(domain(scan(0xffffffffu, 0x26000000u, 0x83800000u), 32u), spv::OpGroupNonUniformUMin) == 1u, "half-wave reduction: the wave64 domain UMin scan under s_orn2_saveexec_b64 vcc, exec did not read lane 31 as a subgroup UMin on 32 lanes");
require(halves(domain(scan(0u, 0x38000000u, 0x88000000u), 64u), spv::OpGroupNonUniformBitwiseOr, 0u), "half-wave reduction: the wave64 domain OR scan did not read lanes 31 and 63 as reductions of host invocations 0-31 and 32-63 on 64 lanes");
const auto floatScan = [&scan](std::uint32_t identity, std::uint32_t vector, std::uint32_t join) {
auto code = scan(identity, vector, 0u);
code[23] = join;
Expand Down Expand Up @@ -1440,6 +1459,7 @@ void verifyHalfWaveReduction() {
auto overwritten = umin;
overwritten.insert(overwritten.begin() + 17, {0x7ef80500u, 0x7e008514u});
expectFailure([&] { static_cast<void>(pixel(overwritten, 32u, true)); }, lane63, "half-wave reduction: a scan of window registers read lane 63 after a v_movreld_b32 at a runtime M0 that may overwrite them");
require(reductions(domain(divergent, 32u), spv::OpGroupNonUniformUMin) == 1u, "half-wave reduction: domain keys masked inside a divergent branch did not read lane 31 as a subgroup UMin on 32 lanes");
const char* arithmetic = "v_readlane_b32 of lane 31 of a wave64 half-wave reduction scan needs subgroup arithmetic";
expectFailure([&] { static_cast<void>(pixel(umin, 32u, false)); }, arithmetic, "half-wave reduction: a device without subgroup arithmetic read lane 31 on 32 lanes");
expectFailure([&] { static_cast<void>(pixel(umin, 64u, false)); }, arithmetic, "half-wave reduction: a device without subgroup arithmetic read lane 31 on 64 lanes");
Expand Down
Loading
Loading