diff --git a/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp b/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp index ca0cb4e15..5f0cbf86c 100644 --- a/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp @@ -834,9 +834,38 @@ static bool BuildResourceSpecialization(const ResourcePlan& program, ResourceSna } else if (image.numeric_class == Prospero::TextureNumericClass::Unsupported || (base.depth_compare && image.numeric_class != Prospero::TextureNumericClass::Float)) { - return SpecializationFail( - fmt::format("sampled image descriptor {} uses unsupported format {}", i, - static_cast(format))); + auto message = fmt::format( + "sampled image descriptor {} uses unsupported format {}: root={} source={} " + "first_use_pc={:#x} r128={} words={:08x},{:08x},{:08x},{:08x}," + "{:08x},{:08x},{:08x},{:08x}", + i, static_cast(format), base_index, base.source, base.first_use_pc, + base.r128, descriptor.dwords[0], descriptor.dwords[1], descriptor.dwords[2], + descriptor.dwords[3], descriptor.dwords[4], descriptor.dwords[5], + descriptor.dwords[6], descriptor.dwords[7]); + const auto* source = Source(program, base.source); + if (i >= program.info.images.size() && source != nullptr && + source->indirect_descriptor && + IsBoundedDescriptorTable(program, *source->indirect_descriptor) && + source->indirect_descriptor->table_stride == 0u) { + const auto& indirect = *source->indirect_descriptor; + const size_t mapping = specialization.images[base_index].indirect_mapping_offset; + const auto& flat = snapshot.flattened_srt; + if (mapping < flat.size() && flat[mapping] <= flat.size() - mapping - 1u) { + uint32_t ordinal = 0; + for (size_t child = program.info.images.size(); child <= i; ++child) + ordinal += specialization.images[child].indirect_root == base_index; + uint32_t matches = 0; + uint64_t first_offset = 0; + for (uint32_t probe = 0; probe < flat[mapping]; ++probe) { + if (flat[mapping + 1u + probe] != ordinal) continue; + if (matches++ == 0u) first_offset = uint64_t {probe} * 4u; + } + message += fmt::format(" table_source={} ordinal={} dense_matches={} " + "first_candidate_offset={:#x}", + indirect.table_source, ordinal, matches, first_offset); + } + } + return SpecializationFail(message); } } for (uint32_t root_index = 0; root_index < specialization.images.size(); root_index++) {