From 27b1effc36ffd228123ded18401f7dc5c34b6f78 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Fri, 19 Apr 2019 08:25:42 -0700 Subject: Updated texture uploader to support multi-mip resources --- Graphics/GraphicsTools/include/TextureUploader.h | 14 +- .../GraphicsTools/include/TextureUploaderBase.h | 35 ++++- .../GraphicsTools/src/TextureUploaderD3D11.cpp | 145 +++++++++++++-------- .../GraphicsTools/src/TextureUploaderD3D12_Vk.cpp | 71 ++++++---- Graphics/GraphicsTools/src/TextureUploaderGL.cpp | 112 ++++++++++++---- 5 files changed, 256 insertions(+), 121 deletions(-) (limited to 'Graphics/GraphicsTools') diff --git a/Graphics/GraphicsTools/include/TextureUploader.h b/Graphics/GraphicsTools/include/TextureUploader.h index dbc4383f..059e32c6 100644 --- a/Graphics/GraphicsTools/include/TextureUploader.h +++ b/Graphics/GraphicsTools/include/TextureUploader.h @@ -30,10 +30,12 @@ namespace Diligent { struct UploadBufferDesc { - Uint32 Width = 0; - Uint32 Height = 0; - Uint32 Depth = 1; - TEXTURE_FORMAT Format = TEX_FORMAT_UNKNOWN; + Uint32 Width = 0; + Uint32 Height = 0; + Uint32 Depth = 1; + Uint32 MipLevels = 1; + Uint32 ArraySize = 1; + TEXTURE_FORMAT Format = TEX_FORMAT_UNKNOWN; bool operator == (const UploadBufferDesc &rhs) const { @@ -48,9 +50,7 @@ namespace Diligent { public: virtual void WaitForCopyScheduled() = 0; - virtual void* GetDataPtr() = 0; - virtual size_t GetRowStride() const = 0; - virtual size_t GetDepthStride()const = 0; + virtual MappedTextureSubresource GetMappedData(Uint32 Mip, Uint32 Slice) = 0; virtual const UploadBufferDesc& GetDesc()const = 0; }; diff --git a/Graphics/GraphicsTools/include/TextureUploaderBase.h b/Graphics/GraphicsTools/include/TextureUploaderBase.h index d1c460a1..5d3c489b 100644 --- a/Graphics/GraphicsTools/include/TextureUploaderBase.h +++ b/Graphics/GraphicsTools/include/TextureUploaderBase.h @@ -23,6 +23,8 @@ #pragma once +#include + #include "TextureUploader.h" #include "../../../Common/interface/ObjectBase.h" #include "../../../Common/interface/HashUtils.h" @@ -47,20 +49,39 @@ namespace Diligent public: UploadBufferBase(IReferenceCounters *pRefCounters, const UploadBufferDesc &Desc) : ObjectBase(pRefCounters), - m_Desc(Desc) + m_Desc(Desc), + m_MappedData(m_Desc.ArraySize * m_Desc.MipLevels) { } - virtual void* GetDataPtr() override final { return m_pData; } - virtual size_t GetRowStride() const override final{ return m_RowStride; } - virtual size_t GetDepthStride()const override final{ return m_DepthStride; } + virtual MappedTextureSubresource GetMappedData(Uint32 Mip, Uint32 Slice)override final + { + VERIFY_EXPR(Mip < m_Desc.MipLevels && Slice < m_Desc.ArraySize); + return m_MappedData[m_Desc.MipLevels * Slice + Mip]; + } virtual const UploadBufferDesc& GetDesc()const override final{ return m_Desc; } + void SetMappedData(Uint32 Mip, Uint32 Slice, const MappedTextureSubresource& MappedData) + { + VERIFY_EXPR(Mip < m_Desc.MipLevels && Slice < m_Desc.ArraySize); + m_MappedData[m_Desc.MipLevels * Slice + Mip] = MappedData; + } + + bool IsMapped(Uint32 Mip, Uint32 Slice)const + { + VERIFY_EXPR(Mip < m_Desc.MipLevels && Slice < m_Desc.ArraySize); + return m_MappedData[m_Desc.MipLevels * Slice + Mip].pData != nullptr; + } + + void Reset() + { + for (auto& MappedData : m_MappedData) + MappedData = MappedTextureSubresource{}; + } + protected: const UploadBufferDesc m_Desc; - void* m_pData = 0; - size_t m_RowStride = 0; - size_t m_DepthStride = 0; + std::vector m_MappedData; }; class TextureUploaderBase : public ObjectBase diff --git a/Graphics/GraphicsTools/src/TextureUploaderD3D11.cpp b/Graphics/GraphicsTools/src/TextureUploaderD3D11.cpp index 3d21df48..9b3ee9a3 100644 --- a/Graphics/GraphicsTools/src/TextureUploaderD3D11.cpp +++ b/Graphics/GraphicsTools/src/TextureUploaderD3D11.cpp @@ -36,6 +36,7 @@ #include "TextureD3D11.h" #include "DXGITypeConversions.h" #include "ThreadSignal.h" +#include "GraphicsAccessories.h" namespace Diligent { @@ -47,22 +48,13 @@ namespace class UploadBufferD3D11 : public UploadBufferBase { public: - UploadBufferD3D11(Diligent::IReferenceCounters *pRefCounters, const UploadBufferDesc &Desc, ID3D11Texture2D *pStagingTexture) : + UploadBufferD3D11(IReferenceCounters *pRefCounters, const UploadBufferDesc &Desc, ID3D11Texture2D *pStagingTexture) : UploadBufferBase(pRefCounters, Desc), m_pStagingTexture(pStagingTexture) {} ~UploadBufferD3D11() { - if (m_pStagingTexture) - LOG_INFO_MESSAGE("UploadBufferD3D11: releasing ", m_Desc.Width, 'x', m_Desc.Height, " Fmt=", m_Desc.Format, " staging texture"); - } - - void SetDataPtr(void *pData, size_t RowStride, size_t DepthStride) - { - m_pData = pData; - m_RowStride = RowStride; - m_DepthStride = DepthStride; } // http://en.cppreference.com/w/cpp/thread/condition_variable @@ -98,11 +90,9 @@ public: void Reset() { - m_pData = nullptr; - m_RowStride = 0; - m_DepthStride = 0; m_BufferMappedSignal.Reset(); m_CopyScheduledSignal.Reset(); + UploadBufferBase::Reset(); } ID3D11Texture2D* GetStagingTex() { return m_pStagingTexture; } @@ -127,21 +117,25 @@ struct TextureUploaderD3D11::InternalData }operation; RefCntAutoPtr pUploadBuffer; CComPtr pd3d11NativeDstTexture; - UINT DstSubresource = 0; + Uint32 DstMip = 0; + Uint32 DstSlice = 0; + Uint32 DstMipLevels = 0; PendingBufferOperation(Operation op, UploadBufferD3D11* pBuff) : - operation(op), + operation (op), pUploadBuffer(pBuff) {} - PendingBufferOperation(Operation op, UploadBufferD3D11* pBuff, ID3D11Resource *pd3d11DstTex, UINT dstSubres) : - operation(op), - pUploadBuffer(pBuff), + PendingBufferOperation(Operation op, UploadBufferD3D11* pBuff, ID3D11Resource* pd3d11DstTex, Uint32 Mip, Uint32 Slice, Uint32 MipLevels) : + operation (op), + pUploadBuffer (pBuff), pd3d11NativeDstTexture(pd3d11DstTex), - DstSubresource(dstSubres) + DstMip (Mip), + DstSlice (Slice), + DstMipLevels (MipLevels) {} }; - InternalData(IRenderDevice *pDevice) + InternalData(IRenderDevice* pDevice) { RefCntAutoPtr pDeviceD3D11(pDevice, IID_RenderDeviceD3D11); m_pd3d11NativeDevice = pDeviceD3D11->GetD3D11Device(); @@ -155,10 +149,10 @@ struct TextureUploaderD3D11::InternalData m_PendingOperations.swap(m_InWorkOperations); } - void EnqueCopy(UploadBufferD3D11 *pUploadBuffer, ID3D11Resource *pd3d11DstTex, UINT dstSubres) + void EnqueCopy(UploadBufferD3D11* pUploadBuffer, ID3D11Resource* pd3d11DstTex, Uint32 Mip, Uint32 Slice, Uint32 MipLevels) { std::lock_guard QueueLock(m_PendingOperationsMtx); - m_PendingOperations.emplace_back(PendingBufferOperation::Operation::Copy, pUploadBuffer, pd3d11DstTex, dstSubres); + m_PendingOperations.emplace_back(PendingBufferOperation::Operation::Copy, pUploadBuffer, pd3d11DstTex, Mip, Slice, MipLevels); } void EnqueMap(UploadBufferD3D11 *pUploadBuffer, PendingBufferOperation::Operation Op) @@ -203,7 +197,7 @@ TextureUploaderD3D11::~TextureUploaderD3D11() } } -void TextureUploaderD3D11::RenderThreadUpdate(Diligent::IDeviceContext *pContext) +void TextureUploaderD3D11::RenderThreadUpdate(IDeviceContext* pContext) { m_pInternalData->SwapMapQueues(); if (!m_pInternalData->m_InWorkOperations.empty()) @@ -213,18 +207,45 @@ void TextureUploaderD3D11::RenderThreadUpdate(Diligent::IDeviceContext *pContext for (auto &OperationInfo : m_pInternalData->m_InWorkOperations) { - auto &pBuffer = OperationInfo.pUploadBuffer; + auto& pBuffer = OperationInfo.pUploadBuffer; + const auto& UploadBuffDesc = pBuffer->GetDesc(); switch (OperationInfo.operation) { case InternalData::PendingBufferOperation::MapAndCache: case InternalData::PendingBufferOperation::Map: { - D3D11_MAPPED_SUBRESOURCE MappedData; - auto hr = pd3d11NativeCtx->Map(pBuffer->GetStagingTex(), 0, D3D11_MAP_WRITE, D3D11_MAP_FLAG_DO_NOT_WAIT, &MappedData); - if (SUCCEEDED(hr)) + bool AllMapped = true; + for (Uint32 Slice = 0; Slice < UploadBuffDesc.ArraySize; ++Slice) + { + for (Uint32 Mip = 0; Mip < UploadBuffDesc.MipLevels; ++Mip) + { + if (!pBuffer->IsMapped(Mip, Slice)) + { + D3D11_MAPPED_SUBRESOURCE MappedData; + UINT Subres = D3D11CalcSubresource(static_cast(Mip), static_cast(Slice), static_cast(UploadBuffDesc.MipLevels)); + auto hr = pd3d11NativeCtx->Map(pBuffer->GetStagingTex(), Subres, D3D11_MAP_WRITE, D3D11_MAP_FLAG_DO_NOT_WAIT, &MappedData); + if (SUCCEEDED(hr)) + { + pBuffer->SetMappedData(Mip, Slice, MappedTextureSubresource{MappedData.pData, MappedData.RowPitch, MappedData.DepthPitch}); + } + else + { + if (hr == DXGI_ERROR_WAS_STILL_DRAWING) + { + AllMapped = false; + } + else + { + LOG_ERROR("Unknown DX error when mapping staging texture: ", hr); + } + } + } + } + } + + if (AllMapped) { - pBuffer->SetDataPtr(MappedData.pData, MappedData.RowPitch, MappedData.DepthPitch); pBuffer->SignalMapped(); if (OperationInfo.operation == InternalData::PendingBufferOperation::MapAndCache) { @@ -235,14 +256,7 @@ void TextureUploaderD3D11::RenderThreadUpdate(Diligent::IDeviceContext *pContext } else { - if (hr == DXGI_ERROR_WAS_STILL_DRAWING) - { - m_pInternalData->EnqueMap(pBuffer, OperationInfo.operation); - } - else - { - LOG_ERROR("Unknown DX error when mapping staging texture: ", hr); - } + m_pInternalData->EnqueMap(pBuffer, OperationInfo.operation); } } break; @@ -250,13 +264,34 @@ void TextureUploaderD3D11::RenderThreadUpdate(Diligent::IDeviceContext *pContext case InternalData::PendingBufferOperation::Copy: { VERIFY(pBuffer->DbgIsMapped(), "Upload buffer must be copied only after it has been mapped"); - pd3d11NativeCtx->Unmap(pBuffer->GetStagingTex(), 0); - pd3d11NativeCtx->CopySubresourceRegion(OperationInfo.pd3d11NativeDstTexture, OperationInfo.DstSubresource, - 0, 0, 0, // DstX, DstY, DstZ - pBuffer->GetStagingTex(), - 0, // SrcSubresource - nullptr // pSrcBox - ); + // Unmap all subresources first to avoid D3D11 warnings + for (Uint32 Subres = 0; Subres < UploadBuffDesc.MipLevels * UploadBuffDesc.ArraySize; ++Subres) + { + pd3d11NativeCtx->Unmap(pBuffer->GetStagingTex(), Subres); + } + + for (Uint32 Slice = 0; Slice < UploadBuffDesc.ArraySize; ++Slice) + { + for (Uint32 Mip = 0; Mip < UploadBuffDesc.MipLevels; ++Mip) + { + UINT SrcSubres = D3D11CalcSubresource( + static_cast(Mip), + static_cast(Slice), + static_cast(UploadBuffDesc.MipLevels) + ); + UINT DstSubres = D3D11CalcSubresource( + static_cast(OperationInfo.DstMip + Mip), + static_cast(OperationInfo.DstSlice + Slice), + static_cast(OperationInfo.DstMipLevels) + ); + pd3d11NativeCtx->CopySubresourceRegion(OperationInfo.pd3d11NativeDstTexture, DstSubres, + 0, 0, 0, // DstX, DstY, DstZ + pBuffer->GetStagingTex(), + SrcSubres, + nullptr // pSrcBox + ); + } + } pBuffer->SignalCopyScheduled(); } break; @@ -294,8 +329,8 @@ void TextureUploaderD3D11::AllocateUploadBuffer(const UploadBufferDesc& Desc, bo { static_cast(Desc.Width), static_cast(Desc.Height), - 1, // UINT MipLevels; - 1, // UINT ArraySize; + static_cast(Desc.MipLevels), + static_cast(Desc.ArraySize), TexFormatToDXGI_Format(Desc.Format), {1, 0}, // DXGI_SAMPLE_DESC SampleDesc; D3D11_USAGE_STAGING, @@ -312,7 +347,8 @@ void TextureUploaderD3D11::AllocateUploadBuffer(const UploadBufferDesc& Desc, bo return; } - LOG_INFO_MESSAGE("TextureUploaderD3D11: created ", Desc.Width, 'x', Desc.Height, ' ', m_pDevice->GetTextureFormatInfo(Desc.Format).Name, " staging texture"); + LOG_INFO_MESSAGE("TextureUploaderD3D11: created ", Desc.Width, 'x', Desc.Height, 'x', Desc.Depth, ' ', Desc.MipLevels, "-mip ", + m_pDevice->GetTextureFormatInfo(Desc.Format).Name, " staging texture"); RefCntAutoPtr pUploadBuffer(MakeNewRCObj()(Desc, pStagingTex)); m_pInternalData->EnqueMap(pUploadBuffer, InternalData::PendingBufferOperation::Map); @@ -321,17 +357,16 @@ void TextureUploaderD3D11::AllocateUploadBuffer(const UploadBufferDesc& Desc, bo } } -void TextureUploaderD3D11::ScheduleGPUCopy(Diligent::ITexture *pDstTexture, - Uint32 ArraySlice, - Uint32 MipLevel, - IUploadBuffer *pUploadBuffer) +void TextureUploaderD3D11::ScheduleGPUCopy(ITexture* pDstTexture, + Uint32 ArraySlice, + Uint32 MipLevel, + IUploadBuffer* pUploadBuffer) { - auto *pUploadBufferD3D11 = ValidatedCast(pUploadBuffer); + auto* pUploadBufferD3D11 = ValidatedCast(pUploadBuffer); RefCntAutoPtr pDstTexD3D11(pDstTexture, IID_TextureD3D11); - auto *pd3d11NativeDstTex = pDstTexD3D11->GetD3D11Texture(); - const auto &DstTexDesc = pDstTexture->GetDesc(); - UINT DstSubres = D3D11CalcSubresource(static_cast(MipLevel), static_cast(ArraySlice), static_cast(DstTexDesc.MipLevels)); - m_pInternalData->EnqueCopy(pUploadBufferD3D11, pd3d11NativeDstTex, DstSubres); + auto* pd3d11NativeDstTex = pDstTexD3D11->GetD3D11Texture(); + const auto& DstTexDesc = pDstTexture->GetDesc(); + m_pInternalData->EnqueCopy(pUploadBufferD3D11, pd3d11NativeDstTex, MipLevel, ArraySlice, DstTexDesc.MipLevels); } void TextureUploaderD3D11::RecycleBuffer(IUploadBuffer *pUploadBuffer) diff --git a/Graphics/GraphicsTools/src/TextureUploaderD3D12_Vk.cpp b/Graphics/GraphicsTools/src/TextureUploaderD3D12_Vk.cpp index 775c9523..28ba46b4 100644 --- a/Graphics/GraphicsTools/src/TextureUploaderD3D12_Vk.cpp +++ b/Graphics/GraphicsTools/src/TextureUploaderD3D12_Vk.cpp @@ -49,7 +49,13 @@ public: ~UploadTexture() { - DEV_CHECK_ERR(m_pData == nullptr, "Releasing mapped staging texture"); + for (Uint32 Slice = 0; Slice < m_Desc.ArraySize; ++Slice) + { + for (Uint32 Mip = 0; Mip < m_Desc.MipLevels; ++Mip) + { + DEV_CHECK_ERR(!IsMapped(Mip, Slice), "Releasing mapped staging texture"); + } + } } void WaitForMap() @@ -68,22 +74,19 @@ public: m_CopyScheduledSignal.Trigger(); } - void Unmap(IDeviceContext* pDeviceContext) + void Unmap(IDeviceContext* pDeviceContext, Uint32 Mip, Uint32 Slice) { - pDeviceContext->UnmapTextureSubresource(m_pStagingTexture, 0, 0); - m_pData = nullptr; - m_RowStride = 0; - m_DepthStride = 0; + VERIFY(IsMapped(Mip, Slice), "This subresource is not mapped"); + pDeviceContext->UnmapTextureSubresource(m_pStagingTexture, Mip, Slice); + SetMappedData(Mip, Slice, MappedTextureSubresource{}); } - void Map(IDeviceContext* pDeviceContext) + void Map(IDeviceContext* pDeviceContext, Uint32 Mip, Uint32 Slice) { - VERIFY(m_pData == nullptr, "Staging texture is already mapped"); + VERIFY(!IsMapped(Mip, Slice), "This subresource 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; + pDeviceContext->MapTextureSubresource(m_pStagingTexture, Mip, Slice, MAP_WRITE, MAP_FLAG_DO_NOT_SYNCHRONIZE, nullptr, MappedData); + SetMappedData(Mip, Slice, MappedData); } void Reset() @@ -91,6 +94,7 @@ public: m_CopyScheduledSignal.Reset(); m_TextureMappedSignal.Reset(); m_CopyScheduledFenceValue = 0; + UploadBufferBase::Reset(); } virtual void WaitForCopyScheduled()override final @@ -286,12 +290,19 @@ void TextureUploaderD3D12_Vk::RenderThreadUpdate(IDeviceContext* pContext) for (auto& OperationInfo : InWorkOperations) { auto& pUploadTex = OperationInfo.pUploadTexture; + const auto& StagingTexDesc = pUploadTex->GetDesc(); switch (OperationInfo.operation) { case InternalData::PendingBufferOperation::Map: { - pUploadTex->Map(pContext); + for (Uint32 Slice = 0; Slice < StagingTexDesc.ArraySize; ++Slice) + { + for (Uint32 Mip = 0; Mip < StagingTexDesc.MipLevels; ++Mip) + { + pUploadTex->Map(pContext, Mip, Slice); + } + } pUploadTex->SignalMapped(); } break; @@ -299,18 +310,26 @@ void TextureUploaderD3D12_Vk::RenderThreadUpdate(IDeviceContext* pContext) case InternalData::PendingBufferOperation::Copy: { VERIFY(pUploadTex->DbgIsMapped(), "Upload texture must be copied only after it has been mapped"); - pUploadTex->Unmap(pContext); - - CopyTextureAttribs CopyInfo + for (Uint32 Slice = 0; Slice < StagingTexDesc.ArraySize; ++Slice) { - 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); + for (Uint32 Mip = 0; Mip < StagingTexDesc.MipLevels; ++Mip) + { + pUploadTex->Unmap(pContext, Mip, Slice); + + CopyTextureAttribs CopyInfo + { + pUploadTex->GetStagingTexture(), + RESOURCE_STATE_TRANSITION_MODE_TRANSITION, + OperationInfo.pDstTexture, + RESOURCE_STATE_TRANSITION_MODE_TRANSITION + }; + CopyInfo.SrcMipLevel = Mip; + CopyInfo.SrcSlice = Slice; + CopyInfo.DstMipLevel = OperationInfo.DstMip + Mip; + CopyInfo.DstSlice = OperationInfo.DstSlice + Slice; + pContext->CopyTexture(CopyInfo); + } + } ++NumCopyOperations; } break; @@ -349,13 +368,15 @@ void TextureUploaderD3D12_Vk::AllocateUploadBuffer(const UploadBufferDesc& Desc, StagingTexDesc.Width = Desc.Width; StagingTexDesc.Height = Desc.Height; StagingTexDesc.Format = Desc.Format; + StagingTexDesc.MipLevels = Desc.MipLevels; StagingTexDesc.CPUAccessFlags = CPU_ACCESS_WRITE; StagingTexDesc.Usage = USAGE_STAGING; RefCntAutoPtr pStagingTexture; m_pDevice->CreateTexture(StagingTexDesc, nullptr, &pStagingTexture); - LOG_INFO_MESSAGE("Created ", Desc.Width, "x", Desc.Height, " ", GetTextureFormatAttribs(Desc.Format).Name, " staging texture"); + LOG_INFO_MESSAGE("Created ", Desc.Width, "x", Desc.Height, 'x', Desc.Depth, ' ', Desc.MipLevels, "-mip ", + GetTextureFormatAttribs(Desc.Format).Name, " staging texture"); pUploadTexture = MakeNewRCObj()(Desc, pStagingTexture); } diff --git a/Graphics/GraphicsTools/src/TextureUploaderGL.cpp b/Graphics/GraphicsTools/src/TextureUploaderGL.cpp index be85e196..2fe321e4 100644 --- a/Graphics/GraphicsTools/src/TextureUploaderGL.cpp +++ b/Graphics/GraphicsTools/src/TextureUploaderGL.cpp @@ -26,8 +26,12 @@ #include #include #include +#include + #include "TextureUploaderGL.h" #include "ThreadSignal.h" +#include "GraphicsAccessories.h" +#include "Align.h" namespace Diligent { @@ -39,14 +43,32 @@ class UploadBufferGL : public UploadBufferBase { public: UploadBufferGL(IReferenceCounters *pRefCounters, const UploadBufferDesc &Desc) : - UploadBufferBase(pRefCounters, Desc) - {} - - void SetDataPtr(void *pData, size_t RowStride, size_t DepthStride) + UploadBufferBase(pRefCounters, Desc), + m_SubresourceOffsets(Desc.MipLevels * Desc.ArraySize + 1), + m_SubresourceStrides(Desc.MipLevels * Desc.ArraySize) { - m_pData = pData; - m_RowStride = RowStride; - m_DepthStride = DepthStride; + const auto& FmtAttribs = GetTextureFormatAttribs(Desc.Format); + Uint32 SubRes = 0; + for (Uint32 Slice = 0; Slice < Desc.ArraySize; ++Slice) + { + for (Uint32 Mip = 0; Mip < Desc.MipLevels; ++Mip) + { + auto MipWidth = std::max(Desc.Width >> Mip, 1u); + auto MipHeight = std::max(Desc.Height >> Mip, 1u); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) + { + MipWidth = Align(MipWidth, Uint32{FmtAttribs.BlockWidth}); + MipHeight = Align(MipHeight, Uint32{FmtAttribs.BlockHeight}); + } + + auto RowStride = MipWidth / Uint32{FmtAttribs.BlockWidth} * FmtAttribs.GetElementSize(); + m_SubresourceStrides[SubRes] = RowStride; + + auto MipSize = MipHeight / Uint32{FmtAttribs.BlockHeight} * RowStride; + m_SubresourceOffsets[SubRes + 1] = m_SubresourceOffsets[SubRes] + MipSize; + ++SubRes; + } + } } // http://en.cppreference.com/w/cpp/thread/condition_variable @@ -72,19 +94,48 @@ public: bool DbgIsCopyScheduled()const { return m_CopyScheduledSignal.IsTriggered(); } + void SetDataPtr(Uint8* pBufferData) + { + for (Uint32 Slice = 0; Slice < m_Desc.ArraySize; ++Slice) + { + for (Uint32 Mip = 0; Mip < m_Desc.MipLevels; ++Mip) + { + SetMappedData(Mip, Slice, MappedTextureSubresource{pBufferData + GetOffset(Mip,Slice), GetStride(Mip,Slice), 0}); + } + } + } + + Uint32 GetOffset(Uint32 Mip, Uint32 Slice) + { + VERIFY_EXPR(Mip < m_Desc.MipLevels && Slice < m_Desc.ArraySize); + return m_SubresourceOffsets[m_Desc.MipLevels * Slice + Mip]; + } + void Reset() { m_BufferMappedSignal.Reset(); m_CopyScheduledSignal.Reset(); - m_pData = nullptr; - // Do not zero out strides + UploadBufferBase::Reset(); + } + + Uint32 GetTotalSize()const + { + return m_SubresourceOffsets.back(); } private: + Uint32 GetStride(Uint32 Mip, Uint32 Slice) + { + VERIFY_EXPR(Mip < m_Desc.MipLevels && Slice < m_Desc.ArraySize); + return m_SubresourceStrides[m_Desc.MipLevels * Slice + Mip]; + } + friend TextureUploaderGL; ThreadingTools::Signal m_BufferMappedSignal; ThreadingTools::Signal m_CopyScheduledSignal; RefCntAutoPtr m_pStagingBuffer; + std::vector m_SubresourceOffsets; + std::vector m_SubresourceStrides; }; } // namespace @@ -177,48 +228,54 @@ void TextureUploaderGL::RenderThreadUpdate(IDeviceContext *pContext) m_pInternalData->SwapMapQueues(); if (!m_pInternalData->m_InWorkOperations.empty()) { - for (auto &OperationInfo : m_pInternalData->m_InWorkOperations) + for (auto& OperationInfo : m_pInternalData->m_InWorkOperations) { - auto &pBuffer = OperationInfo.pUploadBuffer; + auto& pBuffer = OperationInfo.pUploadBuffer; + const auto& UploadBuffDesc = pBuffer->GetDesc(); switch (OperationInfo.operation) { case InternalData::PendingBufferOperation::Map: { - Uint32 RowStride = static_cast(pBuffer->GetRowStride()); if (pBuffer->m_pStagingBuffer == nullptr) { - const auto &Desc = pBuffer->GetDesc(); BufferDesc BuffDesc; BuffDesc.Name = "Staging buffer for UploadBufferGL"; BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE; BuffDesc.Usage = USAGE_STAGING; - - const auto &TexFmtInfo = m_pDevice->GetTextureFormatInfo(Desc.Format); - RowStride = Desc.Width / Uint32{TexFmtInfo.BlockWidth} * TexFmtInfo.GetElementSize(); - BuffDesc.uiSizeInBytes = Desc.Height / Uint32{TexFmtInfo.BlockHeight} * RowStride; + BuffDesc.uiSizeInBytes = pBuffer->GetTotalSize(); RefCntAutoPtr pStagingBuffer; m_pDevice->CreateBuffer(BuffDesc, nullptr, &pBuffer->m_pStagingBuffer); } PVoid CpuAddress = nullptr; pContext->MapBuffer(pBuffer->m_pStagingBuffer, MAP_WRITE, MAP_FLAG_DISCARD, CpuAddress); - pBuffer->SetDataPtr(CpuAddress, RowStride, 0); - + pBuffer->SetDataPtr(reinterpret_cast(CpuAddress)); + pBuffer->SignalMapped(); } break; case InternalData::PendingBufferOperation::Copy: { + const auto& TexDesc = OperationInfo.pDstTexture->GetDesc(); + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); pContext->UnmapBuffer(pBuffer->m_pStagingBuffer, MAP_WRITE); - TextureSubResData SubResData(pBuffer->m_pStagingBuffer, 0, static_cast(pBuffer->GetRowStride())); - Box DstBox; - const auto &TexDesc = OperationInfo.pDstTexture->GetDesc(); - DstBox.MaxX = TexDesc.Width; - DstBox.MaxY = TexDesc.Height; - pContext->UpdateTexture(OperationInfo.pDstTexture, OperationInfo.DstMip, OperationInfo.DstSlice, DstBox, - SubResData, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + for (Uint32 Slice = 0; Slice < UploadBuffDesc.ArraySize; ++Slice) + { + for (Uint32 Mip = 0; Mip < UploadBuffDesc.MipLevels; ++Mip) + { + auto SrcOffset = pBuffer->GetOffset(Mip, Slice); + auto SrcStride = pBuffer->GetMappedData(Mip, Slice).Stride; + TextureSubResData SubResData(pBuffer->m_pStagingBuffer, SrcOffset, SrcStride); + auto MipLevelProps = GetMipLevelProperties(TexDesc, Mip); + Box DstBox; + DstBox.MaxX = MipLevelProps.Width; + DstBox.MaxY = MipLevelProps.Height; + pContext->UpdateTexture(OperationInfo.pDstTexture, OperationInfo.DstMip + Mip, OperationInfo.DstSlice + Slice, DstBox, + SubResData, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + } + } pBuffer->SignalCopyScheduled(); } break; @@ -254,7 +311,8 @@ void TextureUploaderGL::AllocateUploadBuffer(const UploadBufferDesc& Desc, bool if( !pUploadBuffer ) { pUploadBuffer = MakeNewRCObj()(Desc); - LOG_INFO_MESSAGE("TextureUploaderGL: created upload buffer for ", Desc.Width, 'x', Desc.Height, 'x', Desc.Depth, ' ', m_pDevice->GetTextureFormatInfo(Desc.Format).Name, " texture"); + LOG_INFO_MESSAGE("TextureUploaderGL: created upload buffer for ", Desc.Width, 'x', Desc.Height, 'x', Desc.Depth, ' ', Desc.MipLevels, "-mip ", + m_pDevice->GetTextureFormatInfo(Desc.Format).Name, " texture"); } m_pInternalData->EnqueMap(pUploadBuffer); -- cgit v1.2.3