diff options
| author | lucy96chen <47800040+lucy96chen@users.noreply.github.com> | 2022-01-19 16:34:58 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-01-19 16:34:58 -0800 |
| commit | 11d248293f1b56a790faadead1e3d94de81f29a2 (patch) | |
| tree | ad28b0106fcaf98321447e10660435b1f00f7385 | |
| parent | b40cd149c2038b0a429e46d60ddee5610e08b0ba (diff) | |
Vulkan implementations for copyTexture, copyTextureToBuffer, and textureSubresourceBarrier (#2080)
* Added preliminary implementations for Vulkan's copyTexture, copyTextureToBuffer, and textureSubresourceBarrier
* Simple copyTexture test working
* Expanded test to use textureSubresourceBarrier() to change resource states before copying out to a buffer; Changed copyTextureToBuffer() to assert that only a single mip level is being copied; Test passes on Vulkan only
* Fixed an incorrect loop condition in D3D12's textureSubresourceBarrier and changed the size of the results buffer to pre-account for padding; Test runs in D3D12 but does not pass
* D3D12 test working, compareComputeResult for buffers now takes an offset into the results
* Refactored texture copying tests
* Second test written but does not copy correctly
* Fixed texture creation in D3D12 to take into account the subresource index when copying texture data so it actually copies all slices instead of just the ones in the first array layer; Second test working on both D3D12 and Vulkan
* Added a note for future tests to be added for texture copying; Fixed build errors in CUDA
Co-authored-by: Yong He <yhe@nvidia.com>
Co-authored-by: Theresa Foley <tfoleyNV@users.noreply.github.com>
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj | 1 | ||||
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters | 3 | ||||
| -rw-r--r-- | slang-gfx.h | 3 | ||||
| -rw-r--r-- | tools/gfx-unit-test/copy-texture-tests.cpp | 365 | ||||
| -rw-r--r-- | tools/gfx-unit-test/gfx-test-util.cpp | 9 | ||||
| -rw-r--r-- | tools/gfx-unit-test/gfx-test-util.h | 23 | ||||
| -rw-r--r-- | tools/gfx/cuda/render-cuda.cpp | 6 | ||||
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 138 | ||||
| -rw-r--r-- | tools/gfx/debug-layer.cpp | 7 | ||||
| -rw-r--r-- | tools/gfx/debug-layer.h | 3 | ||||
| -rw-r--r-- | tools/gfx/immediate-renderer-base.cpp | 6 | ||||
| -rw-r--r-- | tools/gfx/vulkan/render-vk.cpp | 117 | ||||
| -rw-r--r-- | tools/gfx/vulkan/vk-api.h | 1 |
13 files changed, 569 insertions, 113 deletions
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj index 34ab74ecf..f43d6150e 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj @@ -274,6 +274,7 @@ <ItemGroup>
<ClCompile Include="..\..\..\tools\gfx-unit-test\buffer-barrier-test.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\compute-smoke.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\copy-texture-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\create-buffer-from-handle.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\existing-device-handle-test.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\format-unit-tests.cpp" />
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters index 4925f7f4b..ff873deb9 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters @@ -23,6 +23,9 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\compute-smoke.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\copy-texture-tests.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\tools\gfx-unit-test\create-buffer-from-handle.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/slang-gfx.h b/slang-gfx.h index 4eb1fe707..c35892eb4 100644 --- a/slang-gfx.h +++ b/slang-gfx.h @@ -1560,9 +1560,11 @@ public: /// the entire resource is being copied and dstOffset, srcOffset and extent arguments are ignored. virtual SLANG_NO_THROW void SLANG_MCALL copyTexture( ITextureResource* dst, + ResourceState dstState, SubresourceRange dstSubresource, ITextureResource::Offset3D dstOffset, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) = 0; @@ -1573,6 +1575,7 @@ public: size_t dstOffset, size_t dstSize, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) = 0; diff --git a/tools/gfx-unit-test/copy-texture-tests.cpp b/tools/gfx-unit-test/copy-texture-tests.cpp new file mode 100644 index 000000000..fa206afda --- /dev/null +++ b/tools/gfx-unit-test/copy-texture-tests.cpp @@ -0,0 +1,365 @@ +#include "tools/unit-test/slang-unit-test.h" + +#include "slang-gfx.h" +#include "gfx-test-util.h" +#include "tools/gfx-util/shader-cursor.h" +#include "source/core/slang-basic.h" + +#if SLANG_WINDOWS_FAMILY +#include <d3d12.h> +#endif + +using namespace Slang; +using namespace gfx; + +namespace gfx_test +{ + struct BaseCopyTextureTest + { + IDevice* device; + UnitTestContext* context; + + ComPtr<ITextureResource> srcTexture; + ComPtr<ITextureResource> dstTexture; + ComPtr<IBufferResource> resultsBuffer; + + size_t alignedRowPitch; + + struct TextureInfo + { + ITextureResource::Size extent; + int numMipLevels; + int arraySize; + ITextureResource::SubresourceData const* initData; + }; + + void init(IDevice* device, UnitTestContext* context) + { + this->device = device; + this->context = context; + } + + void createRequiredResources(TextureInfo srcTextureInfo, TextureInfo dstTextureInfo, Format format) + { + ITextureResource::Desc srcTexDesc = {}; + srcTexDesc.type = IResource::Type::Texture2D; + srcTexDesc.numMipLevels = srcTextureInfo.numMipLevels; + srcTexDesc.arraySize = srcTextureInfo.arraySize; + srcTexDesc.size = srcTextureInfo.extent; + srcTexDesc.defaultState = ResourceState::UnorderedAccess; + srcTexDesc.allowedStates = ResourceStateSet( + ResourceState::UnorderedAccess, + ResourceState::ShaderResource, + ResourceState::CopySource); + srcTexDesc.format = format; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + srcTexDesc, + srcTextureInfo.initData, + srcTexture.writeRef())); + + ITextureResource::Desc dstTexDesc = {}; + dstTexDesc.type = IResource::Type::Texture2D; + dstTexDesc.numMipLevels = dstTextureInfo.numMipLevels; + dstTexDesc.arraySize = dstTextureInfo.arraySize; + dstTexDesc.size = dstTextureInfo.extent; + dstTexDesc.defaultState = ResourceState::CopyDestination; + dstTexDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::CopyDestination, + ResourceState::CopySource); + dstTexDesc.format = format; + + GFX_CHECK_CALL_ABORT(device->createTextureResource( + dstTexDesc, + dstTextureInfo.initData, + dstTexture.writeRef())); + + FormatInfo formatInfo; + gfxGetFormatInfo(format, &formatInfo); + UInt alignment = 256; // D3D requires rows to be aligned to a multiple of 256 bytes. + alignedRowPitch = (dstTextureInfo.extent.width * formatInfo.blockSizeInBytes + alignment - 1) & ~(alignment - 1); + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = dstTextureInfo.extent.height * alignedRowPitch; + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = 0; + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::CopyDestination; + bufferDesc.memoryType = MemoryType::DeviceLocal; + + GFX_CHECK_CALL_ABORT(device->createBufferResource( + bufferDesc, + nullptr, + resultsBuffer.writeRef())); + } + + void submitGPUWork( + SubresourceRange srcSubresource, + SubresourceRange dstSubresource, + ITextureResource::Offset3D srcOffset, + ITextureResource::Offset3D dstOffset, + ITextureResource::Size extent, + size_t textureSize) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; + auto queue = device->createCommandQueue(queueDesc); + + 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, dstTexture, ResourceState::CopySource, dstSubresource, dstOffset, extent); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } + }; + + struct SimpleCopyTexture : BaseCopyTextureTest + { + Format format = Format::R8G8B8A8_UINT; + + void run() + { + ITextureResource::Size extent = {}; + extent.width = 2; + extent.height = 2; + extent.depth = 1; + + 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 }; + + uint8_t dstTexData[16] = { 0u }; + ITextureResource::SubresourceData dstSubData = { (void*)dstTexData, 8, 0 }; + + TextureInfo srcTextureInfo = { extent, 1, 1, &srcSubData }; + TextureInfo dstTextureInfo = { extent, 1, 1, &dstSubData }; + + createRequiredResources(srcTextureInfo, dstTextureInfo, format); + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = TextureAspect::Color; + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = 1; + + ITextureResource::Offset3D srcOffset; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = TextureAspect::Color; + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + ITextureResource::Offset3D dstOffset; + + submitGPUWork(srcSubresource, dstSubresource, srcOffset, dstOffset, extent, 16); + + 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); + } + } + }; + + struct Texel + { + float channels[4]; + }; + + struct SubresourceStuff : RefObject + { + List<Texel> texels; + }; + + struct TextureStuff : RefObject + { + List<RefPtr<SubresourceStuff>> subresourceObjects; + List<ITextureResource::SubresourceData> subresourceDatas; + }; + + struct CopyTextureSection : BaseCopyTextureTest + { + Format format = Format::R32G32B32A32_FLOAT; + + RefPtr<TextureStuff> generateTextureData(int width, int height, uint32_t mipLevels, uint32_t arrayLayers) + { + RefPtr<TextureStuff> texture = new TextureStuff(); + for (int layer = 0; layer < arrayLayers; ++layer) + { + for (int mip = 0; mip < mipLevels; ++mip) + { + RefPtr<SubresourceStuff> subresource = new SubresourceStuff(); + texture->subresourceObjects.add(subresource); + + int mipWidth = Math::Max(width >> mip, 1); + int mipHeight = Math::Max(height >> mip, 1); + + 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] = w; + subresource->texels[h * mipWidth + w].channels[1] = h; + subresource->texels[h * mipWidth + w].channels[2] = mip; + subresource->texels[h * mipWidth + w].channels[3] = layer; + } + } + + ITextureResource::SubresourceData subData = {}; + subData.data = subresource->texels.getBuffer(); + subData.strideY = mipWidth * sizeof(Texel); + subData.strideZ = mipHeight * subData.strideY; + texture->subresourceDatas.add(subData); + } + } + return texture; + } + + // 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 + + void run() + { + ITextureResource::Size extent = {}; + extent.width = 4; + extent.height = 4; + extent.depth = 1; + + auto mipLevelCount = 2; + auto arrayLayerCount = 2; + + auto srcTextureStuff = generateTextureData(extent.width, extent.height, mipLevelCount, arrayLayerCount); + + TextureInfo srcTextureInfo = { extent, mipLevelCount, arrayLayerCount, srcTextureStuff->subresourceDatas.getBuffer() }; + TextureInfo dstTextureInfo = { extent, mipLevelCount, arrayLayerCount, nullptr }; + + createRequiredResources(srcTextureInfo, dstTextureInfo, format); + + SubresourceRange srcSubresource = {}; + srcSubresource.aspectMask = TextureAspect::Color; + srcSubresource.mipLevel = 0; + srcSubresource.mipLevelCount = 1; + srcSubresource.baseArrayLayer = 1; + srcSubresource.layerCount = 1; + + ITextureResource::Offset3D srcOffset; + + SubresourceRange dstSubresource = {}; + dstSubresource.aspectMask = TextureAspect::Color; + dstSubresource.mipLevel = 0; + dstSubresource.mipLevelCount = 1; + dstSubresource.baseArrayLayer = 0; + dstSubresource.layerCount = 1; + + ITextureResource::Offset3D dstOffset; + + submitGPUWork(srcSubresource, dstSubresource, srcOffset, dstOffset, extent, extent.height * 256); + + ITextureResource::SubresourceData expectedData = srcTextureStuff->subresourceDatas[2]; + 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; + 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; + } + else if (device->getDeviceInfo().deviceType == DeviceType::Vulkan) + { + compareComputeResult( + device, + resultsBuffer, + 0, + expectedData.data, + 64); + } + } + }; + + template<typename T> + void copyTextureTestImpl(IDevice* device, UnitTestContext* context) + { + T test; + test.init(device, context); + test.run(); + } + + SLANG_UNIT_TEST(copyTextureSimpleD3D12) + { + runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::D3D12); + } + + SLANG_UNIT_TEST(copyTextureSectionD3D12) + { + runTestImpl(copyTextureTestImpl<CopyTextureSection>, unitTestContext, Slang::RenderApiFlag::D3D12); + } + + SLANG_UNIT_TEST(copyTextureSimpleVulkan) + { + runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::Vulkan); + } + + SLANG_UNIT_TEST(copyTextureSectionVulkan) + { + runTestImpl(copyTextureTestImpl<CopyTextureSection>, unitTestContext, Slang::RenderApiFlag::Vulkan); + } +} diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp index 7514f22cf..c95c3d0e5 100644 --- a/tools/gfx-unit-test/gfx-test-util.cpp +++ b/tools/gfx-unit-test/gfx-test-util.cpp @@ -117,7 +117,7 @@ namespace gfx_test gfx::IDevice* device, gfx::ITextureResource* texture, gfx::ResourceState state, - float* expectedResult, + void* expectedResult, size_t expectedResultRowPitch, size_t rowCount) { @@ -139,15 +139,16 @@ namespace gfx_test } } - void compareComputeResult(gfx::IDevice* device, gfx::IBufferResource* buffer, uint8_t* expectedResult, size_t expectedBufferSize) + void compareComputeResult(gfx::IDevice* device, gfx::IBufferResource* buffer, size_t offset, const void* expectedResult, size_t expectedBufferSize) { // Read back the results. ComPtr<ISlangBlob> resultBlob; GFX_CHECK_CALL_ABORT(device->readBufferResource( - buffer, 0, expectedBufferSize, resultBlob.writeRef())); + buffer, offset, expectedBufferSize, resultBlob.writeRef())); SLANG_CHECK(resultBlob->getBufferSize() == expectedBufferSize); + auto result = (float*)resultBlob->getBufferPointer(); // Compare results. - SLANG_CHECK(memcmp(resultBlob->getBufferPointer(), expectedResult, expectedBufferSize) == 0); + SLANG_CHECK(memcmp(resultBlob->getBufferPointer(), (uint8_t*)expectedResult, expectedBufferSize) == 0); } void compareComputeResultFuzzy(const float* result, float* expectedResult, size_t expectedBufferSize) diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h index 04c602359..3be47bc82 100644 --- a/tools/gfx-unit-test/gfx-test-util.h +++ b/tools/gfx-unit-test/gfx-test-util.h @@ -30,7 +30,8 @@ namespace gfx_test void compareComputeResult( gfx::IDevice* device, gfx::IBufferResource* buffer, - uint8_t* expectedResult, + size_t offset, + const void* expectedResult, size_t expectedBufferSize); /// Reads back the content of `buffer` and compares it against `expectedResult`. @@ -38,7 +39,7 @@ namespace gfx_test gfx::IDevice* device, gfx::ITextureResource* texture, gfx::ResourceState state, - float* expectedResult, + void* expectedResult, size_t expectedResultRowPitch, size_t rowCount); @@ -65,24 +66,8 @@ namespace gfx_test expectedBuffer.setCount(bufferSize); memcpy(expectedBuffer.getBuffer(), expectedResult.begin(), bufferSize); if (std::is_same<T, float>::value) return compareComputeResultFuzzy(device, buffer, (float*)expectedBuffer.getBuffer(), bufferSize); - return compareComputeResult(device, buffer, expectedBuffer.getBuffer(), bufferSize); + return compareComputeResult(device, buffer, 0, expectedBuffer.getBuffer(), bufferSize); } - -// TODO: Implement compareComputeResultFuzzy() and keep or just directly use compareComputeResult() above and add a second overload for uint/int? -// template<typename T, Slang::Index count> -// void compareComputeResult( -// gfx::IDevice* device, -// gfx::ITextureResource* texture, -// gfx::ResourceState state, -// Slang::Array<T, count> expectedResult) -// { -// Slang::List<uint8_t> expectedBuffer; -// size_t bufferSize = sizeof(T) * count; -// expectedBuffer.setCount(bufferSize); -// memcpy(expectedBuffer.getBuffer(), expectedResult.begin(), bufferSize); -// if (std::is_same<T, float>::value) return compareComputeResultFuzzy(device, buffer, (float*)expectedBuffer.getBuffer(), bufferSize); -// return compareComputeResult(device, texture, state, expectedBuffer.getBuffer(), bufferSize); -// } Slang::ComPtr<gfx::IDevice> createTestingDevice(UnitTestContext* context, Slang::RenderApiFlag::Enum api); diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp index 2c3f1eb56..3e55242f0 100644 --- a/tools/gfx/cuda/render-cuda.cpp +++ b/tools/gfx/cuda/render-cuda.cpp @@ -1060,17 +1060,21 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL copyTexture( ITextureResource* dst, + ResourceState dstState, SubresourceRange dstSubresource, ITextureResource::Offset3D dstOffset, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override { SLANG_UNUSED(dst); + SLANG_UNUSED(dstState); SLANG_UNUSED(dstSubresource); SLANG_UNUSED(dstOffset); SLANG_UNUSED(src); + SLANG_UNUSED(srcState); SLANG_UNUSED(srcSubresource); SLANG_UNUSED(srcOffset); SLANG_UNUSED(extent); @@ -1123,6 +1127,7 @@ public: size_t dstOffset, size_t dstSize, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override @@ -1131,6 +1136,7 @@ public: SLANG_UNUSED(dstOffset); SLANG_UNUSED(dstSize); SLANG_UNUSED(src); + SLANG_UNUSED(srcState); SLANG_UNUSED(srcSubresource); SLANG_UNUSED(srcOffset); SLANG_UNUSED(extent); diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index 8005f6d15..634fca03e 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -3954,9 +3954,11 @@ public: } virtual SLANG_NO_THROW void SLANG_MCALL copyTexture( ITextureResource* dst, + ResourceState dstState, SubresourceRange dstSubresource, ITextureResource::Offset3D dstOffset, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override @@ -4247,10 +4249,13 @@ public: size_t dstOffset, size_t dstSize, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override { + assert(srcSubresource.mipLevelCount <= 1); + auto srcTexture = static_cast<TextureResourceImpl*>(src); auto dstBuffer = static_cast<BufferResourceImpl*>(dst); auto baseSubresourceIndex = D3DUtil::getSubresourceIndex( @@ -4269,74 +4274,71 @@ public: for (uint32_t layer = 0; layer < srcSubresource.layerCount; layer++) { - for (uint32_t mipId = 0; mipId < srcSubresource.mipLevelCount; mipId++) + // Get the footprint + D3D12_RESOURCE_DESC texDesc = + srcTexture->m_resource.getResource()->GetDesc(); + + D3D12_TEXTURE_COPY_LOCATION dstRegion = {}; + dstRegion.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dstRegion.pResource = dstBuffer->m_resource.getResource(); + D3D12_PLACED_SUBRESOURCE_FOOTPRINT& footprint = dstRegion.PlacedFootprint; + + D3D12_TEXTURE_COPY_LOCATION srcRegion = {}; + srcRegion.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + srcRegion.SubresourceIndex = D3DUtil::getSubresourceIndex( + srcSubresource.mipLevel, + layer + srcSubresource.baseArrayLayer, + 0, + srcTexture->getDesc()->numMipLevels, + srcTexture->getDesc()->arraySize); + srcRegion.pResource = srcTexture->m_resource.getResource(); + + footprint.Offset = dstOffset; + footprint.Footprint.Format = texDesc.Format; + uint32_t mipLevel = srcSubresource.mipLevel; + if (extent.width != 0xFFFFFFFF) { - // Get the footprint - D3D12_RESOURCE_DESC texDesc = - srcTexture->m_resource.getResource()->GetDesc(); - - D3D12_TEXTURE_COPY_LOCATION dstRegion = {}; - dstRegion.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - dstRegion.pResource = dstBuffer->m_resource.getResource(); - D3D12_PLACED_SUBRESOURCE_FOOTPRINT& footprint = dstRegion.PlacedFootprint; - - D3D12_TEXTURE_COPY_LOCATION srcRegion = {}; - srcRegion.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - srcRegion.SubresourceIndex = D3DUtil::getSubresourceIndex( - mipId + srcSubresource.mipLevel, - layer + srcSubresource.baseArrayLayer, - 0, - srcTexture->getDesc()->numMipLevels, - srcTexture->getDesc()->arraySize); - srcRegion.pResource = srcTexture->m_resource.getResource(); - - footprint.Offset = 0; - footprint.Footprint.Format = texDesc.Format; - uint32_t mipLevel = mipId + srcSubresource.mipLevel; - if (extent.width != 0xFFFFFFFF) - { - footprint.Footprint.Width = extent.width; - } - else - { - footprint.Footprint.Width = - Math::Max(1, (textureSize.width >> mipLevel)) - srcOffset.x; - } - if (extent.height != 0xFFFFFFFF) - { - footprint.Footprint.Height = extent.height; - } - else - { - footprint.Footprint.Height = - Math::Max(1, (textureSize.height >> mipLevel)) - srcOffset.y; - } - if (extent.depth != 0xFFFFFFFF) - { - footprint.Footprint.Depth = extent.depth; - } - else - { - footprint.Footprint.Depth = - Math::Max(1, (textureSize.depth >> mipLevel)) - srcOffset.z; - } - footprint.Footprint.RowPitch = (UINT)D3DUtil::calcAligned( - footprint.Footprint.Width * (UInt)formatInfo.blockSizeInBytes, - (uint32_t)D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - - auto bufferSize = footprint.Footprint.RowPitch * - footprint.Footprint.Height * footprint.Footprint.Depth; - - D3D12_BOX srcBox = {}; - srcBox.left = srcOffset.x; - srcBox.top = srcOffset.y; - srcBox.front = srcOffset.z; - srcBox.right = srcOffset.x + extent.width; - srcBox.bottom = srcOffset.y + extent.height; - srcBox.back = srcOffset.z + extent.depth; - m_commandBuffer->m_cmdList->CopyTextureRegion( - &dstRegion, (UINT)dstOffset, 0, 0, &srcRegion, &srcBox); + footprint.Footprint.Width = extent.width; + } + else + { + footprint.Footprint.Width = + Math::Max(1, (textureSize.width >> mipLevel)) - srcOffset.x; + } + if (extent.height != 0xFFFFFFFF) + { + footprint.Footprint.Height = extent.height; + } + else + { + footprint.Footprint.Height = + Math::Max(1, (textureSize.height >> mipLevel)) - srcOffset.y; + } + if (extent.depth != 0xFFFFFFFF) + { + footprint.Footprint.Depth = extent.depth; } + else + { + footprint.Footprint.Depth = + Math::Max(1, (textureSize.depth >> mipLevel)) - srcOffset.z; + } + footprint.Footprint.RowPitch = (UINT)D3DUtil::calcAligned( + footprint.Footprint.Width * (UInt)formatInfo.blockSizeInBytes, + (uint32_t)D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + + auto bufferSize = footprint.Footprint.RowPitch * + footprint.Footprint.Height * footprint.Footprint.Depth; + + D3D12_BOX srcBox = {}; + srcBox.left = srcOffset.x; + srcBox.top = srcOffset.y; + srcBox.front = srcOffset.z; + srcBox.right = srcOffset.x + extent.width; + srcBox.bottom = srcOffset.y + extent.height; + srcBox.back = srcOffset.z + extent.depth; + m_commandBuffer->m_cmdList->CopyTextureRegion( + &dstRegion, 0, 0, 0, &srcRegion, &srcBox); } } @@ -4377,7 +4379,7 @@ public: auto aspect = Math::getLowestBit((int32_t)aspectMask); aspectMask &= ~aspect; auto planeIndex = D3DUtil::getPlaneSlice(d3dFormat, (TextureAspect)aspect); - for (uint32_t layer = 0; layer < subresourceRange.baseArrayLayer; layer++) + for (uint32_t layer = 0; layer < subresourceRange.layerCount; layer++) { for (uint32_t mip = 0; mip < subresourceRange.mipLevelCount; mip++) { @@ -6046,7 +6048,7 @@ Result D3D12Device::createTextureResource(const ITextureResource::Desc& descIn, for (int j = 0; j < numMipMaps; ++j) { - auto srcSubresource = initData[j]; + auto srcSubresource = initData[subResourceIndex + j]; const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& layout = layouts[j]; const D3D12_SUBRESOURCE_FOOTPRINT& footprint = layout.Footprint; diff --git a/tools/gfx/debug-layer.cpp b/tools/gfx/debug-layer.cpp index 83ef129c4..fa8fc6fda 100644 --- a/tools/gfx/debug-layer.cpp +++ b/tools/gfx/debug-layer.cpp @@ -1277,9 +1277,11 @@ void DebugResourceCommandEncoder::bufferBarrier( void DebugResourceCommandEncoder::copyTexture( ITextureResource* dst, + ResourceState dstState, SubresourceRange dstSubresource, ITextureResource::Offset3D dstOffset, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) @@ -1287,9 +1289,11 @@ void DebugResourceCommandEncoder::copyTexture( SLANG_GFX_API_FUNC; baseObject->copyTexture( getInnerObj(dst), + dstState, dstSubresource, dstOffset, getInnerObj(src), + srcState, srcSubresource, srcOffset, extent); @@ -1342,13 +1346,14 @@ void DebugResourceCommandEncoder::copyTextureToBuffer( size_t dstOffset, size_t dstSize, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) { SLANG_GFX_API_FUNC; baseObject->copyTextureToBuffer( - getInnerObj(dst), dstOffset, dstSize, getInnerObj(src), srcSubresource, srcOffset, extent); + getInnerObj(dst), dstOffset, dstSize, getInnerObj(src), srcState, srcSubresource, srcOffset, extent); } void DebugResourceCommandEncoder::textureSubresourceBarrier( diff --git a/tools/gfx/debug-layer.h b/tools/gfx/debug-layer.h index 096c35147..04dafadf2 100644 --- a/tools/gfx/debug-layer.h +++ b/tools/gfx/debug-layer.h @@ -430,9 +430,11 @@ public: ResourceState dst) override; virtual SLANG_NO_THROW void SLANG_MCALL copyTexture( ITextureResource* dst, + ResourceState dstState, SubresourceRange dstSubresource, ITextureResource::Offset3D dstOffset, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override; @@ -461,6 +463,7 @@ public: size_t dstOffset, size_t dstSize, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override; diff --git a/tools/gfx/immediate-renderer-base.cpp b/tools/gfx/immediate-renderer-base.cpp index 912e20df1..ab2a51275 100644 --- a/tools/gfx/immediate-renderer-base.cpp +++ b/tools/gfx/immediate-renderer-base.cpp @@ -334,17 +334,21 @@ public: virtual SLANG_NO_THROW void SLANG_MCALL copyTexture( ITextureResource* dst, + ResourceState dstState, SubresourceRange dstSubresource, ITextureResource::Offset3D dstOffset, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override { SLANG_UNUSED(dst); + SLANG_UNUSED(dstState); SLANG_UNUSED(dstSubresource); SLANG_UNUSED(dstOffset); SLANG_UNUSED(src); + SLANG_UNUSED(srcState); SLANG_UNUSED(srcSubresource); SLANG_UNUSED(srcOffset); SLANG_UNUSED(extent); @@ -397,6 +401,7 @@ public: size_t dstOffset, size_t dstSize, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override @@ -405,6 +410,7 @@ public: SLANG_UNUSED(dstOffset); SLANG_UNUSED(dstSize); SLANG_UNUSED(src); + SLANG_UNUSED(srcState); SLANG_UNUSED(srcSubresource); SLANG_UNUSED(srcOffset); SLANG_UNUSED(extent); diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp index 96e11eb27..9f5af2a1e 100644 --- a/tools/gfx/vulkan/render-vk.cpp +++ b/tools/gfx/vulkan/render-vk.cpp @@ -4502,23 +4502,54 @@ public: m_commandBuffer = commandBuffer; } + VkImageAspectFlags getAspectMask(TextureAspect aspect) + { + if (aspect == TextureAspect::Depth) + return VK_IMAGE_ASPECT_DEPTH_BIT; + if (aspect == TextureAspect::Stencil) + return VK_IMAGE_ASPECT_STENCIL_BIT; + return VK_IMAGE_ASPECT_COLOR_BIT; + } + virtual SLANG_NO_THROW void SLANG_MCALL copyTexture( ITextureResource* dst, + ResourceState dstState, SubresourceRange dstSubresource, ITextureResource::Offset3D dstOffset, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override { - SLANG_UNUSED(dst); - SLANG_UNUSED(dstSubresource); - SLANG_UNUSED(dstOffset); - SLANG_UNUSED(src); - SLANG_UNUSED(srcSubresource); - SLANG_UNUSED(srcOffset); - SLANG_UNUSED(extent); - SLANG_UNIMPLEMENTED_X("copyTexture"); + auto srcImage = static_cast<TextureResourceImpl*>(src); + auto srcDesc = srcImage->getDesc(); + auto srcImageLayout = VulkanUtil::getImageLayoutFromState(srcState); + auto dstImage = static_cast<TextureResourceImpl*>(dst); + auto dstDesc = dstImage->getDesc(); + auto dstImageLayout = VulkanUtil::getImageLayoutFromState(dstState); + + for (Int layer = 0; layer < srcSubresource.layerCount; ++layer) + { + for (Int mipId = 0; mipId < srcSubresource.mipLevelCount; ++mipId) + { + VkImageCopy region = {}; + region.srcSubresource.aspectMask = getAspectMask(srcSubresource.aspectMask); + region.srcSubresource.baseArrayLayer = layer + srcSubresource.baseArrayLayer; + region.srcSubresource.mipLevel = mipId + srcSubresource.mipLevel; + region.srcSubresource.layerCount = 1; + region.srcOffset = { (int32_t)srcOffset.x, (int32_t)srcOffset.y, (int32_t)srcOffset.z }; + region.dstSubresource.aspectMask = getAspectMask(dstSubresource.aspectMask); + region.dstSubresource.baseArrayLayer = layer + dstSubresource.baseArrayLayer; + region.dstSubresource.mipLevel = mipId + dstSubresource.mipLevel; + region.dstSubresource.layerCount = 1; + region.dstOffset = { (int32_t)dstOffset.x, (int32_t)dstOffset.y, (int32_t)dstOffset.z }; + region.extent = { (uint32_t)extent.width, (uint32_t)extent.height, (uint32_t)extent.depth }; + + auto& vkApi = m_commandBuffer->m_renderer->m_api; + vkApi.vkCmdCopyImage(m_commandBuffer->m_commandBuffer, srcImage->m_image, srcImageLayout, dstImage->m_image, dstImageLayout, 1, ®ion); + } + } } virtual SLANG_NO_THROW void SLANG_MCALL uploadTextureData( @@ -4765,18 +4796,31 @@ public: size_t dstOffset, size_t dstSize, ITextureResource* src, + ResourceState srcState, SubresourceRange srcSubresource, ITextureResource::Offset3D srcOffset, ITextureResource::Size extent) override { - SLANG_UNUSED(dst); - SLANG_UNUSED(dstOffset); - SLANG_UNUSED(dstSize); - SLANG_UNUSED(src); - SLANG_UNUSED(srcSubresource); - SLANG_UNUSED(srcOffset); - SLANG_UNUSED(extent); - SLANG_UNIMPLEMENTED_X("copyTextureToBuffer"); + assert(srcSubresource.mipLevelCount <= 1); + + auto image = static_cast<TextureResourceImpl*>(src); + auto desc = image->getDesc(); + auto buffer = static_cast<BufferResourceImpl*>(dst); + auto srcImageLayout = VulkanUtil::getImageLayoutFromState(srcState); + + VkBufferImageCopy region = {}; + region.bufferOffset = dstOffset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = getAspectMask(srcSubresource.aspectMask); + region.imageSubresource.mipLevel = srcSubresource.mipLevel; + region.imageSubresource.baseArrayLayer = srcSubresource.baseArrayLayer; + region.imageSubresource.layerCount = srcSubresource.layerCount; + region.imageOffset = { (int32_t)srcOffset.x, (int32_t)srcOffset.y, (int32_t)srcOffset.z }; + region.imageExtent = { uint32_t(extent.width), uint32_t(extent.height), uint32_t(extent.depth) }; + + auto& vkApi = m_commandBuffer->m_renderer->m_api; + vkApi.vkCmdCopyImageToBuffer(m_commandBuffer->m_commandBuffer, image->m_image, srcImageLayout, buffer->m_buffer.m_buffer, 1, ®ion); } virtual SLANG_NO_THROW void SLANG_MCALL textureSubresourceBarrier( @@ -4785,11 +4829,39 @@ public: ResourceState src, ResourceState dst) override { - SLANG_UNUSED(texture); - SLANG_UNUSED(subresourceRange); - SLANG_UNUSED(src); - SLANG_UNUSED(dst); - SLANG_UNIMPLEMENTED_X("textureSubresourceBarrier"); + ShortList<VkImageMemoryBarrier> barriers; + auto image = static_cast<TextureResourceImpl*>(texture); + auto desc = image->getDesc(); + + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.image = image->m_image; + barrier.oldLayout = translateImageLayout(src); + barrier.newLayout = translateImageLayout(dst); + barrier.subresourceRange.aspectMask = getAspectMask(subresourceRange.aspectMask); + barrier.subresourceRange.baseArrayLayer = subresourceRange.baseArrayLayer; + barrier.subresourceRange.baseMipLevel = subresourceRange.mipLevel; + barrier.subresourceRange.layerCount = subresourceRange.layerCount; + barrier.subresourceRange.levelCount = subresourceRange.mipLevelCount; + barrier.srcAccessMask = calcAccessFlags(src); + barrier.dstAccessMask = calcAccessFlags(dst); + barriers.add(barrier); + + VkPipelineStageFlagBits srcStage = calcPipelineStageFlags(src, true); + VkPipelineStageFlagBits dstStage = calcPipelineStageFlags(dst, false); + + auto& vkApi = m_commandBuffer->m_renderer->m_api; + vkApi.vkCmdPipelineBarrier( + m_commandBuffer->m_commandBuffer, + srcStage, + dstStage, + 0, + 0, + nullptr, + 0, + nullptr, + (uint32_t)barriers.getCount(), + barriers.getArrayView().getBuffer()); } }; @@ -7061,6 +7133,9 @@ void VKDevice::_transitionImageLayout( VkImageLayout oldLayout, VkImageLayout newLayout) { + if (oldLayout == newLayout) + return; + VkImageMemoryBarrier barrier = {}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.oldLayout = oldLayout; diff --git a/tools/gfx/vulkan/vk-api.h b/tools/gfx/vulkan/vk-api.h index 1d8cd66f6..72a6e73c8 100644 --- a/tools/gfx/vulkan/vk-api.h +++ b/tools/gfx/vulkan/vk-api.h @@ -96,6 +96,7 @@ namespace gfx { x(vkCmdEndRenderPass) \ x(vkCmdPipelineBarrier) \ x(vkCmdCopyBufferToImage)\ + x(vkCmdCopyImage) \ x(vkCmdCopyImageToBuffer) \ x(vkCmdPushConstants) \ x(vkCmdSetStencilReference) \ |
