summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlucy96chen <47800040+lucy96chen@users.noreply.github.com>2021-12-08 11:38:14 -0800
committerGitHub <noreply@github.com>2021-12-08 11:38:14 -0800
commit9606401e1de1002e3ad070bc5c6384fa5bc4d9ff (patch)
tree7a557a14fadf5220a34f6df9faf1a5535100743f
parent90d8af888b40c83b33f9f0c037bd2ab8c19a35f4 (diff)
D3D12 and Vulkan to CUDA Texture Sharing (#2038)
-rw-r--r--build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj4
-rw-r--r--build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters12
-rw-r--r--slang-gfx.h6
-rw-r--r--tools/gfx-unit-test/gfx-test-util.cpp14
-rw-r--r--tools/gfx-unit-test/gfx-test-util.h24
-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.cpp221
-rw-r--r--tools/gfx-unit-test/trivial-copy.slang18
-rw-r--r--tools/gfx-util/shader-cursor.h6
-rw-r--r--tools/gfx/cuda/render-cuda.cpp232
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp17
-rw-r--r--tools/gfx/debug-layer.cpp16
-rw-r--r--tools/gfx/debug-layer.h5
-rw-r--r--tools/gfx/renderer-shared.cpp14
-rw-r--r--tools/gfx/renderer-shared.h6
-rw-r--r--tools/gfx/vulkan/render-vk.cpp162
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(&copyParam, 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(&copyParam));
+
+ *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);