diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2019-04-13 14:40:08 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2019-04-13 14:40:08 +0000 |
| commit | bda7a3d7a68dbbaf4894332e2278c0970a61a74e (patch) | |
| tree | 5bd48e470933ce18f798bf858e0908ed562a2d53 /Graphics/GraphicsEngineD3D12 | |
| parent | Updated ALLOCATE macros to make it more convenient (diff) | |
| download | DiligentCore-bda7a3d7a68dbbaf4894332e2278c0970a61a74e.tar.gz DiligentCore-bda7a3d7a68dbbaf4894332e2278c0970a61a74e.zip | |
Improved mipmap generation in D3D12 backend
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
5 files changed, 157 insertions, 89 deletions
diff --git a/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h index a31ce319..552ebeda 100644 --- a/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h @@ -70,16 +70,6 @@ public: virtual D3D12_RESOURCE_STATES GetD3D12ResourceState()const override final; - D3D12_CPU_DESCRIPTOR_HANDLE GetMipLevelUAV(Uint32 Mip) - { - return m_MipUAVs.GetCpuHandle(Mip); - } - - D3D12_CPU_DESCRIPTOR_HANDLE GetTexArraySRV() - { - return m_TexArraySRV.GetCpuHandle(); - } - D3D12_RESOURCE_DESC GetD3D12TextureDesc()const; protected: @@ -91,11 +81,6 @@ protected: void CreateDSV( TextureViewDesc &DSVDesc, D3D12_CPU_DESCRIPTOR_HANDLE DSVHandle ); void CreateUAV( TextureViewDesc &UAVDesc, D3D12_CPU_DESCRIPTOR_HANDLE UAVHandle ); - // UAVs for every mip level to facilitate mipmap generation - DescriptorHeapAllocation m_MipUAVs; - // SRV as texture array (even for a non-array texture) required for mipmap generation - DescriptorHeapAllocation m_TexArraySRV; - friend class RenderDeviceD3D12Impl; }; diff --git a/Graphics/GraphicsEngineD3D12/include/TextureViewD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/TextureViewD3D12Impl.h index 41c17980..f95e71dd 100644 --- a/Graphics/GraphicsEngineD3D12/include/TextureViewD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/TextureViewD3D12Impl.h @@ -46,16 +46,39 @@ public: RenderDeviceD3D12Impl* pDevice, const TextureViewDesc& ViewDesc, class ITexture* pTexture, - DescriptorHeapAllocation&& HandleAlloc, + DescriptorHeapAllocation&& Descriptor, + DescriptorHeapAllocation&& TexArraySRVDescriptor, + DescriptorHeapAllocation&& MipLevelUAVDescriptors, bool bIsDefaultView); + ~TextureViewD3D12Impl(); virtual void QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface)override final; - virtual D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle()override{return m_Descriptor.GetCpuHandle();} + virtual D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle()override final + { + return m_Descriptor.GetCpuHandle(); + } + + D3D12_CPU_DESCRIPTOR_HANDLE GetMipLevelUAV(Uint32 Mip) + { + VERIFY_EXPR((m_Desc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0 && m_MipGenerationDescriptors != nullptr && Mip < m_Desc.NumMipLevels ); + return m_MipGenerationDescriptors[1].GetCpuHandle(Mip); + } + + D3D12_CPU_DESCRIPTOR_HANDLE GetTexArraySRV() + { + VERIFY_EXPR((m_Desc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0 && m_MipGenerationDescriptors != nullptr); + return m_MipGenerationDescriptors[0].GetCpuHandle(); + } protected: /// D3D12 view descriptor handle DescriptorHeapAllocation m_Descriptor; + + // Extra descriptors used for mipmap generation + // [0] == texture array SRV used for mipmap generation + // [1] == mip level UAVs used for mipmap generation + DescriptorHeapAllocation* m_MipGenerationDescriptors = nullptr; }; } diff --git a/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp b/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp index 48e9155d..e0dfe5e3 100644 --- a/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp +++ b/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp @@ -107,25 +107,39 @@ namespace Diligent { auto& ComputeCtx = Ctx.AsComputeContext(); ComputeCtx.SetRootSignature(m_pGenerateMipsRS); - auto* pTexture = pTexView->GetTexture(); - auto* pTexD3D12 = ValidatedCast<TextureD3D12Impl>( pTexture ); - auto& TexDesc = pTexture->GetDesc(); - auto SRVDescriptorHandle = pTexD3D12->GetTexArraySRV(); + auto* pTexD3D12 = pTexView->GetTexture<TextureD3D12Impl>(); + const auto& TexDesc = pTexD3D12->GetDesc(); + const auto& ViewDesc = pTexView->GetDesc(); + auto SRVDescriptorHandle = pTexView->GetTexArraySRV(); if (!pTexD3D12->IsInKnownState()) { LOG_ERROR_MESSAGE("Unable to generate mips for texture '", TexDesc.Name, "' because the texture state is unknown"); return; } + + if (pTexD3D12->GetState() == RESOURCE_STATE_UNDEFINED) + { + // If texture state is undefined, transition it to unordered access state + Ctx.TransitionResource(pTexD3D12, RESOURCE_STATE_UNORDERED_ACCESS); + } - if (pTexD3D12->IsInKnownState() && !pTexD3D12->CheckState(RESOURCE_STATE_UNORDERED_ACCESS)) - Ctx.TransitionResource(pTexD3D12, RESOURCE_STATE_UNORDERED_ACCESS); - - const auto &ViewDesc = pTexView->GetDesc(); - for (uint32_t TopMip = 0; TopMip < TexDesc.MipLevels - 1; ) + const auto OriginalState = pTexD3D12->GetState(); + + pTexD3D12->SetState(RESOURCE_STATE_UNKNOWN); // Switch to manual state management + StateTransitionDesc TextureBarrier(pTexD3D12, OriginalState, RESOURCE_STATE_UNORDERED_ACCESS, false); + TextureBarrier.FirstMipLevel = ViewDesc.MostDetailedMip; + TextureBarrier.MipLevelsCount = ViewDesc.NumMipLevels; + TextureBarrier.FirstArraySlice = ViewDesc.FirstArraySlice; + TextureBarrier.ArraySliceCount = ViewDesc.NumArraySlices; + if (OriginalState != RESOURCE_STATE_UNORDERED_ACCESS) + Ctx.TransitionResource(TextureBarrier); + + auto BottomMip = ViewDesc.NumMipLevels - 1; + for (uint32_t TopMip = 0; TopMip < BottomMip; ) { - uint32_t SrcWidth = std::max(TexDesc.Width >> TopMip, 1u); - uint32_t SrcHeight = std::max(TexDesc.Height >> TopMip, 1u); + uint32_t SrcWidth = std::max(TexDesc.Width >> (TopMip + ViewDesc.MostDetailedMip), 1u); + uint32_t SrcHeight = std::max(TexDesc.Height >> (TopMip + ViewDesc.MostDetailedMip), 1u); uint32_t DstWidth = std::max(SrcWidth >> 1, 1u); uint32_t DstHeight = std::max(SrcHeight >> 1, 1u); @@ -145,8 +159,8 @@ namespace Diligent uint32_t AdditionalMips; _BitScanForward((unsigned long*)&AdditionalMips, DstWidth | DstHeight); uint32_t NumMips = 1 + (AdditionalMips > 3 ? 3 : AdditionalMips); - if (TopMip + NumMips > TexDesc.MipLevels - 1) - NumMips = TexDesc.MipLevels - 1 - TopMip; + if (TopMip + NumMips > BottomMip) + NumMips = BottomMip - TopMip; // These are clamped to 1 after computing additional mips because clamped // dimensions should not limit us from downsampling multiple times. (E.g. @@ -169,7 +183,16 @@ namespace Diligent Uint32 FirstArraySlice; Uint32 Dummy; float TexelSize[2]; // 1.0 / OutMip1.Dimensions - }CBData = { TopMip, NumMips, ViewDesc.FirstArraySlice, 0, 1.0f / static_cast<float>(DstWidth), 1.0f / static_cast<float>(DstHeight) }; + }; + RootCBData CBData + { + TopMip, // Mip levels are relateive to the view's most detailed mip + NumMips, + 0, // Array slices are relative to the view's first array slice + 0, + 1.0f / static_cast<float>(DstWidth), 1.0f / static_cast<float>(DstHeight) + }; + Ctx.GetCommandList()->SetComputeRoot32BitConstants(0, 6, &CBData, 0); // TODO: Shouldn't we transition top mip to shader resource state? @@ -184,7 +207,7 @@ namespace Diligent // So we must populate all 4 slots even though we may actually process less than 4 mip levels // Copy top mip level UAV descriptor handle to all unused slots for (Uint32 u = 0; u < MaxMipsHandledByCS; ++u) - SrcDescriptorRanges[1 + u] = pTexD3D12->GetMipLevelUAV(std::min(TopMip + u + 1, TexDesc.MipLevels - 1)); + SrcDescriptorRanges[1 + u] = pTexView->GetMipLevelUAV(std::min(TopMip + u + 1, BottomMip)); pd3d12Device->CopyDescriptors(1, &DstDescriptorRange, &DstRangeSize, 1 + MaxMipsHandledByCS, SrcDescriptorRanges, SrcRangeSizes, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); @@ -194,5 +217,29 @@ namespace Diligent TopMip += NumMips; } + + RESOURCE_STATE TextureState = OriginalState; + if (OriginalState != RESOURCE_STATE_UNORDERED_ACCESS) + { + bool IsAllSlices = (TexDesc.Type != RESOURCE_DIM_TEX_1D_ARRAY && + TexDesc.Type != RESOURCE_DIM_TEX_2D_ARRAY && + TexDesc.Type != RESOURCE_DIM_TEX_CUBE_ARRAY) || + TexDesc.ArraySize == ViewDesc.NumArraySlices; + bool IsAllMips = ViewDesc.NumMipLevels == TexDesc.MipLevels; + if (IsAllSlices && IsAllMips) + { + TextureState = RESOURCE_STATE_UNORDERED_ACCESS; + } + else + { + VERIFY(OriginalState != RESOURCE_STATE_UNDEFINED, "Original layout must not be undefined"); + // Transition affected subresources back to original layout + std::swap(TextureBarrier.NewState, TextureBarrier.OldState); + Ctx.TransitionResource(TextureBarrier); + } + } + + // Set state + pTexD3D12->SetState(TextureState); } } diff --git a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp index a776f97d..652150ae 100644 --- a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp @@ -130,9 +130,13 @@ TextureD3D12Impl :: TextureD3D12Impl(IReferenceCounters* pRefCounters, 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"); - 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, "'"); + if ((m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) != 0) + { + if (m_Desc.Type != RESOURCE_DIM_TEX_2D && m_Desc.Type != RESOURCE_DIM_TEX_2D_ARRAY) + { + LOG_ERROR_AND_THROW("Mipmap generation is currently only supported for 2D textures and 2D texture arrays in d3d12 backend"); + } + } D3D12_RESOURCE_DESC Desc = GetD3D12TextureDesc(); @@ -261,42 +265,6 @@ TextureD3D12Impl :: TextureD3D12Impl(IReferenceCounters* pRefCounters, // submitting command list for execution! pRenderDeviceD3D12->SafeReleaseDeviceObject(std::move(UploadBuffer), Uint64{1} << QueueIndex); } - - 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"); - } - - 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() ); - } - } } else if (m_Desc.Usage == USAGE_STAGING) { @@ -438,46 +406,76 @@ void TextureD3D12Impl::CreateViewInternal( const struct TextureViewDesc &ViewDes auto UpdatedViewDesc = ViewDesc; CorrectTextureViewDesc( UpdatedViewDesc ); - DescriptorHeapAllocation ViewHandleAlloc; + DescriptorHeapAllocation ViewDescriptor; switch( ViewDesc.ViewType ) { case TEXTURE_VIEW_SHADER_RESOURCE: { VERIFY( m_Desc.BindFlags & BIND_SHADER_RESOURCE, "BIND_SHADER_RESOURCE flag is not set" ); - ViewHandleAlloc = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - CreateSRV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); + ViewDescriptor = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + CreateSRV( UpdatedViewDesc, ViewDescriptor.GetCpuHandle() ); } break; case TEXTURE_VIEW_RENDER_TARGET: { VERIFY( m_Desc.BindFlags & BIND_RENDER_TARGET, "BIND_RENDER_TARGET flag is not set" ); - ViewHandleAlloc = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - CreateRTV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); + ViewDescriptor = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + CreateRTV( UpdatedViewDesc, ViewDescriptor.GetCpuHandle() ); } break; case TEXTURE_VIEW_DEPTH_STENCIL: { VERIFY( m_Desc.BindFlags & BIND_DEPTH_STENCIL, "BIND_DEPTH_STENCIL is not set" ); - ViewHandleAlloc = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); - CreateDSV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); + ViewDescriptor = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + CreateDSV( UpdatedViewDesc, ViewDescriptor.GetCpuHandle() ); } break; case TEXTURE_VIEW_UNORDERED_ACCESS: { VERIFY( m_Desc.BindFlags & BIND_UNORDERED_ACCESS, "BIND_UNORDERED_ACCESS flag is not set" ); - ViewHandleAlloc = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - CreateUAV( UpdatedViewDesc, ViewHandleAlloc.GetCpuHandle() ); + ViewDescriptor = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + CreateUAV( UpdatedViewDesc, ViewDescriptor.GetCpuHandle() ); } break; default: UNEXPECTED( "Unknown view type" ); break; } + DescriptorHeapAllocation TexArraySRVDescriptor, MipUAVDescriptors; + if (UpdatedViewDesc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) + { + VERIFY_EXPR((m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) != 0 && (m_Desc.Type == RESOURCE_DIM_TEX_2D || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY)); + + { + TexArraySRVDescriptor = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1); + TextureViewDesc TexArraySRVDesc = UpdatedViewDesc; + // Create texture array SRV + TexArraySRVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY; + TexArraySRVDesc.ViewType = TEXTURE_VIEW_SHADER_RESOURCE; + CreateSRV( TexArraySRVDesc, TexArraySRVDescriptor.GetCpuHandle() ); + } + + MipUAVDescriptors = pDeviceD3D12Impl->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_Desc.MipLevels); + for (Uint32 MipLevel = 0; MipLevel < m_Desc.MipLevels; ++MipLevel) + { + TextureViewDesc UAVDesc = UpdatedViewDesc; + // Always create texture array UAV + UAVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY; + UAVDesc.ViewType = TEXTURE_VIEW_UNORDERED_ACCESS; + UAVDesc.MostDetailedMip = MipLevel; + UAVDesc.NumMipLevels = 1; + if (UAVDesc.Format == TEX_FORMAT_RGBA8_UNORM_SRGB) + UAVDesc.Format = TEX_FORMAT_RGBA8_UNORM; + else if(UAVDesc.Format == TEX_FORMAT_BGRA8_UNORM_SRGB) + UAVDesc.Format = TEX_FORMAT_BGRA8_UNORM; + CreateUAV( UAVDesc, MipUAVDescriptors.GetCpuHandle(MipLevel) ); + } + } auto pViewD3D12 = NEW_RC_OBJ(TexViewAllocator, "TextureViewD3D12Impl instance", TextureViewD3D12Impl, bIsDefaultView ? this : nullptr) - (GetDevice(), UpdatedViewDesc, this, std::move(ViewHandleAlloc), bIsDefaultView ); + (GetDevice(), UpdatedViewDesc, this, std::move(ViewDescriptor), std::move(TexArraySRVDescriptor), std::move(MipUAVDescriptors), bIsDefaultView); VERIFY( pViewD3D12->GetDesc().ViewType == ViewDesc.ViewType, "Incorrect view type" ); if( bIsDefaultView ) diff --git a/Graphics/GraphicsEngineD3D12/src/TextureViewD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TextureViewD3D12Impl.cpp index a2c8c4d1..d10bf0da 100644 --- a/Graphics/GraphicsEngineD3D12/src/TextureViewD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/TextureViewD3D12Impl.cpp @@ -32,17 +32,32 @@ TextureViewD3D12Impl::TextureViewD3D12Impl( IReferenceCounters* pRefCount RenderDeviceD3D12Impl* pDevice, const TextureViewDesc& ViewDesc, ITexture* pTexture, - DescriptorHeapAllocation&& HandleAlloc, - bool bIsDefaultView ) : + DescriptorHeapAllocation&& Descriptor, + DescriptorHeapAllocation&& TexArraySRVDescriptor, + DescriptorHeapAllocation&& MipLevelUAVDescriptors, + bool bIsDefaultView) : TTextureViewBase( pRefCounters, pDevice, ViewDesc, pTexture, bIsDefaultView ), - m_Descriptor(std::move(HandleAlloc)) + m_Descriptor(std::move(Descriptor)) { + if (!TexArraySRVDescriptor.IsNull() && !MipLevelUAVDescriptors.IsNull()) + { + m_MipGenerationDescriptors = ALLOCATE(GetRawAllocator(), "Raw memory for DescriptorHeapAllocation", DescriptorHeapAllocation, 2); + new (&m_MipGenerationDescriptors[0])DescriptorHeapAllocation(std::move(TexArraySRVDescriptor)); + new (&m_MipGenerationDescriptors[1])DescriptorHeapAllocation(std::move(MipLevelUAVDescriptors)); + } +} + +TextureViewD3D12Impl::~TextureViewD3D12Impl() +{ + if (m_MipGenerationDescriptors != nullptr) + { + for (Uint32 i = 0; i < 2; ++i) + { + m_MipGenerationDescriptors[i].~DescriptorHeapAllocation(); + } + FREE(GetRawAllocator(), m_MipGenerationDescriptors); + } } -// -//ID3D12View* TextureViewD3D12Impl::GetD3D12View() -//{ -// return m_pD3D12View; -//} IMPLEMENT_QUERY_INTERFACE( TextureViewD3D12Impl, IID_TextureViewD3D12, TTextureViewBase ) |
