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