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