Use EXPECT_IMAGE in all backend tests. (#8628)

This commit is contained in:
Matthew Hoffman
2025-04-21 19:57:40 -05:00
committed by GitHub
parent 6dac384bd9
commit cfc4f34c18
44 changed files with 123 additions and 241 deletions
+4 -46
View File
@@ -55,14 +55,17 @@ void BackendTest::init(Backend backend, OperatingSystem operatingSystem, bool is
BackendTest::BackendTest() : commandBufferQueue(CONFIG_MIN_COMMAND_BUFFERS_SIZE,
CONFIG_COMMAND_BUFFERS_SIZE, /*mPaused=*/false) {
initializeDriver();
mImageExpectations.emplace(getDriverApi());
}
BackendTest::~BackendTest() {
// Ensure all graphics commands and callbacks are finished.
flushAndWait();
mImageExpectations->evaluate();
// Note: Don't terminate the driver for OpenGL, as it wipes away the context and removes the buffer from the screen.
if (sBackend == Backend::OPENGL) {
return;
}
flushAndWait();
driver->terminate();
delete driver;
}
@@ -156,51 +159,6 @@ void BackendTest::renderTriangle(
api.endRenderPass();
}
void BackendTest::readPixelsAndAssertHash(const char* testName, size_t width, size_t height,
Handle<HwRenderTarget> rt, uint32_t expectedHash, bool exportScreenshot) {
void* buffer = calloc(1, width * height * 4);
struct Capture {
uint32_t expectedHash;
char* name;
bool exportScreenshot;
size_t width, height;
};
auto* c = new Capture();
c->expectedHash = expectedHash;
c->name = strdup(testName);
c->exportScreenshot = exportScreenshot;
c->width = width;
c->height = height;
PixelBufferDescriptor pbd(buffer, width * height * 4, PixelDataFormat::RGBA, PixelDataType::UBYTE,
1, 0, 0, width, [](void* buffer, size_t size, void* user) {
auto* c = (Capture*)user;
// Export a screenshot, if requested.
if (c->exportScreenshot) {
#ifndef FILAMENT_IOS
LinearImage image(c->width, c->height, 4);
image = toLinearWithAlpha<uint8_t>(c->width, c->height, c->width * 4,
(uint8_t*) buffer);
const std::string png = std::string(c->name) + ".png";
std::ofstream outputStream(png.c_str(), std::ios::binary | std::ios::trunc);
ImageEncoder::encode(outputStream, ImageEncoder::Format::PNG, image, "",
png);
#endif
}
// Hash the contents of the buffer and check that they match.
uint32_t hash = utils::hash::murmur3((const uint32_t*) buffer, size / 4, 0);
ASSERT_EQ(hash, c->expectedHash) << c->name << " failed: hashes do not match." << std::endl;
free(buffer);
free(c->name);
free(c);
}, (void*)c);
getDriverApi().readPixels(rt, 0, 0, width, height, std::move(pbd));
}
bool BackendTest::matchesEnvironment(Backend backend) {
return sBackend == backend;
}
+7 -5
View File
@@ -25,6 +25,7 @@
#include "private/backend/DriverApi.h"
#include "PlatformRunner.h"
#include "ImageExpectations.h"
namespace test {
@@ -65,17 +66,14 @@ protected:
filament::backend::Handle<filament::backend::HwProgram> program,
const filament::backend::RenderPassParams& params);
void readPixelsAndAssertHash(const char* testName, size_t width, size_t height,
filament::backend::Handle<filament::backend::HwRenderTarget> rt, uint32_t expectedHash,
bool exportScreenshot = false);
filament::backend::DriverApi& getDriverApi() { return *commandStream; }
filament::backend::Driver& getDriver() { return *driver; }
ImageExpectations& getExpectations() { return *mImageExpectations; }
static bool matchesEnvironment(Backend backend);
static bool matchesEnvironment(OperatingSystem operatingSystem);
static bool matchesEnvironment(OperatingSystem operatingSystem, Backend backend);
private:
filament::backend::Driver* driver = nullptr;
@@ -83,6 +81,10 @@ private:
std::unique_ptr<filament::backend::DriverApi> commandStream;
filament::backend::Handle<filament::backend::HwBufferObject> uniform;
// This isn't truly optional, it just needs to delay construction until after the driver has
// been initialized
std::optional<ImageExpectations> mImageExpectations;
};
} // namespace test
+18 -15
View File
@@ -97,16 +97,21 @@ void ImageExpectation::evaluate() {
void ImageExpectation::compareImage() const {
bool bytesFilled = mResult.bytesFilled();
// If this fails, it likely means that BackendTest::flushAndWait needs to be called before
// ImageExpectations is evaluated or destroyed.
EXPECT_THAT(bytesFilled, testing::IsTrue())
<< "Render target wasn't copied to the buffer for " << mFileName;
if (bytesFilled) {
LoadedPng loadedImage(mParams.expectedFilePath());
// Rather than directly compare the two images compare their hashes because comparing very
// large arrays generates way too much debug output to be useful.
uint32_t actualHash = mResult.hash();
#ifndef FILAMENT_IOS
LoadedPng loadedImage(mParams.expectedFilePath());
uint32_t loadedImageHash = loadedImage.hash();
EXPECT_THAT(actualHash, testing::Eq(loadedImageHash));
EXPECT_THAT(actualHash, testing::Eq(mParams.expectedHash()));
EXPECT_THAT(actualHash, testing::Eq(loadedImageHash)) << mParams.expectedFileName();
#endif
// For builds that can't load PNGs (currently iOS only) use the expected hash.
EXPECT_THAT(actualHash, testing::Eq(mParams.expectedHash())) << mParams.expectedFileName();
// TODO: Add better debug output, such as generating a diff image.
}
}
@@ -121,12 +126,13 @@ ImageExpectations::~ImageExpectations() {
void ImageExpectations::addExpectation(const char* fileName, int lineNumber,
filament::backend::RenderTargetHandle renderTarget, ScreenshotParams params) {
mExpectations.emplace_back(fileName, lineNumber, mApi, std::move(params), renderTarget);
mExpectations.emplace_back(std::make_unique<ImageExpectation>(fileName, lineNumber, mApi,
std::move(params), renderTarget));
}
void ImageExpectations::evaluate() {
for (auto& expectation: mExpectations) {
expectation.evaluate();
expectation->evaluate();
}
mExpectations.clear();
}
@@ -134,16 +140,13 @@ void ImageExpectations::evaluate() {
RenderTargetDump::RenderTargetDump(filament::backend::DriverApi& api,
filament::backend::RenderTargetHandle renderTarget, const ScreenshotParams& params)
: mInternal(std::make_unique<RenderTargetDump::Internal>(params)) {
#ifdef FILAMENT_IOS
bytesFilled_ = true;
bytes_.resize(size);
std::fill(bytes_.begin(), bytes_.end(), 0);
#else
const size_t size = mInternal->params.width() * mInternal->params.height() * 4;
mInternal->bytes.resize(size);
auto cb = [](void* buffer, size_t size, void* user) {
auto* internal = static_cast<RenderTargetDump::Internal*>(user);
internal->bytesFilled = true;
#ifndef FILAMENT_IOS
image::LinearImage image(internal->params.width(), internal->params.width(), 4);
image = image::toLinearWithAlpha<uint8_t>(internal->params.width(),
internal->params.height(),
@@ -152,14 +155,13 @@ RenderTargetDump::RenderTargetDump(filament::backend::DriverApi& api,
std::ofstream pngStream(filePath, std::ios::binary | std::ios::trunc);
image::ImageEncoder::encode(pngStream, image::ImageEncoder::Format::PNG, image, "",
filePath);
internal->bytesFilled = true;
#endif
};
filament::backend::PixelBufferDescriptor pb(mInternal->bytes.data(), size,
filament::backend::PixelDataFormat::RGBA, filament::backend::PixelDataType::UBYTE, cb,
(void*)mInternal.get());
api.readPixels(renderTarget, 0, 0, mInternal->params.width(), mInternal->params.height(),
std::move(pb));
#endif
}
RenderTargetDump::~RenderTargetDump() {
@@ -183,9 +185,9 @@ bool RenderTargetDump::bytesFilled() const {
RenderTargetDump::Internal::Internal(const ScreenshotParams& params) : params(params) {}
LoadedPng::LoadedPng(std::string filePath) {
LoadedPng::LoadedPng(std::string filePath) : mFilePath(std::move(filePath)) {
#ifndef FILAMENT_IOS
std::ifstream pngStream(filePath, std::ios::binary);
std::ifstream pngStream(mFilePath, std::ios::binary);
image::LinearImage loadedImage = image::ImageDecoder::decode(pngStream, filePath,
image::ImageDecoder::ColorSpace::LINEAR);
size_t valuesInImage = loadedImage.getWidth() * loadedImage.getHeight() *
@@ -201,7 +203,8 @@ LoadedPng::LoadedPng(std::string filePath) {
}
uint32_t LoadedPng::hash() const {
EXPECT_THAT(mBytes, testing::Not(testing::IsEmpty()));
EXPECT_THAT(mBytes, testing::Not(testing::IsEmpty()))
<< "Failed to load expected test result: " << mFilePath;
if (mBytes.empty()) {
return 0;
}
+3 -1
View File
@@ -106,6 +106,7 @@ public:
uint32_t hash() const;
private:
std::string mFilePath;
std::vector<unsigned char> mBytes;
};
@@ -141,7 +142,8 @@ public:
private:
filament::backend::DriverApi& mApi;
std::vector<ImageExpectation> mExpectations;
// Store expectations in unique pointers because they are self referential.
std::vector<std::unique_ptr<ImageExpectation>> mExpectations;
};
#endif //TNT_IMAGE_EXPECTATIONS_H
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

+29 -65
View File
@@ -197,16 +197,10 @@ TEST_F(BlitTest, ColorMagnify) {
}
{
ImageExpectations expectations(api);
{
RenderFrame frame(api);
EXPECT_IMAGE(dstRenderTargets[0], expectations,
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMagnify", 0x410bdd31));
api.commit(swapChain);
}
flushAndWait();
RenderFrame frame(api);
EXPECT_IMAGE(dstRenderTargets[0], getExpectations(),
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMagnify", 0x410bdd31));
api.commit(swapChain);
}
}
@@ -260,14 +254,8 @@ TEST_F(BlitTest, ColorMinify) {
{ 0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel },
SamplerMagFilter::LINEAR);
{
ImageExpectations expectations(api);
EXPECT_IMAGE(dstRenderTargets[0], expectations,
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMinify", 0xf3d9c53f));
flushAndWait();
}
EXPECT_IMAGE(dstRenderTargets[0], getExpectations(),
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMinify", 0xf3d9c53f));
}
TEST_F(BlitTest, ColorResolve) {
@@ -351,14 +339,8 @@ TEST_F(BlitTest, ColorResolve) {
srcRenderTarget, { 0, 0, kSrcTexWidth, kSrcTexHeight },
SamplerMagFilter::NEAREST);
{
ImageExpectations expectations(api);
EXPECT_IMAGE(dstRenderTarget, expectations,
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorResolve", 0xebfac2ef));
flushAndWait();
}
EXPECT_IMAGE(dstRenderTarget, getExpectations(),
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorResolve", 0xebfac2ef));
}
TEST_F(BlitTest, Blit2DTextureArray) {
@@ -423,17 +405,11 @@ TEST_F(BlitTest, Blit2DTextureArray) {
}
{
ImageExpectations expectations(api);
{
RenderFrame frame(api);
EXPECT_IMAGE(dstRenderTarget, expectations,
ScreenshotParams(kDstTexWidth, kDstTexHeight, "Blit2DTextureArray",
0x8de7d55b));
api.commit(swapChain);
}
flushAndWait();
RenderFrame frame(api);
EXPECT_IMAGE(dstRenderTarget, getExpectations(),
ScreenshotParams(kDstTexWidth, kDstTexHeight, "Blit2DTextureArray",
0x8de7d55b));
api.commit(swapChain);
}
}
@@ -503,18 +479,12 @@ TEST_F(BlitTest, BlitRegion) {
}
{
ImageExpectations expectations(api);
{
RenderFrame frame(api);
// TODO: for some reason, this test has very, very slight (as in one pixel) differences
// between OpenGL and Metal. So disable golden checking for now.
// EXPECT_IMAGE(dstRenderTarget, expectations, ScreenshotParams(kDstTexWidth,
// kDstTexHeight, "BlitRegion", 0x74fa34ed));
api.commit(swapChain);
}
flushAndWait();
RenderFrame frame(api);
// TODO: for some reason, this test has very, very slight (as in one pixel) differences
// between OpenGL and Metal. So disable golden checking for now.
// EXPECT_IMAGE(dstRenderTarget, expectations, ScreenshotParams(kDstTexWidth,
// kDstTexHeight, "BlitRegion", 0x74fa34ed));
api.commit(swapChain);
}
}
@@ -567,25 +537,19 @@ TEST_F(BlitTest, BlitRegionToSwapChain) {
};
{
ImageExpectations expectations(api);
{
{
RenderFrame frame(api);
RenderFrame frame(api);
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
dstRect, srcRenderTargets[srcLevel],
srcRect, SamplerMagFilter::LINEAR);
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget,
dstRect, srcRenderTargets[srcLevel],
srcRect, SamplerMagFilter::LINEAR);
api.commit(swapChain);
}
// TODO: for some reason, this test has been disabled. It needs to be tested on all
// machines.
// EXPECT_IMAGE(dstRenderTarget, expectations,
// ScreenshotParams(kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain", 0x0));
}
flushAndWait();
api.commit(swapChain);
}
// TODO: for some reason, this test has been disabled. It needs to be tested on all
// machines.
// EXPECT_IMAGE(dstRenderTarget, expectations,
// ScreenshotParams(kDstTexWidth, kDstTexHeight, "BlitRegionToSwapChain", 0x0));
}
} // namespace test
+4 -3
View File
@@ -16,6 +16,7 @@
#include "BackendTest.h"
#include "ImageExpectations.h"
#include "Lifetimes.h"
#include "Shader.h"
#include "SharedShaders.h"
@@ -220,9 +221,9 @@ TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
renderTarget, swapChain, shader.getProgram(), params);
static const uint32_t expectedHash = 91322442;
readPixelsAndAssertHash(
"BufferObjectUpdateWithOffset", 512, 512, renderTarget, expectedHash, true);
EXPECT_IMAGE(renderTarget, getExpectations(),
ScreenshotParams(512, 512, "BufferObjectUpdateWithOffset", 91322442));
api.flush();
api.commit(swapChain);
+2 -26
View File
@@ -71,8 +71,6 @@ void main() {
fragColor = textureLod(test_tex, uv, params.sourceLevel);
})";
static uint32_t sPixelHashResult = 0;
// Selecting a NPOT texture size seems to exacerbate the bug seen with Intel GPU's.
// Note that Filament uses a higher precision format (R11F_G11F_B10F) but this does not seem
// necessary to trigger the bug.
@@ -96,25 +94,6 @@ struct MaterialParams {
float unused;
};
static void dumpScreenshot(DriverApi& dapi, Handle<HwRenderTarget> rt) {
const size_t size = kTexWidth * kTexHeight * 4;
void* buffer = calloc(1, size);
auto cb = [](void* buffer, size_t size, void* user) {
int w = kTexWidth, h = kTexHeight;
const uint32_t* texels = (uint32_t*) buffer;
sPixelHashResult = utils::hash::murmur3(texels, size / 4, 0);
#ifndef FILAMENT_IOS
LinearImage image(w, h, 4);
image = toLinearWithAlpha<uint8_t>(w, h, w * 4, (uint8_t*) buffer);
std::ofstream pngstrm("feedback.png", std::ios::binary | std::ios::trunc);
ImageEncoder::encode(pngstrm, ImageEncoder::Format::PNG, image, "", "feedback.png");
#endif
free(buffer);
};
PixelBufferDescriptor pb(buffer, size, PixelDataFormat::RGBA, PixelDataType::UBYTE, cb);
dapi.readPixels(rt, 0, 0, kTexWidth, kTexHeight, std::move(pb));
}
// TODO: This test needs work to get Metal and OpenGL to agree on results.
// The problems are caused by both uploading and rendering into the same texture, since the OpenGL
// backend's readPixels does not work correctly with textures that have image data uploaded.
@@ -259,7 +238,8 @@ TEST_F(BackendTest, FeedbackLoops) {
// NOTE: Calling glReadPixels on any miplevel other than the base level
// seems to be un-reliable on some GPU's.
if (frame == kNumFrames - 1) {
dumpScreenshot(api, renderTargets[0]);
EXPECT_IMAGE(renderTargets[0], getExpectations(),
ScreenshotParams(kTexWidth, kTexHeight, "FeedbackLoops", 0x70695aa1));
}
api.flush();
@@ -270,10 +250,6 @@ TEST_F(BackendTest, FeedbackLoops) {
getDriver().purge();
}
}
const uint32_t expected = 0x70695aa1;
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", sPixelHashResult, expected);
EXPECT_TRUE(sPixelHashResult == expected);
}
} // namespace test
+37 -50
View File
@@ -246,42 +246,42 @@ TEST_F(LoadImageTest, UpdateImage2D) {
std::vector<TestCase> testCases;
// Test basic upload.
testCases.emplace_back("RGBA, UBYTE -> RGBA8", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8);
testCases.emplace_back("RGBA UBYTE to RGBA8", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8);
// Test format conversion.
// TODO: Vulkan crashes with `Texture at colorAttachment[0] has usage (0x01) which doesn't specify MTLTextureUsageRenderTarget (0x04)'
testCases.emplace_back("RGBA, FLOAT -> RGBA16F", PixelDataFormat::RGBA, PixelDataType::FLOAT, TextureFormat::RGBA16F);
testCases.emplace_back("RGBA FLOAT to RGBA16F", PixelDataFormat::RGBA, PixelDataType::FLOAT, TextureFormat::RGBA16F);
// Test texture formats not all backends support natively.
// TODO: Vulkan crashes with "VK_FORMAT_R32G32B32_SFLOAT is not supported"
testCases.emplace_back("RGB, FLOAT -> RGB32F", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB32F);
testCases.emplace_back("RGB, FLOAT -> RGB16F", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB16F);
testCases.emplace_back("RGB FLOAT to RGB32F", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB32F);
testCases.emplace_back("RGB FLOAT to RGB16F", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB16F);
// Test packed format uploads.
// TODO: Vulkan crashes with "Texture at colorAttachment[0] has usage (0x01) which doesn't specify MTLTextureUsageRenderTarget (0x04)"
testCases.emplace_back("RGBA, UINT_2_10_10_10_REV -> RGB10_A2", PixelDataFormat::RGBA, PixelDataType::UINT_2_10_10_10_REV, TextureFormat::RGB10_A2);
testCases.emplace_back("RGB, UINT_10F_11F_11F_REV -> R11F_G11F_B10F", PixelDataFormat::RGB, PixelDataType::UINT_10F_11F_11F_REV, TextureFormat::R11F_G11F_B10F);
testCases.emplace_back("RGB, HALF -> R11F_G11F_B10F", PixelDataFormat::RGB, PixelDataType::HALF, TextureFormat::R11F_G11F_B10F);
testCases.emplace_back("RGBA UINT_2_10_10_10_REV to RGB10_A2", PixelDataFormat::RGBA, PixelDataType::UINT_2_10_10_10_REV, TextureFormat::RGB10_A2);
testCases.emplace_back("RGB UINT_10F_11F_11F_REV to R11F_G11F_B10F", PixelDataFormat::RGB, PixelDataType::UINT_10F_11F_11F_REV, TextureFormat::R11F_G11F_B10F);
testCases.emplace_back("RGB HALF to R11F_G11F_B10F", PixelDataFormat::RGB, PixelDataType::HALF, TextureFormat::R11F_G11F_B10F);
// 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 -> RGB8UI", PixelDataFormat::RGB_INTEGER, PixelDataType::UBYTE, TextureFormat::RGB8UI);
testCases.emplace_back("RGB_INTEGER, USHORT -> RGB16UI", PixelDataFormat::RGB_INTEGER, PixelDataType::USHORT, TextureFormat::RGB16UI);
testCases.emplace_back("RGB_INTEGER, INT -> 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)"
testCases.emplace_back("RGBA, UBYTE -> RGBA8 (with buffer padding)", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8, 64u);
testCases.emplace_back("RGBA, FLOAT -> RGBA16F (with buffer padding)", PixelDataFormat::RGBA, PixelDataType::FLOAT, TextureFormat::RGBA16F, 64u);
testCases.emplace_back("RGB, FLOAT -> RGB32F (with buffer padding)", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB32F, 64u);
testCases.emplace_back("RGBA UBYTE to RGBA8 (with buffer padding)", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8, 64u);
testCases.emplace_back("RGBA FLOAT to RGBA16F (with buffer padding)", PixelDataFormat::RGBA, PixelDataType::FLOAT, TextureFormat::RGBA16F, 64u);
testCases.emplace_back("RGB FLOAT to RGB32F (with buffer padding)", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB32F, 64u);
// Upload subregions separately.
// TODO: Vulkan crashes with "Offsets not yet supported"
testCases.emplace_back("RGBA, UBYTE -> RGBA8 (subregions)", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8, 0u, true);
testCases.emplace_back("RGBA, FLOAT -> RGBA16F (subregions)", PixelDataFormat::RGBA, PixelDataType::FLOAT, TextureFormat::RGBA16F, 0u, true);
testCases.emplace_back("RGBA, UBYTE -> RGBA8 (subregions, buffer padding)", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8, 64u, true);
testCases.emplace_back("RGB, FLOAT -> RGB32F (subregions, buffer padding)", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB32F, 64u, true);
testCases.emplace_back("RGBA UBYTE to RGBA8 (subregions)", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8, 0u, true);
testCases.emplace_back("RGBA FLOAT to RGBA16F (subregions)", PixelDataFormat::RGBA, PixelDataType::FLOAT, TextureFormat::RGBA16F, 0u, true);
testCases.emplace_back("RGBA UBYTE to RGBA8 (subregions and buffer padding)", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8, 64u, true);
testCases.emplace_back("RGB FLOAT to RGB32F (subregions and buffer padding)", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB32F, 64u, true);
auto& api = getDriverApi();
@@ -339,16 +339,14 @@ TEST_F(LoadImageTest, UpdateImage2D) {
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
defaultRenderTarget, swapChain, shader.getProgram());
readPixelsAndAssertHash(t.name, 512, 512, defaultRenderTarget, expectedHash);
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
ScreenshotParams(512, 512, t.name, expectedHash));
api.commit(swapChain);
api.endFrame(0);
}
api.finish();
api.stopCapture();
flushAndWait();
}
TEST_F(LoadImageTest, UpdateImageSRGB) {
@@ -372,7 +370,7 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
getSamplerTypeName(textureFormat), fragmentTemplate);
Shader shader(api, cleanup, ShaderConfig{
.vertexShader = mVertexShader, .fragmentShader = fragment, .uniforms = {{
"text_tex", DescriptorType::SAMPLER, samplerInfo
"test_tex", DescriptorType::SAMPLER, samplerInfo
}}});
// Create a texture.
@@ -416,15 +414,12 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
defaultRenderTarget, swapChain, shader.getProgram());
static const uint32_t expectedHash = 359858623;
readPixelsAndAssertHash("UpdateImageSRGB", 512, 512, defaultRenderTarget, expectedHash);
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
ScreenshotParams(512, 512, "UpdateImageSRGB", 359858623));
api.flush();
api.commit(swapChain);
api.endFrame(0);
// This ensures all driver commands have finished before exiting the test.
api.finish();
api.stopCapture();
}
@@ -478,15 +473,12 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
defaultRenderTarget, swapChain, shader.getProgram());
static const uint32_t expectedHash = 3644679986;
readPixelsAndAssertHash("UpdateImageMipLevel", 512, 512, defaultRenderTarget, expectedHash);
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
ScreenshotParams(512, 512, "UpdateImageMipLevel", 3644679986));
api.flush();
api.commit(swapChain);
api.endFrame(0);
// This ensures all driver commands have finished before exiting the test.
api.finish();
api.stopCapture();
}
@@ -538,29 +530,24 @@ TEST_F(LoadImageTest, UpdateImage3D) {
api.update3DImage(texture, 0, 0, 0, 0, 512, 512, 4, std::move(descriptor));
api.beginFrame(0, 0, 0);
{
RenderFrame frame(api);
// Update samplers.
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
});
// Update samplers.
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
api.updateDescriptorSetTexture(descriptorSet, 0, texture,
{ .filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST });
api.bindDescriptorSet(descriptorSet, 1, {});
api.bindDescriptorSet(descriptorSet, 1, {});
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
defaultRenderTarget, swapChain, shader.getProgram());
renderTriangle({ { DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() } },
defaultRenderTarget, swapChain, shader.getProgram());
static const uint32_t expectedHash = 3644679986;
readPixelsAndAssertHash("UpdateImage3D", 512, 512, defaultRenderTarget, expectedHash);
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
ScreenshotParams(512, 512, "UpdateImage3D", 3644679986));
}
api.flush();
api.commit(swapChain);
api.endFrame(0);
// This ensures all driver commands have finished before exiting the test.
api.finish();
api.stopCapture();
}
+3 -7
View File
@@ -16,6 +16,7 @@
#include "BackendTest.h"
#include "ImageExpectations.h"
#include "Lifetimes.h"
#include "ShaderGenerator.h"
#include "Skip.h"
@@ -151,19 +152,14 @@ TEST_F(BackendTest, PushConstants) {
api.endRenderPass();
readPixelsAndAssertHash("pushConstants", 512, 512, renderTarget, 1957275826, true);
EXPECT_IMAGE(renderTarget, getExpectations(),
ScreenshotParams(512, 512, "pushConstants", 1957275826));
api.commit(swapChain);
api.endFrame(0);
}
api.stopCapture(0);
// Wait for the ReadPixels result to come back.
api.finish();
executeCommands();
getDriver().purge();
}
} // namespace test
@@ -16,6 +16,7 @@
#include "BackendTest.h"
#include "ImageExpectations.h"
#include "Lifetimes.h"
#include "Shader.h"
#include "SharedShaders.h"
@@ -200,17 +201,16 @@ TEST_F(BackendTest, RenderExternalImage) {
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
api.endRenderPass();
readPixelsAndAssertHash("RenderExternalImage", 512, 512, defaultRenderTarget, 267229901, true);
api.flush();
api.commit(swapChain);
api.endFrame(0);
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
ScreenshotParams(512, 512, "RenderExternalImage", 267229901));
api.stopCapture(0);
api.finish();
flushAndWait();
executeCommands();
}
} // namespace test
+5 -16
View File
@@ -16,6 +16,7 @@
#include "BackendTest.h"
#include "ImageExpectations.h"
#include "Lifetimes.h"
#include "Shader.h"
#include "SharedShaders.h"
@@ -130,20 +131,14 @@ TEST_F(BackendTest, ScissorViewportRegion) {
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
api.endRenderPass();
readPixelsAndAssertHash("scissor", kSrcTexWidth >> 1, kSrcTexHeight >> 1, fullRenderTarget,
0xAB3D1C53, true);
EXPECT_IMAGE(fullRenderTarget, getExpectations(),
ScreenshotParams(kSrcTexWidth >> 1, kSrcTexHeight >> 1, "scissor", 0xAB3D1C53));
api.commit(swapChain);
api.endFrame(0);
api.stopCapture(0);
}
// Wait for the ReadPixels result to come back.
api.finish();
executeCommands();
getDriver().purge();
}
// Verify that a negative Viewport origin works with scissor.
@@ -226,20 +221,14 @@ TEST_F(BackendTest, ScissorViewportEdgeCases) {
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
api.endRenderPass();
readPixelsAndAssertHash(
"ScissorViewportEdgeCases", 512, 512, renderTarget, 0x6BF00F31, true);
EXPECT_IMAGE(renderTarget, getExpectations(),
ScreenshotParams(512, 512, "ScissorViewportEdgeCases", 0x6BF00F31));
api.commit(swapChain);
api.endFrame(0);
api.stopCapture(0);
}
// Wait for the ReadPixels result to come back.
api.finish();
executeCommands();
getDriver().purge();
}
} // namespace test
+7 -3
View File
@@ -16,6 +16,7 @@
#include "BackendTest.h"
#include "ImageExpectations.h"
#include "Lifetimes.h"
#include "Shader.h"
#include "SharedShaders.h"
@@ -129,7 +130,8 @@ TEST_F(BasicStencilBufferTest, StencilBuffer) {
RunTest(renderTarget);
readPixelsAndAssertHash("StencilBuffer", 512, 512, renderTarget, 0x3B1AEF0F, true);
EXPECT_IMAGE(renderTarget, getExpectations(),
ScreenshotParams(512, 512, "StencilBuffer", 0x3B1AEF0F));
flushAndWait();
getDriver().purge();
@@ -151,7 +153,8 @@ TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
RunTest(renderTarget);
readPixelsAndAssertHash("DepthAndStencilBuffer", 512, 512, renderTarget, 0x3B1AEF0F, true);
EXPECT_IMAGE(renderTarget, getExpectations(),
ScreenshotParams(512, 512, "DepthAndStencilBuffer", 0x3B1AEF0F));
flushAndWait();
getDriver().purge();
@@ -233,7 +236,8 @@ TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
api.stopCapture(0);
api.endFrame(0);
readPixelsAndAssertHash("StencilBufferAutoResolve", 512, 512, renderTarget1, 0x6CEFAC8F, true);
EXPECT_IMAGE(renderTarget1, getExpectations(),
ScreenshotParams(512, 512, "StencilBufferAutoResolve", 0x6CEFAC8F));
flushAndWait();
getDriver().purge();