diff --git a/tests/Testbed/TestTextureTypes.cpp b/tests/Testbed/TestTextureTypes.cpp index af8b64677a..bdc6efde35 100644 --- a/tests/Testbed/TestTextureTypes.cpp +++ b/tests/Testbed/TestTextureTypes.cpp @@ -10,7 +10,7 @@ DEF_TEST( TextureTypes ) { - auto CreateDummyTextureAndMeasureTiming = [this](const char* name, TextureType type, const Extent3D& extent, std::uint32_t mips, std::uint32_t layers, std::uint32_t samples) + auto CreateDummyTextureAndMeasureTiming = [this](const char* name, TextureType type, const Extent3D& extent, std::uint32_t mips, std::uint32_t layers, std::uint32_t samples) -> TestResult { const auto t0 = Timer::Tick(); diff --git a/tests/Testbed/TestTextureWriteAndRead.cpp b/tests/Testbed/TestTextureWriteAndRead.cpp index 48ac9370ed..35f6d2519d 100644 --- a/tests/Testbed/TestTextureWriteAndRead.cpp +++ b/tests/Testbed/TestTextureWriteAndRead.cpp @@ -6,11 +6,187 @@ */ #include "Testbed.h" +#include +std::uint8_t RandomUint8() +{ + return static_cast(::rand() % 0xFF); +} + +static void GenerateRandomColors(ColorRGBAub* colors, std::size_t count) +{ + for (std::size_t i = 0; i < count; ++i) + { + colors[i].r = RandomUint8(); + colors[i].g = RandomUint8(); + colors[i].b = RandomUint8(); + colors[i].a = RandomUint8(); + } +} + +struct RandomColorSet +{ + std::vector colors; + + void Generate(std::size_t count) + { + if (colors.size() != count) + { + colors.resize(count); + GenerateRandomColors(colors.data(), colors.size()); + } + } +}; + DEF_TEST( TextureWriteAndRead ) { - //todo + const ColorRGBAub colorsRgbaUb4[4] = + { + ColorRGBAub{ 0xC0, 0x01, 0x12, 0xFF }, + ColorRGBAub{ 0x80, 0x12, 0x34, 0x90 }, + ColorRGBAub{ 0x13, 0x23, 0x56, 0x80 }, + ColorRGBAub{ 0x12, 0x34, 0x78, 0x70 }, + }; + + static RandomColorSet colorsRgbaUb16; + colorsRgbaUb16.Generate(16); + + auto PrintImageData = [](const void* data, std::size_t dataSize) -> std::string + { + std::string s; + s.reserve(dataSize * 3); + + char formatted[3] = {}; + const unsigned char* bytes = reinterpret_cast(data); + + for_range(i, dataSize) + { + if (!s.empty()) + s += ' '; + ::snprintf(formatted, 3, "%02X", static_cast(bytes[i])); + s += formatted; + } + + return s; + }; + + auto CreateTextureAndTestImageData = [this, &PrintImageData](const char* name, const TextureDescriptor& texDesc, const TextureRegion& region, const void* data, std::size_t dataSize) -> TestResult + { + // Create texture object + Texture* tex = nullptr; + TestResult result = CreateTexture(texDesc, name, &tex); + if (result != TestResult::Passed) + return result; + + // Write texture data + SrcImageDescriptor srcImage; + { + srcImage.format = ImageFormat::RGBA; + srcImage.dataType = DataType::UInt8; + srcImage.data = data; + srcImage.dataSize = dataSize; + } + renderer->WriteTexture(*tex, region, srcImage); + + // Read texture data + std::vector outputData; + outputData.resize(dataSize); + + DstImageDescriptor dstImage; + { + dstImage.format = srcImage.format; + dstImage.dataType = srcImage.dataType; + dstImage.data = outputData.data(); + dstImage.dataSize = outputData.size(); + } + renderer->ReadTexture(*tex, region, dstImage); + + // Release temporary texture + renderer->Release(*tex); + + // Match input with output texture data + if (::memcmp(data, outputData.data(), dataSize) != 0) + { + std::string inputDataStr = PrintImageData(data, dataSize); + std::string outputDataStr = PrintImageData(outputData.data(), dataSize); + + Log::Errorf( + "Mismatch between data of texture %s and initial data:\n -> Expected: [%s]\n -> Actual: [%s] \n", + name, inputDataStr.c_str(), outputDataStr.c_str() + ); + return TestResult::FailedMismatch; + } + + return TestResult::Passed; + }; + + ////////////// Texture2D ////////////// + + TextureDescriptor tex2DDesc; + { + tex2DDesc.type = TextureType::Texture2D; + tex2DDesc.format = Format::RGBA8UNorm; + tex2DDesc.extent.width = 4; + tex2DDesc.extent.height = 4; + tex2DDesc.mipLevels = 0; + } + + CreateTextureAndTestImageData( + "tex2D{2D,4wh}:{MIP0-full-access}", + tex2DDesc, + TextureRegion{ TextureSubresource{ 0, 0 }, Offset3D{ 0, 0, 0 }, Extent3D{ 4, 4, 1 } }, + colorsRgbaUb16.colors.data(), + colorsRgbaUb16.colors.size() * sizeof(ColorRGBAub) + ); + + CreateTextureAndTestImageData( + "tex2D{2D,4wh}:{single-texel-access}", + tex2DDesc, + TextureRegion{ TextureSubresource{ 0, 1 }, Offset3D{ 1, 1, 0 }, Extent3D{ 1, 1, 1 } }, + &(colorsRgbaUb4[0]), + sizeof(ColorRGBAub) + ); + + ////////////// Texture2DArray ////////////// + + if (caps.features.hasArrayTextures) + { + TextureDescriptor tex2DArrayDesc; + { + tex2DArrayDesc.type = TextureType::Texture2DArray; + tex2DArrayDesc.format = Format::RGBA8UNorm; + tex2DArrayDesc.extent.width = 8; + tex2DArrayDesc.extent.height = 4; + tex2DArrayDesc.arrayLayers = 2; + tex2DArrayDesc.mipLevels = 2; + } + + CreateTextureAndTestImageData( + "tex2DArray{2D[2],8w,4h}:{MIP1-full-access}", + tex2DArrayDesc, + TextureRegion{ TextureSubresource{ 0, 2, 1, 1 }, Offset3D{ 0, 0, 0 }, Extent3D{ 4, 2, 1 } }, + colorsRgbaUb16.colors.data(), + colorsRgbaUb16.colors.size() * sizeof(ColorRGBAub) + ); + + CreateTextureAndTestImageData( + "tex2DArray{2D[2],8w,4h}:{1-layer-access}", + tex2DArrayDesc, + TextureRegion{ TextureSubresource{ 1, 1 }, Offset3D{ 1, 0, 0 }, Extent3D{ 2, 2, 1 } }, + colorsRgbaUb4, + sizeof(colorsRgbaUb4) + ); + + CreateTextureAndTestImageData( + "tex2DArray{2D[2],8w,4h}:{2-layer-access}", + tex2DArrayDesc, + TextureRegion{ TextureSubresource{ 0, 2, 1, 1 }, Offset3D{ 1, 0, 0 }, Extent3D{ 2, 1, 1 } }, + colorsRgbaUb4, + sizeof(colorsRgbaUb4) + ); + } + return TestResult::Passed; } diff --git a/tests/Testbed/TestbedContext.cpp b/tests/Testbed/TestbedContext.cpp index b7e5e8678f..87b83a8b49 100644 --- a/tests/Testbed/TestbedContext.cpp +++ b/tests/Testbed/TestbedContext.cpp @@ -26,7 +26,7 @@ static bool HasArgument(int argc, char* argv[], const char* search) TestbedContext::TestbedContext(const char* moduleName, int argc, char* argv[]) : showTiming { HasArgument(argc, argv, "-t") || HasArgument(argc, argv, "--timing") }, - fastTest { HasArgument(argc, argv, "-fast") } + fastTest { HasArgument(argc, argv, "-f") || HasArgument(argc, argv, "--fast") } { RenderSystemDescriptor rendererDesc; {