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