summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineD3D12
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2019-04-02 01:53:10 +0000
committerEgor Yusov <egor.yusov@gmail.com>2019-04-02 01:53:10 +0000
commite03a728e5fd120c285e2d7321bb9a77abedb6759 (patch)
tree16a3784b80924f9d79453d49e44b0b86b85d0838 /Graphics/GraphicsEngineD3D12
parentAdded ScreenCapture class (diff)
downloadDiligentCore-e03a728e5fd120c285e2d7321bb9a77abedb6759.tar.gz
DiligentCore-e03a728e5fd120c285e2d7321bb9a77abedb6759.zip
Implemented staging textures in D3D12 back-end
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
-rw-r--r--Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp234
-rw-r--r--Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp407
3 files changed, 431 insertions, 212 deletions
diff --git a/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h
index 92e3333e..a31ce319 100644
--- a/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h
+++ b/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h
@@ -80,6 +80,8 @@ public:
return m_TexArraySRV.GetCpuHandle();
}
+ D3D12_RESOURCE_DESC GetD3D12TextureDesc()const;
+
protected:
void CreateViewInternal( const struct TextureViewDesc &ViewDesc, ITextureView **ppView, bool bIsDefaultView )override final;
//void PrepareD3D12InitData(const TextureData &InitData, Uint32 NumSubresources, std::vector<D3D12_SUBRESOURCE_DATA> &D3D12InitData);
diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp
index eba7ac5d..2a54ae49 100644
--- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp
@@ -1116,19 +1116,66 @@ namespace Diligent
RESOURCE_STATE_TRANSITION_MODE DstTextureTransitionMode)
{
auto& CmdCtx = GetCmdContext();
+ if (pSrcTexture->GetDesc().Usage == USAGE_STAGING)
+ {
+ DEV_CHECK_ERR((pSrcTexture->GetDesc().CPUAccessFlags & CPU_ACCESS_WRITE) != 0, "Source staging texture must be created with CPU_ACCESS_WRITE flag");
+ DEV_CHECK_ERR(pSrcTexture->GetState() == RESOURCE_STATE_GENERIC_READ || !pSrcTexture->IsInKnownState(), "Staging texture must always be in RESOURCE_STATE_GENERIC_READ state");
+ }
TransitionOrVerifyTextureState(CmdCtx, *pSrcTexture, SrcTextureTransitionMode, RESOURCE_STATE_COPY_SOURCE, "Using resource as copy source (DeviceContextD3D12Impl::CopyTextureRegion)");
- TransitionOrVerifyTextureState(CmdCtx, *pDstTexture, DstTextureTransitionMode, RESOURCE_STATE_COPY_DEST, "Using resource as copy destination (DeviceContextD3D12Impl::CopyTextureRegion)");
- D3D12_TEXTURE_COPY_LOCATION DstLocation = {}, SrcLocation = {};
+ if (pDstTexture->GetDesc().Usage == USAGE_STAGING)
+ {
+ DEV_CHECK_ERR((pDstTexture->GetDesc().CPUAccessFlags & CPU_ACCESS_READ) != 0, "Destination staging texture must be created with CPU_ACCESS_READ flag");
+ DEV_CHECK_ERR(pDstTexture->GetState() == RESOURCE_STATE_COPY_DEST || !pDstTexture->IsInKnownState(), "Staging texture must always be in RESOURCE_STATE_COPY_DEST state");
+ }
+ TransitionOrVerifyTextureState(CmdCtx, *pDstTexture, DstTextureTransitionMode, RESOURCE_STATE_COPY_DEST, "Using resource as copy destination (DeviceContextD3D12Impl::CopyTextureRegion)");
- DstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
- DstLocation.pResource = pDstTexture->GetD3D12Resource();
- DstLocation.SubresourceIndex = DstSubResIndex;
+ D3D12_TEXTURE_COPY_LOCATION DstLocation = {}, SrcLocation = {};
- SrcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
SrcLocation.pResource = pSrcTexture->GetD3D12Resource();
- SrcLocation.SubresourceIndex = SrcSubResIndex;
-
+ if (pSrcTexture->GetDesc().Usage == USAGE_STAGING)
+ {
+ SrcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+ auto d3d12TexDesc = pSrcTexture->GetD3D12TextureDesc();
+ auto* pd3d12Device = m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->GetD3D12Device();
+ pd3d12Device->GetCopyableFootprints(&d3d12TexDesc,
+ SrcSubResIndex,
+ 1, // Num subresources
+ 0, // The offset, in bytes, to the resource.
+ &DstLocation.PlacedFootprint,
+ nullptr,
+ nullptr,
+ nullptr
+ );
+ }
+ else
+ {
+ SrcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ SrcLocation.SubresourceIndex = SrcSubResIndex;
+ }
+
+ DstLocation.pResource = pDstTexture->GetD3D12Resource();
+ if (pDstTexture->GetDesc().Usage == USAGE_STAGING)
+ {
+ DstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+ auto d3d12TexDesc = pDstTexture->GetD3D12TextureDesc();
+ auto* pd3d12Device = m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->GetD3D12Device();
+ pd3d12Device->GetCopyableFootprints(&d3d12TexDesc,
+ DstSubResIndex,
+ 1, // Num subresources
+ 0, // The offset, in bytes, to the resource.
+ &DstLocation.PlacedFootprint,
+ nullptr,
+ nullptr,
+ nullptr
+ );
+ }
+ else
+ {
+ DstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ DstLocation.SubresourceIndex = DstSubResIndex;
+ }
+
CmdCtx.FlushResourceBarriers();
CmdCtx.GetCommandList()->CopyTextureRegion( &DstLocation, DstX, DstY, DstZ, &SrcLocation, pD3D12SrcBox);
++m_State.NumCommands;
@@ -1343,38 +1390,89 @@ namespace Diligent
{
TDeviceContextBase::MapTextureSubresource(pTexture, MipLevel, ArraySlice, MapType, MapFlags, pMapRegion, MappedData);
- if (MapType != MAP_WRITE)
+ auto& TextureD3D12 = *ValidatedCast<TextureD3D12Impl>(pTexture);
+ const auto& TexDesc = TextureD3D12.GetDesc();
+ auto Subres = D3D12CalcSubresource(MipLevel, ArraySlice, 0, TexDesc.MipLevels, TexDesc.ArraySize);
+ if (TexDesc.Usage == USAGE_DEFAULT)
{
- LOG_ERROR("Textures can currently only be mapped for writing in D3D12 backend");
- MappedData = MappedTextureSubresource{};
- return;
- }
+ if (MapType != MAP_WRITE)
+ {
+ LOG_ERROR("USAGE_DEFAULT textures can only be mapped for writing");
+ MappedData = MappedTextureSubresource{};
+ return;
+ }
- if( (MapFlags & (MAP_FLAG_DISCARD | MAP_FLAG_DO_NOT_SYNCHRONIZE)) != 0 )
- LOG_WARNING_MESSAGE_ONCE("Mapping textures with flags MAP_FLAG_DISCARD or MAP_FLAG_DO_NOT_SYNCHRONIZE has no effect in D3D12 backend");
+ if( (MapFlags & (MAP_FLAG_DISCARD | MAP_FLAG_DO_NOT_SYNCHRONIZE)) != 0 )
+ LOG_WARNING_MESSAGE_ONCE("Mapping textures with flags MAP_FLAG_DISCARD or MAP_FLAG_DO_NOT_SYNCHRONIZE has no effect in D3D12 backend");
- auto& TextureD3D12 = *ValidatedCast<TextureD3D12Impl>(pTexture);
- const auto& TexDesc = TextureD3D12.GetDesc();
+ Box FullExtentBox;
+ if (pMapRegion == nullptr)
+ {
+ FullExtentBox.MaxX = std::max(TexDesc.Width >> MipLevel, 1u);
+ FullExtentBox.MaxY = std::max(TexDesc.Height >> MipLevel, 1u);
+ if (TexDesc.Type == RESOURCE_DIM_TEX_3D)
+ FullExtentBox.MaxZ = std::max(TexDesc.Depth >> MipLevel, 1u);
+ pMapRegion = &FullExtentBox;
+ }
- Box FullExtentBox;
- if (pMapRegion == nullptr)
- {
- FullExtentBox.MaxX = std::max(TexDesc.Width >> MipLevel, 1u);
- FullExtentBox.MaxY = std::max(TexDesc.Height >> MipLevel, 1u);
- if (TexDesc.Type == RESOURCE_DIM_TEX_3D)
- FullExtentBox.MaxZ = std::max(TexDesc.Depth >> MipLevel, 1u);
- pMapRegion = &FullExtentBox;
+ auto UploadSpace = AllocateTextureUploadSpace(TexDesc.Format, *pMapRegion);
+ MappedData.pData = reinterpret_cast<Uint8*>(UploadSpace.Allocation.CPUAddress) + (UploadSpace.AlignedOffset - UploadSpace.Allocation.Offset);
+ MappedData.Stride = UploadSpace.Stride;
+ MappedData.DepthStride = UploadSpace.DepthStride;
+
+ auto it = m_MappedTextures.emplace(MappedTextureKey{&TextureD3D12, Subres}, std::move(UploadSpace));
+ if(!it.second)
+ LOG_ERROR_MESSAGE("Mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "' has already been mapped");
}
+ else if (TexDesc.Usage == USAGE_STAGING)
+ {
+ if( (MapFlags & MAP_FLAG_DO_NOT_SYNCHRONIZE) == 0 )
+ {
+ LOG_WARNING_MESSAGE_ONCE("Mapping staging textures is never synchronized in D3D12 backend. "
+ "Application must use fences or other synchronization methods to explicitly synchronize "
+ "access and map texture with MAP_FLAG_DO_NOT_SYNCHRONIZE flag.");
+ }
- auto UploadSpace = AllocateTextureUploadSpace(TexDesc.Format, *pMapRegion);
- MappedData.pData = reinterpret_cast<Uint8*>(UploadSpace.Allocation.CPUAddress) + (UploadSpace.AlignedOffset - UploadSpace.Allocation.Offset);
- MappedData.Stride = UploadSpace.Stride;
- MappedData.DepthStride = UploadSpace.DepthStride;
+ auto d3d12TexDesc = TextureD3D12.GetD3D12TextureDesc();
+ auto* pd3d12Device = m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->GetD3D12Device();
+ D3D12_PLACED_SUBRESOURCE_FOOTPRINT Footprint = {};
+ UINT64 TotalBytes = 0;
+ UINT NumRows = 0;
+ UINT64 RowStride = 0;
+ pd3d12Device->GetCopyableFootprints(&d3d12TexDesc,
+ Subres,
+ 1, // Num subresources
+ 0, // The offset, in bytes, to the resource.
+ &Footprint,
+ &NumRows,
+ &RowStride,
+ &TotalBytes
+ );
+
+ // It is valid to specify the CPU won't read any data by passing a range where
+ // End is less than or equal to Begin.
+ // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/nf-d3d12-id3d12resource-map
+ D3D12_RANGE InvalidateRange = {1,0};
+ if (MapType == MAP_READ)
+ {
+ // Resources on D3D12_HEAP_TYPE_READBACK heaps do not support persistent map.
+ InvalidateRange = D3D12_RANGE{Footprint.Offset, Footprint.Offset + TotalBytes};
+ }
- auto Subres = D3D12CalcSubresource(MipLevel, ArraySlice, 0, TexDesc.MipLevels, TexDesc.ArraySize);
- auto it = m_MappedTextures.emplace(MappedTextureKey{&TextureD3D12, Subres}, std::move(UploadSpace));
- if(!it.second)
- LOG_ERROR_MESSAGE("Mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "' has already been mapped");
+ // Nested Map() calls are supported and are ref-counted. The first call to Map() allocates
+ // a CPU virtual address range for the resource. The last call to Unmap deallocates the CPU
+ // virtual address range.
+
+ // Map() invalidates the CPU cache, when necessary, so that CPU reads to this address
+ // reflect any modifications made by the GPU.
+ TextureD3D12.GetD3D12Resource()->Map(0, &InvalidateRange, &MappedData.pData);
+ MappedData.Stride = static_cast<Uint32>(RowStride);
+ MappedData.DepthStride = static_cast<Uint32>(RowStride * NumRows);
+ }
+ else
+ {
+ UNSUPPORTED(GetUsageString(TexDesc.Usage), " textures cannot currently be mapped in D3D12 back-end");
+ }
}
void DeviceContextD3D12Impl::UnmapTextureSubresource(ITexture* pTexture, Uint32 MipLevel, Uint32 ArraySlice)
@@ -1384,24 +1482,64 @@ namespace Diligent
TextureD3D12Impl& TextureD3D12 = *ValidatedCast<TextureD3D12Impl>(pTexture);
const auto& TexDesc = TextureD3D12.GetDesc();
auto Subres = D3D12CalcSubresource(MipLevel, ArraySlice, 0, TexDesc.MipLevels, TexDesc.ArraySize);
- auto UploadSpaceIt = m_MappedTextures.find(MappedTextureKey{&TextureD3D12, Subres});
- if(UploadSpaceIt != m_MappedTextures.end())
- {
- auto& UploadSpace = UploadSpaceIt->second;
- CopyTextureRegion(UploadSpace.Allocation.pBuffer,
- UploadSpace.AlignedOffset,
- UploadSpace.Stride,
- UploadSpace.DepthStride,
- static_cast<Uint32>(UploadSpace.Allocation.Size - (UploadSpace.AlignedOffset - UploadSpace.Allocation.Offset)),
- TextureD3D12,
- Subres,
- UploadSpace.Region,
- RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
- m_MappedTextures.erase(UploadSpaceIt);
+ if (TexDesc.Usage == USAGE_DEFAULT)
+ {
+ auto UploadSpaceIt = m_MappedTextures.find(MappedTextureKey{&TextureD3D12, Subres});
+ if(UploadSpaceIt != m_MappedTextures.end())
+ {
+ auto& UploadSpace = UploadSpaceIt->second;
+ CopyTextureRegion(UploadSpace.Allocation.pBuffer,
+ UploadSpace.AlignedOffset,
+ UploadSpace.Stride,
+ UploadSpace.DepthStride,
+ static_cast<Uint32>(UploadSpace.Allocation.Size - (UploadSpace.AlignedOffset - UploadSpace.Allocation.Offset)),
+ TextureD3D12,
+ Subres,
+ UploadSpace.Region,
+ RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
+ m_MappedTextures.erase(UploadSpaceIt);
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("Failed to unmap mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "'. The texture has either been unmapped already or has not been mapped");
+ }
+ }
+ else if (TexDesc.Usage == USAGE_STAGING)
+ {
+ // It is valid to specify the CPU didn't write any data by passing a range where
+ // End is less than or equal to Begin.
+ // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/nf-d3d12-id3d12resource-unmap
+ D3D12_RANGE FlushRange = {1, 0};
+
+ if (TexDesc.CPUAccessFlags == CPU_ACCESS_WRITE)
+ {
+ auto d3d12TexDesc = TextureD3D12.GetD3D12TextureDesc();
+ auto* pd3d12Device = m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->GetD3D12Device();
+ D3D12_PLACED_SUBRESOURCE_FOOTPRINT Footprint = {};
+ UINT64 TotalBytes = 0;
+ pd3d12Device->GetCopyableFootprints(&d3d12TexDesc,
+ Subres,
+ 1, // Num subresources
+ 0, // The offset, in bytes, to the resource.
+ &Footprint,
+ nullptr,
+ nullptr,
+ &TotalBytes
+ );
+ FlushRange = D3D12_RANGE{Footprint.Offset, Footprint.Offset + TotalBytes};
+ }
+
+ // Map and Unmap can be called by multiple threads safely. Nested Map calls are supported
+ // and are ref-counted. The first call to Map allocates a CPU virtual address range for the
+ // resource. The last call to Unmap deallocates the CPU virtual address range.
+
+ // Unmap() flushes the CPU cache, when necessary, so that GPU reads to this address reflect
+ // any modifications made by the CPU.
+ TextureD3D12.GetD3D12Resource()->Unmap(0, &FlushRange);
}
else
{
- LOG_ERROR_MESSAGE("Failed to unmap mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "'. The texture has either been unmapped already or has not been mapped");
+ UNSUPPORTED(GetUsageString(TexDesc.Usage), " textures cannot currently be mapped in D3D12 back-end");
}
}
diff --git a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp
index 84fccc67..0310ee06 100644
--- a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp
@@ -71,49 +71,37 @@ DXGI_FORMAT GetClearFormat(DXGI_FORMAT Fmt, D3D12_RESOURCE_FLAGS Flags)
return Fmt;
}
-TextureD3D12Impl :: TextureD3D12Impl(IReferenceCounters* pRefCounters,
- FixedBlockMemoryAllocator& TexViewObjAllocator,
- RenderDeviceD3D12Impl* pRenderDeviceD3D12,
- const TextureDesc& TexDesc,
- const TextureData* pInitData /*= nullptr*/) :
- TTextureBase(pRefCounters, TexViewObjAllocator, pRenderDeviceD3D12, TexDesc)
+D3D12_RESOURCE_DESC TextureD3D12Impl :: GetD3D12TextureDesc()const
{
- if (m_Desc.Usage == USAGE_STATIC && (pInitData == nullptr || pInitData->pSubResources == nullptr))
- LOG_ERROR_AND_THROW("Static textures must be initialized with data at creation time: pInitData can't be null");
+ D3D12_RESOURCE_DESC Desc = {};
- const auto& FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
- if ((m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) != 0 && FmtAttribs.IsTypeless)
- LOG_ERROR_AND_THROW("Textures created with MISC_TEXTURE_FLAG_GENERATE_MIPS flag can't use typeless formats. The following format was provided: ", FmtAttribs.Name, " when attempting to create texture '", m_Desc.Name, "'");
-
- D3D12_RESOURCE_DESC Desc = {};
Desc.Alignment = 0;
- if(m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY)
+ if (m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY)
Desc.DepthOrArraySize = (UINT16)m_Desc.ArraySize;
- else if(m_Desc.Type == RESOURCE_DIM_TEX_3D )
+ else if (m_Desc.Type == RESOURCE_DIM_TEX_3D )
Desc.DepthOrArraySize = (UINT16)m_Desc.Depth;
else
Desc.DepthOrArraySize = 1;
- if( m_Desc.Type == RESOURCE_DIM_TEX_1D || m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY )
+ if (m_Desc.Type == RESOURCE_DIM_TEX_1D || m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY)
Desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;
- else if( m_Desc.Type == RESOURCE_DIM_TEX_2D || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY)
+ else if (m_Desc.Type == RESOURCE_DIM_TEX_2D || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY)
Desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
- else if( m_Desc.Type == RESOURCE_DIM_TEX_3D )
+ else if (m_Desc.Type == RESOURCE_DIM_TEX_3D)
Desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
else
{
LOG_ERROR_AND_THROW("Unknown texture type");
}
-
Desc.Flags = D3D12_RESOURCE_FLAG_NONE;
- if( m_Desc.BindFlags & BIND_RENDER_TARGET )
+ if (m_Desc.BindFlags & BIND_RENDER_TARGET)
Desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
- if( m_Desc.BindFlags & BIND_DEPTH_STENCIL )
+ if (m_Desc.BindFlags & BIND_DEPTH_STENCIL)
Desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
- if( (m_Desc.BindFlags & BIND_UNORDERED_ACCESS) || (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) )
+ if ((m_Desc.BindFlags & BIND_UNORDERED_ACCESS) || (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) )
Desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
- if( (m_Desc.BindFlags & BIND_SHADER_RESOURCE) == 0 )
+ if ((m_Desc.BindFlags & BIND_SHADER_RESOURCE) == 0 && (m_Desc.BindFlags & BIND_DEPTH_STENCIL) != 0)
Desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
auto Format = TexFormatToDXGI_Format(m_Desc.Format, m_Desc.BindFlags);
@@ -121,168 +109,259 @@ TextureD3D12Impl :: TextureD3D12Impl(IReferenceCounters* pRefCounters,
Desc.Format = DXGI_FORMAT_R8G8B8A8_TYPELESS;
else
Desc.Format = Format;
- Desc.Height = (UINT)m_Desc.Height;
- Desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
- Desc.MipLevels = static_cast<Uint16>(m_Desc.MipLevels);
- Desc.SampleDesc.Count = m_Desc.SampleCount;
+
+ Desc.Height = UINT{m_Desc.Height};
+ Desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+ Desc.MipLevels = static_cast<UINT16>(m_Desc.MipLevels);
+ Desc.SampleDesc.Count = m_Desc.SampleCount;
Desc.SampleDesc.Quality = 0;
- Desc.Width = (UINT64)m_Desc.Width;
+ Desc.Width = UINT64{m_Desc.Width};
+ return Desc;
+}
- D3D12_HEAP_PROPERTIES HeapProps;
- HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
- HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
- HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
- HeapProps.CreationNodeMask = 1;
- HeapProps.VisibleNodeMask = 1;
+TextureD3D12Impl :: TextureD3D12Impl(IReferenceCounters* pRefCounters,
+ FixedBlockMemoryAllocator& TexViewObjAllocator,
+ RenderDeviceD3D12Impl* pRenderDeviceD3D12,
+ const TextureDesc& TexDesc,
+ const TextureData* pInitData /*= nullptr*/) :
+ TTextureBase(pRefCounters, TexViewObjAllocator, pRenderDeviceD3D12, TexDesc)
+{
+ if (m_Desc.Usage == USAGE_STATIC && (pInitData == nullptr || pInitData->pSubResources == nullptr))
+ LOG_ERROR_AND_THROW("Static textures must be initialized with data at creation time: pInitData can't be null");
- auto *pd3d12Device = pRenderDeviceD3D12->GetD3D12Device();
- D3D12_CLEAR_VALUE ClearValue;
- D3D12_CLEAR_VALUE *pClearValue = nullptr;
- if( Desc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) )
- {
- if(m_Desc.ClearValue.Format != TEX_FORMAT_UNKNOWN)
- ClearValue.Format = TexFormatToDXGI_Format(m_Desc.ClearValue.Format);
- else
- ClearValue.Format = GetClearFormat(Format, Desc.Flags);
+ const auto& FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
+ if ((m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) != 0 && FmtAttribs.IsTypeless)
+ LOG_ERROR_AND_THROW("Textures created with MISC_TEXTURE_FLAG_GENERATE_MIPS flag can't use typeless formats. The following format was provided: ", FmtAttribs.Name, " when attempting to create texture '", m_Desc.Name, "'");
+
+ D3D12_RESOURCE_DESC Desc = GetD3D12TextureDesc();
- if (Desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
+ auto* pd3d12Device = pRenderDeviceD3D12->GetD3D12Device();
+ if (m_Desc.Usage == USAGE_STATIC || m_Desc.Usage == USAGE_DEFAULT)
+ {
+ D3D12_CLEAR_VALUE ClearValue;
+ D3D12_CLEAR_VALUE* pClearValue = nullptr;
+ if (Desc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
{
- for(int i=0; i < 4; ++i)
- ClearValue.Color[i] = m_Desc.ClearValue.Color[i];
+ if (m_Desc.ClearValue.Format != TEX_FORMAT_UNKNOWN)
+ ClearValue.Format = TexFormatToDXGI_Format(m_Desc.ClearValue.Format);
+ else
+ {
+ auto Format = TexFormatToDXGI_Format(m_Desc.Format, m_Desc.BindFlags);
+ ClearValue.Format = GetClearFormat(Format, Desc.Flags);
+ }
+
+ if (Desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
+ {
+ for(int i=0; i < 4; ++i)
+ ClearValue.Color[i] = m_Desc.ClearValue.Color[i];
+ }
+ else if (Desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
+ {
+ ClearValue.DepthStencil.Depth = m_Desc.ClearValue.DepthStencil.Depth;
+ ClearValue.DepthStencil.Stencil = m_Desc.ClearValue.DepthStencil.Stencil;
+ }
+ pClearValue = &ClearValue;
}
- else if(Desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
+
+ D3D12_HEAP_PROPERTIES HeapProps;
+ HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
+ HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ HeapProps.CreationNodeMask = 1;
+ HeapProps.VisibleNodeMask = 1;
+
+ bool bInitializeTexture = (pInitData != nullptr && pInitData->pSubResources != nullptr && pInitData->NumSubresources > 0);
+ auto InitialState = bInitializeTexture ? RESOURCE_STATE_COPY_DEST : RESOURCE_STATE_UNDEFINED;
+ SetState(InitialState);
+ auto D3D12State = ResourceStateFlagsToD3D12ResourceStates(InitialState);
+ auto hr = pd3d12Device->CreateCommittedResource( &HeapProps, D3D12_HEAP_FLAG_NONE,
+ &Desc, D3D12State, pClearValue, __uuidof(m_pd3d12Resource), reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pd3d12Resource)) );
+ if (FAILED(hr))
+ LOG_ERROR_AND_THROW("Failed to create D3D12 texture");
+
+ if (*m_Desc.Name != 0)
+ m_pd3d12Resource->SetName(WidenString(m_Desc.Name).c_str());
+
+ if (bInitializeTexture)
{
- ClearValue.DepthStencil.Depth = m_Desc.ClearValue.DepthStencil.Depth;
- ClearValue.DepthStencil.Stencil = m_Desc.ClearValue.DepthStencil.Stencil;
+ Uint32 ExpectedNumSubresources = Uint32{Desc.MipLevels} * (Desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? 1 : Uint32{Desc.DepthOrArraySize});
+ if (pInitData->NumSubresources != ExpectedNumSubresources)
+ LOG_ERROR_AND_THROW("Incorrect number of subresources in init data. ", ExpectedNumSubresources, " expected, while ", pInitData->NumSubresources, " provided");
+
+ UINT64 uploadBufferSize = 0;
+ pd3d12Device->GetCopyableFootprints(&Desc, 0, pInitData->NumSubresources, 0, nullptr, nullptr, nullptr, &uploadBufferSize);
+
+ D3D12_HEAP_PROPERTIES UploadHeapProps;
+ UploadHeapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
+ UploadHeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ UploadHeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ UploadHeapProps.CreationNodeMask = 1;
+ UploadHeapProps.VisibleNodeMask = 1;
+
+ D3D12_RESOURCE_DESC BufferDesc;
+ BufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ BufferDesc.Alignment = 0;
+ BufferDesc.Width = uploadBufferSize;
+ BufferDesc.Height = 1;
+ BufferDesc.DepthOrArraySize = 1;
+ BufferDesc.MipLevels = 1;
+ BufferDesc.Format = DXGI_FORMAT_UNKNOWN;
+ BufferDesc.SampleDesc.Count = 1;
+ BufferDesc.SampleDesc.Quality = 0;
+ BufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ BufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ CComPtr<ID3D12Resource> UploadBuffer;
+ hr = pd3d12Device->CreateCommittedResource( &UploadHeapProps, D3D12_HEAP_FLAG_NONE,
+ &BufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ,
+ nullptr, __uuidof(UploadBuffer), reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&UploadBuffer)));
+ if(FAILED(hr))
+ LOG_ERROR_AND_THROW("Failed to create committed resource in an upload heap");
+
+ auto InitContext = pRenderDeviceD3D12->AllocateCommandContext();
+ // copy data to the intermediate upload heap and then schedule a copy from the upload heap to the default texture
+ VERIFY_EXPR(CheckState(RESOURCE_STATE_COPY_DEST));
+ std::vector<D3D12_SUBRESOURCE_DATA, STDAllocatorRawMem<D3D12_SUBRESOURCE_DATA> > D3D12SubResData(pInitData->NumSubresources, D3D12_SUBRESOURCE_DATA(), STD_ALLOCATOR_RAW_MEM(D3D12_SUBRESOURCE_DATA, GetRawAllocator(), "Allocator for vector<D3D12_SUBRESOURCE_DATA>") );
+ for(size_t subres=0; subres < D3D12SubResData.size(); ++subres)
+ {
+ D3D12SubResData[subres].pData = pInitData->pSubResources[subres].pData;
+ D3D12SubResData[subres].RowPitch = pInitData->pSubResources[subres].Stride;
+ D3D12SubResData[subres].SlicePitch = pInitData->pSubResources[subres].DepthStride;
+ }
+ auto UploadedSize = UpdateSubresources(InitContext->GetCommandList(), m_pd3d12Resource, UploadBuffer, 0, 0, pInitData->NumSubresources, D3D12SubResData.data());
+ VERIFY(UploadedSize == uploadBufferSize, "Incorrect uploaded data size (", UploadedSize, "). ", uploadBufferSize, " is expected");
+
+ // Command list fence should only be signaled when submitting cmd list
+ // from the immediate context, otherwise the basic requirement will be violated
+ // as in the scenario below
+ // See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-resource-lifetimes/
+ //
+ // Signaled Fence | Immediate Context | InitContext |
+ // | | |
+ // N | Draw(ResourceX) | |
+ // | Release(ResourceX) | |
+ // | - (ResourceX, N) -> Release Queue | |
+ // | | CopyResource() |
+ // N+1 | | CloseAndExecuteCommandContext() |
+ // | | |
+ // N+2 | CloseAndExecuteCommandContext() | |
+ // | - Cmd list is submitted with number | |
+ // | N+1, but resource it references | |
+ // | was added to the delete queue | |
+ // | with value N | |
+ Uint32 QueueIndex = 0;
+ pRenderDeviceD3D12->CloseAndExecuteTransientCommandContext(QueueIndex, std::move(InitContext));
+
+ // We MUST NOT call TransitionResource() from here, because
+ // it will call AddRef() and potentially Release(), while
+ // the object is not constructed yet
+ // Add reference to the object to the release queue to keep it alive
+ // until copy operation is complete. This must be done after
+ // submitting command list for execution!
+ pRenderDeviceD3D12->SafeReleaseDeviceObject(std::move(UploadBuffer), Uint64{1} << QueueIndex);
}
- pClearValue = &ClearValue;
- }
- bool bInitializeTexture = (pInitData != nullptr && pInitData->pSubResources != nullptr && pInitData->NumSubresources > 0);
- auto InitialState = bInitializeTexture ? RESOURCE_STATE_COPY_DEST : RESOURCE_STATE_UNDEFINED;
- SetState(InitialState);
- auto D3D12State = ResourceStateFlagsToD3D12ResourceStates(InitialState);
- auto hr = pd3d12Device->CreateCommittedResource( &HeapProps, D3D12_HEAP_FLAG_NONE,
- &Desc, D3D12State, pClearValue, __uuidof(m_pd3d12Resource), reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pd3d12Resource)) );
- if(FAILED(hr))
- LOG_ERROR_AND_THROW("Failed to create D3D12 texture");
+ if(m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS)
+ {
+ if (m_Desc.Type != RESOURCE_DIM_TEX_2D && m_Desc.Type != RESOURCE_DIM_TEX_2D_ARRAY)
+ {
+ LOG_ERROR_AND_THROW("Mipmap generation is only supported for 2D textures and texture arrays");
+ }
- if( *m_Desc.Name != 0)
- m_pd3d12Resource->SetName(WidenString(m_Desc.Name).c_str());
+ m_MipUAVs = pRenderDeviceD3D12->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_Desc.MipLevels);
+ for(Uint32 MipLevel = 0; MipLevel < m_Desc.MipLevels; ++MipLevel)
+ {
+ TextureViewDesc UAVDesc;
+ // Always create texture array UAV
+ UAVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
+ UAVDesc.ViewType = TEXTURE_VIEW_UNORDERED_ACCESS;
+ UAVDesc.FirstArraySlice = 0;
+ UAVDesc.NumArraySlices = m_Desc.ArraySize;
+ UAVDesc.MostDetailedMip = MipLevel;
+ if (m_Desc.Format == TEX_FORMAT_RGBA8_UNORM_SRGB)
+ UAVDesc.Format = TEX_FORMAT_RGBA8_UNORM;
+ CreateUAV( UAVDesc, m_MipUAVs.GetCpuHandle(MipLevel) );
+ }
- if(bInitializeTexture)
+ {
+ m_TexArraySRV = pRenderDeviceD3D12->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
+ TextureViewDesc TexArraySRVDesc;
+ // Create texture array SRV
+ TexArraySRVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
+ TexArraySRVDesc.ViewType = TEXTURE_VIEW_SHADER_RESOURCE;
+ TexArraySRVDesc.FirstArraySlice = 0;
+ TexArraySRVDesc.NumArraySlices = m_Desc.ArraySize;
+ TexArraySRVDesc.MostDetailedMip = 0;
+ TexArraySRVDesc.NumMipLevels = m_Desc.MipLevels;
+ CreateSRV( TexArraySRVDesc, m_TexArraySRV.GetCpuHandle() );
+ }
+ }
+ }
+ else if (m_Desc.Usage == USAGE_STAGING)
{
- Uint32 ExpectedNumSubresources = static_cast<Uint32>(Desc.MipLevels * (Desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? 1 : Desc.DepthOrArraySize) );
- if( pInitData->NumSubresources != ExpectedNumSubresources )
- LOG_ERROR_AND_THROW("Incorrect number of subresources in init data. ", ExpectedNumSubresources, " expected, while ", pInitData->NumSubresources, " provided");
+ // Create staging buffer
+ D3D12_HEAP_PROPERTIES StaginHeapProps;
+ DEV_CHECK_ERR( (m_Desc.CPUAccessFlags & (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) == CPU_ACCESS_READ ||
+ (m_Desc.CPUAccessFlags & (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) == CPU_ACCESS_WRITE,
+ "Exactly one of CPU_ACCESS_READ or CPU_ACCESS_WRITE flags must be specified");
+
+ RESOURCE_STATE InitialState = RESOURCE_STATE_UNKNOWN;
+ if (m_Desc.CPUAccessFlags & CPU_ACCESS_READ)
+ {
+ StaginHeapProps.Type = D3D12_HEAP_TYPE_READBACK;
+ InitialState = RESOURCE_STATE_COPY_DEST;
+ }
+ else if (m_Desc.CPUAccessFlags & CPU_ACCESS_WRITE)
+ {
+ StaginHeapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
+ InitialState = RESOURCE_STATE_GENERIC_READ;
+ }
+ else
+ UNEXPECTED("Unexpected CPU access");
+
+ SetState(InitialState);
+ auto D3D12State = ResourceStateFlagsToD3D12ResourceStates(InitialState);
- UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_pd3d12Resource, 0, pInitData->NumSubresources);
+ StaginHeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ StaginHeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ StaginHeapProps.CreationNodeMask = 1;
+ StaginHeapProps.VisibleNodeMask = 1;
- D3D12_HEAP_PROPERTIES UploadHeapProps;
- UploadHeapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
- UploadHeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
- UploadHeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
- UploadHeapProps.CreationNodeMask = 1;
- UploadHeapProps.VisibleNodeMask = 1;
+ UINT64 stagingBufferSize = 0;
+ Uint32 NumSubresources = Uint32{Desc.MipLevels} * (Desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? 1 : Uint32{Desc.DepthOrArraySize});
+ pd3d12Device->GetCopyableFootprints(&Desc, 0, NumSubresources, 0, nullptr, nullptr, nullptr, &stagingBufferSize);
D3D12_RESOURCE_DESC BufferDesc;
- BufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
- BufferDesc.Alignment = 0;
- BufferDesc.Width = uploadBufferSize;
- BufferDesc.Height = 1;
- BufferDesc.DepthOrArraySize = 1;
- BufferDesc.MipLevels = 1;
- BufferDesc.Format = DXGI_FORMAT_UNKNOWN;
- BufferDesc.SampleDesc.Count = 1;
+ BufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ BufferDesc.Alignment = 0;
+ BufferDesc.Width = stagingBufferSize;
+ BufferDesc.Height = 1;
+ BufferDesc.DepthOrArraySize = 1;
+ BufferDesc.MipLevels = 1;
+ BufferDesc.Format = DXGI_FORMAT_UNKNOWN;
+ BufferDesc.SampleDesc.Count = 1;
BufferDesc.SampleDesc.Quality = 0;
- BufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
- BufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
-
- CComPtr<ID3D12Resource> UploadBuffer;
- hr = pd3d12Device->CreateCommittedResource( &UploadHeapProps, D3D12_HEAP_FLAG_NONE,
- &BufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ,
- nullptr, __uuidof(UploadBuffer), reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&UploadBuffer)));
+ BufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ BufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ // Resources on D3D12_HEAP_TYPE_READBACK heaps do not support persistent map. Map() and Unmap() must be
+ // called between CPU and GPU accesses to the same memory address on some system architectures, when the
+ // page caching behavior is write-back. Map() and Unmap() invalidate and flush the last level CPU cache
+ // on some ARM systems, to marshal data between the CPU and GPU through memory addresses with write-back behavior.
+ // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/nf-d3d12-id3d12resource-map
+ auto hr = pd3d12Device->CreateCommittedResource( &StaginHeapProps, D3D12_HEAP_FLAG_NONE, &BufferDesc, D3D12State,
+ nullptr, __uuidof(m_pd3d12Resource), reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pd3d12Resource)));
if(FAILED(hr))
- LOG_ERROR_AND_THROW("Failed to create committed resource in an upload heap");
-
- auto InitContext = pRenderDeviceD3D12->AllocateCommandContext();
- // copy data to the intermediate upload heap and then schedule a copy from the upload heap to the default texture
- VERIFY_EXPR(CheckState(RESOURCE_STATE_COPY_DEST));
- std::vector<D3D12_SUBRESOURCE_DATA, STDAllocatorRawMem<D3D12_SUBRESOURCE_DATA> > D3D12SubResData(pInitData->NumSubresources, D3D12_SUBRESOURCE_DATA(), STD_ALLOCATOR_RAW_MEM(D3D12_SUBRESOURCE_DATA, GetRawAllocator(), "Allocator for vector<D3D12_SUBRESOURCE_DATA>") );
- for(size_t subres=0; subres < D3D12SubResData.size(); ++subres)
- {
- D3D12SubResData[subres].pData = pInitData->pSubResources[subres].pData;
- D3D12SubResData[subres].RowPitch = pInitData->pSubResources[subres].Stride;
- D3D12SubResData[subres].SlicePitch = pInitData->pSubResources[subres].DepthStride;
- }
- auto UploadedSize = UpdateSubresources(InitContext->GetCommandList(), m_pd3d12Resource, UploadBuffer, 0, 0, pInitData->NumSubresources, D3D12SubResData.data());
- VERIFY(UploadedSize == uploadBufferSize, "Incorrect uploaded data size (", UploadedSize, "). ", uploadBufferSize, " is expected");
-
- // Command list fence should only be signaled when submitting cmd list
- // from the immediate context, otherwise the basic requirement will be violated
- // as in the scenario below
- // See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-resource-lifetimes/
- //
- // Signaled Fence | Immediate Context | InitContext |
- // | | |
- // N | Draw(ResourceX) | |
- // | Release(ResourceX) | |
- // | - (ResourceX, N) -> Release Queue | |
- // | | CopyResource() |
- // N+1 | | CloseAndExecuteCommandContext() |
- // | | |
- // N+2 | CloseAndExecuteCommandContext() | |
- // | - Cmd list is submitted with number | |
- // | N+1, but resource it references | |
- // | was added to the delete queue | |
- // | with value N | |
- Uint32 QueueIndex = 0;
- pRenderDeviceD3D12->CloseAndExecuteTransientCommandContext(QueueIndex, std::move(InitContext));
-
- // We MUST NOT call TransitionResource() from here, because
- // it will call AddRef() and potentially Release(), while
- // the object is not constructed yet
- // Add reference to the object to the release queue to keep it alive
- // until copy operation is complete. This must be done after
- // submitting command list for execution!
- pRenderDeviceD3D12->SafeReleaseDeviceObject(std::move(UploadBuffer), Uint64{1} << QueueIndex);
+ LOG_ERROR_AND_THROW("Failed to create staging buffer");
}
-
- if(m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS)
+ else if (m_Desc.Usage == USAGE_DYNAMIC)
{
- if (m_Desc.Type != RESOURCE_DIM_TEX_2D && m_Desc.Type != RESOURCE_DIM_TEX_2D_ARRAY)
- {
- LOG_ERROR_AND_THROW("Mipmap generation is only supported for 2D textures and texture arrays");
- }
-
- m_MipUAVs = pRenderDeviceD3D12->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_Desc.MipLevels);
- for(Uint32 MipLevel = 0; MipLevel < m_Desc.MipLevels; ++MipLevel)
- {
- TextureViewDesc UAVDesc;
- // Always create texture array UAV
- UAVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
- UAVDesc.ViewType = TEXTURE_VIEW_UNORDERED_ACCESS;
- UAVDesc.FirstArraySlice = 0;
- UAVDesc.NumArraySlices = m_Desc.ArraySize;
- UAVDesc.MostDetailedMip = MipLevel;
- if (m_Desc.Format == TEX_FORMAT_RGBA8_UNORM_SRGB)
- UAVDesc.Format = TEX_FORMAT_RGBA8_UNORM;
- CreateUAV( UAVDesc, m_MipUAVs.GetCpuHandle(MipLevel) );
- }
-
- {
- m_TexArraySRV = pRenderDeviceD3D12->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
- TextureViewDesc TexArraySRVDesc;
- // Create texture array SRV
- TexArraySRVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
- TexArraySRVDesc.ViewType = TEXTURE_VIEW_SHADER_RESOURCE;
- TexArraySRVDesc.FirstArraySlice = 0;
- TexArraySRVDesc.NumArraySlices = m_Desc.ArraySize;
- TexArraySRVDesc.MostDetailedMip = 0;
- TexArraySRVDesc.NumMipLevels = m_Desc.MipLevels;
- CreateSRV( TexArraySRVDesc, m_TexArraySRV.GetCpuHandle() );
- }
+ LOG_ERROR_AND_THROW("Dynamic textures are not currently implemented in D3D12 back-end");
+ }
+ else
+ {
+ UNEXPECTED("Unexpected usage");
}
}