Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/libs/prx/libSceAgcDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,8 @@ foreach(agcExecutionTestSource IN LISTS agcExecutionTestSources)
list(APPEND agcExecutionTests ${agcExecutionTest})
endforeach()

target_include_directories(agc_driver_alpha_to_coverage_tests PRIVATE $<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>)

target_include_directories(agc_driver_dual_source_blend_tests PRIVATE $<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>)

target_include_directories(agc_driver_packed_unorm_color_target_tests PRIVATE $<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ std::shared_ptr<DrawDecode> Driver::decodeDraw(const QueueState& queue, const Su
product->pixel = Graphics::DecodePixelStageInfo(queue.context, Graphics::ExportMappings(product->state), Graphics::PixelProgramSkipped(queue));
product->pixel.targetExportPacking = Graphics::ExportPackings(product->state);
product->pixel.dualSourceBlend = product->state.dualSourceBlend;
product->pixel.alphaToCoverage = product->state.alphaToCoverage;
return product;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ void Driver::lookupDraw(const Submission& submission, const std::shared_ptr<Vulk
for (const auto value : pixel.targetExportMapping) mix(value);
for (const auto value : pixel.targetExportPacking) mix(static_cast<std::uint64_t>(value));
mix(pixel.dualSourceBlend);
mix(pixel.alphaToCoverage);
std::lock_guard cacheLock(drawCacheMutex);
++drawEntryCounters.lookups;
const auto found = drawCache.find(drawKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ bool Driver::sameDecode(const DrawDecode& a, const DrawDecode& b) {
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) return false;
if (p.targetExportPacking != q.targetExportPacking || p.dualSourceBlend != q.dualSourceBlend || p.alphaToCoverage != q.alphaToCoverage) return false;
return true;
}

Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ struct State {
VkViewport viewport;
bool negativeOneToOne;
bool depthClamp = false;
bool alphaToCoverage = false;
VkConservativeRasterizationModeEXT conservativeRasterization = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
VkRect2D scissor;
VkCullModeFlags cullMode;
Expand Down
15 changes: 13 additions & 2 deletions core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +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 AlphaToCoverageUndithered = 0x0000aa01u;
constexpr std::uint32_t ScanModeMask = ~0x22u;
constexpr std::uint32_t ScanControlMask = ~0x76023fffu;
constexpr std::uint32_t ScreenOffsetMask = ~0x01ff01ffu;
Expand Down Expand Up @@ -597,7 +598,8 @@ State DecodeState(const QueueState& queue) {
Require((depthControl & 0xc0000000u) == 0, "depth-conditional color writes are unsupported");
}
zero(cx, 0x203, shaderControlMask(read(cx, 0x1c4)), "depth export, shader coverage or ordered fragment execution");
zero(cx, 0x2dc, AlphaToCoverageMask, "alpha-to-coverage");
result.alphaToCoverage = read(cx, 0x2dc) == AlphaToCoverageUndithered;
if (!result.alphaToCoverage) zero(cx, 0x2dc, AlphaToCoverageMask, "dithered or rounded alpha-to-coverage");
zero(cx, 0x2f8, ~0u, "multisampling or coverage conversion");
zero(cx, 0x292, ScanModeMask, "scan conversion mode");
zero(cx, 0x293, ScanControlMask, "sample iteration, primitive discard or out-of-order rasterization");
Expand Down Expand Up @@ -770,6 +772,13 @@ State DecodeState(const QueueState& queue) {
Require(((exportFormat >> 4u) & 0xfu) == (exportFormat & 0xfu), "dual-source blending needs the MRT1 export in the MRT0 export format");
Require(((shaderMask >> 4u) & 0xfu) == (shaderMask & 0xfu), "dual-source blending needs the MRT1 export with the MRT0 shader mask");
}
if (result.alphaToCoverage) {
const auto mrt0 = std::find_if(result.colors.begin(), result.colors.end(), [](const ColorTarget& color) { return color.exportIndex == 0; });
Require(mrt0 != result.colors.end(), "alpha-to-coverage without a written MRT0 color target is unsupported");
const auto format = exportFormat & 0xfu;
Require(format == 4u || format == 5u || format == 6u || format == 9u, "alpha-to-coverage needs an MRT0 export format with a floating-point alpha");
Require(mrt0->componentMapping == 0xe4u && mrt0->packing == ShaderRecompiler::ColorExportPacking::None, "alpha-to-coverage into a component-swapped or packed MRT0 target is unsupported");
}
APS5_LOG_OUT_DEBUG("DecodeState done colorTarget=%u render=%ux%u topology=%u", result.hasColorTarget ? 1u : 0u, result.renderExtent.width, result.renderExtent.height, static_cast<unsigned>(result.topology));
return result;
}
Expand Down Expand Up @@ -983,7 +992,9 @@ std::string DrawRejection(const QueueState& queue, bool indexed) {
std::uint32_t zFormat = 0;
static_cast<void>(value(cx, 0x1c4, zFormat));
if (auto reason = nonzero(cx, 0x203, shaderControlMask(zFormat), "depth export, shader coverage or ordered fragment execution"); !reason.empty()) return reason;
if (auto reason = nonzero(cx, 0x2dc, AlphaToCoverageMask, "alpha-to-coverage"); !reason.empty()) return reason;
if (value(cx, 0x2dc, word) && word != AlphaToCoverageUndithered) {
if (auto reason = nonzero(cx, 0x2dc, AlphaToCoverageMask, "dithered or rounded alpha-to-coverage"); !reason.empty()) return reason;
}
if (auto reason = nonzero(cx, 0x2f8, ~0u, "multisampling or coverage conversion"); !reason.empty()) return reason;
if (auto reason = nonzero(cx, 0x292, ScanModeMask, "scan conversion mode"); !reason.empty()) return reason;
if (auto reason = nonzero(cx, 0x293, ScanControlMask, "sample iteration, primitive discard or out-of-order rasterization"); !reason.empty()) return reason;
Expand Down
23 changes: 22 additions & 1 deletion core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,26 @@ void DepthClipTests() {
}
}

void AlphaToCoverageTests() {
auto queue = makeState();
queue.context[0x1b3] = 2;
queue.context[0x1b4] = 2;
Require(!AgcDriver::Graphics::DecodeState(queue).alphaToCoverage, "alpha-to-coverage decoded while disabled");
queue.context[0x2dc] = 0xaa01;
Require(AgcDriver::Graphics::DecodeState(queue).alphaToCoverage, "undithered alpha-to-coverage was not decoded");
Require(AgcDriver::Graphics::DrawRejection(queue, false).empty(), "the precheck rejected undithered alpha-to-coverage");
for (const auto control : {0x8701u, 0x1aa01u, 0xaa03u}) {
queue.context[0x2dc] = control;
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "alpha-to-coverage");
Require(AgcDriver::Graphics::DrawRejection(queue, false).find("alpha-to-coverage") != std::string::npos, "the precheck accepted unsupported alpha-to-coverage");
}
queue.context[0x2dc] = 0xaa01;
const auto exportFormat = queue.context.at(0x1c5);
queue.context[0x1c5] = (exportFormat & ~0xfu) | 1u;
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "floating-point alpha");
queue.context[0x1c5] = exportFormat;
}

void InitialContextTests() {
const auto configured = makeState();
AgcDriver::QueueState queue;
Expand All @@ -1533,7 +1553,7 @@ void InitialContextTests() {
}
queue.context[0x206] = 0x43f;
queue.context[0x2dc] |= 1;
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "alpha-to-coverage");
Require(AgcDriver::Graphics::DecodeState(queue).alphaToCoverage, "undithered alpha-to-coverage was not decoded");
queue.context.erase(0x2dc);
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "missing register");
queue.ClearContext();
Expand Down Expand Up @@ -4041,6 +4061,7 @@ int main() {
ComputeScratchTests();
shaderUserDataTailPaddingTests();
InitialContextTests();
AlphaToCoverageTests();
pushConstantTests();
resourceTests();
descriptorSnapshotTests();
Expand Down
16 changes: 11 additions & 5 deletions core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1295,7 +1295,7 @@ void verifyPixelRequestSerialization() {
value.posZ, value.posW, value.frontFace, value.ancillary, value.sampleShading,
value.noPerspective, value.linearCentroid, value.pixelKillEnable, value.depthExportEnable,
value.sampleMaskExportEnable, value.earlyZ, value.executeOnNoop, value.conservativeZExport, value.orderedPixelShader,
value.targetOutputMode, value.targetExportMapping);
value.targetOutputMode, value.targetExportMapping, value.alphaToCoverage);
};
const std::array<std::uint32_t, 1> code{0xbf810000u};
const std::array<std::uint32_t, 3> userData{0x12345678u, 0xabcdef01u, 0x87654321u};
Expand Down Expand Up @@ -1338,6 +1338,7 @@ void verifyPixelRequestSerialization() {
.targetOutputMode = {1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u}
};
for (std::uint32_t i = 0; i < pixel.interpolatorSettings.size(); ++i) pixel.interpolatorSettings[i] = 0x10101010u + i;
pixel.alphaToCoverage = true;
const std::array<std::array<std::uint8_t, 8>, 3> mappings{{
{0x00u, 0xe4u, 0xc6u, 0x1bu, 0xffu, 0x80u, 0x55u, 0xaau},
{0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u},
Expand All @@ -1362,6 +1363,10 @@ void verifyPixelRequestSerialization() {
RecompileCacheKey::Build(changed, replayKey);
require(key == replayKey && RecompileCacheKey::ContextHash(request) == RecompileCacheKey::ContextHash(changed), "runtime pixel export mapping changed the static shader identity");
}
auto withoutCoverage = request;
withoutCoverage.context.pixel->alphaToCoverage = false;
RecompileCacheKey::Build(withoutCoverage, replayKey);
require(key != replayKey && RecompileCacheKey::ContextHash(request) != RecompileCacheKey::ContextHash(withoutCoverage), "alpha-to-coverage did not change the static shader identity");
}
request.context.pixel.reset();
request.shader.stage = ShaderStage::Vertex;
Expand All @@ -1373,12 +1378,12 @@ void verifyPixelRequestSerialization() {
minimal.context.waveSize = 64;
minimal.context.pixel = ShaderPixelStageInfo{};
const auto encoded = serializer.Serialize(minimal);
require(requestPrefix(encoded, 8u) == "NVNQQQ8AAAA=", "new requests did not use serialization version 15");
require(requestPrefix(encoded, 8u) == "NVNQQRAAAAA=", "new requests did not use serialization version 16");
constexpr std::size_t mappingOffset = 8u + 37u + 18u + 163u;
for (std::size_t bytes = 0; bytes < 17u; ++bytes) {
expectFailure([&] { static_cast<void>(serializer.Deserialize(requestPrefix(encoded, mappingOffset + bytes))); }, "truncated data", "a truncated pixel mapping, packing or dual-source flag was accepted");
for (std::size_t bytes = 0; bytes < 18u; ++bytes) {
expectFailure([&] { static_cast<void>(serializer.Deserialize(requestPrefix(encoded, mappingOffset + bytes))); }, "truncated data", "a truncated pixel mapping, packing, dual-source or alpha-to-coverage flag was accepted");
}
for (const auto unsupported : {"NVNQQQAAAAA=", "NVNQQRAAAAA="}) {
for (const auto unsupported : {"NVNQQQAAAAA=", "NVNQQREAAAA="}) {
expectFailure([&] { static_cast<void>(serializer.Deserialize(unsupported)); }, "serialization version", "an unsupported request version was accepted");
}
}
Expand Down Expand Up @@ -1467,6 +1472,7 @@ void verifyLegacyPixelRequests() {
require(pixel.targetExportMapping == std::array<std::uint8_t, 8>{}, "legacy pixel mapping no longer defaults to zero");
require(pixel.targetExportPacking == std::array<ColorExportPacking, 8>{}, "a legacy request packed a color export");
require(!pixel.dualSourceBlend, "a legacy request enabled dual-source blending");
require(!pixel.alphaToCoverage, "a legacy request enabled alpha-to-coverage");
require(pixel.inputAddr == 2u && pixel.hasPerspectiveCenterVgpr && pixel.targetOutputMode[0] == 9u, "legacy pixel layout was misread");
require(pixel.conservativeZExport == (version >= 7u ? ConservativeZExport::GreaterThanZ : ConservativeZExport::AnyZ), "legacy conservative Z layout was misread");
require(!pixel.orderedPixelShader, "a legacy request became a primitive-ordered pixel shader");
Expand Down
Loading
Loading