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