From 8ed10d77de31542d62dd28a113908b83128a5116 Mon Sep 17 00:00:00 2001 From: Benjamin Doherty Date: Fri, 8 Aug 2025 11:45:10 -0700 Subject: [PATCH] Begin to refactor test_LoadImage to use SharedShaders --- filament/backend/test/ImageExpectations.cpp | 35 ++++++++-- filament/backend/test/ImageExpectations.h | 64 ++++++++++++++++++- filament/backend/test/SharedShaders.cpp | 32 +++++++++- .../backend/test/SharedShadersConstants.h | 4 +- filament/backend/test/test_LoadImage.cpp | 40 ++++++++---- filament/backend/test/test_MipLevels.cpp | 4 +- .../backend/test/test_RenderExternalImage.cpp | 2 +- 7 files changed, 155 insertions(+), 26 deletions(-) diff --git a/filament/backend/test/ImageExpectations.cpp b/filament/backend/test/ImageExpectations.cpp index 5937ac7f92c2..3b1abeeb8627 100644 --- a/filament/backend/test/ImageExpectations.cpp +++ b/filament/backend/test/ImageExpectations.cpp @@ -36,14 +36,16 @@ namespace test { ScreenshotParams::ScreenshotParams(int width, int height, std::string fileName, - uint32_t expectedHash, bool isSrgb, int numAllowedDeviations, int pixelMatchThreshold) + uint32_t expectedHash, bool isSrgb, int numAllowedDeviations, int pixelMatchThreshold, + std::optional forceAlphaValue) : mWidth(width), mHeight(height), mIsSrgb(isSrgb), mExpectedPixelHash(expectedHash), mFileName(std::move(fileName)), mAllowedPixelDeviations(numAllowedDeviations), - mPixelMatchThreshold(pixelMatchThreshold) {} + mPixelMatchThreshold(pixelMatchThreshold), + mForceAlphaValue(forceAlphaValue) {} int ScreenshotParams::width() const { return mWidth; @@ -61,6 +63,10 @@ uint32_t ScreenshotParams::expectedHash() const { return mExpectedPixelHash; } +std::optional ScreenshotParams::forceAlphaValue() const { + return mForceAlphaValue; +} + std::filesystem::path ScreenshotParams::actualDirectoryPath() { return BackendTest::binaryDirectory().append("images/actual_images"); } @@ -177,9 +183,29 @@ RenderTargetDump::RenderTargetDump(filament::backend::DriverApi& api, const size_t size = mInternal->params.width() * mInternal->params.height() * 4; mInternal->bytes.resize(size); + using filament::backend::PixelDataFormat; + using filament::backend::PixelDataType; + constexpr PixelDataFormat readPixelFormat = PixelDataFormat::RGBA; + constexpr PixelDataType readPixelType = PixelDataType::UBYTE; + auto cb = [](void* buffer, size_t size, void* user) { auto* internal = static_cast(user); internal->bytesFilled = true; + + // If requested, we overwrite the alpha value. + // If the read pixel format or type changes, this logic must be updated. + static_assert(readPixelFormat == PixelDataFormat::RGBA); + static_assert(readPixelType == PixelDataType::UBYTE); + if (auto alphaValue = internal->params.forceAlphaValue(); alphaValue) { + const int pixelCount = internal->params.width() * internal->params.height(); + const int channels = 4; + constexpr int kAlphaChannel = 3; + uint8_t* pixelBuffer = static_cast(buffer); + for (int p = 0; p < pixelCount; p++) { + pixelBuffer[p * channels + kAlphaChannel] = *alphaValue * 255.0f; + } + } + #ifndef FILAMENT_IOS image::LinearImage image; if (internal->params.isSrgb()) { @@ -203,9 +229,8 @@ RenderTargetDump::RenderTargetDump(filament::backend::DriverApi& api, filePath); #endif }; - filament::backend::PixelBufferDescriptor pb(mInternal->bytes.data(), size, - filament::backend::PixelDataFormat::RGBA, filament::backend::PixelDataType::UBYTE, cb, - (void*)mInternal.get()); + filament::backend::PixelBufferDescriptor pb(mInternal->bytes.data(), size, readPixelFormat, + readPixelType, cb, (void*) mInternal.get()); api.readPixels(renderTarget, 0, 0, mInternal->params.width(), mInternal->params.height(), std::move(pb)); } diff --git a/filament/backend/test/ImageExpectations.h b/filament/backend/test/ImageExpectations.h index d96256f3924a..a627d71a2fe7 100644 --- a/filament/backend/test/ImageExpectations.h +++ b/filament/backend/test/ImageExpectations.h @@ -19,6 +19,7 @@ #include #include +#include #include "gtest/gtest.h" @@ -45,12 +46,72 @@ class ScreenshotParams { public: // TODO(b/422804941): Add a set of environments where this test should use a different golden. ScreenshotParams(int width, int height, std::string fileName, uint32_t expectedPixelHash, - bool isSrgb = false, int numAllowedDeviations = 0, int pixelMatchThreshold = 0); + bool isSrgb = false, int numAllowedDeviations = 0, int pixelMatchThreshold = 0, + std::optional forceAlphaValue = std::nullopt); + + class Builder { + public: + Builder& width(int width) { + mWidth = width; + return *this; + } + + Builder& height(int height) { + mHeight = height; + return *this; + } + + Builder& fileName(std::string fileName) { + mFileName = fileName; + return *this; + } + + Builder& expectedPixelHash(uint32_t pixelHash) { + mExpectedPixelHash = pixelHash; + return *this; + } + + Builder& isSrgb(bool isSrgb) { + mIsSrgb = isSrgb; + return *this; + } + + Builder& numAllowedDeviations(int numAllowedDeviations) { + mNumAllowedDeviations = numAllowedDeviations; + return *this; + } + + Builder& pixelMatchTheshold(int pixelMatchTheshold) { + mPixelMatchThreshold = pixelMatchTheshold; + return *this; + } + + Builder& forceAlphaValue(float alphaValue) { + mForceAlphaValue = alphaValue; + return *this; + } + + ScreenshotParams build() { + return ScreenshotParams(mWidth, mHeight, mFileName, mExpectedPixelHash, mIsSrgb, + mNumAllowedDeviations, mPixelMatchThreshold, mForceAlphaValue); + } + + private: + int mWidth; + int mHeight; + std::string mFileName; + uint32_t mExpectedPixelHash; + bool mIsSrgb; + int mNumAllowedDeviations; + int mPixelMatchThreshold; + std::optional mForceAlphaValue; + }; int width() const; int height() const; bool isSrgb() const; uint32_t expectedHash() const; + std::optional forceAlphaValue() const; static std::filesystem::path actualDirectoryPath(); std::string actualFileName() const; @@ -70,6 +131,7 @@ class ScreenshotParams { std::string mFileName; int mAllowedPixelDeviations; int mPixelMatchThreshold; + std::optional mForceAlphaValue; }; /** diff --git a/filament/backend/test/SharedShaders.cpp b/filament/backend/test/SharedShaders.cpp index 02c6762c7d7b..c441a5594032 100644 --- a/filament/backend/test/SharedShaders.cpp +++ b/filament/backend/test/SharedShaders.cpp @@ -158,9 +158,19 @@ layout(binding = 0, set = 0) uniform Params { } params; )"; } - case ShaderUniformType::Sampler: { + case ShaderUniformType::Sampler2D: { return R"( layout(location = 0, set = 0) uniform sampler2D test_tex; +)"; + } + case ShaderUniformType::ISampler2D: { + return R"( +layout(location = 0, set = 0) uniform isampler2D test_tex; +)"; + } + case ShaderUniformType::USampler2D: { + return R"( +layout(location = 0, set = 0) uniform usampler2D test_tex; )"; } default: @@ -179,7 +189,7 @@ std::vector GetUniformConfig(ShaderUniformType type) { case ShaderUniformType::SimpleWithPadding: { return {{ "Params" }}; } - case ShaderUniformType::Sampler: { + case ShaderUniformType::Sampler2D: { filament::SamplerInterfaceBlock::SamplerInfo samplerInfo{ "backend_test", "test_tex", 0, SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH, false }; @@ -187,6 +197,22 @@ std::vector GetUniformConfig(ShaderUniformType type) { "test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo }}; } + case ShaderUniformType::ISampler2D: { + filament::SamplerInterfaceBlock::SamplerInfo samplerInfo{ + "backend_test", "test_tex", 0, + SamplerType::SAMPLER_2D, SamplerFormat::INT, Precision::HIGH, false }; + return {{ + "test_tex", DescriptorType::SAMPLER_2D_INT, samplerInfo + }}; + } + case ShaderUniformType::USampler2D: { + filament::SamplerInterfaceBlock::SamplerInfo samplerInfo{ + "backend_test", "test_tex", 0, + SamplerType::SAMPLER_2D, SamplerFormat::UINT, Precision::HIGH, false }; + return {{ + "test_tex", DescriptorType::SAMPLER_2D_INT, samplerInfo + }}; + } default: abort(); } @@ -252,4 +278,4 @@ std::string SharedShaders::getFragmentShaderText(FragmentShaderType fragment, return fragmentText->withUniform(*uniformText); } -} // namespace test \ No newline at end of file +} // namespace test diff --git a/filament/backend/test/SharedShadersConstants.h b/filament/backend/test/SharedShadersConstants.h index 742580d3eba2..990b6ec6735c 100644 --- a/filament/backend/test/SharedShadersConstants.h +++ b/filament/backend/test/SharedShadersConstants.h @@ -23,7 +23,9 @@ enum class ShaderUniformType : uint8_t { None, Simple, SimpleWithPadding, - Sampler, + Sampler2D, + ISampler2D, + USampler2D, }; struct SimpleMaterialParams { diff --git a/filament/backend/test/test_LoadImage.cpp b/filament/backend/test/test_LoadImage.cpp index fb5940d50ff5..ffd08e532231 100644 --- a/filament/backend/test/test_LoadImage.cpp +++ b/filament/backend/test/test_LoadImage.cpp @@ -287,9 +287,9 @@ TEST_F(LoadImageTest, UpdateImage2D) { // Test integer format uploads. // TODO: These cases fail on OpenGL and Vulkan. // TODO: These cases now also fail on Metal, but at some point previously worked. - testCases.emplace_back("RGB_INTEGER UBYTE to RGB8UI", PixelDataFormat::RGB_INTEGER, PixelDataType::UBYTE, TextureFormat::RGB8UI); - testCases.emplace_back("RGB_INTEGER USHORT to RGB16UI", PixelDataFormat::RGB_INTEGER, PixelDataType::USHORT, TextureFormat::RGB16UI); - testCases.emplace_back("RGB_INTEGER INT to RGB32I", PixelDataFormat::RGB_INTEGER, PixelDataType::INT, TextureFormat::RGB32I); + testCases.emplace_back("RGB_INTEGER UBYTE to RGB8UI", PixelDataFormat::RGB_INTEGER, PixelDataType::UBYTE, TextureFormat::RGB8UI); + testCases.emplace_back("RGB_INTEGER USHORT to RGB16UI", PixelDataFormat::RGB_INTEGER, PixelDataType::USHORT, TextureFormat::RGB16UI); + testCases.emplace_back("RGB_INTEGER INT to RGB32I", PixelDataFormat::RGB_INTEGER, PixelDataType::INT, TextureFormat::RGB32I); // Test uploads with buffer padding. // TODO: Vulkan crashes with "Assertion failed: (offset + size <= allocationSize)" @@ -319,14 +319,23 @@ TEST_F(LoadImageTest, UpdateImage2D) { auto defaultRenderTarget = cleanup.add(api.createDefaultRenderTarget(0)); // Create a program. - filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "test", "tex", 0, - SamplerType::SAMPLER_2D, getSamplerFormat(t.textureFormat), Precision::HIGH, false }; - - std::string const fragment = getFormattedFragment(fragmentTemplate, t.textureFormat); - Shader shader(api, cleanup, ShaderConfig{ - .vertexShader = mVertexShader, - .fragmentShader= fragment, - .uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo}} + ShaderUniformType uniformType; + switch (getSamplerFormat(t.textureFormat)) { + case SamplerFormat::FLOAT: + case SamplerFormat::SHADOW: // not used for tests, but must cover all cases + uniformType = ShaderUniformType::Sampler2D; + break; + case SamplerFormat::INT: + uniformType = ShaderUniformType::ISampler2D; + break; + case SamplerFormat::UINT: + uniformType = ShaderUniformType::USampler2D; + break; + } + Shader shader = SharedShaders::makeShader(api, cleanup, { + .mVertexType = VertexShaderType::Textured, + .mFragmentType = FragmentShaderType::Textured, + .mUniformType = uniformType, }); // Create a Texture. @@ -374,8 +383,13 @@ TEST_F(LoadImageTest, UpdateImage2D) { api.draw2(0, 3, 1); api.endRenderPass(); - EXPECT_IMAGE(defaultRenderTarget, - ScreenshotParams(kTexSize, kTexSize, t.name, expectedHash)); + EXPECT_IMAGE(defaultRenderTarget, ScreenshotParams::Builder() + .width(kTexSize) + .height(kTexSize) + .fileName(t.name) + .expectedPixelHash(expectedHash) + .forceAlphaValue(1.0f) + .build()); api.commit(swapChain); api.endFrame(0); diff --git a/filament/backend/test/test_MipLevels.cpp b/filament/backend/test/test_MipLevels.cpp index 876aab0a60ed..b0c05bbbddb1 100644 --- a/filament/backend/test/test_MipLevels.cpp +++ b/filament/backend/test/test_MipLevels.cpp @@ -69,12 +69,12 @@ TEST_F(BackendTest, TextureViewLod) { Shader whiteShader = SharedShaders::makeShader(api, cleanup, ShaderRequest { .mVertexType = VertexShaderType::Textured, .mFragmentType = FragmentShaderType::White, - .mUniformType = ShaderUniformType::Sampler + .mUniformType = ShaderUniformType::Sampler2D }); // Create a program that samples a texture. std::string vertexShader = SharedShaders::getVertexShaderText( - VertexShaderType::Textured, ShaderUniformType::Sampler); + VertexShaderType::Textured, ShaderUniformType::Sampler2D); filament::SamplerInterfaceBlock::SamplerInfo samplerInfo { "backend_test", "sib_tex", 0, SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH, false }; diff --git a/filament/backend/test/test_RenderExternalImage.cpp b/filament/backend/test/test_RenderExternalImage.cpp index cad0c896cd37..b93181c03d37 100644 --- a/filament/backend/test/test_RenderExternalImage.cpp +++ b/filament/backend/test/test_RenderExternalImage.cpp @@ -40,7 +40,7 @@ Shader createShader(DriverApi& api, Cleanup& cleanup, Backend backend) { return SharedShaders::makeShader(api, cleanup, ShaderRequest{ .mVertexType = VertexShaderType::Textured, .mFragmentType = FragmentShaderType::Textured, - .mUniformType = ShaderUniformType::Sampler + .mUniformType = ShaderUniformType::Sampler2D }); }