diff --git a/src/graphics/shader/recompiler/ResourceMaterialization.cpp b/src/graphics/shader/recompiler/ResourceMaterialization.cpp index 85c21fe..ec5c314 100644 --- a/src/graphics/shader/recompiler/ResourceMaterialization.cpp +++ b/src/graphics/shader/recompiler/ResourceMaterialization.cpp @@ -28,6 +28,10 @@ bool NullImageDescriptor(const DescriptorValue& descriptor) { return descriptor.dwords[0] == 0 && (descriptor.dwords[1] & 0xffu) == 0; } +bool ValidImageDescriptor(const DescriptorValue& descriptor) { + return ((descriptor.dwords[3] >> 28u) & 0x8u) != 0; +} + uint32_t DescriptorImageSwizzle(const DescriptorValue& descriptor) { return descriptor.dwords[3] & 0xfffu; } @@ -223,6 +227,11 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime, cursor += program.info.buffers.size(); next.images.assign(cursor, cursor + program.info.images.size()); cursor += program.info.images.size(); + for (auto& descriptor: next.images) { + if (!ValidImageDescriptor(descriptor)) { + descriptor.dwords.fill(0); + } + } next.samplers.assign(cursor, cursor + program.info.samplers.size()); cursor += program.info.samplers.size(); for (const auto& address: program.info.addresses) { diff --git a/tests/ResourceTrackingTests.cpp b/tests/ResourceTrackingTests.cpp index a32311c..4367aa0 100644 --- a/tests/ResourceTrackingTests.cpp +++ b/tests/ResourceTrackingTests.cpp @@ -913,6 +913,8 @@ void TestMaterializationSharesReadConstEvaluation() { for (uint32_t i = 0; i < memory.words.size(); i++) { memory.words[i] = 0x100 + i; } + memory.words[3] |= + Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) << 28u; std::array user_data{}; user_data[16] = static_cast(memory.base); user_data[17] = static_cast(memory.base >> 32u); @@ -938,6 +940,60 @@ void TestMaterializationSharesReadConstEvaluation() { } } +void TestInvalidImagesMaterializeAsNull() { + Program sampled; + sampled.stage = ShaderType::Pixel; + sampled.user_data_count = 8; + sampled.blocks.resize(1); + sampled.blocks[0].instructions = { + ImageUse(0x40, Opcode::ImageLoad, ResourceKind::Image, + Decoder::ImageDimension::Dim2D)}; + Prepare(&sampled); + Check(sampled.info.images.size() == 1 && sampled.info.samplers.empty(), + "sampled-image normalization test has unexpected resource topology"); + + constexpr std::array stale = { + 0x00000004, 0x00000004, 0xc0061060, 0x06000514, + 0x20010000, 0xa4580290, 0x00000004, 0x00000001}; + std::string error; + for (uint32_t type = 0; type < 8; type++) { + auto descriptor = stale; + descriptor[3] = (descriptor[3] & 0x0fffffffu) | (type << 28u); + ResourceSnapshot snapshot; + Check(MaterializeResources(sampled, {descriptor}, &snapshot, &error) && + snapshot.images.size() == 1 && + std::all_of(snapshot.images[0].dwords.begin(), + snapshot.images[0].dwords.end(), + [](uint32_t word) { return word == 0; }) && + ValidateResourceSpecialization(sampled, snapshot, &error), + error.c_str()); + } + + auto valid = stale; + valid[3] = (valid[3] & 0x0fffffffu) | + (Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) << 28u); + ResourceSnapshot valid_snapshot; + Check(MaterializeResources(sampled, {valid}, &valid_snapshot, &error) && + std::equal(valid.begin(), valid.end(), + valid_snapshot.images[0].dwords.begin()), + "valid sampled image descriptor was normalized"); + + Program storage; + storage.stage = ShaderType::Compute; + storage.user_data_count = 8; + storage.blocks.resize(1); + storage.blocks[0].instructions = { + ImageUse(0x40, Opcode::ImageStore, ResourceKind::StorageImage, + Decoder::ImageDimension::Dim2D)}; + Prepare(&storage); + ResourceSnapshot storage_snapshot; + Check(MaterializeResources(storage, {stale}, &storage_snapshot, &error) && + std::all_of(storage_snapshot.images[0].dwords.begin(), + storage_snapshot.images[0].dwords.end(), + [](uint32_t word) { return word == 0; }), + "invalid storage image descriptor was not normalized to null"); +} + void TestMaterializationFailureIsTransactional() { Program program; program.blocks.resize(1); @@ -1756,6 +1812,7 @@ int main() { RUN(TestSrtPatchingHandlesCfgProducers); RUN(TestSrtPatchPlanValidation); RUN(TestMaterializationSharesReadConstEvaluation); + RUN(TestInvalidImagesMaterializeAsNull); RUN(TestMaterializationFailureIsTransactional); RUN(TestResourceSpecializationIsTypedAndTransactional); RUN(TestRuntimeSpecializationCoversBakedBufferAndAddressFields);