diff --git a/filament/backend/test/BackendTest.cpp b/filament/backend/test/BackendTest.cpp index 9bf3cd490e..31c81040f2 100644 --- a/filament/backend/test/BackendTest.cpp +++ b/filament/backend/test/BackendTest.cpp @@ -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 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(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; } diff --git a/filament/backend/test/BackendTest.h b/filament/backend/test/BackendTest.h index 1cfa3f638d..c2d05cb37d 100644 --- a/filament/backend/test/BackendTest.h +++ b/filament/backend/test/BackendTest.h @@ -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 program, const filament::backend::RenderPassParams& params); - void readPixelsAndAssertHash(const char* testName, size_t width, size_t height, - filament::backend::Handle 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 commandStream; filament::backend::Handle uniform; + + // This isn't truly optional, it just needs to delay construction until after the driver has + // been initialized + std::optional mImageExpectations; }; } // namespace test diff --git a/filament/backend/test/ImageExpectations.cpp b/filament/backend/test/ImageExpectations.cpp index 623d609db8..62dbcac680 100644 --- a/filament/backend/test/ImageExpectations.cpp +++ b/filament/backend/test/ImageExpectations.cpp @@ -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(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(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(user); + internal->bytesFilled = true; +#ifndef FILAMENT_IOS image::LinearImage image(internal->params.width(), internal->params.width(), 4); image = image::toLinearWithAlpha(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; } diff --git a/filament/backend/test/ImageExpectations.h b/filament/backend/test/ImageExpectations.h index cab2b10374..afbc2b646f 100644 --- a/filament/backend/test/ImageExpectations.h +++ b/filament/backend/test/ImageExpectations.h @@ -106,6 +106,7 @@ public: uint32_t hash() const; private: + std::string mFilePath; std::vector mBytes; }; @@ -141,7 +142,8 @@ public: private: filament::backend::DriverApi& mApi; - std::vector mExpectations; + // Store expectations in unique pointers because they are self referential. + std::vector> mExpectations; }; #endif //TNT_IMAGE_EXPECTATIONS_H diff --git a/filament/backend/test/expected_images/Blit2DTextureArray.png b/filament/backend/test/expected_images/Blit2DTextureArray.png index 29fc1e3299..a7c2783556 100644 Binary files a/filament/backend/test/expected_images/Blit2DTextureArray.png and b/filament/backend/test/expected_images/Blit2DTextureArray.png differ diff --git a/filament/backend/test/expected_images/BufferObjectUpdateWithOffset.png b/filament/backend/test/expected_images/BufferObjectUpdateWithOffset.png new file mode 100644 index 0000000000..ee45ccd728 Binary files /dev/null and b/filament/backend/test/expected_images/BufferObjectUpdateWithOffset.png differ diff --git a/filament/backend/test/expected_images/ColorMagnify.png b/filament/backend/test/expected_images/ColorMagnify.png index d3bfe4249b..06f1381eea 100644 Binary files a/filament/backend/test/expected_images/ColorMagnify.png and b/filament/backend/test/expected_images/ColorMagnify.png differ diff --git a/filament/backend/test/expected_images/ColorMinify.png b/filament/backend/test/expected_images/ColorMinify.png index 764cf90ca0..d379f332ff 100644 Binary files a/filament/backend/test/expected_images/ColorMinify.png and b/filament/backend/test/expected_images/ColorMinify.png differ diff --git a/filament/backend/test/expected_images/ColorResolve.png b/filament/backend/test/expected_images/ColorResolve.png index 5b4e381e03..e8b0cde600 100644 Binary files a/filament/backend/test/expected_images/ColorResolve.png and b/filament/backend/test/expected_images/ColorResolve.png differ diff --git a/filament/backend/test/expected_images/DepthAndStencilBuffer.png b/filament/backend/test/expected_images/DepthAndStencilBuffer.png new file mode 100644 index 0000000000..1e663aa397 Binary files /dev/null and b/filament/backend/test/expected_images/DepthAndStencilBuffer.png differ diff --git a/filament/backend/test/expected_images/FeedbackLoops.png b/filament/backend/test/expected_images/FeedbackLoops.png new file mode 100644 index 0000000000..7625833de5 Binary files /dev/null and b/filament/backend/test/expected_images/FeedbackLoops.png differ diff --git a/filament/backend/test/expected_images/RGB FLOAT to RGB16F.png b/filament/backend/test/expected_images/RGB FLOAT to RGB16F.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGB FLOAT to RGB16F.png differ diff --git a/filament/backend/test/expected_images/RGB FLOAT to RGB32F (subregions and buffer padding).png b/filament/backend/test/expected_images/RGB FLOAT to RGB32F (subregions and buffer padding).png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGB FLOAT to RGB32F (subregions and buffer padding).png differ diff --git a/filament/backend/test/expected_images/RGB FLOAT to RGB32F (with buffer padding).png b/filament/backend/test/expected_images/RGB FLOAT to RGB32F (with buffer padding).png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGB FLOAT to RGB32F (with buffer padding).png differ diff --git a/filament/backend/test/expected_images/RGB FLOAT to RGB32F.png b/filament/backend/test/expected_images/RGB FLOAT to RGB32F.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGB FLOAT to RGB32F.png differ diff --git a/filament/backend/test/expected_images/RGB HALF to R11F_G11F_B10F.png b/filament/backend/test/expected_images/RGB HALF to R11F_G11F_B10F.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGB HALF to R11F_G11F_B10F.png differ diff --git a/filament/backend/test/expected_images/RGB UINT_10F_11F_11F_REV to R11F_G11F_B10F.png b/filament/backend/test/expected_images/RGB UINT_10F_11F_11F_REV to R11F_G11F_B10F.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGB UINT_10F_11F_11F_REV to R11F_G11F_B10F.png differ diff --git a/filament/backend/test/expected_images/RGBA FLOAT to RGBA16F (subregions).png b/filament/backend/test/expected_images/RGBA FLOAT to RGBA16F (subregions).png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGBA FLOAT to RGBA16F (subregions).png differ diff --git a/filament/backend/test/expected_images/RGBA FLOAT to RGBA16F (with buffer padding).png b/filament/backend/test/expected_images/RGBA FLOAT to RGBA16F (with buffer padding).png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGBA FLOAT to RGBA16F (with buffer padding).png differ diff --git a/filament/backend/test/expected_images/RGBA FLOAT to RGBA16F.png b/filament/backend/test/expected_images/RGBA FLOAT to RGBA16F.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGBA FLOAT to RGBA16F.png differ diff --git a/filament/backend/test/expected_images/RGBA UBYTE to RGBA8 (subregions and buffer padding).png b/filament/backend/test/expected_images/RGBA UBYTE to RGBA8 (subregions and buffer padding).png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGBA UBYTE to RGBA8 (subregions and buffer padding).png differ diff --git a/filament/backend/test/expected_images/RGBA UBYTE to RGBA8 (subregions).png b/filament/backend/test/expected_images/RGBA UBYTE to RGBA8 (subregions).png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGBA UBYTE to RGBA8 (subregions).png differ diff --git a/filament/backend/test/expected_images/RGBA UBYTE to RGBA8 (with buffer padding).png b/filament/backend/test/expected_images/RGBA UBYTE to RGBA8 (with buffer padding).png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGBA UBYTE to RGBA8 (with buffer padding).png differ diff --git a/filament/backend/test/expected_images/RGBA UBYTE to RGBA8.png b/filament/backend/test/expected_images/RGBA UBYTE to RGBA8.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGBA UBYTE to RGBA8.png differ diff --git a/filament/backend/test/expected_images/RGBA UINT_2_10_10_10_REV to RGB10_A2.png b/filament/backend/test/expected_images/RGBA UINT_2_10_10_10_REV to RGB10_A2.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGBA UINT_2_10_10_10_REV to RGB10_A2.png differ diff --git a/filament/backend/test/expected_images/RGB_INTEGER INT to RGB32I.png b/filament/backend/test/expected_images/RGB_INTEGER INT to RGB32I.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGB_INTEGER INT to RGB32I.png differ diff --git a/filament/backend/test/expected_images/RGB_INTEGER UBYTE to RGB8UI.png b/filament/backend/test/expected_images/RGB_INTEGER UBYTE to RGB8UI.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGB_INTEGER UBYTE to RGB8UI.png differ diff --git a/filament/backend/test/expected_images/RGB_INTEGER USHORT to RGB16UI.png b/filament/backend/test/expected_images/RGB_INTEGER USHORT to RGB16UI.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/RGB_INTEGER USHORT to RGB16UI.png differ diff --git a/filament/backend/test/expected_images/RenderExternalImage.png b/filament/backend/test/expected_images/RenderExternalImage.png new file mode 100644 index 0000000000..6e2f19df6a Binary files /dev/null and b/filament/backend/test/expected_images/RenderExternalImage.png differ diff --git a/filament/backend/test/expected_images/ScissorViewportEdgeCases.png b/filament/backend/test/expected_images/ScissorViewportEdgeCases.png new file mode 100644 index 0000000000..f81906d36d Binary files /dev/null and b/filament/backend/test/expected_images/ScissorViewportEdgeCases.png differ diff --git a/filament/backend/test/expected_images/StencilBuffer.png b/filament/backend/test/expected_images/StencilBuffer.png new file mode 100644 index 0000000000..1e663aa397 Binary files /dev/null and b/filament/backend/test/expected_images/StencilBuffer.png differ diff --git a/filament/backend/test/expected_images/StencilBufferAutoResolve.png b/filament/backend/test/expected_images/StencilBufferAutoResolve.png new file mode 100644 index 0000000000..f5618225a1 Binary files /dev/null and b/filament/backend/test/expected_images/StencilBufferAutoResolve.png differ diff --git a/filament/backend/test/expected_images/UpdateImage3D.png b/filament/backend/test/expected_images/UpdateImage3D.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/UpdateImage3D.png differ diff --git a/filament/backend/test/expected_images/UpdateImageMipLevel.png b/filament/backend/test/expected_images/UpdateImageMipLevel.png new file mode 100644 index 0000000000..120ae640c6 Binary files /dev/null and b/filament/backend/test/expected_images/UpdateImageMipLevel.png differ diff --git a/filament/backend/test/expected_images/UpdateImageSRGB.png b/filament/backend/test/expected_images/UpdateImageSRGB.png new file mode 100644 index 0000000000..6aff04d1a4 Binary files /dev/null and b/filament/backend/test/expected_images/UpdateImageSRGB.png differ diff --git a/filament/backend/test/expected_images/scissor.png b/filament/backend/test/expected_images/scissor.png new file mode 100644 index 0000000000..e21b97b89d Binary files /dev/null and b/filament/backend/test/expected_images/scissor.png differ diff --git a/filament/backend/test/test_Blit.cpp b/filament/backend/test/test_Blit.cpp index 9acdb876c0..909c3adb6d 100644 --- a/filament/backend/test/test_Blit.cpp +++ b/filament/backend/test/test_Blit.cpp @@ -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 diff --git a/filament/backend/test/test_BufferUpdates.cpp b/filament/backend/test/test_BufferUpdates.cpp index 908ab45d7c..3c661e3bb5 100644 --- a/filament/backend/test/test_BufferUpdates.cpp +++ b/filament/backend/test/test_BufferUpdates.cpp @@ -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); diff --git a/filament/backend/test/test_FeedbackLoops.cpp b/filament/backend/test/test_FeedbackLoops.cpp index 2b137264df..5b7b2579d0 100644 --- a/filament/backend/test/test_FeedbackLoops.cpp +++ b/filament/backend/test/test_FeedbackLoops.cpp @@ -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 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(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 diff --git a/filament/backend/test/test_LoadImage.cpp b/filament/backend/test/test_LoadImage.cpp index 47d434ed4e..592431993a 100644 --- a/filament/backend/test/test_LoadImage.cpp +++ b/filament/backend/test/test_LoadImage.cpp @@ -246,42 +246,42 @@ TEST_F(LoadImageTest, UpdateImage2D) { std::vector 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(); } diff --git a/filament/backend/test/test_PushConstants.cpp b/filament/backend/test/test_PushConstants.cpp index 90b2e8d999..34b43525fe 100644 --- a/filament/backend/test/test_PushConstants.cpp +++ b/filament/backend/test/test_PushConstants.cpp @@ -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 diff --git a/filament/backend/test/test_RenderExternalImage.cpp b/filament/backend/test/test_RenderExternalImage.cpp index 6c5e8aa5ce..6f0129f98e 100644 --- a/filament/backend/test/test_RenderExternalImage.cpp +++ b/filament/backend/test/test_RenderExternalImage.cpp @@ -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 diff --git a/filament/backend/test/test_Scissor.cpp b/filament/backend/test/test_Scissor.cpp index 7f261b049d..2ae776ddc8 100644 --- a/filament/backend/test/test_Scissor.cpp +++ b/filament/backend/test/test_Scissor.cpp @@ -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 diff --git a/filament/backend/test/test_StencilBuffer.cpp b/filament/backend/test/test_StencilBuffer.cpp index 7703a69db9..d3c75f5b13 100644 --- a/filament/backend/test/test_StencilBuffer.cpp +++ b/filament/backend/test/test_StencilBuffer.cpp @@ -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();