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