• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #include "pipeline_descriptor_set_binder.h"
17 
18 #include <cstdint>
19 
20 #include <base/math/mathf.h>
21 #include <render/device/pipeline_layout_desc.h>
22 #include <render/device/pipeline_state_desc.h>
23 #include <render/namespace.h>
24 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
25 
26 #include "device/gpu_resource_handle_util.h"
27 #include "device/pipeline_state_object.h"
28 #include "util/log.h"
29 
30 using namespace BASE_NS;
31 
32 RENDER_BEGIN_NAMESPACE()
33 namespace {
34 constexpr uint8_t INVALID_BIDX { 16 };
35 
GetPipelineStageFlags(const ShaderStageFlags shaderStageFlags)36 PipelineStageFlags GetPipelineStageFlags(const ShaderStageFlags shaderStageFlags)
37 {
38     PipelineStageFlags pipelineStageFlags { 0 };
39 
40     if (shaderStageFlags & ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT) {
41         pipelineStageFlags |= PipelineStageFlagBits::CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT;
42     } else if (shaderStageFlags & ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT) {
43         pipelineStageFlags |= PipelineStageFlagBits::CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
44     } else if (shaderStageFlags & ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT) {
45         pipelineStageFlags |= PipelineStageFlagBits::CORE_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
46     }
47 
48     return pipelineStageFlags;
49 }
50 
GetAccessFlags(const DescriptorType dt)51 constexpr AccessFlags GetAccessFlags(const DescriptorType dt)
52 {
53     if ((dt == CORE_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) || (dt == CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
54         (dt == CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)) {
55         return CORE_ACCESS_UNIFORM_READ_BIT;
56     } else if ((dt == CORE_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) || (dt == CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
57                (dt == CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) || (dt == CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE)) {
58         // NOTE: could be optimized with shader reflection info
59         return (CORE_ACCESS_SHADER_READ_BIT | CORE_ACCESS_SHADER_WRITE_BIT);
60     } else if (dt == CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) {
61         return CORE_ACCESS_INPUT_ATTACHMENT_READ_BIT;
62     } else {
63         // CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
64         // CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE
65         // CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
66         // CORE_DESCRIPTOR_TYPE_SAMPLER
67         // CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE
68         return CORE_ACCESS_SHADER_READ_BIT;
69     }
70 }
71 
GetImageLayout(const DescriptorType dt)72 constexpr ImageLayout GetImageLayout(const DescriptorType dt)
73 {
74     if ((dt == CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (dt == CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
75         (dt == CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
76         return CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
77     } else if (dt == CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
78         return CORE_IMAGE_LAYOUT_GENERAL;
79     } else {
80         return CORE_IMAGE_LAYOUT_UNDEFINED;
81     }
82 }
83 
CheckValidBufferDescriptor(const DescriptorType dt)84 inline constexpr bool CheckValidBufferDescriptor(const DescriptorType dt)
85 {
86     return ((dt >= CORE_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) && (dt <= CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) ||
87            (dt == CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE);
88 }
89 
CheckValidImageDescriptor(const DescriptorType dt)90 inline constexpr bool CheckValidImageDescriptor(const DescriptorType dt)
91 {
92     return (dt == CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (dt == CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
93            (dt == CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE) || (dt == CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
94 }
95 
GetRenderHandleType(const DescriptorType dt)96 constexpr RenderHandleType GetRenderHandleType(const DescriptorType dt)
97 {
98     if (dt == CORE_DESCRIPTOR_TYPE_SAMPLER) {
99         return RenderHandleType::GPU_SAMPLER;
100     } else if (((dt >= CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) && (dt <= CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE)) ||
101                (dt == CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
102         return RenderHandleType::GPU_IMAGE;
103     } else if (((dt >= CORE_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) &&
104                    (dt <= CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) ||
105                (dt == CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE)) {
106         return RenderHandleType::GPU_BUFFER;
107     }
108     return RenderHandleType::UNDEFINED;
109 }
110 
111 struct DescriptorCounts {
112     uint32_t count { 0 };
113     uint32_t arrayCount { 0 };
114 };
115 } // namespace
116 
DescriptorSetBinder(const RenderHandle handle,const array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings)117 DescriptorSetBinder::DescriptorSetBinder(
118     const RenderHandle handle, const array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings)
119     : handle_(handle)
120 {
121     if (RenderHandleUtil::GetHandleType(handle) != RenderHandleType::DESCRIPTOR_SET) {
122         PLUGIN_LOG_E("invalid handle in descriptor set binder creation");
123     }
124 
125     bindings_.resize(descriptorSetLayoutBindings.size());
126     for (size_t idx = 0; idx < descriptorSetLayoutBindings.size(); ++idx) {
127         maxBindingCount_ = Math::max(maxBindingCount_, descriptorSetLayoutBindings[idx].binding);
128     }
129     // +1 for binding count
130     maxBindingCount_ = Math::min(maxBindingCount_ + 1, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT);
131 
132     DescriptorCounts bufferCounts;
133     DescriptorCounts imageCounts;
134     DescriptorCounts samplerCounts;
135     for (const auto& binding : descriptorSetLayoutBindings) {
136         const RenderHandleType type = GetRenderHandleType(binding.descriptorType);
137         // we don't have duplicates, array descriptor from index 1 can be found directly from arrayOffset
138         const uint32_t arrayCount = (binding.descriptorCount > 1) ? (binding.descriptorCount - 1) : 0;
139         if (type == RenderHandleType::GPU_BUFFER) {
140             bufferCounts.count++;
141             bufferCounts.arrayCount += arrayCount;
142         } else if (type == RenderHandleType::GPU_IMAGE) {
143             imageCounts.count++;
144             imageCounts.arrayCount += arrayCount;
145         } else if (type == RenderHandleType::GPU_SAMPLER) {
146             samplerCounts.count++;
147             samplerCounts.arrayCount += arrayCount;
148         }
149     }
150     buffers_.resize(bufferCounts.count + bufferCounts.arrayCount);
151     images_.resize(imageCounts.count + imageCounts.arrayCount);
152     samplers_.resize(samplerCounts.count + samplerCounts.arrayCount);
153 
154     InitFillBindings(descriptorSetLayoutBindings, bufferCounts.count, imageCounts.count, samplerCounts.count);
155 }
156 
InitFillBindings(const array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings,const uint32_t bufferCount,const uint32_t imageCount,const uint32_t samplerCount)157 void DescriptorSetBinder::InitFillBindings(
158     const array_view<const DescriptorSetLayoutBinding> descriptorSetLayoutBindings, const uint32_t bufferCount,
159     const uint32_t imageCount, const uint32_t samplerCount)
160 {
161     auto UpdateArrayStates = [](const auto& desc, auto& vec) {
162         const uint32_t maxArrayCount = desc.arrayOffset + desc.binding.descriptorCount - 1;
163         for (uint32_t idx = desc.arrayOffset; idx < maxArrayCount; ++idx) {
164             vec[idx] = desc;
165             vec[idx].binding.descriptorCount = 0;
166             vec[idx].arrayOffset = 0;
167         }
168     };
169 
170     DescriptorCounts bufferIdx { 0, bufferCount };
171     DescriptorCounts imageIdx { 0, imageCount };
172     DescriptorCounts samplerIdx { 0, samplerCount };
173     for (size_t idx = 0; idx < bindings_.size(); ++idx) {
174         auto& currBinding = bindings_[idx];
175         currBinding.binding = descriptorSetLayoutBindings[idx];
176 
177         // setup expected bindings
178         descriptorBindingMask_ |= (1 << currBinding.binding.binding);
179 
180         const AccessFlags accessFlags = GetAccessFlags(currBinding.binding.descriptorType);
181         const ShaderStageFlags shaderStageFlags = currBinding.binding.shaderStageFlags;
182         const PipelineStageFlags pipelineStageFlags = GetPipelineStageFlags(currBinding.binding.shaderStageFlags);
183         if (idx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
184             bindingToIndex_[currBinding.binding.binding] = static_cast<uint8_t>(idx);
185         }
186         const RenderHandleType type = GetRenderHandleType(currBinding.binding.descriptorType);
187         if (type == RenderHandleType::GPU_BUFFER) {
188             currBinding.resourceIndex = bufferIdx.count;
189             PLUGIN_ASSERT(bufferIdx.count < buffers_.size());
190             auto& res = buffers_[bufferIdx.count];
191             res.binding = currBinding.binding;
192             res.state = { shaderStageFlags, accessFlags, pipelineStageFlags, {} };
193 
194             bufferIdx.count++;
195             if (res.binding.descriptorCount > 1) {
196                 res.arrayOffset = bufferIdx.arrayCount;
197                 bufferIdx.arrayCount += (currBinding.binding.descriptorCount - 1);
198                 UpdateArrayStates(res, buffers_);
199             }
200         } else if (type == RenderHandleType::GPU_IMAGE) {
201             currBinding.resourceIndex = imageIdx.count;
202             PLUGIN_ASSERT(imageIdx.count < images_.size());
203             auto& res = images_[imageIdx.count];
204             res.binding = currBinding.binding;
205             res.state = { shaderStageFlags, accessFlags, pipelineStageFlags, {} };
206 
207             imageIdx.count++;
208             if (res.binding.descriptorCount > 1) {
209                 res.arrayOffset = imageIdx.arrayCount;
210                 imageIdx.arrayCount += (currBinding.binding.descriptorCount - 1);
211                 UpdateArrayStates(res, images_);
212             }
213         } else if (type == RenderHandleType::GPU_SAMPLER) {
214             currBinding.resourceIndex = samplerIdx.count;
215             PLUGIN_ASSERT(samplerIdx.count < samplers_.size());
216             auto& res = samplers_[samplerIdx.count];
217             res.binding = currBinding.binding;
218 
219             samplerIdx.count++;
220             if (res.binding.descriptorCount > 1) {
221                 res.arrayOffset = samplerIdx.arrayCount;
222                 samplerIdx.arrayCount += (currBinding.binding.descriptorCount - 1);
223                 UpdateArrayStates(res, samplers_);
224             }
225         }
226     }
227 }
228 
ClearBindings()229 void DescriptorSetBinder::ClearBindings()
230 {
231     bindingMask_ = 0;
232 }
233 
GetDescriptorSetHandle() const234 RenderHandle DescriptorSetBinder::GetDescriptorSetHandle() const
235 {
236     return handle_;
237 }
238 
GetDescriptorSetLayoutBindingResources() const239 DescriptorSetLayoutBindingResources DescriptorSetBinder::GetDescriptorSetLayoutBindingResources() const
240 {
241     DescriptorSetLayoutBindingResources dslbr { bindings_, buffers_, images_, samplers_, descriptorBindingMask_,
242         bindingMask_ };
243 
244 #if (RENDER_VALIDATION_ENABLED == 1)
245     auto CheckValidity = [](const auto& vec, const string_view strView) {
246         for (size_t idx = 0; idx < vec.size(); ++idx) {
247             if (!RenderHandleUtil::IsValid(vec[idx].resource.handle)) {
248                 PLUGIN_LOG_E("RENDER_VALIDATION: invalid resource in descriptor set bindings (binding:%u) (type:%s)",
249                     static_cast<uint32_t>(idx), strView.data());
250             }
251         }
252     };
253     // NOTE: does not check combined image sampler samplers
254     CheckValidity(buffers_, "buffer");
255     CheckValidity(images_, "image");
256     CheckValidity(samplers_, "sampler");
257 #endif
258 
259     return dslbr;
260 }
261 
GetDescriptorSetLayoutBindingValidity() const262 bool DescriptorSetBinder::GetDescriptorSetLayoutBindingValidity() const
263 {
264     return (bindingMask_ == descriptorBindingMask_);
265 }
266 
BindBuffer(const uint32_t binding,const BindableBuffer & resource)267 void DescriptorSetBinder::BindBuffer(const uint32_t binding, const BindableBuffer& resource)
268 {
269     const RenderHandleType handleType = RenderHandleUtil::GetHandleType(resource.handle);
270     const bool validHandleType = (handleType == RenderHandleType::GPU_BUFFER);
271     if ((binding < maxBindingCount_) && validHandleType) {
272 #if (RENDER_VALIDATION_ENABLED == 1)
273         if (resource.byteSize == 0) {
274             PLUGIN_LOG_ONCE_W("PipelineDescriptorSetBinder::BindBuffer()_byteSize",
275                 "RENDER_VALIDATION: PipelineDescriptorSetBinder::BindBuffer() byteSize 0");
276         }
277 #endif
278         const uint32_t index = bindingToIndex_[binding];
279         if (index < INVALID_BIDX) {
280             const auto& bind = bindings_[index];
281             const DescriptorType descriptorType = bind.binding.descriptorType;
282             if (CheckValidBufferDescriptor(descriptorType)) {
283                 buffers_[bind.resourceIndex].resource = resource;
284                 bindingMask_ |= (1 << binding);
285             } else {
286                 PLUGIN_LOG_E("invalid binding for buffer descriptor (binding: %u, descriptorType: %u)", binding,
287                     (uint32_t)descriptorType);
288             }
289         }
290     }
291 #if (RENDER_VALIDATION_ENABLED == 1)
292     if (!validHandleType) {
293         PLUGIN_LOG_ONCE_W("PipelineDescriptorSetBinder::BindBuffer()",
294             "RENDER_VALIDATION: PipelineDescriptorSetBinder::BindBuffer() invalid handle");
295     }
296 #endif
297 }
298 
BindBuffer(const uint32_t binding,const RenderHandle handle,const uint32_t byteOffset)299 void DescriptorSetBinder::BindBuffer(const uint32_t binding, const RenderHandle handle, const uint32_t byteOffset)
300 {
301     BindBuffer(binding, BindableBuffer { handle, byteOffset, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
302 }
303 
BindBuffer(const uint32_t binding,const RenderHandle handle,const uint32_t byteOffset,const uint32_t byteSize)304 void DescriptorSetBinder::BindBuffer(
305     const uint32_t binding, const RenderHandle handle, const uint32_t byteOffset, const uint32_t byteSize)
306 {
307     BindBuffer(binding, BindableBuffer { handle, byteOffset, byteSize });
308 }
309 
BindBuffers(const uint32_t binding,const BASE_NS::array_view<const BindableBuffer> resources)310 void DescriptorSetBinder::BindBuffers(const uint32_t binding, const BASE_NS::array_view<const BindableBuffer> resources)
311 {
312     if ((!resources.empty()) && (binding < maxBindingCount_)) {
313         const uint32_t index = bindingToIndex_[binding];
314         if ((index < INVALID_BIDX) && CheckValidBufferDescriptor(bindings_[index].binding.descriptorType)) {
315             const auto& bind = bindings_[index];
316             BindableBuffer& ref = buffers_[bind.resourceIndex].resource;
317             const uint32_t arrayOffset = buffers_[bind.resourceIndex].arrayOffset;
318 #if (RENDER_VALIDATION_ENABLED == 1)
319             bool validationIssue = false;
320 #endif
321             const uint32_t maxCount = Math::min(static_cast<uint32_t>(resources.size()), bind.binding.descriptorCount);
322             PLUGIN_ASSERT((arrayOffset + maxCount - 1) <= buffers_.size());
323             for (uint32_t idx = 0; idx < maxCount; ++idx) {
324                 const RenderHandle currHandle = resources[idx].handle;
325                 const bool validType = (RenderHandleUtil::GetHandleType(currHandle) == RenderHandleType::GPU_BUFFER);
326 #if (RENDER_VALIDATION_ENABLED == 1)
327                 if (!validType) {
328                     PLUGIN_LOG_E(
329                         "RENDER_VALIDATION: PipelineDescriptorSetBinder::BindBuffers() invalid handle type (index: "
330                         "%u)",
331                         static_cast<uint32_t>(idx));
332                 }
333                 if (bind.binding.descriptorCount != resources.size()) {
334                     validationIssue = true;
335                 }
336 #endif
337                 if (validType) {
338                     BindableBuffer& bRes = (idx == 0) ? ref : buffers_[arrayOffset + idx - 1].resource;
339                     bRes = resources[idx];
340                     bindingMask_ |= (1 << binding);
341                 }
342             }
343 #if (RENDER_VALIDATION_ENABLED == 1)
344             if (validationIssue) {
345                 PLUGIN_LOG_E(
346                     "RENDER_VALIDATION: DescriptorSetBinder::BindBuffers() trying to bind (%u) buffers to set arrays "
347                     "(%u)",
348                     static_cast<uint32_t>(resources.size()), bind.binding.descriptorCount);
349             }
350 #endif
351         } else {
352             PLUGIN_LOG_E("invalid binding for buffer descriptor (binding: %u)", binding);
353         }
354     }
355 }
356 
BindImage(const uint32_t binding,const BindableImage & resource)357 void DescriptorSetBinder::BindImage(const uint32_t binding, const BindableImage& resource)
358 {
359     const bool validHandleType = (RenderHandleUtil::GetHandleType(resource.handle) == RenderHandleType::GPU_IMAGE);
360     if ((binding < maxBindingCount_) && validHandleType) {
361         const uint32_t index = bindingToIndex_[binding];
362         if (index < INVALID_BIDX) {
363             const auto& bind = bindings_[index];
364             const DescriptorType descriptorType = bind.binding.descriptorType;
365             const bool validSamplerHandling =
366                 (descriptorType == CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
367                     ? (RenderHandleUtil::GetHandleType(resource.samplerHandle) == RenderHandleType::GPU_SAMPLER)
368                     : true;
369             if (CheckValidImageDescriptor(descriptorType) && validSamplerHandling) {
370                 BindableImage& bindableImage = images_[bind.resourceIndex].resource;
371                 if (resource.imageLayout != CORE_IMAGE_LAYOUT_UNDEFINED) {
372                     bindableImage.imageLayout = resource.imageLayout;
373                 } else {
374                     bindableImage.imageLayout = (RenderHandleUtil::IsDepthImage(resource.handle))
375                                                     ? ImageLayout::CORE_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
376                                                     : GetImageLayout(bind.binding.descriptorType);
377                 }
378                 bindableImage.handle = resource.handle;
379                 bindableImage.mip = resource.mip;
380                 bindableImage.layer = resource.layer;
381                 bindableImage.samplerHandle = resource.samplerHandle;
382                 bindingMask_ |= (1 << binding);
383             } else {
384                 PLUGIN_LOG_E("invalid binding for image descriptor (binding: %u, descriptorType: %u)", binding,
385                     (uint32_t)descriptorType);
386             }
387         }
388     }
389 #if (RENDER_VALIDATION_ENABLED == 1)
390     if (!validHandleType) {
391         PLUGIN_LOG_ONCE_W("PipelineDescriptorSetBinder::BindImage()",
392             "RENDER_VALIDATION: PipelineDescriptorSetBinder::BindImage() invalid handle");
393     }
394 #endif
395 }
396 
BindImage(const uint32_t binding,const RenderHandle handle)397 void DescriptorSetBinder::BindImage(const uint32_t binding, const RenderHandle handle)
398 {
399     BindImage(
400         binding, BindableImage { handle, PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS,
401                      PipelineStateConstants::GPU_IMAGE_ALL_LAYERS, ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED, {} });
402 }
403 
BindImage(const uint32_t binding,const RenderHandle handle,const RenderHandle samplerHandle)404 void DescriptorSetBinder::BindImage(const uint32_t binding, const RenderHandle handle, const RenderHandle samplerHandle)
405 {
406     BindImage(binding,
407         BindableImage { handle, PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS,
408             PipelineStateConstants::GPU_IMAGE_ALL_LAYERS, ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED, samplerHandle });
409 }
410 
BindImages(const uint32_t binding,const array_view<const BindableImage> resources)411 void DescriptorSetBinder::BindImages(const uint32_t binding, const array_view<const BindableImage> resources)
412 {
413     if ((!resources.empty()) && (binding < maxBindingCount_)) {
414         const uint32_t index = bindingToIndex_[binding];
415         if ((index < INVALID_BIDX) && CheckValidImageDescriptor(bindings_[index].binding.descriptorType)) {
416             const auto& bind = bindings_[index];
417             BindableImage& ref = images_[bind.resourceIndex].resource;
418             const uint32_t arrayOffset = images_[bind.resourceIndex].arrayOffset;
419             const ImageLayout defaultImageLayout = GetImageLayout(bind.binding.descriptorType);
420             const uint32_t maxCount = Math::min(static_cast<uint32_t>(resources.size()), bind.binding.descriptorCount);
421             PLUGIN_ASSERT((arrayOffset + maxCount - 1) <= images_.size());
422             for (uint32_t idx = 0; idx < maxCount; ++idx) {
423                 const BindableImage& currResource = resources[idx];
424                 const RenderHandle currHandle = currResource.handle;
425                 const bool validType = (RenderHandleUtil::GetHandleType(currHandle) == RenderHandleType::GPU_IMAGE);
426 #if (RENDER_VALIDATION_ENABLED == 1)
427                 if (!validType) {
428                     PLUGIN_LOG_E("RENDER_VALIDATION: DescriptorSetBinder::BindImages() invalid handle type (idx:%u)",
429                         static_cast<uint32_t>(idx));
430                 }
431 #endif
432                 if (validType) {
433                     BindableImage& bindableImage = (idx == 0) ? ref : images_[arrayOffset + idx - 1].resource;
434                     if (currResource.imageLayout != CORE_IMAGE_LAYOUT_UNDEFINED) {
435                         bindableImage.imageLayout = currResource.imageLayout;
436                     } else {
437                         bindableImage.imageLayout = (RenderHandleUtil::IsDepthImage(currResource.handle))
438                                                         ? ImageLayout::CORE_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
439                                                         : defaultImageLayout;
440                     }
441                     bindableImage.handle = currResource.handle;
442                     bindableImage.mip = currResource.mip;
443                     bindableImage.layer = currResource.layer;
444                     bindableImage.samplerHandle = currResource.samplerHandle;
445                     bindingMask_ |= (1 << binding);
446                 }
447             }
448 #if (RENDER_VALIDATION_ENABLED == 1)
449             if ((bind.binding.descriptorCount != resources.size())) {
450                 PLUGIN_LOG_E(
451                     "RENDER_VALIDATION: DescriptorSetBinder::BindImages() trying binding (%u) images to arrays (%u)",
452                     static_cast<uint32_t>(resources.size()), bind.binding.descriptorCount);
453             }
454 #endif
455         }
456     }
457 }
458 
BindSampler(const uint32_t binding,const BindableSampler & resource)459 void DescriptorSetBinder::BindSampler(const uint32_t binding, const BindableSampler& resource)
460 {
461     const bool validHandleType = (RenderHandleUtil::GetHandleType(resource.handle) == RenderHandleType::GPU_SAMPLER);
462     if ((binding < maxBindingCount_) && validHandleType) {
463         const uint32_t index = bindingToIndex_[binding];
464         if (index < INVALID_BIDX) {
465             const auto& bind = bindings_[index];
466             const DescriptorType descriptorType = bind.binding.descriptorType;
467             if (descriptorType == CORE_DESCRIPTOR_TYPE_SAMPLER) {
468                 samplers_[bind.resourceIndex].resource = resource;
469                 bindingMask_ |= (1 << binding);
470             } else {
471                 PLUGIN_LOG_E("invalid binding for sampler descriptor (binding: %u, descriptorType: %u)", binding,
472                     (uint32_t)descriptorType);
473             }
474         }
475     }
476 #if (RENDER_VALIDATION_ENABLED == 1)
477     if (!validHandleType) {
478         PLUGIN_LOG_ONCE_W("PipelineDescriptorSetBinder::BindSampler()",
479             "RENDER_VALIDATION: PipelineDescriptorSetBinder::BindSampler() invalid handle");
480     }
481 #endif
482 }
483 
BindSampler(const uint32_t binding,const RenderHandle handle)484 void DescriptorSetBinder::BindSampler(const uint32_t binding, const RenderHandle handle)
485 {
486     BindSampler(binding, BindableSampler { handle });
487 }
488 
BindSamplers(const uint32_t binding,const array_view<const BindableSampler> resources)489 void DescriptorSetBinder::BindSamplers(const uint32_t binding, const array_view<const BindableSampler> resources)
490 {
491     if ((!resources.empty()) && (binding < maxBindingCount_)) {
492         const uint32_t index = bindingToIndex_[binding];
493         if ((index < INVALID_BIDX) && (bindings_[index].binding.descriptorType == CORE_DESCRIPTOR_TYPE_SAMPLER)) {
494             const auto& bind = bindings_[index];
495             BindableSampler& ref = samplers_[bind.resourceIndex].resource;
496             const uint32_t arrayOffset = samplers_[bind.resourceIndex].arrayOffset;
497 #if (RENDER_VALIDATION_ENABLED == 1)
498             bool validationIssue = false;
499 #endif
500             const uint32_t maxCount = Math::min(static_cast<uint32_t>(resources.size()), bind.binding.descriptorCount);
501             PLUGIN_ASSERT((arrayOffset + maxCount - 1) <= samplers_.size());
502             for (uint32_t idx = 0; idx < maxCount; ++idx) {
503                 const RenderHandle currHandle = resources[idx].handle;
504                 const bool validType = (RenderHandleUtil::GetHandleType(currHandle) == RenderHandleType::GPU_SAMPLER);
505 #if (RENDER_VALIDATION_ENABLED == 1)
506                 if (!validType) {
507                     PLUGIN_LOG_E(
508                         "RENDER_VALIDATION: PipelineDescriptorSetBinder::BindSamplers() invalid handle type (index: "
509                         "%u)",
510                         static_cast<uint32_t>(idx));
511                 }
512                 if (bind.binding.descriptorCount != resources.size()) {
513                     validationIssue = true;
514                 }
515 #endif
516                 if (validType) {
517                     BindableSampler& bRes = (idx == 0) ? ref : samplers_[arrayOffset + idx - 1].resource;
518                     bRes = resources[idx];
519                     bindingMask_ |= (1 << binding);
520                 }
521             }
522 #if (RENDER_VALIDATION_ENABLED == 1)
523             if (validationIssue) {
524                 PLUGIN_LOG_E(
525                     "RENDER_VALIDATION: DescriptorSetBinder::BindSamplers() trying to bind (%u) samplers to set "
526                     "arrays (%u)",
527                     static_cast<uint32_t>(resources.size()), bind.binding.descriptorCount);
528             }
529 #endif
530         }
531     }
532 }
533 
Destroy()534 void DescriptorSetBinder::Destroy()
535 {
536     delete this;
537 }
538 
PipelineDescriptorSetBinder(const PipelineLayout & pipelineLayout,const array_view<const RenderHandle> handles,const array_view<const DescriptorSetLayoutBindings> descriptorSetsLayoutBindings)539 PipelineDescriptorSetBinder::PipelineDescriptorSetBinder(const PipelineLayout& pipelineLayout,
540     const array_view<const RenderHandle> handles,
541     const array_view<const DescriptorSetLayoutBindings> descriptorSetsLayoutBindings)
542 {
543     if ((pipelineLayout.descriptorSetCount != descriptorSetsLayoutBindings.size()) ||
544         (handles.size() != descriptorSetsLayoutBindings.size())) {
545         PLUGIN_LOG_E("pipeline layout counts does not match descriptor set layout bindings");
546     }
547 
548     descriptorSetBinders_.reserve(descriptorSetsLayoutBindings.size());
549     setIndices_.reserve(descriptorSetsLayoutBindings.size());
550     descriptorSetHandles_.reserve(descriptorSetsLayoutBindings.size());
551 
552     for (uint32_t setIdx = 0; setIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++setIdx) {
553         const auto& pipelineDescRef = pipelineLayout.descriptorSetLayouts[setIdx];
554         if (pipelineDescRef.set == PipelineLayoutConstants::INVALID_INDEX) {
555             continue;
556         }
557 
558         const uint32_t set = pipelineDescRef.set;
559         const auto& descRef = descriptorSetsLayoutBindings[setIdx];
560         const auto descHandle = handles[setIdx];
561 
562         // create binder
563         descriptorSetBinders_.emplace_back(descHandle, descRef.binding);
564         setIndices_.emplace_back(set);
565         descriptorSetHandles_.emplace_back(descHandle);
566 
567         vector<DescriptorSetLayoutBinding> dslb(pipelineDescRef.bindings.size());
568         for (size_t bindingIdx = 0; bindingIdx < pipelineDescRef.bindings.size(); ++bindingIdx) {
569             const auto& descPipelineRef = descRef.binding[bindingIdx];
570 #if (RENDER_VALIDATION_ENABLED == 1)
571             if (pipelineDescRef.bindings[bindingIdx].binding != descPipelineRef.binding) {
572                 PLUGIN_LOG_E(
573                     "RENDER_VALIDATION: pipeline layout binding does not match descriptor set layout binding or "
574                     "handle");
575             }
576 #endif
577 
578             dslb[bindingIdx] = descPipelineRef;
579 
580             setToBinderIndex_[set] = (uint32_t)setIdx;
581         }
582     }
583 }
584 
ClearBindings()585 void PipelineDescriptorSetBinder::ClearBindings()
586 {
587     for (auto& ref : descriptorSetBinders_) {
588         ref.ClearBindings();
589     }
590 }
591 
BindBuffer(const uint32_t set,const uint32_t binding,const BindableBuffer & resource)592 void PipelineDescriptorSetBinder::BindBuffer(const uint32_t set, const uint32_t binding, const BindableBuffer& resource)
593 {
594     if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
595         const uint32_t setIdx = setToBinderIndex_[set];
596         if (setIdx < static_cast<uint32_t>(descriptorSetBinders_.size())) {
597             descriptorSetBinders_[setIdx].BindBuffer(binding, resource);
598         }
599     }
600 }
601 
BindBuffers(const uint32_t set,const uint32_t binding,const array_view<const BindableBuffer> resources)602 void PipelineDescriptorSetBinder::BindBuffers(
603     const uint32_t set, const uint32_t binding, const array_view<const BindableBuffer> resources)
604 {
605     if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
606         const uint32_t setIdx = setToBinderIndex_[set];
607         if (setIdx < static_cast<uint32_t>(descriptorSetBinders_.size())) {
608             descriptorSetBinders_[setIdx].BindBuffers(binding, resources);
609         }
610     }
611 }
612 
BindImage(const uint32_t set,const uint32_t binding,const BindableImage & resource)613 void PipelineDescriptorSetBinder::BindImage(const uint32_t set, const uint32_t binding, const BindableImage& resource)
614 {
615     if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
616         const uint32_t setIdx = setToBinderIndex_[set];
617         if (setIdx < static_cast<uint32_t>(descriptorSetBinders_.size())) {
618             descriptorSetBinders_[setIdx].BindImage(binding, resource);
619         }
620     }
621 }
622 
BindImages(const uint32_t set,const uint32_t binding,const array_view<const BindableImage> resources)623 void PipelineDescriptorSetBinder::BindImages(
624     const uint32_t set, const uint32_t binding, const array_view<const BindableImage> resources)
625 {
626     if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
627         const uint32_t setIdx = setToBinderIndex_[set];
628         if (setIdx < static_cast<uint32_t>(descriptorSetBinders_.size())) {
629             descriptorSetBinders_[setIdx].BindImages(binding, resources);
630         }
631     }
632 }
633 
BindSampler(const uint32_t set,const uint32_t binding,const BindableSampler & resource)634 void PipelineDescriptorSetBinder::BindSampler(
635     const uint32_t set, const uint32_t binding, const BindableSampler& resource)
636 {
637     if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
638         const uint32_t setIdx = setToBinderIndex_[set];
639         if (setIdx < static_cast<uint32_t>(descriptorSetBinders_.size())) {
640             descriptorSetBinders_[setIdx].BindSampler(binding, resource);
641         }
642     }
643 }
644 
BindSamplers(const uint32_t set,const uint32_t binding,const array_view<const BindableSampler> resources)645 void PipelineDescriptorSetBinder::BindSamplers(
646     const uint32_t set, const uint32_t binding, const array_view<const BindableSampler> resources)
647 {
648     if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
649         const uint32_t setIdx = setToBinderIndex_[set];
650         if (setIdx < static_cast<uint32_t>(descriptorSetBinders_.size())) {
651             descriptorSetBinders_[setIdx].BindSamplers(binding, resources);
652         }
653     }
654 }
655 
GetDescriptorSetHandle(const uint32_t set) const656 RenderHandle PipelineDescriptorSetBinder::GetDescriptorSetHandle(const uint32_t set) const
657 {
658     if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
659         const uint32_t setIdx = setToBinderIndex_[set];
660         if (setIdx < static_cast<uint32_t>(descriptorSetBinders_.size())) {
661             return descriptorSetBinders_[setIdx].GetDescriptorSetHandle();
662         }
663     }
664     return {};
665 }
666 
GetDescriptorSetLayoutBindingResources(const uint32_t set) const667 DescriptorSetLayoutBindingResources PipelineDescriptorSetBinder::GetDescriptorSetLayoutBindingResources(
668     const uint32_t set) const
669 {
670     if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
671         const uint32_t setIdx = setToBinderIndex_[set];
672         if (setIdx < static_cast<uint32_t>(descriptorSetBinders_.size())) {
673             return descriptorSetBinders_[setIdx].GetDescriptorSetLayoutBindingResources();
674         }
675     }
676     return {};
677 }
678 
GetPipelineDescriptorSetLayoutBindingValidity() const679 bool PipelineDescriptorSetBinder::GetPipelineDescriptorSetLayoutBindingValidity() const
680 {
681     bool valid = true;
682     for (const auto& ref : descriptorSetBinders_) {
683         if (!ref.GetDescriptorSetLayoutBindingValidity()) {
684             valid = false;
685         }
686     }
687     return valid;
688 }
689 
GetDescriptorSetCount() const690 uint32_t PipelineDescriptorSetBinder::GetDescriptorSetCount() const
691 {
692     return (uint32_t)descriptorSetBinders_.size();
693 }
694 
GetSetIndices() const695 array_view<const uint32_t> PipelineDescriptorSetBinder::GetSetIndices() const
696 {
697     return array_view<const uint32_t>(setIndices_.data(), setIndices_.size());
698 }
699 
GetDescriptorSetHandles() const700 array_view<const RenderHandle> PipelineDescriptorSetBinder::GetDescriptorSetHandles() const
701 {
702     return { descriptorSetHandles_.data(), descriptorSetHandles_.size() };
703 }
704 
GetFirstSet() const705 uint32_t PipelineDescriptorSetBinder::GetFirstSet() const
706 {
707     uint32_t set = 0;
708     if (!setIndices_.empty()) {
709         set = setIndices_[0];
710     }
711     return set;
712 }
713 
GetDescriptorSetHandles(const uint32_t beginSet,const uint32_t count) const714 array_view<const RenderHandle> PipelineDescriptorSetBinder::GetDescriptorSetHandles(
715     const uint32_t beginSet, const uint32_t count) const
716 {
717     if (beginSet < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
718         const uint32_t setIdx = setToBinderIndex_[beginSet];
719         if (setIdx < static_cast<uint32_t>(descriptorSetBinders_.size())) {
720             const uint32_t maxCount = Math::min(count, static_cast<uint32_t>(descriptorSetHandles_.size()) - beginSet);
721 #if (RENDER_VALIDATION_ENABLED == 1)
722             if (setIdx + count > descriptorSetHandles_.size()) {
723                 PLUGIN_LOG_ONCE_W("PipelineDescriptorSetBinder::GetDescriptorSetHandles()",
724                     "RENDER_VALIDATION: PipelineDescriptorSetBinder::GetDescriptorSetHandles() count exceeds sets");
725             }
726 #endif
727 
728             return array_view<const RenderHandle>(&descriptorSetHandles_[setIdx], maxCount);
729         }
730     }
731     return {};
732 }
733 
Destroy()734 void PipelineDescriptorSetBinder::Destroy()
735 {
736     delete this;
737 }
738 RENDER_END_NAMESPACE()
739