From dcc642551f5a9b2faf1b9b362c76d6b0c7236328 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 14 Oct 2026 21:52:58 +0200 Subject: [PATCH] graphics: classify signed byte textures for native sampling --- src/graphics/guest_gpu/gpu_format.cpp | 1 + tests/ResourceMaterializationTests.cpp | 4 ++- tests/ShaderRecompilerComputeTests.cpp | 42 ++++++++++++++++++-------- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/graphics/guest_gpu/gpu_format.cpp b/src/graphics/guest_gpu/gpu_format.cpp index f968991ea..fe0adfb8f 100644 --- a/src/graphics/guest_gpu/gpu_format.cpp +++ b/src/graphics/guest_gpu/gpu_format.cpp @@ -23,6 +23,7 @@ constexpr FormatInfo kFormatInfo[] = { {BufferFormat::k8UScaled, 1, 0, 0, true, false}, {BufferFormat::k8SNorm, 1, 0, 1, true, false}, {BufferFormat::k8UInt, 1, 0, 1, true, true}, + {BufferFormat::k8SInt, 1, 0, 1, true, false, true}, {BufferFormat::k16UNorm, 2, 0, 2, true, false}, {BufferFormat::k16SNorm, 2, 0, 2, true, false}, {BufferFormat::k16UInt, 2, 0, 2, true, true}, diff --git a/tests/ResourceMaterializationTests.cpp b/tests/ResourceMaterializationTests.cpp index 38287b704..5106c50a9 100644 --- a/tests/ResourceMaterializationTests.cpp +++ b/tests/ResourceMaterializationTests.cpp @@ -1212,7 +1212,7 @@ void TestSignedStorageSpecialization() { Check(binding && ImageBindingResourceClass(*binding) == ImageResourceClass::Storage, "signed storage conversion did not reuse the unsigned storage binding"); } - for (const auto format : {F::k16SInt, F::k32SInt}) { + for (const auto format : {F::k8SInt, F::k16SInt, F::k32SInt}) { data[0] = uint32_t(format) << 20u; auto &image = plan.info.images[0]; image.read = true; @@ -1232,6 +1232,8 @@ void TestSignedStorageSpecialization() { Check(MaterializeResources(plan, runtime, snapshot, specialization) && specialization.images[0].numeric_class == N::Sint && specialization.images[0].conversion_format == F::kInvalid && + Libs::Graphics::Prospero::NumBytesPerElement(format) == + (format == F::k8SInt ? 1u : format == F::k16SInt ? 2u : 4u) && RawSignedStorageFormat(image, format) == F::kInvalid, "storage conversion changed ordinary signed image reads"); image.resource_class = ImageResourceClass::Storage; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index c6206d6ef..0e9284736 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -35743,28 +35743,41 @@ TestCase ImageLoadFmaskUsesNativeSampleMapping() { return test; } -TestCase ImageLoadR32SintUsesSignedSampledImage() { +template TestCase ImageLoadSintUsesSignedSampledImage() { using O = ShaderOpcode; std::vector code; - AppendVMovU32(&code, 20, 2); - AppendVMovU32(&code, 21, 1); - code.push_back(EncodeMimg0(0x00, 0x1)); - code.push_back(EncodeMimg1(0, 20)); - AppendStoreVgpr(&code, 0, 0); + for (u32 pixel = 0; pixel < (byte ? 4u : 1u); ++pixel) { + AppendVMovU32(&code, 20, byte ? pixel : 2u); + AppendVMovU32(&code, 21, 1); + code.push_back(EncodeMimg0(0x00, 0x1)); + code.push_back(EncodeMimg1(0, 20)); + AppendStoreVgpr(&code, 0, pixel); + } AppendEnd(&code); TestCase test; - test.name = "ImageLoadR32SintUsesSignedSampledImage"; + test.name = byte ? "ImageLoadR8SintUsesSignedSampledImage" + : "ImageLoadR32SintUsesSignedSampledImage"; test.code = code; - test.expected = {0xffffff80u}; + if constexpr (byte) test.expected = {0xffffff80u, 0xffffffffu, 0u, 127u}; + else test.expected = {0xffffff80u}; test.opcodes = {O::V_MOV_B32, O::IMAGE_LOAD, O::BUFFER_STORE_DWORD, O::S_ENDPGM}; - test.sampled_image_rgba.resize(16); - test.sampled_image_rgba[6] = 0xffffff80u; - test.sampled_image_format = vk::Format::eR32Sint; + test.sampled_image_rgba.resize(byte ? 4u : 16u); + if constexpr (byte) test.sampled_image_rgba[1] = 0x7f00ff80u; + else test.sampled_image_rgba[6] = 0xffffff80u; + test.sampled_image_format = byte ? vk::Format::eR8Sint : vk::Format::eR32Sint; test.sampled_image_dwords_per_pixel = 1; - test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32SInt); + constexpr auto format = byte ? Prospero::BufferFormat::k8SInt : Prospero::BufferFormat::k32SInt; + const auto surface = TextureGetSurfaceFormatInfo(format); + Require(test.name, "signed format metadata", + Prospero::NumBytesPerElement(format) == (byte ? 1u : 4u) && + Prospero::SampledTextureNumericClass(format) == Prospero::TextureNumericClass::Sint && + surface.vk_format == test.sampled_image_format && + surface.conversion_format == Prospero::BufferFormat::kInvalid, + "signed sampled image lost its byte width, native mapping or numeric class"); + test.user_data = MakeSampledTextureData(format); test.has_user_data = true; test.required_spirv = {"image_17", "OpTypeImage %int", "OpImageFetch %v4int", "OpBitcast %v4uint"}; @@ -41191,7 +41204,8 @@ std::vector MakeCases() { AddCase(ImageLoadVariants); AddCase(ImageLoadR32UintUsesIntegerSampledImage); AddCase(ImageLoadFmaskUsesNativeSampleMapping); - AddCase(ImageLoadR32SintUsesSignedSampledImage); + AddCase(ImageLoadSintUsesSignedSampledImage); + AddCase(ImageLoadSintUsesSignedSampledImage); AddCase(ImageLoadPackedUintUnpacksAndSwizzles); AddCase(ImageLoadPackedUnorm); AddCase(ImageLoadPackedUnorm); @@ -46856,6 +46870,8 @@ int main(int argc, char **argv) { } if (argc == 2 && std::strcmp(argv[1], "--packed-texture-only") == 0) { VulkanHarness vulkan; + RunCase(&vulkan, ImageLoadSintUsesSignedSampledImage()); + RunCase(&vulkan, ImageLoadSintUsesSignedSampledImage()); vulkan.CheckPackedTextureComponents(); CheckSigned16ImageStore(vulkan); vulkan.CheckBgra16Readback();