1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef RENDER_NODECONTEXT_NODE_CONTEXT_DESCRIPTOR_SET_MANAGER_H 17 #define RENDER_NODECONTEXT_NODE_CONTEXT_DESCRIPTOR_SET_MANAGER_H 18 19 #include <cstdint> 20 #include <shared_mutex> 21 22 #include <base/containers/string.h> 23 #include <base/containers/unordered_map.h> 24 #include <base/containers/vector.h> 25 #include <render/device/pipeline_layout_desc.h> 26 #include <render/namespace.h> 27 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h> 28 #include <render/resource_handle.h> 29 30 #include "device/gpu_resource_handle_util.h" 31 32 RENDER_BEGIN_NAMESPACE() 33 class Device; 34 class IDescriptorSetBinder; 35 class IPipelineDescriptorSetBinder; 36 37 struct DynamicOffsetDescriptors { 38 BASE_NS::array_view<const RenderHandle> resources; 39 }; 40 41 struct BufferDescriptorHandler { 42 BufferDescriptor desc; 43 // fetched and compared for possibly needed changes 44 EngineResourceHandle handle; 45 }; 46 47 struct ImageDescriptorHandler { 48 ImageDescriptor desc; 49 // fetched and compared for possibly needed changes 50 EngineResourceHandle handle; 51 EngineResourceHandle samplerHandle; 52 }; 53 54 struct SamplerDescriptorHandler { 55 SamplerDescriptor desc; 56 // fetched and compared for possibly needed changes 57 EngineResourceHandle handle; 58 }; 59 60 /** Descriptor set layout binding resources */ 61 struct DescriptorSetLayoutBindingResourcesHandler { 62 /** Bindings */ 63 BASE_NS::array_view<const DescriptorSetLayoutBindingResource> bindings; 64 65 /** Buffer descriptors */ 66 BASE_NS::array_view<const BufferDescriptorHandler> buffers; 67 /** Image descriptors */ 68 BASE_NS::array_view<const ImageDescriptorHandler> images; 69 /** Sampler descriptors */ 70 BASE_NS::array_view<const SamplerDescriptorHandler> samplers; 71 72 /** Mask of bindings in the descriptor set. Max uint is value which means that not set */ 73 uint32_t descriptorSetBindingMask { ~0u }; 74 /** Current binding mask. Max uint is value which means that not set */ 75 uint32_t bindingMask { ~0u }; 76 }; 77 78 struct CpuDescriptorSet { 79 uint32_t currentGpuBufferingIndex { 0 }; 80 bool gpuDescriptorSetCreated { false }; 81 bool isDirty { false }; 82 bool hasDynamicBarrierResources { false }; 83 bool hasPlatformConversionBindings { false }; // e.g. hwbuffers with ycbcr / OES 84 bool hasImmutableSamplers { false }; 85 86 BASE_NS::vector<DescriptorSetLayoutBindingResource> bindings; 87 88 BASE_NS::vector<BufferDescriptorHandler> buffers; 89 BASE_NS::vector<ImageDescriptorHandler> images; 90 BASE_NS::vector<SamplerDescriptorHandler> samplers; 91 92 // gpu buffers with dynamic offsets 93 BASE_NS::vector<RenderHandle> dynamicOffsetDescriptors; 94 }; 95 96 // storage counts 97 struct LowLevelDescriptorCounts { 98 uint32_t writeDescriptorCount { 0u }; 99 uint32_t bufferCount { 0u }; 100 uint32_t imageCount { 0u }; 101 uint32_t samplerCount { 0u }; 102 uint32_t accelCount { 0u }; 103 }; 104 105 enum DescriptorSetUpdateInfoFlagBits { 106 // invalid handles etc. 107 DESCRIPTOR_SET_UPDATE_INFO_INVALID_BIT = (1 << 0), 108 // new handles -> needs real update 109 DESCRIPTOR_SET_UPDATE_INFO_NEW_BIT = (1 << 1), 110 }; 111 using DescriptorSetUpdateInfoFlags = uint32_t; 112 113 /** 114 * Global descriptor set manager 115 * NOTE: The global descriptor sets are still updated through different NodeContextDescriptorSetManager s 116 */ 117 class DescriptorSetManager { 118 public: 119 explicit DescriptorSetManager(Device& device); 120 virtual ~DescriptorSetManager() = default; 121 122 virtual void BeginFrame(); 123 124 void LockFrameCreation(); 125 126 BASE_NS::vector<RenderHandleReference> CreateDescriptorSets(const BASE_NS::string_view name, 127 const BASE_NS::array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings, const uint32_t count); 128 RenderHandleReference CreateDescriptorSet(const BASE_NS::string_view name, 129 const BASE_NS::array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings); 130 131 // get one 132 RenderHandle GetDescriptorSetHandle(const BASE_NS::string_view name) const; 133 // get all descriptor sets defined with this name 134 BASE_NS::array_view<const RenderHandle> GetDescriptorSetHandles(const BASE_NS::string_view name) const; 135 136 CpuDescriptorSet* GetCpuDescriptorSet(const RenderHandle& handle); 137 DescriptorSetLayoutBindingResourcesHandler GetCpuDescriptorSetData(const RenderHandle& handle); 138 DynamicOffsetDescriptors GetDynamicOffsetDescriptors(const RenderHandle& handle); 139 bool HasDynamicBarrierResources(const RenderHandle& handle); 140 uint32_t GetDynamicOffsetDescriptorCount(const RenderHandle& handle); 141 142 // Will mark the descriptor set write locked for this frame (no one else can write) 143 DescriptorSetUpdateInfoFlags UpdateCpuDescriptorSet(const RenderHandle& handle, 144 const DescriptorSetLayoutBindingResources& bindingResources, const GpuQueue& gpuQueue); 145 // platform 146 virtual void UpdateDescriptorSetGpuHandle(const RenderHandle& handle) = 0; 147 virtual void UpdateCpuDescriptorSetPlatform(const DescriptorSetLayoutBindingResources& bindingResources) = 0; 148 149 // get all updated handles this frame 150 BASE_NS::array_view<const RenderHandle> GetUpdateDescriptorSetHandles() const; 151 152 class LowLevelDescriptorSetData { 153 public: 154 LowLevelDescriptorSetData() = default; 155 virtual ~LowLevelDescriptorSetData() = default; 156 157 LowLevelDescriptorSetData(const LowLevelDescriptorSetData&) = delete; 158 LowLevelDescriptorSetData& operator=(const LowLevelDescriptorSetData&) = delete; 159 }; 160 161 struct GlobalDescriptorSetData { 162 // should only be updated from a single place per frame 163 bool frameWriteLocked { false }; 164 CpuDescriptorSet cpuDescriptorSet; 165 RenderHandleReference renderHandleReference; 166 }; 167 struct GlobalDescriptorSetBase { 168 // handles are separated for direct array_view usage 169 BASE_NS::vector<RenderHandle> handles; 170 BASE_NS::vector<GlobalDescriptorSetData> data; 171 BASE_NS::string name; 172 }; 173 174 protected: 175 // platform 176 virtual void CreateDescriptorSets(const uint32_t arrayIndex, const uint32_t descriptorSetCount, 177 const BASE_NS::array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings) = 0; 178 179 Device& device_; 180 181 // NOTE: does not need mutuxes at the moment 182 // creation happens only in render nodes init or preexecute 183 BASE_NS::vector<BASE_NS::unique_ptr<GlobalDescriptorSetBase>> descriptorSets_; 184 BASE_NS::unordered_map<BASE_NS::string, uint32_t> nameToIndex_; 185 186 BASE_NS::vector<RenderHandle> availableHandles_; 187 188 // all handles this frame which should be updated (needs to be locked when accessed) 189 BASE_NS::vector<RenderHandle> descriptorSetHandlesForUpdate_; 190 191 // lock creation after pre execute done for render nodes 192 bool creationLocked_ { true }; 193 194 // used to lock shared data which could be accessed from multiple threads 195 mutable std::shared_mutex mutex_; 196 }; 197 198 /** 199 class NodeContextDescriptorSetManager. 200 */ 201 class NodeContextDescriptorSetManager : public INodeContextDescriptorSetManager { 202 public: 203 explicit NodeContextDescriptorSetManager(Device& device); 204 ~NodeContextDescriptorSetManager() override = default; 205 IsDynamicDescriptor(const DescriptorType descType)206 static constexpr inline bool IsDynamicDescriptor(const DescriptorType descType) 207 { 208 return ((descType == DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) || 209 (descType == DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)); 210 } 211 GetCpuDescriptorSetIndex(const RenderHandle & handle)212 static constexpr inline uint32_t GetCpuDescriptorSetIndex(const RenderHandle& handle) 213 { 214 const uint32_t addBits = RenderHandleUtil::GetAdditionalData(handle); 215 if (addBits & NodeContextDescriptorSetManager::ONE_FRAME_DESC_SET_BIT) { 216 return NodeContextDescriptorSetManager::DescriptorSetIndexType::DESCRIPTOR_SET_INDEX_TYPE_ONE_FRAME; 217 } else if (addBits & NodeContextDescriptorSetManager::GLOBAL_DESCRIPTOR_BIT) { 218 return ~0U; // invalid 219 } else { 220 return NodeContextDescriptorSetManager::DescriptorSetIndexType::DESCRIPTOR_SET_INDEX_TYPE_STATIC; 221 } 222 } 223 224 // static helper function 225 static void IncreaseDescriptorSetCounts(const DescriptorSetLayoutBinding& refBinding, 226 LowLevelDescriptorCounts& descSetCounts, uint32_t& dynamicOffsetCount); 227 228 void ResetAndReserve(const DescriptorCounts& descriptorCounts) override; 229 void ResetAndReserve(const BASE_NS::array_view<DescriptorCounts> descriptorCounts) override; 230 231 virtual RenderHandle CreateDescriptorSet( 232 const BASE_NS::array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings) override = 0; 233 BASE_NS::vector<RenderHandle> CreateDescriptorSets( 234 const BASE_NS::array_view<const DescriptorSetLayoutBindings> descriptorSetsLayoutBindings) override; 235 RenderHandle CreateDescriptorSet(const uint32_t set, const PipelineLayout& pipelineLayout) override; 236 237 IDescriptorSetBinder::Ptr CreateDescriptorSetBinder(const RenderHandle handle, 238 const BASE_NS::array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings) override; 239 IDescriptorSetBinder::Ptr CreateDescriptorSetBinder( 240 const BASE_NS::array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings) override; 241 242 IPipelineDescriptorSetBinder::Ptr CreatePipelineDescriptorSetBinder(const PipelineLayout& pipelineLayout) override; 243 IPipelineDescriptorSetBinder::Ptr CreatePipelineDescriptorSetBinder(const PipelineLayout& pipelineLayout, 244 const BASE_NS::array_view<const RenderHandle> handles, 245 const BASE_NS::array_view<const DescriptorSetLayoutBindings> descriptorSetsLayoutBindings) override; 246 247 virtual RenderHandle CreateOneFrameDescriptorSet( 248 const BASE_NS::array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings) override = 0; 249 virtual BASE_NS::vector<RenderHandle> CreateOneFrameDescriptorSets( 250 const BASE_NS::array_view<const DescriptorSetLayoutBindings> descriptorSetsLayoutBindings) override; 251 virtual RenderHandle CreateOneFrameDescriptorSet(const uint32_t set, const PipelineLayout& pipelineLayout) override; 252 253 RenderHandleReference CreateGlobalDescriptorSet(const BASE_NS::string_view name, 254 const BASE_NS::array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings) override; 255 BASE_NS::vector<RenderHandleReference> CreateGlobalDescriptorSets(const BASE_NS::string_view name, 256 const BASE_NS::array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings, 257 const uint32_t descriptorSetCount) override; 258 RenderHandle GetGlobalDescriptorSet(const BASE_NS::string_view name) const override; 259 BASE_NS::array_view<const RenderHandle> GetGlobalDescriptorSets(const BASE_NS::string_view name) const override; 260 261 DescriptorSetLayoutBindingResourcesHandler GetCpuDescriptorSetData(const RenderHandle handle) const; 262 DynamicOffsetDescriptors GetDynamicOffsetDescriptors(const RenderHandle handle) const; 263 264 virtual void BeginFrame(); 265 266 // information for barrier creation what kind of descriptors does the descriptor set contain 267 // if returns false -> no need for barriers and/or layout changes 268 bool HasDynamicBarrierResources(const RenderHandle handle) const; 269 // count of dynamic offset needed when binding descriptor set 270 uint32_t GetDynamicOffsetDescriptorCount(const RenderHandle handle) const; 271 272 // update descriptor sets for cpu data (adds correct gpu queue as well) 273 DescriptorSetUpdateInfoFlags UpdateCpuDescriptorSet(const RenderHandle handle, 274 const DescriptorSetLayoutBindingResources& bindingResources, const GpuQueue& gpuQueue); 275 // call from backend before actual graphics api updateDescriptorset() 276 // advances the gpu handle to the next available descriptor set (ring buffer) 277 virtual void UpdateDescriptorSetGpuHandle(const RenderHandle handle) = 0; 278 // platform specific updates 279 virtual void UpdateCpuDescriptorSetPlatform(const DescriptorSetLayoutBindingResources& bindingResources) = 0; 280 281 #if (RENDER_VALIDATION_ENABLED == 1) 282 struct DescriptorCountValidation { 283 BASE_NS::unordered_map<uint32_t, int32_t> typeToCount; 284 }; 285 #endif 286 #if ((RENDER_VALIDATION_ENABLED == 1) || (RENDER_VULKAN_VALIDATION_ENABLED == 1)) 287 void SetValidationDebugName(const BASE_NS::string_view debugName); 288 #endif 289 290 static constexpr uint32_t ONE_FRAME_DESC_SET_BIT { 1U << 0U }; 291 static constexpr uint32_t GLOBAL_DESCRIPTOR_BIT { 1U << 1U }; 292 293 enum DescriptorSetIndexType : uint8_t { 294 DESCRIPTOR_SET_INDEX_TYPE_STATIC = 0, 295 DESCRIPTOR_SET_INDEX_TYPE_ONE_FRAME, 296 DESCRIPTOR_SET_INDEX_TYPE_COUNT, 297 }; 298 299 protected: 300 NodeContextDescriptorSetManager() = delete; 301 Device& device_; 302 303 BASE_NS::vector<CpuDescriptorSet> cpuDescriptorSets_[DESCRIPTOR_SET_INDEX_TYPE_COUNT]; 304 305 uint32_t maxSets_ { 0 }; 306 // indicates if there are some sets updated on CPU which have platfrom conversion bindings 307 bool hasPlatformConversionBindings_ { false }; 308 309 DescriptorSetUpdateInfoFlags UpdateCpuDescriptorSetImpl(const uint32_t index, 310 const DescriptorSetLayoutBindingResources& bindingResources, const GpuQueue& gpuQueue, 311 BASE_NS::vector<CpuDescriptorSet>& cpuDescriptorSets); 312 static DescriptorSetLayoutBindingResourcesHandler GetCpuDescriptorSetDataImpl( 313 const uint32_t index, const BASE_NS::vector<CpuDescriptorSet>& cpuDescriptorSet); 314 static DynamicOffsetDescriptors GetDynamicOffsetDescriptorsImpl( 315 const uint32_t index, const BASE_NS::vector<CpuDescriptorSet>& cpuDescriptorSet); 316 static bool HasDynamicBarrierResourcesImpl( 317 const uint32_t index, const BASE_NS::vector<CpuDescriptorSet>& cpuDescriptorSet); 318 static uint32_t GetDynamicOffsetDescriptorCountImpl( 319 const uint32_t index, const BASE_NS::vector<CpuDescriptorSet>& cpuDescriptorSet); 320 321 BASE_NS::string debugName_; 322 DescriptorSetManager& globalDescriptorSetMgr_; 323 324 private: 325 #if (RENDER_VALIDATION_ENABLED == 1) 326 DescriptorCountValidation descriptorCountValidation_; 327 #endif 328 }; 329 RENDER_END_NAMESPACE() 330 331 #endif // CORE__RENDER__NODE_CONTEXT_DESCRIPTOR_SET_MANAGER_H 332