diff options
| author | lucy96chen <47800040+lucy96chen@users.noreply.github.com> | 2021-12-08 11:38:14 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-12-08 11:38:14 -0800 |
| commit | 9606401e1de1002e3ad070bc5c6384fa5bc4d9ff (patch) | |
| tree | 7a557a14fadf5220a34f6df9faf1a5535100743f | |
| parent | 90d8af888b40c83b33f9f0c037bd2ab8c19a35f4 (diff) | |
D3D12 and Vulkan to CUDA Texture Sharing (#2038)
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj | 4 | ||||
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters | 12 | ||||
| -rw-r--r-- | slang-gfx.h | 6 | ||||
| -rw-r--r-- | tools/gfx-unit-test/gfx-test-util.cpp | 14 | ||||
| -rw-r--r-- | tools/gfx-unit-test/gfx-test-util.h | 24 | ||||
| -rw-r--r-- | tools/gfx-unit-test/shared-buffers-tests.cpp (renamed from tools/gfx-unit-test/get-shared-handle.cpp) | 16 | ||||
| -rw-r--r-- | tools/gfx-unit-test/shared-textures-tests.cpp | 221 | ||||
| -rw-r--r-- | tools/gfx-unit-test/trivial-copy.slang | 18 | ||||
| -rw-r--r-- | tools/gfx-util/shader-cursor.h | 6 | ||||
| -rw-r--r-- | tools/gfx/cuda/render-cuda.cpp | 232 | ||||
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 17 | ||||
| -rw-r--r-- | tools/gfx/debug-layer.cpp | 16 | ||||
| -rw-r--r-- | tools/gfx/debug-layer.h | 5 | ||||
| -rw-r--r-- | tools/gfx/renderer-shared.cpp | 14 | ||||
| -rw-r--r-- | tools/gfx/renderer-shared.h | 6 | ||||
| -rw-r--r-- | tools/gfx/vulkan/render-vk.cpp | 162 |
16 files changed, 659 insertions, 114 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 1463cfecb..81790de85 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 @@ -280,10 +280,11 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\get-buffer-resource-handle-test.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\get-cmd-buffer-handle-test.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\get-cmd-queue-handle-test.cpp" />
- <ClCompile Include="..\..\..\tools\gfx-unit-test\get-shared-handle.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\get-texture-resource-handle-test.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\gfx-test-util.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\shared-buffers-tests.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\shared-textures-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\root-mutable-shader-object.cpp" />
<ClCompile Include="..\..\..\tools\unit-test\slang-unit-test.cpp" />
</ItemGroup>
@@ -293,6 +294,7 @@ <None Include="..\..\..\tools\gfx-unit-test\compute-trivial.slang" />
<None Include="..\..\..\tools\gfx-unit-test\format-test-shaders.slang" />
<None Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.slang" />
+ <None Include="..\..\..\tools\gfx-unit-test\trivial-copy.slang" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\core\core.vcxproj">
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 80186a7eb..988f78ef4 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 @@ -41,9 +41,6 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\get-cmd-queue-handle-test.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="..\..\..\tools\gfx-unit-test\get-shared-handle.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="..\..\..\tools\gfx-unit-test\get-texture-resource-handle-test.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -53,6 +50,12 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\shared-buffers-tests.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\shared-textures-tests.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\tools\gfx-unit-test\root-mutable-shader-object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -76,5 +79,8 @@ <None Include="..\..\..\tools\gfx-unit-test\mutable-shader-object.slang">
<Filter>Source Files</Filter>
</None>
+ <None Include="..\..\..\tools\gfx-unit-test\trivial-copy.slang">
+ <Filter>Source Files</Filter>
+ </None>
</ItemGroup>
</Project>
\ No newline at end of file diff --git a/slang-gfx.h b/slang-gfx.h index 0600d5623..8ed99f2c1 100644 --- a/slang-gfx.h +++ b/slang-gfx.h @@ -1952,6 +1952,12 @@ public: const ITextureResource::Desc& srcDesc, ITextureResource** outResource) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL createTextureFromSharedHandle( + InteropHandle handle, + const ITextureResource::Desc& srcDesc, + const size_t size, + ITextureResource** outResource) = 0; + /// Create a buffer resource virtual SLANG_NO_THROW Result SLANG_MCALL createBufferResource( const IBufferResource::Desc& desc, diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp index aafa3fc59..952638fd8 100644 --- a/tools/gfx-unit-test/gfx-test-util.cpp +++ b/tools/gfx-unit-test/gfx-test-util.cpp @@ -66,6 +66,20 @@ namespace gfx_test return SLANG_OK; } + void compareComputeResult(gfx::IDevice* device, gfx::ITextureResource* texture, gfx::ResourceState state, float* expectedResult, size_t expectedBufferSize) + { + // Read back the results. + ComPtr<ISlangBlob> resultBlob; + size_t rowPitch = 0; + size_t pixelSize = 0; + GFX_CHECK_CALL_ABORT(device->readTextureResource( + texture, state, resultBlob.writeRef(), &rowPitch, &pixelSize)); + SLANG_CHECK(resultBlob->getBufferSize() == expectedBufferSize); + auto result = (float*)resultBlob->getBufferPointer(); + // Compare results. + SLANG_CHECK(memcmp(resultBlob->getBufferPointer(), expectedResult, expectedBufferSize) == 0); + } + void compareComputeResult(gfx::IDevice* device, gfx::IBufferResource* buffer, uint8_t* expectedResult, size_t expectedBufferSize) { // Read back the results. diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h index 01a367915..07513c39a 100644 --- a/tools/gfx-unit-test/gfx-test-util.h +++ b/tools/gfx-unit-test/gfx-test-util.h @@ -25,6 +25,14 @@ namespace gfx_test uint8_t* expectedResult, size_t expectedBufferSize); + /// Reads back the content of `buffer` and compares it against `expectedResult`. + void compareComputeResult( + gfx::IDevice* device, + gfx::ITextureResource* texture, + gfx::ResourceState state, + float* expectedResult, + size_t expectedBufferSize); + /// Reads back the content of `buffer` and compares it against `expectedResult` with a set tolerance. void compareComputeResultFuzzy( gfx::IDevice* device, @@ -45,6 +53,22 @@ namespace gfx_test if (std::is_same<T, float>::value) return compareComputeResultFuzzy(device, buffer, (float*)expectedBuffer.getBuffer(), bufferSize); return compareComputeResult(device, buffer, 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-unit-test/get-shared-handle.cpp b/tools/gfx-unit-test/shared-buffers-tests.cpp index 8b991f15c..fe7757083 100644 --- a/tools/gfx-unit-test/get-shared-handle.cpp +++ b/tools/gfx-unit-test/shared-buffers-tests.cpp @@ -9,7 +9,7 @@ using namespace gfx; namespace gfx_test { - void sharedHandleTestImpl(IDevice* srcDevice, IDevice* dstDevice, UnitTestContext* context) + void sharedBufferTestImpl(IDevice* srcDevice, IDevice* dstDevice, UnitTestContext* context) { // Create a shareable buffer using srcDevice, get its handle, then create a buffer using the handle using // dstDevice. Read back the buffer and check that its contents are correct. @@ -98,7 +98,7 @@ namespace gfx_test Slang::makeArray<float>(1.0f, 2.0f, 3.0f, 4.0f)); } - void sharedHandleTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum srcApi, Slang::RenderApiFlag::Enum dstApi) + void sharedBufferTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum srcApi, Slang::RenderApiFlag::Enum dstApi) { auto srcDevice = createTestingDevice(context, srcApi); auto dstDevice = createTestingDevice(context, dstApi); @@ -107,19 +107,17 @@ namespace gfx_test SLANG_IGNORE_TEST; } - sharedHandleTestImpl(srcDevice, dstDevice, context); + sharedBufferTestImpl(srcDevice, dstDevice, context); } #if SLANG_WIN64 - SLANG_UNIT_TEST(sharedHandleD3D12ToCUDA) + SLANG_UNIT_TEST(sharedBufferD3D12ToCUDA) { - sharedHandleTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12, Slang::RenderApiFlag::CUDA); + sharedBufferTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12, Slang::RenderApiFlag::CUDA); } -#if SLANG_WINDOWS_FAMILY // TODO: Remove when Linux support is added - SLANG_UNIT_TEST(sharedHandleVulkanToCUDA) + SLANG_UNIT_TEST(sharedBufferVulkanToCUDA) { - sharedHandleTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan, Slang::RenderApiFlag::CUDA); + sharedBufferTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan, Slang::RenderApiFlag::CUDA); } #endif -#endif } diff --git a/tools/gfx-unit-test/shared-textures-tests.cpp b/tools/gfx-unit-test/shared-textures-tests.cpp new file mode 100644 index 000000000..896d6d6e6 --- /dev/null +++ b/tools/gfx-unit-test/shared-textures-tests.cpp @@ -0,0 +1,221 @@ +#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" + +using namespace gfx; + +namespace gfx_test +{ + void setUpAndRunShader( + IDevice* device, + ComPtr<ITextureResource> tex, + ComPtr<IResourceView> texView, + ComPtr<IResourceView> bufferView, + const char* entryPoint, + ComPtr<ISamplerState> sampler = nullptr) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr<IShaderProgram> shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "trivial-copy", entryPoint, slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr<gfx::IPipelineState> pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. + { + ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + + auto& desc = *tex->getDesc(); + entryPointCursor["width"].setData(desc.size.width); + entryPointCursor["height"].setData(desc.size.height); + + // Bind texture view to the entry point + entryPointCursor["tex"].setResource(texView); + + if (sampler) entryPointCursor["sampler"].setSampler(sampler); + + // Bind buffer view to the entry point. + entryPointCursor["buffer"].setResource(bufferView); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->waitOnHost(); + } + } + + ComPtr<ITextureResource> createTexture(IDevice* device, ITextureResource::Size extents, gfx::Format format, ITextureResource::SubresourceData* initialData) + { + ITextureResource::Desc texDesc = {}; + texDesc.type = IResource::Type::Texture2D; + texDesc.numMipLevels = 1; + texDesc.arraySize = 1; + texDesc.size = extents; + texDesc.defaultState = ResourceState::UnorderedAccess; + texDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + texDesc.format = format; + texDesc.isShared = true; + + ComPtr<ITextureResource> inTex; + GFX_CHECK_CALL_ABORT(device->createTextureResource( + texDesc, + initialData, + inTex.writeRef())); + return inTex; + } + + ComPtr<IResourceView> createTexView(IDevice* device, ComPtr<ITextureResource> inTexture) + { + ComPtr<IResourceView> texView; + IResourceView::Desc texViewDesc = {}; + texViewDesc.type = IResourceView::Type::UnorderedAccess; + texViewDesc.format = inTexture->getDesc()->format; // TODO: Handle typeless formats - gfxIsTypelessFormat(format) ? convertTypelessFormat(format) : format; + GFX_CHECK_CALL_ABORT(device->createTextureView(inTexture, texViewDesc, texView.writeRef())); + return texView; + } + + template <typename T> + ComPtr<IBufferResource> createBuffer(IDevice* device, int size, void* initialData) + { + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = size * sizeof(T); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(T); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.cpuAccessFlags = AccessFlag::Write | AccessFlag::Read; + + ComPtr<IBufferResource> outBuffer; + GFX_CHECK_CALL_ABORT(device->createBufferResource( + bufferDesc, + initialData, + outBuffer.writeRef())); + return outBuffer; + } + + ComPtr<IResourceView> createOutBufferView(IDevice* device, ComPtr<IBufferResource> outBuffer) + { + ComPtr<IResourceView> bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT(device->createBufferView(outBuffer, viewDesc, bufferView.writeRef())); + return bufferView; + } + + void sharedTextureTestImpl(IDevice* srcDevice, IDevice* dstDevice, UnitTestContext* context) + { + ISamplerState::Desc samplerDesc; + auto sampler = dstDevice->createSamplerState(samplerDesc); + + float initFloatData[16] = { 0.0f }; + auto floatResults = createBuffer<float>(dstDevice, 16, initFloatData); + auto floatBufferView = createOutBufferView(dstDevice, floatResults); + + uint32_t initUintData[16] = { 0u }; + auto uintResults = createBuffer<uint32_t>(dstDevice, 16, initUintData); + auto uintBufferView = createOutBufferView(dstDevice, uintResults); + + int32_t initIntData[16] = { 0 }; + auto intResults = createBuffer<uint32_t>(dstDevice, 16, initIntData); + auto intBufferView = createOutBufferView(dstDevice, intResults); + + ITextureResource::Size size = {}; + size.width = 2; + size.height = 2; + size.depth = 1; + + ITextureResource::Size bcSize = {}; + bcSize.width = 4; + bcSize.height = 4; + bcSize.depth = 1; + + { + float texData[] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f }; + ITextureResource::SubresourceData subData = { (void*)texData, 32, 0 }; + + // Create a shareable texture using srcDevice, get its handle, then create a texture using the handle using + // dstDevice. Read back the texture and check that its contents are correct. + auto srcTexture = createTexture(srcDevice, size, gfx::Format::R32G32B32A32_FLOAT, &subData); + + InteropHandle sharedHandle; + GFX_CHECK_CALL_ABORT(srcTexture->getSharedHandle(&sharedHandle)); + ComPtr<ITextureResource> dstTexture; + size_t sizeInBytes = 0; + size_t alignment = 0; + GFX_CHECK_CALL_ABORT(srcDevice->getTextureAllocationInfo(*(srcTexture->getDesc()), &sizeInBytes, &alignment)); + GFX_CHECK_CALL_ABORT(dstDevice->createTextureFromSharedHandle(sharedHandle, *(srcTexture->getDesc()), sizeInBytes, dstTexture.writeRef())); + // Reading back the buffer from srcDevice to make sure it's been filled in before reading anything back from dstDevice + // TODO: Implement actual synchronization (and not this hacky solution) + compareComputeResult( + dstDevice, + dstTexture, + ResourceState::ShaderResource, + texData, + sizeof(texData)); + + auto texView = createTexView(dstDevice, dstTexture); + setUpAndRunShader(dstDevice, dstTexture, texView, floatBufferView, "copyTexFloat4"); + compareComputeResult( + dstDevice, + floatResults, + Slang::makeArray<float>(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f)); + } + } + + void sharedTextureTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum srcApi, Slang::RenderApiFlag::Enum dstApi) + { + auto srcDevice = createTestingDevice(context, srcApi); + auto dstDevice = createTestingDevice(context, dstApi); + if (!srcDevice || !dstDevice) + { + SLANG_IGNORE_TEST; + } + + sharedTextureTestImpl(srcDevice, dstDevice, context); + } +#if SLANG_WIN64 + SLANG_UNIT_TEST(sharedTextureD3D12ToCUDA) + { + sharedTextureTestAPI(unitTestContext, Slang::RenderApiFlag::D3D12, Slang::RenderApiFlag::CUDA); + } + + SLANG_UNIT_TEST(sharedTextureVulkanToCUDA) + { + sharedTextureTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan, Slang::RenderApiFlag::CUDA); + } +#endif +} diff --git a/tools/gfx-unit-test/trivial-copy.slang b/tools/gfx-unit-test/trivial-copy.slang new file mode 100644 index 000000000..acf091ffa --- /dev/null +++ b/tools/gfx-unit-test/trivial-copy.slang @@ -0,0 +1,18 @@ +// trivial-copy.slang + +// Copy the contents of "tex" into "buffer". These are for textures containing FLOAT data. +[shader("compute")] +[numthreads(4,1,1)] +void copyTexFloat4( + uint3 sv_dispatchThreadID : SV_DispatchThreadID, + uniform uint width, + uniform uint height, + uniform RWTexture2D<float4> tex, + uniform RWStructuredBuffer<float> buffer) +{ + float4 result = tex[uint2(sv_dispatchThreadID.x % width, sv_dispatchThreadID.x / width)]; + buffer[sv_dispatchThreadID.x * 4] = result.r; + buffer[sv_dispatchThreadID.x * 4 + 1] = result.g; + buffer[sv_dispatchThreadID.x * 4 + 2] = result.b; + buffer[sv_dispatchThreadID.x * 4 + 3] = result.a; +} diff --git a/tools/gfx-util/shader-cursor.h b/tools/gfx-util/shader-cursor.h index 41d0b3945..4c281c99a 100644 --- a/tools/gfx-util/shader-cursor.h +++ b/tools/gfx-util/shader-cursor.h @@ -87,6 +87,12 @@ struct ShaderCursor return m_baseObject->setData(m_offset, data, size); } + template <typename T> + SlangResult setData(T const& data) const + { + return setData(&data, sizeof(data)); + } + SlangResult setObject(IShaderObject* object) const { return m_baseObject->setObject(m_offset, object); diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp index 7abf51ef3..b97fc819c 100644 --- a/tools/gfx/cuda/render-cuda.cpp +++ b/tools/gfx/cuda/render-cuda.cpp @@ -242,6 +242,8 @@ public: CUarray m_cudaArray = CUarray(); CUmipmappedArray m_cudaMipMappedArray = CUmipmappedArray(); + void* m_cudaExternalMemory = nullptr; + RefPtr<CUDAContext> m_cudaContext; virtual SLANG_NO_THROW Result SLANG_MCALL getNativeResourceHandle(InteropHandle* outHandle) override @@ -1439,6 +1441,62 @@ public: return SLANG_OK; } + Result getCUDAFormat(Format format, CUarray_format* outFormat) + { + // TODO: Expand to cover all available formats that can be supported in CUDA + switch (format) + { + case Format::R32G32B32A32_FLOAT: + case Format::R32G32B32_FLOAT: + case Format::R32G32_FLOAT: + case Format::R32_FLOAT: + case Format::D32_FLOAT: + *outFormat = CU_AD_FORMAT_FLOAT; + return SLANG_OK; + case Format::R16G16B16A16_FLOAT: + case Format::R16G16_FLOAT: + case Format::R16_FLOAT: + *outFormat = CU_AD_FORMAT_HALF; + return SLANG_OK; + case Format::R32G32B32A32_UINT: + case Format::R32G32B32_UINT: + case Format::R32G32_UINT: + case Format::R32_UINT: + *outFormat = CU_AD_FORMAT_UNSIGNED_INT32; + return SLANG_OK; + case Format::R16G16B16A16_UINT: + case Format::R16G16_UINT: + case Format::R16_UINT: + *outFormat = CU_AD_FORMAT_UNSIGNED_INT16; + return SLANG_OK; + case Format::R8G8B8A8_UINT: + case Format::R8G8_UINT: + case Format::R8_UINT: + case Format::R8G8B8A8_UNORM: + *outFormat = CU_AD_FORMAT_UNSIGNED_INT8; + return SLANG_OK; + case Format::R32G32B32A32_SINT: + case Format::R32G32B32_SINT: + case Format::R32G32_SINT: + case Format::R32_SINT: + *outFormat = CU_AD_FORMAT_SIGNED_INT32; + return SLANG_OK; + case Format::R16G16B16A16_SINT: + case Format::R16G16_SINT: + case Format::R16_SINT: + *outFormat = CU_AD_FORMAT_SIGNED_INT16; + return SLANG_OK; + case Format::R8G8B8A8_SINT: + case Format::R8G8_SINT: + case Format::R8_SINT: + *outFormat = CU_AD_FORMAT_SIGNED_INT8; + return SLANG_OK; + default: + SLANG_ASSERT(!"Only support R32_FLOAT/R8G8B8A8_UNORM formats for now"); + return SLANG_FAIL; + } + } + virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource( const ITextureResource::Desc& desc, const ITextureResource::SubresourceData* initData, @@ -1489,45 +1547,34 @@ public: { CUarray_format format = CU_AD_FORMAT_FLOAT; int numChannels = 0; - - switch (desc.format) + + SLANG_RETURN_ON_FAIL(getCUDAFormat(desc.format, &format)); + FormatInfo info; + gfxGetFormatInfo(desc.format, &info); + numChannels = info.channelCount; + + switch (format) { - case Format::R32G32B32A32_FLOAT: - case Format::R32G32B32_FLOAT: - case Format::R32G32_FLOAT: - case Format::R32_FLOAT: - case Format::D32_FLOAT: - { - FormatInfo info; - gfxGetFormatInfo(desc.format, &info); - format = CU_AD_FORMAT_FLOAT; - numChannels = info.channelCount; - elementSize = sizeof(float) * numChannels; - break; - } - case Format::R16G16B16A16_FLOAT: - case Format::R16G16_FLOAT: - case Format::R16_FLOAT: - { - FormatInfo info; - gfxGetFormatInfo(desc.format, &info); - format = CU_AD_FORMAT_HALF; - numChannels = info.channelCount; - elementSize = sizeof(uint16_t) * numChannels; - break; - } - case Format::R8G8B8A8_UNORM: - { - format = CU_AD_FORMAT_UNSIGNED_INT8; - numChannels = 4; - elementSize = sizeof(uint32_t); - break; - } + case CU_AD_FORMAT_FLOAT: + { + elementSize = sizeof(float) * numChannels; + break; + } + case CU_AD_FORMAT_HALF: + { + elementSize = sizeof(uint16_t) * numChannels; + break; + } + case CU_AD_FORMAT_UNSIGNED_INT8: + { + elementSize = sizeof(uint32_t) * numChannels; + break; + } default: - { - SLANG_ASSERT(!"Only support R32_FLOAT/R8G8B8A8_UNORM formats for now"); - return SLANG_FAIL; - } + { + SLANG_ASSERT(!"Only support R32_FLOAT/R8G8B8A8_UNORM formats for now"); + return SLANG_FAIL; + } } if (desc.numMipLevels > 1) @@ -1951,6 +1998,83 @@ public: return SLANG_OK; } + virtual SLANG_NO_THROW Result SLANG_MCALL createTextureFromSharedHandle( + InteropHandle handle, + const ITextureResource::Desc& desc, + const size_t size, + ITextureResource** outResource) override + { + if (handle.handleValue == 0) + { + *outResource = nullptr; + return SLANG_OK; + } + + RefPtr<TextureCUDAResource> resource = new TextureCUDAResource(desc); + resource->m_cudaContext = m_context; + + // CUDA manages sharing of buffers through the idea of an + // "external memory" object, which represents the relationship + // with another API's objects. In order to create this external + // memory association, we first need to fill in a descriptor struct. + CUDA_EXTERNAL_MEMORY_HANDLE_DESC externalMemoryHandleDesc; + memset(&externalMemoryHandleDesc, 0, sizeof(externalMemoryHandleDesc)); + switch (handle.api) + { + case InteropHandleAPI::D3D12: + externalMemoryHandleDesc.type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE; + break; + case InteropHandleAPI::Vulkan: + externalMemoryHandleDesc.type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32; + break; + default: + return SLANG_FAIL; + } + externalMemoryHandleDesc.handle.win32.handle = (void*)handle.handleValue; + externalMemoryHandleDesc.size = size; + externalMemoryHandleDesc.flags = cudaExternalMemoryDedicated; + + CUexternalMemory externalMemory; + SLANG_CUDA_RETURN_ON_FAIL(cuImportExternalMemory(&externalMemory, &externalMemoryHandleDesc)); + resource->m_cudaExternalMemory = externalMemory; + + FormatInfo formatInfo; + SLANG_RETURN_ON_FAIL(gfxGetFormatInfo(desc.format, &formatInfo)); + CUDA_ARRAY3D_DESCRIPTOR arrayDesc; + arrayDesc.Depth = desc.size.depth; + arrayDesc.Height = desc.size.height; + arrayDesc.Width = desc.size.width; + arrayDesc.NumChannels = formatInfo.channelCount; + getCUDAFormat(desc.format, &arrayDesc.Format); + arrayDesc.Flags = 0; // TODO: Flags? CUDA_ARRAY_LAYERED/SURFACE_LDST/CUBEMAP/TEXTURE_GATHER + + CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC externalMemoryMipDesc; + memset(&externalMemoryMipDesc, 0, sizeof(externalMemoryMipDesc)); + externalMemoryMipDesc.offset = 0; + externalMemoryMipDesc.arrayDesc = arrayDesc; + externalMemoryMipDesc.numLevels = desc.numMipLevels; + + CUmipmappedArray mipArray; + SLANG_CUDA_RETURN_ON_FAIL(cuExternalMemoryGetMappedMipmappedArray(&mipArray, externalMemory, &externalMemoryMipDesc)); + resource->m_cudaMipMappedArray = mipArray; + + CUarray cuArray; + SLANG_CUDA_RETURN_ON_FAIL(cuMipmappedArrayGetLevel(&cuArray, mipArray, 0)); + resource->m_cudaArray = cuArray; + + CUDA_RESOURCE_DESC surfDesc; + memset(&surfDesc, 0, sizeof(surfDesc)); + surfDesc.resType = CU_RESOURCE_TYPE_ARRAY; + surfDesc.res.array.hArray = cuArray; + + CUsurfObject surface; + SLANG_CUDA_RETURN_ON_FAIL(cuSurfObjectCreate(&surface, &surfDesc)); + resource->m_cudaSurfObj = surface; + + returnComPtr(outResource, resource); + return SLANG_OK; + } + virtual SLANG_NO_THROW Result SLANG_MCALL createTextureView( ITextureResource* texture, IResourceView::Desc const& desc, IResourceView** outView) override { @@ -2183,12 +2307,36 @@ public: size_t* outRowPitch, size_t* outPixelSize) override { - SLANG_UNUSED(texture); - SLANG_UNUSED(outBlob); - SLANG_UNUSED(outRowPitch); - SLANG_UNUSED(outPixelSize); + auto textureImpl = static_cast<TextureCUDAResource*>(texture); + RefPtr<ListBlob> blob = new ListBlob(); - return SLANG_E_NOT_AVAILABLE; + auto desc = textureImpl->getDesc(); + auto width = desc->size.width; + auto height = desc->size.height; + FormatInfo sizeInfo; + SLANG_RETURN_ON_FAIL(gfxGetFormatInfo(desc->format, &sizeInfo)); + size_t pixelSize = sizeInfo.blockSizeInBytes / sizeInfo.pixelsPerBlock; + size_t rowPitch = width * pixelSize; + size_t size = height * rowPitch; + blob->m_data.setCount((Index)size); + + CUDA_MEMCPY2D copyParam; + memset(©Param, 0, sizeof(copyParam)); + + copyParam.srcMemoryType = CU_MEMORYTYPE_ARRAY; + copyParam.srcArray = textureImpl->m_cudaArray; + + copyParam.dstMemoryType = CU_MEMORYTYPE_HOST; + copyParam.dstHost = blob->m_data.getBuffer(); + copyParam.dstPitch = rowPitch; + copyParam.WidthInBytes = copyParam.dstPitch; + copyParam.Height = height; + SLANG_CUDA_RETURN_ON_FAIL(cuMemcpy2D(©Param)); + + *outRowPitch = rowPitch; + *outPixelSize = pixelSize; + returnComPtr(outBlob, blob); + return SLANG_OK; } virtual SLANG_NO_THROW Result SLANG_MCALL readBufferResource( diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index 371d22002..ebc894291 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -314,11 +314,19 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL getSharedHandle(InteropHandle* outHandle) override { + // Check if a shared handle already exists for this resource. + if (sharedHandle.handleValue != 0) + { + *outHandle = sharedHandle; + return SLANG_OK; + } + + // If a shared handle doesn't exist, create one and store it. ComPtr<ID3D12Device> pDevice; auto pResource = m_resource.getResource(); pResource->GetDevice(IID_PPV_ARGS(pDevice.writeRef())); SLANG_RETURN_ON_FAIL(pDevice->CreateSharedHandle(pResource, NULL, GENERIC_ALL, nullptr, (HANDLE*)&outHandle->handleValue)); - outHandle->api = InteropHandleAPI::Win32; + outHandle->api = InteropHandleAPI::D3D12; return SLANG_OK; } }; @@ -5031,7 +5039,7 @@ Result D3D12Device::getTextureAllocationInfo( TextureResource::Desc srcDesc = fixupTextureDesc(desc); D3D12_RESOURCE_DESC resourceDesc = {}; setupResourceDesc(resourceDesc, srcDesc); - auto allocInfo = m_device->GetResourceAllocationInfo(0xFF, 1, &resourceDesc); + auto allocInfo = m_device->GetResourceAllocationInfo(0, 1, &resourceDesc); *outSize = (size_t)allocInfo.SizeInBytes; *outAlignment = (size_t)allocInfo.Alignment; return SLANG_OK; @@ -5061,6 +5069,9 @@ Result D3D12Device::createTextureResource(const ITextureResource::Desc& descIn, heapProps.CreationNodeMask = 1; heapProps.VisibleNodeMask = 1; + D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE; + if (descIn.isShared) flags |= D3D12_HEAP_FLAG_SHARED; + D3D12_CLEAR_VALUE clearValue; D3D12_CLEAR_VALUE* clearValuePtr = &clearValue; if ((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | @@ -5075,7 +5086,7 @@ Result D3D12Device::createTextureResource(const ITextureResource::Desc& descIn, SLANG_RETURN_ON_FAIL(texture->m_resource.initCommitted( m_device, heapProps, - D3D12_HEAP_FLAG_NONE, + flags, resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, clearValuePtr)); diff --git a/tools/gfx/debug-layer.cpp b/tools/gfx/debug-layer.cpp index 470b63599..60e726243 100644 --- a/tools/gfx/debug-layer.cpp +++ b/tools/gfx/debug-layer.cpp @@ -370,6 +370,22 @@ Result DebugDevice::createTextureFromNativeHandle( return result; } +Result DebugDevice::createTextureFromSharedHandle( + InteropHandle handle, + const ITextureResource::Desc& srcDesc, + const size_t size, + ITextureResource** outResource) +{ + SLANG_GFX_API_FUNC; + + RefPtr<DebugTextureResource> outObject = new DebugTextureResource(); + auto result = baseObject->createTextureFromSharedHandle(handle, srcDesc, size, outObject->baseObject.writeRef()); + if (SLANG_FAILED(result)) + return result; + returnComPtr(outResource, outObject); + return result; +} + Result DebugDevice::createBufferResource( const IBufferResource::Desc& desc, const void* initData, diff --git a/tools/gfx/debug-layer.h b/tools/gfx/debug-layer.h index e0a97ee1c..71cf74260 100644 --- a/tools/gfx/debug-layer.h +++ b/tools/gfx/debug-layer.h @@ -60,6 +60,11 @@ public: InteropHandle handle, const ITextureResource::Desc& srcDesc, ITextureResource** outResource) override; + virtual SLANG_NO_THROW Result SLANG_MCALL createTextureFromSharedHandle( + InteropHandle handle, + const ITextureResource::Desc& srcDesc, + const size_t size, + ITextureResource** outResource) override; virtual SLANG_NO_THROW Result SLANG_MCALL createBufferResource( const IBufferResource::Desc& desc, const void* initData, diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp index 101e02d47..df6ebd37e 100644 --- a/tools/gfx/renderer-shared.cpp +++ b/tools/gfx/renderer-shared.cpp @@ -365,6 +365,19 @@ SLANG_NO_THROW Result SLANG_MCALL RendererBase::createTextureFromNativeHandle( return SLANG_E_NOT_AVAILABLE; } +SLANG_NO_THROW Result SLANG_MCALL RendererBase::createTextureFromSharedHandle( + InteropHandle handle, + const ITextureResource::Desc& srcDesc, + const size_t size, + ITextureResource** outResource) +{ + SLANG_UNUSED(handle); + SLANG_UNUSED(srcDesc); + SLANG_UNUSED(size); + SLANG_UNUSED(outResource); + return SLANG_E_NOT_AVAILABLE; +} + SLANG_NO_THROW Result SLANG_MCALL RendererBase::createBufferFromNativeHandle( InteropHandle handle, const IBufferResource::Desc& srcDesc, @@ -381,6 +394,7 @@ SLANG_NO_THROW Result SLANG_MCALL RendererBase::createBufferFromSharedHandle( const IBufferResource::Desc& srcDesc, IBufferResource** outResource) { + SLANG_UNUSED(handle); SLANG_UNUSED(srcDesc); SLANG_UNUSED(outResource); return SLANG_E_NOT_AVAILABLE; diff --git a/tools/gfx/renderer-shared.h b/tools/gfx/renderer-shared.h index e7ea1b7f5..7859f1ad9 100644 --- a/tools/gfx/renderer-shared.h +++ b/tools/gfx/renderer-shared.h @@ -1206,6 +1206,12 @@ public: const ITextureResource::Desc& srcDesc, ITextureResource** outResource) SLANG_OVERRIDE; + virtual SLANG_NO_THROW Result SLANG_MCALL createTextureFromSharedHandle( + InteropHandle handle, + const ITextureResource::Desc& srcDesc, + const size_t size, + ITextureResource** outResource) SLANG_OVERRIDE; + virtual SLANG_NO_THROW Result SLANG_MCALL createBufferFromNativeHandle( InteropHandle handle, const IBufferResource::Desc& srcDesc, diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp index 25609ec6e..b55c78ea0 100644 --- a/tools/gfx/vulkan/render-vk.cpp +++ b/tools/gfx/vulkan/render-vk.cpp @@ -381,6 +381,12 @@ public: vkAPI.vkFreeMemory(vkAPI.m_device, m_imageMemory, nullptr); vkAPI.vkDestroyImage(vkAPI.m_device, m_image, nullptr); } + if (sharedHandle.handleValue != 0) + { +#if SLANG_WINDOWS_FAMILY + CloseHandle((HANDLE)sharedHandle.handleValue); +#endif + } } VkImage m_image = VK_NULL_HANDLE; @@ -398,8 +404,31 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL getSharedHandle(InteropHandle* outHandle) override { + // Check if a shared handle already exists for this resource. + if (sharedHandle.handleValue != 0) + { + *outHandle = sharedHandle; + return SLANG_OK; + } + + // If a shared handle doesn't exist, create one and store it. +#if SLANG_WINDOWS_FAMILY + VkMemoryGetWin32HandleInfoKHR info = {}; + info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + info.pNext = nullptr; + info.memory = m_imageMemory; + info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + + auto& api = m_device->m_api; + PFN_vkGetMemoryWin32HandleKHR vkCreateSharedHandle; + vkCreateSharedHandle = api.vkGetMemoryWin32HandleKHR; + if (!vkCreateSharedHandle) + { + return SLANG_FAIL; + } + SLANG_RETURN_ON_FAIL(vkCreateSharedHandle(m_device->m_device, &info, (HANDLE*)&outHandle->handleValue) != VK_SUCCESS); +#endif outHandle->api = InteropHandleAPI::Vulkan; - outHandle->handleValue = 0; return SLANG_OK; } }; @@ -5712,7 +5741,7 @@ Result VKDevice::Buffer::init( exportMemoryAllocateInfo.pNext = extMemHandleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR ? &exportMemoryWin32HandleInfo - : NULL; + : nullptr; exportMemoryAllocateInfo.handleTypes = extMemHandleType; allocateInfo.pNext = &exportMemoryAllocateInfo; } @@ -6921,78 +6950,99 @@ Result VKDevice::createTextureResource(const ITextureResource::Desc& descIn, con RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(desc, this)); texture->m_vkformat = format; // Create the image + + VkImageCreateInfo imageInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + switch (desc.type) { - VkImageCreateInfo imageInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; - switch (desc.type) + case IResource::Type::Texture1D: { - case IResource::Type::Texture1D: - { - imageInfo.imageType = VK_IMAGE_TYPE_1D; - imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), 1, 1 }; - break; - } - case IResource::Type::Texture2D: - { - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1 }; - break; - } - case IResource::Type::TextureCube: - { - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1 }; - imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - break; - } - case IResource::Type::Texture3D: - { - // Can't have an array and 3d texture - assert(desc.arraySize <= 1); + imageInfo.imageType = VK_IMAGE_TYPE_1D; + imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), 1, 1 }; + break; + } + case IResource::Type::Texture2D: + { + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1 }; + break; + } + case IResource::Type::TextureCube: + { + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1 }; + imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + break; + } + case IResource::Type::Texture3D: + { + // Can't have an array and 3d texture + assert(desc.arraySize <= 1); - imageInfo.imageType = VK_IMAGE_TYPE_3D; - imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), uint32_t(descIn.size.depth) }; - break; - } - default: - { - assert(!"Unhandled type"); - return SLANG_FAIL; - } + imageInfo.imageType = VK_IMAGE_TYPE_3D; + imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), uint32_t(descIn.size.depth) }; + break; + } + default: + { + assert(!"Unhandled type"); + return SLANG_FAIL; } + } - imageInfo.mipLevels = desc.numMipLevels; - imageInfo.arrayLayers = arraySize; + imageInfo.mipLevels = desc.numMipLevels; + imageInfo.arrayLayers = arraySize; - imageInfo.format = format; + imageInfo.format = format; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.usage = _calcImageUsageFlags(desc.allowedStates, desc.cpuAccessFlags, initData); - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.usage = _calcImageUsageFlags(desc.allowedStates, desc.cpuAccessFlags, initData); + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateImage(m_device, &imageInfo, nullptr, &texture->m_image)); + VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = { VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO }; +#if SLANG_WINDOWS_FAMILY + VkExternalMemoryHandleTypeFlags extMemoryHandleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (descIn.isShared) + { + externalMemoryImageCreateInfo.pNext = nullptr; + externalMemoryImageCreateInfo.handleTypes = extMemoryHandleType; + imageInfo.pNext = &externalMemoryImageCreateInfo; } +#endif + SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateImage(m_device, &imageInfo, nullptr, &texture->m_image)); VkMemoryRequirements memRequirements; m_api.vkGetImageMemoryRequirements(m_device, texture->m_image, &memRequirements); // Allocate the memory - { - VkMemoryPropertyFlags reqMemoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - VkMemoryAllocateInfo allocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; - - int memoryTypeIndex = m_api.findMemoryTypeIndex(memRequirements.memoryTypeBits, reqMemoryProperties); - assert(memoryTypeIndex >= 0); - - VkMemoryPropertyFlags actualMemoryProperites = m_api.m_deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags; + VkMemoryPropertyFlags reqMemoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + int memoryTypeIndex = m_api.findMemoryTypeIndex(memRequirements.memoryTypeBits, reqMemoryProperties); + assert(memoryTypeIndex >= 0); - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = memoryTypeIndex; + VkMemoryPropertyFlags actualMemoryProperites = m_api.m_deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags; + VkMemoryAllocateInfo allocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = memoryTypeIndex; +#if SLANG_WINDOWS_FAMILY + VkExportMemoryWin32HandleInfoKHR exportMemoryWin32HandleInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR }; + VkExportMemoryAllocateInfoKHR exportMemoryAllocateInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR }; + if (descIn.isShared) + { + exportMemoryWin32HandleInfo.pNext = nullptr; + exportMemoryWin32HandleInfo.pAttributes = nullptr; + exportMemoryWin32HandleInfo.dwAccess = DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE; + exportMemoryWin32HandleInfo.name = NULL; - SLANG_VK_RETURN_ON_FAIL(m_api.vkAllocateMemory(m_device, &allocInfo, nullptr, &texture->m_imageMemory)); + exportMemoryAllocateInfo.pNext = + extMemoryHandleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR + ? &exportMemoryWin32HandleInfo + : nullptr; + exportMemoryAllocateInfo.handleTypes = extMemoryHandleType; + allocInfo.pNext = &exportMemoryAllocateInfo; } +#endif + SLANG_VK_RETURN_ON_FAIL(m_api.vkAllocateMemory(m_device, &allocInfo, nullptr, &texture->m_imageMemory)); // Bind the memory to the image m_api.vkBindImageMemory(m_device, texture->m_image, texture->m_imageMemory, 0); |
