Use EXPECT_IMAGE in all backend tests. (#8628)
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 982 B |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||