Compare commits

...

1 Commits

Author SHA1 Message Date
Benjamin Doherty
8ed10d77de Begin to refactor test_LoadImage to use SharedShaders 2025-08-12 17:39:26 -04:00
7 changed files with 155 additions and 26 deletions

View File

@@ -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<float> 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<float> 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<RenderTargetDump::Internal*>(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<uint8_t*>(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));
}

View File

@@ -19,6 +19,7 @@
#include <filesystem>
#include <vector>
#include <optional>
#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<float> 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<float> mForceAlphaValue;
};
int width() const;
int height() const;
bool isSrgb() const;
uint32_t expectedHash() const;
std::optional<float> forceAlphaValue() const;
static std::filesystem::path actualDirectoryPath();
std::string actualFileName() const;
@@ -70,6 +131,7 @@ private:
std::string mFileName;
int mAllowedPixelDeviations;
int mPixelMatchThreshold;
std::optional<float> mForceAlphaValue;
};
/**

View File

@@ -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<UniformConfig> 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<UniformConfig> 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
} // namespace test

View File

@@ -23,7 +23,9 @@ enum class ShaderUniformType : uint8_t {
None,
Simple,
SimpleWithPadding,
Sampler,
Sampler2D,
ISampler2D,
USampler2D,
};
struct SimpleMaterialParams {

View File

@@ -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);

View File

@@ -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 };

View File

@@ -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
});
}