diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2019-04-11 15:39:32 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2019-04-11 15:39:32 +0000 |
| commit | 8ad6ca05f069b59af9544bc99bed7e5d1f785950 (patch) | |
| tree | 0dd6d845177796fb24902f8baa88484922c99e37 /Graphics | |
| parent | Added render target format validation when creating a PSO (diff) | |
| download | DiligentCore-8ad6ca05f069b59af9544bc99bed7e5d1f785950.tar.gz DiligentCore-8ad6ca05f069b59af9544bc99bed7e5d1f785950.zip | |
Reworked automatic mipmap generation in Vulkan backend to support sRGB textures, enable mipmap generation for partial texture views and optimize state transitions
Diffstat (limited to 'Graphics')
17 files changed, 452 insertions, 212 deletions
diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.h b/Graphics/GraphicsEngine/include/DeviceContextBase.h index a742c912..74226452 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.h +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.h @@ -861,7 +861,10 @@ inline void DeviceContextBase<BaseInterface,ImplementationTraits> :: VERIFY(pTexView != nullptr, "pTexView must not be null"); #ifdef DEVELOPMENT const auto& ViewDesc = pTexView->GetDesc(); - DEV_CHECK_ERR( ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, "GenerateMips() is allowed for shader resource views only, ", GetTexViewTypeLiteralName(ViewDesc.ViewType), " is not allowed." ); + DEV_CHECK_ERR(ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, "Shader resource view '", ViewDesc.Name, + "' can't be used to generate mipmaps because its type is ", GetTexViewTypeLiteralName(ViewDesc.ViewType), ". Required view type: TEXTURE_VIEW_SHADER_RESOURCE." ); + DEV_CHECK_ERR((ViewDesc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0, "Shader resource view '", ViewDesc.Name, + "' was not created with TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION flag and can't be used to generate mipmaps."); #endif } diff --git a/Graphics/GraphicsEngine/include/TextureBase.h b/Graphics/GraphicsEngine/include/TextureBase.h index 0ebc5cf1..939c0e3a 100644 --- a/Graphics/GraphicsEngine/include/TextureBase.h +++ b/Graphics/GraphicsEngine/include/TextureBase.h @@ -392,6 +392,15 @@ void TextureBase<BaseInterface, TRenderDeviceImpl, TTextureViewImpl, TTexViewObj TEX_VIEW_VALIDATION_ERROR( "Texture view format (", GetTextureFormatAttribs(ViewDesc.Format).Name, ") cannot be typeless" ); } + if ((ViewDesc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0) + { + if ((this->m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) == 0) + TEX_VIEW_VALIDATION_ERROR( "TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION flag can only set if the texture was created with MISC_TEXTURE_FLAG_GENERATE_MIPS flag" ); + + if (ViewDesc.ViewType != TEXTURE_VIEW_SHADER_RESOURCE) + TEX_VIEW_VALIDATION_ERROR( "TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION flag can only be used with TEXTURE_VIEW_SHADER_RESOURCE view type" ); + } + #undef TEX_VIEW_VALIDATION_ERROR if( ViewDesc.NumMipLevels == 0 || ViewDesc.NumMipLevels == TextureViewDesc::RemainingMipLevels ) @@ -444,6 +453,8 @@ void TextureBase<BaseInterface, TRenderDeviceImpl, TTextureViewImpl, TTexViewObj TextureViewDesc ViewDesc; ViewDesc.ViewType = TEXTURE_VIEW_SHADER_RESOURCE; ITextureView *pSRV = nullptr; + if ((this->m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) != 0) + ViewDesc.Flags |= TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION; CreateViewInternal( ViewDesc, &pSRV, true ); m_pDefaultSRV.reset( static_cast<TTextureViewImpl*>(pSRV) ); VERIFY( m_pDefaultSRV->GetDesc().ViewType == TEXTURE_VIEW_SHADER_RESOURCE, "Unexpected view type" ); diff --git a/Graphics/GraphicsEngine/include/TextureViewBase.h b/Graphics/GraphicsEngine/include/TextureViewBase.h index f035e2e7..1c96a0fd 100644 --- a/Graphics/GraphicsEngine/include/TextureViewBase.h +++ b/Graphics/GraphicsEngine/include/TextureViewBase.h @@ -118,14 +118,14 @@ public: protected: /// Strong reference to the sampler - Diligent::RefCntAutoPtr<ISampler> m_pSampler; + RefCntAutoPtr<ISampler> m_pSampler; /// Raw pointer to the texture ITexture* const m_pTexture; /// Strong reference to the texture. Used for non-default views /// to keep the texture alive - Diligent::RefCntAutoPtr<ITexture> m_spTexture; + RefCntAutoPtr<ITexture> m_spTexture; }; } diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index bca337e7..f1c89e58 100644 --- a/Graphics/GraphicsEngine/interface/APIInfo.h +++ b/Graphics/GraphicsEngine/interface/APIInfo.h @@ -26,7 +26,7 @@ /// \file /// Diligent API information -#define DILIGENT_API_VERSION 240022 +#define DILIGENT_API_VERSION 240023 #include "../../../Primitives/interface/BasicTypes.h" diff --git a/Graphics/GraphicsEngine/interface/TextureView.h b/Graphics/GraphicsEngine/interface/TextureView.h index dc03314f..0f6a98b2 100644 --- a/Graphics/GraphicsEngine/interface/TextureView.h +++ b/Graphics/GraphicsEngine/interface/TextureView.h @@ -26,6 +26,7 @@ /// \file /// Definition of the Diligent::ITextureView interface and related data structures +#include "../../../Primitives/interface/FlagEnum.h" #include "DeviceObject.h" namespace Diligent @@ -38,7 +39,7 @@ static constexpr INTERFACE_ID IID_TextureView = { 0x5b2ea04e, 0x8128, 0x45e4, { 0xaa, 0x4d, 0x6d, 0xc7, 0xe7, 0xd, 0xc4, 0x24 } }; /// Describes allowed unordered access view mode -enum UAV_ACCESS_FLAG : Int32 +enum UAV_ACCESS_FLAG : Uint8 { /// Access mode is unspecified UAV_ACCESS_UNSPECIFIED = 0x00, @@ -52,6 +53,20 @@ enum UAV_ACCESS_FLAG : Int32 /// Allow read and write operations on the UAV UAV_ACCESS_FLAG_READ_WRITE = UAV_ACCESS_FLAG_READ | UAV_ACCESS_FLAG_WRITE }; +DEFINE_FLAG_ENUM_OPERATORS(UAV_ACCESS_FLAG) + +/// Texture view flags +enum TEXTURE_VIEW_FLAGS : Uint8 +{ + /// No flags + TEXTURE_VIEW_FLAG_NONE = 0x00, + + /// Allow automatic mipmap generation for this view. + /// This flag is only allowed for TEXTURE_VIEW_SHADER_RESOURCE view type. + /// The texture must be created with MISC_TEXTURE_FLAG_GENERATE_MIPS flag. + TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION = 0x01, +}; +DEFINE_FLAG_ENUM_OPERATORS(TEXTURE_VIEW_FLAGS) /// Texture view description struct TextureViewDesc : DeviceObjectAttribs @@ -105,7 +120,10 @@ struct TextureViewDesc : DeviceObjectAttribs /// For an unordered access view, allowed access flags. See Diligent::UAV_ACCESS_FLAG /// for details. - Uint32 AccessFlags = 0; + UAV_ACCESS_FLAG AccessFlags = UAV_ACCESS_UNSPECIFIED; + + /// Texture view flags, see Diligent::TEXTURE_VIEW_FLAGS. + TEXTURE_VIEW_FLAGS Flags = TEXTURE_VIEW_FLAG_NONE; TextureViewDesc()noexcept{} @@ -116,7 +134,8 @@ struct TextureViewDesc : DeviceObjectAttribs Uint32 _NumMipLevels = TextureViewDesc{}.NumMipLevels, Uint32 _FirstArrayOrDepthSlice = TextureViewDesc{}.FirstArraySlice, Uint32 _NumArrayOrDepthSlices = TextureViewDesc{}.NumArraySlices, - Uint32 _AccessFlags = TextureViewDesc{}.AccessFlags)noexcept : + UAV_ACCESS_FLAG _AccessFlags = TextureViewDesc{}.AccessFlags, + TEXTURE_VIEW_FLAGS _Flags = TextureViewDesc{}.Flags)noexcept : ViewType (_ViewType), TextureDim (_TextureDim), Format (_Format), @@ -124,7 +143,8 @@ struct TextureViewDesc : DeviceObjectAttribs NumMipLevels (_NumMipLevels), FirstArraySlice (_FirstArrayOrDepthSlice), NumArraySlices (_NumArrayOrDepthSlices), - AccessFlags (_AccessFlags) + AccessFlags (_AccessFlags), + Flags (_Flags) {} /// Tests if two structures are equivalent diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp index 976d8983..5d9f19ae 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp @@ -37,18 +37,18 @@ D3D12DynamicPage::D3D12DynamicPage(ID3D12Device* pd3d12Device, Uint64 Size) HeapProps.VisibleNodeMask = 1; D3D12_RESOURCE_DESC ResourceDesc; - ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - ResourceDesc.Alignment = 0; - ResourceDesc.Height = 1; - ResourceDesc.DepthOrArraySize = 1; - ResourceDesc.MipLevels = 1; - ResourceDesc.Format = DXGI_FORMAT_UNKNOWN; - ResourceDesc.SampleDesc.Count = 1; + ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + ResourceDesc.Alignment = 0; + ResourceDesc.Height = 1; + ResourceDesc.DepthOrArraySize = 1; + ResourceDesc.MipLevels = 1; + ResourceDesc.Format = DXGI_FORMAT_UNKNOWN; + ResourceDesc.SampleDesc.Count = 1; ResourceDesc.SampleDesc.Quality = 0; - ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; D3D12_RESOURCE_STATES DefaultUsage = D3D12_RESOURCE_STATE_GENERIC_READ; - HeapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + HeapProps.Type = D3D12_HEAP_TYPE_UPLOAD; ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; DefaultUsage = D3D12_RESOURCE_STATE_GENERIC_READ; ResourceDesc.Width = Size; diff --git a/Graphics/GraphicsEngineD3DBase/include/D3DViewDescConversionImpl.h b/Graphics/GraphicsEngineD3DBase/include/D3DViewDescConversionImpl.h index 461d637e..fe2bef9f 100644 --- a/Graphics/GraphicsEngineD3DBase/include/D3DViewDescConversionImpl.h +++ b/Graphics/GraphicsEngineD3DBase/include/D3DViewDescConversionImpl.h @@ -41,16 +41,16 @@ namespace Diligent switch (SRVDesc.TextureDim) { case RESOURCE_DIM_TEX_1D: - d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1D; - d3dSRVDesc.Texture1D.MipLevels = SRVDesc.NumMipLevels; + d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1D; + d3dSRVDesc.Texture1D.MipLevels = SRVDesc.NumMipLevels; d3dSRVDesc.Texture1D.MostDetailedMip = SRVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_1D_ARRAY: - d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1DARRAY; - d3dSRVDesc.Texture1DArray.ArraySize = SRVDesc.NumArraySlices; + d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1DARRAY; + d3dSRVDesc.Texture1DArray.ArraySize = SRVDesc.NumArraySlices; d3dSRVDesc.Texture1DArray.FirstArraySlice = SRVDesc.FirstArraySlice; - d3dSRVDesc.Texture1DArray.MipLevels = SRVDesc.NumMipLevels; + d3dSRVDesc.Texture1DArray.MipLevels = SRVDesc.NumMipLevels; d3dSRVDesc.Texture1DArray.MostDetailedMip = SRVDesc.MostDetailedMip; break; @@ -62,8 +62,8 @@ namespace Diligent } else { - d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2D; - d3dSRVDesc.Texture2D.MipLevels = SRVDesc.NumMipLevels; + d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2D; + d3dSRVDesc.Texture2D.MipLevels = SRVDesc.NumMipLevels; d3dSRVDesc.Texture2D.MostDetailedMip = SRVDesc.MostDetailedMip; } break; @@ -71,38 +71,38 @@ namespace Diligent case RESOURCE_DIM_TEX_2D_ARRAY: if( SampleCount > 1 ) { - d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DMSARRAY; - d3dSRVDesc.Texture2DMSArray.ArraySize = SRVDesc.NumArraySlices; + d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DMSARRAY; + d3dSRVDesc.Texture2DMSArray.ArraySize = SRVDesc.NumArraySlices; d3dSRVDesc.Texture2DMSArray.FirstArraySlice = SRVDesc.FirstArraySlice; } else { - d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DARRAY; - d3dSRVDesc.Texture2DArray.ArraySize = SRVDesc.NumArraySlices; + d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DARRAY; + d3dSRVDesc.Texture2DArray.ArraySize = SRVDesc.NumArraySlices; d3dSRVDesc.Texture2DArray.FirstArraySlice = SRVDesc.FirstArraySlice; - d3dSRVDesc.Texture2DArray.MipLevels = SRVDesc.NumMipLevels; + d3dSRVDesc.Texture2DArray.MipLevels = SRVDesc.NumMipLevels; d3dSRVDesc.Texture2DArray.MostDetailedMip = SRVDesc.MostDetailedMip; } break; case RESOURCE_DIM_TEX_3D: - d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE3D; - d3dSRVDesc.Texture3D.MipLevels = SRVDesc.NumMipLevels; + d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE3D; + d3dSRVDesc.Texture3D.MipLevels = SRVDesc.NumMipLevels; d3dSRVDesc.Texture3D.MostDetailedMip = SRVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_CUBE: - d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBE; - d3dSRVDesc.TextureCube.MipLevels = SRVDesc.NumMipLevels; + d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBE; + d3dSRVDesc.TextureCube.MipLevels = SRVDesc.NumMipLevels; d3dSRVDesc.TextureCube.MostDetailedMip = SRVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_CUBE_ARRAY: - d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBEARRAY; - d3dSRVDesc.TextureCubeArray.MipLevels = SRVDesc.NumMipLevels; - d3dSRVDesc.TextureCubeArray.MostDetailedMip = SRVDesc.MostDetailedMip; + d3dSRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBEARRAY; + d3dSRVDesc.TextureCubeArray.MipLevels = SRVDesc.NumMipLevels; + d3dSRVDesc.TextureCubeArray.MostDetailedMip = SRVDesc.MostDetailedMip; d3dSRVDesc.TextureCubeArray.First2DArrayFace = SRVDesc.FirstArraySlice; - d3dSRVDesc.TextureCubeArray.NumCubes = SRVDesc.NumArraySlices / 6; + d3dSRVDesc.TextureCubeArray.NumCubes = SRVDesc.NumArraySlices / 6; break; default: @@ -119,27 +119,27 @@ namespace Diligent switch(RTVDesc.TextureDim) { case RESOURCE_DIM_TEX_1D: - d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE1D; + d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE1D; d3dRTVDesc.Texture1D.MipSlice = RTVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_1D_ARRAY: d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE1DARRAY; - d3dRTVDesc.Texture1DArray.ArraySize = RTVDesc.NumArraySlices; + d3dRTVDesc.Texture1DArray.ArraySize = RTVDesc.NumArraySlices; d3dRTVDesc.Texture1DArray.FirstArraySlice = RTVDesc.FirstArraySlice; - d3dRTVDesc.Texture1DArray.MipSlice = RTVDesc.MostDetailedMip; + d3dRTVDesc.Texture1DArray.MipSlice = RTVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_2D: if( SampleCount > 1 ) { - d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE2DMS; + d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE2DMS; d3dRTVDesc.Texture2DMS.UnusedField_NothingToDefine = 0; } else { - d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE2D; + d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE2D; d3dRTVDesc.Texture2D.MipSlice = RTVDesc.MostDetailedMip; } break; @@ -153,18 +153,18 @@ namespace Diligent } else { - d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE2DARRAY; - d3dRTVDesc.Texture2DArray.ArraySize = RTVDesc.NumArraySlices; + d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE2DARRAY; + d3dRTVDesc.Texture2DArray.ArraySize = RTVDesc.NumArraySlices; d3dRTVDesc.Texture2DArray.FirstArraySlice = RTVDesc.FirstArraySlice; - d3dRTVDesc.Texture2DArray.MipSlice = RTVDesc.MostDetailedMip; + d3dRTVDesc.Texture2DArray.MipSlice = RTVDesc.MostDetailedMip; } break; case RESOURCE_DIM_TEX_3D: - d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE3D; + d3dRTVDesc.ViewDimension = D3D_RTV_DIMENSION_TEXTURE3D; d3dRTVDesc.Texture3D.FirstWSlice = RTVDesc.FirstDepthSlice; - d3dRTVDesc.Texture3D.WSize = RTVDesc.NumDepthSlices; - d3dRTVDesc.Texture3D.MipSlice = RTVDesc.MostDetailedMip; + d3dRTVDesc.Texture3D.WSize = RTVDesc.NumDepthSlices; + d3dRTVDesc.Texture3D.MipSlice = RTVDesc.MostDetailedMip; break; default: @@ -181,27 +181,27 @@ namespace Diligent switch(DSVDesc.TextureDim) { case RESOURCE_DIM_TEX_1D: - d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE1D; + d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE1D; d3dDSVDesc.Texture1D.MipSlice = DSVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_1D_ARRAY: - d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE1DARRAY; - d3dDSVDesc.Texture1DArray.ArraySize = DSVDesc.NumArraySlices; + d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE1DARRAY; + d3dDSVDesc.Texture1DArray.ArraySize = DSVDesc.NumArraySlices; d3dDSVDesc.Texture1DArray.FirstArraySlice = DSVDesc.FirstArraySlice; - d3dDSVDesc.Texture1DArray.MipSlice = DSVDesc.MostDetailedMip; + d3dDSVDesc.Texture1DArray.MipSlice = DSVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_2D: if( SampleCount > 1 ) { - d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE2DMS; + d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE2DMS; d3dDSVDesc.Texture2DMS.UnusedField_NothingToDefine = 0; } else { - d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE2D; + d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE2D; d3dDSVDesc.Texture2D.MipSlice = DSVDesc.MostDetailedMip; } break; @@ -209,16 +209,16 @@ namespace Diligent case RESOURCE_DIM_TEX_2D_ARRAY: if( SampleCount > 1 ) { - d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE2DMSARRAY; - d3dDSVDesc.Texture2DMSArray.ArraySize = DSVDesc.NumArraySlices; + d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE2DMSARRAY; + d3dDSVDesc.Texture2DMSArray.ArraySize = DSVDesc.NumArraySlices; d3dDSVDesc.Texture2DMSArray.FirstArraySlice = DSVDesc.FirstArraySlice; } else { - d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE2DARRAY; - d3dDSVDesc.Texture2DArray.ArraySize = DSVDesc.NumArraySlices; + d3dDSVDesc.ViewDimension = D3D_DSV_DIMENSION_TEXTURE2DARRAY; + d3dDSVDesc.Texture2DArray.ArraySize = DSVDesc.NumArraySlices; d3dDSVDesc.Texture2DArray.FirstArraySlice = DSVDesc.FirstArraySlice; - d3dDSVDesc.Texture2DArray.MipSlice = DSVDesc.MostDetailedMip; + d3dDSVDesc.Texture2DArray.MipSlice = DSVDesc.MostDetailedMip; } break; @@ -240,34 +240,34 @@ namespace Diligent switch(UAVDesc.TextureDim) { case RESOURCE_DIM_TEX_1D: - d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE1D; + d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE1D; d3dUAVDesc.Texture1D.MipSlice = UAVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_1D_ARRAY: - d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE1DARRAY; - d3dUAVDesc.Texture1DArray.ArraySize = UAVDesc.NumArraySlices; + d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE1DARRAY; + d3dUAVDesc.Texture1DArray.ArraySize = UAVDesc.NumArraySlices; d3dUAVDesc.Texture1DArray.FirstArraySlice = UAVDesc.FirstArraySlice; - d3dUAVDesc.Texture1DArray.MipSlice = UAVDesc.MostDetailedMip; + d3dUAVDesc.Texture1DArray.MipSlice = UAVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_2D: - d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE2D; + d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE2D; d3dUAVDesc.Texture2D.MipSlice = UAVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_2D_ARRAY: - d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE2DARRAY; - d3dUAVDesc.Texture2DArray.ArraySize = UAVDesc.NumArraySlices; + d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE2DARRAY; + d3dUAVDesc.Texture2DArray.ArraySize = UAVDesc.NumArraySlices; d3dUAVDesc.Texture2DArray.FirstArraySlice = UAVDesc.FirstArraySlice; - d3dUAVDesc.Texture2DArray.MipSlice = UAVDesc.MostDetailedMip; + d3dUAVDesc.Texture2DArray.MipSlice = UAVDesc.MostDetailedMip; break; case RESOURCE_DIM_TEX_3D: - d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE3D; + d3dUAVDesc.ViewDimension = D3D_UAV_DIMENSION_TEXTURE3D; d3dUAVDesc.Texture3D.FirstWSlice = UAVDesc.FirstDepthSlice; - d3dUAVDesc.Texture3D.WSize = UAVDesc.NumDepthSlices; - d3dUAVDesc.Texture3D.MipSlice = UAVDesc.MostDetailedMip; + d3dUAVDesc.Texture3D.WSize = UAVDesc.NumDepthSlices; + d3dUAVDesc.Texture3D.MipSlice = UAVDesc.MostDetailedMip; break; default: diff --git a/Graphics/GraphicsEngineVulkan/include/GenerateMipsVkHelper.h b/Graphics/GraphicsEngineVulkan/include/GenerateMipsVkHelper.h index 4c878ae7..17b20d4b 100644 --- a/Graphics/GraphicsEngineVulkan/include/GenerateMipsVkHelper.h +++ b/Graphics/GraphicsEngineVulkan/include/GenerateMipsVkHelper.h @@ -49,11 +49,15 @@ namespace Diligent void GenerateMips(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB); void CreateSRB(IShaderResourceBinding** ppSRB); + void WarmUpCache(TEXTURE_FORMAT Fmt); private: std::array<RefCntAutoPtr<IPipelineState>, 4> CreatePSOs(TEXTURE_FORMAT Fmt); std::array<RefCntAutoPtr<IPipelineState>, 4>& FindPSOs (TEXTURE_FORMAT Fmt); + VkImageLayout GenerateMipsCS (TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange); + VkImageLayout GenerateMipsBlit(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange); + RenderDeviceVkImpl& m_DeviceVkImpl; std::mutex m_PSOMutex; diff --git a/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h index 8989c245..2e69e34e 100644 --- a/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h @@ -54,9 +54,36 @@ public: VkImageView GetVulkanImageView()const override final{return m_ImageView;} + bool HasMipLevelViews() const + { + return m_MipLevelViews != nullptr; + } + + TextureViewVkImpl* GetMipLevelSRV(Uint32 MipLevel) + { + VERIFY_EXPR(m_MipLevelViews != nullptr && MipLevel < m_Desc.NumMipLevels); + return m_MipLevelViews[MipLevel*2].get(); + } + + TextureViewVkImpl* GetMipLevelUAV(Uint32 MipLevel) + { + VERIFY_EXPR(m_MipLevelViews != nullptr && MipLevel < m_Desc.NumMipLevels); + return m_MipLevelViews[MipLevel*2 + 1].get(); + } + + using MipLevelViewAutoPtrType = std::unique_ptr<TextureViewVkImpl, STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator> >; + + void AssignMipLevelViews(MipLevelViewAutoPtrType* MipLevelViews) + { + m_MipLevelViews = MipLevelViews; + } + protected: /// Vulkan image view descriptor handle - VulkanUtilities::ImageViewWrapper m_ImageView; + VulkanUtilities::ImageViewWrapper m_ImageView; + + /// Individual mip level views used for mipmap generation + MipLevelViewAutoPtrType* m_MipLevelViews = nullptr; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h index 33f07b79..d3d0883a 100644 --- a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h @@ -83,17 +83,6 @@ public: return vkImage; } - ITextureView* GetMipLevelSRV(Uint32 MipLevel) - { - return m_MipLevelSRV[MipLevel].get(); - } - - ITextureView* GetMipLevelUAV(Uint32 MipLevel) - { - return m_MipLevelUAV[MipLevel].get(); - } - - void SetLayout(VkImageLayout Layout)override final; VkImageLayout GetLayout()const override final; @@ -116,16 +105,15 @@ protected: void CreateViewInternal( const struct TextureViewDesc& ViewDesc, ITextureView** ppView, bool bIsDefaultView )override; //void PrepareVkInitData(const TextureData &InitData, Uint32 NumSubresources, std::vector<Vk_SUBRESOURCE_DATA> &VkInitData); + bool CheckCSBasedMipGenerationSupport(VkFormat vkFmt)const; + VulkanUtilities::ImageViewWrapper CreateImageView(TextureViewDesc &ViewDesc); VulkanUtilities::ImageWrapper m_VulkanImage; VulkanUtilities::BufferWrapper m_StagingBuffer; VulkanUtilities::VulkanMemoryAllocation m_MemoryAllocation; VkDeviceSize m_StagingDataAlignedOffset; - - // Texture views needed for mipmap generation - std::vector<std::unique_ptr<TextureViewVkImpl, STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator> > > m_MipLevelSRV; - std::vector<std::unique_ptr<TextureViewVkImpl, STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator> > > m_MipLevelUAV; + bool m_bCSBasedMipGenerationSupported = false; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h index 3d35c581..8fc47e3b 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h @@ -394,6 +394,24 @@ namespace VulkanUtilities vkCmdCopyImageToBuffer(m_VkCmdBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions); } + void BlitImage(VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit* pRegions, + VkFilter filter) + { + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + if (m_State.RenderPass != VK_NULL_HANDLE) + { + // Blit must be performed outside of render pass. + EndRenderPass(); + } + + vkCmdBlitImage(m_VkCmdBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter); + } + void FlushBarriers(); void SetVkCmdBuffer(VkCommandBuffer VkCmdBuffer) diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h index 7056268f..a264c80c 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h @@ -48,6 +48,7 @@ namespace VulkanUtilities uint32_t GetMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties)const; const VkPhysicalDeviceProperties& GetProperties() const {return m_Properties;} const VkPhysicalDeviceFeatures& GetFeatures() const {return m_Features; } + VkFormatProperties GetPhysicalDeviceFormatProperties(VkFormat imageFormat)const; private: VulkanPhysicalDevice(VkPhysicalDevice vkDevice); diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 384a342d..03eb0992 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -2023,7 +2023,11 @@ namespace Diligent void DeviceContextVkImpl::TransitionImageLayout(TextureVkImpl& TextureVk, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange) { - VERIFY(TextureVk.GetLayout() != NewLayout, "The texture is already transitioned to correct layout"); + // Note that the method may be used to transition texture subresources when global texture state is not altered, + // so the debug check below can't be used + // VERIFY(!TextureVk.IsInKnownState() || TextureVk.GetLayout() != NewLayout, "The texture is already transitioned to correct layout"); + + VERIFY(OldLayout != NewLayout, "Old and new layouts are the same"); EnsureVkCmdBuffer(); auto vkImg = TextureVk.GetVkImage(); m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, SubresRange); diff --git a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp index 3f4a716c..58b2b122 100644 --- a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp +++ b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp @@ -176,8 +176,6 @@ namespace Diligent FindPSOs(TEX_FORMAT_RGBA8_UNORM); FindPSOs(TEX_FORMAT_BGRA8_UNORM); - FindPSOs(TEX_FORMAT_RGBA8_UNORM_SRGB); - FindPSOs(TEX_FORMAT_BGRA8_UNORM_SRGB); } void GenerateMipsVkHelper::CreateSRB(IShaderResourceBinding** ppSRB) @@ -196,31 +194,29 @@ namespace Diligent return it->second; } + void GenerateMipsVkHelper::WarmUpCache(TEXTURE_FORMAT Fmt) + { + FindPSOs(Fmt); + } + void GenerateMipsVkHelper::GenerateMips(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB) { auto* pTexVk = TexView.GetTexture<TextureVkImpl>(); - const auto& TexDesc = pTexVk->GetDesc(); - if (!pTexVk->IsInKnownState()) { - LOG_ERROR_MESSAGE("Unable to generate mips for texture '", TexDesc.Name, "' because the texture state is unknown"); + LOG_ERROR_MESSAGE("Unable to generate mips for texture '", pTexVk->GetDesc().Name, "' because the texture state is unknown"); return; } - const auto& ViewDesc = TexView.GetDesc(); - auto* pSrcMipVar = SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "SrcMip"); - IShaderResourceVariable* pOutMipVar[4] = - { - SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip0"), - SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip1"), - SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip2"), - SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip3") - }; + DEV_CHECK_ERR(TexView.GetDesc().NumMipLevels > 1, "Number of mip levels in the view must be greater than 1"); - auto& PSOs = FindPSOs(ViewDesc.Format); + const auto OriginalState = pTexVk->GetState(); + const auto OriginalLayout = pTexVk->GetLayout(); + const auto& TexDesc = pTexVk->GetDesc(); + const auto& ViewDesc = TexView.GetDesc(); - const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); - VkImageSubresourceRange SubresRange; + const auto& FmtAttribs = GetTextureFormatAttribs(ViewDesc.Format); + VkImageSubresourceRange SubresRange = {}; if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) SubresRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) @@ -232,27 +228,84 @@ namespace Diligent } else SubresRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - SubresRange.baseArrayLayer = 0; - SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + SubresRange.baseArrayLayer = ViewDesc.FirstArraySlice; + SubresRange.layerCount = ViewDesc.NumArraySlices; + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; + SubresRange.levelCount = 1; + + VkImageLayout AffectedMipLevelLayout; + if (TexView.HasMipLevelViews()) + { + AffectedMipLevelLayout = GenerateMipsCS(TexView, Ctx, SRB, SubresRange); + } + else + { + AffectedMipLevelLayout = GenerateMipsBlit(TexView, Ctx, SRB, SubresRange); + } + + // All affected mip levels are now in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL state + if (AffectedMipLevelLayout != OriginalLayout) + { + 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) + { + pTexVk->SetLayout(AffectedMipLevelLayout); + } + else + { + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; + SubresRange.levelCount = ViewDesc.NumMipLevels; + // Transition all affected subresources back to original layout + Ctx.TransitionImageLayout(*pTexVk, AffectedMipLevelLayout, OriginalLayout, SubresRange); + VERIFY_EXPR(pTexVk->GetLayout() == OriginalLayout); + } + } + } + + VkImageLayout GenerateMipsVkHelper::GenerateMipsCS(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange) + { + auto* pTexVk = TexView.GetTexture<TextureVkImpl>(); + const auto& TexDesc = pTexVk->GetDesc(); + + VERIFY(TexDesc.Type == RESOURCE_DIM_TEX_2D || TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY, + "CS-based mipmap generation is only supported for 2D textures and texture arrays"); + + const auto& ViewDesc = TexView.GetDesc(); + auto* pSrcMipVar = SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "SrcMip"); + IShaderResourceVariable* pOutMipVar[4] = + { + SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip0"), + SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip1"), + SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip2"), + SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip3") + }; + + auto& PSOs = FindPSOs(ViewDesc.Format); - const auto CurrState = pTexVk->GetState(); - const auto CurrLayout = ResourceStateToVkImageLayout(CurrState); + const auto OriginalState = pTexVk->GetState(); + const auto OriginalLayout = pTexVk->GetLayout(); // Transition the lowest mip level to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - SubresRange.baseMipLevel = 0; - SubresRange.levelCount = 1; - if (CurrState != RESOURCE_STATE_SHADER_RESOURCE) - Ctx.TransitionTextureState(*pTexVk, CurrState, RESOURCE_STATE_SHADER_RESOURCE, false, &SubresRange); + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; + SubresRange.levelCount = 1; + if (OriginalState != RESOURCE_STATE_SHADER_RESOURCE) + Ctx.TransitionTextureState(*pTexVk, OriginalState, RESOURCE_STATE_SHADER_RESOURCE, false /*UpdateTextureState*/, &SubresRange); VERIFY_EXPR(ResourceStateToVkImageLayout(RESOURCE_STATE_SHADER_RESOURCE) == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - for (uint32_t TopMip = 0; TopMip < TexDesc.MipLevels - 1; ) + // Note that mip levels are relative to the view's most detailed mip + auto LowestMip = ViewDesc.NumMipLevels - 1; + for (uint32_t TopMip = 0; TopMip < LowestMip; ) { // In Vulkan all subresources of a view must be transitioned to the same layout, so // we can't bind the entire texture and have to bind single mip level at a time - pSrcMipVar->Set(pTexVk->GetMipLevelSRV(TopMip)); + pSrcMipVar->Set(TexView.GetMipLevelSRV(TopMip)); - 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); @@ -268,8 +321,8 @@ namespace Diligent // in the low bits. Zeros indicate we can divide by two without truncating. uint32_t AdditionalMips = PlatformMisc::GetLSB(DstWidth | DstHeight); uint32_t NumMips = 1 + (AdditionalMips > 3 ? 3 : AdditionalMips); - if (TopMip + NumMips > TexDesc.MipLevels - 1) - NumMips = TexDesc.MipLevels - 1 - TopMip; + if (TopMip + NumMips > LowestMip) + NumMips = LowestMip - TopMip; // These are clamped to 1 after computing additional mips because clamped // dimensions should not limit us from downsampling multiple times. (E.g. @@ -286,7 +339,7 @@ namespace Diligent Int32 NumMipLevels; // Number of OutMips to write: [1, 4] Int32 ArraySlice; Int32 Dummy; - float TexelSize[2]; // 1.0 / OutMip1.Dimensions + float TexelSize[2]; // 1.0 / OutMip1.Dimensions }; MapHelper<CBData> MappedData(&Ctx, m_ConstantsCB, MAP_WRITE, MAP_FLAG_DISCARD); @@ -294,8 +347,8 @@ namespace Diligent { static_cast<Int32>(TopMip), static_cast<Int32>(NumMips), - static_cast<Int32>(ViewDesc.FirstArraySlice), - 0, + 0, // Array slices are relative to the view's first array slice + 0, // Unused {1.0f / static_cast<float>(DstWidth), 1.0f / static_cast<float>(DstHeight)} }; } @@ -303,14 +356,14 @@ namespace Diligent constexpr const Uint32 MaxMipsHandledByCS = 4; // Max number of mip levels processed by one CS shader invocation for (Uint32 u = 0; u < MaxMipsHandledByCS; ++u) { - auto* MipLevelUAV = pTexVk->GetMipLevelUAV(std::min(TopMip + u + 1, TexDesc.MipLevels - 1)); + auto* MipLevelUAV = TexView.GetMipLevelUAV(std::min(TopMip + u + 1, LowestMip)); pOutMipVar[u]->Set(MipLevelUAV); } - SubresRange.baseMipLevel = TopMip + 1; - SubresRange.levelCount = std::min(4u, TexDesc.MipLevels - (TopMip + 1)); - if (CurrLayout != VK_IMAGE_LAYOUT_GENERAL) - Ctx.TransitionImageLayout(*pTexVk, CurrLayout, VK_IMAGE_LAYOUT_GENERAL, SubresRange); + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip + TopMip + 1; + SubresRange.levelCount = std::min(4u, LowestMip - TopMip); + if (OriginalLayout != VK_IMAGE_LAYOUT_GENERAL) + Ctx.TransitionImageLayout(*pTexVk, OriginalLayout, VK_IMAGE_LAYOUT_GENERAL, SubresRange); Ctx.CommitShaderResources(&SRB, RESOURCE_STATE_TRANSITION_MODE_NONE); DispatchComputeAttribs DispatchAttrs((DstWidth + 7) / 8, (DstHeight + 7) / 8, ViewDesc.NumArraySlices); @@ -321,8 +374,74 @@ namespace Diligent TopMip += NumMips; } - // All mip levels are now in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL state - pTexVk->SetState(RESOURCE_STATE_SHADER_RESOURCE); - VERIFY_EXPR(pTexVk->GetLayout() == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + VkImageLayout GenerateMipsVkHelper::GenerateMipsBlit(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange) + { + auto* pTexVk = TexView.GetTexture<TextureVkImpl>(); + const auto& TexDesc = pTexVk->GetDesc(); + const auto& ViewDesc = TexView.GetDesc(); + auto vkImage = pTexVk->GetVkImage(); + + const auto OriginalState = pTexVk->GetState(); + const auto OriginalLayout = ResourceStateToVkImageLayout(OriginalState); + + VkImageBlit BlitRegion = {}; + BlitRegion.srcSubresource.baseArrayLayer = ViewDesc.FirstArraySlice; + BlitRegion.srcSubresource.layerCount = ViewDesc.NumArraySlices; + BlitRegion.srcSubresource.aspectMask = SubresRange.aspectMask; + BlitRegion.dstSubresource.baseArrayLayer = BlitRegion.srcSubresource.baseArrayLayer; + BlitRegion.dstSubresource.layerCount = BlitRegion.srcSubresource.layerCount; + BlitRegion.dstSubresource.aspectMask = BlitRegion.srcSubresource.aspectMask; + BlitRegion.srcOffsets[0] = VkOffset3D{0, 0, 0}; + BlitRegion.dstOffsets[0] = VkOffset3D{0, 0, 0}; + + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; + SubresRange.levelCount = 1; + if (OriginalState != RESOURCE_STATE_COPY_SOURCE) + Ctx.TransitionTextureState(*pTexVk, OriginalState, RESOURCE_STATE_COPY_SOURCE, false /*UpdateTextureState*/, &SubresRange); + + auto& CmdBuffer = Ctx.GetCommandBuffer(); + for (uint32_t mip = ViewDesc.MostDetailedMip + 1; mip < ViewDesc.MostDetailedMip + ViewDesc.NumMipLevels; ++mip) + { + BlitRegion.srcSubresource.mipLevel = mip-1; + BlitRegion.dstSubresource.mipLevel = mip; + + BlitRegion.srcOffsets[1] = + VkOffset3D + { + static_cast<int32_t>(std::max(TexDesc.Width >> (mip-1), 1u)), + static_cast<int32_t>(std::max(TexDesc.Height >> (mip-1), 1u)), + 1 + }; + BlitRegion.dstOffsets[1] = + VkOffset3D + { + static_cast<int32_t>(std::max(TexDesc.Width >> mip, 1u)), + static_cast<int32_t>(std::max(TexDesc.Height >> mip, 1u)), + 1 + }; + if (TexDesc.Type == RESOURCE_DIM_TEX_3D) + { + BlitRegion.srcOffsets[1].z = std::max(TexDesc.Depth >> (mip-1), 1u); + BlitRegion.dstOffsets[1].z = std::max(TexDesc.Depth >> mip, 1u); + } + + SubresRange.baseMipLevel = mip; + if (OriginalLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + Ctx.TransitionImageLayout(*pTexVk, OriginalLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange); + + CmdBuffer.BlitImage(vkImage, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL + vkImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL + 1, + &BlitRegion, + VK_FILTER_LINEAR); + Ctx.TransitionImageLayout(*pTexVk, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, SubresRange); + } + + return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; } } diff --git a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp index f12d217a..8ad690fa 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp @@ -34,14 +34,24 @@ TextureViewVkImpl::TextureViewVkImpl( IReferenceCounters* pRefCo const TextureViewDesc& ViewDesc, ITexture* pTexture, VulkanUtilities::ImageViewWrapper&& ImgView, - bool bIsDefaultView ) : + bool bIsDefaultView) : TTextureViewBase( pRefCounters, pDevice, ViewDesc, pTexture, bIsDefaultView ), - m_ImageView(std::move(ImgView)) + m_ImageView (std::move(ImgView)) { } TextureViewVkImpl::~TextureViewVkImpl() { + if (m_MipLevelViews != nullptr) + { + for (Uint32 MipView=0; MipView < m_Desc.NumMipLevels * 2; ++MipView) + { + m_MipLevelViews[MipView].~MipLevelViewAutoPtrType(); + } + // Memory allocated in TextureVkImpl::CreateViewInternal() + GetRawAllocator().Free(m_MipLevelViews); + } + if(m_Desc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL || m_Desc.ViewType == TEXTURE_VIEW_RENDER_TARGET) m_pDevice->GetFramebufferCache().OnDestroyImageView(m_ImageView); m_pDevice->SafeReleaseDeviceObject(std::move(m_ImageView), m_pTexture->GetDesc().CommandQueueMask); diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index 6c4e08a0..4d05b81f 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -69,9 +69,6 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, 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, "'"); - const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); if (m_Desc.Usage == USAGE_STATIC || m_Desc.Usage == USAGE_DEFAULT || m_Desc.Usage == USAGE_DYNAMIC) @@ -100,28 +97,26 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, LOG_ERROR_AND_THROW("Unknown texture type"); } + TEXTURE_FORMAT InternalTexFmt = m_Desc.Format; if (FmtAttribs.IsTypeless) { - TEXTURE_VIEW_TYPE DefaultTexView; - if(m_Desc.BindFlags & BIND_DEPTH_STENCIL) - DefaultTexView = TEXTURE_VIEW_DEPTH_STENCIL; + TEXTURE_VIEW_TYPE PrimaryViewType; + if (m_Desc.BindFlags & BIND_DEPTH_STENCIL) + PrimaryViewType = TEXTURE_VIEW_DEPTH_STENCIL; else if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS) - DefaultTexView = TEXTURE_VIEW_UNORDERED_ACCESS; + PrimaryViewType = TEXTURE_VIEW_UNORDERED_ACCESS; else if (m_Desc.BindFlags & BIND_RENDER_TARGET) - DefaultTexView = TEXTURE_VIEW_RENDER_TARGET; + PrimaryViewType = TEXTURE_VIEW_RENDER_TARGET; else - DefaultTexView = TEXTURE_VIEW_SHADER_RESOURCE; - auto DefaultViewFormat = GetDefaultTextureViewFormat(m_Desc, DefaultTexView); - ImageCI.format = TexFormatToVkFormat(DefaultViewFormat); - } - else - { - ImageCI.format = TexFormatToVkFormat(m_Desc.Format); + PrimaryViewType = TEXTURE_VIEW_SHADER_RESOURCE; + InternalTexFmt = GetDefaultTextureViewFormat(m_Desc, PrimaryViewType); } + + ImageCI.format = TexFormatToVkFormat(InternalTexFmt); - ImageCI.extent.width = m_Desc.Width; + ImageCI.extent.width = m_Desc.Width; ImageCI.extent.height = (m_Desc.Type == RESOURCE_DIM_TEX_1D || m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) ? 1 : m_Desc.Height; - ImageCI.extent.depth = (m_Desc.Type == RESOURCE_DIM_TEX_3D) ? m_Desc.Depth : 1; + ImageCI.extent.depth = (m_Desc.Type == RESOURCE_DIM_TEX_3D) ? m_Desc.Depth : 1; ImageCI.mipLevels = m_Desc.MipLevels; if (m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY || @@ -146,7 +141,7 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, // VK_IMAGE_USAGE_TRANSFER_DST_BIT is required for vkCmdClearDepthStencilImage() ImageCI.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; } - if ((m_Desc.BindFlags & BIND_UNORDERED_ACCESS) || (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS)) + if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS) { ImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT; } @@ -155,6 +150,28 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, ImageCI.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; } + if (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) + { + if (CheckCSBasedMipGenerationSupport(ImageCI.format)) + { + ImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT; + m_bCSBasedMipGenerationSupported = true; + // TODO: warm-up generate mips PSO cache + } + else + { + const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice(); + auto FmtProperties = PhysicalDevice.GetPhysicalDeviceFormatProperties(ImageCI.format); (void)FmtProperties; + DEV_CHECK_ERR((FmtProperties.optimalTilingFeatures & (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT)) == (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT), + "Texture format ", GetTextureFormatAttribs(InternalTexFmt).Name, " does not support blitting. " + "Automatic mipmap generation can't be done neither by CS nor by blitting."); + + DEV_CHECK_ERR((FmtProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) != 0, + "Texture format ", GetTextureFormatAttribs(InternalTexFmt).Name, " does not support linear filtering. " + "Automatic mipmap generation can't be done neither by CS nor by blitting."); + } + } + ImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ImageCI.queueFamilyIndexCount = 0; ImageCI.pQueueFamilyIndices = nullptr; @@ -384,60 +401,6 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, Uint32 QueueIndex = 0; pRenderDeviceVk->ExecuteAndDisposeTransientCmdBuff(QueueIndex, vkCmdBuff, std::move(CmdPool)); } - - - 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_MipLevelUAV.reserve(m_Desc.MipLevels); - for(Uint32 MipLevel = 0; MipLevel < m_Desc.MipLevels; ++MipLevel) - { - // Create mip level UAV - TextureViewDesc UAVDesc; - std::stringstream name_ss; - name_ss << "Mip " << MipLevel << " UAV for texture '" << m_Desc.Name << "'"; - auto name = name_ss.str(); - UAVDesc.Name = name.c_str(); - // 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; - ITextureView* pMipUAV = nullptr; - CreateViewInternal( UAVDesc, &pMipUAV, true ); - m_MipLevelUAV.emplace_back(ValidatedCast<TextureViewVkImpl>(pMipUAV), STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator>(TexViewObjAllocator)); - } - VERIFY_EXPR(m_MipLevelUAV.size() == m_Desc.MipLevels); - - m_MipLevelSRV.reserve(m_Desc.MipLevels); - for(Uint32 MipLevel = 0; MipLevel < m_Desc.MipLevels; ++MipLevel) - { - // Create mip level SRV - TextureViewDesc TexArraySRVDesc; - std::stringstream name_ss; - name_ss << "Mip " << MipLevel << " SRV for texture '" << m_Desc.Name << "'"; - auto name = name_ss.str(); - TexArraySRVDesc.Name = name.c_str(); - // Alaways create texture array view - TexArraySRVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY; - TexArraySRVDesc.ViewType = TEXTURE_VIEW_SHADER_RESOURCE; - TexArraySRVDesc.FirstArraySlice = 0; - TexArraySRVDesc.NumArraySlices = m_Desc.ArraySize; - TexArraySRVDesc.MostDetailedMip = MipLevel; - TexArraySRVDesc.NumMipLevels = 1; - ITextureView* pMipLevelSRV = nullptr; - CreateViewInternal( TexArraySRVDesc, &pMipLevelSRV, true ); - m_MipLevelSRV.emplace_back(ValidatedCast<TextureViewVkImpl>(pMipLevelSRV), STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator>(TexViewObjAllocator)); - } - VERIFY_EXPR(m_MipLevelSRV.size() == m_Desc.MipLevels); - } } else if(m_Desc.Usage == USAGE_STAGING) { @@ -549,7 +512,7 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters, IMPLEMENT_QUERY_INTERFACE( TextureVkImpl, IID_TextureVk, TTextureBase ) -void TextureVkImpl::CreateViewInternal( const struct TextureViewDesc &ViewDesc, ITextureView **ppView, bool bIsDefaultView ) +void TextureVkImpl::CreateViewInternal(const TextureViewDesc& ViewDesc, ITextureView** ppView, bool bIsDefaultView) { VERIFY( ppView != nullptr, "View pointer address is null" ); if( !ppView )return; @@ -559,22 +522,71 @@ void TextureVkImpl::CreateViewInternal( const struct TextureViewDesc &ViewDesc, try { - auto &TexViewAllocator = m_pDevice->GetTexViewObjAllocator(); + auto& TexViewAllocator = m_pDevice->GetTexViewObjAllocator(); VERIFY( &TexViewAllocator == &m_dbgTexViewObjAllocator, "Texture view allocator does not match allocator provided during texture initialization" ); auto UpdatedViewDesc = ViewDesc; CorrectTextureViewDesc( UpdatedViewDesc ); VulkanUtilities::ImageViewWrapper ImgView = CreateImageView(UpdatedViewDesc); - auto pViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, bIsDefaultView ? this : nullptr) - (GetDevice(), UpdatedViewDesc, this, std::move(ImgView), bIsDefaultView ); + (GetDevice(), UpdatedViewDesc, this, std::move(ImgView), bIsDefaultView); VERIFY( pViewVk->GetDesc().ViewType == ViewDesc.ViewType, "Incorrect view type" ); - if( bIsDefaultView ) + if (bIsDefaultView) *ppView = pViewVk; else pViewVk->QueryInterface(IID_TextureView, reinterpret_cast<IObject**>(ppView) ); + + + if ((UpdatedViewDesc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0 && + m_bCSBasedMipGenerationSupported && + CheckCSBasedMipGenerationSupport(TexFormatToVkFormat(pViewVk->GetDesc().Format))) + { + auto* pMipLevelViewsRawMem = ALLOCATE(GetRawAllocator(), "Raw memory for mip level views", sizeof(TextureViewVkImpl::MipLevelViewAutoPtrType) * UpdatedViewDesc.NumMipLevels * 2); + auto* pMipLevelViews = reinterpret_cast<TextureViewVkImpl::MipLevelViewAutoPtrType*>(pMipLevelViewsRawMem); + for (Uint32 MipLevel = 0; MipLevel < UpdatedViewDesc.NumMipLevels; ++MipLevel) + { + auto CreateMipLevelView = [&](TEXTURE_VIEW_TYPE ViewType, Uint32 MipLevel, TextureViewVkImpl::MipLevelViewAutoPtrType* ppMipLevelView) + { + TextureViewDesc MipLevelViewDesc = pViewVk->GetDesc(); + // Always create texture array views + std::stringstream name_ss; + name_ss << "Internal " << (ViewType == TEXTURE_VIEW_SHADER_RESOURCE ? "SRV" : "UAV") + << " of mip level " << MipLevel << " of texture view '" << pViewVk->GetDesc().Name << "'"; + auto name = name_ss.str(); + MipLevelViewDesc.Name = name.c_str(); + MipLevelViewDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY; + MipLevelViewDesc.ViewType = ViewType; + MipLevelViewDesc.MostDetailedMip += MipLevel; + MipLevelViewDesc.NumMipLevels = 1; + + if (ViewType == TEXTURE_VIEW_UNORDERED_ACCESS) + { + if (MipLevelViewDesc.Format == TEX_FORMAT_RGBA8_UNORM_SRGB) + MipLevelViewDesc.Format = TEX_FORMAT_RGBA8_UNORM; + } + + VulkanUtilities::ImageViewWrapper ImgView = CreateImageView(MipLevelViewDesc); + // Attach to parent view + auto pMipLevelViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, pViewVk) + (GetDevice(), MipLevelViewDesc, this, std::move(ImgView), bIsDefaultView); + new (ppMipLevelView) TextureViewVkImpl::MipLevelViewAutoPtrType(pMipLevelViewVk, STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator>(TexViewAllocator)); + }; + + if ((MipLevel % 4) == 0) + { + // Mip levles are generated 4 at a time, so we only need SRV for every 4-th level + CreateMipLevelView(TEXTURE_VIEW_SHADER_RESOURCE, MipLevel, &pMipLevelViews[MipLevel * 2]); + } + else + { + new (&pMipLevelViews[MipLevel * 2]) TextureViewVkImpl::MipLevelViewAutoPtrType{}; + } + CreateMipLevelView(TEXTURE_VIEW_UNORDERED_ACCESS, MipLevel, &pMipLevelViews[MipLevel * 2 + 1]); + } + pViewVk->AssignMipLevelViews(pMipLevelViews); + } } catch( const std::runtime_error & ) { @@ -638,11 +650,11 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc else { ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_3D; - Uint32 MipDepth = std::max(m_Desc.Depth >> ViewDesc.MostDetailedMip, 1U); + Uint32 MipDepth = std::max(Uint32{m_Desc.Depth} >> Uint32{ViewDesc.MostDetailedMip}, 1U); if (ViewDesc.FirstDepthSlice != 0 || ViewDesc.NumDepthSlices != MipDepth) { - LOG_ERROR("3D texture view '", (ViewDesc.Name ? ViewDesc.Name : ""), "' (most detailed mip: ", ViewDesc.MostDetailedMip, - "; mip levels: ", ViewDesc.NumMipLevels, "; first slice: ", ViewDesc.FirstDepthSlice, + LOG_ERROR("3D texture view '", (ViewDesc.Name ? ViewDesc.Name : ""), "' (most detailed mip: ", Uint32{ViewDesc.MostDetailedMip}, + "; mip levels: ", Uint32{ViewDesc.NumMipLevels}, "; first slice: ", ViewDesc.FirstDepthSlice, "; num depth slices: ", ViewDesc.NumDepthSlices, ") of texture '", m_Desc.Name, "' does not references" " all depth slices (", MipDepth, ") in the mip level. 3D texture views in Vulkan must address all depth slices." ); ViewDesc.FirstDepthSlice = 0; @@ -663,7 +675,7 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc } TEXTURE_FORMAT CorrectedViewFormat = ViewDesc.Format; - if(m_Desc.BindFlags & BIND_DEPTH_STENCIL) + if (m_Desc.BindFlags & BIND_DEPTH_STENCIL) CorrectedViewFormat = GetDefaultTextureViewFormat(CorrectedViewFormat, TEXTURE_VIEW_DEPTH_STENCIL, m_Desc.BindFlags); ImageViewCI.format = TexFormatToVkFormat(CorrectedViewFormat); ImageViewCI.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; @@ -736,6 +748,22 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc return LogicalDevice.CreateImageView(ImageViewCI, ViewName.c_str()); } +bool TextureVkImpl::CheckCSBasedMipGenerationSupport(VkFormat vkFmt)const +{ + VERIFY_EXPR(m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS); + if (m_Desc.Type == RESOURCE_DIM_TEX_2D || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY) + { + const auto& PhysicalDevice = m_pDevice->GetPhysicalDevice(); + auto FmtProperties = PhysicalDevice.GetPhysicalDeviceFormatProperties(vkFmt); + if ((FmtProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0) + { + return true; + } + } + + return false; +} + void TextureVkImpl::SetLayout(VkImageLayout Layout) { SetState(VkImageLayoutToResourceState(Layout)); diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index d9766c52..2a5b010e 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -191,4 +191,11 @@ namespace VulkanUtilities } return InvalidMemoryTypeIndex; } + + VkFormatProperties VulkanPhysicalDevice::GetPhysicalDeviceFormatProperties(VkFormat imageFormat)const + { + VkFormatProperties formatProperties; + vkGetPhysicalDeviceFormatProperties(m_VkDevice, imageFormat, &formatProperties); + return formatProperties; + } } |
