diff options
| author | lucy96chen <47800040+lucy96chen@users.noreply.github.com> | 2022-03-21 16:56:11 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-21 16:56:11 -0700 |
| commit | 91292b8ca80ede633d1c4effaf8b3f5cf2ac3f2b (patch) | |
| tree | 8482871a0aac4cb939031c65886432a36068bcda /tools/gfx-unit-test/copy-texture-tests.cpp | |
| parent | 2e1a84add57efd9f8a50a88d0569a48ae4b6d834 (diff) | |
Add additional texture to texture copying tests (#2165)
* Working on finding a better way to do result comparisons in order to accommodate testing different formats and texture types, copying small to large texture currently half broken
* All tests except copying into a buffer with an offset working with new code for results comparison, support for most formats WIP
* Replaced SubresourceStuff with ValidationTextureData; Added implementation for ValidationTextureFormat::initializeTexel() and changed generateTextureData() to call this
* All implemented formats work on D3D12, a few broken for Vulkan
* Fixed numerous locations in render-vk.cpp to set aspect masks based on either the format or the provided TextureAspect; All tests except copy to buffer with offset working on new code structure
* All texture to texture copying tests work for all non-compressed formats; Test code cleaned up to minimize the amount of stuff needing to be passed between functions
* All tests working with all texture types except TextureCube and all non-compressed formats; Temporarily removing test for copying to a buffer at an offset, will likely return in a separate test file
* Small cleanup changes
* build fixes
Diffstat (limited to 'tools/gfx-unit-test/copy-texture-tests.cpp')
| -rw-r--r-- | tools/gfx-unit-test/copy-texture-tests.cpp | 1135 |
1 files changed, 959 insertions, 176 deletions
diff --git a/tools/gfx-unit-test/copy-texture-tests.cpp b/tools/gfx-unit-test/copy-texture-tests.cpp index dec71541f..6b9bced1a 100644 --- a/tools/gfx-unit-test/copy-texture-tests.cpp +++ b/tools/gfx-unit-test/copy-texture-tests.cpp @@ -14,43 +14,406 @@ using namespace gfx; namespace gfx_test { + struct ValidationTextureFormatBase : RefObject + { + virtual void validateBlocksEqual(const void* actual, const void* expected) = 0; + + virtual void initializeTexel(void* texel, int x, int y, int z, int mipLevel, int arrayLayer) = 0; + }; + + template <typename T> + struct ValidationTextureFormat : ValidationTextureFormatBase + { + int componentCount; + + ValidationTextureFormat(int componentCount) : componentCount(componentCount) {}; + + virtual void validateBlocksEqual(const void* actual, const void* expected) override + { + auto a = (const T*)actual; + auto e = (const T*)expected; + + for (Int i = 0; i < componentCount; ++i) + { + SLANG_CHECK(a[i] == e[i]); + } + } + + virtual void initializeTexel(void* texel, int x, int y, int z, int mipLevel, int arrayLayer) override + { + auto temp = (T*)texel; + + switch (componentCount) + { + case 1: + temp[0] = T(x + y + z + mipLevel + arrayLayer); + break; + case 2: + temp[0] = T(x + z + arrayLayer); + temp[1] = T(y + mipLevel); + break; + case 3: + temp[0] = T(x + mipLevel); + temp[1] = T(y + arrayLayer); + temp[2] = T(z); + break; + case 4: + temp[0] = T(x + arrayLayer); + temp[1] = (T)y; + temp[2] = (T)z; + temp[3] = (T)mipLevel; + break; + default: + assert(!"component count should be no greater than 4"); + SLANG_CHECK_ABORT(false); + } + } + }; + + template <typename T> + struct PackedValidationTextureFormat : ValidationTextureFormatBase + { + int rBits; + int gBits; + int bBits; + int aBits; + + PackedValidationTextureFormat(int rBits, int gBits, int bBits, int aBits) + : rBits(rBits), gBits(gBits), bBits(bBits), aBits(aBits) {}; + + virtual void validateBlocksEqual(const void* actual, const void* expected) override + { + T a[4]; + T e[4]; + unpackTexel(*(const T*)actual, a); + unpackTexel(*(const T*)expected, e); + + for (Int i = 0; i < 4; ++i) + { + SLANG_CHECK(a[i] == e[i]); + } + } + + virtual void initializeTexel(void* texel, int x, int y, int z, int mipLevel, int arrayLayer) override + { + T temp = 0; + + // The only formats which currently use this have either 3 or 4 channels. TODO: BC formats? + if (aBits == 0) + { + temp |= z; + temp <<= gBits; + temp |= (y + arrayLayer); + temp <<= rBits; + temp |= (x + mipLevel); + } + else + { + temp |= mipLevel; + temp <<= bBits; + temp |= z; + temp <<= gBits; + temp |= y; + temp <<= rBits; + temp |= (x + arrayLayer); + } + + *(T*)texel = temp; + } + + void unpackTexel(T texel, T* outComponents) + { + outComponents[0] = texel & ((1 << rBits) - 1); + texel >>= rBits; + + outComponents[1] = texel & ((1 << gBits) - 1); + texel >>= gBits; + + outComponents[2] = texel & ((1 << bBits) - 1); + texel >>= bBits; + + outComponents[3] = texel & ((1 << aBits) - 1); + texel >>= aBits; + + //for () + } + }; + + RefPtr<ValidationTextureFormatBase> getValidationTextureFormat(Format format) + { + switch (format) + { + case Format::R32G32B32A32_TYPELESS: return new ValidationTextureFormat<uint32_t>(4); + case Format::R32G32B32_TYPELESS: return new ValidationTextureFormat<uint32_t>(3); + case Format::R32G32_TYPELESS: return new ValidationTextureFormat<uint32_t>(2); + case Format::R32_TYPELESS: return new ValidationTextureFormat<uint32_t>(1); + + case Format::R16G16B16A16_TYPELESS: return new ValidationTextureFormat<uint16_t>(4); + case Format::R16G16_TYPELESS: return new ValidationTextureFormat<uint16_t>(2); + case Format::R16_TYPELESS: return new ValidationTextureFormat<uint16_t>(1); + + case Format::R8G8B8A8_TYPELESS: return new ValidationTextureFormat<uint8_t>(4); + case Format::R8G8_TYPELESS: return new ValidationTextureFormat<uint8_t>(2); + case Format::R8_TYPELESS: return new ValidationTextureFormat<uint8_t>(1); + case Format::B8G8R8A8_TYPELESS: return new ValidationTextureFormat<uint8_t>(4); + + case Format::R32G32B32A32_FLOAT: return new ValidationTextureFormat<float>(4); + case Format::R32G32B32_FLOAT: return new ValidationTextureFormat<float>(3); + case Format::R32G32_FLOAT: return new ValidationTextureFormat<float>(2); + case Format::R32_FLOAT: return new ValidationTextureFormat<float>(1); + + case Format::R16G16B16A16_FLOAT: return new ValidationTextureFormat<uint16_t>(4); + case Format::R16G16_FLOAT: return new ValidationTextureFormat<uint16_t>(2); + case Format::R16_FLOAT: return new ValidationTextureFormat<uint16_t>(1); + + case Format::R32G32B32A32_UINT: return new ValidationTextureFormat<uint32_t>(4); + case Format::R32G32B32_UINT: return new ValidationTextureFormat<uint32_t>(3); + case Format::R32G32_UINT: return new ValidationTextureFormat<uint32_t>(2); + case Format::R32_UINT: return new ValidationTextureFormat<uint32_t>(1); + + case Format::R16G16B16A16_UINT: return new ValidationTextureFormat<uint16_t>(4); + case Format::R16G16_UINT: return new ValidationTextureFormat<uint16_t>(2); + case Format::R16_UINT: return new ValidationTextureFormat<uint16_t>(1); + + case Format::R8G8B8A8_UINT: return new ValidationTextureFormat<uint8_t>(4); + case Format::R8G8_UINT: return new ValidationTextureFormat<uint8_t>(2); + case Format::R8_UINT: return new ValidationTextureFormat<uint8_t>(1); + + case Format::R32G32B32A32_SINT: return new ValidationTextureFormat<int32_t>(4); + case Format::R32G32B32_SINT: return new ValidationTextureFormat<int32_t>(3); + case Format::R32G32_SINT: return new ValidationTextureFormat<int32_t>(2); + case Format::R32_SINT: return new ValidationTextureFormat<int32_t>(1); + + case Format::R16G16B16A16_SINT: return new ValidationTextureFormat<int16_t>(4); + case Format::R16G16_SINT: return new ValidationTextureFormat<int16_t>(2); + case Format::R16_SINT: return new ValidationTextureFormat<int16_t>(1); + + case Format::R8G8B8A8_SINT: return new ValidationTextureFormat<int8_t>(4); + case Format::R8G8_SINT: return new ValidationTextureFormat<int8_t>(2); + case Format::R8_SINT: return new ValidationTextureFormat<int8_t>(1); + + case Format::R16G16B16A16_UNORM: return new ValidationTextureFormat<uint16_t>(4); + case Format::R16G16_UNORM: return new ValidationTextureFormat<uint16_t>(2); + case Format::R16_UNORM: return new ValidationTextureFormat<uint16_t>(1); + + case Format::R8G8B8A8_UNORM: return new ValidationTextureFormat<uint8_t>(4); + case Format::R8G8B8A8_UNORM_SRGB: return new ValidationTextureFormat<uint8_t>(4); + case Format::R8G8_UNORM: return new ValidationTextureFormat<uint8_t>(2); + case Format::R8_UNORM: return new ValidationTextureFormat<uint8_t>(1); + case Format::B8G8R8A8_UNORM: return new ValidationTextureFormat<uint8_t>(4); + case Format::B8G8R8A8_UNORM_SRGB: return new ValidationTextureFormat<uint8_t>(4); + case Format::B8G8R8X8_UNORM: return new ValidationTextureFormat<uint8_t>(3); + case Format::B8G8R8X8_UNORM_SRGB: return new ValidationTextureFormat<uint8_t>(3); + + case Format::R16G16B16A16_SNORM: return new ValidationTextureFormat<int16_t>(4); + case Format::R16G16_SNORM: return new ValidationTextureFormat<int16_t>(2); + case Format::R16_SNORM: return new ValidationTextureFormat<int16_t>(1); + + case Format::R8G8B8A8_SNORM: return new ValidationTextureFormat<int8_t>(4); + case Format::R8G8_SNORM: return new ValidationTextureFormat<int8_t>(2); + case Format::R8_SNORM: return new ValidationTextureFormat<int8_t>(1); + + case Format::D32_FLOAT: return new ValidationTextureFormat<float>(1); + case Format::D16_UNORM: return new ValidationTextureFormat<uint16_t>(1); + + case Format::B4G4R4A4_UNORM: return new PackedValidationTextureFormat<uint16_t>(4, 4, 4, 4); + case Format::B5G6R5_UNORM: return new PackedValidationTextureFormat<uint16_t>(5, 6, 5, 0); + case Format::B5G5R5A1_UNORM: return new PackedValidationTextureFormat<uint16_t>(5, 5, 5, 1); + + case Format::R9G9B9E5_SHAREDEXP: return new ValidationTextureFormat<uint32_t>(1); + case Format::R10G10B10A2_TYPELESS: return new PackedValidationTextureFormat<uint32_t>(10, 10, 10, 2); + case Format::R10G10B10A2_UNORM: return new PackedValidationTextureFormat<uint32_t>(10, 10, 10, 2); + case Format::R10G10B10A2_UINT: return new PackedValidationTextureFormat<uint32_t>(10, 10, 10, 2); + case Format::R11G11B10_FLOAT: return new PackedValidationTextureFormat<uint32_t>(11, 11, 10, 0); + + // TODO: Add testing support for BC formats +// BC1_UNORM, +// BC1_UNORM_SRGB, +// BC2_UNORM, +// BC2_UNORM_SRGB, +// BC3_UNORM, +// BC3_UNORM_SRGB, +// BC4_UNORM, +// BC4_SNORM, +// BC5_UNORM, +// BC5_SNORM, +// BC6H_UF16, +// BC6H_SF16, +// BC7_UNORM, +// BC7_UNORM_SRGB, + default: + return nullptr; + } + } + + struct TextureInfo + { + ITextureResource::Size extent; + int numMipLevels; + int arraySize; + ITextureResource::SubresourceData const* initData; + }; + + struct ValidationTextureData : RefObject + { + const void* textureData; + ITextureResource::Size extents; + ITextureResource::Offset3D strides; + + void* getBlockAt(Int x, Int y, Int z) + { + assert(x >= 0 && x < extents.width); + assert(y >= 0 && y < extents.height); + assert(z >= 0 && z < extents.depth); + + char* layerData = (char*)textureData + z * strides.z; + char* rowData = layerData + y * strides.y; + return rowData + x * strides.x; + } + }; + + struct TextureToTextureCopyInfo + { + SubresourceRange srcSubresource; + SubresourceRange dstSubresource; + ITextureResource::Size extent; + ITextureResource::Offset3D srcOffset; + ITextureResource::Offset3D dstOffset; + }; + + struct TextureToBufferCopyInfo + { + SubresourceRange srcSubresource; + ITextureResource::Size extent; + ITextureResource::Offset3D textureOffset; + size_t bufferOffset; + size_t bufferSize; + }; + + struct TextureStuff : RefObject + { + List<RefPtr<ValidationTextureData>> subresourceObjects; + List<ITextureResource::SubresourceData> subresourceDatas; + }; + struct BaseCopyTextureTest { IDevice* device; UnitTestContext* context; + Format format; + uint32_t texelSize; + size_t alignedRowStride; + ITextureResource::Type textureType; + + TextureInfo srcTextureInfo; + TextureInfo dstTextureInfo; + TextureToTextureCopyInfo texCopyInfo; + TextureToBufferCopyInfo bufferCopyInfo; + ComPtr<ITextureResource> srcTexture; ComPtr<ITextureResource> dstTexture; ComPtr<IBufferResource> resultsBuffer; - size_t alignedRowPitch; + RefPtr<ValidationTextureFormatBase> validationFormat; + + void init( + IDevice* device, + UnitTestContext* context, + Format format, + RefPtr<ValidationTextureFormatBase> validationFormat, + ITextureResource::Type type) + { + this->device = device; + this->context = context; + this->format = format; + this->validationFormat = validationFormat; + this->textureType = type; + + FormatInfo formatInfo; + GFX_CHECK_CALL_ABORT(gfxGetFormatInfo(format, &formatInfo)); + this->texelSize = formatInfo.blockSizeInBytes / formatInfo.pixelsPerBlock; + } - struct TextureInfo + RefPtr<TextureStuff> generateTextureData(int width, int height, int depth, uint32_t mipLevels, uint32_t arrayLayers) { - ITextureResource::Size extent; - int numMipLevels; - int arraySize; - ITextureResource::SubresourceData const* initData; - }; + RefPtr<TextureStuff> texture = new TextureStuff(); + for (uint32_t layer = 0; layer < arrayLayers; ++layer) + { + for (uint32_t mip = 0; mip < mipLevels; ++mip) + { + RefPtr<ValidationTextureData> subresource = new ValidationTextureData(); - void init(IDevice* device, UnitTestContext* context) + auto mipWidth = Math::Max(width >> mip, 1); + auto mipHeight = Math::Max(height >> mip, 1); + auto mipDepth = Math::Max(depth >> mip, 1); + auto mipSize = mipWidth * mipHeight * mipDepth * texelSize; + subresource->textureData = malloc(mipSize); + SLANG_CHECK_ABORT(subresource->textureData); + + subresource->extents.width = mipWidth; + subresource->extents.height = mipHeight; + subresource->extents.depth = mipDepth; + subresource->strides.x = texelSize; + subresource->strides.y = mipWidth * texelSize; + subresource->strides.z = mipHeight * subresource->strides.y; + texture->subresourceObjects.add(subresource); + + for (int z = 0; z < mipDepth; ++z) + { + for (int y = 0; y < mipHeight; ++y) + { + for (int x = 0; x < mipWidth; ++x) + { + auto texel = subresource->getBlockAt(x, y, z); + validationFormat->initializeTexel(texel, x, y, z, mip, layer); + } + } + } + + ITextureResource::SubresourceData subData = {}; + subData.data = subresource->textureData; + subData.strideY = subresource->strides.y; + subData.strideZ = subresource->strides.z; + texture->subresourceDatas.add(subData); + } + } + return texture; + } + + TextureAspect getTextureAspect() { - this->device = device; - this->context = context; + switch (format) + { + case Format::D16_UNORM: + case Format::D32_FLOAT: + return TextureAspect::Depth; + default: + return TextureAspect::Color; + } } - void createRequiredResources(TextureInfo srcTextureInfo, TextureInfo dstTextureInfo, Format format) + uint32_t getSubresourceIndex(uint32_t mipLevel, uint32_t mipLevelCount, uint32_t baseArrayLayer) + { + return baseArrayLayer * mipLevelCount + mipLevel; + } + + void createRequiredResources() { ITextureResource::Desc srcTexDesc = {}; - srcTexDesc.type = IResource::Type::Texture2D; + srcTexDesc.type = textureType; srcTexDesc.numMipLevels = srcTextureInfo.numMipLevels; srcTexDesc.arraySize = srcTextureInfo.arraySize; srcTexDesc.size = srcTextureInfo.extent; - srcTexDesc.defaultState = ResourceState::UnorderedAccess; + srcTexDesc.defaultState = ResourceState::ShaderResource; srcTexDesc.allowedStates = ResourceStateSet( - ResourceState::UnorderedAccess, ResourceState::ShaderResource, ResourceState::CopySource); + if (format == Format::D32_FLOAT || format == Format::D16_UNORM) + { + srcTexDesc.allowedStates.add(ResourceState::DepthWrite); + srcTexDesc.allowedStates.add(ResourceState::DepthRead); + } srcTexDesc.format = format; GFX_CHECK_CALL_ABORT(device->createTextureResource( @@ -59,7 +422,7 @@ namespace gfx_test srcTexture.writeRef())); ITextureResource::Desc dstTexDesc = {}; - dstTexDesc.type = IResource::Type::Texture2D; + dstTexDesc.type = textureType; dstTexDesc.numMipLevels = dstTextureInfo.numMipLevels; dstTexDesc.arraySize = dstTextureInfo.arraySize; dstTexDesc.size = dstTextureInfo.extent; @@ -68,6 +431,11 @@ namespace gfx_test ResourceState::ShaderResource, ResourceState::CopyDestination, ResourceState::CopySource); + if (format == Format::D32_FLOAT || format == Format::D16_UNORM) + { + srcTexDesc.allowedStates.add(ResourceState::DepthWrite); + srcTexDesc.allowedStates.add(ResourceState::DepthRead); + } dstTexDesc.format = format; GFX_CHECK_CALL_ABORT(device->createTextureResource( @@ -75,13 +443,12 @@ namespace gfx_test dstTextureInfo.initData, dstTexture.writeRef())); - FormatInfo formatInfo; - gfxGetFormatInfo(format, &formatInfo); + auto bufferCopyExtents = bufferCopyInfo.extent; size_t alignment; device->getTextureRowAlignment(&alignment); - alignedRowPitch = (dstTextureInfo.extent.width * formatInfo.blockSizeInBytes + alignment - 1) & ~(alignment - 1); + alignedRowStride = (bufferCopyExtents.width * texelSize + alignment - 1) & ~(alignment - 1); IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = dstTextureInfo.extent.height * alignedRowPitch; + bufferDesc.sizeInBytes = bufferCopyExtents.height * bufferCopyExtents.depth * alignedRowStride; bufferDesc.format = gfx::Format::Unknown; bufferDesc.elementSize = 0; bufferDesc.allowedStates = ResourceStateSet( @@ -89,6 +456,11 @@ namespace gfx_test ResourceState::UnorderedAccess, ResourceState::CopyDestination, ResourceState::CopySource); + if (format == Format::D32_FLOAT || format == Format::D16_UNORM) + { + srcTexDesc.allowedStates.add(ResourceState::DepthWrite); + srcTexDesc.allowedStates.add(ResourceState::DepthRead); + } bufferDesc.defaultState = ResourceState::CopyDestination; bufferDesc.memoryType = MemoryType::DeviceLocal; @@ -96,15 +468,11 @@ namespace gfx_test bufferDesc, nullptr, resultsBuffer.writeRef())); + + bufferCopyInfo.bufferSize = bufferDesc.sizeInBytes; } - void submitGPUWork( - SubresourceRange srcSubresource, - SubresourceRange dstSubresource, - ITextureResource::Offset3D srcOffset, - ITextureResource::Offset3D dstOffset, - ITextureResource::Size extent, - size_t textureSize) + void submitGPUWork() { Slang::ComPtr<ITransientResourceHeap> transientHeap; ITransientResourceHeap::Desc transientHeapDesc = {}; @@ -118,249 +486,664 @@ namespace gfx_test auto commandBuffer = transientHeap->createCommandBuffer(); auto encoder = commandBuffer->encodeResourceCommands(); - encoder->textureSubresourceBarrier(srcTexture, srcSubresource, ResourceState::UnorderedAccess, ResourceState::CopySource); - encoder->copyTexture(dstTexture, ResourceState::CopyDestination, dstSubresource, dstOffset, srcTexture, ResourceState::CopySource, srcSubresource, srcOffset, extent); - encoder->textureSubresourceBarrier(dstTexture, dstSubresource, ResourceState::CopyDestination, ResourceState::CopySource); - encoder->copyTextureToBuffer(resultsBuffer, 0, textureSize, alignedRowPitch, dstTexture, ResourceState::CopySource, dstSubresource, dstOffset, extent); + encoder->textureSubresourceBarrier(srcTexture, texCopyInfo.srcSubresource, ResourceState::ShaderResource, ResourceState::CopySource); + encoder->copyTexture( + dstTexture, + ResourceState::CopyDestination, + texCopyInfo.dstSubresource, + texCopyInfo.dstOffset, + srcTexture, + ResourceState::CopySource, + texCopyInfo.srcSubresource, + texCopyInfo.srcOffset, + texCopyInfo.extent); + + encoder->textureSubresourceBarrier(dstTexture, bufferCopyInfo.srcSubresource, ResourceState::CopyDestination, ResourceState::CopySource); + encoder->copyTextureToBuffer( + resultsBuffer, + bufferCopyInfo.bufferOffset, + bufferCopyInfo.bufferSize, + alignedRowStride, + dstTexture, + ResourceState::CopySource, + bufferCopyInfo.srcSubresource, + bufferCopyInfo.textureOffset, + bufferCopyInfo.extent); + encoder->endEncoding(); commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); queue->waitOnHost(); } + + bool isWithinCopyBounds(int x, int y, int z) + { + auto copyExtents = texCopyInfo.extent; + auto copyOffset = texCopyInfo.dstOffset; + + auto xLowerBound = copyOffset.x; + auto xUpperBound = copyOffset.x + copyExtents.width; + auto yLowerBound = copyOffset.y; + auto yUpperBound = copyOffset.y + copyExtents.height; + auto zLowerBound = copyOffset.z; + auto zUpperBound = copyOffset.z + copyExtents.depth; + + if (x < xLowerBound || x >= xUpperBound || y < yLowerBound || y >= yUpperBound || z < zLowerBound || z >= zUpperBound) + return false; + else + return true; + } + + void validateTestResults( + ValidationTextureData actual, + ValidationTextureData expectedCopied, + ValidationTextureData expectedOriginal) + { + auto actualExtents = actual.extents; + auto copyExtent = texCopyInfo.extent; + auto srcTexOffset = texCopyInfo.srcOffset; + auto dstTexOffset = texCopyInfo.dstOffset; + + for (Int x = 0; x < actualExtents.width; ++x) + { + for (Int y = 0; y < actualExtents.height; ++y) + { + for (Int z = 0; z < actualExtents.depth; ++z) + { + auto actualBlock = actual.getBlockAt(x, y, z); + if (isWithinCopyBounds(x, y, z)) + { + // Block is located within the bounds of the source texture + auto xSource = x + srcTexOffset.x - dstTexOffset.x; + auto ySource = y + srcTexOffset.y - dstTexOffset.y; + auto zSource = z + srcTexOffset.z - dstTexOffset.z; + auto expectedBlock = expectedCopied.getBlockAt(xSource, ySource, zSource); + validationFormat->validateBlocksEqual(actualBlock, expectedBlock); + } + else + { + // Block is located outside the bounds of the source texture and should be compared + // against known expected values for the destination texture. + auto expectedBlock = expectedOriginal.getBlockAt(x, y, z); + validationFormat->validateBlocksEqual(actualBlock, expectedBlock); + } + } + } + } + } + + void checkTestResults(ITextureResource::Size srcMipExtent, const void* expectedCopiedData, const void* expectedOriginalData) + { + ComPtr<ISlangBlob> resultBlob; + GFX_CHECK_CALL_ABORT(device->readBufferResource(resultsBuffer, 0, bufferCopyInfo.bufferSize, resultBlob.writeRef())); + auto results = resultBlob->getBufferPointer(); + + ValidationTextureData actual; + actual.extents = bufferCopyInfo.extent; + actual.textureData = results; + actual.strides.x = texelSize; + actual.strides.y = (uint32_t)alignedRowStride; + actual.strides.z = actual.extents.height * actual.strides.y; + + ValidationTextureData expectedCopied; + expectedCopied.extents = srcMipExtent; + expectedCopied.textureData = expectedCopiedData; + expectedCopied.strides.x = texelSize; + expectedCopied.strides.y = expectedCopied.extents.width * expectedCopied.strides.x; + expectedCopied.strides.z = expectedCopied.extents.height * expectedCopied.strides.y; + + ValidationTextureData expectedOriginal; + if (expectedOriginalData) + { + expectedOriginal.extents = bufferCopyInfo.extent; + expectedOriginal.textureData = expectedOriginalData; + expectedOriginal.strides.x = texelSize; + expectedOriginal.strides.y = expectedOriginal.extents.width * expectedOriginal.strides.x; + expectedOriginal.strides.z = expectedOriginal.extents.height * expectedOriginal.strides.y; + } + + validateTestResults(actual, expectedCopied, expectedOriginal); + } }; struct SimpleCopyTexture : BaseCopyTextureTest { - Format format = Format::R8G8B8A8_UINT; + void run() + { + ITextureResource::Size extent = {}; + extent.width = 4; + extent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + extent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto mipLevelCount = 1; + auto arrayLayerCount = 1; + + auto srcTextureStuff = generateTextureData(extent.width, extent.height, extent.depth, mipLevelCount, arrayLayerCount); + + srcTextureInfo = { extent, mipLevelCount, arrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; + dstTextureInfo = { extent, mipLevelCount, arrayLayerCount, nullptr }; + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = extent; + texCopyInfo.srcOffset = { 0, 0, 0 }; + texCopyInfo.dstOffset = { 0, 0, 0 }; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = extent; + bufferCopyInfo.textureOffset = { 0, 0, 0 }; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto subresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, mipLevelCount, srcSubresource.baseArrayLayer); + auto expectedData = srcTextureStuff->subresourceDatas[subresourceIndex]; + checkTestResults(extent, expectedData.data, nullptr); + } + }; + struct CopyTextureSection : BaseCopyTextureTest + { void run() { ITextureResource::Size extent = {}; - extent.width = 2; - extent.height = 2; - extent.depth = 1; + extent.width = 4; + extent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + extent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto mipLevelCount = 2; + auto arrayLayerCount = (textureType == ITextureResource::Type::Texture3D) ? 1 : 2; + + auto srcTextureStuff = generateTextureData(extent.width, extent.height, extent.depth, mipLevelCount, arrayLayerCount); + + srcTextureInfo = { extent, mipLevelCount, arrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; + dstTextureInfo = { extent, mipLevelCount, arrayLayerCount, nullptr }; + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = (textureType == ITextureResource::Type::Texture3D) ? 0 : 1; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = extent; + texCopyInfo.srcOffset = { 0, 0, 0 }; + texCopyInfo.dstOffset = { 0, 0, 0 }; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = extent; + bufferCopyInfo.textureOffset = { 0, 0, 0 }; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto subresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, mipLevelCount, srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedData = srcTextureStuff->subresourceDatas[subresourceIndex]; + checkTestResults(extent, expectedData.data, nullptr); + } + }; - uint8_t srcTexData[16] = { 255u, 0u, 0u, 255u, 0u, 255u, 0u, 255u, - 0u, 0u, 255u, 255u, 127u, 127u, 127u, 255u }; - ITextureResource::SubresourceData srcSubData = { (void*)srcTexData, 8, 0 }; + struct LargeSrcToSmallDst : BaseCopyTextureTest + { + void run() + { + ITextureResource::Size srcExtent = {}; + srcExtent.width = 8; + srcExtent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; + srcExtent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto srcMipLevelCount = 1; + auto srcArrayLayerCount = 1; - uint8_t dstTexData[16] = { 0u }; - ITextureResource::SubresourceData dstSubData = { (void*)dstTexData, 8, 0 }; + auto srcTextureStuff = generateTextureData(srcExtent.width, srcExtent.height, srcExtent.depth, srcMipLevelCount, srcArrayLayerCount); + srcTextureInfo = { srcExtent, srcMipLevelCount, srcArrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; - TextureInfo srcTextureInfo = { extent, 1, 1, &srcSubData }; - TextureInfo dstTextureInfo = { extent, 1, 1, &dstSubData }; + ITextureResource::Size dstExtent = {}; + dstExtent.width = 4; + dstExtent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + dstExtent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto dstMipLevelCount = 1; + auto dstArrayLayerCount = 1; - createRequiredResources(srcTextureInfo, dstTextureInfo, format); + dstTextureInfo = { dstExtent, dstMipLevelCount, dstArrayLayerCount, nullptr }; SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = TextureAspect::Color; + srcSubresource.aspectMask = getTextureAspect(); srcSubresource.mipLevel = 0; srcSubresource.mipLevelCount = 1; srcSubresource.baseArrayLayer = 0; srcSubresource.layerCount = 1; - ITextureResource::Offset3D srcOffset; - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = TextureAspect::Color; + dstSubresource.aspectMask = getTextureAspect(); dstSubresource.mipLevel = 0; dstSubresource.mipLevelCount = 1; dstSubresource.baseArrayLayer = 0; dstSubresource.layerCount = 1; - ITextureResource::Offset3D dstOffset; + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = dstExtent; + texCopyInfo.srcOffset = { 0, 0, 0 }; + texCopyInfo.dstOffset = { 0, 0, 0 }; - submitGPUWork(srcSubresource, dstSubresource, srcOffset, dstOffset, extent, 16); + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstExtent; + bufferCopyInfo.textureOffset = { 0, 0, 0 }; + bufferCopyInfo.bufferOffset = 0; - if (device->getDeviceInfo().deviceType == DeviceType::DirectX12) - { - // D3D12 has to pad out the rows in order to adhere to alignment, so when comparing results - // we need to make sure not to include the padding. - size_t testOffset = 0; - for (Int i = 0; i < extent.height; ++i) - { - compareComputeResult( - device, - resultsBuffer, - testOffset, - srcTexData + 8 * i, - 8); - testOffset += alignedRowPitch; - } - } - else if (device->getDeviceInfo().deviceType == DeviceType::Vulkan) - { - compareComputeResult( - device, - resultsBuffer, - 0, - srcTexData, - 16); - } + createRequiredResources(); + submitGPUWork(); + + auto subresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcMipLevelCount, srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedData = srcTextureStuff->subresourceDatas[subresourceIndex]; + checkTestResults(srcExtent, expectedData.data, nullptr); } }; - struct Texel + struct SmallSrcToLargeDst : BaseCopyTextureTest { - float channels[4]; + void run() + { + ITextureResource::Size srcExtent = {}; + srcExtent.width = 4; + srcExtent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + srcExtent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto srcMipLevelCount = 1; + auto srcArrayLayerCount = 1; + + auto srcTextureStuff = generateTextureData(srcExtent.width, srcExtent.height, srcExtent.depth, srcMipLevelCount, srcArrayLayerCount); + srcTextureInfo = { srcExtent, srcMipLevelCount, srcArrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; + + ITextureResource::Size dstExtent = {}; + dstExtent.width = 8; + dstExtent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; + dstExtent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto dstMipLevelCount = 1; + auto dstArrayLayerCount = 1; + + auto dstTextureStuff = generateTextureData(dstExtent.width, dstExtent.height, dstExtent.depth, dstMipLevelCount, dstArrayLayerCount); + dstTextureInfo = { dstExtent, dstMipLevelCount, dstArrayLayerCount, dstTextureStuff->subresourceDatas.getBuffer() }; + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = srcExtent; + texCopyInfo.srcOffset = { 0, 0, 0 }; + texCopyInfo.dstOffset = { 0, 0, 0 }; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstExtent; + bufferCopyInfo.textureOffset = { 0, 0, 0 }; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcMipLevelCount, srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedCopiedData = srcTextureStuff->subresourceDatas[copiedSubresourceIndex]; + auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, dstMipLevelCount, dstSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedOriginalData = dstTextureStuff->subresourceDatas[originalSubresourceIndex]; + checkTestResults(srcExtent, expectedCopiedData.data, expectedOriginalData.data); + } }; - struct SubresourceStuff : RefObject + struct CopyBetweenMips : BaseCopyTextureTest { - List<Texel> texels; + void run() + { + ITextureResource::Size srcExtent = {}; + srcExtent.width = 16; + srcExtent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 16; + srcExtent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto srcMipLevelCount = 4; + auto srcArrayLayerCount = 1; + + auto srcTextureStuff = generateTextureData(srcExtent.width, srcExtent.height, srcExtent.depth, srcMipLevelCount, srcArrayLayerCount); + srcTextureInfo = { srcExtent, srcMipLevelCount, srcArrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; + + ITextureResource::Size dstExtent = {}; + dstExtent.width = 16; + dstExtent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 16; + dstExtent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto dstMipLevelCount = 4; + auto dstArrayLayerCount = 1; + + auto dstTextureStuff = generateTextureData(dstExtent.width, dstExtent.height, dstExtent.depth, dstMipLevelCount, dstArrayLayerCount); + dstTextureInfo = { dstExtent, dstMipLevelCount, dstArrayLayerCount, dstTextureStuff->subresourceDatas.getBuffer() }; + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(); + srcSubresource.mipLevel = 2; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(); + dstSubresource.mipLevel = 1; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcMipLevelCount, srcSubresource.baseArrayLayer); + auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, dstMipLevelCount, dstSubresource.baseArrayLayer); + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = srcTextureStuff->subresourceObjects[copiedSubresourceIndex]->extents; + texCopyInfo.srcOffset = { 0, 0, 0 }; + texCopyInfo.dstOffset = { 0, 0, 0 }; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstTextureStuff->subresourceObjects[originalSubresourceIndex]->extents; + bufferCopyInfo.textureOffset = { 0, 0, 0 }; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + ITextureResource::SubresourceData expectedCopiedData = srcTextureStuff->subresourceDatas[copiedSubresourceIndex]; + ITextureResource::SubresourceData expectedOriginalData = dstTextureStuff->subresourceDatas[originalSubresourceIndex]; + auto srcMipExtent = srcTextureStuff->subresourceObjects[2]->extents; + checkTestResults(srcMipExtent, expectedCopiedData.data, expectedOriginalData.data); + } }; - struct TextureStuff : RefObject + struct CopyBetweenLayers : BaseCopyTextureTest { - List<RefPtr<SubresourceStuff>> subresourceObjects; - List<ITextureResource::SubresourceData> subresourceDatas; + void run() + { + ITextureResource::Size extent = {}; + extent.width = 4; + extent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 4; + extent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto mipLevelCount = 1; + auto arrayLayerCount = (textureType == ITextureResource::Type::Texture3D) ? 1 : 2; + + auto srcTextureStuff = generateTextureData(extent.width, extent.height, extent.depth, mipLevelCount, arrayLayerCount); + srcTextureInfo = { extent, mipLevelCount, arrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; + + auto dstTextureStuff = generateTextureData(extent.width, extent.height, extent.depth, mipLevelCount, arrayLayerCount); + dstTextureInfo = { extent, mipLevelCount, arrayLayerCount, dstTextureStuff->subresourceDatas.getBuffer() }; + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = (textureType == ITextureResource::Type::Texture3D) ? 0 : 1; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent = extent; + texCopyInfo.srcOffset = { 0, 0, 0 }; + texCopyInfo.dstOffset = { 0, 0, 0 }; + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = extent; + bufferCopyInfo.textureOffset = { 0, 0, 0 }; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, mipLevelCount, srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedCopiedData = srcTextureStuff->subresourceDatas[copiedSubresourceIndex]; + auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, mipLevelCount, dstSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedOriginalData = dstTextureStuff->subresourceDatas[originalSubresourceIndex]; + checkTestResults(extent, expectedCopiedData.data, expectedOriginalData.data); + } }; - struct CopyTextureSection : BaseCopyTextureTest + struct CopyWithOffsets : BaseCopyTextureTest { - Format format = Format::R32G32B32A32_FLOAT; - - RefPtr<TextureStuff> generateTextureData(int width, int height, uint32_t mipLevels, uint32_t arrayLayers) + void run() { - RefPtr<TextureStuff> texture = new TextureStuff(); - for (uint32_t layer = 0; layer < arrayLayers; ++layer) - { - for (uint32_t mip = 0; mip < mipLevels; ++mip) - { - RefPtr<SubresourceStuff> subresource = new SubresourceStuff(); - texture->subresourceObjects.add(subresource); + ITextureResource::Size srcExtent = {}; + srcExtent.width = 8; + srcExtent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; + srcExtent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto srcMipLevelCount = 1; + auto srcArrayLayerCount = 1; - int mipWidth = Math::Max(width >> mip, 1); - int mipHeight = Math::Max(height >> mip, 1); + auto srcTextureStuff = generateTextureData(srcExtent.width, srcExtent.height, srcExtent.depth, srcMipLevelCount, srcArrayLayerCount); + srcTextureInfo = { srcExtent, srcMipLevelCount, srcArrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; - int mipTexelCount = mipWidth * mipHeight; - subresource->texels.setCount(mipTexelCount); - for (int h = 0; h < mipHeight; ++h) - { - for (int w = 0; w < mipWidth; ++w) - { - // 4 channels per pixel - subresource->texels[h * mipWidth + w].channels[0] = (float)w; - subresource->texels[h * mipWidth + w].channels[1] = (float)h; - subresource->texels[h * mipWidth + w].channels[2] = (float)mip; - subresource->texels[h * mipWidth + w].channels[3] = (float)layer; - } - } + ITextureResource::Size dstExtent = {}; + dstExtent.width = 16; + dstExtent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 16; + dstExtent.depth = (textureType == ITextureResource::Type::Texture3D) ? 4 : 1; + auto dstMipLevelCount = 1; + auto dstArrayLayerCount = 1; - ITextureResource::SubresourceData subData = {}; - subData.data = subresource->texels.getBuffer(); - subData.strideY = mipWidth * sizeof(Texel); - subData.strideZ = mipHeight * subData.strideY; - texture->subresourceDatas.add(subData); - } + auto dstTextureStuff = generateTextureData(dstExtent.width, dstExtent.height, dstExtent.depth, dstMipLevelCount, dstArrayLayerCount); + dstTextureInfo = { dstExtent, dstMipLevelCount, dstArrayLayerCount, dstTextureStuff->subresourceDatas.getBuffer() }; + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = getTextureAspect(); + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = getTextureAspect(); + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent.width = 4; + texCopyInfo.extent.height = 4; + texCopyInfo.extent.depth = 1; + texCopyInfo.srcOffset = { 2, 2, 0 }; + texCopyInfo.dstOffset = { 4, 4, 0 }; + + if (textureType == ITextureResource::Type::Texture1D) + { + texCopyInfo.extent.height = 1; + texCopyInfo.srcOffset.y = 0; + texCopyInfo.dstOffset.y = 0; } - return texture; - } + else if (textureType == ITextureResource::Type::Texture3D) + { + texCopyInfo.extent.depth = srcExtent.depth; + texCopyInfo.dstOffset.z = 1; + } + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = dstExtent; + bufferCopyInfo.textureOffset = { 0, 0, 0 }; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); - // TODO: Things to test in the future - // 1. Size of src texture(W, H, mips, layers) - // 2. Size of dst texture(...) - // 3. src subresource(mip, layer) - // 4. dst subresource(mip, layer) - // 5. copy extents(x, y) - // 6. copy src coords(x, y) - // 7. copy dst coords(x, y) - // 8. Final buffer offset + auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, srcMipLevelCount, srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedCopiedData = srcTextureStuff->subresourceDatas[copiedSubresourceIndex]; + auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, dstMipLevelCount, dstSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedOriginalData = dstTextureStuff->subresourceDatas[originalSubresourceIndex]; + checkTestResults(srcExtent, expectedCopiedData.data, expectedOriginalData.data); + } + }; + struct CopySectionWithSetExtent : BaseCopyTextureTest + { void run() { ITextureResource::Size extent = {}; - extent.width = 4; - extent.height = 4; - extent.depth = 1; - - auto mipLevelCount = 2; - auto arrayLayerCount = 2; + extent.width = 8; + extent.height = (textureType == ITextureResource::Type::Texture1D) ? 1 : 8; + extent.depth = (textureType == ITextureResource::Type::Texture3D) ? 2 : 1; + auto mipLevelCount = 1; + auto arrayLayerCount = 1; - auto srcTextureStuff = generateTextureData(extent.width, extent.height, mipLevelCount, arrayLayerCount); - - TextureInfo srcTextureInfo = { extent, mipLevelCount, arrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; - TextureInfo dstTextureInfo = { extent, mipLevelCount, arrayLayerCount, nullptr }; + auto srcTextureStuff = generateTextureData(extent.width, extent.height, extent.depth, mipLevelCount, arrayLayerCount); + srcTextureInfo = { extent, mipLevelCount, arrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; - createRequiredResources(srcTextureInfo, dstTextureInfo, format); + auto dstTextureStuff = generateTextureData(extent.width, extent.height, extent.depth, mipLevelCount, arrayLayerCount); + dstTextureInfo = { extent, mipLevelCount, arrayLayerCount, dstTextureStuff->subresourceDatas.getBuffer() }; SubresourceRange srcSubresource = {}; - srcSubresource.aspectMask = TextureAspect::Color; + srcSubresource.aspectMask = getTextureAspect(); srcSubresource.mipLevel = 0; srcSubresource.mipLevelCount = 1; - srcSubresource.baseArrayLayer = 1; + srcSubresource.baseArrayLayer = 0; srcSubresource.layerCount = 1; - ITextureResource::Offset3D srcOffset; - SubresourceRange dstSubresource = {}; - dstSubresource.aspectMask = TextureAspect::Color; + dstSubresource.aspectMask = getTextureAspect(); dstSubresource.mipLevel = 0; dstSubresource.mipLevelCount = 1; dstSubresource.baseArrayLayer = 0; dstSubresource.layerCount = 1; - ITextureResource::Offset3D dstOffset; + texCopyInfo.srcSubresource = srcSubresource; + texCopyInfo.dstSubresource = dstSubresource; + texCopyInfo.extent.width = 4; + texCopyInfo.extent.height = 4; + texCopyInfo.extent.depth = 1; + texCopyInfo.srcOffset = { 0, 0, 0 }; + texCopyInfo.dstOffset = { 4, 4, 0 }; - submitGPUWork(srcSubresource, dstSubresource, srcOffset, dstOffset, extent, extent.height * 256); - - ITextureResource::SubresourceData expectedData = srcTextureStuff->subresourceDatas[2]; - if (device->getDeviceInfo().deviceType == DeviceType::DirectX12) + if (textureType == ITextureResource::Type::Texture1D) { - // D3D12 has to pad out the rows in order to adhere to alignment, so when comparing results - // we need to make sure not to include the padding. - size_t testOffset = 0; - size_t dataOffset = 0; - auto rowStride = expectedData.strideY / 4; - for (Int i = 0; i < extent.height; ++i) - { - compareComputeResult( - device, - resultsBuffer, - testOffset, - (float*) expectedData.data + rowStride * i, - rowStride * 4); - testOffset += alignedRowPitch; - } - dataOffset += srcTextureStuff->subresourceDatas[0].strideZ / 4; + texCopyInfo.extent.height = 1; + texCopyInfo.dstOffset.y = 0; } - else if (device->getDeviceInfo().deviceType == DeviceType::Vulkan) + else if (textureType == ITextureResource::Type::Texture3D) { - compareComputeResult( - device, - resultsBuffer, - 0, - expectedData.data, - 64); + texCopyInfo.extent.depth = extent.depth; } + + bufferCopyInfo.srcSubresource = dstSubresource; + bufferCopyInfo.extent = extent; + bufferCopyInfo.textureOffset = { 0, 0, 0 }; + bufferCopyInfo.bufferOffset = 0; + + createRequiredResources(); + submitGPUWork(); + + auto copiedSubresourceIndex = getSubresourceIndex(srcSubresource.mipLevel, mipLevelCount, srcSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedCopiedData = srcTextureStuff->subresourceDatas[copiedSubresourceIndex]; + auto originalSubresourceIndex = getSubresourceIndex(dstSubresource.mipLevel, mipLevelCount, dstSubresource.baseArrayLayer); + ITextureResource::SubresourceData expectedOriginalData = dstTextureStuff->subresourceDatas[originalSubresourceIndex]; + checkTestResults(extent, expectedCopiedData.data, expectedOriginalData.data); } }; template<typename T> void copyTextureTestImpl(IDevice* device, UnitTestContext* context) { - T test; - test.init(device, context); - test.run(); + // Skip Type::Unknown and Type::Buffer as well as Format::Unknown + // TODO: Add support for TextureCube + for (uint32_t i = 2; i < (uint32_t)ITextureResource::Type::CountOf - 1; ++i) + { + for (uint32_t j = 1; j < (uint32_t)Format::CountOf; ++j) + { + auto type = (ITextureResource::Type)i; + auto format = (Format)j; + auto validationFormat = getValidationTextureFormat(format); + if (!validationFormat) + continue; + + T test; + test.init(device, context, format, validationFormat, type); + test.run(); + } + } } - SLANG_UNIT_TEST(copyTextureSimpleD3D12) + SLANG_UNIT_TEST(copyTextureSimple) { runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::Vulkan); } - SLANG_UNIT_TEST(copyTextureSectionD3D12) + SLANG_UNIT_TEST(copyTextureSection) { runTestImpl(copyTextureTestImpl<CopyTextureSection>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(copyTextureTestImpl<CopyTextureSection>, unitTestContext, Slang::RenderApiFlag::Vulkan); } - SLANG_UNIT_TEST(copyTextureSimpleVulkan) + SLANG_UNIT_TEST(copyLargeToSmallTexture) { - runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::Vulkan); + runTestImpl(copyTextureTestImpl<LargeSrcToSmallDst>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(copyTextureTestImpl<LargeSrcToSmallDst>, unitTestContext, Slang::RenderApiFlag::Vulkan); } - SLANG_UNIT_TEST(copyTextureSectionVulkan) + SLANG_UNIT_TEST(copySmallToLargeTexture) { - runTestImpl(copyTextureTestImpl<CopyTextureSection>, unitTestContext, Slang::RenderApiFlag::Vulkan); + runTestImpl(copyTextureTestImpl<SmallSrcToLargeDst>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(copyTextureTestImpl<SmallSrcToLargeDst>, unitTestContext, Slang::RenderApiFlag::Vulkan); + } + + SLANG_UNIT_TEST(copyBetweenMips) + { + runTestImpl(copyTextureTestImpl<CopyBetweenMips>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(copyTextureTestImpl<CopyBetweenMips>, unitTestContext, Slang::RenderApiFlag::Vulkan); + } + + SLANG_UNIT_TEST(copyBetweenLayers) + { + runTestImpl(copyTextureTestImpl<CopyBetweenLayers>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(copyTextureTestImpl<CopyBetweenLayers>, unitTestContext, Slang::RenderApiFlag::Vulkan); + } + + SLANG_UNIT_TEST(copyWithOffsets) + { + runTestImpl(copyTextureTestImpl<CopyWithOffsets>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(copyTextureTestImpl<CopyWithOffsets>, unitTestContext, Slang::RenderApiFlag::Vulkan); + } + + SLANG_UNIT_TEST(copySectionWithSetExtent) + { + runTestImpl(copyTextureTestImpl<CopySectionWithSetExtent>, unitTestContext, Slang::RenderApiFlag::D3D12); + runTestImpl(copyTextureTestImpl<CopySectionWithSetExtent>, unitTestContext, Slang::RenderApiFlag::Vulkan); } } |
