From 4cd65f03b74b18853a439e0ecc640b4a6c6572f0 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Tue, 27 Jun 2017 00:11:16 -0400 Subject: [PATCH] Add a readpixel test --- src/tests/NXTTest.cpp | 45 ++++++++++++++++++++++++++++++++ src/tests/NXTTest.h | 16 ++++++++++++ src/tests/end2end/BasicTests.cpp | 24 +++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/src/tests/NXTTest.cpp b/src/tests/NXTTest.cpp index c2bb460578..b709958aa8 100644 --- a/src/tests/NXTTest.cpp +++ b/src/tests/NXTTest.cpp @@ -161,6 +161,34 @@ void NXTTest::AddBufferExpectation(const char* file, int line, const nxt::Buffer deferredExpectations.push_back(deferred); } +void NXTTest::AddTextureExpectation(const char* file, int line, const nxt::Texture& texture, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t pixelSize, detail::Expectation* expectation) { + nxt::Texture source = texture.Clone(); + uint32_t size = width * height * pixelSize; + + auto readback = ReserveReadback(size); + + // We need to enqueue the copy immediately because by the time we resolve the expectation, + // the texture might have been modified. + nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() + .TransitionTextureUsage(source, nxt::TextureUsageBit::TransferSrc) + .TransitionBufferUsage(readback.buffer, nxt::BufferUsageBit::TransferDst) + .CopyTextureToBuffer(source, x, y, 0, width, height, 1, 0, readback.buffer, readback.offset) + .GetResult(); + + queue.Submit(1, &commands); + + DeferredExpectation deferred; + deferred.file = file; + deferred.line = line; + deferred.readbackSlot = readback.slot; + deferred.readbackOffset = readback.offset; + deferred.size = size; + deferred.expectation = expectation; + + deferredExpectations.push_back(deferred); +} + + NXTTest::ReadbackReservation NXTTest::ReserveReadback(uint32_t readbackSize) { // For now create a new MapRead buffer for each readback // TODO(cwallez@chromium.org): eventually make bigger buffers and allocate linearly? @@ -230,6 +258,22 @@ void NXTTest::ResolveExpectations() { } } +bool RGBA8::operator==(const RGBA8& other) const { + return r == other.r && g == other.g && b == other.b && a == other.a; +} + +bool RGBA8::operator!=(const RGBA8& other) const { + return !(*this == other); +} + +std::ostream& operator<< (std::ostream& stream, const RGBA8& color) { + return stream << "RGBA8(" << + static_cast(color.r) << ", " << + static_cast(color.g) << ", " << + static_cast(color.b) << ", " << + static_cast(color.a) << ")"; +} + namespace detail { bool IsBackendAvailable(BackendType type) { #if defined(__APPLE__) @@ -272,4 +316,5 @@ namespace detail { } template class ExpectEq; + template class ExpectEq; } diff --git a/src/tests/NXTTest.h b/src/tests/NXTTest.h index e13f9dd32d..f275403b40 100644 --- a/src/tests/NXTTest.h +++ b/src/tests/NXTTest.h @@ -22,6 +22,20 @@ #define EXPECT_BUFFER_U32_EQ(expected, buffer, offset) \ AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint32_t), new detail::ExpectEq(expected)); +// Test a pixel of the mip level 0 of a 2D texture. +#define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \ + AddTextureExpectation(__FILE__, __LINE__, texture, x, y, 1, 1, sizeof(RGBA8), new detail::ExpectEq(expected)); + +struct RGBA8 { + constexpr RGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a): r(r), g(g), b(b), a(a) { + } + bool operator==(const RGBA8& other) const; + bool operator!=(const RGBA8& other) const; + + uint8_t r, g, b, a; +}; +std::ostream& operator<< (std::ostream& stream, const RGBA8& color); + // Backend types used in the NXT_INSTANTIATE_TEST enum BackendType { D3D12Backend, @@ -52,6 +66,7 @@ class NXTTest : public ::testing::TestWithParam { // Helper methods to implement the EXPECT_ macros void AddBufferExpectation(const char* file, int line, const nxt::Buffer& buffer, uint32_t offset, uint32_t size, detail::Expectation* expectation); + void AddTextureExpectation(const char* file, int line, const nxt::Texture& texture, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t pixelSize, detail::Expectation* expectation); private: // MapRead buffers used to get data for the expectations @@ -125,5 +140,6 @@ namespace detail { std::vector expected; }; extern template class ExpectEq; + extern template class ExpectEq; } diff --git a/src/tests/end2end/BasicTests.cpp b/src/tests/end2end/BasicTests.cpp index c7664a66f4..38c18d7ef7 100644 --- a/src/tests/end2end/BasicTests.cpp +++ b/src/tests/end2end/BasicTests.cpp @@ -14,6 +14,8 @@ #include "tests/NXTTest.h" +#include "utils/NXTHelpers.h" + class BasicTests : public NXTTest { }; @@ -32,4 +34,26 @@ TEST_P(BasicTests, BufferSetSubData) { EXPECT_BUFFER_U32_EQ(value, buffer, 0); } +TEST_P(BasicTests, ReadPixelsTest) { + RGBA8 red(255, 0, 0, 255); + nxt::Buffer buffer = utils::CreateFrozenBufferFromData(device, &red, sizeof(red), nxt::BufferUsageBit::TransferSrc); + + nxt::Texture texture = device.CreateTextureBuilder() + .SetDimension(nxt::TextureDimension::e2D) + .SetExtent(1, 1, 1) + .SetMipLevels(1) + .SetAllowedUsage(nxt::TextureUsageBit::TransferSrc | nxt::TextureUsageBit::TransferDst) + .SetFormat(nxt::TextureFormat::R8G8B8A8Unorm) + .GetResult(); + + nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() + .TransitionTextureUsage(texture, nxt::TextureUsageBit::TransferDst) + .CopyBufferToTexture(buffer, 0, texture, 0, 0, 0, 1, 1, 1, 0) + .GetResult(); + + queue.Submit(1, &commands); + + EXPECT_PIXEL_RGBA8_EQ(red, texture, 0, 0); +} + NXT_INSTANTIATE_TEST(BasicTests, MetalBackend)