From a78add37a57b51d80ef2fd21a7a0799ba73dd937 Mon Sep 17 00:00:00 2001 From: assiduous Date: Thu, 23 Jul 2020 15:24:54 -0700 Subject: Added Render pass interface stub --- Graphics/GraphicsEngine/CMakeLists.txt | 1 + Graphics/GraphicsEngine/interface/RenderDevice.h | 13 +++ Graphics/GraphicsEngine/interface/RenderPass.h | 123 +++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 Graphics/GraphicsEngine/interface/RenderPass.h (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt index 935aeee9..c3dd8678 100644 --- a/Graphics/GraphicsEngine/CMakeLists.txt +++ b/Graphics/GraphicsEngine/CMakeLists.txt @@ -47,6 +47,7 @@ set(INTERFACE interface/Query.h interface/RasterizerState.h interface/RenderDevice.h + interface/RenderPass.h interface/ResourceMapping.h interface/Sampler.h interface/Shader.h diff --git a/Graphics/GraphicsEngine/interface/RenderDevice.h b/Graphics/GraphicsEngine/interface/RenderDevice.h index 23eae467..24c641bc 100644 --- a/Graphics/GraphicsEngine/interface/RenderDevice.h +++ b/Graphics/GraphicsEngine/interface/RenderDevice.h @@ -46,6 +46,7 @@ #include "PipelineState.h" #include "Fence.h" #include "Query.h" +#include "RenderPass.h" #include "DepthStencilState.h" #include "RasterizerState.h" @@ -188,6 +189,18 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) IQuery** ppQuery) PURE; + /// Creates a render pass object + + /// \param [in] Desc - Render pass description, see Diligent::RenderPassDesc for details. + /// \param [out] ppRenderPass - Address of the memory location where the pointer to the + /// render pass interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + VIRTUAL void METHOD(CreateRenderPass)(THIS_ + const RenderPassDesc REF Desc, + IRenderPass** ppRenderPass) PURE; + + /// Gets the device capabilities, see Diligent::DeviceCaps for details VIRTUAL const DeviceCaps REF METHOD(GetDeviceCaps)(THIS) CONST PURE; diff --git a/Graphics/GraphicsEngine/interface/RenderPass.h b/Graphics/GraphicsEngine/interface/RenderPass.h new file mode 100644 index 00000000..2e7c8b63 --- /dev/null +++ b/Graphics/GraphicsEngine/interface/RenderPass.h @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +// clang-format off + +/// \file +/// Definition of the Diligent::IRenderPass interface and related data structures + +#include "DeviceObject.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {B818DEC7-174D-447A-A8E4-94D21C57B40A} +static const struct INTERFACE_ID IID_RenderPass = + { 0xb818dec7, 0x174d, 0x447a, { 0xa8, 0xe4, 0x94, 0xd2, 0x1c, 0x57, 0xb4, 0xa } }; + + +/// Render pass attachment description. +struct RenderPassAttachmentDesc +{ + int Dummy; +}; +typedef struct RenderPassAttachmentDesc RenderPassAttachmentDesc; + + +/// Render pass subpass decription. +struct SubpassDesc +{ + int Dummy; +}; +typedef struct SubpassDesc SubpassDesc; + + +/// Subpass dependency description +struct SubpassDependencyDesc +{ + int Dummy; +}; +typedef struct SubpassDependencyDesc SubpassDependencyDesc; + +/// Render pass description +struct RenderPassDesc DILIGENT_DERIVE(DeviceObjectAttribs) + + /// The number of attachments. + Uint32 AttachmentCount DEFAULT_INITIALIZER(0); + + /// Pointer to the array of subpass attachments, see Diligent::RenderPassAttachmentDesc. + const RenderPassAttachmentDesc* pAttachments DEFAULT_INITIALIZER(nullptr); + + /// The number of subpasses. + Uint32 SubpassCount DEFAULT_INITIALIZER(0); + + /// Pointer to the array of subpass descriptions, see Diligent::SubpassDesc. + const SubpassDesc* pSubpasses DEFAULT_INITIALIZER(nullptr); + + /// The number of subpass dependencies. + Uint32 DependencyCount DEFAULT_INITIALIZER(0); + + /// The array of subpass dependencies, see Diligent::SubpassDependencyDesc. + const SubpassDependencyDesc* pDependencies DEFAULT_INITIALIZER(nullptr); +}; +typedef struct RenderPassDesc RenderPassDesc; + + +#if DILIGENT_CPP_INTERFACE + +/// Render pass interface + +/// Render pass has no methods. +class IRenderPass : public IDeviceObject +{ +}; + +#else + +struct IRenderPass; + +// C requires that a struct or union has at least one member +//struct IRenderPassMethods +//{ +//}; + +struct IRenderPassVtbl +{ + struct IObjectMethods Object; + struct IDeviceObjectMethods DeviceObject; + //struct IRenderPassMethods RenderPass; +}; + +typedef struct IRenderPass +{ + struct IRenderPassVtbl* pVtbl; +} IRenderPass; + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent -- cgit v1.2.3 From 8a7504ff49c357ad86d547a35bdfd3258bea72df Mon Sep 17 00:00:00 2001 From: assiduous Date: Thu, 23 Jul 2020 15:58:46 -0700 Subject: Added render pass object implementation stubs in all backends --- Graphics/GraphicsEngine/CMakeLists.txt | 1 + .../GraphicsEngine/include/RenderDeviceBase.hpp | 27 ++++---- Graphics/GraphicsEngine/include/RenderPassBase.hpp | 72 ++++++++++++++++++++++ 3 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 Graphics/GraphicsEngine/include/RenderPassBase.hpp (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt index c3dd8678..0c522bed 100644 --- a/Graphics/GraphicsEngine/CMakeLists.txt +++ b/Graphics/GraphicsEngine/CMakeLists.txt @@ -17,6 +17,7 @@ set(INCLUDE include/PipelineStateBase.hpp include/QueryBase.hpp include/RenderDeviceBase.hpp + include/RenderPassBase.hpp include/ResourceMappingImpl.hpp include/SamplerBase.hpp include/ShaderBase.hpp diff --git a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp index 49e54d12..854e5ec9 100644 --- a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp +++ b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp @@ -220,6 +220,9 @@ public: /// Size of the query object (QueryD3D12Impl, QueryVkImpl, etc.), in bytes const size_t QuerySize; + + /// Size of the render pass object (RenderPassD3D12Impl, RenderPassVkImpl, etc.), in bytes + const size_t RenderPassObjSize; }; /// \param pRefCounters - reference counters object that controls the lifetime of this render device @@ -243,17 +246,18 @@ public: m_TexFmtInfoInitFlags (TEX_FORMAT_NUM_FORMATS, false, STD_ALLOCATOR_RAW_MEM(bool, RawMemAllocator, "Allocator for vector")), m_wpDeferredContexts (NumDeferredContexts, RefCntWeakPtr(), STD_ALLOCATOR_RAW_MEM(RefCntWeakPtr, RawMemAllocator, "Allocator for vector< RefCntWeakPtr >")), m_RawMemAllocator {RawMemAllocator}, - m_TexObjAllocator {RawMemAllocator, ObjectSizes.TextureObjSize, 64 }, - m_TexViewObjAllocator {RawMemAllocator, ObjectSizes.TexViewObjSize, 64 }, - m_BufObjAllocator {RawMemAllocator, ObjectSizes.BufferObjSize, 128 }, - m_BuffViewObjAllocator {RawMemAllocator, ObjectSizes.BuffViewObjSize, 128 }, - m_ShaderObjAllocator {RawMemAllocator, ObjectSizes.ShaderObjSize, 32 }, - m_SamplerObjAllocator {RawMemAllocator, ObjectSizes.SamplerObjSize, 32 }, - m_PSOAllocator {RawMemAllocator, ObjectSizes.PSOSize, 128 }, - m_SRBAllocator {RawMemAllocator, ObjectSizes.SRBSize, 1024}, - m_ResMappingAllocator {RawMemAllocator, sizeof(ResourceMappingImpl), 16 }, - m_FenceAllocator {RawMemAllocator, ObjectSizes.FenceSize, 16 }, - m_QueryAllocator {RawMemAllocator, ObjectSizes.QuerySize, 16 } + m_TexObjAllocator {RawMemAllocator, ObjectSizes.TextureObjSize, 64 }, + m_TexViewObjAllocator {RawMemAllocator, ObjectSizes.TexViewObjSize, 64 }, + m_BufObjAllocator {RawMemAllocator, ObjectSizes.BufferObjSize, 128 }, + m_BuffViewObjAllocator {RawMemAllocator, ObjectSizes.BuffViewObjSize, 128 }, + m_ShaderObjAllocator {RawMemAllocator, ObjectSizes.ShaderObjSize, 32 }, + m_SamplerObjAllocator {RawMemAllocator, ObjectSizes.SamplerObjSize, 32 }, + m_PSOAllocator {RawMemAllocator, ObjectSizes.PSOSize, 128 }, + m_SRBAllocator {RawMemAllocator, ObjectSizes.SRBSize, 1024}, + m_ResMappingAllocator {RawMemAllocator, sizeof(ResourceMappingImpl), 16 }, + m_FenceAllocator {RawMemAllocator, ObjectSizes.FenceSize, 16 }, + m_QueryAllocator {RawMemAllocator, ObjectSizes.QuerySize, 16 }, + m_RenderPassAllocator {RawMemAllocator, ObjectSizes.RenderPassObjSize, 16 } // clang-format on { // Initialize texture format info @@ -426,6 +430,7 @@ protected: FixedBlockMemoryAllocator m_ResMappingAllocator; ///< Allocator for resource mapping objects FixedBlockMemoryAllocator m_FenceAllocator; ///< Allocator for fence objects FixedBlockMemoryAllocator m_QueryAllocator; ///< Allocator for query objects + FixedBlockMemoryAllocator m_RenderPassAllocator; ///< Allocator for render pass objects }; diff --git a/Graphics/GraphicsEngine/include/RenderPassBase.hpp b/Graphics/GraphicsEngine/include/RenderPassBase.hpp new file mode 100644 index 00000000..c10f39a1 --- /dev/null +++ b/Graphics/GraphicsEngine/include/RenderPassBase.hpp @@ -0,0 +1,72 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Implementation of the Diligent::RenderPassBase template class + +#include "RenderPass.h" +#include "DeviceObjectBase.hpp" +#include "RenderDeviceBase.hpp" + +namespace Diligent +{ + +/// Template class implementing base functionality for the render pass object. + +/// \tparam BaseInterface - base interface that this class will inheret +/// (Diligent::IRenderPassVk). +/// \tparam RenderDeviceImplType - type of the render device implementation +/// (Diligent::RenderDeviceD3D11Impl, Diligent::RenderDeviceD3D12Impl, +/// Diligent::RenderDeviceGLImpl, or Diligent::RenderDeviceVkImpl) +template +class RenderPassBase : public DeviceObjectBase +{ +public: + using TDeviceObjectBase = DeviceObjectBase; + + /// \param pRefCounters - reference counters object that controls the lifetime of this render pass. + /// \param pDevice - pointer to the device. + /// \param Desc - Render pass description. + /// \param bIsDeviceInternal - flag indicating if the RenderPass is an internal device object and + /// must not keep a strong reference to the device. + RenderPassBase(IReferenceCounters* pRefCounters, + RenderDeviceImplType* pDevice, + const RenderPassDesc& Desc, + bool bIsDeviceInternal = false) : + TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal} + {} + + ~RenderPassBase() + { + } + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_RenderPass, TDeviceObjectBase) +}; + +} // namespace Diligent -- cgit v1.2.3 From b35dbd3450904e5300f96f6e650d38964078fca7 Mon Sep 17 00:00:00 2001 From: assiduous Date: Thu, 23 Jul 2020 20:41:58 -0700 Subject: Implemented RenderPassAttachmentDesc struct; added render pass creation test; WIP implementation of render pass initialization in Vulkan --- Graphics/GraphicsEngine/CMakeLists.txt | 5 +- Graphics/GraphicsEngine/include/RenderPassBase.hpp | 46 +++- Graphics/GraphicsEngine/interface/RenderPass.h | 88 +++++- Graphics/GraphicsEngine/src/RenderPassBase.cpp | 99 +++++++ Graphics/GraphicsEngine/src/ResourceMapping.cpp | 124 --------- .../GraphicsEngine/src/ResourceMappingBase.cpp | 124 +++++++++ Graphics/GraphicsEngine/src/Texture.cpp | 297 --------------------- Graphics/GraphicsEngine/src/TextureBase.cpp | 297 +++++++++++++++++++++ Graphics/GraphicsEngine/src/pch.cpp | 31 --- 9 files changed, 651 insertions(+), 460 deletions(-) create mode 100644 Graphics/GraphicsEngine/src/RenderPassBase.cpp delete mode 100644 Graphics/GraphicsEngine/src/ResourceMapping.cpp create mode 100644 Graphics/GraphicsEngine/src/ResourceMappingBase.cpp delete mode 100644 Graphics/GraphicsEngine/src/Texture.cpp create mode 100644 Graphics/GraphicsEngine/src/TextureBase.cpp delete mode 100644 Graphics/GraphicsEngine/src/pch.cpp (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt index 0c522bed..d7b51d87 100644 --- a/Graphics/GraphicsEngine/CMakeLists.txt +++ b/Graphics/GraphicsEngine/CMakeLists.txt @@ -63,8 +63,9 @@ set(SOURCE src/APIInfo.cpp src/DefaultShaderSourceStreamFactory.cpp src/EngineMemory.cpp - src/ResourceMapping.cpp - src/Texture.cpp + src/ResourceMappingBase.cpp + src/RenderPassBase.cpp + src/TextureBase.cpp ) add_library(Diligent-GraphicsEngine STATIC ${SOURCE} ${INTERFACE} ${INCLUDE}) diff --git a/Graphics/GraphicsEngine/include/RenderPassBase.hpp b/Graphics/GraphicsEngine/include/RenderPassBase.hpp index c10f39a1..03fecd78 100644 --- a/Graphics/GraphicsEngine/include/RenderPassBase.hpp +++ b/Graphics/GraphicsEngine/include/RenderPassBase.hpp @@ -37,6 +37,8 @@ namespace Diligent { +void ValidateRenderPassDesc(const RenderPassDesc& Desc); + /// Template class implementing base functionality for the render pass object. /// \tparam BaseInterface - base interface that this class will inheret @@ -60,10 +62,52 @@ public: const RenderPassDesc& Desc, bool bIsDeviceInternal = false) : TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal} - {} + { + ValidateRenderPassDesc(Desc); + + if (Desc.AttachmentCount != 0) + { + auto* pAttachments = + ALLOCATE(GetRawAllocator(), "Memory for RenderPassAttachmentDesc array", RenderPassAttachmentDesc, Desc.AttachmentCount); + this->m_Desc.pAttachments = pAttachments; + for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) + { + pAttachments[i] = Desc.pAttachments[i]; + } + } + + if (Desc.SubpassCount != 0) + { + auto* pSubpasses = + ALLOCATE(GetRawAllocator(), "Memory for SubpassDesc array", SubpassDesc, Desc.SubpassCount); + this->m_Desc.pSubpasses = pSubpasses; + for (Uint32 i = 0; i < Desc.SubpassCount; ++i) + { + pSubpasses[i] = Desc.pSubpasses[i]; + } + } + + if (Desc.DependencyCount != 0) + { + auto* pDependencies = + ALLOCATE(GetRawAllocator(), "Memory for SubpassDependencyDesc array", SubpassDependencyDesc, Desc.DependencyCount); + this->m_Desc.pDependencies = pDependencies; + for (Uint32 i = 0; i < Desc.DependencyCount; ++i) + { + pDependencies[i] = Desc.pDependencies[i]; + } + } + } ~RenderPassBase() { + auto& RawAllocator = GetRawAllocator(); + if (this->m_Desc.pAttachments != nullptr) + RawAllocator.Free(const_cast(this->m_Desc.pAttachments)); + if (this->m_Desc.pSubpasses != nullptr) + RawAllocator.Free(const_cast(this->m_Desc.pSubpasses)); + if (this->m_Desc.pDependencies != nullptr) + RawAllocator.Free(const_cast(this->m_Desc.pDependencies)); } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_RenderPass, TDeviceObjectBase) diff --git a/Graphics/GraphicsEngine/interface/RenderPass.h b/Graphics/GraphicsEngine/interface/RenderPass.h index 2e7c8b63..36cfc46c 100644 --- a/Graphics/GraphicsEngine/interface/RenderPass.h +++ b/Graphics/GraphicsEngine/interface/RenderPass.h @@ -40,11 +40,87 @@ DILIGENT_BEGIN_NAMESPACE(Diligent) static const struct INTERFACE_ID IID_RenderPass = { 0xb818dec7, 0x174d, 0x447a, { 0xa8, 0xe4, 0x94, 0xd2, 0x1c, 0x57, 0xb4, 0xa } }; +/// Render pass attachment load operation +DILIGENT_TYPED_ENUM(ATTACHMENT_LOAD_OP, Uint8) +{ + /// The previous contents of the texture within the render area will be preserved. + ATTACHMENT_LOAD_OP_LOAD = 0, + + /// The contents within the render area will be cleared to a uniform value, which is + /// specified when a render pass instance is begun + ATTACHMENT_LOAD_OP_CLEAR, + + /// The previous contents within the area need not be preserved; the contents of + /// the attachment will be undefined inside the render area. + ATTACHMENT_LOAD_OP_DONT_CARE +}; + +/// Render pass attachment store operation +DILIGENT_TYPED_ENUM(ATTACHMENT_STORE_OP, Uint8) +{ + /// The contents generated during the render pass and within the render area are written to memory. + ATTACHMENT_STORE_OP_STORE = 0, + + /// The contents within the render area are not needed after rendering, and may be discarded; + /// the contents of the attachment will be undefined inside the render area. + ATTACHMENT_STORE_OP_DONT_CARE +}; + + /// Render pass attachment description. struct RenderPassAttachmentDesc { - int Dummy; + /// The format of the texture view that will be used for the attachment. + TEXTURE_FORMAT Format DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); + + /// The number of samples in the texture. + Uint8 SampleCount DEFAULT_INITIALIZER(1); + + /// Load operation that specifies how the contents of color and depth components of + /// the attachment are treated at the beginning of the subpass where it is first used. + ATTACHMENT_LOAD_OP LoadOp DEFAULT_INITIALIZER(ATTACHMENT_LOAD_OP_LOAD); + + /// Store operation how the contents of color and depth components of the attachment + /// are treated at the end of the subpass where it is last used. + ATTACHMENT_STORE_OP StoreOp DEFAULT_INITIALIZER(ATTACHMENT_STORE_OP_STORE); + + /// Load operation that specifies how the contents of the stencil component of the + /// attachment is treated at the beginning of the subpass where it is first used. + /// This value is ignored when the format does not have stencil component. + ATTACHMENT_LOAD_OP StencilLoadOp DEFAULT_INITIALIZER(ATTACHMENT_LOAD_OP_LOAD); + + /// Store operation how the contents of the stencil component of the attachment + /// is treated at the end of the subpass where it is last used. + /// This value is ignored when the format does not have stencil component. + ATTACHMENT_STORE_OP StencilStoreOp DEFAULT_INITIALIZER(ATTACHMENT_STORE_OP_STORE); + + /// The state the attachment texture subresource will be in when a render pass instance begins. + RESOURCE_STATE InitialState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN); + + /// The state the attachment texture subresource will be transitioned to when a render pass instance ends. + RESOURCE_STATE FinalState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN); + + +#if DILIGENT_CPP_INTERFACE + /// Tests if two structures are equivalent + + /// \param [in] RHS - reference to the structure to perform comparison with + /// \return + /// - True if all members of the two structures are equal. + /// - False otherwise + bool operator == (const RenderPassAttachmentDesc& RHS)const + { + return Format == RHS.Format && + SampleCount == RHS.SampleCount && + LoadOp == RHS.LoadOp && + StoreOp == RHS.StoreOp && + StencilLoadOp == RHS.StencilLoadOp && + StencilStoreOp == RHS.StencilStoreOp && + InitialState == RHS.InitialState && + FinalState == RHS.FinalState; + } +#endif }; typedef struct RenderPassAttachmentDesc RenderPassAttachmentDesc; @@ -67,22 +143,22 @@ typedef struct SubpassDependencyDesc SubpassDependencyDesc; /// Render pass description struct RenderPassDesc DILIGENT_DERIVE(DeviceObjectAttribs) - /// The number of attachments. + /// The number of attachments used by the render pass. Uint32 AttachmentCount DEFAULT_INITIALIZER(0); /// Pointer to the array of subpass attachments, see Diligent::RenderPassAttachmentDesc. const RenderPassAttachmentDesc* pAttachments DEFAULT_INITIALIZER(nullptr); - /// The number of subpasses. + /// The number of subpasses in the render pass. Uint32 SubpassCount DEFAULT_INITIALIZER(0); /// Pointer to the array of subpass descriptions, see Diligent::SubpassDesc. const SubpassDesc* pSubpasses DEFAULT_INITIALIZER(nullptr); - /// The number of subpass dependencies. + /// The number of memory dependencies between pairs of subpasses. Uint32 DependencyCount DEFAULT_INITIALIZER(0); - /// The array of subpass dependencies, see Diligent::SubpassDependencyDesc. + /// Pointer to the array of subpass dependencies, see Diligent::SubpassDependencyDesc. const SubpassDependencyDesc* pDependencies DEFAULT_INITIALIZER(nullptr); }; typedef struct RenderPassDesc RenderPassDesc; @@ -95,6 +171,8 @@ typedef struct RenderPassDesc RenderPassDesc; /// Render pass has no methods. class IRenderPass : public IDeviceObject { +public: + virtual const RenderPassDesc& GetDesc() const override = 0; }; #else diff --git a/Graphics/GraphicsEngine/src/RenderPassBase.cpp b/Graphics/GraphicsEngine/src/RenderPassBase.cpp new file mode 100644 index 00000000..4c4e0abd --- /dev/null +++ b/Graphics/GraphicsEngine/src/RenderPassBase.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "RenderPassBase.hpp" +#include "GraphicsAccessories.hpp" +#include "Align.hpp" + +namespace Diligent +{ + +void ValidateRenderPassDesc(const RenderPassDesc& Desc) +{ +#define LOG_RENDER_PASS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Render pass '", (Desc.Name ? Desc.Name : ""), "': ", ##__VA_ARGS__) + + for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) + { + const auto& Attachment = Desc.pAttachments[i]; + if (Attachment.Format == TEX_FORMAT_UNKNOWN) + LOG_RENDER_PASS_ERROR_AND_THROW("the format of attachment ", i, " is unknown"); + + if (Attachment.SampleCount == 0) + LOG_RENDER_PASS_ERROR_AND_THROW("the sample count of attachment ", i, " is zero"); + + if (!IsPowerOfTwo(Attachment.SampleCount)) + LOG_RENDER_PASS_ERROR_AND_THROW("the sample count of attachment ", i, "(", Attachment.SampleCount, ") is not power of two"); + + const auto& FmtInfo = GetTextureFormatAttribs(Attachment.Format); + if (FmtInfo.ComponentType == COMPONENT_TYPE_DEPTH || + FmtInfo.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + { + if (Attachment.InitialState != RESOURCE_STATE_DEPTH_WRITE && + Attachment.InitialState != RESOURCE_STATE_DEPTH_READ && + Attachment.InitialState != RESOURCE_STATE_UNORDERED_ACCESS && + Attachment.InitialState != RESOURCE_STATE_SHADER_RESOURCE && + Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && + Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid"); + } + + if (Attachment.FinalState != RESOURCE_STATE_DEPTH_WRITE && + Attachment.FinalState != RESOURCE_STATE_DEPTH_READ && + Attachment.FinalState != RESOURCE_STATE_UNORDERED_ACCESS && + Attachment.FinalState != RESOURCE_STATE_SHADER_RESOURCE && + Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && + Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the final state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid"); + } + } + else + { + if (Attachment.InitialState != RESOURCE_STATE_RENDER_TARGET && + Attachment.InitialState != RESOURCE_STATE_UNORDERED_ACCESS && + Attachment.InitialState != RESOURCE_STATE_SHADER_RESOURCE && + Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && + Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of color attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid"); + } + + if (Attachment.FinalState != RESOURCE_STATE_RENDER_TARGET && + Attachment.FinalState != RESOURCE_STATE_UNORDERED_ACCESS && + Attachment.FinalState != RESOURCE_STATE_SHADER_RESOURCE && + Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && + Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the final state of color attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid"); + } + } + } +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngine/src/ResourceMapping.cpp b/Graphics/GraphicsEngine/src/ResourceMapping.cpp deleted file mode 100644 index bf34056c..00000000 --- a/Graphics/GraphicsEngine/src/ResourceMapping.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2019-2020 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#include "pch.h" -#include "ResourceMappingImpl.hpp" -#include "DeviceObjectBase.hpp" - -using namespace std; - -namespace Diligent -{ -ResourceMappingImpl::~ResourceMappingImpl() -{ -} - -IMPLEMENT_QUERY_INTERFACE(ResourceMappingImpl, IID_ResourceMapping, TObjectBase) - -ThreadingTools::LockHelper ResourceMappingImpl::Lock() -{ - return ThreadingTools::LockHelper(m_LockFlag); -} - -void ResourceMappingImpl::AddResourceArray(const Char* Name, Uint32 StartIndex, IDeviceObject* const* ppObjects, Uint32 NumElements, bool bIsUnique) -{ - if (Name == nullptr || *Name == 0) - return; - - auto LockHelper = Lock(); - for (Uint32 Elem = 0; Elem < NumElements; ++Elem) - { - auto* pObject = ppObjects[Elem]; - - // Try to construct new element in place - auto Elems = - m_HashTable.emplace( - make_pair(Diligent::ResMappingHashKey(Name, true, StartIndex + Elem), // Make a copy of the source string - Diligent::RefCntAutoPtr(pObject))); - // If there is already element with the same name, replace it - if (!Elems.second && Elems.first->second != pObject) - { - if (bIsUnique) - { - UNEXPECTED("Resource with the same name already exists"); - LOG_WARNING_MESSAGE( - "Resource with name ", Name, - " marked is unique, but already present in the hash.\n" - "New resource will be used\n."); - } - Elems.first->second = pObject; - } - } -} - -void ResourceMappingImpl::AddResource(const Char* Name, IDeviceObject* pObject, bool bIsUnique) -{ - AddResourceArray(Name, 0, &pObject, 1, bIsUnique); -} - -void ResourceMappingImpl::RemoveResourceByName(const Char* Name, Uint32 ArrayIndex) -{ - if (*Name == 0) - return; - - auto LockHelper = Lock(); - // Remove object with the given name - // Name will be implicitly converted to HashMapStringKey without making a copy - m_HashTable.erase(ResMappingHashKey(Name, false, ArrayIndex)); -} - -void ResourceMappingImpl::GetResource(const Char* Name, IDeviceObject** ppResource, Uint32 ArrayIndex) -{ - VERIFY(Name, "Name is null"); - if (*Name == 0) - return; - - VERIFY(ppResource, "Null pointer provided"); - if (!ppResource) - return; - - VERIFY(*ppResource == nullptr, "Overwriting reference to existing object may cause memory leaks"); - *ppResource = nullptr; - - auto LockHelper = Lock(); - - // Find an object with the requested name - // Name will be implicitly converted to HashMapStringKey without making a copy - auto It = m_HashTable.find(ResMappingHashKey(Name, false, ArrayIndex)); - if (It != m_HashTable.end()) - { - *ppResource = It->second.RawPtr(); - if (*ppResource) - (*ppResource)->AddRef(); - } -} - -size_t ResourceMappingImpl::GetSize() -{ - return m_HashTable.size(); -} -} // namespace Diligent diff --git a/Graphics/GraphicsEngine/src/ResourceMappingBase.cpp b/Graphics/GraphicsEngine/src/ResourceMappingBase.cpp new file mode 100644 index 00000000..bf34056c --- /dev/null +++ b/Graphics/GraphicsEngine/src/ResourceMappingBase.cpp @@ -0,0 +1,124 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "ResourceMappingImpl.hpp" +#include "DeviceObjectBase.hpp" + +using namespace std; + +namespace Diligent +{ +ResourceMappingImpl::~ResourceMappingImpl() +{ +} + +IMPLEMENT_QUERY_INTERFACE(ResourceMappingImpl, IID_ResourceMapping, TObjectBase) + +ThreadingTools::LockHelper ResourceMappingImpl::Lock() +{ + return ThreadingTools::LockHelper(m_LockFlag); +} + +void ResourceMappingImpl::AddResourceArray(const Char* Name, Uint32 StartIndex, IDeviceObject* const* ppObjects, Uint32 NumElements, bool bIsUnique) +{ + if (Name == nullptr || *Name == 0) + return; + + auto LockHelper = Lock(); + for (Uint32 Elem = 0; Elem < NumElements; ++Elem) + { + auto* pObject = ppObjects[Elem]; + + // Try to construct new element in place + auto Elems = + m_HashTable.emplace( + make_pair(Diligent::ResMappingHashKey(Name, true, StartIndex + Elem), // Make a copy of the source string + Diligent::RefCntAutoPtr(pObject))); + // If there is already element with the same name, replace it + if (!Elems.second && Elems.first->second != pObject) + { + if (bIsUnique) + { + UNEXPECTED("Resource with the same name already exists"); + LOG_WARNING_MESSAGE( + "Resource with name ", Name, + " marked is unique, but already present in the hash.\n" + "New resource will be used\n."); + } + Elems.first->second = pObject; + } + } +} + +void ResourceMappingImpl::AddResource(const Char* Name, IDeviceObject* pObject, bool bIsUnique) +{ + AddResourceArray(Name, 0, &pObject, 1, bIsUnique); +} + +void ResourceMappingImpl::RemoveResourceByName(const Char* Name, Uint32 ArrayIndex) +{ + if (*Name == 0) + return; + + auto LockHelper = Lock(); + // Remove object with the given name + // Name will be implicitly converted to HashMapStringKey without making a copy + m_HashTable.erase(ResMappingHashKey(Name, false, ArrayIndex)); +} + +void ResourceMappingImpl::GetResource(const Char* Name, IDeviceObject** ppResource, Uint32 ArrayIndex) +{ + VERIFY(Name, "Name is null"); + if (*Name == 0) + return; + + VERIFY(ppResource, "Null pointer provided"); + if (!ppResource) + return; + + VERIFY(*ppResource == nullptr, "Overwriting reference to existing object may cause memory leaks"); + *ppResource = nullptr; + + auto LockHelper = Lock(); + + // Find an object with the requested name + // Name will be implicitly converted to HashMapStringKey without making a copy + auto It = m_HashTable.find(ResMappingHashKey(Name, false, ArrayIndex)); + if (It != m_HashTable.end()) + { + *ppResource = It->second.RawPtr(); + if (*ppResource) + (*ppResource)->AddRef(); + } +} + +size_t ResourceMappingImpl::GetSize() +{ + return m_HashTable.size(); +} +} // namespace Diligent diff --git a/Graphics/GraphicsEngine/src/Texture.cpp b/Graphics/GraphicsEngine/src/Texture.cpp deleted file mode 100644 index 4cfdbd0b..00000000 --- a/Graphics/GraphicsEngine/src/Texture.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright 2019-2020 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#include "pch.h" -#include "Texture.h" -#include "GraphicsAccessories.hpp" - -namespace Diligent -{ - -void ValidateTextureDesc(const TextureDesc& Desc) -{ -#define LOG_TEXTURE_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Texture \"", Desc.Name ? Desc.Name : "", "\": ", ##__VA_ARGS__) - - if (Desc.Type == RESOURCE_DIM_UNDEFINED) - { - LOG_TEXTURE_ERROR_AND_THROW("Resource dimension is undefined"); - } - - if (!(Desc.Type >= RESOURCE_DIM_TEX_1D && Desc.Type <= RESOURCE_DIM_TEX_CUBE_ARRAY)) - { - LOG_TEXTURE_ERROR_AND_THROW("Unexpected resource dimension"); - } - - if (Desc.Width == 0) - { - LOG_TEXTURE_ERROR_AND_THROW("Texture width cannot be zero"); - } - - // Perform some parameter correctness check - if (Desc.Type == RESOURCE_DIM_TEX_1D || Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) - { - if (Desc.Height != 1) - LOG_TEXTURE_ERROR_AND_THROW("Height (", Desc.Height, ") of Texture 1D/Texture 1D Array must be 1"); - } - else - { - if (Desc.Height == 0) - LOG_TEXTURE_ERROR_AND_THROW("Texture height cannot be zero"); - } - - if (Desc.Type == RESOURCE_DIM_TEX_3D && Desc.Depth == 0) - { - LOG_TEXTURE_ERROR_AND_THROW("3D texture depth cannot be zero"); - } - - if (Desc.Type == RESOURCE_DIM_TEX_1D || Desc.Type == RESOURCE_DIM_TEX_2D) - { - if (Desc.ArraySize != 1) - LOG_TEXTURE_ERROR_AND_THROW("Texture 1D/2D must have one array slice (", Desc.ArraySize, " provided). Use Texture 1D/2D array if you need more than one slice."); - } - - if (Desc.Type == RESOURCE_DIM_TEX_CUBE || Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) - { - if (Desc.Width != Desc.Height) - LOG_TEXTURE_ERROR_AND_THROW("For cube map textures, texture width (", Desc.Width, " provided) must match texture height (", Desc.Height, " provided)"); - - if (Desc.ArraySize < 6) - LOG_TEXTURE_ERROR_AND_THROW("Texture cube/cube array must have at least 6 slices (", Desc.ArraySize, " provided)."); - } - - Uint32 MaxDim = 0; - if (Desc.Type == RESOURCE_DIM_TEX_1D || Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) - MaxDim = Desc.Width; - else if (Desc.Type == RESOURCE_DIM_TEX_2D || Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || Desc.Type == RESOURCE_DIM_TEX_CUBE || Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) - MaxDim = std::max(Desc.Width, Desc.Height); - else if (Desc.Type == RESOURCE_DIM_TEX_3D) - MaxDim = std::max(std::max(Desc.Width, Desc.Height), Desc.Depth); - VERIFY(MaxDim >= (1U << (Desc.MipLevels - 1)), "Texture \"", Desc.Name ? Desc.Name : "", "\": Incorrect number of Mip levels (", Desc.MipLevels, ")"); - - if (Desc.SampleCount > 1) - { - if (!(Desc.Type == RESOURCE_DIM_TEX_2D || Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY)) - LOG_TEXTURE_ERROR_AND_THROW("Only Texture 2D/Texture 2D Array can be multisampled"); - - if (Desc.MipLevels != 1) - LOG_TEXTURE_ERROR_AND_THROW("Multisampled textures must have one mip level (", Desc.MipLevels, " levels specified)"); - - if (Desc.BindFlags & BIND_UNORDERED_ACCESS) - LOG_TEXTURE_ERROR_AND_THROW("UAVs are not allowed for multisampled resources"); - } - - if ((Desc.BindFlags & BIND_RENDER_TARGET) && - (Desc.Format == TEX_FORMAT_R8_SNORM || Desc.Format == TEX_FORMAT_RG8_SNORM || Desc.Format == TEX_FORMAT_RGBA8_SNORM || - Desc.Format == TEX_FORMAT_R16_SNORM || Desc.Format == TEX_FORMAT_RG16_SNORM || Desc.Format == TEX_FORMAT_RGBA16_SNORM)) - { - const auto* FmtName = GetTextureFormatAttribs(Desc.Format).Name; - LOG_WARNING_MESSAGE(FmtName, " texture is created with BIND_RENDER_TARGET flag set.\n" - "There might be an issue in OpenGL driver on NVidia hardware: when rendering to SNORM textures, all negative values are clamped to zero.\n" - "Use UNORM format instead."); - } - - if (Desc.Usage == USAGE_STAGING) - { - if (Desc.BindFlags != 0) - LOG_TEXTURE_ERROR_AND_THROW("Staging textures cannot be bound to any GPU pipeline stage"); - - if (Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) - LOG_TEXTURE_ERROR_AND_THROW("Mipmaps cannot be autogenerated for staging textures"); - - if (Desc.CPUAccessFlags == 0) - LOG_TEXTURE_ERROR_AND_THROW("Staging textures must specify CPU access flags"); - - if ((Desc.CPUAccessFlags & (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) == (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) - LOG_TEXTURE_ERROR_AND_THROW("Staging textures must use exactly one of ACESS_READ or ACCESS_WRITE flags"); - } -} - - -void ValidateTextureRegion(const TextureDesc& TexDesc, Uint32 MipLevel, Uint32 Slice, const Box& Box) -{ -#define VERIFY_TEX_PARAMS(Expr, ...) \ - do \ - { \ - if (!(Expr)) \ - { \ - LOG_ERROR("Texture \"", TexDesc.Name ? TexDesc.Name : "", "\": ", ##__VA_ARGS__); \ - } \ - } while (false) - -#ifdef DILIGENT_DEVELOPMENT - VERIFY_TEX_PARAMS(MipLevel < TexDesc.MipLevels, "Mip level (", MipLevel, ") is out of allowed range [0, ", TexDesc.MipLevels - 1, "]"); - VERIFY_TEX_PARAMS(Box.MinX < Box.MaxX, "Invalid X range: ", Box.MinX, "..", Box.MaxX); - VERIFY_TEX_PARAMS(Box.MinY < Box.MaxY, "Invalid Y range: ", Box.MinY, "..", Box.MaxY); - VERIFY_TEX_PARAMS(Box.MinZ < Box.MaxZ, "Invalid Z range: ", Box.MinZ, "..", Box.MaxZ); - - if (TexDesc.Type == RESOURCE_DIM_TEX_1D_ARRAY || - TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY || - TexDesc.Type == RESOURCE_DIM_TEX_CUBE || - TexDesc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) - { - VERIFY_TEX_PARAMS(Slice < TexDesc.ArraySize, "Array slice (", Slice, ") is out of range [0,", TexDesc.ArraySize - 1, "]"); - } - else - { - VERIFY_TEX_PARAMS(Slice == 0, "Array slice (", Slice, ") must be 0 for non-array textures"); - } - - const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); - - Uint32 MipWidth = std::max(TexDesc.Width >> MipLevel, 1U); - if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) - { - VERIFY_EXPR((FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth - 1)) == 0); - Uint32 BlockAlignedMipWidth = (MipWidth + (FmtAttribs.BlockWidth - 1)) & ~(FmtAttribs.BlockWidth - 1); - VERIFY_TEX_PARAMS(Box.MaxX <= BlockAlignedMipWidth, "Region max X coordinate (", Box.MaxX, ") is out of allowed range [0, ", BlockAlignedMipWidth, "]"); - VERIFY_TEX_PARAMS((Box.MinX % FmtAttribs.BlockWidth) == 0, "For compressed formats, the region min X coordinate (", Box.MinX, ") must be a multiple of block width (", Uint32{FmtAttribs.BlockWidth}, ")"); - VERIFY_TEX_PARAMS((Box.MaxX % FmtAttribs.BlockWidth) == 0 || Box.MaxX == MipWidth, "For compressed formats, the region max X coordinate (", Box.MaxX, ") must be a multiple of block width (", Uint32{FmtAttribs.BlockWidth}, ") or equal the mip level width (", MipWidth, ")"); - } - else - VERIFY_TEX_PARAMS(Box.MaxX <= MipWidth, "Region max X coordinate (", Box.MaxX, ") is out of allowed range [0, ", MipWidth, "]"); - - if (TexDesc.Type != RESOURCE_DIM_TEX_1D && - TexDesc.Type != RESOURCE_DIM_TEX_1D_ARRAY) - { - Uint32 MipHeight = std::max(TexDesc.Height >> MipLevel, 1U); - if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) - { - VERIFY_EXPR((FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight - 1)) == 0); - Uint32 BlockAlignedMipHeight = (MipHeight + (FmtAttribs.BlockHeight - 1)) & ~(FmtAttribs.BlockHeight - 1); - VERIFY_TEX_PARAMS(Box.MaxY <= BlockAlignedMipHeight, "Region max Y coordinate (", Box.MaxY, ") is out of allowed range [0, ", BlockAlignedMipHeight, "]"); - VERIFY_TEX_PARAMS((Box.MinY % FmtAttribs.BlockHeight) == 0, "For compressed formats, the region min Y coordinate (", Box.MinY, ") must be a multiple of block height (", Uint32{FmtAttribs.BlockHeight}, ")"); - VERIFY_TEX_PARAMS((Box.MaxY % FmtAttribs.BlockHeight) == 0 || Box.MaxY == MipHeight, "For compressed formats, the region max Y coordinate (", Box.MaxY, ") must be a multiple of block height (", Uint32{FmtAttribs.BlockHeight}, ") or equal the mip level height (", MipHeight, ")"); - } - else - VERIFY_TEX_PARAMS(Box.MaxY <= MipHeight, "Region max Y coordinate (", Box.MaxY, ") is out of allowed range [0, ", MipHeight, "]"); - } - - if (TexDesc.Type == RESOURCE_DIM_TEX_3D) - { - Uint32 MipDepth = std::max(TexDesc.Depth >> MipLevel, 1U); - VERIFY_TEX_PARAMS(Box.MaxZ <= MipDepth, "Region max Z coordinate (", Box.MaxZ, ") is out of allowed range [0, ", MipDepth, "]"); - } - else - { - VERIFY_TEX_PARAMS(Box.MinZ == 0, "Region min Z (", Box.MinZ, ") must be 0 for all but 3D textures"); - VERIFY_TEX_PARAMS(Box.MaxZ == 1, "Region max Z (", Box.MaxZ, ") must be 1 for all but 3D textures"); - } -#endif -} - -void ValidateUpdateTextureParams(const TextureDesc& TexDesc, Uint32 MipLevel, Uint32 Slice, const Box& DstBox, const TextureSubResData& SubresData) -{ - VERIFY((SubresData.pData != nullptr) ^ (SubresData.pSrcBuffer != nullptr), "Either CPU data pointer (pData) or GPU buffer (pSrcBuffer) must not be null, but not both"); - ValidateTextureRegion(TexDesc, MipLevel, Slice, DstBox); - -#ifdef DILIGENT_DEVELOPMENT - VERIFY_TEX_PARAMS(TexDesc.SampleCount == 1, "Only non-multisampled textures can be updated with UpdateData()"); - VERIFY_TEX_PARAMS((SubresData.Stride & 0x03) == 0, "Texture data stride (", SubresData.Stride, ") must be at least 32-bit aligned"); - VERIFY_TEX_PARAMS((SubresData.DepthStride & 0x03) == 0, "Texture data depth stride (", SubresData.DepthStride, ") must be at least 32-bit aligned"); - - auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX; - auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY; - auto UpdateRegionDepth = DstBox.MaxZ - DstBox.MinZ; - const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); - Uint32 RowSize = 0; - Uint32 RowCount = 0; - if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) - { - // Align update region size by the block size. This is only necessary when updating - // coarse mip levels. Otherwise UpdateRegionWidth/Height should be multiples of block size - VERIFY_EXPR((FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth - 1)) == 0); - VERIFY_EXPR((FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight - 1)) == 0); - UpdateRegionWidth = (UpdateRegionWidth + (FmtAttribs.BlockWidth - 1)) & ~(FmtAttribs.BlockWidth - 1); - UpdateRegionHeight = (UpdateRegionHeight + (FmtAttribs.BlockHeight - 1)) & ~(FmtAttribs.BlockHeight - 1); - RowSize = UpdateRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize}; - RowCount = UpdateRegionHeight / FmtAttribs.BlockHeight; - } - else - { - RowSize = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents}; - RowCount = UpdateRegionHeight; - } - DEV_CHECK_ERR(SubresData.Stride >= RowSize, "Source data stride (", SubresData.Stride, ") is below the image row size (", RowSize, ")"); - const Uint32 PlaneSize = SubresData.Stride * RowCount; - DEV_CHECK_ERR(UpdateRegionDepth == 1 || SubresData.DepthStride >= PlaneSize, "Source data depth stride (", SubresData.DepthStride, ") is below the image plane size (", PlaneSize, ")"); -#endif -} - -void ValidateCopyTextureParams(const CopyTextureAttribs& CopyAttribs) -{ - VERIFY_EXPR(CopyAttribs.pSrcTexture != nullptr && CopyAttribs.pDstTexture != nullptr); - Box SrcBox; - const auto& SrcTexDesc = CopyAttribs.pSrcTexture->GetDesc(); - const auto& DstTexDesc = CopyAttribs.pDstTexture->GetDesc(); - auto pSrcBox = CopyAttribs.pSrcBox; - if (pSrcBox == nullptr) - { - auto MipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); - SrcBox.MaxX = MipLevelAttribs.LogicalWidth; - SrcBox.MaxY = MipLevelAttribs.LogicalHeight; - SrcBox.MaxZ = MipLevelAttribs.Depth; - pSrcBox = &SrcBox; - } - ValidateTextureRegion(SrcTexDesc, CopyAttribs.SrcMipLevel, CopyAttribs.SrcSlice, *pSrcBox); - - Box DstBox; - DstBox.MinX = CopyAttribs.DstX; - DstBox.MinY = CopyAttribs.DstY; - DstBox.MinZ = CopyAttribs.DstZ; - DstBox.MaxX = DstBox.MinX + (pSrcBox->MaxX - pSrcBox->MinX); - DstBox.MaxY = DstBox.MinY + (pSrcBox->MaxY - pSrcBox->MinY); - DstBox.MaxZ = DstBox.MinZ + (pSrcBox->MaxZ - pSrcBox->MinZ); - ValidateTextureRegion(DstTexDesc, CopyAttribs.DstMipLevel, CopyAttribs.DstSlice, DstBox); -} - -void ValidateMapTextureParams(const TextureDesc& TexDesc, - Uint32 MipLevel, - Uint32 ArraySlice, - MAP_TYPE MapType, - Uint32 MapFlags, - const Box* pMapRegion) -{ - VERIFY_TEX_PARAMS(MipLevel < TexDesc.MipLevels, "Mip level (", MipLevel, ") is out of allowed range [0, ", TexDesc.MipLevels - 1, "]"); - if (TexDesc.Type == RESOURCE_DIM_TEX_1D_ARRAY || - TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY || - TexDesc.Type == RESOURCE_DIM_TEX_CUBE || - TexDesc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) - { - VERIFY_TEX_PARAMS(ArraySlice < TexDesc.ArraySize, "Array slice (", ArraySlice, ") is out of range [0,", TexDesc.ArraySize - 1, "]"); - } - else - { - VERIFY_TEX_PARAMS(ArraySlice == 0, "Array slice (", ArraySlice, ") must be 0 for non-array textures"); - } - - if (pMapRegion != nullptr) - { - ValidateTextureRegion(TexDesc, MipLevel, ArraySlice, *pMapRegion); - } -} - -} // namespace Diligent diff --git a/Graphics/GraphicsEngine/src/TextureBase.cpp b/Graphics/GraphicsEngine/src/TextureBase.cpp new file mode 100644 index 00000000..e7073aae --- /dev/null +++ b/Graphics/GraphicsEngine/src/TextureBase.cpp @@ -0,0 +1,297 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "Texture.h" +#include "GraphicsAccessories.hpp" + +namespace Diligent +{ + +void ValidateTextureDesc(const TextureDesc& Desc) +{ +#define LOG_TEXTURE_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Texture '", (Desc.Name ? Desc.Name : ""), "': ", ##__VA_ARGS__) + + if (Desc.Type == RESOURCE_DIM_UNDEFINED) + { + LOG_TEXTURE_ERROR_AND_THROW("Resource dimension is undefined"); + } + + if (!(Desc.Type >= RESOURCE_DIM_TEX_1D && Desc.Type <= RESOURCE_DIM_TEX_CUBE_ARRAY)) + { + LOG_TEXTURE_ERROR_AND_THROW("Unexpected resource dimension"); + } + + if (Desc.Width == 0) + { + LOG_TEXTURE_ERROR_AND_THROW("Texture width cannot be zero"); + } + + // Perform some parameter correctness check + if (Desc.Type == RESOURCE_DIM_TEX_1D || Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) + { + if (Desc.Height != 1) + LOG_TEXTURE_ERROR_AND_THROW("Height (", Desc.Height, ") of Texture 1D/Texture 1D Array must be 1"); + } + else + { + if (Desc.Height == 0) + LOG_TEXTURE_ERROR_AND_THROW("Texture height cannot be zero"); + } + + if (Desc.Type == RESOURCE_DIM_TEX_3D && Desc.Depth == 0) + { + LOG_TEXTURE_ERROR_AND_THROW("3D texture depth cannot be zero"); + } + + if (Desc.Type == RESOURCE_DIM_TEX_1D || Desc.Type == RESOURCE_DIM_TEX_2D) + { + if (Desc.ArraySize != 1) + LOG_TEXTURE_ERROR_AND_THROW("Texture 1D/2D must have one array slice (", Desc.ArraySize, " provided). Use Texture 1D/2D array if you need more than one slice."); + } + + if (Desc.Type == RESOURCE_DIM_TEX_CUBE || Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) + { + if (Desc.Width != Desc.Height) + LOG_TEXTURE_ERROR_AND_THROW("For cube map textures, texture width (", Desc.Width, " provided) must match texture height (", Desc.Height, " provided)"); + + if (Desc.ArraySize < 6) + LOG_TEXTURE_ERROR_AND_THROW("Texture cube/cube array must have at least 6 slices (", Desc.ArraySize, " provided)."); + } + + Uint32 MaxDim = 0; + if (Desc.Type == RESOURCE_DIM_TEX_1D || Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) + MaxDim = Desc.Width; + else if (Desc.Type == RESOURCE_DIM_TEX_2D || Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || Desc.Type == RESOURCE_DIM_TEX_CUBE || Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) + MaxDim = std::max(Desc.Width, Desc.Height); + else if (Desc.Type == RESOURCE_DIM_TEX_3D) + MaxDim = std::max(std::max(Desc.Width, Desc.Height), Desc.Depth); + VERIFY(MaxDim >= (1U << (Desc.MipLevels - 1)), "Texture '", Desc.Name ? Desc.Name : "", "': Incorrect number of Mip levels (", Desc.MipLevels, ")"); + + if (Desc.SampleCount > 1) + { + if (!(Desc.Type == RESOURCE_DIM_TEX_2D || Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY)) + LOG_TEXTURE_ERROR_AND_THROW("Only Texture 2D/Texture 2D Array can be multisampled"); + + if (Desc.MipLevels != 1) + LOG_TEXTURE_ERROR_AND_THROW("Multisampled textures must have one mip level (", Desc.MipLevels, " levels specified)"); + + if (Desc.BindFlags & BIND_UNORDERED_ACCESS) + LOG_TEXTURE_ERROR_AND_THROW("UAVs are not allowed for multisampled resources"); + } + + if ((Desc.BindFlags & BIND_RENDER_TARGET) && + (Desc.Format == TEX_FORMAT_R8_SNORM || Desc.Format == TEX_FORMAT_RG8_SNORM || Desc.Format == TEX_FORMAT_RGBA8_SNORM || + Desc.Format == TEX_FORMAT_R16_SNORM || Desc.Format == TEX_FORMAT_RG16_SNORM || Desc.Format == TEX_FORMAT_RGBA16_SNORM)) + { + const auto* FmtName = GetTextureFormatAttribs(Desc.Format).Name; + LOG_WARNING_MESSAGE(FmtName, " texture is created with BIND_RENDER_TARGET flag set.\n" + "There might be an issue in OpenGL driver on NVidia hardware: when rendering to SNORM textures, all negative values are clamped to zero.\n" + "Use UNORM format instead."); + } + + if (Desc.Usage == USAGE_STAGING) + { + if (Desc.BindFlags != 0) + LOG_TEXTURE_ERROR_AND_THROW("Staging textures cannot be bound to any GPU pipeline stage"); + + if (Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) + LOG_TEXTURE_ERROR_AND_THROW("Mipmaps cannot be autogenerated for staging textures"); + + if (Desc.CPUAccessFlags == 0) + LOG_TEXTURE_ERROR_AND_THROW("Staging textures must specify CPU access flags"); + + if ((Desc.CPUAccessFlags & (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) == (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) + LOG_TEXTURE_ERROR_AND_THROW("Staging textures must use exactly one of ACESS_READ or ACCESS_WRITE flags"); + } +} + + +void ValidateTextureRegion(const TextureDesc& TexDesc, Uint32 MipLevel, Uint32 Slice, const Box& Box) +{ +#define VERIFY_TEX_PARAMS(Expr, ...) \ + do \ + { \ + if (!(Expr)) \ + { \ + LOG_ERROR("Texture '", (TexDesc.Name ? TexDesc.Name : ""), "': ", ##__VA_ARGS__); \ + } \ + } while (false) + +#ifdef DILIGENT_DEVELOPMENT + VERIFY_TEX_PARAMS(MipLevel < TexDesc.MipLevels, "Mip level (", MipLevel, ") is out of allowed range [0, ", TexDesc.MipLevels - 1, "]"); + VERIFY_TEX_PARAMS(Box.MinX < Box.MaxX, "Invalid X range: ", Box.MinX, "..", Box.MaxX); + VERIFY_TEX_PARAMS(Box.MinY < Box.MaxY, "Invalid Y range: ", Box.MinY, "..", Box.MaxY); + VERIFY_TEX_PARAMS(Box.MinZ < Box.MaxZ, "Invalid Z range: ", Box.MinZ, "..", Box.MaxZ); + + if (TexDesc.Type == RESOURCE_DIM_TEX_1D_ARRAY || + TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY || + TexDesc.Type == RESOURCE_DIM_TEX_CUBE || + TexDesc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) + { + VERIFY_TEX_PARAMS(Slice < TexDesc.ArraySize, "Array slice (", Slice, ") is out of range [0,", TexDesc.ArraySize - 1, "]"); + } + else + { + VERIFY_TEX_PARAMS(Slice == 0, "Array slice (", Slice, ") must be 0 for non-array textures"); + } + + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + + Uint32 MipWidth = std::max(TexDesc.Width >> MipLevel, 1U); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) + { + VERIFY_EXPR((FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth - 1)) == 0); + Uint32 BlockAlignedMipWidth = (MipWidth + (FmtAttribs.BlockWidth - 1)) & ~(FmtAttribs.BlockWidth - 1); + VERIFY_TEX_PARAMS(Box.MaxX <= BlockAlignedMipWidth, "Region max X coordinate (", Box.MaxX, ") is out of allowed range [0, ", BlockAlignedMipWidth, "]"); + VERIFY_TEX_PARAMS((Box.MinX % FmtAttribs.BlockWidth) == 0, "For compressed formats, the region min X coordinate (", Box.MinX, ") must be a multiple of block width (", Uint32{FmtAttribs.BlockWidth}, ")"); + VERIFY_TEX_PARAMS((Box.MaxX % FmtAttribs.BlockWidth) == 0 || Box.MaxX == MipWidth, "For compressed formats, the region max X coordinate (", Box.MaxX, ") must be a multiple of block width (", Uint32{FmtAttribs.BlockWidth}, ") or equal the mip level width (", MipWidth, ")"); + } + else + VERIFY_TEX_PARAMS(Box.MaxX <= MipWidth, "Region max X coordinate (", Box.MaxX, ") is out of allowed range [0, ", MipWidth, "]"); + + if (TexDesc.Type != RESOURCE_DIM_TEX_1D && + TexDesc.Type != RESOURCE_DIM_TEX_1D_ARRAY) + { + Uint32 MipHeight = std::max(TexDesc.Height >> MipLevel, 1U); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) + { + VERIFY_EXPR((FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight - 1)) == 0); + Uint32 BlockAlignedMipHeight = (MipHeight + (FmtAttribs.BlockHeight - 1)) & ~(FmtAttribs.BlockHeight - 1); + VERIFY_TEX_PARAMS(Box.MaxY <= BlockAlignedMipHeight, "Region max Y coordinate (", Box.MaxY, ") is out of allowed range [0, ", BlockAlignedMipHeight, "]"); + VERIFY_TEX_PARAMS((Box.MinY % FmtAttribs.BlockHeight) == 0, "For compressed formats, the region min Y coordinate (", Box.MinY, ") must be a multiple of block height (", Uint32{FmtAttribs.BlockHeight}, ")"); + VERIFY_TEX_PARAMS((Box.MaxY % FmtAttribs.BlockHeight) == 0 || Box.MaxY == MipHeight, "For compressed formats, the region max Y coordinate (", Box.MaxY, ") must be a multiple of block height (", Uint32{FmtAttribs.BlockHeight}, ") or equal the mip level height (", MipHeight, ")"); + } + else + VERIFY_TEX_PARAMS(Box.MaxY <= MipHeight, "Region max Y coordinate (", Box.MaxY, ") is out of allowed range [0, ", MipHeight, "]"); + } + + if (TexDesc.Type == RESOURCE_DIM_TEX_3D) + { + Uint32 MipDepth = std::max(TexDesc.Depth >> MipLevel, 1U); + VERIFY_TEX_PARAMS(Box.MaxZ <= MipDepth, "Region max Z coordinate (", Box.MaxZ, ") is out of allowed range [0, ", MipDepth, "]"); + } + else + { + VERIFY_TEX_PARAMS(Box.MinZ == 0, "Region min Z (", Box.MinZ, ") must be 0 for all but 3D textures"); + VERIFY_TEX_PARAMS(Box.MaxZ == 1, "Region max Z (", Box.MaxZ, ") must be 1 for all but 3D textures"); + } +#endif +} + +void ValidateUpdateTextureParams(const TextureDesc& TexDesc, Uint32 MipLevel, Uint32 Slice, const Box& DstBox, const TextureSubResData& SubresData) +{ + VERIFY((SubresData.pData != nullptr) ^ (SubresData.pSrcBuffer != nullptr), "Either CPU data pointer (pData) or GPU buffer (pSrcBuffer) must not be null, but not both"); + ValidateTextureRegion(TexDesc, MipLevel, Slice, DstBox); + +#ifdef DILIGENT_DEVELOPMENT + VERIFY_TEX_PARAMS(TexDesc.SampleCount == 1, "Only non-multisampled textures can be updated with UpdateData()"); + VERIFY_TEX_PARAMS((SubresData.Stride & 0x03) == 0, "Texture data stride (", SubresData.Stride, ") must be at least 32-bit aligned"); + VERIFY_TEX_PARAMS((SubresData.DepthStride & 0x03) == 0, "Texture data depth stride (", SubresData.DepthStride, ") must be at least 32-bit aligned"); + + auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX; + auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY; + auto UpdateRegionDepth = DstBox.MaxZ - DstBox.MinZ; + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + Uint32 RowSize = 0; + Uint32 RowCount = 0; + if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) + { + // Align update region size by the block size. This is only necessary when updating + // coarse mip levels. Otherwise UpdateRegionWidth/Height should be multiples of block size + VERIFY_EXPR((FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth - 1)) == 0); + VERIFY_EXPR((FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight - 1)) == 0); + UpdateRegionWidth = (UpdateRegionWidth + (FmtAttribs.BlockWidth - 1)) & ~(FmtAttribs.BlockWidth - 1); + UpdateRegionHeight = (UpdateRegionHeight + (FmtAttribs.BlockHeight - 1)) & ~(FmtAttribs.BlockHeight - 1); + RowSize = UpdateRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize}; + RowCount = UpdateRegionHeight / FmtAttribs.BlockHeight; + } + else + { + RowSize = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents}; + RowCount = UpdateRegionHeight; + } + DEV_CHECK_ERR(SubresData.Stride >= RowSize, "Source data stride (", SubresData.Stride, ") is below the image row size (", RowSize, ")"); + const Uint32 PlaneSize = SubresData.Stride * RowCount; + DEV_CHECK_ERR(UpdateRegionDepth == 1 || SubresData.DepthStride >= PlaneSize, "Source data depth stride (", SubresData.DepthStride, ") is below the image plane size (", PlaneSize, ")"); +#endif +} + +void ValidateCopyTextureParams(const CopyTextureAttribs& CopyAttribs) +{ + VERIFY_EXPR(CopyAttribs.pSrcTexture != nullptr && CopyAttribs.pDstTexture != nullptr); + Box SrcBox; + const auto& SrcTexDesc = CopyAttribs.pSrcTexture->GetDesc(); + const auto& DstTexDesc = CopyAttribs.pDstTexture->GetDesc(); + auto pSrcBox = CopyAttribs.pSrcBox; + if (pSrcBox == nullptr) + { + auto MipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); + SrcBox.MaxX = MipLevelAttribs.LogicalWidth; + SrcBox.MaxY = MipLevelAttribs.LogicalHeight; + SrcBox.MaxZ = MipLevelAttribs.Depth; + pSrcBox = &SrcBox; + } + ValidateTextureRegion(SrcTexDesc, CopyAttribs.SrcMipLevel, CopyAttribs.SrcSlice, *pSrcBox); + + Box DstBox; + DstBox.MinX = CopyAttribs.DstX; + DstBox.MinY = CopyAttribs.DstY; + DstBox.MinZ = CopyAttribs.DstZ; + DstBox.MaxX = DstBox.MinX + (pSrcBox->MaxX - pSrcBox->MinX); + DstBox.MaxY = DstBox.MinY + (pSrcBox->MaxY - pSrcBox->MinY); + DstBox.MaxZ = DstBox.MinZ + (pSrcBox->MaxZ - pSrcBox->MinZ); + ValidateTextureRegion(DstTexDesc, CopyAttribs.DstMipLevel, CopyAttribs.DstSlice, DstBox); +} + +void ValidateMapTextureParams(const TextureDesc& TexDesc, + Uint32 MipLevel, + Uint32 ArraySlice, + MAP_TYPE MapType, + Uint32 MapFlags, + const Box* pMapRegion) +{ + VERIFY_TEX_PARAMS(MipLevel < TexDesc.MipLevels, "Mip level (", MipLevel, ") is out of allowed range [0, ", TexDesc.MipLevels - 1, "]"); + if (TexDesc.Type == RESOURCE_DIM_TEX_1D_ARRAY || + TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY || + TexDesc.Type == RESOURCE_DIM_TEX_CUBE || + TexDesc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) + { + VERIFY_TEX_PARAMS(ArraySlice < TexDesc.ArraySize, "Array slice (", ArraySlice, ") is out of range [0,", TexDesc.ArraySize - 1, "]"); + } + else + { + VERIFY_TEX_PARAMS(ArraySlice == 0, "Array slice (", ArraySlice, ") must be 0 for non-array textures"); + } + + if (pMapRegion != nullptr) + { + ValidateTextureRegion(TexDesc, MipLevel, ArraySlice, *pMapRegion); + } +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngine/src/pch.cpp b/Graphics/GraphicsEngine/src/pch.cpp deleted file mode 100644 index 07ab47d2..00000000 --- a/Graphics/GraphicsEngine/src/pch.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright 2015-2018 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -// stdafx.cpp : source file that includes just the standard includes -// RenderEngine.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "pch.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file -- cgit v1.2.3 From 4b44eea6ac2311d5e9d4373053c6aa382a1e3e0a Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 24 Jul 2020 11:35:54 -0700 Subject: Defined SubpassDesc struct --- Graphics/GraphicsEngine/include/RenderPassBase.hpp | 91 ++++++++++++- Graphics/GraphicsEngine/interface/RenderPass.h | 142 ++++++++++++++++++++- Graphics/GraphicsEngine/src/RenderPassBase.cpp | 20 +++ 3 files changed, 251 insertions(+), 2 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/RenderPassBase.hpp b/Graphics/GraphicsEngine/include/RenderPassBase.hpp index 03fecd78..a8d73dc2 100644 --- a/Graphics/GraphicsEngine/include/RenderPassBase.hpp +++ b/Graphics/GraphicsEngine/include/RenderPassBase.hpp @@ -76,6 +76,20 @@ public: } } + Uint32 TotalAttachmentReferencesCount = 0; + Uint32 TotalPreserveAttachmentsCount = 0; + CountSubpassAttachmentReferences(Desc, TotalAttachmentReferencesCount, TotalPreserveAttachmentsCount); + if (TotalAttachmentReferencesCount != 0) + { + m_pAttachmentReferences = ALLOCATE(GetRawAllocator(), "Memory for subpass attachment references array", AttachmentReference, TotalAttachmentReferencesCount); + } + if (TotalPreserveAttachmentsCount != 0) + { + m_pPreserveAttachments = ALLOCATE(GetRawAllocator(), "Memory for subpass preserve attachments array", Uint32, TotalPreserveAttachmentsCount); + } + + auto* pCurrAttachmentRef = m_pAttachmentReferences; + auto* pCurrPreserveAttachment = m_pPreserveAttachments; if (Desc.SubpassCount != 0) { auto* pSubpasses = @@ -83,9 +97,56 @@ public: this->m_Desc.pSubpasses = pSubpasses; for (Uint32 i = 0; i < Desc.SubpassCount; ++i) { - pSubpasses[i] = Desc.pSubpasses[i]; + const auto& SrcSubpass = Desc.pSubpasses[i]; + auto& DstSubpass = pSubpasses[i]; + + DstSubpass = SrcSubpass; + if (SrcSubpass.InputAttachmentCount != 0) + { + DstSubpass.pInputAttachments = pCurrAttachmentRef; + for (Uint32 input_attachment = 0; input_attachment < SrcSubpass.InputAttachmentCount; ++input_attachment) + *(pCurrAttachmentRef++) = SrcSubpass.pInputAttachments[input_attachment]; + } + else + DstSubpass.pInputAttachments = nullptr; + + if (SrcSubpass.RenderTargetAttachmentCount != 0) + { + DstSubpass.pRenderTargetAttachments = pCurrAttachmentRef; + for (Uint32 rt_attachment = 0; rt_attachment < SrcSubpass.RenderTargetAttachmentCount; ++rt_attachment) + *(pCurrAttachmentRef++) = SrcSubpass.pRenderTargetAttachments[rt_attachment]; + if (DstSubpass.pResolveAttachments) + { + for (Uint32 rslv_attachment = 0; rslv_attachment < SrcSubpass.RenderTargetAttachmentCount; ++rslv_attachment) + *(pCurrAttachmentRef++) = SrcSubpass.pResolveAttachments[rslv_attachment]; + } + else + DstSubpass.pResolveAttachments = nullptr; + } + else + { + DstSubpass.pRenderTargetAttachments = nullptr; + DstSubpass.pResolveAttachments = nullptr; + } + + if (SrcSubpass.pDepthStencilAttachment != nullptr) + { + DstSubpass.pDepthStencilAttachment = pCurrAttachmentRef; + *(pCurrAttachmentRef++) = *SrcSubpass.pDepthStencilAttachment; + } + + if (SrcSubpass.PreserveAttachmentCount != 0) + { + DstSubpass.pPreserveAttachments = pCurrPreserveAttachment; + for (Uint32 prsv_attachment = 0; prsv_attachment < SrcSubpass.PreserveAttachmentCount; ++prsv_attachment) + *(pCurrPreserveAttachment++) = SrcSubpass.pPreserveAttachments[prsv_attachment]; + } + else + DstSubpass.pPreserveAttachments = nullptr; } } + VERIFY_EXPR(pCurrAttachmentRef - m_pAttachmentReferences == TotalAttachmentReferencesCount); + VERIFY_EXPR(pCurrPreserveAttachment - m_pPreserveAttachments == TotalPreserveAttachmentsCount); if (Desc.DependencyCount != 0) { @@ -108,9 +169,37 @@ public: RawAllocator.Free(const_cast(this->m_Desc.pSubpasses)); if (this->m_Desc.pDependencies != nullptr) RawAllocator.Free(const_cast(this->m_Desc.pDependencies)); + if (m_pAttachmentReferences != nullptr) + RawAllocator.Free(m_pAttachmentReferences); + if (m_pPreserveAttachments != nullptr) + RawAllocator.Free(m_pPreserveAttachments); } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_RenderPass, TDeviceObjectBase) + +protected: + static void CountSubpassAttachmentReferences(const RenderPassDesc& Desc, + Uint32& TotalAttachmentReferencesCount, + Uint32& TotalPreserveAttachmentsCount) + { + TotalAttachmentReferencesCount = 0; + TotalPreserveAttachmentsCount = 0; + for (Uint32 i = 0; i < Desc.SubpassCount; ++i) + { + const auto& Subpass = Desc.pSubpasses[i]; + TotalAttachmentReferencesCount += Subpass.InputAttachmentCount; + TotalAttachmentReferencesCount += Subpass.RenderTargetAttachmentCount; + if (Subpass.pResolveAttachments != nullptr) + TotalAttachmentReferencesCount += Subpass.RenderTargetAttachmentCount; + if (Subpass.pDepthStencilAttachment != nullptr) + TotalAttachmentReferencesCount += 1; + TotalPreserveAttachmentsCount += Subpass.PreserveAttachmentCount; + } + } + +private: + AttachmentReference* m_pAttachmentReferences = nullptr; + Uint32* m_pPreserveAttachments = nullptr; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngine/interface/RenderPass.h b/Graphics/GraphicsEngine/interface/RenderPass.h index 36cfc46c..3ac3e3ce 100644 --- a/Graphics/GraphicsEngine/interface/RenderPass.h +++ b/Graphics/GraphicsEngine/interface/RenderPass.h @@ -124,11 +124,151 @@ struct RenderPassAttachmentDesc }; typedef struct RenderPassAttachmentDesc RenderPassAttachmentDesc; +#define ATTACHMENT_UNUSED (~0U) + +/// Attachment reference description. +struct AttachmentReference +{ + /// Either an integer value identifying an attachment at the corresponding index in RenderPassDesc::pAttachments, + /// or ATTACHMENT_UNUSED to signify that this attachment is not used. + Uint32 AttachmentIndex DEFAULT_INITIALIZER(0); + + /// The state of the attachment during the subpass. + RESOURCE_STATE State DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN); + +#if DILIGENT_CPP_INTERFACE + AttachmentReference()noexcept{} + + AttachmentReference(Uint32 _AttachmentIndex, + RESOURCE_STATE _State)noexcept : + AttachmentIndex{_AttachmentIndex}, + State {_State} + {} + + /// Tests if two structures are equivalent + + /// \param [in] RHS - reference to the structure to perform comparison with + /// \return + /// - True if all members of the two structures are equal. + /// - False otherwise + bool operator == (const AttachmentReference& RHS) const + { + return AttachmentIndex == RHS.AttachmentIndex && + State == RHS.State; + } + + bool operator != (const AttachmentReference& RHS) const + { + return !(*this == RHS); + } +#endif +}; +typedef struct AttachmentReference AttachmentReference; + /// Render pass subpass decription. struct SubpassDesc { - int Dummy; + /// The number of input attachments the subpass uses. + Uint32 InputAttachmentCount DEFAULT_INITIALIZER(0); + + /// Pointer to the array of input attachments, see Diligent::AttachmentReference. + const AttachmentReference* pInputAttachments DEFAULT_INITIALIZER(nullptr); + + /// The number of color render target attachments. + Uint32 RenderTargetAttachmentCount DEFAULT_INITIALIZER(0); + + /// Pointer to the array of color render target attachments, see Diligent::AttachmentReference. + + /// Each element of the pRenderTargetAttachments array corresponds to an output in the pixel shader, + /// i.e. if the shader declares an output variable decorated with a render target index X, then it uses + /// the attachment provided in pRenderTargetAttachments[X]. If the attachment index is ATTACHMENT_UNUSED, + /// writes to this render target are ignored. + const AttachmentReference* pRenderTargetAttachments DEFAULT_INITIALIZER(nullptr); + + /// Pointer to the array of resolve attachments, see Diligent::AttachmentReference. + + /// If pResolveAttachments is not NULL, each of its elements corresponds to a render target attachment + /// (the element in pRenderTargetAttachments at the same index), and a multisample resolve operation is + /// defined for each attachment. At the end of each subpass, multisample resolve operations read the subpass's + /// color attachments, and resolve the samples for each pixel within the render area to the same pixel location + /// in the corresponding resolve attachments, unless the resolve attachment index is ATTACHMENT_UNUSED. + const AttachmentReference* pResolveAttachments DEFAULT_INITIALIZER(nullptr); + + /// Pointer to the depth-stencil attachment, see Diligent::AttachmentReference. + const AttachmentReference* pDepthStencilAttachment DEFAULT_INITIALIZER(nullptr); + + /// The number of preserve attachments. + Uint32 PreserveAttachmentCount DEFAULT_INITIALIZER(0); + + /// Pointer to the array of preserve attachments, see Diligent::AttachmentReference. + const Uint32* pPreserveAttachments DEFAULT_INITIALIZER(nullptr); + +#if DILIGENT_CPP_INTERFACE + /// Tests if two structures are equivalent + + /// \param [in] RHS - reference to the structure to perform comparison with + /// \return + /// - True if all members of the two structures are equal. + /// - False otherwise + bool operator == (const SubpassDesc& RHS)const + { + if (InputAttachmentCount != RHS.InputAttachmentCount || + RenderTargetAttachmentCount != RHS.RenderTargetAttachmentCount || + PreserveAttachmentCount != RHS.PreserveAttachmentCount) + return false; + + for(Uint32 i=0; i < InputAttachmentCount; ++i) + { + if (pInputAttachments[i] != RHS.pInputAttachments[i]) + return false; + } + + for(Uint32 i=0; i < RenderTargetAttachmentCount; ++i) + { + if (pRenderTargetAttachments[i] != RHS.pRenderTargetAttachments[i]) + return false; + } + + if ((pResolveAttachments == nullptr && RHS.pResolveAttachments != nullptr) || + (pResolveAttachments != nullptr && RHS.pResolveAttachments == nullptr)) + return false; + + if (pResolveAttachments != nullptr && RHS.pResolveAttachments != nullptr) + { + for(Uint32 i=0; i < RenderTargetAttachmentCount; ++i) + { + if (pResolveAttachments[i] != RHS.pResolveAttachments[i]) + return false; + } + } + + if ((pDepthStencilAttachment == nullptr && RHS.pDepthStencilAttachment != nullptr) || + (pDepthStencilAttachment != nullptr && RHS.pDepthStencilAttachment == nullptr)) + return false; + + if (pDepthStencilAttachment != nullptr && RHS.pDepthStencilAttachment != nullptr) + { + if (*pDepthStencilAttachment != *RHS.pDepthStencilAttachment) + return false; + } + + if ((pPreserveAttachments == nullptr && RHS.pPreserveAttachments != nullptr) || + (pPreserveAttachments != nullptr && RHS.pPreserveAttachments == nullptr)) + return false; + + if (pPreserveAttachments != nullptr && RHS.pPreserveAttachments != nullptr) + { + for(Uint32 i=0; i < PreserveAttachmentCount; ++i) + { + if (pPreserveAttachments[i] != RHS.pPreserveAttachments[i]) + return false; + } + } + + return true; + } +#endif }; typedef struct SubpassDesc SubpassDesc; diff --git a/Graphics/GraphicsEngine/src/RenderPassBase.cpp b/Graphics/GraphicsEngine/src/RenderPassBase.cpp index 4c4e0abd..782e950f 100644 --- a/Graphics/GraphicsEngine/src/RenderPassBase.cpp +++ b/Graphics/GraphicsEngine/src/RenderPassBase.cpp @@ -94,6 +94,26 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) } } } + + for (Uint32 i = 0; i < Desc.SubpassCount; ++i) + { + const auto& Subpass = Desc.pSubpasses[i]; + if (Subpass.InputAttachmentCount != 0 && Subpass.pInputAttachments == nullptr) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the input attachment count (", Subpass.InputAttachmentCount, ") of subpass ", i, + " is not zero, while pInputAttachments is null"); + } + if (Subpass.RenderTargetAttachmentCount != 0 && Subpass.pRenderTargetAttachments == nullptr) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the render target attachment count (", Subpass.RenderTargetAttachmentCount, ") of subpass ", i, + " is not zero, while pRenderTargetAttachments is null"); + } + if (Subpass.PreserveAttachmentCount != 0 && Subpass.pPreserveAttachments == nullptr) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the preserve attachment count (", Subpass.PreserveAttachmentCount, ") of subpass ", i, + " is not zero, while pPreserveAttachments is null"); + } + } } } // namespace Diligent -- cgit v1.2.3 From b175c814abddc737071b17c7509658fecbb9a7f5 Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 24 Jul 2020 16:42:34 -0700 Subject: Added IFramebuffer interface --- Graphics/GraphicsEngine/CMakeLists.txt | 1 + Graphics/GraphicsEngine/interface/Framebuffer.h | 102 ++++++++++++++++++++++++ Graphics/GraphicsEngine/interface/RenderPass.h | 2 +- 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 Graphics/GraphicsEngine/interface/Framebuffer.h (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt index d7b51d87..7a8a4715 100644 --- a/Graphics/GraphicsEngine/CMakeLists.txt +++ b/Graphics/GraphicsEngine/CMakeLists.txt @@ -42,6 +42,7 @@ set(INTERFACE interface/DeviceObject.h interface/EngineFactory.h interface/Fence.h + interface/Framebuffer.h interface/GraphicsTypes.h interface/InputLayout.h interface/PipelineState.h diff --git a/Graphics/GraphicsEngine/interface/Framebuffer.h b/Graphics/GraphicsEngine/interface/Framebuffer.h new file mode 100644 index 00000000..c8bed172 --- /dev/null +++ b/Graphics/GraphicsEngine/interface/Framebuffer.h @@ -0,0 +1,102 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +// clang-format off + +/// \file +/// Definition of the Diligent::IFramebuffer interface and related data structures + +#include "DeviceObject.h" +#include "RenderPass.h" +#include "TextureView.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {05DA9E47-3CA6-4F96-A967-1DDDC53181A6} +static const struct INTERFACE_ID IID_Framebuffer = + { 0x5da9e47, 0x3ca6, 0x4f96, { 0xa9, 0x67, 0x1d, 0xdd, 0xc5, 0x31, 0x81, 0xa6 } }; + +/// Framebuffer description. +struct FramebufferDesc DILIGENT_DERIVE(DeviceObjectAttribs) + + /// Render pass that the framebuffer will be compatible with. + IRenderPass* pRenderPass DEFAULT_INITIALIZER(nullptr); + + /// The number of attachments. + Uint32 AttachmentCount DEFAULT_INITIALIZER(0); + + /// Pointer to the array of attachments. + const ITextureView* pAttachments DEFAULT_INITIALIZER(nullptr); + + /// Width of the framebuffer. + Uint32 Width DEFAULT_INITIALIZER(0); + + /// Height of the framebuffer. + Uint32 Height DEFAULT_INITIALIZER(0); + + /// The number of layers in the framebuffer. + Uint32 Layers DEFAULT_INITIALIZER(0); +}; +typedef struct FramebufferDesc FramebufferDesc; + +#if DILIGENT_CPP_INTERFACE + +/// Framebuffer interface + +/// Framebuffer has no methods. +class IFramebuffer : public IDeviceObject +{ +public: + virtual const FramebufferDesc& GetDesc() const override = 0; +}; + +#else + +struct IFramebuffer; + +// C requires that a struct or union has at least one member +//struct IFramebufferMethods +//{ +//}; + +struct IFramebufferVtbl +{ + struct IObjectMethods Object; + struct IDeviceObjectMethods DeviceObject; + //struct IFramebufferMethods Framebuffer; +}; + +typedef struct IFramebuffer +{ + struct IFramebufferVtbl* pVtbl; +} IFramebuffer; + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngine/interface/RenderPass.h b/Graphics/GraphicsEngine/interface/RenderPass.h index 3ac3e3ce..0cc37f96 100644 --- a/Graphics/GraphicsEngine/interface/RenderPass.h +++ b/Graphics/GraphicsEngine/interface/RenderPass.h @@ -276,7 +276,7 @@ typedef struct SubpassDesc SubpassDesc; /// Subpass dependency description struct SubpassDependencyDesc { - int Dummy; + void* TBD; }; typedef struct SubpassDependencyDesc SubpassDependencyDesc; -- cgit v1.2.3 From 16dd04efc73e4093a991a517f786ebaf03f3f6d1 Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 24 Jul 2020 21:18:48 -0700 Subject: Added framebuffer object implementation stubs --- Graphics/GraphicsEngine/CMakeLists.txt | 1 + .../GraphicsEngine/include/FramebufferBase.hpp | 77 ++++++++++++++++++++++ .../GraphicsEngine/include/RenderDeviceBase.hpp | 29 ++++---- Graphics/GraphicsEngine/include/RenderPassBase.hpp | 2 +- Graphics/GraphicsEngine/interface/RenderDevice.h | 14 ++++ 5 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 Graphics/GraphicsEngine/include/FramebufferBase.hpp (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt index 7a8a4715..daafe96e 100644 --- a/Graphics/GraphicsEngine/CMakeLists.txt +++ b/Graphics/GraphicsEngine/CMakeLists.txt @@ -13,6 +13,7 @@ set(INCLUDE include/EngineFactoryBase.hpp include/EngineMemory.h include/FenceBase.hpp + include/FramebufferBase.hpp include/pch.h include/PipelineStateBase.hpp include/QueryBase.hpp diff --git a/Graphics/GraphicsEngine/include/FramebufferBase.hpp b/Graphics/GraphicsEngine/include/FramebufferBase.hpp new file mode 100644 index 00000000..ad33e9c0 --- /dev/null +++ b/Graphics/GraphicsEngine/include/FramebufferBase.hpp @@ -0,0 +1,77 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Implementation of the Diligent::FramebufferBase template class + +#include "Framebuffer.h" +#include "DeviceObjectBase.hpp" +#include "RenderDeviceBase.hpp" + +namespace Diligent +{ + +void ValidateFramebufferDesc(const FramebufferDesc& Desc); + +/// Template class implementing base functionality for the framebuffer object. + +/// \tparam BaseInterface - base interface that this class will inheret +/// (e.g. Diligent::IFramebufferVk). +/// \tparam RenderDeviceImplType - type of the render device implementation +/// (Diligent::RenderDeviceD3D11Impl, Diligent::RenderDeviceD3D12Impl, +/// Diligent::RenderDeviceGLImpl, or Diligent::RenderDeviceVkImpl) +template +class FramebufferBase : public DeviceObjectBase +{ +public: + using TDeviceObjectBase = DeviceObjectBase; + + /// \param pRefCounters - reference counters object that controls the lifetime of this framebuffer pass. + /// \param pDevice - pointer to the device. + /// \param Desc - Framebuffer description. + /// \param bIsDeviceInternal - flag indicating if the Framebuffer is an internal device object and + /// must not keep a strong reference to the device. + FramebufferBase(IReferenceCounters* pRefCounters, + RenderDeviceImplType* pDevice, + const FramebufferDesc& Desc, + bool bIsDeviceInternal = false) : + TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal} + { + } + + ~FramebufferBase() + { + } + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_Framebuffer, TDeviceObjectBase) + +private: +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp index 854e5ec9..a0ffeda6 100644 --- a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp +++ b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp @@ -223,6 +223,9 @@ public: /// Size of the render pass object (RenderPassD3D12Impl, RenderPassVkImpl, etc.), in bytes const size_t RenderPassObjSize; + + /// Size of the framebuffer object (FramebufferD3D12Impl, FramebufferVkImpl, etc.), in bytes + const size_t FramebufferObjSize; }; /// \param pRefCounters - reference counters object that controls the lifetime of this render device @@ -246,18 +249,19 @@ public: m_TexFmtInfoInitFlags (TEX_FORMAT_NUM_FORMATS, false, STD_ALLOCATOR_RAW_MEM(bool, RawMemAllocator, "Allocator for vector")), m_wpDeferredContexts (NumDeferredContexts, RefCntWeakPtr(), STD_ALLOCATOR_RAW_MEM(RefCntWeakPtr, RawMemAllocator, "Allocator for vector< RefCntWeakPtr >")), m_RawMemAllocator {RawMemAllocator}, - m_TexObjAllocator {RawMemAllocator, ObjectSizes.TextureObjSize, 64 }, - m_TexViewObjAllocator {RawMemAllocator, ObjectSizes.TexViewObjSize, 64 }, - m_BufObjAllocator {RawMemAllocator, ObjectSizes.BufferObjSize, 128 }, - m_BuffViewObjAllocator {RawMemAllocator, ObjectSizes.BuffViewObjSize, 128 }, - m_ShaderObjAllocator {RawMemAllocator, ObjectSizes.ShaderObjSize, 32 }, - m_SamplerObjAllocator {RawMemAllocator, ObjectSizes.SamplerObjSize, 32 }, - m_PSOAllocator {RawMemAllocator, ObjectSizes.PSOSize, 128 }, - m_SRBAllocator {RawMemAllocator, ObjectSizes.SRBSize, 1024}, - m_ResMappingAllocator {RawMemAllocator, sizeof(ResourceMappingImpl), 16 }, - m_FenceAllocator {RawMemAllocator, ObjectSizes.FenceSize, 16 }, - m_QueryAllocator {RawMemAllocator, ObjectSizes.QuerySize, 16 }, - m_RenderPassAllocator {RawMemAllocator, ObjectSizes.RenderPassObjSize, 16 } + m_TexObjAllocator {RawMemAllocator, ObjectSizes.TextureObjSize, 64 }, + m_TexViewObjAllocator {RawMemAllocator, ObjectSizes.TexViewObjSize, 64 }, + m_BufObjAllocator {RawMemAllocator, ObjectSizes.BufferObjSize, 128 }, + m_BuffViewObjAllocator {RawMemAllocator, ObjectSizes.BuffViewObjSize, 128 }, + m_ShaderObjAllocator {RawMemAllocator, ObjectSizes.ShaderObjSize, 32 }, + m_SamplerObjAllocator {RawMemAllocator, ObjectSizes.SamplerObjSize, 32 }, + m_PSOAllocator {RawMemAllocator, ObjectSizes.PSOSize, 128 }, + m_SRBAllocator {RawMemAllocator, ObjectSizes.SRBSize, 1024}, + m_ResMappingAllocator {RawMemAllocator, sizeof(ResourceMappingImpl), 16 }, + m_FenceAllocator {RawMemAllocator, ObjectSizes.FenceSize, 16 }, + m_QueryAllocator {RawMemAllocator, ObjectSizes.QuerySize, 16 }, + m_RenderPassAllocator {RawMemAllocator, ObjectSizes.RenderPassObjSize, 16 }, + m_FramebufferAllocator {RawMemAllocator, ObjectSizes.FramebufferObjSize, 16 } // clang-format on { // Initialize texture format info @@ -431,6 +435,7 @@ protected: FixedBlockMemoryAllocator m_FenceAllocator; ///< Allocator for fence objects FixedBlockMemoryAllocator m_QueryAllocator; ///< Allocator for query objects FixedBlockMemoryAllocator m_RenderPassAllocator; ///< Allocator for render pass objects + FixedBlockMemoryAllocator m_FramebufferAllocator; ///< Allocator for framebuffer objects }; diff --git a/Graphics/GraphicsEngine/include/RenderPassBase.hpp b/Graphics/GraphicsEngine/include/RenderPassBase.hpp index a8d73dc2..8099abb2 100644 --- a/Graphics/GraphicsEngine/include/RenderPassBase.hpp +++ b/Graphics/GraphicsEngine/include/RenderPassBase.hpp @@ -42,7 +42,7 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc); /// Template class implementing base functionality for the render pass object. /// \tparam BaseInterface - base interface that this class will inheret -/// (Diligent::IRenderPassVk). +/// (e.g. Diligent::IRenderPassVk). /// \tparam RenderDeviceImplType - type of the render device implementation /// (Diligent::RenderDeviceD3D11Impl, Diligent::RenderDeviceD3D12Impl, /// Diligent::RenderDeviceGLImpl, or Diligent::RenderDeviceVkImpl) diff --git a/Graphics/GraphicsEngine/interface/RenderDevice.h b/Graphics/GraphicsEngine/interface/RenderDevice.h index 24c641bc..ddbc75b2 100644 --- a/Graphics/GraphicsEngine/interface/RenderDevice.h +++ b/Graphics/GraphicsEngine/interface/RenderDevice.h @@ -47,6 +47,7 @@ #include "Fence.h" #include "Query.h" #include "RenderPass.h" +#include "Framebuffer.h" #include "DepthStencilState.h" #include "RasterizerState.h" @@ -201,6 +202,19 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject) IRenderPass** ppRenderPass) PURE; + + /// Creates a framebuffer object + + /// \param [in] Desc - Framebuffer description, see Diligent::FramebufferDesc for details. + /// \param [out] ppFramebuffer - Address of the memory location where the pointer to the + /// framebuffer interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + VIRTUAL void METHOD(CreateFramebuffer)(THIS_ + const FramebufferDesc REF Desc, + IFramebuffer** ppFramebuffer) PURE; + + /// Gets the device capabilities, see Diligent::DeviceCaps for details VIRTUAL const DeviceCaps REF METHOD(GetDeviceCaps)(THIS) CONST PURE; -- cgit v1.2.3 From 955768292c4316f6e12c7cceff330a203a756337 Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 24 Jul 2020 22:59:29 -0700 Subject: Implemente framebuffer in Vulkan --- .../GraphicsEngine/include/FramebufferBase.hpp | 44 ++++++++++++++++++++++ Graphics/GraphicsEngine/interface/Framebuffer.h | 14 +++---- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 7 ++-- 3 files changed, 55 insertions(+), 10 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/FramebufferBase.hpp b/Graphics/GraphicsEngine/include/FramebufferBase.hpp index ad33e9c0..6bf77918 100644 --- a/Graphics/GraphicsEngine/include/FramebufferBase.hpp +++ b/Graphics/GraphicsEngine/include/FramebufferBase.hpp @@ -33,6 +33,8 @@ #include "Framebuffer.h" #include "DeviceObjectBase.hpp" #include "RenderDeviceBase.hpp" +#include "TextureView.h" +#include "GraphicsAccessories.hpp" namespace Diligent { @@ -63,15 +65,57 @@ public: bool bIsDeviceInternal = false) : TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal} { + if (Desc.pRenderPass == nullptr) + { + LOG_ERROR_AND_THROW("Render pass must not be null"); + } + + if (this->m_Desc.AttachmentCount > 0) + { + m_ppAttachments = + ALLOCATE(GetRawAllocator(), "Memory for framebuffer attachment array", ITextureView*, this->m_Desc.AttachmentCount); + this->m_Desc.ppAttachments = m_ppAttachments; + for (Uint32 i = 0; i < this->m_Desc.AttachmentCount; ++i) + { + m_ppAttachments[i] = Desc.ppAttachments[i]; + m_ppAttachments[i]->AddRef(); + + if ((this->m_Desc.Width == 0 || this->m_Desc.Height == 0 || this->m_Desc.NumArraySlices == 0) && m_ppAttachments[i] != nullptr) + { + const auto& ViewDesc = m_ppAttachments[i]->GetDesc(); + const auto& TexDesc = m_ppAttachments[i]->GetTexture()->GetDesc(); + + auto MipLevelProps = GetMipLevelProperties(TexDesc, ViewDesc.MostDetailedMip); + if (this->m_Desc.Width == 0) + this->m_Desc.Width = MipLevelProps.LogicalWidth; + if (this->m_Desc.Height == 0) + this->m_Desc.Height = MipLevelProps.LogicalHeight; + if (this->m_Desc.NumArraySlices == 0) + this->m_Desc.NumArraySlices = ViewDesc.NumArraySlices; + } + } + } + Desc.pRenderPass->AddRef(); } ~FramebufferBase() { + if (this->m_Desc.AttachmentCount > 0) + { + VERIFY_EXPR(m_ppAttachments != nullptr); + for (Uint32 i = 0; i < this->m_Desc.AttachmentCount; ++i) + { + m_ppAttachments[i]->Release(); + } + GetRawAllocator().Free(m_ppAttachments); + } + this->m_Desc.pRenderPass->Release(); } IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_Framebuffer, TDeviceObjectBase) private: + ITextureView** m_ppAttachments = nullptr; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngine/interface/Framebuffer.h b/Graphics/GraphicsEngine/interface/Framebuffer.h index c8bed172..9b00ea70 100644 --- a/Graphics/GraphicsEngine/interface/Framebuffer.h +++ b/Graphics/GraphicsEngine/interface/Framebuffer.h @@ -46,22 +46,22 @@ static const struct INTERFACE_ID IID_Framebuffer = struct FramebufferDesc DILIGENT_DERIVE(DeviceObjectAttribs) /// Render pass that the framebuffer will be compatible with. - IRenderPass* pRenderPass DEFAULT_INITIALIZER(nullptr); + IRenderPass* pRenderPass DEFAULT_INITIALIZER(nullptr); /// The number of attachments. - Uint32 AttachmentCount DEFAULT_INITIALIZER(0); + Uint32 AttachmentCount DEFAULT_INITIALIZER(0); /// Pointer to the array of attachments. - const ITextureView* pAttachments DEFAULT_INITIALIZER(nullptr); + ITextureView* const* ppAttachments DEFAULT_INITIALIZER(nullptr); /// Width of the framebuffer. - Uint32 Width DEFAULT_INITIALIZER(0); + Uint32 Width DEFAULT_INITIALIZER(0); /// Height of the framebuffer. - Uint32 Height DEFAULT_INITIALIZER(0); + Uint32 Height DEFAULT_INITIALIZER(0); - /// The number of layers in the framebuffer. - Uint32 Layers DEFAULT_INITIALIZER(0); + /// The number of array slices in the framebuffer. + Uint32 NumArraySlices DEFAULT_INITIALIZER(0); }; typedef struct FramebufferDesc FramebufferDesc; diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 0d0631b7..a6612158 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -84,7 +84,8 @@ DILIGENT_TYPED_ENUM(BIND_FLAGS, Uint32) BIND_RENDER_TARGET = 0x20L,///< A texture can be bound as a render target BIND_DEPTH_STENCIL = 0x40L,///< A texture can be bound as a depth-stencil target BIND_UNORDERED_ACCESS = 0x80L,///< A buffer or a texture can be bound as an unordered access view - BIND_INDIRECT_DRAW_ARGS = 0x100L///< A buffer can be bound as the source buffer for indirect draw commands + BIND_INDIRECT_DRAW_ARGS = 0x100L,///< A buffer can be bound as the source buffer for indirect draw commands + BIND_INPUT_ATTACHMENT = 0x200L ///< A texture can be used as render pass input attachment }; DEFINE_FLAG_ENUM_OPERATORS(BIND_FLAGS) @@ -1372,8 +1373,8 @@ typedef struct EngineCreateInfo EngineCreateInfo; /// Attributes of the OpenGL-based engine implementation struct EngineGLCreateInfo DILIGENT_DERIVE(EngineCreateInfo) - /// Native window wrapper - NativeWindow Window; + /// Native window wrapper + NativeWindow Window; /// Create debug OpenGL context and enable debug output. -- cgit v1.2.3 From 7a8f70f4bc019afd1180590d1b85621463aa3e26 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 25 Jul 2020 12:05:15 -0700 Subject: Added frambuffer desc validation --- Graphics/GraphicsEngine/CMakeLists.txt | 1 + .../GraphicsEngine/include/FramebufferBase.hpp | 7 +- Graphics/GraphicsEngine/src/FramebufferBase.cpp | 214 +++++++++++++++++++++ 3 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 Graphics/GraphicsEngine/src/FramebufferBase.cpp (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt index daafe96e..c6ec31ae 100644 --- a/Graphics/GraphicsEngine/CMakeLists.txt +++ b/Graphics/GraphicsEngine/CMakeLists.txt @@ -65,6 +65,7 @@ set(SOURCE src/APIInfo.cpp src/DefaultShaderSourceStreamFactory.cpp src/EngineMemory.cpp + src/FramebufferBase.cpp src/ResourceMappingBase.cpp src/RenderPassBase.cpp src/TextureBase.cpp diff --git a/Graphics/GraphicsEngine/include/FramebufferBase.hpp b/Graphics/GraphicsEngine/include/FramebufferBase.hpp index 6bf77918..42e31c8f 100644 --- a/Graphics/GraphicsEngine/include/FramebufferBase.hpp +++ b/Graphics/GraphicsEngine/include/FramebufferBase.hpp @@ -65,10 +65,7 @@ public: bool bIsDeviceInternal = false) : TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal} { - if (Desc.pRenderPass == nullptr) - { - LOG_ERROR_AND_THROW("Render pass must not be null"); - } + ValidateFramebufferDesc(Desc); if (this->m_Desc.AttachmentCount > 0) { @@ -80,7 +77,7 @@ public: m_ppAttachments[i] = Desc.ppAttachments[i]; m_ppAttachments[i]->AddRef(); - if ((this->m_Desc.Width == 0 || this->m_Desc.Height == 0 || this->m_Desc.NumArraySlices == 0) && m_ppAttachments[i] != nullptr) + if (this->m_Desc.Width == 0 || this->m_Desc.Height == 0 || this->m_Desc.NumArraySlices == 0) { const auto& ViewDesc = m_ppAttachments[i]->GetDesc(); const auto& TexDesc = m_ppAttachments[i]->GetTexture()->GetDesc(); diff --git a/Graphics/GraphicsEngine/src/FramebufferBase.cpp b/Graphics/GraphicsEngine/src/FramebufferBase.cpp new file mode 100644 index 00000000..d3d06702 --- /dev/null +++ b/Graphics/GraphicsEngine/src/FramebufferBase.cpp @@ -0,0 +1,214 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "FramebufferBase.hpp" +#include "GraphicsAccessories.hpp" + +namespace Diligent +{ + +void ValidateFramebufferDesc(const FramebufferDesc& Desc) +{ +#define LOG_FRAMEBUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Framebuffer '", (Desc.Name ? Desc.Name : ""), "': ", ##__VA_ARGS__) + + if (Desc.pRenderPass == nullptr) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("Render pass must not be null"); + } + + for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) + { + if (Desc.ppAttachments[i] == nullptr) + { + // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, and attachmentCount is not 0, + // pAttachments must be a valid pointer to an array of attachmentCount valid VkImageView handles. + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-flags-02778 + LOG_FRAMEBUFFER_ERROR_AND_THROW("Framebuffer attachment ", i, " is null"); + } + } + + const auto& RPDesc = Desc.pRenderPass->GetDesc(); + if (Desc.AttachmentCount < RPDesc.AttachmentCount) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The number of framebuffer attachments (", Desc.AttachmentCount, + ") is smaller than the number of attachments (", RPDesc.AttachmentCount, + ") in the render pass '", RPDesc.Name, "'."); + } + + for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i) + { + const auto& AttDesc = RPDesc.pAttachments[i]; + const auto& TexDesc = Desc.ppAttachments[i]->GetTexture()->GetDesc(); + + // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments + // must have been created with a VkFormat value that matches the VkFormat specified by the corresponding + // VkAttachmentDescription in renderPass + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00880 + if (TexDesc.Format != AttDesc.Format) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The format (", GetTextureFormatAttribs(TexDesc.Format).Name, ") of attachment ", i, + " does not match the format (", GetTextureFormatAttribs(AttDesc.Format).Name, + ") defined by the render pass for the same attachment."); + } + + // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments must have + // been created with a samples value that matches the samples value specified by the corresponding + // VkAttachmentDescription in renderPass + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00881 + if (TexDesc.SampleCount != AttDesc.SampleCount) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The sample count (", Uint32{TexDesc.SampleCount}, ") of attachment ", i, + " does not match the sample count (", Uint32{AttDesc.SampleCount}, + ") defined by the render pass for the same attachment."); + } + } + + for (Uint32 i = 0; i < RPDesc.SubpassCount; ++i) + { + const auto& Subpass = RPDesc.pSubpasses[i]; + for (Uint32 input_attachment = 0; input_attachment < Subpass.InputAttachmentCount; ++input_attachment) + { + const auto& AttchRef = Subpass.pInputAttachments[input_attachment]; + if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) + continue; + + if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of input attachment reference ", input_attachment, + " of subpass ", i, " of render pass '", RPDesc.Name, + "' exceeds the number of attachments in the framebuffer (", Desc.AttachmentCount, ")"); + } + + const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); + + // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments that + // is used as an input attachment by renderPass must have been created with a usage value including + // VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00879 + if ((TexDesc.BindFlags & BIND_INPUT_ATTACHMENT) == 0) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, + " is used as input attachment by subpass ", + i, " of render pass '", RPDesc.Name, + "', but was not created with BIND_INPUT_ATTACHMENT bind flag"); + } + } + + for (Uint32 rt_attachment = 0; rt_attachment < Subpass.RenderTargetAttachmentCount; ++rt_attachment) + { + const auto& AttchRef = Subpass.pRenderTargetAttachments[rt_attachment]; + if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) + continue; + + if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of render target attachment reference ", rt_attachment, + " of subpass ", i, " of render pass '", RPDesc.Name, + "' exceeds the number of attachments in the framebuffer (", Desc.AttachmentCount, ")"); + } + + const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); + + // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments that is used + // as a color attachment or resolve attachment by renderPass must have been created with a usage value including + // VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00877 + if ((TexDesc.BindFlags & BIND_RENDER_TARGET) == 0) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, + " is used as render target attachment by subpass ", + i, " of render pass '", RPDesc.Name, + "', but was not created with BIND_RENDER_TARGET bind flag"); + } + } + + if (Subpass.pResolveAttachments != nullptr) + { + for (Uint32 rslv_attachment = 0; rslv_attachment < Subpass.RenderTargetAttachmentCount; ++rslv_attachment) + { + const auto& AttchRef = Subpass.pResolveAttachments[rslv_attachment]; + if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) + continue; + + if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of resolve attachment reference ", rslv_attachment, + " of subpass ", i, " of render pass '", RPDesc.Name, + "' exceeds the number of attachments in the framebuffer (", Desc.AttachmentCount, ")"); + } + + const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); + + // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments that is used + // as a color attachment or resolve attachment by renderPass must have been created with a usage value including + // VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00877 + if ((TexDesc.BindFlags & BIND_RENDER_TARGET) == 0) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, + " is used as resolve attachment by subpass ", + i, " of render pass '", RPDesc.Name, + "', but was not created with BIND_RENDER_TARGET bind flag"); + } + } + } + + if (Subpass.pDepthStencilAttachment != nullptr) + { + const auto& AttchRef = *Subpass.pDepthStencilAttachment; + if (AttchRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of depth-stencil attachment reference of subpass ", i, + " of render pass '", RPDesc.Name, + "' exceeds the number of attachments in the framebuffer (", Desc.AttachmentCount, ")"); + } + + const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); + + // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments that is + // used as a depth/stencil attachment by renderPass must have been created with a usage value including + // VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-02633 + if ((TexDesc.BindFlags & BIND_DEPTH_STENCIL) == 0) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, + " is used as detph-stencil attachment by subpass ", + i, " of render pass '", RPDesc.Name, + "', but was not created with BIND_DEPTH_STENCIL bind flag"); + } + } + } + + //for (Uint32 prsv_attachment = 0; prsv_attachment < Subpass.PreserveAttachmentCount; ++prsv_attachment) + // ; + } +} + +} // namespace Diligent -- cgit v1.2.3 From 2a37e90153caf4aaa1c9d4aa9f082678feb29756 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 26 Jul 2020 11:59:04 -0700 Subject: Added PIPELINE_STAGE_FLAGS and ACCESS_FLAGS --- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 269 ++++++++++++++++++---- 1 file changed, 229 insertions(+), 40 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index a6612158..a0493c54 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -65,7 +65,7 @@ DILIGENT_TYPED_ENUM(VALUE_TYPE, Uint8) /// Resource binding flags -/// [D3D11_BIND_FLAG]: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476085(v=vs.85).aspx +/// [D3D11_BIND_FLAG]: https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_bind_flag /// /// This enumeration describes which parts of the pipeline a resource can be bound to. /// It generally mirrors [D3D11_BIND_FLAG][] enumeration. It is used by @@ -91,7 +91,7 @@ DEFINE_FLAG_ENUM_OPERATORS(BIND_FLAGS) /// Resource usage -/// [D3D11_USAGE]: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476259(v=vs.85).aspx +/// [D3D11_USAGE]: https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_usage /// This enumeration describes expected resource usage. It generally mirrors [D3D11_USAGE] enumeration. /// The enumeration is used by /// - BufferDesc to describe usage for a buffer @@ -134,7 +134,7 @@ DEFINE_FLAG_ENUM_OPERATORS(CPU_ACCESS_FLAGS) /// Resource mapping type -/// [D3D11_MAP]: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476181(v=vs.85).aspx +/// [D3D11_MAP]: https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_map /// Describes how a mapped resource will be accessed. This enumeration generally /// mirrors [D3D11_MAP][] enumeration. It is used by /// - IBuffer::Map to describe buffer mapping type @@ -258,7 +258,7 @@ DILIGENT_TYPED_ENUM(BUFFER_VIEW_TYPE, Uint8) /// This enumeration describes available texture formats and generally mirrors DXGI_FORMAT enumeration. /// The table below provides detailed information on each format. Most of the formats are widely supported /// by all modern APIs (DX10+, OpenGL3.3+ and OpenGLES3.0+). Specific requirements are additionally indicated. -/// \sa DXGI_FORMAT enumeration on MSDN, +/// \sa DXGI_FORMAT enumeration on MSDN, /// OpenGL Texture Formats /// DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) @@ -569,7 +569,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC1_TYPELESS. OpenGL does not have direct counterpart, GL_COMPRESSED_RGB_S3TC_DXT1_EXT is used. \n /// [GL_EXT_texture_compression_s3tc]: https://www.khronos.org/registry/gles/extensions/EXT/texture_compression_s3tc.txt /// OpenGL & OpenGLES: [GL_EXT_texture_compression_s3tc][] extension is required - /// \sa BC1 on MSDN , + /// \sa BC1 on MSDN , /// DXT1 on OpenGL.org TEX_FORMAT_BC1_TYPELESS, @@ -578,7 +578,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC1_UNORM. OpenGL counterpart: GL_COMPRESSED_RGB_S3TC_DXT1_EXT.\n /// [GL_EXT_texture_compression_s3tc]: https://www.khronos.org/registry/gles/extensions/EXT/texture_compression_s3tc.txt /// OpenGL & OpenGLES: [GL_EXT_texture_compression_s3tc][] extension is required - /// \sa BC1 on MSDN , + /// \sa BC1 on MSDN , /// DXT1 on OpenGL.org TEX_FORMAT_BC1_UNORM, @@ -587,7 +587,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC1_UNORM_SRGB. OpenGL counterpart: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT.\n /// [GL_EXT_texture_compression_s3tc]: https://www.khronos.org/registry/gles/extensions/EXT/texture_compression_s3tc.txt /// OpenGL & OpenGLES: [GL_EXT_texture_compression_s3tc][] extension is required - /// \sa BC1 on MSDN , + /// \sa BC1 on MSDN , /// DXT1 on OpenGL.org TEX_FORMAT_BC1_UNORM_SRGB, @@ -595,7 +595,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC2_TYPELESS. OpenGL does not have direct counterpart, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT is used. \n /// [GL_EXT_texture_compression_s3tc]: https://www.khronos.org/registry/gles/extensions/EXT/texture_compression_s3tc.txt /// OpenGL & OpenGLES: [GL_EXT_texture_compression_s3tc][] extension is required - /// \sa BC2 on MSDN , + /// \sa BC2 on MSDN , /// DXT3 on OpenGL.org TEX_FORMAT_BC2_TYPELESS, @@ -604,7 +604,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC2_UNORM. OpenGL counterpart: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT. \n /// [GL_EXT_texture_compression_s3tc]: https://www.khronos.org/registry/gles/extensions/EXT/texture_compression_s3tc.txt /// OpenGL & OpenGLES: [GL_EXT_texture_compression_s3tc][] extension is required - /// \sa BC2 on MSDN , + /// \sa BC2 on MSDN , /// DXT3 on OpenGL.org TEX_FORMAT_BC2_UNORM, @@ -613,7 +613,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC2_UNORM_SRGB. OpenGL counterpart: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT. \n /// [GL_EXT_texture_compression_s3tc]: https://www.khronos.org/registry/gles/extensions/EXT/texture_compression_s3tc.txt /// OpenGL & OpenGLES: [GL_EXT_texture_compression_s3tc][] extension is required - /// \sa BC2 on MSDN , + /// \sa BC2 on MSDN , /// DXT3 on OpenGL.org TEX_FORMAT_BC2_UNORM_SRGB, @@ -621,7 +621,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC3_TYPELESS. OpenGL does not have direct counterpart, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT is used. \n /// [GL_EXT_texture_compression_s3tc]: https://www.khronos.org/registry/gles/extensions/EXT/texture_compression_s3tc.txt /// OpenGL & OpenGLES: [GL_EXT_texture_compression_s3tc][] extension is required - /// \sa BC3 on MSDN , + /// \sa BC3 on MSDN , /// DXT5 on OpenGL.org TEX_FORMAT_BC3_TYPELESS, @@ -630,7 +630,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC3_UNORM. OpenGL counterpart: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT. \n /// [GL_EXT_texture_compression_s3tc]: https://www.khronos.org/registry/gles/extensions/EXT/texture_compression_s3tc.txt /// OpenGL & OpenGLES: [GL_EXT_texture_compression_s3tc][] extension is required - /// \sa BC3 on MSDN , + /// \sa BC3 on MSDN , /// DXT5 on OpenGL.org TEX_FORMAT_BC3_UNORM, @@ -639,7 +639,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC3_UNORM_SRGB. OpenGL counterpart: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT. \n /// [GL_EXT_texture_compression_s3tc]: https://www.khronos.org/registry/gles/extensions/EXT/texture_compression_s3tc.txt /// OpenGL & OpenGLES: [GL_EXT_texture_compression_s3tc][] extension is required - /// \sa BC3 on MSDN , + /// \sa BC3 on MSDN , /// DXT5 on OpenGL.org TEX_FORMAT_BC3_UNORM_SRGB, @@ -647,7 +647,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC4_TYPELESS. OpenGL does not have direct counterpart, GL_COMPRESSED_RED_RGTC1 is used. \n /// [GL_ARB_texture_compression_rgtc]: https://www.opengl.org/registry/specs/ARB/texture_compression_rgtc.txt /// OpenGL & OpenGLES: [GL_ARB_texture_compression_rgtc][] extension is required - /// \sa BC4 on MSDN , + /// \sa BC4 on MSDN , /// Compressed formats on OpenGL.org TEX_FORMAT_BC4_TYPELESS, @@ -656,7 +656,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC4_UNORM. OpenGL counterpart: GL_COMPRESSED_RED_RGTC1. \n /// [GL_ARB_texture_compression_rgtc]: https://www.opengl.org/registry/specs/ARB/texture_compression_rgtc.txt /// OpenGL & OpenGLES: [GL_ARB_texture_compression_rgtc][] extension is required - /// \sa BC4 on MSDN , + /// \sa BC4 on MSDN , /// Compressed formats on OpenGL.org TEX_FORMAT_BC4_UNORM, @@ -665,7 +665,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC4_SNORM. OpenGL counterpart: GL_COMPRESSED_SIGNED_RED_RGTC1. \n /// [GL_ARB_texture_compression_rgtc]: https://www.opengl.org/registry/specs/ARB/texture_compression_rgtc.txt /// OpenGL & OpenGLES: [GL_ARB_texture_compression_rgtc][] extension is required - /// \sa BC4 on MSDN , + /// \sa BC4 on MSDN , /// Compressed formats on OpenGL.org TEX_FORMAT_BC4_SNORM, @@ -673,7 +673,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC5_TYPELESS. OpenGL does not have direct counterpart, GL_COMPRESSED_RG_RGTC2 is used. \n /// [GL_ARB_texture_compression_rgtc]: https://www.opengl.org/registry/specs/ARB/texture_compression_rgtc.txt /// OpenGL & OpenGLES: [GL_ARB_texture_compression_rgtc][] extension is required - /// \sa BC5 on MSDN , + /// \sa BC5 on MSDN , /// Compressed formats on OpenGL.org TEX_FORMAT_BC5_TYPELESS, @@ -682,7 +682,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC5_UNORM. OpenGL counterpart: GL_COMPRESSED_RG_RGTC2. \n /// [GL_ARB_texture_compression_rgtc]: https://www.opengl.org/registry/specs/ARB/texture_compression_rgtc.txt /// OpenGL & OpenGLES: [GL_ARB_texture_compression_rgtc][] extension is required - /// \sa BC5 on MSDN , + /// \sa BC5 on MSDN , /// Compressed formats on OpenGL.org TEX_FORMAT_BC5_UNORM, @@ -691,7 +691,7 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// D3D counterpart: DXGI_FORMAT_BC5_SNORM. OpenGL counterpart: GL_COMPRESSED_SIGNED_RG_RGTC2. \n /// [GL_ARB_texture_compression_rgtc]: https://www.opengl.org/registry/specs/ARB/texture_compression_rgtc.txt /// OpenGL & OpenGLES: [GL_ARB_texture_compression_rgtc][] extension is required - /// \sa BC5 on MSDN , + /// \sa BC5 on MSDN , /// Compressed formats on OpenGL.org TEX_FORMAT_BC5_SNORM, @@ -742,49 +742,49 @@ DILIGENT_TYPED_ENUM(TEXTURE_FORMAT, Uint16) /// Three-component typeless block-compression format. \n /// D3D counterpart: DXGI_FORMAT_BC6H_TYPELESS. OpenGL does not have direct counterpart, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT is used. \n - /// [GL_ARB_texture_compression_bptc]: https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/specs/ARB/texture_compression_bptc.txt + /// [GL_ARB_texture_compression_bptc]: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt /// OpenGL: [GL_ARB_texture_compression_bptc][] extension is required. Not supported in at least OpenGLES3.1 - /// \sa BC6H on MSDN , + /// \sa BC6H on MSDN , /// BPTC Texture Compression on OpenGL.org TEX_FORMAT_BC6H_TYPELESS, /// Three-component unsigned half-precision floating-point format with 16 bits for each channel. \n /// D3D counterpart: DXGI_FORMAT_BC6H_UF16. OpenGL counterpart: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT. \n - /// [GL_ARB_texture_compression_bptc]: https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/specs/ARB/texture_compression_bptc.txt + /// [GL_ARB_texture_compression_bptc]: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt /// OpenGL: [GL_ARB_texture_compression_bptc][] extension is required. Not supported in at least OpenGLES3.1 - /// \sa BC6H on MSDN , + /// \sa BC6H on MSDN , /// BPTC Texture Compression on OpenGL.org TEX_FORMAT_BC6H_UF16, /// Three-channel signed half-precision floating-point format with 16 bits per each channel. \n /// D3D counterpart: DXGI_FORMAT_BC6H_SF16. OpenGL counterpart: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT. \n - /// [GL_ARB_texture_compression_bptc]: https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/specs/ARB/texture_compression_bptc.txt + /// [GL_ARB_texture_compression_bptc]: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt /// OpenGL: [GL_ARB_texture_compression_bptc][] extension is required. Not supported in at least OpenGLES3.1 - /// \sa BC6H on MSDN , + /// \sa BC6H on MSDN , /// BPTC Texture Compression on OpenGL.org TEX_FORMAT_BC6H_SF16, /// Three-component typeless block-compression format. \n /// D3D counterpart: DXGI_FORMAT_BC7_TYPELESS. OpenGL does not have direct counterpart, GL_COMPRESSED_RGBA_BPTC_UNORM is used. \n - /// [GL_ARB_texture_compression_bptc]: https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/specs/ARB/texture_compression_bptc.txt + /// [GL_ARB_texture_compression_bptc]: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt /// OpenGL: [GL_ARB_texture_compression_bptc][] extension is required. Not supported in at least OpenGLES3.1 - /// \sa BC7 on MSDN , + /// \sa BC7 on MSDN , /// BPTC Texture Compression on OpenGL.org TEX_FORMAT_BC7_TYPELESS, /// Three-component block-compression unsigned-normalized-integer format with 4 to 7 bits per color channel and 0 to 8 bits of alpha. \n /// D3D counterpart: DXGI_FORMAT_BC7_UNORM. OpenGL counterpart: GL_COMPRESSED_RGBA_BPTC_UNORM. \n - /// [GL_ARB_texture_compression_bptc]: https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/specs/ARB/texture_compression_bptc.txt + /// [GL_ARB_texture_compression_bptc]: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt /// OpenGL: [GL_ARB_texture_compression_bptc][] extension is required. Not supported in at least OpenGLES3.1 - /// \sa BC7 on MSDN , + /// \sa BC7 on MSDN , /// BPTC Texture Compression on OpenGL.org TEX_FORMAT_BC7_UNORM, /// Three-component block-compression unsigned-normalized-integer sRGB format with 4 to 7 bits per color channel and 0 to 8 bits of alpha. \n /// D3D counterpart: DXGI_FORMAT_BC7_UNORM_SRGB. OpenGL counterpart: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM. \n - /// [GL_ARB_texture_compression_bptc]: https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/specs/ARB/texture_compression_bptc.txt + /// [GL_ARB_texture_compression_bptc]: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt /// OpenGL: [GL_ARB_texture_compression_bptc][] extension is required. Not supported in at least OpenGLES3.1 - /// \sa BC7 on MSDN , + /// \sa BC7 on MSDN , /// BPTC Texture Compression on OpenGL.org TEX_FORMAT_BC7_UNORM_SRGB, @@ -817,8 +817,8 @@ DILIGENT_TYPED_ENUM(FILTER_TYPE, Uint8) /// Texture address mode -/// [D3D11_TEXTURE_ADDRESS_MODE]: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476256(v=vs.85).aspx -/// [D3D12_TEXTURE_ADDRESS_MODE]: https://msdn.microsoft.com/en-us/library/windows/desktop/dn770441(v=vs.85).aspx +/// [D3D11_TEXTURE_ADDRESS_MODE]: https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_texture_address_mode +/// [D3D12_TEXTURE_ADDRESS_MODE]: https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_texture_address_mode /// Defines a technique for resolving texture coordinates that are outside of /// the boundaries of a texture. The enumeration generally mirrors [D3D11_TEXTURE_ADDRESS_MODE][]/[D3D12_TEXTURE_ADDRESS_MODE][] enumeration. /// It is used by SamplerDesc structure to define the address mode for U,V and W texture coordinates. @@ -858,8 +858,8 @@ DILIGENT_TYPED_ENUM(TEXTURE_ADDRESS_MODE, Uint8) /// Comparison function -/// [D3D11_COMPARISON_FUNC]: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476101(v=vs.85).aspx -/// [D3D12_COMPARISON_FUNC]: https://msdn.microsoft.com/en-us/library/windows/desktop/dn770349(v=vs.85).aspx +/// [D3D11_COMPARISON_FUNC]: https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_comparison_func +/// [D3D12_COMPARISON_FUNC]: https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_comparison_func /// This enumeartion defines a comparison function. It generally mirrors [D3D11_COMPARISON_FUNC]/[D3D12_COMPARISON_FUNC] enum and is used by /// - SamplerDesc to define a comparison function if one of the comparison mode filters is used /// - StencilOpDesc to define a stencil function @@ -1142,7 +1142,7 @@ typedef struct AdapterAttribs AdapterAttribs; /// Flags indicating how an image is stretched to fit a given monitor's resolution. -/// \sa DXGI_MODE_SCALING enumeration on MSDN, +/// \sa DXGI_MODE_SCALING enumeration on MSDN, enum SCALING_MODE { /// Unspecified scaling. @@ -1161,7 +1161,7 @@ enum SCALING_MODE /// Flags indicating the method the raster uses to create an image on a surface. -/// \sa DXGI_MODE_SCANLINE_ORDER enumeration on MSDN, +/// \sa DXGI_MODE_SCANLINE_ORDER enumeration on MSDN, enum SCANLINE_ORDER { /// Scanline order is unspecified @@ -1328,7 +1328,7 @@ struct SwapChainDesc typedef struct SwapChainDesc SwapChainDesc; /// Full screen mode description -/// \sa DXGI_SWAP_CHAIN_FULLSCREEN_DESC structure on MSDN, +/// \sa DXGI_SWAP_CHAIN_FULLSCREEN_DESC structure on MSDN, struct FullScreenModeDesc { /// A Boolean value that specifies whether the swap chain is in fullscreen mode. @@ -1373,8 +1373,8 @@ typedef struct EngineCreateInfo EngineCreateInfo; /// Attributes of the OpenGL-based engine implementation struct EngineGLCreateInfo DILIGENT_DERIVE(EngineCreateInfo) - /// Native window wrapper - NativeWindow Window; + /// Native window wrapper + NativeWindow Window; /// Create debug OpenGL context and enable debug output. @@ -1907,6 +1907,195 @@ struct TextureFormatInfoExt DILIGENT_DERIVE(TextureFormatInfo) typedef struct TextureFormatInfoExt TextureFormatInfoExt; +/// Pipeline stage flags. + +/// These flags mirror [VkPipelineStageFlagBits](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VkPipelineStageFlagBits) +/// enum and only have effect in Vulkan backend. +DILIGENT_TYPED_ENUM(PIPELINE_STAGE_FLAGS, Uint32) +{ + /// The top of the pipeline. + PIPELINE_STAGE_FLAG_TOP_OF_PIPE = 0x00000001, + + /// The stage of the pipeline where Draw/DispatchIndirect data structures are consumed. + PIPELINE_STAGE_FLAG_DRAW_INDIRECT = 0x00000002, + + /// The stage of the pipeline where vertex and index buffers are consumed. + PIPELINE_STAGE_FLAG_VERTEX_INPUT = 0x00000004, + + /// Vertex shader stage. + PIPELINE_STAGE_FLAG_VERTEX_SHADER = 0x00000008, + + /// Hull shader stage. + PIPELINE_STAGE_FLAG_HULL_SHADER = 0x00000010, + + /// Domain shader stage. + PIPELINE_STAGE_FLAG_DOMAIN_SHADER = 0x00000020, + + /// Geometry shader stage. + PIPELINE_STAGE_FLAG_GEOMETRY_SHADER = 0x00000040, + + /// Fragment shader stage. + PIPELINE_STAGE_FLAG_FRAGMENT_SHADER = 0x00000080, + + /// The stage of the pipeline where early fragment tests (depth and + /// stencil tests before fragment shading) are performed. This stage + /// also includes subpass load operations for framebuffer attachments + /// with a depth/stencil format. + PIPELINE_STAGE_FLAG_EARLY_FRAGMENT_TESTS = 0x00000100, + + /// The stage of the pipeline where late fragment tests (depth and + /// stencil tests after fragment shading) are performed. This stage + /// also includes subpass store operations for framebuffer attachments + /// with a depth/stencil format. + PIPELINE_STAGE_FLAG_LATE_FRAGMENT_TESTS = 0x00000200, + + /// The stage of the pipeline after blending where the final color values + /// are output from the pipeline. This stage also includes subpass load + /// and store operations and multisample resolve operations for framebuffer + /// attachments with a color or depth/stencil format. + PIPELINE_STAGE_FLAG_RENDER_TARGET = 0x00000400, + + /// Compute shader stage. + PIPELINE_STAGE_FLAG_COMPUTE_SHADER = 0x00000800, + + /// The stage where all copy and outside-of-renderpass + /// resolve and clear operations happen. + PIPELINE_STAGE_FLAG_TRANSFER = 0x00001000, + + /// The bottom of the pipeline. + PIPELINE_STAGE_FLAG_BOTTOM_OF_PIPE = 0x00002000, + + /// A pseudo-stage indicating execution on the host of reads/writes + /// of device memory. This stage is not invoked by any commands recorded + /// in a command buffer. + PIPELINE_STAGE_FLAG_HOST = 0x00004000, + + /// The stage of the pipeline where the predicate of conditional rendering is consumed. + PIPELINE_STAGE_FLAG_CONDITIONAL_RENDERING = 0x00040000, + + /// The stage of the pipeline where the shading rate texture is + /// read to determine the shading rate for portions of a rasterized primitive. + PIPELINE_STAGE_FLAG_SHADING_RATE_TEXTURE = 0x00400000, + + /// Ray tracing shader. + PIPELINE_STAGE_FLAG_RAY_TRACING_SHADER = 0x00200000, + + /// Acceleration structure build shader. + PIPELINE_STAGE_FLAG_ACCELERATION_STRUCTURE_BUILD = 0x02000000, + + /// Task shader stage. + PIPELINE_STAGE_FLAG_TASK_SHADER = 0x00080000, + + /// Mesh shader stage. + PIPELINE_STAGE_FLAG_MESH_SHADER = 0x00100000, + + /// + PIPELINE_STAGE_FLAG_FRAGMENT_DENSITY_PROCESS = 0x00800000, + + /// Default pipeline stage that is determined by the resource state. + /// For example, RESOURCE_STATE_RENDER_TARGET corresponds to + /// PIPELINE_STAGE_FLAG_RENDER_TARGET pipeline stage. + PIPELINE_STAGE_FLAG_DEFAULT = 0x80000000 +}; +DEFINE_FLAG_ENUM_OPERATORS(PIPELINE_STAGE_FLAGS) + + +/// Access flag. + +/// The flags mirror [VkAccessFlags](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VkAccessFlags) enum +/// and only have effect in Vulkan backend. +DILIGENT_TYPED_ENUM(ACCESS_FLAGS, Uint32) +{ + /// No access + ACCESS_FLAG_NONE = 0x00000000, + + /// Read access to indirect command data read as part of an indirect + /// drawing or dispatch command. + ACCESS_FLAG_INDIRECT_COMMAND_READ = 0x00000001, + + /// Read access to an index buffer as part of an indexed drawing command + ACCESS_FLAG_INDEX_READ = 0x00000002, + + /// Read access to a vertex buffer as part of a drawing command + ACCESS_FLAG_VERTEX_READ = 0x00000004, + + /// Read access to a uniform buffer + ACCESS_FLAG_UNIFORM_READ = 0x00000008, + + /// Read access to an input attachment within a render pass during fragment shading + ACCESS_FLAG_INPUT_ATTACHMENT_READ = 0x00000010, + + /// Read access from a shader resource, formatted buffer, UAV + ACCESS_FLAG_SHADER_READ = 0x00000020, + + /// Write access to a UAV + ACCESS_FLAG_SHADER_WRITE = 0x00000040, + + /// Read access to a color render target, such as via blending, + /// logic operations, or via certain subpass load operations. + ACCESS_FLAG_RENDER_TARGET_READ = 0x00000080, + + /// Write access to a color render target, resolve, or depth/stencil resolve + /// attachment during a render pass or via certain subpass load and store operations. + ACCESS_FLAG_RENDER_TARGET_WRITE = 0x00000100, + + /// Read access to a depth/stencil buffer, via depth or stencil operations + /// or via certain subpass load operations + ACCESS_FLAG_DEPTH_STENCIL_READ = 0x00000200, + + /// Write access to a depth/stencil buffer, via depth or stencil operations + /// or via certain subpass load and store operations + ACCESS_FLAG_DEPTH_STENCIL_WRITE = 0x00000400, + + /// Read access to an texture or buffer in a copy operation. + ACCESS_FLAG_COPY_SRC = 0x00000800, + + /// Write access to an texture or buffer in a copy operation. + ACCESS_FLAG_COPY_DST = 0x00001000, + + /// Read access by a host operation. Accesses of this type are + /// not performed through a resource, but directly on memory. + ACCESS_FLAG_HOST_READ = 0x00002000, + + /// Write access by a host operation. Accesses of this type are + /// not performed through a resource, but directly on memory. + ACCESS_FLAG_HOST_WRITE = 0x00004000, + + /// All read accesses. It is always valid in any access mask, + /// and is treated as equivalent to setting all READ access flags + /// that are valid where it is used. + ACCESS_FLAG_MEMORY_READ = 0x00008000, + + /// All write accesses. It is always valid in any access mask, + /// and is treated as equivalent to setting all WRITE access + // flags that are valid where it is used. + ACCESS_FLAG_MEMORY_WRITE = 0x00010000, + + /// Read access to a predicate as part of conditional rendering. + ACCESS_FLAG_CONDITIONAL_RENDERING_READ = 0x00100000, + + /// Read access to a shading rate texture as part of a drawing comman. + ACCESS_FLAG_SHADING_RATE_TEXTURE_READ = 0x00800000, + + /// Read access to an acceleration structure as part of a trace or build command. + ACCESS_FLAG_ACCELERATION_STRUCTURE_READ = 0x00200000, + + /// Write access to an acceleration structure or acceleration structure + /// scratch buffer as part of a build command. + ACCESS_FLAG_ACCELERATION_STRUCTURE_WRITE = 0x00400000, + + /// Read access to a fragment density map attachment during + /// dynamic fragment density map operations. + ACCESS_FLAG_FRAGMENT_DENSITY_MAP_READ = 0x01000000, + + /// Default access type that is determined by the resource state. + /// For example, RESOURCE_STATE_RENDER_TARGET corresponds to + /// ACCESS_FLAG_RENDER_TARGET_WRITE access type. + ACCESS_FLAG_DEFAULT = 0x80000000 +}; +DEFINE_FLAG_ENUM_OPERATORS(ACCESS_FLAGS) + + /// Resource usage state DILIGENT_TYPED_ENUM(RESOURCE_STATE, Uint32) { -- cgit v1.2.3 From dfa7d46a0cf961d77be6d4a93eba1831935224f7 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 26 Jul 2020 12:56:01 -0700 Subject: Implemented SubpassDependencyDesc struct --- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 7 +++++-- Graphics/GraphicsEngine/interface/RenderPass.h | 20 +++++++++++++++++++- Graphics/GraphicsEngine/src/RenderPassBase.cpp | 23 +++++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index a0493c54..5fbb5412 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -1913,6 +1913,9 @@ typedef struct TextureFormatInfoExt TextureFormatInfoExt; /// enum and only have effect in Vulkan backend. DILIGENT_TYPED_ENUM(PIPELINE_STAGE_FLAGS, Uint32) { + /// Undefined stage + PIPELINE_STAGE_FLAG_UNDEFINED = 0x00000000, + /// The top of the pipeline. PIPELINE_STAGE_FLAG_TOP_OF_PIPE = 0x00000001, @@ -1934,8 +1937,8 @@ DILIGENT_TYPED_ENUM(PIPELINE_STAGE_FLAGS, Uint32) /// Geometry shader stage. PIPELINE_STAGE_FLAG_GEOMETRY_SHADER = 0x00000040, - /// Fragment shader stage. - PIPELINE_STAGE_FLAG_FRAGMENT_SHADER = 0x00000080, + /// Pixel shader stage. + PIPELINE_STAGE_FLAG_PIXEL_SHADER = 0x00000080, /// The stage of the pipeline where early fragment tests (depth and /// stencil tests before fragment shading) are performed. This stage diff --git a/Graphics/GraphicsEngine/interface/RenderPass.h b/Graphics/GraphicsEngine/interface/RenderPass.h index 0cc37f96..0f12c66d 100644 --- a/Graphics/GraphicsEngine/interface/RenderPass.h +++ b/Graphics/GraphicsEngine/interface/RenderPass.h @@ -273,10 +273,28 @@ struct SubpassDesc typedef struct SubpassDesc SubpassDesc; +#define SUBPASS_EXTERNAL (~0U) + /// Subpass dependency description struct SubpassDependencyDesc { - void* TBD; + /// The subpass index of the first subpass in the dependency, or SUBPASS_EXTERNAL. + Uint32 SrcSubpass DEFAULT_INITIALIZER(0); + + /// The subpass index of the second subpass in the dependency, or SUBPASS_EXTERNAL. + Uint32 DstSubpass DEFAULT_INITIALIZER(0); + + /// A bitmask of PIPELINE_STAGE_FLAGS specifying the source stage mask. + PIPELINE_STAGE_FLAGS SrcStageMask DEFAULT_INITIALIZER(PIPELINE_STAGE_FLAG_UNDEFINED); + + /// A bitmask of PIPELINE_STAGE_FLAGS specifying the destination stage mask. + PIPELINE_STAGE_FLAGS DstStageMask DEFAULT_INITIALIZER(PIPELINE_STAGE_FLAG_UNDEFINED); + + /// A bitmask of ACCESS_FLAGS specifying a source access mask. + ACCESS_FLAGS SrcAccessMask DEFAULT_INITIALIZER(ACCESS_FLAG_NONE); + + /// A bitmask of ACCESS_FLAGS specifying a destination access mask. + ACCESS_FLAGS DstAccessMask DEFAULT_INITIALIZER(ACCESS_FLAG_NONE); }; typedef struct SubpassDependencyDesc SubpassDependencyDesc; diff --git a/Graphics/GraphicsEngine/src/RenderPassBase.cpp b/Graphics/GraphicsEngine/src/RenderPassBase.cpp index 782e950f..a77ef404 100644 --- a/Graphics/GraphicsEngine/src/RenderPassBase.cpp +++ b/Graphics/GraphicsEngine/src/RenderPassBase.cpp @@ -37,6 +37,15 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) { #define LOG_RENDER_PASS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Render pass '", (Desc.Name ? Desc.Name : ""), "': ", ##__VA_ARGS__) + if (Desc.AttachmentCount != 0 && Desc.pAttachments == nullptr) + LOG_RENDER_PASS_ERROR_AND_THROW("The attachment count (", Desc.AttachmentCount, ") is not zero, but pAttachments is null"); + + if (Desc.SubpassCount != 0 && Desc.pSubpasses == nullptr) + LOG_RENDER_PASS_ERROR_AND_THROW("The subpass count (", Desc.SubpassCount, ") is not zero, but pSubpasses is null"); + + if (Desc.DependencyCount != 0 && Desc.pDependencies == nullptr) + LOG_RENDER_PASS_ERROR_AND_THROW("The dependency count (", Desc.DependencyCount, ") is not zero, but pDependencies is null"); + for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) { const auto& Attachment = Desc.pAttachments[i]; @@ -114,6 +123,20 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) " is not zero, while pPreserveAttachments is null"); } } + + for (Uint32 i = 0; i < Desc.DependencyCount; ++i) + { + const auto& Dependency = Desc.pDependencies[i]; + + if (Dependency.SrcStageMask == PIPELINE_STAGE_FLAG_UNDEFINED) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the source stage mask of subpass dependency ", i, " is undefined"); + } + if (Dependency.DstStageMask == PIPELINE_STAGE_FLAG_UNDEFINED) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the destination stage mask of subpass dependency ", i, " is undefined"); + } + } } } // namespace Diligent -- cgit v1.2.3 From 8798aa2e94602372a61c362d5c3f288cc07388c9 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 26 Jul 2020 19:16:18 -0700 Subject: Added BeginRenderPass, NextSubpass, and EndRenderPass device context methods --- Graphics/GraphicsEngine/interface/DeviceContext.h | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index 79f8bd39..f0c4acf5 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -609,6 +609,16 @@ struct CopyTextureAttribs }; typedef struct CopyTextureAttribs CopyTextureAttribs; + +/// BeginRenderPass command attributes. + +/// This structure is used by IDeviceContext::BeginRenderPass(). +struct BeginRenderPassAttribs +{ + int TBD; +}; +typedef struct BeginRenderPassAttribs BeginRenderPassAttribs; + #define DILIGENT_INTERFACE_NAME IDeviceContext #include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" @@ -864,6 +874,21 @@ DILIGENT_BEGIN_INTERFACE(IDeviceContext, IObject) RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) PURE; + /// Begins a new render pass. + + /// \param [in] Attribs - The command attributes, see Diligent::BeginRenderPassAttribs for details. + VIRTUAL void METHOD(BeginRenderPass)(THIS_ + const BeginRenderPassAttribs REF Attribs) PURE; + + + /// Transitions to the next subpass in the render pass instance. + VIRTUAL void METHOD(NextSubpass)(THIS) PURE; + + + /// Ends current render pass. + VIRTUAL void METHOD(EndRenderPass)(THIS) PURE; + + /// Executes a draw command. /// \param [in] Attribs - Draw command attributes, see Diligent::DrawAttribs for details. -- cgit v1.2.3 From c778652b7fd834aeee7ca046d1a8d1e1d0a9f5e4 Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 31 Jul 2020 19:47:37 -0700 Subject: PipelineStateVkImpl: creating implicit IRenderPass object instead of Vulkan render pass --- Graphics/GraphicsEngine/include/PipelineStateBase.hpp | 2 ++ Graphics/GraphicsEngine/interface/PipelineState.h | 1 + 2 files changed, 3 insertions(+) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index 6d70f4da..dbb974b2 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -389,6 +389,8 @@ protected: RefCntAutoPtr m_pHS; ///< Strong reference to the hull shader RefCntAutoPtr m_pCS; ///< Strong reference to the compute shader + RefCntAutoPtr m_pRenderPass; ///< Strong reference to the render pass object + IShader* m_ppShaders[5] = {}; ///< Array of pointers to the shaders used by this PSO size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index 5e99a392..4079a66a 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -43,6 +43,7 @@ #include "ShaderResourceVariable.h" #include "Shader.h" #include "Sampler.h" +#include "RenderPass.h" DILIGENT_BEGIN_NAMESPACE(Diligent) -- cgit v1.2.3 From 910f9f8c26b5d9db1dfa0437030d10951486ee3c Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 31 Jul 2020 20:51:27 -0700 Subject: Added pRenderPass and SubpassIndex members to GraphicsPipelineDesc struct --- .../GraphicsEngine/include/PipelineStateBase.hpp | 70 ++++++++++++++++++---- Graphics/GraphicsEngine/interface/APIInfo.h | 2 +- Graphics/GraphicsEngine/interface/PipelineState.h | 44 +++++++++----- 3 files changed, 87 insertions(+), 29 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index dbb974b2..109b6ce4 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -69,6 +69,8 @@ public: TDeviceObjectBase{pRefCounters, pDevice, PSODesc, bIsDeviceInternal}, m_NumShaders{0} { + ValidateDesc(); + const auto& SrcLayout = PSODesc.ResourceLayout; size_t StringPoolSize = 0; if (SrcLayout.Variables != nullptr) @@ -187,6 +189,8 @@ public: DEV_CHECK_ERR(m_NumShaders > 0, "There must be at least one shader in the Pipeline State"); + m_pRenderPass = PSODesc.GraphicsPipeline.pRenderPass; + for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt) { auto RTVFmt = GraphicsPipeline.RTVFormats[rt]; @@ -395,13 +399,52 @@ protected: size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout private: +#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ", (this->m_Desc.IsComputePipeline ? "compute" : "graphics"), " PSO '", this->m_Desc.Name, "' is invalid: ", ##__VA_ARGS__) + + void ValidateDesc() const + { + if (this->m_Desc.IsComputePipeline) + { + if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr) + { + LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null"); + } + } + else + { + const auto& GraphicsPipeline = this->m_Desc.GraphicsPipeline; + if (GraphicsPipeline.pRenderPass != nullptr) + { + if (GraphicsPipeline.NumRenderTargets != 0) + LOG_PSO_ERROR_AND_THROW("NumRenderTargets must be 0 when explicit render pass is used"); + if (GraphicsPipeline.DSVFormat != TEX_FORMAT_UNKNOWN) + LOG_PSO_ERROR_AND_THROW("DSVFormat must be TEX_FORMAT_UNKNOWN when explicit render pass is used"); + + for (Uint32 rt = 0; rt < MAX_RENDER_TARGETS; ++rt) + { + if (GraphicsPipeline.RTVFormats[rt] != TEX_FORMAT_UNKNOWN) + LOG_PSO_ERROR_AND_THROW("RTVFormats[", rt, "] must be TEX_FORMAT_UNKNOWN when explicit render pass is used"); + } + + const auto& RPDesc = GraphicsPipeline.pRenderPass->GetDesc(); + if (GraphicsPipeline.SubpassIndex >= RPDesc.SubpassCount) + LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") exceeds the number of subpasses (", Uint32{RPDesc.SubpassCount}, ") in render pass '", RPDesc.Name, "'"); + } + else + { + if (GraphicsPipeline.SubpassIndex != 0) + LOG_PSO_ERROR_AND_THROW("Subpass index (", Uint32{GraphicsPipeline.SubpassIndex}, ") must be 0 when explicit render pass is not used"); + } + } + } + void CheckRasterizerStateDesc() const { const auto& RSDesc = this->m_Desc.GraphicsPipeline.RasterizerDesc; if (RSDesc.FillMode == FILL_MODE_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: RasterizerDesc.FillMode must not be FILL_MODE_UNDEFINED"); + LOG_PSO_ERROR_AND_THROW("RasterizerDesc.FillMode must not be FILL_MODE_UNDEFINED"); if (RSDesc.CullMode == CULL_MODE_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: RasterizerDesc.CullMode must not be CULL_MODE_UNDEFINED"); + LOG_PSO_ERROR_AND_THROW("RasterizerDesc.CullMode must not be CULL_MODE_UNDEFINED"); } void CheckAndCorrectDepthStencilDesc() @@ -410,7 +453,7 @@ private: if (DSSDesc.DepthFunc == COMPARISON_FUNC_UNKNOWN) { if (DSSDesc.DepthEnable) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: DepthStencilDesc.DepthFunc must not be COMPARISON_FUNC_UNKNOWN when depth is enabled"); + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.DepthFunc must not be COMPARISON_FUNC_UNKNOWN when depth is enabled"); else DSSDesc.DepthFunc = DepthStencilStateDesc{}.DepthFunc; } @@ -420,13 +463,13 @@ private: if (DSSDesc.StencilEnable) { if (OpDesc.StencilFailOp == STENCIL_OP_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: DepthStencilDesc.", FaceName, ".StencilFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); if (OpDesc.StencilDepthFailOp == STENCIL_OP_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: DepthStencilDesc.", FaceName, ".StencilDepthFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilDepthFailOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); if (OpDesc.StencilPassOp == STENCIL_OP_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: DepthStencilDesc.", FaceName, ".StencilPassOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilPassOp must not be STENCIL_OP_UNDEFINED when stencil is enabled"); if (OpDesc.StencilFunc == COMPARISON_FUNC_UNKNOWN) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: DepthStencilDesc.", FaceName, ".StencilFunc must not be COMPARISON_FUNC_UNKNOWN when stencil is enabled"); + LOG_PSO_ERROR_AND_THROW("DepthStencilDesc.", FaceName, ".StencilFunc must not be COMPARISON_FUNC_UNKNOWN when stencil is enabled"); } else { @@ -457,18 +500,18 @@ private: if (BlendEnable) { if (RTDesc.SrcBlend == BLEND_FACTOR_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: BlendDesc.RenderTargets[", rt, "].SrcBlend must not be BLEND_FACTOR_UNDEFINED"); + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlend must not be BLEND_FACTOR_UNDEFINED"); if (RTDesc.DestBlend == BLEND_FACTOR_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: BlendDesc.RenderTargets[", rt, "].DestBlend must not be BLEND_FACTOR_UNDEFINED"); + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlend must not be BLEND_FACTOR_UNDEFINED"); if (RTDesc.BlendOp == BLEND_OPERATION_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: BlendDesc.RenderTargets[", rt, "].BlendOp must not be BLEND_OPERATION_UNDEFINED"); + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOp must not be BLEND_OPERATION_UNDEFINED"); if (RTDesc.SrcBlendAlpha == BLEND_FACTOR_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: BlendDesc.RenderTargets[", rt, "].SrcBlendAlpha must not be BLEND_FACTOR_UNDEFINED"); + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].SrcBlendAlpha must not be BLEND_FACTOR_UNDEFINED"); if (RTDesc.DestBlendAlpha == BLEND_FACTOR_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: BlendDesc.RenderTargets[", rt, "].DestBlendAlpha must not be BLEND_FACTOR_UNDEFINED"); + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].DestBlendAlpha must not be BLEND_FACTOR_UNDEFINED"); if (RTDesc.BlendOpAlpha == BLEND_OPERATION_UNDEFINED) - LOG_ERROR_AND_THROW("Description of graphics PSO '", this->m_Desc.Name, "' is invalid: BlendDesc.RenderTargets[", rt, "].BlendOpAlpha must not be BLEND_OPERATION_UNDEFINED"); + LOG_PSO_ERROR_AND_THROW("BlendDesc.RenderTargets[", rt, "].BlendOpAlpha must not be BLEND_OPERATION_UNDEFINED"); } else { @@ -491,6 +534,7 @@ private: RTDesc.LogicOp = RenderTargetBlendDesc{}.LogicOp; } } +#undef LOG_PSO_ERROR_AND_THROW }; } // namespace Diligent diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index c355b315..59d3bd30 100644 --- a/Graphics/GraphicsEngine/interface/APIInfo.h +++ b/Graphics/GraphicsEngine/interface/APIInfo.h @@ -30,7 +30,7 @@ /// \file /// Diligent API information -#define DILIGENT_API_VERSION 240064 +#define DILIGENT_API_VERSION 240065 #include "../../../Primitives/interface/BasicTypes.h" diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index 4079a66a..3de6f02d 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -151,24 +151,24 @@ typedef struct PipelineResourceLayoutDesc PipelineResourceLayoutDesc; /// This structure describes the graphics pipeline state and is part of the PipelineStateDesc structure. struct GraphicsPipelineDesc { - /// Vertex shader to be used with the pipeline + /// Vertex shader to be used with the pipeline. IShader* pVS DEFAULT_INITIALIZER(nullptr); - /// Pixel shader to be used with the pipeline + /// Pixel shader to be used with the pipeline. IShader* pPS DEFAULT_INITIALIZER(nullptr); - /// Domain shader to be used with the pipeline + /// Domain shader to be used with the pipeline. IShader* pDS DEFAULT_INITIALIZER(nullptr); - /// Hull shader to be used with the pipeline + /// Hull shader to be used with the pipeline. IShader* pHS DEFAULT_INITIALIZER(nullptr); - /// Geometry shader to be used with the pipeline + /// Geometry shader to be used with the pipeline. IShader* pGS DEFAULT_INITIALIZER(nullptr); //D3D12_STREAM_OUTPUT_DESC StreamOutput; - /// Blend state description + /// Blend state description. BlendStateDesc BlendDesc; /// 32-bit sample mask that determines which samples get updated @@ -177,34 +177,48 @@ struct GraphicsPipelineDesc /// depend on whether an application uses multisample render targets. Uint32 SampleMask DEFAULT_INITIALIZER(0xFFFFFFFF); - /// Rasterizer state description + /// Rasterizer state description. RasterizerStateDesc RasterizerDesc; - /// Depth-stencil state description + /// Depth-stencil state description. DepthStencilStateDesc DepthStencilDesc; - /// Input layout + /// Input layout. InputLayoutDesc InputLayout; //D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue; - /// Primitive topology type + /// Primitive topology type. PRIMITIVE_TOPOLOGY PrimitiveTopology DEFAULT_INITIALIZER(PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); - /// Number of viewports used by this pipeline + /// The number of viewports used by this pipeline Uint8 NumViewports DEFAULT_INITIALIZER(1); - /// Number of render targets in the RTVFormats member + /// The number of render targets in the RTVFormats array. + /// Must be 0 when pRenderPass is not null. Uint8 NumRenderTargets DEFAULT_INITIALIZER(0); - /// Render target formats + /// When pRenderPass is not null, the subpass + /// index within the render pass. + /// When pRenderPass is null, this member must be 0. + Uint8 SubpassIndex DEFAULT_INITIALIZER(0); + + /// Render target formats. + /// All formats must be TEX_FORMAT_UNKNOWN when pRenderPass is not null. TEXTURE_FORMAT RTVFormats[8] DEFAULT_INITIALIZER({}); - /// Depth-stencil format + /// Depth-stencil format. + /// Must be TEX_FORMAT_UNKNOWN when pRenderPass is not null. TEXTURE_FORMAT DSVFormat DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); - /// Multisampling parameters + /// Multisampling parameters. SampleDesc SmplDesc; + /// Pointer to the render pass object. + + /// When non-null render pass is specified, NumRenderTargets must be 0, + /// and all RTV formats as well as DSV format must be TEX_FORMAT_UNKNOWN. + IRenderPass* pRenderPass DEFAULT_INITIALIZER(nullptr); + /// Node mask. Uint32 NodeMask DEFAULT_INITIALIZER(0); -- cgit v1.2.3 From b875435c82aa5efbea55ee17719c4a57b171a811 Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 31 Jul 2020 23:31:05 -0700 Subject: Base implementation of BeginRenderPass/NextSubpass/EndRenderPass methods --- .../GraphicsEngine/include/DeviceContextBase.hpp | 98 ++++++++++++++++++++-- Graphics/GraphicsEngine/interface/DeviceContext.h | 6 +- 2 files changed, 94 insertions(+), 10 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index b4c271fa..74fc5966 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -76,6 +76,8 @@ public: using PipelineStateImplType = typename ImplementationTraits::PipelineStateType; using TextureViewImplType = typename TextureImplType::ViewImplType; using QueryImplType = typename ImplementationTraits::QueryType; + using FramebufferImplType = typename ImplementationTraits::FramebufferType; + using RenderPassImplType = typename ImplementationTraits::RenderPassType; /// \param pRefCounters - reference counters object that controls the lifetime of this device context. /// \param pRenderDevice - render device. @@ -124,6 +126,12 @@ public: /// from the cached value and false otherwise. inline bool SetRenderTargets(Uint32 NumRenderTargets, ITextureView* ppRenderTargets[], ITextureView* pDepthStencil); + virtual void DILIGENT_CALL_TYPE BeginRenderPass(const BeginRenderPassAttribs& Attribs) override = 0; + + virtual void DILIGENT_CALL_TYPE NextSubpass() override = 0; + + virtual void DILIGENT_CALL_TYPE EndRenderPass() override = 0; + /// Base implementation of IDeviceContext::UpdateBuffer(); validates input parameters. virtual void DILIGENT_CALL_TYPE UpdateBuffer(IBuffer* pBuffer, Uint32 Offset, @@ -309,6 +317,15 @@ protected: /// Use final texture view implementation type to avoid virtual calls to AddRef()/Release() RefCntAutoPtr m_pBoundDepthStencil; + /// Strong reference to the bound framebuffer. + RefCntAutoPtr m_pBoundFramebuffer; + + /// Strong reference to the render pass. + RefCntAutoPtr m_pActiveRenderPass; + + /// Current subpass index. + Uint32 m_SubpassIndex = 0; + const bool m_bIsDeferred = false; #ifdef DILIGENT_DEBUG @@ -344,6 +361,10 @@ inline void DeviceContextBase:: LOG_ERROR_MESSAGE("The range of vertex buffer slots being set [", StartSlot, ", ", StartSlot + NumBuffersSet - 1, "] is out of allowed range [0, ", MAX_BUFFER_SLOTS - 1, "]."); NumBuffersSet = MAX_BUFFER_SLOTS - StartSlot; } + + VERIFY(!(m_pActiveRenderPass != nullptr && StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION), + "Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); #endif if (Flags & SET_VERTEX_BUFFERS_FLAG_RESET) @@ -392,6 +413,10 @@ inline bool DeviceContextBase:: CommitShaderResources(IShaderResourceBinding* pShaderResourceBinding, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode, int) { #ifdef DILIGENT_DEVELOPMENT + VERIFY(!(m_pActiveRenderPass != nullptr && StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION), + "Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); + if (!m_pPipelineState) { LOG_ERROR_MESSAGE("No pipeline state is bound to the pipeline"); @@ -423,6 +448,10 @@ inline void DeviceContextBase:: m_pIndexBuffer = ValidatedCast(pIndexBuffer); m_IndexDataStartOffset = ByteOffset; #ifdef DILIGENT_DEVELOPMENT + VERIFY(!(m_pActiveRenderPass != nullptr && StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION), + "Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); + if (m_pIndexBuffer) { const auto& BuffDesc = m_pIndexBuffer->GetDesc(); @@ -549,6 +578,8 @@ inline bool DeviceContextBase:: return false; } + VERIFY(m_pActiveRenderPass == nullptr, "Setting render targets inside the render pass is not allowed. The render pass must be ended first."); + bool bBindRenderTargets = false; m_FramebufferWidth = 0; m_FramebufferHeight = 0; @@ -571,7 +602,7 @@ inline bool DeviceContextBase:: const auto& RTVDesc = pRTView->GetDesc(); #ifdef DILIGENT_DEVELOPMENT if (RTVDesc.ViewType != TEXTURE_VIEW_RENDER_TARGET) - LOG_ERROR("Texture view object named '", RTVDesc.Name ? RTVDesc.Name : "", "' has incorrect view type (", GetTexViewTypeLiteralName(RTVDesc.ViewType), "). Render target view is expected"); + LOG_ERROR_MESSAGE("Texture view object named '", RTVDesc.Name ? RTVDesc.Name : "", "' has incorrect view type (", GetTexViewTypeLiteralName(RTVDesc.ViewType), "). Render target view is expected"); #endif // Use this RTV to set the render target size if (m_FramebufferWidth == 0) @@ -587,11 +618,11 @@ inline bool DeviceContextBase:: #ifdef DILIGENT_DEVELOPMENT const auto& TexDesc = pRTView->GetTexture()->GetDesc(); if (m_FramebufferWidth != std::max(TexDesc.Width >> RTVDesc.MostDetailedMip, 1U)) - LOG_ERROR("Render target width (", std::max(TexDesc.Width >> RTVDesc.MostDetailedMip, 1U), ") specified by RTV '", RTVDesc.Name, "' is inconsistent with the width of previously bound render targets (", m_FramebufferWidth, ")"); + LOG_ERROR_MESSAGE("Render target width (", std::max(TexDesc.Width >> RTVDesc.MostDetailedMip, 1U), ") specified by RTV '", RTVDesc.Name, "' is inconsistent with the width of previously bound render targets (", m_FramebufferWidth, ")"); if (m_FramebufferHeight != std::max(TexDesc.Height >> RTVDesc.MostDetailedMip, 1U)) - LOG_ERROR("Render target height (", std::max(TexDesc.Height >> RTVDesc.MostDetailedMip, 1U), ") specified by RTV '", RTVDesc.Name, "' is inconsistent with the height of previously bound render targets (", m_FramebufferHeight, ")"); + LOG_ERROR_MESSAGE("Render target height (", std::max(TexDesc.Height >> RTVDesc.MostDetailedMip, 1U), ") specified by RTV '", RTVDesc.Name, "' is inconsistent with the height of previously bound render targets (", m_FramebufferHeight, ")"); if (m_FramebufferSlices != RTVDesc.NumArraySlices) - LOG_ERROR("Number of slices (", RTVDesc.NumArraySlices, ") specified by RTV '", RTVDesc.Name, "' is inconsistent with the number of slices in previously bound render targets (", m_FramebufferSlices, ")"); + LOG_ERROR_MESSAGE("Number of slices (", RTVDesc.NumArraySlices, ") specified by RTV '", RTVDesc.Name, "' is inconsistent with the number of slices in previously bound render targets (", m_FramebufferSlices, ")"); #endif } } @@ -611,7 +642,7 @@ inline bool DeviceContextBase:: const auto& DSVDesc = pDepthStencil->GetDesc(); #ifdef DILIGENT_DEVELOPMENT if (DSVDesc.ViewType != TEXTURE_VIEW_DEPTH_STENCIL) - LOG_ERROR("Texture view object named '", DSVDesc.Name ? DSVDesc.Name : "", "' has incorrect view type (", GetTexViewTypeLiteralName(DSVDesc.ViewType), "). Depth stencil view is expected"); + LOG_ERROR_MESSAGE("Texture view object named '", DSVDesc.Name ? DSVDesc.Name : "", "' has incorrect view type (", GetTexViewTypeLiteralName(DSVDesc.ViewType), "). Depth stencil view is expected"); #endif // Use depth stencil size to set render target size @@ -628,11 +659,11 @@ inline bool DeviceContextBase:: #ifdef DILIGENT_DEVELOPMENT const auto& TexDesc = pDepthStencil->GetTexture()->GetDesc(); if (m_FramebufferWidth != std::max(TexDesc.Width >> DSVDesc.MostDetailedMip, 1U)) - LOG_ERROR("Depth-stencil target width (", std::max(TexDesc.Width >> DSVDesc.MostDetailedMip, 1U), ") specified by DSV '", DSVDesc.Name, "' is inconsistent with the width of previously bound render targets (", m_FramebufferWidth, ")"); + LOG_ERROR_MESSAGE("Depth-stencil target width (", std::max(TexDesc.Width >> DSVDesc.MostDetailedMip, 1U), ") specified by DSV '", DSVDesc.Name, "' is inconsistent with the width of previously bound render targets (", m_FramebufferWidth, ")"); if (m_FramebufferHeight != std::max(TexDesc.Height >> DSVDesc.MostDetailedMip, 1U)) - LOG_ERROR("Depth-stencil target height (", std::max(TexDesc.Height >> DSVDesc.MostDetailedMip, 1U), ") specified by DSV '", DSVDesc.Name, "' is inconsistent with the height of previously bound render targets (", m_FramebufferHeight, ")"); + LOG_ERROR_MESSAGE("Depth-stencil target height (", std::max(TexDesc.Height >> DSVDesc.MostDetailedMip, 1U), ") specified by DSV '", DSVDesc.Name, "' is inconsistent with the height of previously bound render targets (", m_FramebufferHeight, ")"); if (m_FramebufferSlices != DSVDesc.NumArraySlices) - LOG_ERROR("Number of slices (", DSVDesc.NumArraySlices, ") specified by DSV '", DSVDesc.Name, "' is inconsistent with the number of slices in previously bound render targets (", m_FramebufferSlices, ")"); + LOG_ERROR_MESSAGE("Number of slices (", DSVDesc.NumArraySlices, ") specified by DSV '", DSVDesc.Name, "' is inconsistent with the number of slices in previously bound render targets (", m_FramebufferSlices, ")"); #endif } } @@ -747,6 +778,8 @@ bool DeviceContextBase::CheckIfBoundAsDepth template bool DeviceContextBase::UnbindTextureFromFramebuffer(TextureImplType* pTexture, bool bShowMessage) { + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside render pass"); + if (pTexture == nullptr) return false; @@ -799,6 +832,8 @@ bool DeviceContextBase::UnbindTextureFromFr template void DeviceContextBase::ResetRenderTargets() { + VERIFY(m_pActiveRenderPass == nullptr, "Resetting render targets inside the render pass may result in undefined behavior."); + for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) m_pBoundRenderTargets[rt].Release(); #ifdef DILIGENT_DEBUG @@ -815,6 +850,33 @@ void DeviceContextBase::ResetRenderTargets( m_pBoundDepthStencil.Release(); } +template +inline void DeviceContextBase::BeginRenderPass(const BeginRenderPassAttribs& Attribs) +{ + VERIFY(m_pActiveRenderPass == nullptr, "Attempting to begin render pass while another render pass ('", m_pActiveRenderPass->GetDesc().Name, "') is active."); + VERIFY(Attribs.pRenderPass != nullptr, "Render pass must not be null"); + ResetRenderTargets(); + m_pActiveRenderPass = ValidatedCast(Attribs.pRenderPass); + m_pBoundFramebuffer = ValidatedCast(Attribs.pFramebuffer); + m_SubpassIndex = 0; +} + +template +inline void DeviceContextBase::NextSubpass() +{ + VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass"); + ++m_SubpassIndex; +} + +template +inline void DeviceContextBase::EndRenderPass() +{ + VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass"); + m_pActiveRenderPass.Release(); + m_pBoundFramebuffer.Release(); + m_SubpassIndex = 0; +} + template inline bool DeviceContextBase::ClearDepthStencil(ITextureView* pView) @@ -826,6 +888,8 @@ inline bool DeviceContextBase::ClearDepthSt } #ifdef DILIGENT_DEVELOPMENT + VERIFY(m_pActiveRenderPass == nullptr, "ClearDepthStencil command must be used outside of render pass. Inside the render pass, use ClearDepthStencilAttachment command."); + { const auto& ViewDesc = pView->GetDesc(); if (ViewDesc.ViewType != TEXTURE_VIEW_DEPTH_STENCIL) @@ -868,6 +932,8 @@ inline bool DeviceContextBase::ClearRenderT } #ifdef DILIGENT_DEVELOPMENT + VERIFY(m_pActiveRenderPass == nullptr, "ClearRenderTarget command must be used outside of render pass. Inside the render pass, use ClearRenderTargetAttachment command."); + { const auto& ViewDesc = pView->GetDesc(); if (ViewDesc.ViewType != TEXTURE_VIEW_RENDER_TARGET) @@ -957,6 +1023,7 @@ inline void DeviceContextBase:: UpdateBuffer(IBuffer* pBuffer, Uint32 Offset, Uint32 Size, const void* pData, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) { VERIFY(pBuffer != nullptr, "Buffer must not be null"); + VERIFY(m_pActiveRenderPass == nullptr, "UpdateBuffer command must be used outside of render pass."); #ifdef DILIGENT_DEVELOPMENT { const auto& BuffDesc = ValidatedCast(pBuffer)->GetDesc(); @@ -979,6 +1046,7 @@ inline void DeviceContextBase:: { VERIFY(pSrcBuffer != nullptr, "Source buffer must not be null"); VERIFY(pDstBuffer != nullptr, "Destination buffer must not be null"); + VERIFY(m_pActiveRenderPass == nullptr, "CopyBuffer command must be used outside of render pass."); #ifdef DILIGENT_DEVELOPMENT { const auto& SrcBufferDesc = ValidatedCast(pSrcBuffer)->GetDesc(); @@ -1062,6 +1130,7 @@ inline void DeviceContextBase:: UpdateTexture(ITexture* pTexture, Uint32 MipLevel, Uint32 Slice, const Box& DstBox, const TextureSubResData& SubresData, RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode, RESOURCE_STATE_TRANSITION_MODE TextureTransitionMode) { VERIFY(pTexture != nullptr, "pTexture must not be null"); + VERIFY(m_pActiveRenderPass == nullptr, "UpdateTexture must be used outside of render pass."); ValidateUpdateTextureParams(pTexture->GetDesc(), MipLevel, Slice, DstBox, SubresData); } @@ -1071,6 +1140,7 @@ inline void DeviceContextBase:: { VERIFY(CopyAttribs.pSrcTexture, "Src texture must not be null"); VERIFY(CopyAttribs.pDstTexture, "Dst texture must not be null"); + VERIFY(m_pActiveRenderPass == nullptr, "CopyTexture must be used outside of render pass."); ValidateCopyTextureParams(CopyAttribs); } @@ -1102,6 +1172,7 @@ inline void DeviceContextBase:: GenerateMips(ITextureView* pTexView) { VERIFY(pTexView != nullptr, "pTexView must not be null"); + VERIFY(m_pActiveRenderPass == nullptr, "GenerateMips must be used outside of render pass."); #ifdef DILIGENT_DEVELOPMENT { const auto& ViewDesc = pTexView->GetDesc(); @@ -1158,6 +1229,7 @@ void DeviceContextBase:: DEV_CHECK_ERR(!ResolveFmtAttribs.IsTypeless, "Format of a resolve operation must not be typeless when one of the texture formats is typeless"); } + VERIFY(m_pActiveRenderPass == nullptr, "ResolveTextureSubresource must be used outside of render pass."); #endif } @@ -1259,6 +1331,10 @@ inline bool DeviceContextBase:: pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); return false; } + + VERIFY(!(m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION), + "Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); } else { @@ -1310,6 +1386,10 @@ inline bool DeviceContextBase:: pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); return false; } + + VERIFY(!(m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION), + "Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); } else { @@ -1326,7 +1406,7 @@ inline void DeviceContextBase:: { if (!m_pPipelineState) { - LOG_ERROR("No pipeline state is bound"); + LOG_ERROR_MESSAGE("No pipeline state is bound"); return; } diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index f0c4acf5..8136c582 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -49,6 +49,8 @@ #include "PipelineState.h" #include "Fence.h" #include "Query.h" +#include "RenderPass.h" +#include "Framebuffer.h" #include "CommandList.h" #include "SwapChain.h" @@ -615,7 +617,9 @@ typedef struct CopyTextureAttribs CopyTextureAttribs; /// This structure is used by IDeviceContext::BeginRenderPass(). struct BeginRenderPassAttribs { - int TBD; + IRenderPass* pRenderPass DEFAULT_INITIALIZER(nullptr); + + IFramebuffer* pFramebuffer DEFAULT_INITIALIZER(nullptr); }; typedef struct BeginRenderPassAttribs BeginRenderPassAttribs; -- cgit v1.2.3 From 465e53fd32f983aadc2e46c6cee3a0d7b836fe64 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 1 Aug 2020 11:46:38 -0700 Subject: Implemented BeginRenderPass/NextSubpass/EndRenderPass in Vulkan backend --- Graphics/GraphicsEngine/interface/DeviceContext.h | 12 ++++++ Graphics/GraphicsEngine/interface/GraphicsTypes.h | 49 +++++++++++++++++++++++ Graphics/GraphicsEngine/interface/Texture.h | 48 +--------------------- 3 files changed, 62 insertions(+), 47 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index 8136c582..5eca22a9 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -617,9 +617,21 @@ typedef struct CopyTextureAttribs CopyTextureAttribs; /// This structure is used by IDeviceContext::BeginRenderPass(). struct BeginRenderPassAttribs { + /// Render pass to begin. IRenderPass* pRenderPass DEFAULT_INITIALIZER(nullptr); + /// Framebuffer containing the attachments that are used with the render pass. IFramebuffer* pFramebuffer DEFAULT_INITIALIZER(nullptr); + + /// The number of elements in pClearValues array. + Uint32 ClearValueCount DEFAULT_INITIALIZER(0); + + /// A pointer to an array of ClearValueCount OptimizedClearValue structures that contains + /// clear values for each attachment, if the attachment uses a LoadOp value of ATTACHMENT_LOAD_OP_CLEAR + /// or if the attachment has a depth/stencil format and uses a StencilLoadOp value of ATTACHMENT_LOAD_OP_CLEAR. + /// The array is indexed by attachment number. Only elements corresponding to cleared attachments are used. + /// Other elements of pClearValues are ignored. + OptimizedClearValue* pClearValues DEFAULT_INITIALIZER(nullptr); }; typedef struct BeginRenderPassAttribs BeginRenderPassAttribs; diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 5fbb5412..796d7449 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -1079,6 +1079,55 @@ DILIGENT_TYPED_ENUM(PRIMITIVE_TOPOLOGY, Uint8) PRIMITIVE_TOPOLOGY_NUM_TOPOLOGIES }; + +/// Defines optimized depth-stencil clear value. +struct DepthStencilClearValue +{ + /// Depth clear value + Float32 Depth DEFAULT_INITIALIZER(1.f); + /// Stencil clear value + Uint8 Stencil DEFAULT_INITIALIZER(0); + +#if DILIGENT_CPP_INTERFACE + DepthStencilClearValue()noexcept{} + + DepthStencilClearValue(Float32 _Depth, + Uint8 _Stencil)noexcept : + Depth {_Depth }, + Stencil {_Stencil} + {} +#endif +}; +typedef struct DepthStencilClearValue DepthStencilClearValue; + +/// Defines optimized clear value. +struct OptimizedClearValue +{ + /// Format + TEXTURE_FORMAT Format DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); + + /// Render target clear value + Float32 Color[4] DEFAULT_INITIALIZER({}); + + /// Depth stencil clear value + DepthStencilClearValue DepthStencil; + +#if DILIGENT_CPP_INTERFACE + bool operator == (const OptimizedClearValue& rhs)const + { + return Format == rhs.Format && + Color[0] == rhs.Color[0] && + Color[1] == rhs.Color[1] && + Color[2] == rhs.Color[2] && + Color[3] == rhs.Color[3] && + DepthStencil.Depth == rhs.DepthStencil.Depth && + DepthStencil.Stencil == rhs.DepthStencil.Stencil; + } +#endif +}; +typedef struct OptimizedClearValue OptimizedClearValue; + + /// Describes common device object attributes struct DeviceObjectAttribs { diff --git a/Graphics/GraphicsEngine/interface/Texture.h b/Graphics/GraphicsEngine/interface/Texture.h index 294bb875..3f61338f 100644 --- a/Graphics/GraphicsEngine/interface/Texture.h +++ b/Graphics/GraphicsEngine/interface/Texture.h @@ -32,6 +32,7 @@ /// \file /// Definition of the Diligent::ITexture interface and related data structures +#include "GraphicsTypes.h" #include "DeviceObject.h" #include "TextureView.h" @@ -42,53 +43,6 @@ DILIGENT_BEGIN_NAMESPACE(Diligent) static const INTERFACE_ID IID_Texture = {0xa64b0e60, 0x1b5e, 0x4cfd,{0xb8, 0x80, 0x66, 0x3a, 0x1a, 0xdc, 0xbe, 0x98}}; -/// Defines optimized depth-stencil clear value. -struct DepthStencilClearValue -{ - /// Depth clear value - Float32 Depth DEFAULT_INITIALIZER(1.f); - /// Stencil clear value - Uint8 Stencil DEFAULT_INITIALIZER(0); - -#if DILIGENT_CPP_INTERFACE - DepthStencilClearValue()noexcept{} - - DepthStencilClearValue(Float32 _Depth, - Uint8 _Stencil)noexcept : - Depth {_Depth }, - Stencil {_Stencil} - {} -#endif -}; -typedef struct DepthStencilClearValue DepthStencilClearValue; - -/// Defines optimized clear value. -struct OptimizedClearValue -{ - /// Format - TEXTURE_FORMAT Format DEFAULT_INITIALIZER(TEX_FORMAT_UNKNOWN); - - /// Render target clear value - Float32 Color[4] DEFAULT_INITIALIZER({}); - - /// Depth stencil clear value - DepthStencilClearValue DepthStencil; - -#if DILIGENT_CPP_INTERFACE - bool operator == (const OptimizedClearValue& rhs)const - { - return Format == rhs.Format && - Color[0] == rhs.Color[0] && - Color[1] == rhs.Color[1] && - Color[2] == rhs.Color[2] && - Color[3] == rhs.Color[3] && - DepthStencil.Depth == rhs.DepthStencil.Depth && - DepthStencil.Stencil == rhs.DepthStencil.Stencil; - } -#endif -}; -typedef struct OptimizedClearValue OptimizedClearValue; - /// Texture description struct TextureDesc DILIGENT_DERIVE(DeviceObjectAttribs) -- cgit v1.2.3 From 89e1718309473686f1bae9ef46c501fc1d6e1520 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 1 Aug 2020 14:22:47 -0700 Subject: Implemented ClearRenderTarget/ClearDepthStencil for inside render pass clears --- .../GraphicsEngine/include/DeviceContextBase.hpp | 94 ++++++++++++++++------ 1 file changed, 68 insertions(+), 26 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 74fc5966..8679f202 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -888,8 +888,6 @@ inline bool DeviceContextBase::ClearDepthSt } #ifdef DILIGENT_DEVELOPMENT - VERIFY(m_pActiveRenderPass == nullptr, "ClearDepthStencil command must be used outside of render pass. Inside the render pass, use ClearDepthStencilAttachment command."); - { const auto& ViewDesc = pView->GetDesc(); if (ViewDesc.ViewType != TEXTURE_VIEW_DEPTH_STENCIL) @@ -899,21 +897,44 @@ inline bool DeviceContextBase::ClearDepthSt return false; } - if (pView != m_pBoundDepthStencil) + if (m_pActiveRenderPass != nullptr) { - if (m_pDevice->GetDeviceCaps().IsGLDevice()) + bool AttachmentFound = false; + if (m_pBoundFramebuffer != nullptr) + { + const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); + for (Uint32 i = 0; i < FBDesc.AttachmentCount && !AttachmentFound; ++i) + { + AttachmentFound = FBDesc.ppAttachments[i] == pView; + } + } + + if (!AttachmentFound) { LOG_ERROR_MESSAGE("Depth-stencil view '", ViewDesc.Name, - "' is not bound to the device context. ClearDepthStencil command requires " - "depth-stencil view be bound to the device contex in OpenGL backend"); + "' is not bound as framebuffer attachment. ClearDepthStencil command inside a render pass " + "requires depth-stencil view be bound as framebuffer attachment."); return false; } - else + } + else + { + if (pView != m_pBoundDepthStencil) { - LOG_WARNING_MESSAGE("Depth-stencil view '", ViewDesc.Name, - "' is not bound to the device context. " - "ClearDepthStencil command is more efficient when depth-stencil " - "view is bound to the context. In OpenGL backend this is a requirement."); + if (m_pDevice->GetDeviceCaps().IsGLDevice()) + { + LOG_ERROR_MESSAGE("Depth-stencil view '", ViewDesc.Name, + "' is not bound to the device context. ClearDepthStencil command requires " + "depth-stencil view be bound to the device contex in OpenGL backend"); + return false; + } + else + { + LOG_WARNING_MESSAGE("Depth-stencil view '", ViewDesc.Name, + "' is not bound to the device context. " + "ClearDepthStencil command is more efficient when depth-stencil " + "view is bound to the context. In OpenGL backend this is a requirement."); + } } } } @@ -932,8 +953,6 @@ inline bool DeviceContextBase::ClearRenderT } #ifdef DILIGENT_DEVELOPMENT - VERIFY(m_pActiveRenderPass == nullptr, "ClearRenderTarget command must be used outside of render pass. Inside the render pass, use ClearRenderTargetAttachment command."); - { const auto& ViewDesc = pView->GetDesc(); if (ViewDesc.ViewType != TEXTURE_VIEW_RENDER_TARGET) @@ -943,25 +962,48 @@ inline bool DeviceContextBase::ClearRenderT return false; } - bool RTFound = false; - for (Uint32 i = 0; i < m_NumBoundRenderTargets && !RTFound; ++i) - { - RTFound = m_pBoundRenderTargets[i] == pView; - } - if (!RTFound) + if (m_pActiveRenderPass != nullptr) { - if (m_pDevice->GetDeviceCaps().IsGLDevice()) + bool AttachmentFound = false; + if (m_pBoundFramebuffer != nullptr) + { + const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); + for (Uint32 i = 0; i < FBDesc.AttachmentCount && !AttachmentFound; ++i) + { + AttachmentFound = FBDesc.ppAttachments[i] == pView; + } + } + + if (!AttachmentFound) { LOG_ERROR_MESSAGE("Render target view '", ViewDesc.Name, - "' is not bound to the device context. ClearRenderTarget command " - "requires render target view be bound to the device contex in OpenGL backend"); + "' is not bound as framebuffer attachment. ClearRenderTarget command inside a render pass " + "requires render target view be bound as framebuffer attachment."); return false; } - else + } + else + { + bool RTFound = false; + for (Uint32 i = 0; i < m_NumBoundRenderTargets && !RTFound; ++i) + { + RTFound = m_pBoundRenderTargets[i] == pView; + } + if (!RTFound) { - LOG_WARNING_MESSAGE("Render target view '", ViewDesc.Name, - "' is not bound to the device context. ClearRenderTarget command is more efficient " - "if render target view is bound to the device context. In OpenGL backend this is a requirement."); + if (m_pDevice->GetDeviceCaps().IsGLDevice()) + { + LOG_ERROR_MESSAGE("Render target view '", ViewDesc.Name, + "' is not bound to the device context. ClearRenderTarget command " + "requires render target view be bound to the device contex in OpenGL backend"); + return false; + } + else + { + LOG_WARNING_MESSAGE("Render target view '", ViewDesc.Name, + "' is not bound to the device context. ClearRenderTarget command is more efficient " + "if render target view is bound to the device context. In OpenGL backend this is a requirement."); + } } } } -- cgit v1.2.3 From 3aa36ab27691129b99702a4102f73afdd9f4c52b Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 1 Aug 2020 16:56:01 -0700 Subject: Fixed frame buffer attachment clear operations; updated clear render target tests --- .../GraphicsEngine/include/DeviceContextBase.hpp | 33 ++++++++++++++++++++++ Graphics/GraphicsEngine/interface/DeviceContext.h | 3 ++ 2 files changed, 36 insertions(+) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 8679f202..d217a115 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -855,10 +855,43 @@ inline void DeviceContextBase::BeginRenderP { VERIFY(m_pActiveRenderPass == nullptr, "Attempting to begin render pass while another render pass ('", m_pActiveRenderPass->GetDesc().Name, "') is active."); VERIFY(Attribs.pRenderPass != nullptr, "Render pass must not be null"); + VERIFY(Attribs.pFramebuffer != nullptr, "Framebuffer must not be null"); ResetRenderTargets(); + m_pActiveRenderPass = ValidatedCast(Attribs.pRenderPass); m_pBoundFramebuffer = ValidatedCast(Attribs.pFramebuffer); m_SubpassIndex = 0; + + const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); + m_FramebufferWidth = FBDesc.Width; + m_FramebufferHeight = FBDesc.Height; + m_FramebufferSlices = FBDesc.NumArraySlices; + + if (Attribs.StateTransitionMode != RESOURCE_STATE_TRANSITION_MODE_NONE) + { + const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + VERIFY(RPDesc.AttachmentCount <= FBDesc.AttachmentCount, + "The number of attachments (", FBDesc.AttachmentCount, + ") in currently bound framebuffer is smaller than the number of attachments in the render pass (", RPDesc.AttachmentCount, ")"); + for (Uint32 i = 0; i < FBDesc.AttachmentCount; ++i) + { + auto* pView = FBDesc.ppAttachments[i]; + if (pView == nullptr) + return; + + auto* pTex = ValidatedCast(pView->GetTexture()); + auto RequiredState = RPDesc.pAttachments[i].InitialState; + if (Attribs.StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + StateTransitionDesc Barrier{pTex, RESOURCE_STATE_UNKNOWN, RequiredState, true}; + TransitionResourceStates(1, &Barrier); + } + else if (Attribs.StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + DvpVerifyTextureState(*pTex, RequiredState, "BeginRenderPass"); + } + } + } } template diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index 5eca22a9..5b52cec0 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -632,6 +632,9 @@ struct BeginRenderPassAttribs /// The array is indexed by attachment number. Only elements corresponding to cleared attachments are used. /// Other elements of pClearValues are ignored. OptimizedClearValue* pClearValues DEFAULT_INITIALIZER(nullptr); + + /// Framebuffer attachments state transition mode. + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); }; typedef struct BeginRenderPassAttribs BeginRenderPassAttribs; -- cgit v1.2.3 From cb8665cbb6bb002dc096a3e69dc36b1d6ceb7260 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 1 Aug 2020 17:17:46 -0700 Subject: Fixed build error --- Graphics/GraphicsEngine/include/DeviceContextBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index d217a115..9a9e5e89 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -884,7 +884,7 @@ inline void DeviceContextBase::BeginRenderP if (Attribs.StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { StateTransitionDesc Barrier{pTex, RESOURCE_STATE_UNKNOWN, RequiredState, true}; - TransitionResourceStates(1, &Barrier); + this->TransitionResourceStates(1, &Barrier); } else if (Attribs.StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) { -- cgit v1.2.3 From 812fc38d1b0957ed96d93e023b7322d65c5d3f5d Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 1 Aug 2020 18:18:48 -0700 Subject: Updated EndRenderPass to optionally update resource states --- .../GraphicsEngine/include/DeviceContextBase.hpp | 20 ++++++++++++++++++-- Graphics/GraphicsEngine/interface/DeviceContext.h | 9 ++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 9a9e5e89..68f9ec4e 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -130,7 +130,7 @@ public: virtual void DILIGENT_CALL_TYPE NextSubpass() override = 0; - virtual void DILIGENT_CALL_TYPE EndRenderPass() override = 0; + virtual void DILIGENT_CALL_TYPE EndRenderPass(bool UpdateResourceStates) override = 0; /// Base implementation of IDeviceContext::UpdateBuffer(); validates input parameters. virtual void DILIGENT_CALL_TYPE UpdateBuffer(IBuffer* pBuffer, @@ -902,9 +902,25 @@ inline void DeviceContextBase::NextSubpass( } template -inline void DeviceContextBase::EndRenderPass() +inline void DeviceContextBase::EndRenderPass(bool UpdateResourceStates) { VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass"); + VERIFY(m_pBoundFramebuffer != nullptr, "There is no active framebuffer"); + if (UpdateResourceStates) + { + const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); + VERIFY(FBDesc.AttachmentCount >= RPDesc.AttachmentCount, + "Framebuffer attachment count (", FBDesc.AttachmentCount, ") is smaller than the render pass attachment count (", RPDesc.AttachmentCount, ")"); + for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i) + { + if (auto* pView = FBDesc.ppAttachments[i]) + { + auto* pTex = ValidatedCast(pView->GetTexture()); + pTex->SetState(RPDesc.pAttachments[i].FinalState); + } + } + } m_pActiveRenderPass.Release(); m_pBoundFramebuffer.Release(); m_SubpassIndex = 0; diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index 5b52cec0..3445a8d6 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -905,7 +905,14 @@ DILIGENT_BEGIN_INTERFACE(IDeviceContext, IObject) /// Ends current render pass. - VIRTUAL void METHOD(EndRenderPass)(THIS) PURE; + + /// \param [in] UpdateResourceStates - Indicates whether to update resource states so that they match + /// the final states specified by the render pass attachments. + /// Note that resources are always transitioned to the final states. + /// The flag only indicates if the internal state variables should be + /// updated to match the actual final states. + VIRTUAL void METHOD(EndRenderPass)(THIS_ + bool UpdateResourceStates) PURE; /// Executes a draw command. -- cgit v1.2.3 From 2c8af36b75be6b3c093175987ffa07df921adc56 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 1 Aug 2020 21:26:33 -0700 Subject: Few improvements to render pass API --- Graphics/GraphicsEngine/interface/RenderPass.h | 22 +++++++++++++++++++--- Graphics/GraphicsEngine/src/FramebufferBase.cpp | 16 ++++++++++++++++ Graphics/GraphicsEngine/src/RenderPassBase.cpp | 24 ++++++++++++++++++++++-- 3 files changed, 57 insertions(+), 5 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/RenderPass.h b/Graphics/GraphicsEngine/interface/RenderPass.h index 0f12c66d..e9f3027d 100644 --- a/Graphics/GraphicsEngine/interface/RenderPass.h +++ b/Graphics/GraphicsEngine/interface/RenderPass.h @@ -40,30 +40,46 @@ DILIGENT_BEGIN_NAMESPACE(Diligent) static const struct INTERFACE_ID IID_RenderPass = { 0xb818dec7, 0x174d, 0x447a, { 0xa8, 0xe4, 0x94, 0xd2, 0x1c, 0x57, 0xb4, 0xa } }; + /// Render pass attachment load operation +/// Vulkan counterpart: [VkAttachmentLoadOp](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VkAttachmentLoadOp). +/// D3D12 counterpart: [D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE](https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_render_pass_beginning_access_type). DILIGENT_TYPED_ENUM(ATTACHMENT_LOAD_OP, Uint8) { /// The previous contents of the texture within the render area will be preserved. + /// Vulkan counterpart: VK_ATTACHMENT_LOAD_OP_LOAD. + /// D3D12 counterpart: D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE. ATTACHMENT_LOAD_OP_LOAD = 0, /// The contents within the render area will be cleared to a uniform value, which is - /// specified when a render pass instance is begun + /// specified when a render pass instance is begun. + /// Vulkan counterpart: VK_ATTACHMENT_LOAD_OP_CLEAR. + /// D3D12 counterpart: D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR. ATTACHMENT_LOAD_OP_CLEAR, /// The previous contents within the area need not be preserved; the contents of /// the attachment will be undefined inside the render area. - ATTACHMENT_LOAD_OP_DONT_CARE + /// Vulkan counterpart: VK_ATTACHMENT_LOAD_OP_DONT_CARE. + /// D3D12 counterpart: D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD. + ATTACHMENT_LOAD_OP_DISCARD }; + /// Render pass attachment store operation +/// Vulkan counterpart: [VkAttachmentStoreOp](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VkAttachmentStoreOp). +/// D3D12 counterpart: [D3D12_RENDER_PASS_ENDING_ACCESS_TYPE](https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_render_pass_ending_access_type). DILIGENT_TYPED_ENUM(ATTACHMENT_STORE_OP, Uint8) { /// The contents generated during the render pass and within the render area are written to memory. + /// Vulkan counterpart: VK_ATTACHMENT_STORE_OP_STORE. + /// D3D12 counterpart: D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE. ATTACHMENT_STORE_OP_STORE = 0, /// The contents within the render area are not needed after rendering, and may be discarded; /// the contents of the attachment will be undefined inside the render area. - ATTACHMENT_STORE_OP_DONT_CARE + /// Vulkan counterpart: VK_ATTACHMENT_STORE_OP_DONT_CARE. + /// D3D12 counterpart: D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD. + ATTACHMENT_STORE_OP_DISCARD }; diff --git a/Graphics/GraphicsEngine/src/FramebufferBase.cpp b/Graphics/GraphicsEngine/src/FramebufferBase.cpp index d3d06702..89b1aa5f 100644 --- a/Graphics/GraphicsEngine/src/FramebufferBase.cpp +++ b/Graphics/GraphicsEngine/src/FramebufferBase.cpp @@ -97,6 +97,10 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) continue; + // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments + // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not + // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) { LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of input attachment reference ", input_attachment, @@ -125,6 +129,10 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) continue; + // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments + // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not + // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) { LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of render target attachment reference ", rt_attachment, @@ -155,6 +163,10 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) continue; + // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments + // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not + // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) { LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of resolve attachment reference ", rslv_attachment, @@ -183,6 +195,10 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) const auto& AttchRef = *Subpass.pDepthStencilAttachment; if (AttchRef.AttachmentIndex != ATTACHMENT_UNUSED) { + // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments + // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not + // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) { LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of depth-stencil attachment reference of subpass ", i, diff --git a/Graphics/GraphicsEngine/src/RenderPassBase.cpp b/Graphics/GraphicsEngine/src/RenderPassBase.cpp index a77ef404..f060c8a0 100644 --- a/Graphics/GraphicsEngine/src/RenderPassBase.cpp +++ b/Graphics/GraphicsEngine/src/RenderPassBase.cpp @@ -38,13 +38,33 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) #define LOG_RENDER_PASS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Render pass '", (Desc.Name ? Desc.Name : ""), "': ", ##__VA_ARGS__) if (Desc.AttachmentCount != 0 && Desc.pAttachments == nullptr) + { + // If attachmentCount is not 0, pAttachments must be a valid pointer to an + // array of attachmentCount valid VkAttachmentDescription structures. + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pAttachments-parameter LOG_RENDER_PASS_ERROR_AND_THROW("The attachment count (", Desc.AttachmentCount, ") is not zero, but pAttachments is null"); + } - if (Desc.SubpassCount != 0 && Desc.pSubpasses == nullptr) - LOG_RENDER_PASS_ERROR_AND_THROW("The subpass count (", Desc.SubpassCount, ") is not zero, but pSubpasses is null"); + if (Desc.SubpassCount == 0) + { + // subpassCount must be greater than 0. + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-subpassCount-arraylength + LOG_RENDER_PASS_ERROR_AND_THROW("Render pass must have at least one subpass"); + } + if (Desc.pSubpasses == nullptr) + { + // pSubpasses must be a valid pointer to an array of subpassCount valid VkSubpassDescription structures. + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pSubpasses-parameter + LOG_RENDER_PASS_ERROR_AND_THROW("pSubpasses must not be null"); + } if (Desc.DependencyCount != 0 && Desc.pDependencies == nullptr) + { + // If dependencyCount is not 0, pDependencies must be a valid pointer to an array of + // dependencyCount valid VkSubpassDependency structures. + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pDependencies-parameter LOG_RENDER_PASS_ERROR_AND_THROW("The dependency count (", Desc.DependencyCount, ") is not zero, but pDependencies is null"); + } for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) { -- cgit v1.2.3 From 26003b33992221c28bc63b92afb5ab4719cce4bb Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 2 Aug 2020 17:55:20 -0700 Subject: Added more render pass desc validation --- Graphics/GraphicsEngine/src/FramebufferBase.cpp | 82 ++++------- Graphics/GraphicsEngine/src/RenderPassBase.cpp | 186 +++++++++++++++++++++--- 2 files changed, 190 insertions(+), 78 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/src/FramebufferBase.cpp b/Graphics/GraphicsEngine/src/FramebufferBase.cpp index 89b1aa5f..fa1f8d10 100644 --- a/Graphics/GraphicsEngine/src/FramebufferBase.cpp +++ b/Graphics/GraphicsEngine/src/FramebufferBase.cpp @@ -34,11 +34,11 @@ namespace Diligent void ValidateFramebufferDesc(const FramebufferDesc& Desc) { -#define LOG_FRAMEBUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Framebuffer '", (Desc.Name ? Desc.Name : ""), "': ", ##__VA_ARGS__) +#define LOG_FRAMEBUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of framebuffer '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__) if (Desc.pRenderPass == nullptr) { - LOG_FRAMEBUFFER_ERROR_AND_THROW("Render pass must not be null"); + LOG_FRAMEBUFFER_ERROR_AND_THROW("render pass must not be null."); } for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) @@ -48,30 +48,31 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, and attachmentCount is not 0, // pAttachments must be a valid pointer to an array of attachmentCount valid VkImageView handles. // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-flags-02778 - LOG_FRAMEBUFFER_ERROR_AND_THROW("Framebuffer attachment ", i, " is null"); + LOG_FRAMEBUFFER_ERROR_AND_THROW("framebuffer attachment ", i, " is null."); } } const auto& RPDesc = Desc.pRenderPass->GetDesc(); if (Desc.AttachmentCount < RPDesc.AttachmentCount) { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The number of framebuffer attachments (", Desc.AttachmentCount, + LOG_FRAMEBUFFER_ERROR_AND_THROW("the number of framebuffer attachments (", Desc.AttachmentCount, ") is smaller than the number of attachments (", RPDesc.AttachmentCount, ") in the render pass '", RPDesc.Name, "'."); } for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i) { - const auto& AttDesc = RPDesc.pAttachments[i]; - const auto& TexDesc = Desc.ppAttachments[i]->GetTexture()->GetDesc(); + const auto& AttDesc = RPDesc.pAttachments[i]; + const auto& ViewDesc = Desc.ppAttachments[i]->GetDesc(); + const auto& TexDesc = Desc.ppAttachments[i]->GetTexture()->GetDesc(); // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments // must have been created with a VkFormat value that matches the VkFormat specified by the corresponding // VkAttachmentDescription in renderPass // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00880 - if (TexDesc.Format != AttDesc.Format) + if (ViewDesc.Format != AttDesc.Format) { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The format (", GetTextureFormatAttribs(TexDesc.Format).Name, ") of attachment ", i, + LOG_FRAMEBUFFER_ERROR_AND_THROW("the format (", GetTextureFormatAttribs(ViewDesc.Format).Name, ") of attachment ", i, " does not match the format (", GetTextureFormatAttribs(AttDesc.Format).Name, ") defined by the render pass for the same attachment."); } @@ -82,7 +83,7 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00881 if (TexDesc.SampleCount != AttDesc.SampleCount) { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The sample count (", Uint32{TexDesc.SampleCount}, ") of attachment ", i, + LOG_FRAMEBUFFER_ERROR_AND_THROW("the sample count (", Uint32{TexDesc.SampleCount}, ") of attachment ", i, " does not match the sample count (", Uint32{AttDesc.SampleCount}, ") defined by the render pass for the same attachment."); } @@ -97,16 +98,9 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) continue; - // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments - // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not - // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount - // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 - if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) - { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of input attachment reference ", input_attachment, - " of subpass ", i, " of render pass '", RPDesc.Name, - "' exceeds the number of attachments in the framebuffer (", Desc.AttachmentCount, ")"); - } + VERIFY(AttchRef.AttachmentIndex < Desc.AttachmentCount, + "Input attachment index (", AttchRef.AttachmentIndex, ") must be less than the attachment count (", + Desc.AttachmentCount, ") as this is ensured by ValidateRenderPassDesc."); const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); @@ -116,7 +110,7 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00879 if ((TexDesc.BindFlags & BIND_INPUT_ATTACHMENT) == 0) { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, + LOG_FRAMEBUFFER_ERROR_AND_THROW("the attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, " is used as input attachment by subpass ", i, " of render pass '", RPDesc.Name, "', but was not created with BIND_INPUT_ATTACHMENT bind flag"); @@ -129,16 +123,9 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) continue; - // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments - // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not - // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount - // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 - if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) - { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of render target attachment reference ", rt_attachment, - " of subpass ", i, " of render pass '", RPDesc.Name, - "' exceeds the number of attachments in the framebuffer (", Desc.AttachmentCount, ")"); - } + VERIFY(AttchRef.AttachmentIndex < Desc.AttachmentCount, + "Render target attachment index (", AttchRef.AttachmentIndex, ") must be less than the attachment count (", + Desc.AttachmentCount, ") as this is ensured by ValidateRenderPassDesc."); const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); @@ -148,7 +135,7 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00877 if ((TexDesc.BindFlags & BIND_RENDER_TARGET) == 0) { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, + LOG_FRAMEBUFFER_ERROR_AND_THROW("the attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, " is used as render target attachment by subpass ", i, " of render pass '", RPDesc.Name, "', but was not created with BIND_RENDER_TARGET bind flag"); @@ -163,16 +150,9 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) continue; - // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments - // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not - // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount - // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 - if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) - { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of resolve attachment reference ", rslv_attachment, - " of subpass ", i, " of render pass '", RPDesc.Name, - "' exceeds the number of attachments in the framebuffer (", Desc.AttachmentCount, ")"); - } + VERIFY(AttchRef.AttachmentIndex < Desc.AttachmentCount, + "Resolve attachment index (", AttchRef.AttachmentIndex, ") must be less than the attachment count (", + Desc.AttachmentCount, ") as this is ensured by ValidateRenderPassDesc."); const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); @@ -182,7 +162,7 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-00877 if ((TexDesc.BindFlags & BIND_RENDER_TARGET) == 0) { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, + LOG_FRAMEBUFFER_ERROR_AND_THROW("the attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, " is used as resolve attachment by subpass ", i, " of render pass '", RPDesc.Name, "', but was not created with BIND_RENDER_TARGET bind flag"); @@ -195,16 +175,9 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) const auto& AttchRef = *Subpass.pDepthStencilAttachment; if (AttchRef.AttachmentIndex != ATTACHMENT_UNUSED) { - // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments - // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not - // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount - // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 - if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) - { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment index (", AttchRef.AttachmentIndex, ") of depth-stencil attachment reference of subpass ", i, - " of render pass '", RPDesc.Name, - "' exceeds the number of attachments in the framebuffer (", Desc.AttachmentCount, ")"); - } + VERIFY(AttchRef.AttachmentIndex < Desc.AttachmentCount, + "Depth-stencil attachment index (", AttchRef.AttachmentIndex, ") must be less than the attachment count (", + Desc.AttachmentCount, ") as this is ensured by ValidateRenderPassDesc."); const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); @@ -214,16 +187,13 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-pAttachments-02633 if ((TexDesc.BindFlags & BIND_DEPTH_STENCIL) == 0) { - LOG_FRAMEBUFFER_ERROR_AND_THROW("The attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, + LOG_FRAMEBUFFER_ERROR_AND_THROW("the attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, " is used as detph-stencil attachment by subpass ", i, " of render pass '", RPDesc.Name, "', but was not created with BIND_DEPTH_STENCIL bind flag"); } } } - - //for (Uint32 prsv_attachment = 0; prsv_attachment < Subpass.PreserveAttachmentCount; ++prsv_attachment) - // ; } } diff --git a/Graphics/GraphicsEngine/src/RenderPassBase.cpp b/Graphics/GraphicsEngine/src/RenderPassBase.cpp index f060c8a0..683d86aa 100644 --- a/Graphics/GraphicsEngine/src/RenderPassBase.cpp +++ b/Graphics/GraphicsEngine/src/RenderPassBase.cpp @@ -35,27 +35,27 @@ namespace Diligent void ValidateRenderPassDesc(const RenderPassDesc& Desc) { -#define LOG_RENDER_PASS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Render pass '", (Desc.Name ? Desc.Name : ""), "': ", ##__VA_ARGS__) +#define LOG_RENDER_PASS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of render pass '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__) if (Desc.AttachmentCount != 0 && Desc.pAttachments == nullptr) { // If attachmentCount is not 0, pAttachments must be a valid pointer to an // array of attachmentCount valid VkAttachmentDescription structures. // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pAttachments-parameter - LOG_RENDER_PASS_ERROR_AND_THROW("The attachment count (", Desc.AttachmentCount, ") is not zero, but pAttachments is null"); + LOG_RENDER_PASS_ERROR_AND_THROW("the attachment count (", Desc.AttachmentCount, ") is not zero, but pAttachments is null."); } if (Desc.SubpassCount == 0) { // subpassCount must be greater than 0. // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-subpassCount-arraylength - LOG_RENDER_PASS_ERROR_AND_THROW("Render pass must have at least one subpass"); + LOG_RENDER_PASS_ERROR_AND_THROW("render pass must have at least one subpass."); } if (Desc.pSubpasses == nullptr) { // pSubpasses must be a valid pointer to an array of subpassCount valid VkSubpassDescription structures. // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pSubpasses-parameter - LOG_RENDER_PASS_ERROR_AND_THROW("pSubpasses must not be null"); + LOG_RENDER_PASS_ERROR_AND_THROW("pSubpasses must not be null."); } if (Desc.DependencyCount != 0 && Desc.pDependencies == nullptr) @@ -63,20 +63,20 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) // If dependencyCount is not 0, pDependencies must be a valid pointer to an array of // dependencyCount valid VkSubpassDependency structures. // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-pDependencies-parameter - LOG_RENDER_PASS_ERROR_AND_THROW("The dependency count (", Desc.DependencyCount, ") is not zero, but pDependencies is null"); + LOG_RENDER_PASS_ERROR_AND_THROW("the dependency count (", Desc.DependencyCount, ") is not zero, but pDependencies is null."); } for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) { const auto& Attachment = Desc.pAttachments[i]; if (Attachment.Format == TEX_FORMAT_UNKNOWN) - LOG_RENDER_PASS_ERROR_AND_THROW("the format of attachment ", i, " is unknown"); + LOG_RENDER_PASS_ERROR_AND_THROW("the format of attachment ", i, " is unknown."); if (Attachment.SampleCount == 0) - LOG_RENDER_PASS_ERROR_AND_THROW("the sample count of attachment ", i, " is zero"); + LOG_RENDER_PASS_ERROR_AND_THROW("the sample count of attachment ", i, " is zero."); if (!IsPowerOfTwo(Attachment.SampleCount)) - LOG_RENDER_PASS_ERROR_AND_THROW("the sample count of attachment ", i, "(", Attachment.SampleCount, ") is not power of two"); + LOG_RENDER_PASS_ERROR_AND_THROW("the sample count (", Uint32{Attachment.SampleCount}, ") of attachment ", i, " is not power of two."); const auto& FmtInfo = GetTextureFormatAttribs(Attachment.Format); if (FmtInfo.ComponentType == COMPONENT_TYPE_DEPTH || @@ -89,7 +89,7 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE) { - LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid"); + LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid."); } if (Attachment.FinalState != RESOURCE_STATE_DEPTH_WRITE && @@ -99,7 +99,7 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE) { - LOG_RENDER_PASS_ERROR_AND_THROW("the final state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid"); + LOG_RENDER_PASS_ERROR_AND_THROW("the final state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid."); } } else @@ -110,7 +110,7 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE) { - LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of color attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid"); + LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of color attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid."); } if (Attachment.FinalState != RESOURCE_STATE_RENDER_TARGET && @@ -119,28 +119,170 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE) { - LOG_RENDER_PASS_ERROR_AND_THROW("the final state of color attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid"); + LOG_RENDER_PASS_ERROR_AND_THROW("the final state of color attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid."); } } } - for (Uint32 i = 0; i < Desc.SubpassCount; ++i) + for (Uint32 subpass = 0; subpass < Desc.SubpassCount; ++subpass) { - const auto& Subpass = Desc.pSubpasses[i]; + const auto& Subpass = Desc.pSubpasses[subpass]; if (Subpass.InputAttachmentCount != 0 && Subpass.pInputAttachments == nullptr) { - LOG_RENDER_PASS_ERROR_AND_THROW("the input attachment count (", Subpass.InputAttachmentCount, ") of subpass ", i, - " is not zero, while pInputAttachments is null"); + LOG_RENDER_PASS_ERROR_AND_THROW("the input attachment count (", Subpass.InputAttachmentCount, ") of subpass ", subpass, + " is not zero, while pInputAttachments is null."); } if (Subpass.RenderTargetAttachmentCount != 0 && Subpass.pRenderTargetAttachments == nullptr) { - LOG_RENDER_PASS_ERROR_AND_THROW("the render target attachment count (", Subpass.RenderTargetAttachmentCount, ") of subpass ", i, - " is not zero, while pRenderTargetAttachments is null"); + LOG_RENDER_PASS_ERROR_AND_THROW("the render target attachment count (", Subpass.RenderTargetAttachmentCount, ") of subpass ", subpass, + " is not zero, while pRenderTargetAttachments is null."); } if (Subpass.PreserveAttachmentCount != 0 && Subpass.pPreserveAttachments == nullptr) { - LOG_RENDER_PASS_ERROR_AND_THROW("the preserve attachment count (", Subpass.PreserveAttachmentCount, ") of subpass ", i, - " is not zero, while pPreserveAttachments is null"); + LOG_RENDER_PASS_ERROR_AND_THROW("the preserve attachment count (", Subpass.PreserveAttachmentCount, ") of subpass ", subpass, + " is not zero, while pPreserveAttachments is null."); + } + + for (Uint32 input_attachment = 0; input_attachment < Subpass.InputAttachmentCount; ++input_attachment) + { + const auto& AttchRef = Subpass.pInputAttachments[input_attachment]; + if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) + continue; + + // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments + // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not + // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 + if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the attachment index (", AttchRef.AttachmentIndex, ") of input attachment reference ", input_attachment, + " of subpass ", subpass, " must be less than the number of attachments (", Desc.AttachmentCount, ")."); + } + } + + for (Uint32 rt_attachment = 0; rt_attachment < Subpass.RenderTargetAttachmentCount; ++rt_attachment) + { + const auto& AttchRef = Subpass.pRenderTargetAttachments[rt_attachment]; + if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) + continue; + + // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments + // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not + // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 + if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the attachment index (", AttchRef.AttachmentIndex, ") of render target attachment reference ", rt_attachment, + " of subpass ", subpass, " must be less than the number of attachments (", Desc.AttachmentCount, ")."); + } + } + + if (Subpass.pResolveAttachments != nullptr) + { + for (Uint32 rslv_attachment = 0; rslv_attachment < Subpass.RenderTargetAttachmentCount; ++rslv_attachment) + { + const auto& AttchRef = Subpass.pResolveAttachments[rslv_attachment]; + if (AttchRef.AttachmentIndex == ATTACHMENT_UNUSED) + continue; + + // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments + // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not + // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 + if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the attachment index (", AttchRef.AttachmentIndex, ") of resolve attachment reference ", rslv_attachment, + " of subpass ", subpass, " must be less than the number of attachments (", Desc.AttachmentCount, ")."); + } + } + } + + if (Subpass.pDepthStencilAttachment != nullptr) + { + const auto& AttchRef = *Subpass.pDepthStencilAttachment; + if (AttchRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + // If the attachment member of any element of pInputAttachments, pColorAttachments, pResolveAttachments + // or pDepthStencilAttachment, or any element of pPreserveAttachments in any element of pSubpasses is not + // VK_ATTACHMENT_UNUSED, it must be less than attachmentCount + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkRenderPassCreateInfo-attachment-00834 + if (AttchRef.AttachmentIndex >= Desc.AttachmentCount) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the attachment index (", AttchRef.AttachmentIndex, ") of depth-stencil attachment reference of subpass ", subpass, + " must be less than the number of attachments (", Desc.AttachmentCount, ")."); + } + } + } + + for (Uint32 prsv_attachment = 0; prsv_attachment < Subpass.PreserveAttachmentCount; ++prsv_attachment) + { + const auto PrsvAttachment = Subpass.pPreserveAttachments[prsv_attachment]; + if (PrsvAttachment == ATTACHMENT_UNUSED) + { + // The attachment member of each element of pPreserveAttachments must not be VK_ATTACHMENT_UNUSED + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-attachment-00853 + LOG_RENDER_PASS_ERROR_AND_THROW("the attachment index of preserve attachment reference ", prsv_attachment, + " of subpass ", subpass, " is ATTACHMENT_UNUSED."); + } + + if (PrsvAttachment >= Desc.AttachmentCount) + { + LOG_RENDER_PASS_ERROR_AND_THROW("the attachment index (", PrsvAttachment, ") of preserve attachment reference ", prsv_attachment, + " of subpass ", subpass, " exceeds the number of attachments (", Desc.AttachmentCount, ")."); + } + } + + if (Subpass.pResolveAttachments != nullptr) + { + for (Uint32 attchmnt = 0; attchmnt < Subpass.RenderTargetAttachmentCount; ++attchmnt) + { + const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[attchmnt]; + const auto& RslvAttachmentRef = Subpass.pResolveAttachments[attchmnt]; + if (RslvAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED && RTAttachmentRef.AttachmentIndex == ATTACHMENT_UNUSED) + { + // If pResolveAttachments is not NULL, for each resolve attachment that is not VK_ATTACHMENT_UNUSED, + // the corresponding color attachment must not be VK_ATTACHMENT_UNUSED + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00847 + LOG_RENDER_PASS_ERROR_AND_THROW("pResolveAttachments of subpass ", subpass, " is not null and resolve attachment reference ", attchmnt, + " is not ATTACHMENT_UNUSED, but corresponding render target attachment reference is ATTACHMENT_UNUSED."); + } + + if (RslvAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED && Desc.pAttachments[RTAttachmentRef.AttachmentIndex].SampleCount == 1) + { + // If pResolveAttachments is not NULL, for each resolve attachment that is not VK_ATTACHMENT_UNUSED, + // the corresponding color attachment must not have a sample count of VK_SAMPLE_COUNT_1_BIT + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00848 + LOG_RENDER_PASS_ERROR_AND_THROW("Render target attachment at index ", RTAttachmentRef.AttachmentIndex, " referenced by", + " attachment reference ", attchmnt, " of subpass ", subpass, + " is used as the source of resolve operation, but its sample count is 1."); + } + + if (RslvAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED && Desc.pAttachments[RslvAttachmentRef.AttachmentIndex].SampleCount != 1) + { + // If pResolveAttachments is not NULL, each resolve attachment that is not VK_ATTACHMENT_UNUSED must + // have a sample count of VK_SAMPLE_COUNT_1_BIT + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00849 + LOG_RENDER_PASS_ERROR_AND_THROW("Resolve attachment at index ", RslvAttachmentRef.AttachmentIndex, " referenced by", + " attachment reference ", attchmnt, " of subpass ", subpass, + " must have sample count of 1."); + } + + if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED && RslvAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED && + Desc.pAttachments[RTAttachmentRef.AttachmentIndex].Format != Desc.pAttachments[RslvAttachmentRef.AttachmentIndex].Format) + { + // If pResolveAttachments is not NULL, each resolve attachment that is not VK_ATTACHMENT_UNUSED + // must have the same VkFormat as its corresponding color attachment. + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkSubpassDescription-pResolveAttachments-00850 + LOG_RENDER_PASS_ERROR_AND_THROW("The format (", + GetTextureFormatAttribs(Desc.pAttachments[RTAttachmentRef.AttachmentIndex].Format).Name, + ") of render target attachment at index ", RTAttachmentRef.AttachmentIndex, + " referenced by attachment reference ", attchmnt, " of subpass ", subpass, + " does not match the format (", + GetTextureFormatAttribs(Desc.pAttachments[RslvAttachmentRef.AttachmentIndex].Format).Name, + ") of the corresponding resolve attachment at index ", + RslvAttachmentRef.AttachmentIndex, "."); + } + } } } @@ -150,11 +292,11 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) if (Dependency.SrcStageMask == PIPELINE_STAGE_FLAG_UNDEFINED) { - LOG_RENDER_PASS_ERROR_AND_THROW("the source stage mask of subpass dependency ", i, " is undefined"); + LOG_RENDER_PASS_ERROR_AND_THROW("the source stage mask of subpass dependency ", i, " is undefined."); } if (Dependency.DstStageMask == PIPELINE_STAGE_FLAG_UNDEFINED) { - LOG_RENDER_PASS_ERROR_AND_THROW("the destination stage mask of subpass dependency ", i, " is undefined"); + LOG_RENDER_PASS_ERROR_AND_THROW("the destination stage mask of subpass dependency ", i, " is undefined."); } } } -- cgit v1.2.3 From fc13c4af335cd91a8901d245b775e519cff03eb7 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 2 Aug 2020 22:08:11 -0700 Subject: More framebuffer validation --- .../GraphicsEngine/include/FramebufferBase.hpp | 15 ++++++ Graphics/GraphicsEngine/src/FramebufferBase.cpp | 62 +++++++++++++++++----- 2 files changed, 63 insertions(+), 14 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/FramebufferBase.hpp b/Graphics/GraphicsEngine/include/FramebufferBase.hpp index 42e31c8f..597639fc 100644 --- a/Graphics/GraphicsEngine/include/FramebufferBase.hpp +++ b/Graphics/GraphicsEngine/include/FramebufferBase.hpp @@ -74,6 +74,9 @@ public: this->m_Desc.ppAttachments = m_ppAttachments; for (Uint32 i = 0; i < this->m_Desc.AttachmentCount; ++i) { + if (Desc.ppAttachments[i] == nullptr) + continue; + m_ppAttachments[i] = Desc.ppAttachments[i]; m_ppAttachments[i]->AddRef(); @@ -92,6 +95,18 @@ public: } } } + + // It is legal for a subpass to use no color or depth/stencil attachments, either because it has no attachment + // references or because all of them are VK_ATTACHMENT_UNUSED. This kind of subpass can use shader side effects + // such as image stores and atomics to produce an output. In this case, the subpass continues to use the width, + // height, and layers of the framebuffer to define the dimensions of the rendering area. + if (this->m_Desc.Width == 0) + LOG_ERROR_AND_THROW("The framebuffer width is zero and can't be automatically determined as there are no non-null attachments"); + if (this->m_Desc.Height == 0) + LOG_ERROR_AND_THROW("The framebuffer height is zero and can't be automatically determined as there are no non-null attachments"); + if (this->m_Desc.NumArraySlices == 0) + LOG_ERROR_AND_THROW("The framebuffer array slice count is zero and can't be automatically determined as there are no non-null attachments"); + Desc.pRenderPass->AddRef(); } diff --git a/Graphics/GraphicsEngine/src/FramebufferBase.cpp b/Graphics/GraphicsEngine/src/FramebufferBase.cpp index fa1f8d10..75c00d71 100644 --- a/Graphics/GraphicsEngine/src/FramebufferBase.cpp +++ b/Graphics/GraphicsEngine/src/FramebufferBase.cpp @@ -41,27 +41,29 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) LOG_FRAMEBUFFER_ERROR_AND_THROW("render pass must not be null."); } - for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) + if (Desc.AttachmentCount != 0 && Desc.ppAttachments == nullptr) { - if (Desc.ppAttachments[i] == nullptr) - { - // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, and attachmentCount is not 0, - // pAttachments must be a valid pointer to an array of attachmentCount valid VkImageView handles. - // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-flags-02778 - LOG_FRAMEBUFFER_ERROR_AND_THROW("framebuffer attachment ", i, " is null."); - } + // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, and attachmentCount is not 0, + // pAttachments must be a valid pointer to an array of attachmentCount valid VkImageView handles. + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-flags-02778 + LOG_FRAMEBUFFER_ERROR_AND_THROW("attachment count is not zero, but ppAttachments is null."); } const auto& RPDesc = Desc.pRenderPass->GetDesc(); - if (Desc.AttachmentCount < RPDesc.AttachmentCount) + if (Desc.AttachmentCount != RPDesc.AttachmentCount) { + // AttachmentCount must be equal to the attachment count specified in renderPass. + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-attachmentCount-00876 LOG_FRAMEBUFFER_ERROR_AND_THROW("the number of framebuffer attachments (", Desc.AttachmentCount, - ") is smaller than the number of attachments (", RPDesc.AttachmentCount, + ") must be equal to the number of attachments (", RPDesc.AttachmentCount, ") in the render pass '", RPDesc.Name, "'."); } for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i) { + if (Desc.ppAttachments[i] == nullptr) + continue; + const auto& AttDesc = RPDesc.pAttachments[i]; const auto& ViewDesc = Desc.ppAttachments[i]->GetDesc(); const auto& TexDesc = Desc.ppAttachments[i]->GetTexture()->GetDesc(); @@ -102,6 +104,14 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) "Input attachment index (", AttchRef.AttachmentIndex, ") must be less than the attachment count (", Desc.AttachmentCount, ") as this is ensured by ValidateRenderPassDesc."); + if (Desc.ppAttachments[AttchRef.AttachmentIndex] == nullptr) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("attachment at index ", AttchRef.AttachmentIndex, + " is used as input attachment by subpass ", + i, " of render pass '", RPDesc.Name, + "', and must not be null."); + } + const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments that @@ -113,7 +123,7 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) LOG_FRAMEBUFFER_ERROR_AND_THROW("the attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, " is used as input attachment by subpass ", i, " of render pass '", RPDesc.Name, - "', but was not created with BIND_INPUT_ATTACHMENT bind flag"); + "', but was not created with BIND_INPUT_ATTACHMENT bind flag."); } } @@ -127,6 +137,14 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) "Render target attachment index (", AttchRef.AttachmentIndex, ") must be less than the attachment count (", Desc.AttachmentCount, ") as this is ensured by ValidateRenderPassDesc."); + if (Desc.ppAttachments[AttchRef.AttachmentIndex] == nullptr) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("attachment at index ", AttchRef.AttachmentIndex, + " is used as render target attachment by subpass ", + i, " of render pass '", RPDesc.Name, + "', and must not be null."); + } + const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments that is used @@ -138,7 +156,7 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) LOG_FRAMEBUFFER_ERROR_AND_THROW("the attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, " is used as render target attachment by subpass ", i, " of render pass '", RPDesc.Name, - "', but was not created with BIND_RENDER_TARGET bind flag"); + "', but was not created with BIND_RENDER_TARGET bind flag."); } } @@ -154,6 +172,14 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) "Resolve attachment index (", AttchRef.AttachmentIndex, ") must be less than the attachment count (", Desc.AttachmentCount, ") as this is ensured by ValidateRenderPassDesc."); + if (Desc.ppAttachments[AttchRef.AttachmentIndex] == nullptr) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("attachment at index ", AttchRef.AttachmentIndex, + " is used as resolve attachment by subpass ", + i, " of render pass '", RPDesc.Name, + "', and must not be null."); + } + const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments that is used @@ -165,7 +191,7 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) LOG_FRAMEBUFFER_ERROR_AND_THROW("the attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, " is used as resolve attachment by subpass ", i, " of render pass '", RPDesc.Name, - "', but was not created with BIND_RENDER_TARGET bind flag"); + "', but was not created with BIND_RENDER_TARGET bind flag."); } } } @@ -179,6 +205,14 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) "Depth-stencil attachment index (", AttchRef.AttachmentIndex, ") must be less than the attachment count (", Desc.AttachmentCount, ") as this is ensured by ValidateRenderPassDesc."); + if (Desc.ppAttachments[AttchRef.AttachmentIndex] == nullptr) + { + LOG_FRAMEBUFFER_ERROR_AND_THROW("attachment at index ", AttchRef.AttachmentIndex, + " is used as detph-stencil attachment by subpass ", + i, " of render pass '", RPDesc.Name, + "', and must not be null."); + } + const auto& TexDesc = Desc.ppAttachments[AttchRef.AttachmentIndex]->GetTexture()->GetDesc(); // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, each element of pAttachments that is @@ -190,7 +224,7 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) LOG_FRAMEBUFFER_ERROR_AND_THROW("the attachment '", TexDesc.Name, "' at index ", AttchRef.AttachmentIndex, " is used as detph-stencil attachment by subpass ", i, " of render pass '", RPDesc.Name, - "', but was not created with BIND_DEPTH_STENCIL bind flag"); + "', but was not created with BIND_DEPTH_STENCIL bind flag."); } } } -- cgit v1.2.3 From 68550189ed94ff35fbac03c9ec855fc2097b28f2 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 2 Aug 2020 22:21:25 -0700 Subject: Added another framebuffer validation check --- Graphics/GraphicsEngine/src/FramebufferBase.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/src/FramebufferBase.cpp b/Graphics/GraphicsEngine/src/FramebufferBase.cpp index 75c00d71..41943b09 100644 --- a/Graphics/GraphicsEngine/src/FramebufferBase.cpp +++ b/Graphics/GraphicsEngine/src/FramebufferBase.cpp @@ -49,6 +49,17 @@ void ValidateFramebufferDesc(const FramebufferDesc& Desc) LOG_FRAMEBUFFER_ERROR_AND_THROW("attachment count is not zero, but ppAttachments is null."); } + for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) + { + if (Desc.ppAttachments[i] == nullptr) + { + // If flags does not include VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, and attachmentCount is not 0, + // pAttachments must be a valid pointer to an array of attachmentCount valid VkImageView handles. + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkFramebufferCreateInfo-flags-02778 + LOG_FRAMEBUFFER_ERROR_AND_THROW("framebuffer attachment ", i, " is null."); + } + } + const auto& RPDesc = Desc.pRenderPass->GetDesc(); if (Desc.AttachmentCount != RPDesc.AttachmentCount) { -- cgit v1.2.3 From b10979c67bf9a2c49f46e01873a2cac1e44bc97a Mon Sep 17 00:00:00 2001 From: assiduous Date: Sun, 2 Aug 2020 22:38:31 -0700 Subject: Few more updated to render pass desc validation --- Graphics/GraphicsEngine/src/RenderPassBase.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/src/RenderPassBase.cpp b/Graphics/GraphicsEngine/src/RenderPassBase.cpp index 683d86aa..a0548e4d 100644 --- a/Graphics/GraphicsEngine/src/RenderPassBase.cpp +++ b/Graphics/GraphicsEngine/src/RenderPassBase.cpp @@ -87,7 +87,9 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.InitialState != RESOURCE_STATE_UNORDERED_ACCESS && Attachment.InitialState != RESOURCE_STATE_SHADER_RESOURCE && Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && - Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE) + Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE && + Attachment.InitialState != RESOURCE_STATE_COPY_DEST && + Attachment.InitialState != RESOURCE_STATE_COPY_SOURCE) { LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid."); } @@ -97,7 +99,9 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.FinalState != RESOURCE_STATE_UNORDERED_ACCESS && Attachment.FinalState != RESOURCE_STATE_SHADER_RESOURCE && Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && - Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE) + Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE && + Attachment.FinalState != RESOURCE_STATE_COPY_DEST && + Attachment.FinalState != RESOURCE_STATE_COPY_SOURCE) { LOG_RENDER_PASS_ERROR_AND_THROW("the final state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid."); } @@ -108,7 +112,9 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.InitialState != RESOURCE_STATE_UNORDERED_ACCESS && Attachment.InitialState != RESOURCE_STATE_SHADER_RESOURCE && Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && - Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE) + Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE && + Attachment.InitialState != RESOURCE_STATE_COPY_SOURCE && + Attachment.InitialState != RESOURCE_STATE_PRESENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of color attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid."); } @@ -117,7 +123,9 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.FinalState != RESOURCE_STATE_UNORDERED_ACCESS && Attachment.FinalState != RESOURCE_STATE_SHADER_RESOURCE && Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && - Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE) + Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE && + Attachment.FinalState != RESOURCE_STATE_COPY_SOURCE && + Attachment.FinalState != RESOURCE_STATE_PRESENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the final state of color attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid."); } -- cgit v1.2.3 From 706b34a2e4dbd372dc4255a9b6f021b9c7ee34ac Mon Sep 17 00:00:00 2001 From: assiduous Date: Mon, 3 Aug 2020 13:46:43 -0700 Subject: Few fixes to render passes --- .../GraphicsEngine/include/DeviceContextBase.hpp | 26 +++++++++++++++ Graphics/GraphicsEngine/interface/GraphicsTypes.h | 39 ++++++++++++---------- 2 files changed, 47 insertions(+), 18 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 68f9ec4e..9e478675 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -856,6 +856,32 @@ inline void DeviceContextBase::BeginRenderP VERIFY(m_pActiveRenderPass == nullptr, "Attempting to begin render pass while another render pass ('", m_pActiveRenderPass->GetDesc().Name, "') is active."); VERIFY(Attribs.pRenderPass != nullptr, "Render pass must not be null"); VERIFY(Attribs.pFramebuffer != nullptr, "Framebuffer must not be null"); +#ifdef DILIGENT_DEBUG + { + const auto& RPDesc = Attribs.pRenderPass->GetDesc(); + + Uint32 NumRequiredClearValues = 0; + for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i) + { + const auto& Attchmnt = RPDesc.pAttachments[i]; + if (Attchmnt.LoadOp == ATTACHMENT_LOAD_OP_CLEAR) + NumRequiredClearValues = i + 1; + + const auto& FmtAttribs = GetTextureFormatAttribs(Attchmnt.Format); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + { + if (Attchmnt.StencilLoadOp == ATTACHMENT_LOAD_OP_CLEAR) + NumRequiredClearValues = i + 1; + } + } + VERIFY(Attribs.ClearValueCount >= NumRequiredClearValues, + "Begin render pass operation requiers at least ", NumRequiredClearValues, + " clear values, but only ", Attribs.ClearValueCount, " are given."); + VERIFY(Attribs.ClearValueCount == 0 || Attribs.pClearValues != nullptr, + "pClearValues must not be null when ClearValueCount is not zero"); + } +#endif + ResetRenderTargets(); m_pActiveRenderPass = ValidatedCast(Attribs.pRenderPass); diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 796d7449..3c0ca99a 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -2152,57 +2152,60 @@ DEFINE_FLAG_ENUM_OPERATORS(ACCESS_FLAGS) DILIGENT_TYPED_ENUM(RESOURCE_STATE, Uint32) { /// The resource state is not known to the engine and is managed by the application - RESOURCE_STATE_UNKNOWN = 0x0000, + RESOURCE_STATE_UNKNOWN = 0x00000, /// The resource state is known to the engine, but is undefined. A resource is typically in an undefined state right after initialization. - RESOURCE_STATE_UNDEFINED = 0x0001, + RESOURCE_STATE_UNDEFINED = 0x00001, /// The resource is accessed as vertex buffer - RESOURCE_STATE_VERTEX_BUFFER = 0x0002, + RESOURCE_STATE_VERTEX_BUFFER = 0x00002, /// The resource is accessed as constant (uniform) buffer - RESOURCE_STATE_CONSTANT_BUFFER = 0x0004, + RESOURCE_STATE_CONSTANT_BUFFER = 0x00004, /// The resource is accessed as index buffer - RESOURCE_STATE_INDEX_BUFFER = 0x0008, + RESOURCE_STATE_INDEX_BUFFER = 0x00008, /// The resource is accessed as render target - RESOURCE_STATE_RENDER_TARGET = 0x0010, + RESOURCE_STATE_RENDER_TARGET = 0x00010, /// The resource is used for unordered access - RESOURCE_STATE_UNORDERED_ACCESS = 0x0020, + RESOURCE_STATE_UNORDERED_ACCESS = 0x00020, /// The resource is used in a writable depth-stencil view or in clear operation - RESOURCE_STATE_DEPTH_WRITE = 0x0040, + RESOURCE_STATE_DEPTH_WRITE = 0x00040, /// The resource is used in a read-only depth-stencil view - RESOURCE_STATE_DEPTH_READ = 0x0080, + RESOURCE_STATE_DEPTH_READ = 0x00080, /// The resource is accessed from a shader - RESOURCE_STATE_SHADER_RESOURCE = 0x0100, + RESOURCE_STATE_SHADER_RESOURCE = 0x00100, /// The resource is used as the destination for stream output - RESOURCE_STATE_STREAM_OUT = 0x0200, + RESOURCE_STATE_STREAM_OUT = 0x00200, /// The resource is used as indirect draw/dispatch arguments buffer - RESOURCE_STATE_INDIRECT_ARGUMENT = 0x0400, + RESOURCE_STATE_INDIRECT_ARGUMENT = 0x00400, /// The resource is used as the destination in a copy operation - RESOURCE_STATE_COPY_DEST = 0x0800, + RESOURCE_STATE_COPY_DEST = 0x00800, /// The resource is used as the source in a copy operation - RESOURCE_STATE_COPY_SOURCE = 0x1000, + RESOURCE_STATE_COPY_SOURCE = 0x01000, /// The resource is used as the destination in a resolve operation - RESOURCE_STATE_RESOLVE_DEST = 0x2000, + RESOURCE_STATE_RESOLVE_DEST = 0x02000, /// The resource is used as the source in a resolve operation - RESOURCE_STATE_RESOLVE_SOURCE = 0x4000, + RESOURCE_STATE_RESOLVE_SOURCE = 0x04000, + + /// The resource is used as input attachment in a render pass subpass + RESOURCE_STATE_INPUT_ATTACHMENT = 0x08000, /// The resource is used for present - RESOURCE_STATE_PRESENT = 0x8000, + RESOURCE_STATE_PRESENT = 0x10000, - RESOURCE_STATE_MAX_BIT = 0x8000, + RESOURCE_STATE_MAX_BIT = 0x10000, RESOURCE_STATE_GENERIC_READ = RESOURCE_STATE_VERTEX_BUFFER | RESOURCE_STATE_CONSTANT_BUFFER | -- cgit v1.2.3 From f1d382b62d674616de7979f5f3d78f74ea31f0e0 Mon Sep 17 00:00:00 2001 From: assiduous Date: Mon, 3 Aug 2020 14:00:00 -0700 Subject: Added comparison opertors to SubpassDependencyDesc struct --- Graphics/GraphicsEngine/interface/RenderPass.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/RenderPass.h b/Graphics/GraphicsEngine/interface/RenderPass.h index e9f3027d..3f822e0c 100644 --- a/Graphics/GraphicsEngine/interface/RenderPass.h +++ b/Graphics/GraphicsEngine/interface/RenderPass.h @@ -311,6 +311,29 @@ struct SubpassDependencyDesc /// A bitmask of ACCESS_FLAGS specifying a destination access mask. ACCESS_FLAGS DstAccessMask DEFAULT_INITIALIZER(ACCESS_FLAG_NONE); + +#if DILIGENT_CPP_INTERFACE + /// Tests if two structures are equivalent + + /// \param [in] RHS - reference to the structure to perform comparison with + /// \return + /// - True if all members of the two structures are equal. + /// - False otherwise + bool operator == (const SubpassDependencyDesc& RHS) const + { + return SrcSubpass == RHS.SrcSubpass && + DstSubpass == RHS.DstSubpass && + SrcStageMask == RHS.SrcStageMask && + DstStageMask == RHS.DstStageMask && + SrcAccessMask == RHS.SrcAccessMask && + DstAccessMask == RHS.DstAccessMask; + } + + bool operator != (const SubpassDependencyDesc& RHS) const + { + return !(*this == RHS); + } +#endif }; typedef struct SubpassDependencyDesc SubpassDependencyDesc; -- cgit v1.2.3 From 86bd2d7175d3e2d0f5c1c313a802a22c9f95b4ea Mon Sep 17 00:00:00 2001 From: assiduous Date: Tue, 4 Aug 2020 14:05:42 -0700 Subject: Implemented input attachments in Vulkan backend; added test --- Graphics/GraphicsEngine/include/TextureBase.hpp | 3 +++ Graphics/GraphicsEngine/interface/GraphicsTypes.h | 15 +++++++++------ Graphics/GraphicsEngine/interface/Shader.h | 11 +++++++++-- Graphics/GraphicsEngine/src/RenderPassBase.cpp | 8 ++++++-- 4 files changed, 27 insertions(+), 10 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/TextureBase.hpp b/Graphics/GraphicsEngine/include/TextureBase.hpp index 38414be2..fd0256b6 100644 --- a/Graphics/GraphicsEngine/include/TextureBase.hpp +++ b/Graphics/GraphicsEngine/include/TextureBase.hpp @@ -123,6 +123,9 @@ public: ") correspond to one of ", pDevice->GetCommandQueueCount(), " available device command queues"); this->m_Desc.CommandQueueMask &= DeviceQueuesMask; + if ((this->m_Desc.BindFlags & BIND_INPUT_ATTACHMENT) != 0) + this->m_Desc.BindFlags |= BIND_SHADER_RESOURCE; + // Validate correctness of texture description ValidateTextureDesc(this->m_Desc); } diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 3c0ca99a..727888d9 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -1644,6 +1644,7 @@ struct VulkanDescriptorPoolSize Uint32 NumStorageBufferDescriptors DEFAULT_INITIALIZER(0); Uint32 NumUniformTexelBufferDescriptors DEFAULT_INITIALIZER(0); Uint32 NumStorageTexelBufferDescriptors DEFAULT_INITIALIZER(0); + Uint32 NumInputAttachmentDescriptors DEFAULT_INITIALIZER(0); #if DILIGENT_CPP_INTERFACE VulkanDescriptorPoolSize()noexcept {} @@ -1656,7 +1657,8 @@ struct VulkanDescriptorPoolSize Uint32 _NumUniformBufferDescriptors, Uint32 _NumStorageBufferDescriptors, Uint32 _NumUniformTexelBufferDescriptors, - Uint32 _NumStorageTexelBufferDescriptors)noexcept : + Uint32 _NumStorageTexelBufferDescriptors, + Uint32 _NumInputAttachmentDescriptors)noexcept : MaxDescriptorSets {_MaxDescriptorSets }, NumSeparateSamplerDescriptors {_NumSeparateSamplerDescriptors }, NumCombinedSamplerDescriptors {_NumCombinedSamplerDescriptors }, @@ -1665,7 +1667,8 @@ struct VulkanDescriptorPoolSize NumUniformBufferDescriptors {_NumUniformBufferDescriptors }, NumStorageBufferDescriptors {_NumStorageBufferDescriptors }, NumUniformTexelBufferDescriptors{_NumUniformTexelBufferDescriptors}, - NumStorageTexelBufferDescriptors{_NumStorageTexelBufferDescriptors} + NumStorageTexelBufferDescriptors{_NumStorageTexelBufferDescriptors}, + NumInputAttachmentDescriptors {_NumInputAttachmentDescriptors } { // On clang aggregate initialization fails to compile if // structure members have default initializers @@ -1700,8 +1703,8 @@ struct EngineVkCreateInfo DILIGENT_DERIVE(EngineCreateInfo) /// the engine creates another one. VulkanDescriptorPoolSize MainDescriptorPoolSize #if DILIGENT_CPP_INTERFACE - //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB - {8192, 1024, 8192, 8192, 1024, 4096, 4096, 1024, 1024} + //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB InptAtt + {8192, 1024, 8192, 8192, 1024, 4096, 4096, 1024, 1024, 256} #endif ; @@ -1712,8 +1715,8 @@ struct EngineVkCreateInfo DILIGENT_DERIVE(EngineCreateInfo) VulkanDescriptorPoolSize DynamicDescriptorPoolSize #if DILIGENT_CPP_INTERFACE - //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB - {2048, 256, 2048, 2048, 256, 1024, 1024, 256, 256} + //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB InptAtt + {2048, 256, 2048, 2048, 256, 1024, 1024, 256, 256, 64} #endif ; diff --git a/Graphics/GraphicsEngine/interface/Shader.h b/Graphics/GraphicsEngine/interface/Shader.h index eacd35f0..f3df92d3 100644 --- a/Graphics/GraphicsEngine/interface/Shader.h +++ b/Graphics/GraphicsEngine/interface/Shader.h @@ -283,8 +283,10 @@ struct ShaderCreateInfo }; typedef struct ShaderCreateInfo ShaderCreateInfo; +// clang-format off /// Describes shader resource type -DILIGENT_TYPED_ENUM(SHADER_RESOURCE_TYPE, Uint8){ +DILIGENT_TYPED_ENUM(SHADER_RESOURCE_TYPE, Uint8) +{ /// Shader resource type is unknown SHADER_RESOURCE_TYPE_UNKNOWN = 0, @@ -304,7 +306,12 @@ DILIGENT_TYPED_ENUM(SHADER_RESOURCE_TYPE, Uint8){ SHADER_RESOURCE_TYPE_BUFFER_UAV, /// Sampler (separate sampler) - SHADER_RESOURCE_TYPE_SAMPLER}; + SHADER_RESOURCE_TYPE_SAMPLER, + + /// Input attachment in a render pass + SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT +}; +// clang-format on /// Shader resource description struct ShaderResourceDesc diff --git a/Graphics/GraphicsEngine/src/RenderPassBase.cpp b/Graphics/GraphicsEngine/src/RenderPassBase.cpp index a0548e4d..b6b38dd0 100644 --- a/Graphics/GraphicsEngine/src/RenderPassBase.cpp +++ b/Graphics/GraphicsEngine/src/RenderPassBase.cpp @@ -89,7 +89,8 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE && Attachment.InitialState != RESOURCE_STATE_COPY_DEST && - Attachment.InitialState != RESOURCE_STATE_COPY_SOURCE) + Attachment.InitialState != RESOURCE_STATE_COPY_SOURCE && + Attachment.InitialState != RESOURCE_STATE_INPUT_ATTACHMENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid."); } @@ -101,7 +102,8 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE && Attachment.FinalState != RESOURCE_STATE_COPY_DEST && - Attachment.FinalState != RESOURCE_STATE_COPY_SOURCE) + Attachment.FinalState != RESOURCE_STATE_COPY_SOURCE && + Attachment.FinalState != RESOURCE_STATE_INPUT_ATTACHMENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the final state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid."); } @@ -114,6 +116,7 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE && Attachment.InitialState != RESOURCE_STATE_COPY_SOURCE && + Attachment.InitialState != RESOURCE_STATE_INPUT_ATTACHMENT && Attachment.InitialState != RESOURCE_STATE_PRESENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of color attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid."); @@ -125,6 +128,7 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE && Attachment.FinalState != RESOURCE_STATE_COPY_SOURCE && + Attachment.FinalState != RESOURCE_STATE_INPUT_ATTACHMENT && Attachment.FinalState != RESOURCE_STATE_PRESENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the final state of color attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid."); -- cgit v1.2.3 From 3ce2d21558fa0568ab7d332a5c300a661e444f44 Mon Sep 17 00:00:00 2001 From: assiduous Date: Tue, 4 Aug 2020 19:21:19 -0700 Subject: Added more renderpass-related checks --- .../GraphicsEngine/include/DeviceContextBase.hpp | 65 ++++++++++++++++------ 1 file changed, 47 insertions(+), 18 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 9e478675..c932d3b4 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -438,6 +438,9 @@ inline bool DeviceContextBase:: template inline void DeviceContextBase::InvalidateState() { + if (m_pActiveRenderPass != nullptr) + LOG_ERROR_MESSAGE("Invalidating context inside an active render pass. Call EndRenderPass() to finish the pass."); + DeviceContextBase::ClearStateCache(); } @@ -778,7 +781,7 @@ bool DeviceContextBase::CheckIfBoundAsDepth template bool DeviceContextBase::UnbindTextureFromFramebuffer(TextureImplType* pTexture, bool bShowMessage) { - VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside render pass"); + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass."); if (pTexture == nullptr) return false; @@ -884,18 +887,18 @@ inline void DeviceContextBase::BeginRenderP ResetRenderTargets(); - m_pActiveRenderPass = ValidatedCast(Attribs.pRenderPass); - m_pBoundFramebuffer = ValidatedCast(Attribs.pFramebuffer); - m_SubpassIndex = 0; + auto* pNewRenderPass = ValidatedCast(Attribs.pRenderPass); + auto* pNewFramebuffer = ValidatedCast(Attribs.pFramebuffer); + m_SubpassIndex = 0; - const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); + const auto& FBDesc = pNewFramebuffer->GetDesc(); m_FramebufferWidth = FBDesc.Width; m_FramebufferHeight = FBDesc.Height; m_FramebufferSlices = FBDesc.NumArraySlices; if (Attribs.StateTransitionMode != RESOURCE_STATE_TRANSITION_MODE_NONE) { - const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + const auto& RPDesc = pNewRenderPass->GetDesc(); VERIFY(RPDesc.AttachmentCount <= FBDesc.AttachmentCount, "The number of attachments (", FBDesc.AttachmentCount, ") in currently bound framebuffer is smaller than the number of attachments in the render pass (", RPDesc.AttachmentCount, ")"); @@ -918,12 +921,17 @@ inline void DeviceContextBase::BeginRenderP } } } + + m_pActiveRenderPass = pNewRenderPass; + m_pBoundFramebuffer = pNewFramebuffer; + m_SubpassIndex = 0; } template inline void DeviceContextBase::NextSubpass() { VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass"); + VERIFY(m_SubpassIndex + 1 < m_pActiveRenderPass->GetDesc().SubpassCount, "The render pass has reached the final subpass already"); ++m_SubpassIndex; } @@ -932,6 +940,9 @@ inline void DeviceContextBase::EndRenderPas { VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass"); VERIFY(m_pBoundFramebuffer != nullptr, "There is no active framebuffer"); + VERIFY(m_pActiveRenderPass->GetDesc().SubpassCount == m_SubpassIndex + 1, + "Ending render pass at subpass ", m_SubpassIndex, " before reaching the final subpass"); + if (UpdateResourceStates) { const auto& RPDesc = m_pActiveRenderPass->GetDesc(); @@ -1247,7 +1258,7 @@ inline void DeviceContextBase:: UpdateTexture(ITexture* pTexture, Uint32 MipLevel, Uint32 Slice, const Box& DstBox, const TextureSubResData& SubresData, RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode, RESOURCE_STATE_TRANSITION_MODE TextureTransitionMode) { VERIFY(pTexture != nullptr, "pTexture must not be null"); - VERIFY(m_pActiveRenderPass == nullptr, "UpdateTexture must be used outside of render pass."); + VERIFY(m_pActiveRenderPass == nullptr, "UpdateTexture command must be used outside of render pass."); ValidateUpdateTextureParams(pTexture->GetDesc(), MipLevel, Slice, DstBox, SubresData); } @@ -1257,7 +1268,7 @@ inline void DeviceContextBase:: { VERIFY(CopyAttribs.pSrcTexture, "Src texture must not be null"); VERIFY(CopyAttribs.pDstTexture, "Dst texture must not be null"); - VERIFY(m_pActiveRenderPass == nullptr, "CopyTexture must be used outside of render pass."); + VERIFY(m_pActiveRenderPass == nullptr, "CopyTexture command must be used outside of render pass."); ValidateCopyTextureParams(CopyAttribs); } @@ -1289,7 +1300,7 @@ inline void DeviceContextBase:: GenerateMips(ITextureView* pTexView) { VERIFY(pTexView != nullptr, "pTexView must not be null"); - VERIFY(m_pActiveRenderPass == nullptr, "GenerateMips must be used outside of render pass."); + VERIFY(m_pActiveRenderPass == nullptr, "GenerateMips command must be used outside of render pass."); #ifdef DILIGENT_DEVELOPMENT { const auto& ViewDesc = pTexView->GetDesc(); @@ -1346,7 +1357,7 @@ void DeviceContextBase:: DEV_CHECK_ERR(!ResolveFmtAttribs.IsTypeless, "Format of a resolve operation must not be typeless when one of the texture formats is typeless"); } - VERIFY(m_pActiveRenderPass == nullptr, "ResolveTextureSubresource must be used outside of render pass."); + VERIFY(m_pActiveRenderPass == nullptr, "ResolveTextureSubresource command must be used outside of render pass."); #endif } @@ -1448,10 +1459,6 @@ inline bool DeviceContextBase:: pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); return false; } - - VERIFY(!(m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION), - "Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " - "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); } else { @@ -1459,6 +1466,13 @@ inline bool DeviceContextBase:: return false; } + if (m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + LOG_ERROR_MESSAGE("Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); + return false; + } + return true; } @@ -1503,10 +1517,6 @@ inline bool DeviceContextBase:: pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); return false; } - - VERIFY(!(m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION), - "Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " - "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); } else { @@ -1514,6 +1524,13 @@ inline bool DeviceContextBase:: return false; } + if (m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + LOG_ERROR_MESSAGE("Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); + return false; + } + return true; } @@ -1588,6 +1605,12 @@ inline bool DeviceContextBase:: return false; } + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("DispatchCompute command must be performed outside of render pass"); + return false; + } + if (Attribs.ThreadGroupCountX == 0) LOG_WARNING_MESSAGE("DispatchCompute command arguments are invalid: ThreadGroupCountX is zero."); @@ -1617,6 +1640,12 @@ inline bool DeviceContextBase:: return false; } + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("DispatchComputeIndirect command must be performed outside of render pass"); + return false; + } + if (pAttribsBuffer != nullptr) { if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0) -- cgit v1.2.3 From 6e663135a6d194f5ed8b41f112c6d5a2c98b080d Mon Sep 17 00:00:00 2001 From: assiduous Date: Thu, 6 Aug 2020 11:30:15 -0700 Subject: Added few debug checks --- Graphics/GraphicsEngine/include/DeviceContextBase.hpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index c932d3b4..4df47bfc 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -750,6 +750,9 @@ inline void DeviceContextBase::ClearStateCa m_NumScissorRects = 0; ResetRenderTargets(); + + m_pActiveRenderPass = nullptr; + m_pBoundFramebuffer = nullptr; } template -- cgit v1.2.3 From a72d485f4b157d5c8fb488bc2afb3b9278e465b7 Mon Sep 17 00:00:00 2001 From: assiduous Date: Thu, 6 Aug 2020 20:41:08 -0700 Subject: Treating subpass render target and depth stencil attachments as current RT and DS buffers --- .../GraphicsEngine/include/DeviceContextBase.hpp | 176 +++++++++++---------- .../GraphicsEngine/include/PipelineStateBase.hpp | 30 +++- 2 files changed, 125 insertions(+), 81 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 4df47bfc..3e1a5779 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -122,10 +122,6 @@ public: /// Caches the scissor rects inline void SetScissorRects(Uint32 NumRects, const Rect* pRects, Uint32& RTWidth, Uint32& RTHeight); - /// Caches the render target and depth stencil views. Returns true if any view is different - /// from the cached value and false otherwise. - inline bool SetRenderTargets(Uint32 NumRenderTargets, ITextureView* ppRenderTargets[], ITextureView* pDepthStencil); - virtual void DILIGENT_CALL_TYPE BeginRenderPass(const BeginRenderPassAttribs& Attribs) override = 0; virtual void DILIGENT_CALL_TYPE NextSubpass() override = 0; @@ -210,6 +206,13 @@ public: bool UnbindTextureFromFramebuffer(TextureImplType* pTexture, bool bShowMessage); protected: + /// Caches the render target and depth stencil views. Returns true if any view is different + /// from the cached value and false otherwise. + inline bool SetRenderTargets(Uint32 NumRenderTargets, ITextureView* ppRenderTargets[], ITextureView* pDepthStencil); + + /// Initializes render targets for the current subpass + inline bool SetSubpassRenderTargets(); + inline bool SetBlendFactors(const float* BlendFactors, int Dummy); inline bool SetStencilRef(Uint32 StencilRef, int Dummy); @@ -581,8 +584,6 @@ inline bool DeviceContextBase:: return false; } - VERIFY(m_pActiveRenderPass == nullptr, "Setting render targets inside the render pass is not allowed. The render pass must be ended first."); - bool bBindRenderTargets = false; m_FramebufferWidth = 0; m_FramebufferHeight = 0; @@ -683,6 +684,49 @@ inline bool DeviceContextBase:: return bBindRenderTargets; } +template +inline bool DeviceContextBase::SetSubpassRenderTargets() +{ + VERIFY_EXPR(m_pBoundFramebuffer); + VERIFY_EXPR(m_pActiveRenderPass); + + const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); + VERIFY_EXPR(m_SubpassIndex < RPDesc.SubpassCount); + const auto& Subpass = RPDesc.pSubpasses[m_SubpassIndex]; + + ITextureView* ppRTVs[MAX_RENDER_TARGETS] = {}; + ITextureView* pDSV = nullptr; + for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt) + { + const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt]; + if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); + ppRTVs[rt] = FBDesc.ppAttachments[RTAttachmentRef.AttachmentIndex]; + } + } + + if (Subpass.pDepthStencilAttachment != nullptr) + { + const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment; + if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); + pDSV = FBDesc.ppAttachments[DSAttachmentRef.AttachmentIndex]; + } + } + bool BindRenderTargets = SetRenderTargets(Subpass.RenderTargetAttachmentCount, ppRTVs, pDSV); + + // Use framebuffer dimensions (override what was set by SetRenderTargets) + m_FramebufferWidth = FBDesc.Width; + m_FramebufferHeight = FBDesc.Height; + m_FramebufferSlices = FBDesc.NumArraySlices; + + return BindRenderTargets; +} + + template inline void DeviceContextBase:: GetRenderTargets(Uint32& NumRenderTargets, ITextureView** ppRTVs, ITextureView** ppDSV) @@ -751,6 +795,7 @@ inline void DeviceContextBase::ClearStateCa ResetRenderTargets(); + VERIFY(!m_pActiveRenderPass, "Clearing state cache inside an active render pass"); m_pActiveRenderPass = nullptr; m_pBoundFramebuffer = nullptr; } @@ -838,8 +883,6 @@ bool DeviceContextBase::UnbindTextureFromFr template void DeviceContextBase::ResetRenderTargets() { - VERIFY(m_pActiveRenderPass == nullptr, "Resetting render targets inside the render pass may result in undefined behavior."); - for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) m_pBoundRenderTargets[rt].Release(); #ifdef DILIGENT_DEBUG @@ -854,12 +897,16 @@ void DeviceContextBase::ResetRenderTargets( m_FramebufferSlices = 0; m_pBoundDepthStencil.Release(); + + // Do not reset framebuffer here as there may potentially + // be a subpass without any render target attachments. } template inline void DeviceContextBase::BeginRenderPass(const BeginRenderPassAttribs& Attribs) { VERIFY(m_pActiveRenderPass == nullptr, "Attempting to begin render pass while another render pass ('", m_pActiveRenderPass->GetDesc().Name, "') is active."); + VERIFY(m_pBoundFramebuffer == nullptr, "Attempting to begin render pass while another framebuffer ('", m_pBoundFramebuffer->GetDesc().Name, "') is bound."); VERIFY(Attribs.pRenderPass != nullptr, "Render pass must not be null"); VERIFY(Attribs.pFramebuffer != nullptr, "Framebuffer must not be null"); #ifdef DILIGENT_DEBUG @@ -892,16 +939,10 @@ inline void DeviceContextBase::BeginRenderP auto* pNewRenderPass = ValidatedCast(Attribs.pRenderPass); auto* pNewFramebuffer = ValidatedCast(Attribs.pFramebuffer); - m_SubpassIndex = 0; - - const auto& FBDesc = pNewFramebuffer->GetDesc(); - m_FramebufferWidth = FBDesc.Width; - m_FramebufferHeight = FBDesc.Height; - m_FramebufferSlices = FBDesc.NumArraySlices; - if (Attribs.StateTransitionMode != RESOURCE_STATE_TRANSITION_MODE_NONE) { const auto& RPDesc = pNewRenderPass->GetDesc(); + const auto& FBDesc = pNewFramebuffer->GetDesc(); VERIFY(RPDesc.AttachmentCount <= FBDesc.AttachmentCount, "The number of attachments (", FBDesc.AttachmentCount, ") in currently bound framebuffer is smaller than the number of attachments in the render pass (", RPDesc.AttachmentCount, ")"); @@ -915,8 +956,11 @@ inline void DeviceContextBase::BeginRenderP auto RequiredState = RPDesc.pAttachments[i].InitialState; if (Attribs.StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { - StateTransitionDesc Barrier{pTex, RESOURCE_STATE_UNKNOWN, RequiredState, true}; - this->TransitionResourceStates(1, &Barrier); + if (pTex->IsInKnownState() && !pTex->CheckState(RequiredState)) + { + StateTransitionDesc Barrier{pTex, RESOURCE_STATE_UNKNOWN, RequiredState, true}; + this->TransitionResourceStates(1, &Barrier); + } } else if (Attribs.StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) { @@ -928,6 +972,7 @@ inline void DeviceContextBase::BeginRenderP m_pActiveRenderPass = pNewRenderPass; m_pBoundFramebuffer = pNewFramebuffer; m_SubpassIndex = 0; + SetSubpassRenderTargets(); } template @@ -936,6 +981,7 @@ inline void DeviceContextBase::NextSubpass( VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass"); VERIFY(m_SubpassIndex + 1 < m_pActiveRenderPass->GetDesc().SubpassCount, "The render pass has reached the final subpass already"); ++m_SubpassIndex; + SetSubpassRenderTargets(); } template @@ -964,6 +1010,7 @@ inline void DeviceContextBase::EndRenderPas m_pActiveRenderPass.Release(); m_pBoundFramebuffer.Release(); m_SubpassIndex = 0; + ResetRenderTargets(); } @@ -986,44 +1033,28 @@ inline bool DeviceContextBase::ClearDepthSt return false; } - if (m_pActiveRenderPass != nullptr) + if (pView != m_pBoundDepthStencil) { - bool AttachmentFound = false; - if (m_pBoundFramebuffer != nullptr) + if (m_pActiveRenderPass != nullptr) { - const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); - for (Uint32 i = 0; i < FBDesc.AttachmentCount && !AttachmentFound; ++i) - { - AttachmentFound = FBDesc.ppAttachments[i] == pView; - } + LOG_ERROR_MESSAGE("Depth-stencil view '", ViewDesc.Name, + "' is not bound as framebuffer attachment. ClearDepthStencil command inside a render pass " + "requires depth-stencil view to be bound as a framebuffer attachment."); + return false; } - - if (!AttachmentFound) + else if (m_pDevice->GetDeviceCaps().IsGLDevice()) { LOG_ERROR_MESSAGE("Depth-stencil view '", ViewDesc.Name, - "' is not bound as framebuffer attachment. ClearDepthStencil command inside a render pass " - "requires depth-stencil view be bound as framebuffer attachment."); + "' is not bound to the device context. ClearDepthStencil command requires " + "depth-stencil view be bound to the device contex in OpenGL backend"); return false; } - } - else - { - if (pView != m_pBoundDepthStencil) + else { - if (m_pDevice->GetDeviceCaps().IsGLDevice()) - { - LOG_ERROR_MESSAGE("Depth-stencil view '", ViewDesc.Name, - "' is not bound to the device context. ClearDepthStencil command requires " - "depth-stencil view be bound to the device contex in OpenGL backend"); - return false; - } - else - { - LOG_WARNING_MESSAGE("Depth-stencil view '", ViewDesc.Name, - "' is not bound to the device context. " - "ClearDepthStencil command is more efficient when depth-stencil " - "view is bound to the context. In OpenGL backend this is a requirement."); - } + LOG_WARNING_MESSAGE("Depth-stencil view '", ViewDesc.Name, + "' is not bound to the device context. " + "ClearDepthStencil command is more efficient when depth-stencil " + "view is bound to the context. In OpenGL backend this is a requirement."); } } } @@ -1051,48 +1082,33 @@ inline bool DeviceContextBase::ClearRenderT return false; } - if (m_pActiveRenderPass != nullptr) + bool RTFound = false; + for (Uint32 i = 0; i < m_NumBoundRenderTargets && !RTFound; ++i) { - bool AttachmentFound = false; - if (m_pBoundFramebuffer != nullptr) - { - const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); - for (Uint32 i = 0; i < FBDesc.AttachmentCount && !AttachmentFound; ++i) - { - AttachmentFound = FBDesc.ppAttachments[i] == pView; - } - } + RTFound = m_pBoundRenderTargets[i] == pView; + } - if (!AttachmentFound) + if (!RTFound) + { + if (m_pActiveRenderPass != nullptr) { LOG_ERROR_MESSAGE("Render target view '", ViewDesc.Name, "' is not bound as framebuffer attachment. ClearRenderTarget command inside a render pass " - "requires render target view be bound as framebuffer attachment."); + "requires render target view to be bound as a framebuffer attachment."); return false; } - } - else - { - bool RTFound = false; - for (Uint32 i = 0; i < m_NumBoundRenderTargets && !RTFound; ++i) + else if (m_pDevice->GetDeviceCaps().IsGLDevice()) { - RTFound = m_pBoundRenderTargets[i] == pView; + LOG_ERROR_MESSAGE("Render target view '", ViewDesc.Name, + "' is not bound to the device context. ClearRenderTarget command " + "requires render target view to be bound to the device contex in OpenGL backend"); + return false; } - if (!RTFound) + else { - if (m_pDevice->GetDeviceCaps().IsGLDevice()) - { - LOG_ERROR_MESSAGE("Render target view '", ViewDesc.Name, - "' is not bound to the device context. ClearRenderTarget command " - "requires render target view be bound to the device contex in OpenGL backend"); - return false; - } - else - { - LOG_WARNING_MESSAGE("Render target view '", ViewDesc.Name, - "' is not bound to the device context. ClearRenderTarget command is more efficient " - "if render target view is bound to the device context. In OpenGL backend this is a requirement."); - } + LOG_WARNING_MESSAGE("Render target view '", ViewDesc.Name, + "' is not bound to the device context. ClearRenderTarget command is more efficient " + "if render target view is bound to the device context. In OpenGL backend this is a requirement."); } } } @@ -1564,7 +1580,7 @@ inline void DeviceContextBase:: const auto& GraphicsPipeline = PSODesc.GraphicsPipeline; if (GraphicsPipeline.NumRenderTargets != m_NumBoundRenderTargets) { - LOG_WARNING_MESSAGE("Number of currently bound render targets (", m_NumBoundRenderTargets, + LOG_WARNING_MESSAGE("The number of currently bound render targets (", m_NumBoundRenderTargets, ") does not match the number of outputs specified by the PSO '", PSODesc.Name, "' (", Uint32{GraphicsPipeline.NumRenderTargets}, ")."); } diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index 109b6ce4..fbfbb100 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -201,6 +201,34 @@ public: } } + if (m_pRenderPass) + { + const auto& RPDesc = m_pRenderPass->GetDesc(); + VERIFY_EXPR(GraphicsPipeline.SubpassIndex < RPDesc.SubpassCount); + const auto& Subpass = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex]; + + this->m_Desc.GraphicsPipeline.NumRenderTargets = static_cast(Subpass.RenderTargetAttachmentCount); + for (Uint32 rt = 0; rt < Subpass.RenderTargetAttachmentCount; ++rt) + { + const auto& RTAttachmentRef = Subpass.pRenderTargetAttachments[rt]; + if (RTAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + VERIFY_EXPR(RTAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); + this->m_Desc.GraphicsPipeline.RTVFormats[rt] = RPDesc.pAttachments[RTAttachmentRef.AttachmentIndex].Format; + } + } + + if (Subpass.pDepthStencilAttachment != nullptr) + { + const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment; + if (DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + VERIFY_EXPR(DSAttachmentRef.AttachmentIndex < RPDesc.AttachmentCount); + this->m_Desc.GraphicsPipeline.DSVFormat = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex].Format; + } + } + } + const auto& InputLayout = PSODesc.GraphicsPipeline.InputLayout; LayoutElement* pLayoutElements = nullptr; if (InputLayout.NumElements > 0) @@ -407,7 +435,7 @@ private: { if (this->m_Desc.GraphicsPipeline.pRenderPass != nullptr) { - LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null"); + LOG_PSO_ERROR_AND_THROW("GraphicsPipeline.pRenderPass must be null for compute pipelines"); } } else -- cgit v1.2.3 From a34d7e04dc092e6c1bae4db120edbf5e6fc8c564 Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 7 Aug 2020 12:14:43 -0700 Subject: First implementation of render passes in d3d11 --- .../GraphicsEngine/include/DeviceContextBase.hpp | 4 +- Graphics/GraphicsEngine/include/RenderPassBase.hpp | 130 ++++++++++++++------- 2 files changed, 94 insertions(+), 40 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 3e1a5779..a340bbd2 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -935,6 +935,7 @@ inline void DeviceContextBase::BeginRenderP } #endif + // Reset current render targets (in Vulkan backend, this may end current render pass). ResetRenderTargets(); auto* pNewRenderPass = ValidatedCast(Attribs.pRenderPass); @@ -1003,7 +1004,8 @@ inline void DeviceContextBase::EndRenderPas if (auto* pView = FBDesc.ppAttachments[i]) { auto* pTex = ValidatedCast(pView->GetTexture()); - pTex->SetState(RPDesc.pAttachments[i].FinalState); + if (pTex->IsInKnownState()) + pTex->SetState(RPDesc.pAttachments[i].FinalState); } } } diff --git a/Graphics/GraphicsEngine/include/RenderPassBase.hpp b/Graphics/GraphicsEngine/include/RenderPassBase.hpp index 8099abb2..46432ea0 100644 --- a/Graphics/GraphicsEngine/include/RenderPassBase.hpp +++ b/Graphics/GraphicsEngine/include/RenderPassBase.hpp @@ -30,6 +30,7 @@ /// \file /// Implementation of the Diligent::RenderPassBase template class +#include #include "RenderPass.h" #include "DeviceObjectBase.hpp" #include "RenderDeviceBase.hpp" @@ -88,62 +89,88 @@ public: m_pPreserveAttachments = ALLOCATE(GetRawAllocator(), "Memory for subpass preserve attachments array", Uint32, TotalPreserveAttachmentsCount); } + m_AttachmentStates.resize(Desc.AttachmentCount * Desc.SubpassCount); + m_AttachmentFirstUseSubpass.resize(Desc.AttachmentCount, ATTACHMENT_UNUSED); + auto* pCurrAttachmentRef = m_pAttachmentReferences; auto* pCurrPreserveAttachment = m_pPreserveAttachments; - if (Desc.SubpassCount != 0) + VERIFY(Desc.SubpassCount != 0, "Render pass must have at least one subpass"); + auto* pSubpasses = + ALLOCATE(GetRawAllocator(), "Memory for SubpassDesc array", SubpassDesc, Desc.SubpassCount); + this->m_Desc.pSubpasses = pSubpasses; + for (Uint32 i = 0; i < Desc.SubpassCount; ++i) { - auto* pSubpasses = - ALLOCATE(GetRawAllocator(), "Memory for SubpassDesc array", SubpassDesc, Desc.SubpassCount); - this->m_Desc.pSubpasses = pSubpasses; - for (Uint32 i = 0; i < Desc.SubpassCount; ++i) + for (Uint32 att = 0; att < Desc.AttachmentCount; ++att) { - const auto& SrcSubpass = Desc.pSubpasses[i]; - auto& DstSubpass = pSubpasses[i]; + SetAttachmentState(i, att, i > 0 ? GetAttachmentState(i - 1, att) : Desc.pAttachments[i].InitialState); + } - DstSubpass = SrcSubpass; - if (SrcSubpass.InputAttachmentCount != 0) - { - DstSubpass.pInputAttachments = pCurrAttachmentRef; - for (Uint32 input_attachment = 0; input_attachment < SrcSubpass.InputAttachmentCount; ++input_attachment) - *(pCurrAttachmentRef++) = SrcSubpass.pInputAttachments[input_attachment]; - } - else - DstSubpass.pInputAttachments = nullptr; + const auto& SrcSubpass = Desc.pSubpasses[i]; + auto& DstSubpass = pSubpasses[i]; - if (SrcSubpass.RenderTargetAttachmentCount != 0) + auto UpdateAttachmentStateAndFirstUseSubpass = [this, i](const AttachmentReference& AttRef) // + { + if (AttRef.AttachmentIndex != ATTACHMENT_UNUSED) { - DstSubpass.pRenderTargetAttachments = pCurrAttachmentRef; - for (Uint32 rt_attachment = 0; rt_attachment < SrcSubpass.RenderTargetAttachmentCount; ++rt_attachment) - *(pCurrAttachmentRef++) = SrcSubpass.pRenderTargetAttachments[rt_attachment]; - if (DstSubpass.pResolveAttachments) - { - for (Uint32 rslv_attachment = 0; rslv_attachment < SrcSubpass.RenderTargetAttachmentCount; ++rslv_attachment) - *(pCurrAttachmentRef++) = SrcSubpass.pResolveAttachments[rslv_attachment]; - } - else - DstSubpass.pResolveAttachments = nullptr; + SetAttachmentState(i, AttRef.AttachmentIndex, AttRef.State); + if (m_AttachmentFirstUseSubpass[AttRef.AttachmentIndex] == ATTACHMENT_UNUSED) + m_AttachmentFirstUseSubpass[AttRef.AttachmentIndex] = i; } - else + }; + + DstSubpass = SrcSubpass; + if (SrcSubpass.InputAttachmentCount != 0) + { + DstSubpass.pInputAttachments = pCurrAttachmentRef; + for (Uint32 input_attachment = 0; input_attachment < SrcSubpass.InputAttachmentCount; ++input_attachment, ++pCurrAttachmentRef) { - DstSubpass.pRenderTargetAttachments = nullptr; - DstSubpass.pResolveAttachments = nullptr; + *pCurrAttachmentRef = SrcSubpass.pInputAttachments[input_attachment]; + UpdateAttachmentStateAndFirstUseSubpass(*pCurrAttachmentRef); } + } + else + DstSubpass.pInputAttachments = nullptr; - if (SrcSubpass.pDepthStencilAttachment != nullptr) + if (SrcSubpass.RenderTargetAttachmentCount != 0) + { + DstSubpass.pRenderTargetAttachments = pCurrAttachmentRef; + for (Uint32 rt_attachment = 0; rt_attachment < SrcSubpass.RenderTargetAttachmentCount; ++rt_attachment, ++pCurrAttachmentRef) { - DstSubpass.pDepthStencilAttachment = pCurrAttachmentRef; - *(pCurrAttachmentRef++) = *SrcSubpass.pDepthStencilAttachment; + *pCurrAttachmentRef = SrcSubpass.pRenderTargetAttachments[rt_attachment]; + UpdateAttachmentStateAndFirstUseSubpass(*pCurrAttachmentRef); } - if (SrcSubpass.PreserveAttachmentCount != 0) + if (DstSubpass.pResolveAttachments) { - DstSubpass.pPreserveAttachments = pCurrPreserveAttachment; - for (Uint32 prsv_attachment = 0; prsv_attachment < SrcSubpass.PreserveAttachmentCount; ++prsv_attachment) - *(pCurrPreserveAttachment++) = SrcSubpass.pPreserveAttachments[prsv_attachment]; + DstSubpass.pResolveAttachments = pCurrAttachmentRef; + for (Uint32 rslv_attachment = 0; rslv_attachment < SrcSubpass.RenderTargetAttachmentCount; ++rslv_attachment, ++pCurrAttachmentRef) + { + *pCurrAttachmentRef = SrcSubpass.pResolveAttachments[rslv_attachment]; + UpdateAttachmentStateAndFirstUseSubpass(*pCurrAttachmentRef); + } } - else - DstSubpass.pPreserveAttachments = nullptr; } + else + { + DstSubpass.pRenderTargetAttachments = nullptr; + DstSubpass.pResolveAttachments = nullptr; + } + + if (SrcSubpass.pDepthStencilAttachment != nullptr) + { + DstSubpass.pDepthStencilAttachment = pCurrAttachmentRef; + *(pCurrAttachmentRef++) = *SrcSubpass.pDepthStencilAttachment; + UpdateAttachmentStateAndFirstUseSubpass(*SrcSubpass.pDepthStencilAttachment); + } + + if (SrcSubpass.PreserveAttachmentCount != 0) + { + DstSubpass.pPreserveAttachments = pCurrPreserveAttachment; + for (Uint32 prsv_attachment = 0; prsv_attachment < SrcSubpass.PreserveAttachmentCount; ++prsv_attachment) + *(pCurrPreserveAttachment++) = SrcSubpass.pPreserveAttachments[prsv_attachment]; + } + else + DstSubpass.pPreserveAttachments = nullptr; } VERIFY_EXPR(pCurrAttachmentRef - m_pAttachmentReferences == TotalAttachmentReferencesCount); VERIFY_EXPR(pCurrPreserveAttachment - m_pPreserveAttachments == TotalPreserveAttachmentsCount); @@ -177,6 +204,18 @@ public: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_RenderPass, TDeviceObjectBase) + RESOURCE_STATE GetAttachmentState(Uint32 Subpass, Uint32 Attachment) const + { + VERIFY_EXPR(Attachment < this->m_Desc.AttachmentCount); + VERIFY_EXPR(Subpass < this->m_Desc.SubpassCount); + return m_AttachmentStates[this->m_Desc.AttachmentCount * Subpass + Attachment]; + } + + Uint32 GetAttachmentFirstUseSubpass(Uint32 Attachment) const + { + return m_AttachmentFirstUseSubpass[Attachment]; + } + protected: static void CountSubpassAttachmentReferences(const RenderPassDesc& Desc, Uint32& TotalAttachmentReferencesCount, @@ -198,8 +237,21 @@ protected: } private: + void SetAttachmentState(Uint32 Subpass, Uint32 Attachment, RESOURCE_STATE State) + { + VERIFY_EXPR(Attachment < this->m_Desc.AttachmentCount); + VERIFY_EXPR(Subpass < this->m_Desc.SubpassCount); + m_AttachmentStates[this->m_Desc.AttachmentCount * Subpass + Attachment] = State; + } + AttachmentReference* m_pAttachmentReferences = nullptr; Uint32* m_pPreserveAttachments = nullptr; + + // Attachment states during each subpass + std::vector m_AttachmentStates; + + // The index of the subpass where the attachment is first used + std::vector m_AttachmentFirstUseSubpass; }; } // namespace Diligent -- cgit v1.2.3 From aef7f38b073ce6e7fdb00544419b7f3291508017 Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 7 Aug 2020 14:56:01 -0700 Subject: D3D11 backend: udpating resource states when calling NextSubpass --- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 1 + 1 file changed, 1 insertion(+) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 727888d9..41e83d4e 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -2217,6 +2217,7 @@ DILIGENT_TYPED_ENUM(RESOURCE_STATE, Uint32) RESOURCE_STATE_INDIRECT_ARGUMENT | RESOURCE_STATE_COPY_SOURCE }; +DEFINE_FLAG_ENUM_OPERATORS(RESOURCE_STATE); /// State transition barrier type DILIGENT_TYPED_ENUM(STATE_TRANSITION_TYPE, Uint8) -- cgit v1.2.3 From 6d402d55f6c5315c7213bc20dd5a381a70888198 Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 7 Aug 2020 17:30:58 -0700 Subject: Added render pass test references stubs for D3D12 and GL --- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 41e83d4e..2e063c8d 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -2215,7 +2215,8 @@ DILIGENT_TYPED_ENUM(RESOURCE_STATE, Uint32) RESOURCE_STATE_INDEX_BUFFER | RESOURCE_STATE_SHADER_RESOURCE | RESOURCE_STATE_INDIRECT_ARGUMENT | - RESOURCE_STATE_COPY_SOURCE + RESOURCE_STATE_COPY_SOURCE | + RESOURCE_STATE_INPUT_ATTACHMENT }; DEFINE_FLAG_ENUM_OPERATORS(RESOURCE_STATE); -- cgit v1.2.3 From 87d23dc98343ad4e4a2308826ed5f4f12125953e Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 8 Aug 2020 14:05:23 -0700 Subject: Initial implementation of render passes in D3D12 --- Graphics/GraphicsEngine/include/RenderPassBase.hpp | 28 ++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/RenderPassBase.hpp b/Graphics/GraphicsEngine/include/RenderPassBase.hpp index 46432ea0..96b479e6 100644 --- a/Graphics/GraphicsEngine/include/RenderPassBase.hpp +++ b/Graphics/GraphicsEngine/include/RenderPassBase.hpp @@ -31,6 +31,8 @@ /// Implementation of the Diligent::RenderPassBase template class #include +#include + #include "RenderPass.h" #include "DeviceObjectBase.hpp" #include "RenderDeviceBase.hpp" @@ -90,7 +92,7 @@ public: } m_AttachmentStates.resize(Desc.AttachmentCount * Desc.SubpassCount); - m_AttachmentFirstUseSubpass.resize(Desc.AttachmentCount, ATTACHMENT_UNUSED); + m_AttachmentFirstLastUse.resize(Desc.AttachmentCount, std::pair{ATTACHMENT_UNUSED, 0}); auto* pCurrAttachmentRef = m_pAttachmentReferences; auto* pCurrPreserveAttachment = m_pPreserveAttachments; @@ -98,23 +100,25 @@ public: auto* pSubpasses = ALLOCATE(GetRawAllocator(), "Memory for SubpassDesc array", SubpassDesc, Desc.SubpassCount); this->m_Desc.pSubpasses = pSubpasses; - for (Uint32 i = 0; i < Desc.SubpassCount; ++i) + for (Uint32 subpass = 0; subpass < Desc.SubpassCount; ++subpass) { for (Uint32 att = 0; att < Desc.AttachmentCount; ++att) { - SetAttachmentState(i, att, i > 0 ? GetAttachmentState(i - 1, att) : Desc.pAttachments[i].InitialState); + SetAttachmentState(subpass, att, subpass > 0 ? GetAttachmentState(subpass - 1, att) : Desc.pAttachments[subpass].InitialState); } - const auto& SrcSubpass = Desc.pSubpasses[i]; - auto& DstSubpass = pSubpasses[i]; + const auto& SrcSubpass = Desc.pSubpasses[subpass]; + auto& DstSubpass = pSubpasses[subpass]; - auto UpdateAttachmentStateAndFirstUseSubpass = [this, i](const AttachmentReference& AttRef) // + auto UpdateAttachmentStateAndFirstUseSubpass = [this, subpass](const AttachmentReference& AttRef) // { if (AttRef.AttachmentIndex != ATTACHMENT_UNUSED) { - SetAttachmentState(i, AttRef.AttachmentIndex, AttRef.State); - if (m_AttachmentFirstUseSubpass[AttRef.AttachmentIndex] == ATTACHMENT_UNUSED) - m_AttachmentFirstUseSubpass[AttRef.AttachmentIndex] = i; + SetAttachmentState(subpass, AttRef.AttachmentIndex, AttRef.State); + auto& FirstLastUse = m_AttachmentFirstLastUse[AttRef.AttachmentIndex]; + if (FirstLastUse.first == ATTACHMENT_UNUSED) + FirstLastUse.first = subpass; + FirstLastUse.second = subpass; } }; @@ -211,9 +215,9 @@ public: return m_AttachmentStates[this->m_Desc.AttachmentCount * Subpass + Attachment]; } - Uint32 GetAttachmentFirstUseSubpass(Uint32 Attachment) const + std::pair GetAttachmentFirstLastUse(Uint32 Attachment) const { - return m_AttachmentFirstUseSubpass[Attachment]; + return m_AttachmentFirstLastUse[Attachment]; } protected: @@ -251,7 +255,7 @@ private: std::vector m_AttachmentStates; // The index of the subpass where the attachment is first used - std::vector m_AttachmentFirstUseSubpass; + std::vector> m_AttachmentFirstLastUse; }; } // namespace Diligent -- cgit v1.2.3 From fd6ecbc3e52569119c4e0ff30236bd23f2757737 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 8 Aug 2020 16:48:40 -0700 Subject: Implemented unified render pass attachment state updates within subpasses and after the render pass ends --- .../GraphicsEngine/include/DeviceContextBase.hpp | 66 +++++++++++++++------- Graphics/GraphicsEngine/include/TextureBase.hpp | 6 ++ Graphics/GraphicsEngine/interface/DeviceContext.h | 22 +++++--- 3 files changed, 65 insertions(+), 29 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index a340bbd2..e5d9b90e 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -126,7 +126,7 @@ public: virtual void DILIGENT_CALL_TYPE NextSubpass() override = 0; - virtual void DILIGENT_CALL_TYPE EndRenderPass(bool UpdateResourceStates) override = 0; + virtual void DILIGENT_CALL_TYPE EndRenderPass() override = 0; /// Base implementation of IDeviceContext::UpdateBuffer(); validates input parameters. virtual void DILIGENT_CALL_TYPE UpdateBuffer(IBuffer* pBuffer, @@ -228,6 +228,9 @@ protected: /// Checks if the texture is currently bound as depth-stencil buffer. bool CheckIfBoundAsDepthStencil(TextureImplType* pTexture); + /// Updates the states of render pass attachments to match states within the gievn subpass + void UpdateAttachmentStates(Uint32 SubpassIndex); + bool ClearDepthStencil(ITextureView* pView); bool ClearRenderTarget(ITextureView* pView); @@ -329,6 +332,9 @@ protected: /// Current subpass index. Uint32 m_SubpassIndex = 0; + /// Render pass attachments transition mode. + RESOURCE_STATE_TRANSITION_MODE m_RenderPassAttachmentsTransitionMode = RESOURCE_STATE_TRANSITION_MODE_NONE; + const bool m_bIsDeferred = false; #ifdef DILIGENT_DEBUG @@ -970,9 +976,11 @@ inline void DeviceContextBase::BeginRenderP } } - m_pActiveRenderPass = pNewRenderPass; - m_pBoundFramebuffer = pNewFramebuffer; - m_SubpassIndex = 0; + m_pActiveRenderPass = pNewRenderPass; + m_pBoundFramebuffer = pNewFramebuffer; + m_SubpassIndex = 0; + m_RenderPassAttachmentsTransitionMode = Attribs.StateTransitionMode; + UpdateAttachmentStates(m_SubpassIndex); SetSubpassRenderTargets(); } @@ -982,36 +990,54 @@ inline void DeviceContextBase::NextSubpass( VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass"); VERIFY(m_SubpassIndex + 1 < m_pActiveRenderPass->GetDesc().SubpassCount, "The render pass has reached the final subpass already"); ++m_SubpassIndex; + UpdateAttachmentStates(m_SubpassIndex); SetSubpassRenderTargets(); } template -inline void DeviceContextBase::EndRenderPass(bool UpdateResourceStates) +inline void DeviceContextBase::UpdateAttachmentStates(Uint32 SubpassIndex) { - VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass"); - VERIFY(m_pBoundFramebuffer != nullptr, "There is no active framebuffer"); - VERIFY(m_pActiveRenderPass->GetDesc().SubpassCount == m_SubpassIndex + 1, - "Ending render pass at subpass ", m_SubpassIndex, " before reaching the final subpass"); + if (m_RenderPassAttachmentsTransitionMode != RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + return; + + VERIFY_EXPR(m_pActiveRenderPass != nullptr); + VERIFY_EXPR(m_pBoundFramebuffer != nullptr); - if (UpdateResourceStates) + const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); + VERIFY(FBDesc.AttachmentCount == RPDesc.AttachmentCount, + "Framebuffer attachment count (", FBDesc.AttachmentCount, ") is not consistent with the render pass attachment count (", RPDesc.AttachmentCount, ")"); + VERIFY_EXPR(SubpassIndex <= RPDesc.SubpassCount); + for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i) { - const auto& RPDesc = m_pActiveRenderPass->GetDesc(); - const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); - VERIFY(FBDesc.AttachmentCount >= RPDesc.AttachmentCount, - "Framebuffer attachment count (", FBDesc.AttachmentCount, ") is smaller than the render pass attachment count (", RPDesc.AttachmentCount, ")"); - for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i) + if (auto* pView = FBDesc.ppAttachments[i]) { - if (auto* pView = FBDesc.ppAttachments[i]) + auto* pTex = ValidatedCast(pView->GetTexture()); + if (pTex->IsInKnownState()) { - auto* pTex = ValidatedCast(pView->GetTexture()); - if (pTex->IsInKnownState()) - pTex->SetState(RPDesc.pAttachments[i].FinalState); + auto CurrState = SubpassIndex < RPDesc.SubpassCount ? + m_pActiveRenderPass->GetAttachmentState(SubpassIndex, i) : + RPDesc.pAttachments[i].FinalState; + pTex->SetState(CurrState); } } } +} + +template +inline void DeviceContextBase::EndRenderPass() +{ + VERIFY(m_pActiveRenderPass != nullptr, "There is no active render pass"); + VERIFY(m_pBoundFramebuffer != nullptr, "There is no active framebuffer"); + VERIFY(m_pActiveRenderPass->GetDesc().SubpassCount == m_SubpassIndex + 1, + "Ending render pass at subpass ", m_SubpassIndex, " before reaching the final subpass"); + + UpdateAttachmentStates(m_SubpassIndex + 1); + m_pActiveRenderPass.Release(); m_pBoundFramebuffer.Release(); - m_SubpassIndex = 0; + m_SubpassIndex = 0; + m_RenderPassAttachmentsTransitionMode = RESOURCE_STATE_TRANSITION_MODE_NONE; ResetRenderTargets(); } diff --git a/Graphics/GraphicsEngine/include/TextureBase.hpp b/Graphics/GraphicsEngine/include/TextureBase.hpp index fd0256b6..1805f7d3 100644 --- a/Graphics/GraphicsEngine/include/TextureBase.hpp +++ b/Graphics/GraphicsEngine/include/TextureBase.hpp @@ -184,6 +184,12 @@ public: return (this->m_State & State) == State; } + bool CheckAnyState(RESOURCE_STATE States) const + { + VERIFY(IsInKnownState(), "Texture state is unknown"); + return (this->m_State & States) != 0; + } + /// Implementation of ITexture::GetDefaultView(). virtual ITextureView* DILIGENT_CALL_TYPE GetDefaultView(TEXTURE_VIEW_TYPE ViewType) override { diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index 3445a8d6..eb77ba8e 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -633,7 +633,18 @@ struct BeginRenderPassAttribs /// Other elements of pClearValues are ignored. OptimizedClearValue* pClearValues DEFAULT_INITIALIZER(nullptr); - /// Framebuffer attachments state transition mode. + /// Framebuffer attachments state transition mode before the render pass begins. + + /// This parameter also indicates how attachment states should be handled when + /// transitioning between subpasses as well as after the render pass ends. + /// When RESOURCE_STATE_TRANSITION_MODE_TRANSITION is used, attachment states will be + /// updated so that they match the state in the current subpass as well as the final states + /// specified by the render pass when the pass ends. + /// Note that resources are always transitioned. The flag only indicates if the internal + /// state variables should be updated. + /// When RESOURCE_STATE_TRANSITION_MODE_NONE or RESOURCE_STATE_TRANSITION_MODE_VERIFY is used, + /// internal state variables are not updated and it is the application responsibility to set them + /// manually to match the actual states. RESOURCE_STATE_TRANSITION_MODE StateTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); }; typedef struct BeginRenderPassAttribs BeginRenderPassAttribs; @@ -905,14 +916,7 @@ DILIGENT_BEGIN_INTERFACE(IDeviceContext, IObject) /// Ends current render pass. - - /// \param [in] UpdateResourceStates - Indicates whether to update resource states so that they match - /// the final states specified by the render pass attachments. - /// Note that resources are always transitioned to the final states. - /// The flag only indicates if the internal state variables should be - /// updated to match the actual final states. - VIRTUAL void METHOD(EndRenderPass)(THIS_ - bool UpdateResourceStates) PURE; + VIRTUAL void METHOD(EndRenderPass)(THIS) PURE; /// Executes a draw command. -- cgit v1.2.3 From fecbd929c60de890f022c35e6b0774ee9db91ca7 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 8 Aug 2020 17:15:53 -0700 Subject: Fixed RESOURCE_STATE_GENERIC_READ enum value; few updates in D3D12 backend --- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 2e063c8d..41e83d4e 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -2215,8 +2215,7 @@ DILIGENT_TYPED_ENUM(RESOURCE_STATE, Uint32) RESOURCE_STATE_INDEX_BUFFER | RESOURCE_STATE_SHADER_RESOURCE | RESOURCE_STATE_INDIRECT_ARGUMENT | - RESOURCE_STATE_COPY_SOURCE | - RESOURCE_STATE_INPUT_ATTACHMENT + RESOURCE_STATE_COPY_SOURCE }; DEFINE_FLAG_ENUM_OPERATORS(RESOURCE_STATE); -- cgit v1.2.3 From c2a16b234fbd087e3f076895f9ce6873ef7b3e29 Mon Sep 17 00:00:00 2001 From: assiduous Date: Sat, 8 Aug 2020 19:13:00 -0700 Subject: Vk backend: improved handling of RESOURCE_STATE_RESOLVE_DEST attachment state --- Graphics/GraphicsEngine/include/RenderPassBase.hpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/RenderPassBase.hpp b/Graphics/GraphicsEngine/include/RenderPassBase.hpp index 96b479e6..c2a6b5c1 100644 --- a/Graphics/GraphicsEngine/include/RenderPassBase.hpp +++ b/Graphics/GraphicsEngine/include/RenderPassBase.hpp @@ -42,6 +42,21 @@ namespace Diligent void ValidateRenderPassDesc(const RenderPassDesc& Desc); +template +void _CorrectAttachmentState(RESOURCE_STATE& State) {} + +template <> +inline void _CorrectAttachmentState(RESOURCE_STATE& State) +{ + if (State == RESOURCE_STATE_RESOLVE_DEST) + { + // In Vulkan resolve attachments must be in VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL state. + // It is important to correct the state because outside of render pass RESOURCE_STATE_RESOLVE_DEST maps + // to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. + State = RESOURCE_STATE_RENDER_TARGET; + } +} + /// Template class implementing base functionality for the render pass object. /// \tparam BaseInterface - base interface that this class will inheret @@ -76,6 +91,7 @@ public: for (Uint32 i = 0; i < Desc.AttachmentCount; ++i) { pAttachments[i] = Desc.pAttachments[i]; + _CorrectAttachmentState(pAttachments[i].FinalState); } } @@ -150,6 +166,7 @@ public: for (Uint32 rslv_attachment = 0; rslv_attachment < SrcSubpass.RenderTargetAttachmentCount; ++rslv_attachment, ++pCurrAttachmentRef) { *pCurrAttachmentRef = SrcSubpass.pResolveAttachments[rslv_attachment]; + _CorrectAttachmentState(pCurrAttachmentRef->State); UpdateAttachmentStateAndFirstUseSubpass(*pCurrAttachmentRef); } } -- cgit v1.2.3 From 80d0d972308444d949eb1c363fb81864143c0762 Mon Sep 17 00:00:00 2001 From: assiduous Date: Mon, 10 Aug 2020 18:45:28 -0700 Subject: Initial implementation of render passes in GL backend --- Graphics/GraphicsEngine/include/FramebufferBase.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Graphics/GraphicsEngine') diff --git a/Graphics/GraphicsEngine/include/FramebufferBase.hpp b/Graphics/GraphicsEngine/include/FramebufferBase.hpp index 597639fc..fc008d73 100644 --- a/Graphics/GraphicsEngine/include/FramebufferBase.hpp +++ b/Graphics/GraphicsEngine/include/FramebufferBase.hpp @@ -63,7 +63,8 @@ public: RenderDeviceImplType* pDevice, const FramebufferDesc& Desc, bool bIsDeviceInternal = false) : - TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal} + TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}, + m_pRenderPass{Desc.pRenderPass} { ValidateFramebufferDesc(Desc); @@ -127,6 +128,8 @@ public: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_Framebuffer, TDeviceObjectBase) private: + RefCntAutoPtr m_pRenderPass; + ITextureView** m_ppAttachments = nullptr; }; -- cgit v1.2.3