From 7e4e142aaebd2a5169ac73cb1a91b6c8d6fe2a7f Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 11 Oct 2026 00:00:23 +0200 Subject: [PATCH] gpu: enable native R8 SNORM texture sampling --- src/graphics/guest_gpu/gpu_format.cpp | 2 +- tests/ShaderRecompilerComputeTests.cpp | 52 ++++++++++++++++---------- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/graphics/guest_gpu/gpu_format.cpp b/src/graphics/guest_gpu/gpu_format.cpp index 44f11ffe..8a89bdbe 100644 --- a/src/graphics/guest_gpu/gpu_format.cpp +++ b/src/graphics/guest_gpu/gpu_format.cpp @@ -21,7 +21,7 @@ struct FormatInfo { constexpr FormatInfo kFormatInfo[] = { {BufferFormat::k8UNorm, 1, 0, 1, true, false}, {BufferFormat::k8UScaled, 1, 0, 0, true, false}, - {BufferFormat::k8SNorm, 1, 0, 1, false, false}, + {BufferFormat::k8SNorm, 1, 0, 1, true, false}, {BufferFormat::k8UInt, 1, 0, 1, true, true}, {BufferFormat::k16UNorm, 2, 0, 2, true, false}, {BufferFormat::k16SNorm, 2, 0, 2, true, false}, diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index bb6d3339..6b77f72b 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -34170,10 +34170,11 @@ TestCase ImageSamplePackedUintConvertsSampleAndGather() { return test; } -template TestCase ImageSampleUScaled8() { +template TestCase ImageSamplePacked8() { using O = ShaderOpcode; TestCase test; - test.name = rg ? "ImageSampleRG8UScaled" : "ImageSampleR8UScaled"; + test.name = snorm ? "ImageSampleR8SNorm" + : rg ? "ImageSampleRG8UScaled" : "ImageSampleR8UScaled"; AppendVMovLiteral(&test.code, 20, std::bit_cast(0.375f)); AppendVMovLiteral(&test.code, 21, std::bit_cast(0.375f)); test.code.push_back(EncodeMimg0(0x20, 0xf)); @@ -34186,26 +34187,37 @@ template TestCase ImageSampleUScaled8() { AppendStoreVgpr(&test.code, component, component); } AppendEnd(&test.code); - // R varies horizontally; G varies vertically in the opposite direction. - // Bilinear samples must retain fractions despite host UNorm filter precision. test.image_width = test.image_height = 2; - test.sampled_image_rgba = rg ? std::vector{0xffffff00u, 0x00ff0000u} - : std::vector{0xff00ff00u}; - test.sampled_image_format = rg ? vk::Format::eR8G8Unorm : vk::Format::eR8Unorm; + test.sampled_image_rgba = + snorm ? std::vector{0x7fc08180u} + : rg ? std::vector{0xffffff00u, 0x00ff0000u} + : std::vector{0xff00ff00u}; + test.sampled_image_format = + snorm ? vk::Format::eR8Snorm + : rg ? vk::Format::eR8G8Unorm : vk::Format::eR8Unorm; test.sampled_image_dwords_per_pixel = 1; - test.sampler_filter = vk::Filter::eLinear; - test.expected_float_tolerance = 0.01f; - test.user_data = MakeSampledTextureData(rg ? Prospero::BufferFormat::k8_8UScaled - : Prospero::BufferFormat::k8UScaled); + test.sampler_filter = snorm ? vk::Filter::eNearest : vk::Filter::eLinear; + test.expected_float_tolerance = snorm ? 0.00002f : 0.01f; + test.user_data = MakeSampledTextureData( + snorm ? Prospero::BufferFormat::k8SNorm + : rg ? Prospero::BufferFormat::k8_8UScaled + : Prospero::BufferFormat::k8UScaled); test.user_data[1] |= 1u << 30u; test.user_data[2] = 1u << 14u; test.user_data[50] = 12u * sizeof(u32); test.user_data[51] = 3u << 28u; test.has_user_data = true; - test.image_descriptor_swizzle = DstSel(rg ? 5 : 4, 4, 0, 1); - for (float value : {rg ? 191.25f : 63.75f, 63.75f, 0.0f, 1.0f, - 0.0f, rg ? 0.0f : 255.0f, 255.0f, rg ? 255.0f : 0.0f, - 1.0f, 1.0f, 1.0f, 1.0f}) { + test.image_descriptor_swizzle = snorm ? DstSel(4, 5, 6, 7) + : DstSel(rg ? 5 : 4, 4, 0, 1); + constexpr float midpoint = -64.0f / 127.0f; + const std::array expected = snorm + // -128 and -127 both clamp to -1; the interior signed value normalizes by 127. + ? std::array{-1, 0, 0, 1, midpoint, 1, -1, -1, 1, 1, 1, 1} + // R varies horizontally; G varies vertically in the opposite direction. + : std::array{rg ? 191.25f : 63.75f, 63.75f, 0.0f, 1.0f, + 0.0f, rg ? 0.0f : 255.0f, 255.0f, rg ? 255.0f : 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f}; + for (float value : expected) { test.expected.push_back(std::bit_cast(value)); } test.opcodes = {O::V_MOV_B32, O::IMAGE_SAMPLE, O::IMAGE_GATHER4_LZ, @@ -37565,8 +37577,9 @@ std::vector MakeCases() { AddCase(ImageLoadR32SintUsesSignedSampledImage); AddCase(ImageLoadPackedUintUnpacksAndSwizzles); AddCase(ImageSamplePackedUintConvertsSampleAndGather); - AddCase(ImageSampleUScaled8); - AddCase(ImageSampleUScaled8); + AddCase(ImageSamplePacked8); + AddCase(ImageSamplePacked8); + AddCase(ImageSamplePacked8); AddCase(ImageLoadR128IgnoresAdjacentMaskSgprs); AddCase(ImageLoad1DUsesScalarCoordinate); AddCase(ImageGather2DInstructionWith1DDescriptor); @@ -43136,8 +43149,9 @@ int main(int argc, char **argv) { } if (argc == 2 && std::strcmp(argv[1], "--scaled-texture-only") == 0) { VulkanHarness vulkan; - RunCase(&vulkan, ImageSampleUScaled8()); - RunCase(&vulkan, ImageSampleUScaled8()); + RunCase(&vulkan, ImageSamplePacked8()); + RunCase(&vulkan, ImageSamplePacked8()); + RunCase(&vulkan, ImageSamplePacked8()); return 0; } if (argc == 2 && std::strcmp(argv[1], "--packed-texture-only") == 0) {