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