/* * Copyright 2019-2021 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 /// Declaration of Diligent::RootParamsManager class and related data structures #include #include #include #include "Shader.h" #include "ShaderResourceVariable.h" namespace Diligent { enum ROOT_PARAMETER_GROUP : Uint32 { ROOT_PARAMETER_GROUP_STATIC_MUTABLE = 0, ROOT_PARAMETER_GROUP_DYNAMIC = 1, ROOT_PARAMETER_GROUP_COUNT }; inline ROOT_PARAMETER_GROUP VariableTypeToRootParameterGroup(SHADER_RESOURCE_VARIABLE_TYPE VarType) { return VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? ROOT_PARAMETER_GROUP_DYNAMIC : ROOT_PARAMETER_GROUP_STATIC_MUTABLE; } struct RootParameter { private: static constexpr Uint32 ParameterGroupBits = 1; static constexpr Uint32 RootIndexBits = 32 - ParameterGroupBits; static_assert((1 << ParameterGroupBits) >= ROOT_PARAMETER_GROUP_COUNT, "Not enough bits to represent ROOT_PARAMETER_GROUP"); public: const Uint32 RootIndex : RootIndexBits; const ROOT_PARAMETER_GROUP Group : ParameterGroupBits; // Each descriptor table is suballocated from one of the four descriptor heap allocations: // {CBV_SRV_UAV, SAMPLER} x {STATIC_MUTABLE, DYNAMIC}. // TableOffsetInGroupAllocation indicates starting offset from the beginning of the // corresponding allocation. const Uint32 TableOffsetInGroupAllocation; static constexpr Uint32 InvalidTableOffsetInGroupAllocation = ~0u; const D3D12_ROOT_PARAMETER d3d12RootParam; RootParameter(Uint32 _RootIndex, ROOT_PARAMETER_GROUP _Group, const D3D12_ROOT_PARAMETER& _d3d12RootParam, Uint32 _TableOffsetInGroupAllocation = InvalidTableOffsetInGroupAllocation) noexcept; // clang-format off RootParameter (const RootParameter&) = delete; RootParameter& operator=(const RootParameter&) = delete; RootParameter (RootParameter&&) = default; RootParameter& operator=(RootParameter&&) = delete; // clang-format on Uint32 GetDescriptorTableSize() const { VERIFY(d3d12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter type: descriptor table is expected"); // All descriptors in the table are tightly packed, so the table size is given // by the end of the last range const auto& d3d12Tbl = d3d12RootParam.DescriptorTable; VERIFY(d3d12Tbl.NumDescriptorRanges > 0, "Descriptor table must contain at least one range"); const auto& d3d12LastRange = d3d12Tbl.pDescriptorRanges[d3d12Tbl.NumDescriptorRanges - 1]; VERIFY(d3d12LastRange.NumDescriptors > 0, "The range must not be empty"); return d3d12LastRange.OffsetInDescriptorsFromTableStart + d3d12LastRange.NumDescriptors; } bool operator==(const RootParameter& rhs) const; bool operator!=(const RootParameter& rhs) const { return !(*this == rhs); } size_t GetHash() const; }; static_assert(sizeof(RootParameter) == sizeof(D3D12_ROOT_PARAMETER) + sizeof(Uint32) * 2, "Unexpected sizeof(RootParameter) - did you pack the members properly?"); /// Container for root parameters /// RootParamsManager keeps root parameters of a single pipeline resource signature. /// When resource signatures are combined into a single d3d12 root signature, /// root indices and shader spaces are biased based on earlier signatures. // Note that root index is NOT the same as the index of // the root table or index of the root view, e.g. // // Root Index | Root Table Index | Root View Index // 0 | 0 | // 1 | | 0 // 2 | 1 | // 3 | 2 | // 4 | | 1 // class RootParamsManager { public: RootParamsManager() noexcept {} ~RootParamsManager(); // clang-format off RootParamsManager (const RootParamsManager&) = delete; RootParamsManager& operator=(const RootParamsManager&) = delete; RootParamsManager (RootParamsManager&&) = delete; RootParamsManager& operator=(RootParamsManager&&) = delete; // clang-format on Uint32 GetNumRootTables() const { return m_NumRootTables; } Uint32 GetNumRootViews() const { return m_NumRootViews; } const RootParameter& GetRootTable(Uint32 TableInd) const { VERIFY_EXPR(TableInd < m_NumRootTables); return m_pRootTables[TableInd]; } const RootParameter& GetRootView(Uint32 ViewInd) const { VERIFY_EXPR(ViewInd < m_NumRootViews); return m_pRootViews[ViewInd]; } // Returns the total number of resources in a given parameter group and descriptor heap type Uint32 GetParameterGroupSize(D3D12_DESCRIPTOR_HEAP_TYPE d3d12HeapType, ROOT_PARAMETER_GROUP Group) const { return m_ParameterGroupSizes[d3d12HeapType][Group]; } bool operator==(const RootParamsManager& RootParams) const; #ifdef DILIGENT_DEBUG void Validate() const; #endif private: friend class RootParamsBuilder; std::unique_ptr> m_pMemory; Uint32 m_NumRootTables = 0; Uint32 m_NumRootViews = 0; const RootParameter* m_pRootTables = nullptr; const RootParameter* m_pRootViews = nullptr; // The total number of resources placed in descriptor tables for each heap type and parameter group type std::array, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER + 1> m_ParameterGroupSizes{}; }; class RootParamsBuilder { public: RootParamsBuilder(); // Allocates root parameter slot for the given resource attributes. void AllocateResourceSlot(SHADER_TYPE ShaderStages, SHADER_RESOURCE_VARIABLE_TYPE VariableType, D3D12_ROOT_PARAMETER_TYPE RootParameterType, D3D12_DESCRIPTOR_RANGE_TYPE RangeType, Uint32 ArraySize, Uint32 Register, Uint32 Space, Uint32& RootIndex, Uint32& OffsetFromTableStart); void InitializeMgr(IMemoryAllocator& MemAllocator, RootParamsManager& ParamsMgr); private: // Adds a new root view parameter and returns the reference to it. RootParameter& AddRootView(D3D12_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, UINT RegisterSpace, D3D12_SHADER_VISIBILITY Visibility, ROOT_PARAMETER_GROUP RootType); struct RootTableData; // Adds a new root table parameter and returns the reference to it. RootTableData& AddRootTable(Uint32 RootIndex, D3D12_SHADER_VISIBILITY Visibility, ROOT_PARAMETER_GROUP RootType, Uint32 NumRangesInNewTable = 1); private: struct RootTableData { RootTableData(Uint32 _RootIndex, D3D12_SHADER_VISIBILITY _Visibility, ROOT_PARAMETER_GROUP _Group, Uint32 _NumRanges); void Extend(Uint32 NumExtraRanges); const Uint32 RootIndex; const ROOT_PARAMETER_GROUP Group; D3D12_ROOT_PARAMETER d3d12RootParam{}; std::vector Ranges; }; std::vector m_RootTables; std::vector m_RootViews; static constexpr int InvalidRootTableIndex = -1; // The array below contains the index of a CBV/SRV/UAV root table in m_RootTables // (NOT the Root Index!), for every root parameter group (static/mutable, dynamic) // and every shader visbility, or -1, if the table is not yet assigned to the combination. // Note: max(D3D12_SHADER_VISIBILITY) == D3D12_SHADER_VISIBILITY_MESH == 7 std::array, ROOT_PARAMETER_GROUP_COUNT> m_SrvCbvUavRootTablesMap = {}; // This array contains the same data for Sampler root table std::array, ROOT_PARAMETER_GROUP_COUNT> m_SamplerRootTablesMap = {}; }; } // namespace Diligent