diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp index 1ee82cd53..c4c68bb3d 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp @@ -220,6 +220,10 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, Prospero::TextureNumericClass numeric_class, bool dref, const IR::MemoryInfo& mem, bool gather = false) { auto value_class = numeric_class; + const auto conversion = ctx.state.program.info.images[mem.resource].conversion_format; + if (conversion != Prospero::BufferFormat::kInvalid) { + value_class = Prospero::SampledTextureNumericClass(conversion); + } if (dref) { value_class = Prospero::TextureNumericClass::Float; } @@ -425,6 +429,8 @@ uint32_t UnpackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint if (info.packed_bitfield) { components[component] = ExtractPackedImageComponent(ctx.state, info, packed, scalar_type, component); + components[component] = + NormalizeFormatComponent(ctx.state, info, component, components[component]); } else { components[component] = ctx.state.builder.AllocateId(); ctx.state.builder.AddFunction(spv::OpCompositeExtract, scalar_type, @@ -443,8 +449,9 @@ uint32_t UnpackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint for (uint32_t component = 0; component < 4u; component++) { const auto selector = (swizzle >> (component * 3u)) & 7u; if (selector == 1u) { - selected[component] = info.packed_bitfield ? ConstantU32(ctx.state, 1u) - : ConstantF32Value(ctx.state, 1.0f); + selected[component] = info.packed_bitfield + ? ConstantU32(ctx.state, Format::FormattedConstantBits(info, Format::FormattedSourceKind::One)) + : ConstantF32Value(ctx.state, 1.0f); } else if (selector >= 4u) { selected[component] = components[selector - 4u]; } else { @@ -456,7 +463,8 @@ uint32_t UnpackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint ctx.state.builder.AddFunction(spv::OpCompositeConstruct, ImageVectorType(ctx.state, numeric_class, 4), result, selected[0], selected[1], selected[2], selected[3]); - return result; + return info.type == Format::ComponentType::Unorm + ? Unary(ctx.state, spv::OpBitcast, TypeF32Vector(ctx.state, 4), result) : result; } uint32_t UnpackImageGather(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32_t gathered) { @@ -840,7 +848,7 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) { ctx.Define(inst, QueryDimensions(ctx, mem, *address)); return; } - if (image.resource_class == IR::ImageResourceClass::Sampled && + if (image_info.needs_sampler && image.conversion_format == Prospero::BufferFormat::k11_11_10UNorm) { if (op != IR::ValueOpcode::ImageSampleRaw || image.dimension != ImageDimension::Dim2D || diff --git a/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp b/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp index 3162f5519..58d298185 100644 --- a/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp @@ -716,7 +716,9 @@ static bool BuildResourceSpecialization(const ResourcePlan& program, ResourceSna if (image.indirect_root != ImageResource::NoIndirectImage) { return SpecializationFail("packed UNorm sampling requires a direct image"); } - if (!ValidatePackedUnormSampling(program, snapshot, i)) return false; + if (std::ranges::any_of(program.info.sampled_pairs, + [&](const auto& pair) { return pair.image == i; }) && + !ValidatePackedUnormSampling(program, snapshot, i)) return false; } if (storage) { if ((!raw_sint_storage && image.numeric_class == Prospero::TextureNumericClass::Sint) || diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 585244c0a..c166bc347 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -34986,6 +34986,36 @@ TestCase ImageLoadPackedUintUnpacksAndSwizzles() { return test; } +template TestCase ImageLoadPackedUnorm() { + TestCase test; + test.opcodes = {ShaderOpcode::V_MOV_B32, ShaderOpcode::IMAGE_LOAD, + ShaderOpcode::BUFFER_STORE_DWORD, ShaderOpcode::S_ENDPGM}; + test.name = d16 ? (sparse ? "ImageLoadPackedUnormD16Sparse" : "ImageLoadPackedUnormD16") + : (sparse ? "ImageLoadPackedUnormSparse" : "ImageLoadPackedUnorm"); + AppendVMovU32(&test.code, 20, 2u); + AppendVMovU32(&test.code, 21, 1u); + test.code.push_back(EncodeMimg0(0x00u, sparse ? 0x5u : 0xfu)); + test.code.push_back(EncodeMimg1(0, 20, 0, 0, false, d16)); + constexpr u32 words = (sparse ? 2u : 4u) / (d16 ? 2u : 1u); + for (u32 word = 0; word < words; ++word) AppendStoreVgpr(&test.code, word, word); + AppendEnd(&test.code); + test.sampled_image_rgba.assign(16, 0u); + test.sampled_image_rgba[6] = (1024u << 11u) | (1023u << 22u); + test.sampled_image_format = vk::Format::eR32Uint; + test.sampled_image_dwords_per_pixel = 1; + test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k11_11_10UNorm); + test.has_user_data = true; + test.image_descriptor_swizzle = sparse ? DstSel(1, 4, 5, 0) : DstSel(6, 5, 4, 7); + const u32 green = std::bit_cast(1024.0f * (1.0f / 2047.0f)); + test.expected = d16 ? std::vector{0x38013c00u, 0u} + : std::vector{0x3f800000u, green, 0u, 0u}; + test.expected.resize(words); + test.required_spirv = {"OpImageFetch %v4uint", "OpBitFieldUExtract", "OpConvertUToF"}; + if constexpr (d16) test.required_spirv.emplace_back("PackHalf2x16"); + test.forbidden_spirv = {"OpTypeSampler", "OpImageGather"}; + return test; +} + TestCase ImageSamplePackedUintConvertsSampleAndGather() { using O = ShaderOpcode; @@ -39429,6 +39459,10 @@ std::vector MakeCases() { AddCase(ImageLoadFmaskUsesNativeSampleMapping); AddCase(ImageLoadR32SintUsesSignedSampledImage); AddCase(ImageLoadPackedUintUnpacksAndSwizzles); + AddCase(ImageLoadPackedUnorm); + AddCase(ImageLoadPackedUnorm); + AddCase(ImageLoadPackedUnorm); + AddCase(ImageLoadPackedUnorm); AddCase(ImageSamplePackedUintConvertsSampleAndGather); AddCase(ImageSamplePackedUnormBilinear); AddCase(ImageSamplePackedUnormBilinear); @@ -45078,6 +45112,10 @@ int main(int argc, char **argv) { vulkan.CheckPackedTextureComponents(); vulkan.CheckBgra16Readback(); RunCase(&vulkan, ImageLoadPackedUintUnpacksAndSwizzles()); + RunCase(&vulkan, ImageLoadPackedUnorm()); + RunCase(&vulkan, ImageLoadPackedUnorm()); + RunCase(&vulkan, ImageLoadPackedUnorm()); + RunCase(&vulkan, ImageLoadPackedUnorm()); RunCase(&vulkan, ImageSamplePackedUintConvertsSampleAndGather()); RunCase(&vulkan, ImageSamplePackedUnormBilinear()); RunCase(&vulkan, ImageSamplePackedUnormBilinear());