Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ std::shared_ptr<DrawDecode> Driver::decodeDraw(const QueueState& queue, const Su
DecodeGraphicsPrograms(*product, queue, *submission.shaders, false, true);
product->pixel = Graphics::DecodePixelStageInfo(queue.context, Graphics::ExportMappings(product->state), Graphics::PixelProgramSkipped(queue));
product->pixel.targetExportPacking = Graphics::ExportPackings(product->state);
product->pixel.targetOutputType = Graphics::ExportOutputTypes(product->state);
product->pixel.dualSourceBlend = product->state.dualSourceBlend;
product->pixel.alphaToCoverage = product->state.alphaToCoverage;
product->pixel.quadPixelMask = Graphics::QuadPixelMask(product->state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ void Driver::lookupDraw(const Submission& submission, const std::shared_ptr<Vulk
mix(pixel.orderedPixelShader);
mix(pixel.stencilRefExportEnable);
for (const auto value : pixel.targetOutputMode) mix(value);
for (const auto value : pixel.targetOutputType) mix(static_cast<std::uint64_t>(value));
for (const auto value : pixel.targetExportMapping) mix(value);
for (const auto value : pixel.targetExportPacking) mix(static_cast<std::uint64_t>(value));
mix(pixel.dualSourceBlend);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,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 || x.tailContinuation != y.tailContinuation) return false;
}
if (p.targetExportPacking != q.targetExportPacking || p.dualSourceBlend != q.dualSourceBlend || p.alphaToCoverage != q.alphaToCoverage || p.rasterPrimitive != q.rasterPrimitive || p.ditheredAlphaToCoverage != q.ditheredAlphaToCoverage || p.quadPixelMask != q.quadPixelMask || p.quadSampleMask != q.quadSampleMask) return false;
if (p.targetOutputType != q.targetOutputType || p.targetExportPacking != q.targetExportPacking || p.dualSourceBlend != q.dualSourceBlend || p.alphaToCoverage != q.alphaToCoverage || p.rasterPrimitive != q.rasterPrimitive || p.ditheredAlphaToCoverage != q.ditheredAlphaToCoverage || p.quadPixelMask != q.quadPixelMask || p.quadSampleMask != q.quadSampleMask) return false;
if (s.samples != t.samples || s.quadSampleMask != t.quadSampleMask || s.pixelEarlyZ != t.pixelEarlyZ) return false;
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ std::array<VkSampleLocationEXT, 32> SampleLocations(const State& state);
VkExtent2D SampleLocationGrid(const State& state);
std::array<std::uint8_t, 8> ExportMappings(const State& state);
std::array<ShaderRecompiler::ColorExportPacking, 8> ExportPackings(const State& state);
ShaderRecompiler::ColorOutputType ColorOutputTypeOf(const ColorTarget& color);
std::array<ShaderRecompiler::ColorOutputType, 8> ExportOutputTypes(const State& state);
ShaderRecompiler::RasterPrimitive RasterPrimitiveOf(const State& state);
bool PartialSampleMask(const State& state);
bool UniformSampleMask(const State& state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -661,9 +661,10 @@ std::set<std::uint32_t> ValidateShaders(std::span<const CompiledShader> shaders,
for (const auto& [location, signature] : previous.outputs) {
if (location >= attachments) continue;
const auto color = std::find_if(state.colors.begin(), state.colors.end(), [&](const ColorTarget& target) { return target.exportIndex == location; });
const bool uintExport = color != state.colors.end() && color->uintExport;
const auto outputType = color != state.colors.end() ? ColorOutputTypeOf(*color) : ShaderRecompiler::ColorOutputType::Float;
const bool packed = color != state.colors.end() && color->packing != ShaderRecompiler::ColorExportPacking::None;
Require(signature == (uintExport || packed ? "vertex:u32x4" : "vertex:f32x4"), packed ? "fragment shader must export uint4 words to its packed 10_11_11 unorm attachments" : uintExport ? "fragment shader must export uint4 colors to its unsigned integer attachments" : "fragment shader must export float4 colors to its attachments");
const auto expected = packed || outputType == ShaderRecompiler::ColorOutputType::Uint ? "vertex:u32x4" : outputType == ShaderRecompiler::ColorOutputType::Sint ? "vertex:i32x4" : "vertex:f32x4";
Require(signature == expected, "fragment output numeric type disagrees with its attachment (expected " + std::string(expected) + ", got " + signature + ")");
locations.insert(location);
}
Require(!state.dualSourceBlend || previous.secondSource == "f32x4", "dual-source blending needs a float4 second color at location 0 index 1");
Expand Down
29 changes: 27 additions & 2 deletions core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,10 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) {
auto color = DecodeColorBuffer(cx, slot);
if (slotExport == 7 && ((read(cx, 0x31c + slot * 0xfu) >> 8u) & 7u) != 4u) throw std::runtime_error("AGC graphics: color export format 7 (UINT16_ABGR) into a target that is not unsigned integer is unsupported");
color.exportIndex = index;
color.uintExport = slotExport == 7;
const auto outputType = ColorOutputTypeOf(color);
const bool integerOutput = outputType == ShaderRecompiler::ColorOutputType::Uint || outputType == ShaderRecompiler::ColorOutputType::Sint;
Require(!integerOutput || slotExport == 1 || slotExport == 2 || slotExport == 3 || slotExport == 7 || slotExport == 9, "integer attachment needs a raw32 or UINT16 color export");
color.uintExport = outputType == ShaderRecompiler::ColorOutputType::Uint;
if (color.samples > 1 && result.samples == 1 && result.colors.empty() && !result.depth && !result.alphaToCoverage && (read(cx, 0x292) & 1u) == 0) {
result.samples = color.samples;
result.customSampleLocations = true;
Expand Down Expand Up @@ -994,7 +997,7 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) {
}
state.blendEnable = ((blend >> 30u) & 1u) != 0 && (read(cx, 0x31c + slot * 0xfu) & 0x10000u) == 0;
if (state.blendEnable && (mapping == 0x1bu || mapping == 0x93u)) throw std::runtime_error("AGC graphics: blending into a color target with a reversed component order is not implemented");
Require(!state.blendEnable || !color.uintExport, "blending into an unsigned integer target is unsupported");
Require(!state.blendEnable || ColorOutputTypeOf(color) == ShaderRecompiler::ColorOutputType::Float, "blending into an unsigned integer target or signed integer target is unsupported");
if (state.blendEnable) {
state.srcColorBlendFactor = blendFactor(blend & 0x1fu);
state.dstColorBlendFactor = blendFactor((blend >> 8u) & 0x1fu);
Expand Down Expand Up @@ -1057,6 +1060,7 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) {
}
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() || ColorOutputTypeOf(*mrt0) == ShaderRecompiler::ColorOutputType::Float, "alpha-to-coverage into an integer target is unsupported");
const auto format = read(cx, 0x1c5) & 0xfu;
Require(format == 3u || format == 4u || format == 5u || format == 6u || format == 9u, "alpha-to-coverage needs an MRT0 export format with a floating-point alpha");
Require(!result.ditheredAlphaToCoverage || format == 4u || format == 9u, "dithered alpha-to-coverage needs an FP16_ABGR or 32_ABGR export");
Expand All @@ -1074,6 +1078,27 @@ std::array<ShaderRecompiler::ColorExportPacking, 8> ExportPackings(const State&
return packings;
}

ShaderRecompiler::ColorOutputType ColorOutputTypeOf(const ColorTarget& color) {
using Type = ShaderRecompiler::ColorOutputType;
if (color.packing != ShaderRecompiler::ColorExportPacking::None) return Type::Float;
switch (color.format) {
case VK_FORMAT_R8_UINT: case VK_FORMAT_R16_UINT: case VK_FORMAT_R32_UINT:
case VK_FORMAT_R16G16_UINT: case VK_FORMAT_R8G8B8A8_UINT:
case VK_FORMAT_R32G32_UINT: case VK_FORMAT_R16G16B16A16_UINT:
case VK_FORMAT_R32G32B32A32_UINT: return Type::Uint;
case VK_FORMAT_R32_SINT: return Type::Sint;
default: return Type::Float;
}
}

std::array<ShaderRecompiler::ColorOutputType, 8> ExportOutputTypes(const State& state) {
std::array<ShaderRecompiler::ColorOutputType, 8> types{};
for (const auto& color : state.colors) {
if (color.exportIndex < types.size()) types[color.exportIndex] = ColorOutputTypeOf(color);
}
return types;
}

bool PartialSampleMask(const State& state) {
const auto full = (1u << state.samples) - 1u;
return std::ranges::any_of(state.quadSampleMask, [&](std::uint16_t mask) { return (mask & full) != full; });
Expand Down
41 changes: 39 additions & 2 deletions core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,14 @@ void hdrComponentSwapTests() {
queue.context[0x8e] = 0xf;
queue.context[0x1e0] = (1u << 30u) | 13u;
for (std::uint32_t i = 0; i < 4; ++i) queue.context[0x105 + i] = std::bit_cast<std::uint32_t>(float(i + 1) / 8.0f);
if (number == 4u) {
expectFailure([&] { DecodeState(queue); }, "blending into an unsigned integer target");
queue.context[0x1e0] = 0;
queue.context[0x31c] &= ~(1u << 11u);
state = DecodeState(queue);
Require(state.color.componentMapping == 0xe4u && ExportOutputTypes(state)[0] == ShaderRecompiler::ColorOutputType::Uint, "standard integer color mapping or numeric type changed");
continue;
}
state = DecodeState(queue);
Require(state.blendConstants == std::array<float, 4>{0.375f, 0.25f, 0.125f, 0.5f}, "alternate color blend constants were not swizzled with the export");
queue.context[0x31c] &= ~(1u << 11u);
Expand Down Expand Up @@ -2347,6 +2355,26 @@ void uint16ExportTests() {
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "color export format 8");
}

void raw32IntegerExportTests() {
using Type = ShaderRecompiler::ColorOutputType;
for (const auto number : {4u, 5u}) {
for (const auto mode : {1u, 2u, 3u, 9u}) {
auto queue = makeState();
queue.context[0x1c5] = mode;
queue.context[0x31c] = (queue.context[0x31c] & ~0x77cu) | (4u << 2u) | (number << 8u);
const auto state = AgcDriver::Graphics::DecodeState(queue);
const auto expected = number == 4u ? Type::Uint : Type::Sint;
Require(AgcDriver::Graphics::ExportOutputTypes(state)[0] == expected, "a raw32 export lost its attachment numeric type");
auto compacted = state;
compacted.colors[0].exportIndex = 3u;
const auto types = AgcDriver::Graphics::ExportOutputTypes(compacted);
Require(types[0] == Type::Auto && types[3] == expected, "attachment numeric type followed the physical target instead of the export location");
queue.context[0x1e0] = 1u << 30u;
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "integer target");
}
}
}

VkSampleCountFlags depthSampleCounts = VK_SAMPLE_COUNT_4_BIT;
VkResult depthSampleResult = VK_SUCCESS;
std::uint32_t depthSampleQueries = 0;
Expand Down Expand Up @@ -5970,10 +5998,12 @@ void unorm10_11_11TargetTests() {
return AgcDriver::Graphics::ValidateShaders(shaders, target, subgroup, false);
};
Require(validate(packed, state) == std::set<std::uint32_t>{0u}, "the packed export did not reach attachment 0");
expectFailure([&] { validate(unpacked, state); }, "uint4 words to its packed 10_11_11 unorm attachments");
expectFailure([&] { validate(unpacked, state); }, "expected vertex:u32x4, got vertex:f32x4");
auto plainState = state;
plainState.colors[0].packing = ColorExportPacking::None;
expectFailure([&] { validate(packed, plainState); }, "float4 colors");
Require(validate(packed, plainState) == std::set<std::uint32_t>{0u}, "uint4 outputs did not validate against an ordinary R32_UINT attachment");
plainState.colors[0].format = VK_FORMAT_R32_SFLOAT;
expectFailure([&] { validate(packed, plainState); }, "expected vertex:f32x4, got vertex:u32x4");
auto uintExport = request;
uintExport.context.pixel->targetOutputMode[0] = 7;
expectFailure([&] { static_cast<void>(ShaderRecompiler::Recompile(uintExport)); }, "fragment output 0 has no 10_11_11 unorm packing path");
Expand Down Expand Up @@ -6734,6 +6764,12 @@ int main(int argc, char** argv) {
setenv("APS5_HEAP_MIRROR_MIB", "4", 1);
#endif
try {
if (argc == 2 && std::string_view(argv[1]) == "--raw32-integer-exports") {
uint16ExportTests();
raw32IntegerExportTests();
std::cout << "raw32 integer attachment state tests passed\n";
return 0;
}
if (argc == 2 && std::string_view(argv[1]) == "--sparse-buffer-holes") {
bool passed = false;
{
Expand Down Expand Up @@ -6878,6 +6914,7 @@ int main(int argc, char** argv) {
metadataPassTests();
cmaskTests();
uint16ExportTests();
raw32IntegerExportTests();
uint8x4TargetTests();
multisampleTests();
MsaaEnableSingleSampleTests();
Expand Down
8 changes: 8 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,14 @@ void verifyKeySensitivity() {
require(fragment.Key() == fragmentKey && RecompileCacheKey::ContextHash(fragment.request) == fragmentContextKey, "runtime export mapping changed the fragment artifact key");
fragment.request.context.pixel->targetOutputMode[0] = 7;
require(fragment.Key() != fragmentKey, "integer fragment output reused a float interface");
fragment.request.context.pixel->targetOutputMode[0] = 9;
fragment.request.context.pixel->targetOutputType[0] = ColorOutputType::Uint;
const auto uintKey = fragment.Key();
require(uintKey != fragmentKey && RecompileCacheKey::ContextHash(fragment.request) != fragmentContextKey, "raw32 unsigned attachment reused a float interface");
fragment.request.context.pixel->targetOutputType[0] = ColorOutputType::Sint;
require(fragment.Key() != uintKey && fragment.Key() != fragmentKey, "raw32 signed attachment reused an unsigned or float interface");
fragment.request.context.pixel->targetOutputType[0] = ColorOutputType::Float;
require(fragment.Key() == fragmentKey, "explicit float attachment changed the legacy float interface");
}

void verifyFloatModeSerialization() {
Expand Down
Loading
Loading