From 90d8af888b40c83b33f9f0c037bd2ab8c19a35f4 Mon Sep 17 00:00:00 2001 From: Yong He Date: Tue, 7 Dec 2021 13:45:49 -0800 Subject: gfx: D3D12 and VK Fence implementation. (#2048) * gfx: D3D12 and VK Fence implementation. * Fix. * Update project files. * Revert project file changes. * Remove project files Co-authored-by: Yong He --- .../gfx-unit-test-tool/gfx-unit-test-tool.vcxproj | 1 + .../gfx-unit-test-tool.vcxproj.filters | 3 + examples/example-base/example-base.cpp | 2 +- examples/example-base/example-base.h | 2 +- examples/ray-tracing-pipeline/main.cpp | 6 +- examples/ray-tracing/main.cpp | 6 +- examples/shader-object/main.cpp | 2 +- slang-gfx.h | 8 +- tools/gfx-unit-test/buffer-barrier-test.cpp | 2 +- tools/gfx-unit-test/compute-smoke.cpp | 2 +- tools/gfx-unit-test/create-buffer-from-handle.cpp | 2 +- .../gfx-unit-test/existing-device-handle-test.cpp | 2 +- tools/gfx-unit-test/format-unit-tests.cpp | 2 +- tools/gfx-unit-test/get-shared-handle.cpp | 2 +- tools/gfx-unit-test/mutable-shader-object.cpp | 2 +- tools/gfx-unit-test/root-mutable-shader-object.cpp | 2 +- tools/gfx/cuda/render-cuda.cpp | 8 +- tools/gfx/d3d12/render-d3d12.cpp | 108 +++++++++- tools/gfx/debug-layer.cpp | 18 +- tools/gfx/debug-layer.h | 4 +- tools/gfx/immediate-renderer-base.cpp | 8 +- tools/gfx/renderer-shared.cpp | 7 + tools/gfx/renderer-shared.h | 7 + tools/gfx/vulkan/render-vk.cpp | 227 ++++++++++++++++++--- tools/gfx/vulkan/vk-api.cpp | 5 +- tools/gfx/vulkan/vk-api.h | 6 + tools/render-test/render-test-main.cpp | 10 +- 27 files changed, 390 insertions(+), 64 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 d48caf61d..1463cfecb 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 @@ -284,6 +284,7 @@ + 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 c2b2d6a49..80186a7eb 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 @@ -53,6 +53,9 @@ Source Files + + Source Files + Source Files diff --git a/examples/example-base/example-base.cpp b/examples/example-base/example-base.cpp index a7a8e7673..2a50c12db 100644 --- a/examples/example-base/example-base.cpp +++ b/examples/example-base/example-base.cpp @@ -155,7 +155,7 @@ void WindowedAppBase::createSwapchainFramebuffers() void WindowedAppBase::windowSizeChanged() { // Wait for the GPU to finish. - gQueue->wait(); + gQueue->waitOnHost(); auto clientRect = gWindow->getClientRect(); if (clientRect.width > 0 && clientRect.height > 0) diff --git a/examples/example-base/example-base.h b/examples/example-base/example-base.h index b898f7417..49c992ca3 100644 --- a/examples/example-base/example-base.h +++ b/examples/example-base/example-base.h @@ -40,7 +40,7 @@ protected: virtual void renderFrame(int framebufferIndex) = 0; public: platform::Window* getWindow() { return gWindow.Ptr(); } - virtual void finalize() { gQueue->wait(); } + virtual void finalize() { gQueue->waitOnHost(); } }; int64_t getCurrentTime(); diff --git a/examples/ray-tracing-pipeline/main.cpp b/examples/ray-tracing-pipeline/main.cpp index 17ca046db..f83025b52 100644 --- a/examples/ray-tracing-pipeline/main.cpp +++ b/examples/ray-tracing-pipeline/main.cpp @@ -405,7 +405,7 @@ Slang::Result initialize() encoder->endEncoding(); commandBuffer->close(); gQueue->executeCommandBuffer(commandBuffer); - gQueue->wait(); + gQueue->waitOnHost(); uint64_t compactedSize = 0; compactedSizeQuery->getResult(0, 1, &compactedSize); @@ -427,7 +427,7 @@ Slang::Result initialize() encoder->endEncoding(); commandBuffer->close(); gQueue->executeCommandBuffer(commandBuffer); - gQueue->wait(); + gQueue->waitOnHost(); } // Build top level acceleration structure. @@ -491,7 +491,7 @@ Slang::Result initialize() encoder->endEncoding(); commandBuffer->close(); gQueue->executeCommandBuffer(commandBuffer); - gQueue->wait(); + gQueue->waitOnHost(); } IBufferResource::Desc fullScreenVertexBufferDesc; diff --git a/examples/ray-tracing/main.cpp b/examples/ray-tracing/main.cpp index e51a601a2..2d947e567 100644 --- a/examples/ray-tracing/main.cpp +++ b/examples/ray-tracing/main.cpp @@ -397,7 +397,7 @@ Slang::Result initialize() encoder->endEncoding(); commandBuffer->close(); gQueue->executeCommandBuffer(commandBuffer); - gQueue->wait(); + gQueue->waitOnHost(); uint64_t compactedSize = 0; compactedSizeQuery->getResult(0, 1, &compactedSize); @@ -419,7 +419,7 @@ Slang::Result initialize() encoder->endEncoding(); commandBuffer->close(); gQueue->executeCommandBuffer(commandBuffer); - gQueue->wait(); + gQueue->waitOnHost(); } // Build top level acceleration structure. @@ -483,7 +483,7 @@ Slang::Result initialize() encoder->endEncoding(); commandBuffer->close(); gQueue->executeCommandBuffer(commandBuffer); - gQueue->wait(); + gQueue->waitOnHost(); } IBufferResource::Desc fullScreenVertexBufferDesc; diff --git a/examples/shader-object/main.cpp b/examples/shader-object/main.cpp index 5ab327df7..14835f0c8 100644 --- a/examples/shader-object/main.cpp +++ b/examples/shader-object/main.cpp @@ -235,7 +235,7 @@ int main() encoder->endEncoding(); commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); - queue->wait(); + queue->waitOnHost(); } // Read back the results. ComPtr resultBlob; diff --git a/slang-gfx.h b/slang-gfx.h index 80327e992..0600d5623 100644 --- a/slang-gfx.h +++ b/slang-gfx.h @@ -913,6 +913,7 @@ public: struct Desc { uint64_t initialValue = 0; + bool isShared = false; }; /// Returns the currently signaled value on the device. @@ -1727,9 +1728,12 @@ public: executeCommandBuffers(1, &commandBuffer, fenceToSignal, newFenceValue); } - virtual SLANG_NO_THROW void SLANG_MCALL wait() = 0; - virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(NativeHandle* outHandle) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL waitOnHost() = 0; + + /// Queue a device side wait for the given fences. + virtual SLANG_NO_THROW Result SLANG_MCALL waitForFences(uint32_t fenceCount, IFence** fences, uint64_t* waitValues) = 0; }; #define SLANG_UUID_ICommandQueue \ { \ diff --git a/tools/gfx-unit-test/buffer-barrier-test.cpp b/tools/gfx-unit-test/buffer-barrier-test.cpp index 4dd3aa9a8..f11dd1e5b 100644 --- a/tools/gfx-unit-test/buffer-barrier-test.cpp +++ b/tools/gfx-unit-test/buffer-barrier-test.cpp @@ -109,7 +109,7 @@ namespace gfx_test encoder->endEncoding(); commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); - queue->wait(); + queue->waitOnHost(); } compareComputeResult( diff --git a/tools/gfx-unit-test/compute-smoke.cpp b/tools/gfx-unit-test/compute-smoke.cpp index 9a8298bf8..4dc3c685c 100644 --- a/tools/gfx-unit-test/compute-smoke.cpp +++ b/tools/gfx-unit-test/compute-smoke.cpp @@ -87,7 +87,7 @@ namespace gfx_test encoder->endEncoding(); commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); - queue->wait(); + queue->waitOnHost(); } compareComputeResult( diff --git a/tools/gfx-unit-test/create-buffer-from-handle.cpp b/tools/gfx-unit-test/create-buffer-from-handle.cpp index 538dc492a..71b5f5ca2 100644 --- a/tools/gfx-unit-test/create-buffer-from-handle.cpp +++ b/tools/gfx-unit-test/create-buffer-from-handle.cpp @@ -78,7 +78,7 @@ namespace gfx_test encoder->endEncoding(); commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); - queue->wait(); + queue->waitOnHost(); } compareComputeResult( diff --git a/tools/gfx-unit-test/existing-device-handle-test.cpp b/tools/gfx-unit-test/existing-device-handle-test.cpp index 652a530af..257ac1f37 100644 --- a/tools/gfx-unit-test/existing-device-handle-test.cpp +++ b/tools/gfx-unit-test/existing-device-handle-test.cpp @@ -72,7 +72,7 @@ namespace gfx_test encoder->endEncoding(); commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); - queue->wait(); + queue->waitOnHost(); } compareComputeResult( diff --git a/tools/gfx-unit-test/format-unit-tests.cpp b/tools/gfx-unit-test/format-unit-tests.cpp index b499b67bd..d46a074e5 100644 --- a/tools/gfx-unit-test/format-unit-tests.cpp +++ b/tools/gfx-unit-test/format-unit-tests.cpp @@ -91,7 +91,7 @@ namespace gfx_test encoder->endEncoding(); commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); - queue->wait(); + queue->waitOnHost(); } } diff --git a/tools/gfx-unit-test/get-shared-handle.cpp b/tools/gfx-unit-test/get-shared-handle.cpp index 06114f139..8b991f15c 100644 --- a/tools/gfx-unit-test/get-shared-handle.cpp +++ b/tools/gfx-unit-test/get-shared-handle.cpp @@ -89,7 +89,7 @@ namespace gfx_test encoder->endEncoding(); commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); - queue->wait(); + queue->waitOnHost(); } compareComputeResult( diff --git a/tools/gfx-unit-test/mutable-shader-object.cpp b/tools/gfx-unit-test/mutable-shader-object.cpp index efaf95761..8e3838620 100644 --- a/tools/gfx-unit-test/mutable-shader-object.cpp +++ b/tools/gfx-unit-test/mutable-shader-object.cpp @@ -104,7 +104,7 @@ namespace gfx_test commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); - queue->wait(); + queue->waitOnHost(); } compareComputeResult( diff --git a/tools/gfx-unit-test/root-mutable-shader-object.cpp b/tools/gfx-unit-test/root-mutable-shader-object.cpp index 8cd2abbd6..c20d3aa41 100644 --- a/tools/gfx-unit-test/root-mutable-shader-object.cpp +++ b/tools/gfx-unit-test/root-mutable-shader-object.cpp @@ -99,7 +99,7 @@ namespace gfx_test commandBuffer->close(); queue->executeCommandBuffer(commandBuffer); - queue->wait(); + queue->waitOnHost(); } compareComputeResult( diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp index a3c288ab0..7abf51ef3 100644 --- a/tools/gfx/cuda/render-cuda.cpp +++ b/tools/gfx/cuda/render-cuda.cpp @@ -1212,13 +1212,19 @@ public: } } - virtual SLANG_NO_THROW void SLANG_MCALL wait() override + virtual SLANG_NO_THROW void SLANG_MCALL waitOnHost() override { auto resultCode = cuStreamSynchronize(stream); if (resultCode != cudaSuccess) SLANG_CUDA_HANDLE_ERROR(resultCode); } + virtual SLANG_NO_THROW Result SLANG_MCALL + waitForFences(uint32_t fenceCount, IFence** fences, uint64_t* waitValues) override + { + return SLANG_FAIL; + } + virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(NativeHandle* outHandle) override { diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index e8dadfbbb..371d22002 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -144,6 +144,16 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL createQueryPool( const IQueryPool::Desc& desc, IQueryPool** outState) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + createFence(const IFence::Desc& desc, IFence** outFence) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL waitForFences( + uint32_t fenceCount, + IFence** fences, + uint64_t* fenceValues, + bool waitForAll, + uint64_t timeout) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource( ITextureResource* resource, ResourceState state, @@ -3780,6 +3790,65 @@ public: } }; + class FenceImpl : public FenceBase + { + public: + ComPtr m_fence; + HANDLE m_waitEvent = 0; + + ~FenceImpl() + { + if (m_waitEvent) + CloseHandle(m_waitEvent); + } + + HANDLE getWaitEvent() + { + if (m_waitEvent) + return m_waitEvent; + m_waitEvent = CreateEventEx( + nullptr, + nullptr, + 0, + EVENT_ALL_ACCESS); + return m_waitEvent; + } + + Result init(D3D12Device* device, const IFence::Desc& desc) + { + SLANG_RETURN_ON_FAIL(device->m_device->CreateFence( + desc.initialValue, + desc.isShared ? D3D12_FENCE_FLAG_SHARED : D3D12_FENCE_FLAG_NONE, + IID_PPV_ARGS(m_fence.writeRef()))); + return SLANG_OK; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL getCurrentValue(uint64_t* outValue) override + { + *outValue = m_fence->GetCompletedValue(); + return SLANG_OK; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL setCurrentValue(uint64_t value) override + { + SLANG_RETURN_ON_FAIL(m_fence->Signal(value)); + return SLANG_OK; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL getSharedHandle(InteropHandle* outHandle) override + { + outHandle->handleValue = 0; + return SLANG_FAIL; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL + getNativeHandle(InteropHandle* outNativeHandle) override + { + outNativeHandle->handleValue = 0; + return SLANG_FAIL; + } + }; + class CommandQueueImpl : public ICommandQueue , public ComObject @@ -3823,7 +3892,7 @@ public: } ~CommandQueueImpl() { - wait(); + waitOnHost(); CloseHandle(globalWaitHandle); m_renderer->m_queueIndexAllocator.free((int)m_queueIndex, 1); } @@ -3861,7 +3930,7 @@ public: ResetEvent(globalWaitHandle); } - virtual SLANG_NO_THROW void SLANG_MCALL wait() override + virtual SLANG_NO_THROW void SLANG_MCALL waitOnHost() override { m_fenceValue++; m_d3dQueue->Signal(m_fence, m_fenceValue); @@ -3870,6 +3939,17 @@ public: WaitForSingleObject(globalWaitHandle, INFINITE); } + virtual SLANG_NO_THROW Result SLANG_MCALL + waitForFences(uint32_t fenceCount, IFence** fences, uint64_t* waitValues) override + { + for (uint32_t i = 0; i < fenceCount; ++i) + { + auto fenceImpl = static_cast(fences[i]); + m_d3dQueue->Wait(fenceImpl->m_fence.get(), waitValues[i]); + } + return SLANG_OK; + } + virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(NativeHandle* outHandle) override { @@ -6205,6 +6285,30 @@ Result D3D12Device::createQueryPool(const IQueryPool::Desc& desc, IQueryPool** o } } +Result D3D12Device::createFence(const IFence::Desc& desc, IFence** outFence) +{ + RefPtr fence = new FenceImpl(); + SLANG_RETURN_ON_FAIL(fence->init(this, desc)); + returnComPtr(outFence, fence); + return SLANG_OK; +} + +Result D3D12Device::waitForFences( + uint32_t fenceCount, IFence** fences, uint64_t* fenceValues, bool waitForAll, uint64_t timeout) +{ + List waitHandles; + for (uint32_t i = 0; i < fenceCount; ++i) + { + auto fenceImpl = static_cast(fences[i]); + waitHandles.add(fenceImpl->getWaitEvent()); + SLANG_RETURN_ON_FAIL(fenceImpl->m_fence->SetEventOnCompletion(fenceValues[i], fenceImpl->getWaitEvent())); + } + auto result = WaitForMultipleObjects(fenceCount, waitHandles.getBuffer(), waitForAll ? TRUE : FALSE, (DWORD)timeout); + if (result == WAIT_TIMEOUT) + return SLANG_E_TIME_OUT; + return result == WAIT_FAILED ? SLANG_FAIL : SLANG_OK; +} + #if SLANG_GFX_HAS_DXR_SUPPORT class D3D12AccelerationStructureImpl diff --git a/tools/gfx/debug-layer.cpp b/tools/gfx/debug-layer.cpp index 831566c7c..470b63599 100644 --- a/tools/gfx/debug-layer.cpp +++ b/tools/gfx/debug-layer.cpp @@ -1467,10 +1467,26 @@ void DebugCommandQueue::executeCommandBuffers(uint32_t count, ICommandBuffer* co baseObject->executeCommandBuffers(count, innerCommandBuffers.getBuffer(), getInnerObj(fence), valueToSignal); } -void DebugCommandQueue::wait() { baseObject->wait(); } +void DebugCommandQueue::waitOnHost() +{ + SLANG_GFX_API_FUNC; + baseObject->waitOnHost(); +} + +Result DebugCommandQueue::waitForFences(uint32_t fenceCount, IFence** fences, uint64_t* waitValues) +{ + SLANG_GFX_API_FUNC; + List innerFences; + for (uint32_t i = 0; i < fenceCount; ++i) + { + innerFences.add(getInnerObj(fences[i])); + } + return baseObject->waitForFences(fenceCount, innerFences.getBuffer(), waitValues); +} Result DebugCommandQueue::getNativeHandle(NativeHandle* outHandle) { + SLANG_GFX_API_FUNC; return baseObject->getNativeHandle(outHandle); } diff --git a/tools/gfx/debug-layer.h b/tools/gfx/debug-layer.h index f61917835..e0a97ee1c 100644 --- a/tools/gfx/debug-layer.h +++ b/tools/gfx/debug-layer.h @@ -560,7 +560,9 @@ public: virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() override; virtual SLANG_NO_THROW void SLANG_MCALL executeCommandBuffers(uint32_t count, ICommandBuffer* const* commandBuffers, IFence* fence, uint64_t valueToSignal) override; - virtual SLANG_NO_THROW void SLANG_MCALL wait() override; + virtual SLANG_NO_THROW void SLANG_MCALL waitOnHost() override; + virtual SLANG_NO_THROW Result SLANG_MCALL + waitForFences(uint32_t fenceCount, IFence** fences, uint64_t* waitValues) override; virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(NativeHandle* outHandle) override; }; diff --git a/tools/gfx/immediate-renderer-base.cpp b/tools/gfx/immediate-renderer-base.cpp index 360370aa0..34cc70b74 100644 --- a/tools/gfx/immediate-renderer-base.cpp +++ b/tools/gfx/immediate-renderer-base.cpp @@ -593,7 +593,13 @@ public: static_cast(m_renderer.get())->endCommandBuffer(info); } - virtual SLANG_NO_THROW void SLANG_MCALL wait() override { getRenderer()->waitForGpu(); } + virtual SLANG_NO_THROW void SLANG_MCALL waitOnHost() override { getRenderer()->waitForGpu(); } + + virtual SLANG_NO_THROW Result SLANG_MCALL + waitForFences(uint32_t fenceCount, IFence** fences, uint64_t* waitValues) override + { + return SLANG_FAIL; + } virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(NativeHandle* outHandle) override diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp index c212f21eb..101e02d47 100644 --- a/tools/gfx/renderer-shared.cpp +++ b/tools/gfx/renderer-shared.cpp @@ -65,6 +65,13 @@ return gfx::StageType::TO } } +IFence* FenceBase::getInterface(const Slang::Guid& guid) +{ + if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IFence) + return static_cast(this); + return nullptr; +} + IResource* BufferResource::getInterface(const Slang::Guid& guid) { if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IResource || diff --git a/tools/gfx/renderer-shared.h b/tools/gfx/renderer-shared.h index 1d5d1860e..e7ea1b7f5 100644 --- a/tools/gfx/renderer-shared.h +++ b/tools/gfx/renderer-shared.h @@ -185,6 +185,13 @@ void returnRefPtrMove(TDest** outPtr, Slang::RefPtr& refPtr) gfx::StageType translateStage(SlangStage slangStage); +class FenceBase : public IFence, public Slang::ComObject +{ +public: + SLANG_COM_OBJECT_IUNKNOWN_ALL + IFence* getInterface(const Slang::Guid& guid); +}; + class Resource : public Slang::ComObject { public: diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp index 59f12cb41..25609ec6e 100644 --- a/tools/gfx/vulkan/render-vk.cpp +++ b/tools/gfx/vulkan/render-vk.cpp @@ -146,6 +146,16 @@ public: virtual SLANG_NO_THROW Result SLANG_MCALL getTextureAllocationInfo( const ITextureResource::Desc& desc, size_t* outSize, size_t* outAlignment) override; + virtual SLANG_NO_THROW Result SLANG_MCALL + createFence(const IFence::Desc& desc, IFence** outFence) override; + + virtual SLANG_NO_THROW Result SLANG_MCALL waitForFences( + uint32_t fenceCount, + IFence** fences, + uint64_t* fenceValues, + bool waitForAll, + uint64_t timeout) override; + void waitForGpu(); virtual SLANG_NO_THROW const DeviceInfo& SLANG_MCALL getDeviceInfo() const override @@ -270,13 +280,90 @@ public: { return SLANG_FAIL; } - SLANG_RETURN_ON_FAIL(vkCreateSharedHandle(api->m_device, &info, (HANDLE*)&outHandle->handleValue) != VK_SUCCESS); + SLANG_VK_RETURN_ON_FAIL( + vkCreateSharedHandle(api->m_device, &info, (HANDLE*)&outHandle->handleValue)); #endif outHandle->api = InteropHandleAPI::Vulkan; return SLANG_OK; } }; + class FenceImpl : public FenceBase + { + public: + VkSemaphore m_semaphore = VK_NULL_HANDLE; + RefPtr m_device; + + FenceImpl(VKDevice* device) + : m_device(device) + { + + } + + ~FenceImpl() + { + if (m_semaphore) + { + m_device->m_api.vkDestroySemaphore(m_device->m_api.m_device, m_semaphore, nullptr); + } + } + + Result init(const IFence::Desc& desc) + { + if (!m_device->m_api.m_extendedFeatures.timelineFeatures.timelineSemaphore) + return SLANG_E_NOT_AVAILABLE; + + VkSemaphoreTypeCreateInfo timelineCreateInfo; + timelineCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + timelineCreateInfo.pNext = nullptr; + timelineCreateInfo.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + timelineCreateInfo.initialValue = desc.initialValue; + + VkSemaphoreCreateInfo createInfo; + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + createInfo.pNext = &timelineCreateInfo; + createInfo.flags = 0; + + SLANG_VK_RETURN_ON_FAIL(m_device->m_api.vkCreateSemaphore( + m_device->m_api.m_device, &createInfo, nullptr, &m_semaphore)); + + return SLANG_OK; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL getCurrentValue(uint64_t* outValue) override + { + SLANG_VK_RETURN_ON_FAIL(m_device->m_api.vkGetSemaphoreCounterValue( + m_device->m_api.m_device, m_semaphore, outValue)); + return SLANG_OK; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL setCurrentValue(uint64_t value) override + { + VkSemaphoreSignalInfo signalInfo; + signalInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; + signalInfo.pNext = NULL; + signalInfo.semaphore = m_semaphore; + signalInfo.value = 2; + + SLANG_VK_RETURN_ON_FAIL( + m_device->m_api.vkSignalSemaphore(m_device->m_api.m_device, &signalInfo)); + return SLANG_OK; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL getSharedHandle(InteropHandle* outHandle) override + { + outHandle->handleValue = 0; + return SLANG_FAIL; + } + + virtual SLANG_NO_THROW Result SLANG_MCALL + getNativeHandle(InteropHandle* outNativeHandle) override + { + outNativeHandle->handleValue = 0; + return SLANG_FAIL; + } + }; + class TextureResourceImpl : public TextureResource { public: @@ -4817,40 +4904,37 @@ public: RefPtr m_renderer; VkQueue m_queue; uint32_t m_queueFamilyIndex; + struct FenceWaitInfo + { + RefPtr fence; + uint64_t waitValue; + }; + List m_pendingWaitFences; VkSemaphore m_pendingWaitSemaphores[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE}; List m_submitCommandBuffers; - static const int kSemaphoreCount = 32; - uint32_t m_currentSemaphoreIndex; - VkSemaphore m_semaphores[kSemaphoreCount]; + VkSemaphore m_semaphore; ~CommandQueueImpl() { m_renderer->m_api.vkQueueWaitIdle(m_queue); m_renderer->m_queueAllocCount--; - for (int i = 0; i < kSemaphoreCount; i++) - { - m_renderer->m_api.vkDestroySemaphore( - m_renderer->m_api.m_device, m_semaphores[i], nullptr); - } + m_renderer->m_api.vkDestroySemaphore( + m_renderer->m_api.m_device, m_semaphore, nullptr); } void init(VKDevice* renderer, VkQueue queue, uint32_t queueFamilyIndex) { m_renderer = renderer; - m_currentSemaphoreIndex = 0; m_queue = queue; m_queueFamilyIndex = queueFamilyIndex; - for (int i = 0; i < kSemaphoreCount; i++) - { - VkSemaphoreCreateInfo semaphoreCreateInfo = {}; - semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - semaphoreCreateInfo.flags = 0; - m_renderer->m_api.vkCreateSemaphore( - m_renderer->m_api.m_device, &semaphoreCreateInfo, nullptr, &m_semaphores[i]); - } + VkSemaphoreCreateInfo semaphoreCreateInfo = {}; + semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semaphoreCreateInfo.flags = 0; + m_renderer->m_api.vkCreateSemaphore( + m_renderer->m_api.m_device, &semaphoreCreateInfo, nullptr, &m_semaphore); } - virtual SLANG_NO_THROW void SLANG_MCALL wait() override + virtual SLANG_NO_THROW void SLANG_MCALL waitOnHost() override { auto& vkAPI = m_renderer->m_api; vkAPI.vkQueueWaitIdle(m_queue); @@ -4868,15 +4952,25 @@ public: return m_desc; } - virtual SLANG_NO_THROW void SLANG_MCALL executeCommandBuffers( - uint32_t count, ICommandBuffer* const* commandBuffers, IFence* fence, uint64_t valueToSignal) override + virtual SLANG_NO_THROW Result SLANG_MCALL + waitForFences(uint32_t fenceCount, IFence** fences, uint64_t* waitValues) override { - // TODO: implement fence signaling. - assert(fence == nullptr); - - if (count == 0) - return; + for (uint32_t i = 0; i < fenceCount; ++i) + { + FenceWaitInfo waitInfo; + waitInfo.fence = static_cast(fences[i]); + waitInfo.waitValue = waitValues[i]; + m_pendingWaitFences.add(waitInfo); + } + return SLANG_OK; + } + void queueSubmitImpl( + uint32_t count, + ICommandBuffer* const* commandBuffers, + IFence* fence, + uint64_t valueToSignal) + { auto& vkAPI = m_renderer->m_api; m_submitCommandBuffers.clear(); for (uint32_t i = 0; i < count; i++) @@ -4887,7 +4981,11 @@ public: auto vkCmdBuf = cmdBufImpl->m_commandBuffer; m_submitCommandBuffers.add(vkCmdBuf); } - VkSemaphore signalSemaphore = m_semaphores[m_currentSemaphoreIndex]; + Array signalSemaphores; + Array signalValues; + signalSemaphores.add(m_semaphore); + signalValues.add(0); + VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; VkPipelineStageFlags stageFlag[] = { @@ -4895,32 +4993,58 @@ public: submitInfo.pWaitDstStageMask = stageFlag; submitInfo.commandBufferCount = (uint32_t)m_submitCommandBuffers.getCount(); submitInfo.pCommandBuffers = m_submitCommandBuffers.getBuffer(); - Array waitSemaphores; + Array waitSemaphores; + Array waitValues; for (auto s : m_pendingWaitSemaphores) { if (s != VK_NULL_HANDLE) { waitSemaphores.add(s); + waitValues.add(0); } } + for (auto& fenceWait : m_pendingWaitFences) + { + waitSemaphores.add(fenceWait.fence->m_semaphore); + waitValues.add(fenceWait.waitValue); + } + m_pendingWaitFences.clear(); + VkTimelineSemaphoreSubmitInfo timelineSubmitInfo = { + VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO}; + if (fence) + { + auto fenceImpl = static_cast(fence); + signalSemaphores.add(fenceImpl->m_semaphore); + signalValues.add(valueToSignal); + submitInfo.pNext = &timelineSubmitInfo; + timelineSubmitInfo.signalSemaphoreValueCount = (uint32_t)signalValues.getCount(); + timelineSubmitInfo.pSignalSemaphoreValues = signalValues.getBuffer(); + timelineSubmitInfo.waitSemaphoreValueCount = (uint32_t)waitValues.getCount(); + timelineSubmitInfo.pWaitSemaphoreValues = waitValues.getBuffer(); + } submitInfo.waitSemaphoreCount = (uint32_t)waitSemaphores.getCount(); if (submitInfo.waitSemaphoreCount) { submitInfo.pWaitSemaphores = waitSemaphores.getBuffer(); } - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &signalSemaphore; + submitInfo.signalSemaphoreCount = (uint32_t)signalSemaphores.getCount(); + submitInfo.pSignalSemaphores = signalSemaphores.getBuffer(); auto commandBufferImpl = static_cast(commandBuffers[0]); auto vkFence = commandBufferImpl->m_transientHeap->getCurrentFence(); vkAPI.vkResetFences(vkAPI.m_device, 1, &vkFence); vkAPI.vkQueueSubmit(m_queue, 1, &submitInfo, vkFence); - m_pendingWaitSemaphores[0] = signalSemaphore; + m_pendingWaitSemaphores[0] = m_semaphore; m_pendingWaitSemaphores[1] = VK_NULL_HANDLE; commandBufferImpl->m_transientHeap->advanceFence(); + } - m_currentSemaphoreIndex++; - m_currentSemaphoreIndex = m_currentSemaphoreIndex % kSemaphoreCount; + virtual SLANG_NO_THROW void SLANG_MCALL executeCommandBuffers( + uint32_t count, ICommandBuffer* const* commandBuffers, IFence* fence, uint64_t valueToSignal) override + { + if (count == 0 && fence == nullptr) + return; + queueSubmitImpl(count, commandBuffers, fence, valueToSignal); } }; @@ -5348,6 +5472,13 @@ public: } virtual SLANG_NO_THROW Result SLANG_MCALL present() override { + // If there are pending fence wait operations, flush them as an + // empty vkQueueSubmit. + if (m_queue->m_pendingWaitFences.getCount() != 0) + { + m_queue->queueSubmitImpl(0, nullptr, nullptr, 0); + } + uint32_t swapChainIndices[] = {uint32_t(m_currentImageIndex)}; VkPresentInfoKHR presentInfo = {}; @@ -7802,4 +7933,34 @@ Result VKDevice::createQueryPool( return SLANG_OK; } +Result VKDevice::createFence(const IFence::Desc& desc, IFence** outFence) +{ + RefPtr fence = new FenceImpl(this); + SLANG_RETURN_ON_FAIL(fence->init(desc)); + returnComPtr(outFence, fence); + return SLANG_OK; +} + +Result VKDevice::waitForFences( + uint32_t fenceCount, IFence** fences, uint64_t* fenceValues, bool waitForAll, uint64_t timeout) +{ + ShortList semaphores; + for (uint32_t i = 0; i < fenceCount; ++i) + { + auto fenceImpl = static_cast(fences[i]); + semaphores.add(fenceImpl->m_semaphore); + } + VkSemaphoreWaitInfo waitInfo; + waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; + waitInfo.pNext = NULL; + waitInfo.flags = 0; + waitInfo.semaphoreCount = 1; + waitInfo.pSemaphores = semaphores.getArrayView().getBuffer(); + waitInfo.pValues = fenceValues; + auto result = m_api.vkWaitSemaphores(m_api.m_device, &waitInfo, timeout); + if (result == VK_TIMEOUT) + return SLANG_E_TIME_OUT; + return result == VK_SUCCESS ? SLANG_OK : SLANG_FAIL; +} + } // renderer_test diff --git a/tools/gfx/vulkan/vk-api.cpp b/tools/gfx/vulkan/vk-api.cpp index 7e1a9bae2..8f5e4235b 100644 --- a/tools/gfx/vulkan/vk-api.cpp +++ b/tools/gfx/vulkan/vk-api.cpp @@ -91,7 +91,10 @@ Slang::Result VulkanApi::initDeviceProcs(VkDevice device) vkGetBufferDeviceAddressKHR = vkGetBufferDeviceAddressEXT; if (!vkGetBufferDeviceAddress && vkGetBufferDeviceAddressKHR) vkGetBufferDeviceAddress = vkGetBufferDeviceAddressKHR; - + if (!vkGetSemaphoreCounterValue && vkGetSemaphoreCounterValueKHR) + vkGetSemaphoreCounterValue = vkGetSemaphoreCounterValueKHR; + if (!vkSignalSemaphore && vkSignalSemaphoreKHR) + vkSignalSemaphore = vkSignalSemaphoreKHR; m_device = device; return SLANG_OK; } diff --git a/tools/gfx/vulkan/vk-api.h b/tools/gfx/vulkan/vk-api.h index 543ad90d1..6e7024752 100644 --- a/tools/gfx/vulkan/vk-api.h +++ b/tools/gfx/vulkan/vk-api.h @@ -179,6 +179,12 @@ namespace gfx { x(vkCreateAccelerationStructureKHR) \ x(vkDestroyAccelerationStructureKHR) \ x(vkGetAccelerationStructureBuildSizesKHR) \ + x(vkGetSemaphoreCounterValue) \ + x(vkGetSemaphoreCounterValueKHR) \ + x(vkSignalSemaphore) \ + x(vkSignalSemaphoreKHR) \ + x(vkWaitSemaphores) \ + x(vkWaitSemaphoresKHR) \ /* */ #define VK_API_ALL_GLOBAL_PROCS(x) \ diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp index 96d0e4047..78fa149e8 100644 --- a/tools/render-test/render-test-main.cpp +++ b/tools/render-test/render-test-main.cpp @@ -751,7 +751,7 @@ void RenderTestApp::_initializeAccelerationStructure() encoder->endEncoding(); commandBuffer->close(); m_queue->executeCommandBuffer(commandBuffer); - m_queue->wait(); + m_queue->waitOnHost(); uint64_t compactedSize = 0; compactedSizeQuery->getResult(0, 1, &compactedSize); @@ -774,7 +774,7 @@ void RenderTestApp::_initializeAccelerationStructure() encoder->endEncoding(); commandBuffer->close(); m_queue->executeCommandBuffer(commandBuffer); - m_queue->wait(); + m_queue->waitOnHost(); } // Build top level acceleration structure. @@ -840,7 +840,7 @@ void RenderTestApp::_initializeAccelerationStructure() encoder->endEncoding(); commandBuffer->close(); m_queue->executeCommandBuffer(commandBuffer); - m_queue->wait(); + m_queue->waitOnHost(); } } @@ -883,7 +883,7 @@ void RenderTestApp::finalize() Result RenderTestApp::writeBindingOutput(const String& fileName) { // Wait until everything is complete - m_queue->wait(); + m_queue->waitOnHost(); FILE * f = fopen(fileName.getBuffer(), "wb"); if (!f) @@ -993,7 +993,7 @@ Result RenderTestApp::update() m_startTicks = Process::getClockTick(); m_queue->executeCommandBuffer(commandBuffer); - m_queue->wait(); + m_queue->waitOnHost(); // If we are in a mode where output is requested, we need to snapshot the back buffer here if (m_options.outputPath.getLength() || m_options.performanceProfile) -- cgit v1.2.3