summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsTools
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2019-04-16 04:42:28 +0000
committerEgor Yusov <egor.yusov@gmail.com>2019-04-16 04:42:28 +0000
commita08fc052ea6190738cb1408644b51d7de760eee1 (patch)
treed387bf07c4219de9137330bde5ce7c2041db0e02 /Graphics/GraphicsTools
parentFixed issue with FenceVkImpl not waiting for Vulkan fences to signal when bei... (diff)
downloadDiligentCore-a08fc052ea6190738cb1408644b51d7de760eee1.tar.gz
DiligentCore-a08fc052ea6190738cb1408644b51d7de760eee1.zip
Reworked TextureUploaderD3D12 to work in D3D12 and Vulkan modes
Diffstat (limited to 'Graphics/GraphicsTools')
-rw-r--r--Graphics/GraphicsTools/CMakeLists.txt7
-rw-r--r--Graphics/GraphicsTools/include/TextureUploaderD3D11.h17
-rw-r--r--Graphics/GraphicsTools/include/TextureUploaderD3D12_Vk.h (renamed from Graphics/GraphicsTools/include/TextureUploaderD3D12.h)21
-rw-r--r--Graphics/GraphicsTools/include/TextureUploaderGL.h17
-rw-r--r--Graphics/GraphicsTools/src/TextureUploader.cpp5
-rw-r--r--Graphics/GraphicsTools/src/TextureUploaderD3D12.cpp284
-rw-r--r--Graphics/GraphicsTools/src/TextureUploaderD3D12_Vk.cpp368
7 files changed, 412 insertions, 307 deletions
diff --git a/Graphics/GraphicsTools/CMakeLists.txt b/Graphics/GraphicsTools/CMakeLists.txt
index 05061415..f2908cb0 100644
--- a/Graphics/GraphicsTools/CMakeLists.txt
+++ b/Graphics/GraphicsTools/CMakeLists.txt
@@ -27,10 +27,9 @@ if(D3D11_SUPPORTED)
list(APPEND DEPENDENCIES GraphicsEngineD3D11Interface)
endif()
-if(D3D12_SUPPORTED)
- list(APPEND SOURCE src/TextureUploaderD3D12.cpp)
- list(APPEND INCLUDE include/TextureUploaderD3D12.h)
- list(APPEND DEPENDENCIES GraphicsEngineD3D12Interface)
+if(D3D12_SUPPORTED OR VULKAN_SUPPORTED)
+ list(APPEND SOURCE src/TextureUploaderD3D12_Vk.cpp)
+ list(APPEND INCLUDE include/TextureUploaderD3D12_Vk.h)
endif()
if(GL_SUPPORTED OR GLES_SUPPORTED)
diff --git a/Graphics/GraphicsTools/include/TextureUploaderD3D11.h b/Graphics/GraphicsTools/include/TextureUploaderD3D11.h
index dc14fd75..f6cec59d 100644
--- a/Graphics/GraphicsTools/include/TextureUploaderD3D11.h
+++ b/Graphics/GraphicsTools/include/TextureUploaderD3D11.h
@@ -30,13 +30,20 @@ namespace Diligent
class TextureUploaderD3D11 : public TextureUploaderBase
{
public:
- TextureUploaderD3D11(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc);
+ TextureUploaderD3D11(IReferenceCounters* pRefCounters,
+ IRenderDevice* pDevice,
+ const TextureUploaderDesc Desc);
~TextureUploaderD3D11();
- virtual void RenderThreadUpdate(IDeviceContext *pContext)override final;
+ virtual void RenderThreadUpdate(IDeviceContext* pContext)override final;
- virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer)override final;
- virtual void ScheduleGPUCopy(ITexture *pDstTexture, Uint32 ArraySlice, Uint32 MipLevel, IUploadBuffer *pUploadBuffer)override final;
- virtual void RecycleBuffer(IUploadBuffer *pUploadBuffer)override final;
+ virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc,
+ bool IsRenderThread,
+ IUploadBuffer** ppBuffer)override final;
+ virtual void ScheduleGPUCopy(ITexture* pDstTexture,
+ Uint32 ArraySlice,
+ Uint32 MipLevel,
+ IUploadBuffer* pUploadBuffer)override final;
+ virtual void RecycleBuffer(IUploadBuffer* pUploadBuffer)override final;
private:
struct InternalData;
diff --git a/Graphics/GraphicsTools/include/TextureUploaderD3D12.h b/Graphics/GraphicsTools/include/TextureUploaderD3D12_Vk.h
index c2ca81e5..585d0f37 100644
--- a/Graphics/GraphicsTools/include/TextureUploaderD3D12.h
+++ b/Graphics/GraphicsTools/include/TextureUploaderD3D12_Vk.h
@@ -27,16 +27,23 @@
namespace Diligent
{
- class TextureUploaderD3D12 : public TextureUploaderBase
+ class TextureUploaderD3D12_Vk : public TextureUploaderBase
{
public:
- TextureUploaderD3D12(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc);
- ~TextureUploaderD3D12();
- virtual void RenderThreadUpdate(IDeviceContext *pContext)override final;
+ TextureUploaderD3D12_Vk(IReferenceCounters* pRefCounters,
+ IRenderDevice* pDevice,
+ const TextureUploaderDesc Desc);
+ ~TextureUploaderD3D12_Vk();
+ virtual void RenderThreadUpdate(IDeviceContext* pContext)override final;
- virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer)override final;
- virtual void ScheduleGPUCopy(ITexture *pDstTexture, Uint32 ArraySlice, Uint32 MipLevel, IUploadBuffer *pUploadBuffer)override final;
- virtual void RecycleBuffer(IUploadBuffer *pUploadBuffer)override final;
+ virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc,
+ bool IsRenderThread,
+ IUploadBuffer** ppBuffer)override final;
+ virtual void ScheduleGPUCopy(ITexture* pDstTexture,
+ Uint32 ArraySlice,
+ Uint32 MipLevel,
+ IUploadBuffer* pUploadBuffer)override final;
+ virtual void RecycleBuffer(IUploadBuffer* pUploadBuffer)override final;
private:
struct InternalData;
diff --git a/Graphics/GraphicsTools/include/TextureUploaderGL.h b/Graphics/GraphicsTools/include/TextureUploaderGL.h
index d186b20c..fd9d77e4 100644
--- a/Graphics/GraphicsTools/include/TextureUploaderGL.h
+++ b/Graphics/GraphicsTools/include/TextureUploaderGL.h
@@ -30,13 +30,20 @@ namespace Diligent
class TextureUploaderGL : public TextureUploaderBase
{
public:
- TextureUploaderGL(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc);
+ TextureUploaderGL(IReferenceCounters* pRefCounters,
+ IRenderDevice* pDevice,
+ const TextureUploaderDesc Desc);
~TextureUploaderGL();
- virtual void RenderThreadUpdate(IDeviceContext *pContext)override final;
+ virtual void RenderThreadUpdate(IDeviceContext* pContext)override final;
- virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer)override final;
- virtual void ScheduleGPUCopy(ITexture *pDstTexture, Uint32 ArraySlice, Uint32 MipLevel, IUploadBuffer *pUploadBuffer)override final;
- virtual void RecycleBuffer(IUploadBuffer *pUploadBuffer)override final;
+ virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc,
+ bool IsRenderThread,
+ IUploadBuffer** ppBuffer)override final;
+ virtual void ScheduleGPUCopy(ITexture* pDstTexture,
+ Uint32 ArraySlice,
+ Uint32 MipLevel,
+ IUploadBuffer* pUploadBuffer)override final;
+ virtual void RecycleBuffer(IUploadBuffer* pUploadBuffer)override final;
private:
struct InternalData;
diff --git a/Graphics/GraphicsTools/src/TextureUploader.cpp b/Graphics/GraphicsTools/src/TextureUploader.cpp
index 46b96cff..ed355677 100644
--- a/Graphics/GraphicsTools/src/TextureUploader.cpp
+++ b/Graphics/GraphicsTools/src/TextureUploader.cpp
@@ -23,7 +23,7 @@
#include "pch.h"
#include "TextureUploaderD3D11.h"
-#include "TextureUploaderD3D12.h"
+#include "TextureUploaderD3D12_Vk.h"
#include "TextureUploaderGL.h"
namespace Diligent
@@ -38,7 +38,8 @@ namespace Diligent
break;
case DeviceType::D3D12:
- *ppUploader = MakeNewRCObj<TextureUploaderD3D12>()( pDevice, Desc );
+ case DeviceType::Vulkan:
+ *ppUploader = MakeNewRCObj<TextureUploaderD3D12_Vk>()( pDevice, Desc );
break;
case DeviceType::OpenGLES:
diff --git a/Graphics/GraphicsTools/src/TextureUploaderD3D12.cpp b/Graphics/GraphicsTools/src/TextureUploaderD3D12.cpp
deleted file mode 100644
index 71f612cb..00000000
--- a/Graphics/GraphicsTools/src/TextureUploaderD3D12.cpp
+++ /dev/null
@@ -1,284 +0,0 @@
-/* Copyright 2015-2019 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#include "pch.h"
-
-#include <atlbase.h>
-#include <mutex>
-#include <unordered_map>
-#include <deque>
-#include <vector>
-#include <d3d12.h>
-
-#include "TextureUploaderD3D12.h"
-#include "RenderDeviceD3D12.h"
-#include "BufferD3D12.h"
-#include "TextureD3D12.h"
-#include "ThreadSignal.h"
-
-namespace Diligent
-{
-
- class UploadBufferD3D12 : public UploadBufferBase
- {
- public:
- UploadBufferD3D12(IReferenceCounters *pRefCounters,
- IRenderDeviceD3D12 *pRenderDeviceD3D12,
- const UploadBufferDesc &Desc,
- IBuffer *pStagingBuffer,
- void *pData,
- size_t RowStride,
- size_t DepthStride) :
- UploadBufferBase(pRefCounters, Desc),
- m_pDeviceD3D12(pRenderDeviceD3D12),
- m_pStagingBuffer(pStagingBuffer)
- {
- m_pData = pData;
- m_RowStride = RowStride;
- m_DepthStride = DepthStride;
- }
-
- ~UploadBufferD3D12()
- {
- RefCntAutoPtr<IBufferD3D12> pBufferD3D12(m_pStagingBuffer, IID_BufferD3D12);
- size_t DataStartOffset;
- auto* pd3d12Buff = pBufferD3D12->GetD3D12Buffer(DataStartOffset, nullptr);
- pd3d12Buff->Unmap(0, nullptr);
- LOG_INFO_MESSAGE("Releasing staging buffer of size ", m_pStagingBuffer->GetDesc().uiSizeInBytes);
- }
-
- void SignalCopyScheduled()
- {
- m_CopyScheduledSignal.Trigger();
- }
-
- void Reset()
- {
- m_CopyScheduledSignal.Reset();
- }
-
- virtual void WaitForCopyScheduled()override final
- {
- m_CopyScheduledSignal.Wait();
- }
-
- IBuffer* GetStagingBuffer() { return m_pStagingBuffer; }
-
- bool DbgIsCopyScheduled()const { return m_CopyScheduledSignal.IsTriggered(); }
- private:
-
- ThreadingTools::Signal m_CopyScheduledSignal;
-
- RefCntAutoPtr<IBuffer> m_pStagingBuffer;
- RefCntAutoPtr<IRenderDeviceD3D12> m_pDeviceD3D12;
- };
-
- struct TextureUploaderD3D12::InternalData
- {
- InternalData(IRenderDevice *pDevice) :
- m_pDeviceD3D12(pDevice, IID_RenderDeviceD3D12)
- {
- m_pd3d12NativeDevice = m_pDeviceD3D12->GetD3D12Device();
- }
-
- CComPtr<ID3D12Device> m_pd3d12NativeDevice;
- RefCntAutoPtr<IRenderDeviceD3D12> m_pDeviceD3D12;
-
- void SwapMapQueues()
- {
- std::lock_guard<std::mutex> QueueLock(m_PendingOperationsMtx);
- m_PendingOperations.swap(m_InWorkOperations);
- }
-
- void EnqueCopy(UploadBufferD3D12 *pUploadBuffer, ITextureD3D12 *pDstTex, Uint32 dstSlice, Uint32 dstMip)
- {
- std::lock_guard<std::mutex> QueueLock(m_PendingOperationsMtx);
- m_PendingOperations.emplace_back(PendingBufferOperation::Operation::Copy, pUploadBuffer, pDstTex, dstSlice, dstMip);
- }
-
- std::mutex m_PendingOperationsMtx;
- struct PendingBufferOperation
- {
- enum Operation
- {
- Copy
- }operation;
- RefCntAutoPtr<UploadBufferD3D12> pUploadBuffer;
- RefCntAutoPtr<ITextureD3D12> pDstTexture;
- Uint32 DstSlice = 0;
- Uint32 DstMip = 0;
-
- PendingBufferOperation(Operation op, UploadBufferD3D12* pBuff) :
- operation(op),
- pUploadBuffer(pBuff)
- {}
- PendingBufferOperation(Operation op, UploadBufferD3D12* pBuff, ITextureD3D12 *pDstTex, Uint32 dstSlice, Uint32 dstMip) :
- operation(op),
- pUploadBuffer(pBuff),
- pDstTexture(pDstTex),
- DstSlice(dstSlice),
- DstMip(dstMip)
- {}
- };
- std::vector< PendingBufferOperation > m_PendingOperations;
- std::vector< PendingBufferOperation > m_InWorkOperations;
-
- std::mutex m_UploadBuffCacheMtx;
- std::unordered_map< UploadBufferDesc, std::deque< std::pair<Uint64, RefCntAutoPtr<UploadBufferD3D12> > > > m_UploadBufferCache;
- };
-
- TextureUploaderD3D12::TextureUploaderD3D12(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc) :
- TextureUploaderBase(pRefCounters, pDevice, Desc),
- m_pInternalData(new InternalData(pDevice))
- {
- }
-
- TextureUploaderD3D12::~TextureUploaderD3D12()
- {
- for (auto BuffQueueIt : m_pInternalData->m_UploadBufferCache)
- {
- if (BuffQueueIt.second.size())
- {
- const auto &desc = BuffQueueIt.first;
- auto &FmtInfo = m_pDevice->GetTextureFormatInfo(desc.Format);
- LOG_INFO_MESSAGE("TextureUploaderD3D12: releasing ", BuffQueueIt.second.size(), ' ', desc.Width, 'x', desc.Height, 'x', desc.Depth, ' ', FmtInfo.Name, " upload buffer(s) ");
- }
- }
- }
-
- void TextureUploaderD3D12::RenderThreadUpdate(IDeviceContext *pContext)
- {
- m_pInternalData->SwapMapQueues();
- if (!m_pInternalData->m_InWorkOperations.empty())
- {
- for (auto &OperationInfo : m_pInternalData->m_InWorkOperations)
- {
- auto &pBuffer = OperationInfo.pUploadBuffer;
-
- switch (OperationInfo.operation)
- {
- case InternalData::PendingBufferOperation::Copy:
- {
- TextureSubResData SubResData(pBuffer->GetStagingBuffer(), 0, static_cast<Uint32>(pBuffer->GetRowStride()));
- const auto &TexDesc = OperationInfo.pDstTexture->GetDesc();
- Box DstBox;
- DstBox.MaxX = TexDesc.Width;
- DstBox.MaxY = TexDesc.Height;
- // UpdateTexture() transitions dst subresource to COPY_DEST state and then transitions back to original state
- pContext->UpdateTexture(OperationInfo.pDstTexture, OperationInfo.DstMip, OperationInfo.DstSlice, DstBox,
- SubResData, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
- pBuffer->SignalCopyScheduled();
- }
- break;
- }
- }
-
- m_pInternalData->m_InWorkOperations.clear();
- }
- }
-
- void TextureUploaderD3D12::AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer)
- {
- *ppBuffer = nullptr;
-
- {
- std::lock_guard<std::mutex> CacheLock(m_pInternalData->m_UploadBuffCacheMtx);
- auto &Cache = m_pInternalData->m_UploadBufferCache;
- if (!Cache.empty())
- {
- auto DequeIt = Cache.find(Desc);
- if (DequeIt != Cache.end())
- {
- auto &Deque = DequeIt->second;
- if (!Deque.empty())
- {
- auto &FrontBuff = Deque.front();
- if (m_pInternalData->m_pDeviceD3D12->IsFenceSignaled(0, FrontBuff.first))
- {
- *ppBuffer = FrontBuff.second.Detach();
- Deque.pop_front();
- }
- }
- }
- }
- }
-
- // No available buffer found in the cache
- if(*ppBuffer == nullptr)
- {
- BufferDesc BuffDesc;
- BuffDesc.Name = "Staging buffer for UploadBufferD3D12";
- BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
- BuffDesc.Usage = USAGE_STAGING;
-
- const auto &TexFmtInfo = m_pDevice->GetTextureFormatInfo(Desc.Format);
- Uint32 RowStride = Desc.Width * Uint32{TexFmtInfo.ComponentSize} * Uint32{TexFmtInfo.NumComponents};
- static_assert((D3D12_TEXTURE_DATA_PITCH_ALIGNMENT & (D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1)) == 0, "Alginment is expected to be power of 2");
- Uint32 AlignmentMask = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT-1;
- RowStride = (RowStride + AlignmentMask) & (~AlignmentMask);
-
- BuffDesc.uiSizeInBytes = Desc.Height * RowStride;
- RefCntAutoPtr<IBuffer> pStagingBuffer;
- m_pDevice->CreateBuffer(BuffDesc, nullptr, &pStagingBuffer);
-
- PVoid CpuVirtualAddress = nullptr;
- RefCntAutoPtr<IBufferD3D12> pStagingBufferD3D12(pStagingBuffer, IID_BufferD3D12);
- size_t DataStartOffset;
- auto* pd3d12Buff = pStagingBufferD3D12->GetD3D12Buffer(DataStartOffset, nullptr);
- pd3d12Buff->Map(0, nullptr, &CpuVirtualAddress);
- if (CpuVirtualAddress == nullptr)
- {
- LOG_ERROR_MESSAGE("Failed to map upload buffer");
- return;
- }
-
- LOG_INFO_MESSAGE("Created staging buffer of size ", BuffDesc.uiSizeInBytes);
-
- RefCntAutoPtr<UploadBufferD3D12> pUploadBuffer(MakeNewRCObj<UploadBufferD3D12>()(m_pInternalData->m_pDeviceD3D12, Desc, pStagingBuffer, CpuVirtualAddress, RowStride, 0));
- *ppBuffer = pUploadBuffer.Detach();
- }
- }
-
- void TextureUploaderD3D12::ScheduleGPUCopy(ITexture *pDstTexture,
- Uint32 ArraySlice,
- Uint32 MipLevel,
- IUploadBuffer *pUploadBuffer)
- {
- auto *pUploadBufferD3D12 = ValidatedCast<UploadBufferD3D12>(pUploadBuffer);
- RefCntAutoPtr<ITextureD3D12> pDstTexD3D12(pDstTexture, IID_TextureD3D12);
- m_pInternalData->EnqueCopy(pUploadBufferD3D12, pDstTexD3D12, ArraySlice, MipLevel);
- }
-
- void TextureUploaderD3D12::RecycleBuffer(IUploadBuffer *pUploadBuffer)
- {
- auto *pUploadBufferD3D12 = ValidatedCast<UploadBufferD3D12>(pUploadBuffer);
- VERIFY(pUploadBufferD3D12->DbgIsCopyScheduled(), "Upload buffer must be recycled only after copy operation has been scheduled on the GPU");
- pUploadBufferD3D12->Reset();
-
- std::lock_guard<std::mutex> CacheLock(m_pInternalData->m_UploadBuffCacheMtx);
- auto &Cache = m_pInternalData->m_UploadBufferCache;
- auto &Deque = Cache[pUploadBufferD3D12->GetDesc()];
- Uint64 FenceValue = m_pInternalData->m_pDeviceD3D12->GetNextFenceValue(0);
- Deque.emplace_back( FenceValue, pUploadBufferD3D12 );
- }
-}
diff --git a/Graphics/GraphicsTools/src/TextureUploaderD3D12_Vk.cpp b/Graphics/GraphicsTools/src/TextureUploaderD3D12_Vk.cpp
new file mode 100644
index 00000000..b3e843b7
--- /dev/null
+++ b/Graphics/GraphicsTools/src/TextureUploaderD3D12_Vk.cpp
@@ -0,0 +1,368 @@
+/* Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+
+#include <atlbase.h>
+#include <mutex>
+#include <unordered_map>
+#include <deque>
+#include <vector>
+
+#include "TextureUploaderD3D12_Vk.h"
+#include "ThreadSignal.h"
+#include "GraphicsAccessories.h"
+
+namespace Diligent
+{
+
+namespace
+{
+
+class UploadTexture : public UploadBufferBase
+{
+public:
+ UploadTexture(IReferenceCounters* pRefCounters,
+ const UploadBufferDesc& Desc,
+ ITexture* pStagingTexture) :
+ UploadBufferBase (pRefCounters, Desc),
+ m_pStagingTexture (pStagingTexture)
+ {
+ }
+
+ ~UploadTexture()
+ {
+ DEV_CHECK_ERR(m_pData == nullptr, "Releasing mapped staging texture");
+ }
+
+ void WaitForMap()
+ {
+ m_TextureMappedSignal.Wait();
+ }
+
+ void SignalMapped()
+ {
+ m_TextureMappedSignal.Trigger();
+ }
+
+ void SignalCopyScheduled(Uint64 FenceValue)
+ {
+ m_CopyScheduledFenceValue = FenceValue;
+ m_CopyScheduledSignal.Trigger();
+ }
+
+ void Unmap(IDeviceContext* pDeviceContext)
+ {
+ pDeviceContext->UnmapTextureSubresource(m_pStagingTexture, 0, 0);
+ m_pData = nullptr;
+ m_RowStride = 0;
+ m_DepthStride = 0;
+ }
+
+ void Map(IDeviceContext* pDeviceContext)
+ {
+ VERIFY(m_pData == nullptr, "Staging texture is already mapped");
+ MappedTextureSubresource MappedData;
+ pDeviceContext->MapTextureSubresource(m_pStagingTexture, 0, 0, MAP_WRITE, MAP_FLAG_DO_NOT_SYNCHRONIZE, nullptr, MappedData);
+ m_pData = MappedData.pData;
+ m_RowStride = MappedData.Stride;
+ m_DepthStride = MappedData.DepthStride;
+ }
+
+ void Reset()
+ {
+ m_CopyScheduledSignal.Reset();
+ m_TextureMappedSignal.Reset();
+ m_CopyScheduledFenceValue = 0;
+ }
+
+ virtual void WaitForCopyScheduled()override final
+ {
+ m_CopyScheduledSignal.Wait();
+ }
+
+ ITexture* GetStagingTexture() { return m_pStagingTexture; }
+
+ bool DbgIsCopyScheduled()const
+ {
+ return m_CopyScheduledSignal.IsTriggered();
+ }
+
+ bool DbgIsMapped()
+ {
+ return m_TextureMappedSignal.IsTriggered();
+ }
+
+ Uint64 GetCopyScheduledFenceValue()const
+ {
+ VERIFY(m_CopyScheduledFenceValue != 0, "Fence value has not been initialized");
+ return m_CopyScheduledFenceValue;
+ }
+
+private:
+ ThreadingTools::Signal m_CopyScheduledSignal;
+ ThreadingTools::Signal m_TextureMappedSignal;
+
+ RefCntAutoPtr<ITexture> m_pStagingTexture;
+ Uint64 m_CopyScheduledFenceValue = 0;
+};
+
+} // namespace
+
+
+struct TextureUploaderD3D12_Vk::InternalData
+{
+ struct PendingBufferOperation
+ {
+ enum Operation
+ {
+ Copy,
+ Map
+ }operation;
+ RefCntAutoPtr<UploadTexture> pUploadTexture;
+ RefCntAutoPtr<ITexture> pDstTexture;
+ Uint32 DstSlice = 0;
+ Uint32 DstMip = 0;
+
+ PendingBufferOperation(Operation op, UploadTexture* pUploadTex) :
+ operation (op),
+ pUploadTexture(pUploadTex)
+ {}
+ PendingBufferOperation(Operation op, UploadTexture* pUploadTex, ITexture* pDstTex, Uint32 dstSlice, Uint32 dstMip) :
+ operation (op),
+ pUploadTexture (pUploadTex),
+ pDstTexture (pDstTex),
+ DstSlice (dstSlice),
+ DstMip (dstMip)
+ {}
+ };
+
+ InternalData(IRenderDevice* pDevice)
+ {
+ FenceDesc fenceDesc;
+ fenceDesc.Name = "Texture uploader sync fence";
+ pDevice->CreateFence(fenceDesc, &m_pFence);
+ }
+
+ ~InternalData()
+ {
+ for (auto it : m_UploadTexturesCache)
+ {
+ if (it.second.size())
+ {
+ const auto& desc = it.first;
+ auto& FmtInfo = GetTextureFormatAttribs(desc.Format);
+ LOG_INFO_MESSAGE("TextureUploaderD3D12_Vk: releasing ", it.second.size(), ' ', desc.Width, 'x', desc.Height, 'x', desc.Depth, ' ', FmtInfo.Name, " upload buffer(s) ");
+ }
+ }
+ }
+
+ std::vector<PendingBufferOperation>& SwapMapQueues()
+ {
+ std::lock_guard<std::mutex> QueueLock(m_PendingOperationsMtx);
+ m_PendingOperations.swap(m_InWorkOperations);
+ return m_InWorkOperations;
+ }
+
+ void EnqueCopy(UploadTexture* pUploadBuffer, ITexture* pDstTex, Uint32 dstSlice, Uint32 dstMip)
+ {
+ std::lock_guard<std::mutex> QueueLock(m_PendingOperationsMtx);
+ m_PendingOperations.emplace_back(PendingBufferOperation::Operation::Copy, pUploadBuffer, pDstTex, dstSlice, dstMip);
+ }
+
+ void EnqueMap(UploadTexture* pUploadBuffer)
+ {
+ std::lock_guard<std::mutex> QueueLock(m_PendingOperationsMtx);
+ m_PendingOperations.emplace_back(PendingBufferOperation::Operation::Map, pUploadBuffer);
+ }
+
+ Uint64 SignalFence(IDeviceContext* pContext)
+ {
+ // Fences can't be accessed from multiple threads simultaneously even
+ // when protected by mutex
+ auto FenceValue = m_NextFenceValue++;
+ pContext->SignalFence(m_pFence, FenceValue);
+ return FenceValue;
+ }
+
+ void UpdatedCompletedFenceValue()
+ {
+ // Fences can't be accessed from multiple threads simultaneously even
+ // when protected by mutex
+ m_CompletedFenceValue = m_pFence->GetCompletedValue();
+ }
+
+ RefCntAutoPtr<UploadTexture> FindCachedUploadTexture(const UploadBufferDesc& Desc)
+ {
+ RefCntAutoPtr<UploadTexture> pUploadTexture;
+ std::lock_guard<std::mutex> CacheLock(m_UploadTexturesCacheMtx);
+ auto DequeIt = m_UploadTexturesCache.find(Desc);
+ if (DequeIt != m_UploadTexturesCache.end())
+ {
+ auto& Deque = DequeIt->second;
+ if (!Deque.empty())
+ {
+ auto& FrontBuff = Deque.front();
+ if (FrontBuff->GetCopyScheduledFenceValue() <= m_CompletedFenceValue)
+ {
+ pUploadTexture = std::move(FrontBuff);
+ Deque.pop_front();
+ pUploadTexture->Reset();
+ }
+ }
+ }
+
+ return pUploadTexture;
+ }
+
+ void RecycleUploadTexture(UploadTexture* pUploadTexture)
+ {
+ std::lock_guard<std::mutex> CacheLock(m_UploadTexturesCacheMtx);
+ auto& Deque = m_UploadTexturesCache[pUploadTexture->GetDesc()];
+ Deque.emplace_back(pUploadTexture);
+ }
+
+private:
+ std::mutex m_PendingOperationsMtx;
+ std::vector<PendingBufferOperation> m_PendingOperations;
+ std::vector<PendingBufferOperation> m_InWorkOperations;
+
+ std::mutex m_UploadTexturesCacheMtx;
+ std::unordered_map< UploadBufferDesc, std::deque< RefCntAutoPtr<UploadTexture> > > m_UploadTexturesCache;
+
+ RefCntAutoPtr<IFence> m_pFence;
+ Uint64 m_NextFenceValue = 1;
+ Uint64 m_CompletedFenceValue = 0;
+};
+
+TextureUploaderD3D12_Vk::TextureUploaderD3D12_Vk(IReferenceCounters* pRefCounters, IRenderDevice* pDevice, const TextureUploaderDesc Desc) :
+ TextureUploaderBase(pRefCounters, pDevice, Desc),
+ m_pInternalData(new InternalData(pDevice))
+{
+}
+
+TextureUploaderD3D12_Vk::~TextureUploaderD3D12_Vk()
+{
+}
+
+void TextureUploaderD3D12_Vk::RenderThreadUpdate(IDeviceContext* pContext)
+{
+ auto& InWorkOperations = m_pInternalData->SwapMapQueues();
+ if (!InWorkOperations.empty())
+ {
+ for (auto& OperationInfo : InWorkOperations)
+ {
+ auto& pUploadTex = OperationInfo.pUploadTexture;
+
+ switch (OperationInfo.operation)
+ {
+ case InternalData::PendingBufferOperation::Map:
+ {
+ pUploadTex->Map(pContext);
+ pUploadTex->SignalMapped();
+ }
+ break;
+
+ case InternalData::PendingBufferOperation::Copy:
+ {
+ VERIFY(pUploadTex->DbgIsMapped(), "Upload texture must be copied only after it has been mapped");
+ pUploadTex->Unmap(pContext);
+
+ CopyTextureAttribs CopyInfo
+ {
+ pUploadTex->GetStagingTexture(),
+ RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
+ OperationInfo.pDstTexture,
+ RESOURCE_STATE_TRANSITION_MODE_TRANSITION
+ };
+ CopyInfo.DstSlice = OperationInfo.DstSlice;
+ CopyInfo.DstMipLevel = OperationInfo.DstMip;
+ pContext->CopyTexture(CopyInfo);
+ }
+ break;
+ }
+ }
+
+ // The buffer may be recycled immediately after the copy scheduled is signaled,
+ // so we must signal the fence first.
+ auto SignaledFenceValue = m_pInternalData->SignalFence(pContext);
+
+ for (auto& OperationInfo : InWorkOperations)
+ {
+ if (OperationInfo.operation == InternalData::PendingBufferOperation::Copy)
+ OperationInfo.pUploadTexture->SignalCopyScheduled(SignaledFenceValue);
+ }
+
+ InWorkOperations.clear();
+ }
+
+ // This must be called by the same thread that signals the fence
+ m_pInternalData->UpdatedCompletedFenceValue();
+}
+
+void TextureUploaderD3D12_Vk::AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer** ppBuffer)
+{
+ RefCntAutoPtr<UploadTexture> pUploadTexture = m_pInternalData->FindCachedUploadTexture(Desc);
+
+ // No available buffer found in the cache
+ if (!pUploadTexture)
+ {
+ TextureDesc StagingTexDesc;
+ StagingTexDesc.Type = RESOURCE_DIM_TEX_2D;
+ StagingTexDesc.Width = Desc.Width;
+ StagingTexDesc.Height = Desc.Height;
+ StagingTexDesc.Format = Desc.Format;
+ StagingTexDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
+ StagingTexDesc.Usage = USAGE_STAGING;
+
+ RefCntAutoPtr<ITexture> pStagingTexture;
+ m_pDevice->CreateTexture(StagingTexDesc, nullptr, &pStagingTexture);
+
+ LOG_INFO_MESSAGE("Created ", Desc.Width, "x", Desc.Height, " ", GetTextureFormatAttribs(Desc.Format).Name, " staging texture");
+
+ pUploadTexture = MakeNewRCObj<UploadTexture>()(Desc, pStagingTexture);
+ }
+
+ m_pInternalData->EnqueMap(pUploadTexture);
+ pUploadTexture->WaitForMap();
+ *ppBuffer = pUploadTexture.Detach();
+}
+
+void TextureUploaderD3D12_Vk::ScheduleGPUCopy(ITexture* pDstTexture,
+ Uint32 ArraySlice,
+ Uint32 MipLevel,
+ IUploadBuffer* pUploadBuffer)
+{
+ auto* pUploadTexture = ValidatedCast<UploadTexture>(pUploadBuffer);
+ m_pInternalData->EnqueCopy(pUploadTexture, pDstTexture, ArraySlice, MipLevel);
+}
+
+void TextureUploaderD3D12_Vk::RecycleBuffer(IUploadBuffer* pUploadBuffer)
+{
+ auto* pUploadTexture = ValidatedCast<UploadTexture>(pUploadBuffer);
+ VERIFY(pUploadTexture->DbgIsCopyScheduled(), "Upload buffer must be recycled only after copy operation has been scheduled on the GPU");
+
+ m_pInternalData->RecycleUploadTexture(pUploadTexture);
+}
+
+} // namespace Diligent