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 "shader_pipeline_binder.h"
17
18 #include <algorithm>
19 #include <atomic>
20
21 #include <base/containers/allocator.h>
22 #include <base/containers/array_view.h>
23 #include <base/math/matrix_util.h>
24 #include <render/device/intf_shader_manager.h>
25 #include <render/device/pipeline_layout_desc.h>
26 #include <render/device/pipeline_state_desc.h>
27 #include <render/namespace.h>
28 #include <render/property/property_types.h>
29
30 #include "nodecontext/pipeline_descriptor_set_binder.h"
31 #include "util/log.h"
32 #include "util/property_util.h"
33
34 using namespace BASE_NS;
35 using namespace CORE_NS;
36
37 RENDER_BEGIN_NAMESPACE()
38 namespace {
39 constexpr uint32_t CUSTOM_PROPERTY_POD_CONTAINER_BYTE_SIZE { 256U };
40 constexpr string_view CUSTOM_PROPERTIES = "customProperties";
41 constexpr string_view CUSTOM_BINDING_PROPERTIES = "customBindingProperties";
42 constexpr string_view BINDING_PROPERTIES = "bindingProperties";
43 constexpr string_view CUSTOM_PROPERTY_DATA = "data";
44 constexpr string_view NAME = "name";
45 constexpr string_view DISPLAY_NAME = "displayName";
46 constexpr string_view DESCRIPTOR_SET = "set";
47 constexpr string_view DESCRIPTOR_SET_BINDING = "binding";
48
UpdateCustomPropertyMetadata(const json::value & customProperties,ShaderPipelineBinder::CustomPropertyData & cpd)49 void UpdateCustomPropertyMetadata(const json::value& customProperties, ShaderPipelineBinder::CustomPropertyData& cpd)
50 {
51 if (customProperties && customProperties.is_array() && cpd.properties) {
52 CustomPropertyPodContainer& properties = *cpd.properties;
53 for (const auto& ref : customProperties.array_) {
54 if (const auto customProps = ref.find(CUSTOM_PROPERTIES); customProps && customProps->is_array()) {
55 // process custom properties i.e. local factors
56 for (const auto& propRef : customProps->array_) {
57 if (const auto setProp = propRef.find(DESCRIPTOR_SET); setProp && setProp->is_number()) {
58 cpd.set = (uint32_t)setProp->unsigned_;
59 }
60 if (const auto setProp = propRef.find(DESCRIPTOR_SET_BINDING); setProp && setProp->is_number()) {
61 cpd.binding = (uint32_t)setProp->unsigned_;
62 }
63 if (const auto customData = propRef.find(CUSTOM_PROPERTY_DATA); customData) {
64 // reserve the property count
65 properties.ReservePropertyCount(customData->array_.size());
66 for (const auto& dataValue : customData->array_) {
67 if (dataValue.is_object()) {
68 string_view name;
69 string_view displayName;
70 string_view type;
71 const json::value* value = nullptr;
72 for (const auto& dataObject : dataValue.object_) {
73 if (dataObject.key == NAME && dataObject.value.is_string()) {
74 name = dataObject.value.string_;
75 } else if (dataObject.key == DISPLAY_NAME && dataObject.value.is_string()) {
76 displayName = dataObject.value.string_;
77 } else if (dataObject.key == "type" && dataObject.value.is_string()) {
78 type = dataObject.value.string_;
79 } else if (dataObject.key == "value") {
80 value = &dataObject.value;
81 }
82 }
83 const PropertyTypeDecl typeDecl =
84 CustomPropertyPodHelper::GetPropertyTypeDeclaration(type);
85 const size_t align = CustomPropertyPodHelper::GetPropertyTypeAlignment(typeDecl);
86 const size_t offset = [](size_t value, size_t align) -> size_t {
87 if (align == 0U) {
88 return value;
89 }
90 return ((value + align - 1U) / align) * align;
91 }(properties.GetByteSize(), align);
92
93 properties.AddOffsetProperty(name, displayName, offset, typeDecl);
94 CustomPropertyPodHelper::SetCustomPropertyBlobValue(
95 typeDecl, value, properties, offset);
96 }
97 }
98 }
99 }
100 }
101 }
102 }
103 }
104
UpdateBindingPropertyMetadata(const json::value & customProperties,CustomPropertyBindingContainer & properties,vector<ShaderPipelineBinder::BindingPropertyData::SetAndBinding> & setAndBindings)105 void UpdateBindingPropertyMetadata(const json::value& customProperties, CustomPropertyBindingContainer& properties,
106 vector<ShaderPipelineBinder::BindingPropertyData::SetAndBinding>& setAndBindings)
107 {
108 if (customProperties && customProperties.is_array()) {
109 for (const auto& ref : customProperties.array_) {
110 auto customProps = ref.find(BINDING_PROPERTIES);
111 if (!customProps) {
112 customProps = ref.find(CUSTOM_BINDING_PROPERTIES);
113 }
114 if (customProps && customProps->is_array()) {
115 setAndBindings.reserve(customProps->array_.size());
116 // process the array
117 for (const auto& propRef : customProps->array_) {
118 if (const auto customData = propRef.find(CUSTOM_PROPERTY_DATA); customData) {
119 // reserve the property count
120 properties.ReservePropertyCount(customData->array_.size());
121 for (const auto& dataValue : customData->array_) {
122 if (dataValue.is_object()) {
123 string_view name;
124 string_view displayName;
125 string_view type;
126 uint32_t set { ~0U };
127 uint32_t binding { ~0U };
128 for (const auto& dataObject : dataValue.object_) {
129 if (dataObject.key == NAME && dataObject.value.is_string()) {
130 name = dataObject.value.string_;
131 } else if (dataObject.key == DISPLAY_NAME && dataObject.value.is_string()) {
132 displayName = dataObject.value.string_;
133 } else if (dataObject.key == "type" && dataObject.value.is_string()) {
134 type = dataObject.value.string_;
135 } else if (dataObject.key == DESCRIPTOR_SET && dataObject.value.is_number()) {
136 set = (uint32_t)dataObject.value.unsigned_;
137 } else if (dataObject.key == DESCRIPTOR_SET_BINDING &&
138 dataObject.value.is_number()) {
139 binding = (uint32_t)dataObject.value.unsigned_;
140 }
141 }
142 set = Math::min(set, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT);
143 binding = Math::min(binding, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT);
144 setAndBindings.push_back({ set, binding });
145 const PropertyTypeDecl typeDecl =
146 CustomPropertyBindingHelper::GetPropertyTypeDeclaration(type);
147 const size_t align = CustomPropertyBindingHelper::GetPropertyTypeAlignment(typeDecl);
148 const size_t offset = [](size_t value, size_t align) -> size_t {
149 if (align == 0U) {
150 return value;
151 }
152 return ((value + align - 1U) / align) * align;
153 }(properties.GetByteSize(), align);
154 properties.AddOffsetProperty(name, displayName, offset, typeDecl);
155 }
156 }
157 }
158 }
159 }
160 }
161 }
162 }
163
CreatePipelineDescriptorSetBinder(const PipelineLayout & pipelineLayout)164 IPipelineDescriptorSetBinder::Ptr CreatePipelineDescriptorSetBinder(const PipelineLayout& pipelineLayout)
165 {
166 DescriptorSetLayoutBindings descriptorSetLayoutBindings[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT];
167 for (uint32_t idx = 0; idx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++idx) {
168 if (pipelineLayout.descriptorSetLayouts[idx].set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
169 descriptorSetLayoutBindings[idx] = { pipelineLayout.descriptorSetLayouts[idx].bindings };
170 }
171 }
172 // pass max amount to binder, it will check validity of sets and their set indices
173 return IPipelineDescriptorSetBinder::Ptr { new PipelineDescriptorSetBinder(
174 pipelineLayout, descriptorSetLayoutBindings) };
175 }
176 } // namespace
177
ShaderPipelineBinderPropertyBindingSignal(ShaderPipelineBinder & shaderPipelineBinder)178 ShaderPipelineBinderPropertyBindingSignal::ShaderPipelineBinderPropertyBindingSignal(
179 ShaderPipelineBinder& shaderPipelineBinder)
180 : shaderPipelineBinder_(shaderPipelineBinder)
181 {}
182
Signal()183 void ShaderPipelineBinderPropertyBindingSignal::Signal()
184 {
185 shaderPipelineBinder_.BindPropertyBindings();
186 }
187
ShaderPipelineBinder(IShaderManager & shaderMgr,const RenderHandleReference & shader,const PipelineLayout & pipelineLayout)188 ShaderPipelineBinder::ShaderPipelineBinder(
189 IShaderManager& shaderMgr, const RenderHandleReference& shader, const PipelineLayout& pipelineLayout)
190 : shaderMgr_(shaderMgr), shader_(shader), pipelineLayout_(pipelineLayout), renderHandleType_(shader.GetHandleType())
191 {
192 #if (RENDER_VALIDATION_ENABLED == 1)
193 if (!((renderHandleType_ == RenderHandleType::SHADER_STATE_OBJECT) ||
194 (renderHandleType_ == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT))) {
195 PLUGIN_LOG_W("RENDER_VALIDATION: Invalid handle for shader pipeline binder (type:%hhu)",
196 static_cast<uint8_t>(renderHandleType_));
197 }
198 #endif
199 InitCustomProperties();
200 pipelineDescriptorSetBinder_ = CreatePipelineDescriptorSetBinder(pipelineLayout_);
201 // process with pipeline descriptor set binder
202 if (pipelineDescriptorSetBinder_) {
203 const array_view<const uint32_t> setIndices = pipelineDescriptorSetBinder_->GetSetIndices();
204 descriptorSetResources_.resize(setIndices.size());
205 uint32_t vecIdx = 0U;
206 for (const auto& setIdx : setIndices) {
207 const DescriptorSetLayoutBindingResources descSetBindingRes =
208 pipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(setIdx);
209 auto& descSetRes = descriptorSetResources_[vecIdx];
210 // resize
211 descSetRes.bindings.resize(descSetBindingRes.bindings.size());
212 descSetRes.buffers.resize(descSetBindingRes.buffers.size());
213 descSetRes.images.resize(descSetBindingRes.images.size());
214 descSetRes.samplers.resize(descSetBindingRes.samplers.size());
215 // set bindings
216 for (size_t idx = 0; idx < descSetBindingRes.bindings.size(); ++idx) {
217 const auto& ref = descSetBindingRes.bindings[idx];
218 if (ref.binding.binding >= PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
219 continue;
220 }
221 // indirection
222 descSetRes.bindingToIndex[ref.binding.binding] = static_cast<uint8_t>(idx);
223
224 const RenderHandleType type = DescriptorSetBinderUtil::GetRenderHandleType(ref.binding.descriptorType);
225 descSetRes.bindings[idx].binding = ref.binding.binding;
226 descSetRes.bindings[idx].resIdx = ref.resourceIndex;
227 descSetRes.bindings[idx].type = type;
228 descSetRes.bindings[idx].descriptorCount = ref.binding.descriptorCount;
229 if (type == RenderHandleType::GPU_BUFFER) {
230 descSetRes.bindings[idx].arrayoffset = descSetBindingRes.buffers[ref.resourceIndex].arrayOffset;
231 } else if (type == RenderHandleType::GPU_IMAGE) {
232 descSetRes.bindings[idx].arrayoffset = descSetBindingRes.images[ref.resourceIndex].arrayOffset;
233 } else if (type == RenderHandleType::GPU_SAMPLER) {
234 descSetRes.bindings[idx].arrayoffset = descSetBindingRes.samplers[ref.resourceIndex].arrayOffset;
235 }
236 }
237 setToBinderIndex_[setIdx] = vecIdx++;
238 }
239 }
240 if (pipelineLayout_.pushConstant.byteSize > 0) {
241 pushData_.resize(pipelineLayout_.pushConstant.byteSize);
242 std::fill(pushData_.begin(), pushData_.end(), uint8_t(0));
243 }
244 EvaluateCustomPropertyBindings();
245 }
246
InitCustomProperties()247 void ShaderPipelineBinder::InitCustomProperties()
248 {
249 // fetch custom properties if any
250 if (const auto* metaJson = shaderMgr_.GetMaterialMetadata(shader_); (metaJson && metaJson->is_array())) {
251 customPropertyData_.properties =
252 make_unique<CustomPropertyPodContainer>(CUSTOM_PROPERTY_POD_CONTAINER_BYTE_SIZE);
253 bindingPropertyData_.bindingSignal = make_unique<ShaderPipelineBinderPropertyBindingSignal>(*this);
254 if (bindingPropertyData_.bindingSignal) {
255 bindingPropertyData_.properties =
256 make_unique<CustomPropertyBindingContainer>(*bindingPropertyData_.bindingSignal);
257 }
258 if (customPropertyData_.properties && bindingPropertyData_.properties) {
259 UpdateCustomPropertyMetadata(*metaJson, customPropertyData_);
260 customPropertyData_.handle = customPropertyData_.properties.get();
261
262 UpdateBindingPropertyMetadata(
263 *metaJson, *bindingPropertyData_.properties, bindingPropertyData_.setAndBindings);
264 bindingPropertyData_.handle = bindingPropertyData_.properties.get();
265 }
266 }
267 }
268
EvaluateCustomPropertyBindings()269 void ShaderPipelineBinder::EvaluateCustomPropertyBindings()
270 {
271 #if (RENDER_VALIDATION_ENABLED == 1)
272 for (uint32_t setIdx = 0; setIdx < static_cast<uint32_t>(descriptorSetResources_.size()); ++setIdx) {
273 const auto& descRef = descriptorSetResources_[setIdx];
274 const auto& plSet = pipelineLayout_.descriptorSetLayouts[setIdx];
275 const bool bindingCountMismatch = (descRef.bindings.size() != plSet.bindings.size());
276 if (!bindingCountMismatch) {
277 for (size_t idx = 0; idx < descRef.bindings.size(); ++idx) {
278 const auto& bindingRef = descRef.bindings[idx];
279 const auto& plBindingRef = plSet.bindings[idx];
280 const RenderHandleType plDescType =
281 DescriptorSetBinderUtil::GetRenderHandleType(plBindingRef.descriptorType);
282 if (bindingRef.binding != plBindingRef.binding) {
283 CORE_LOG_W("RENDER_VALIDATION: Binding property descriptor set binding missmatch to pipeline "
284 "layout (set: %u, bindingIdx %u != bindingIdx %u)",
285 setIdx, bindingRef.binding, plBindingRef.binding);
286 }
287 if (bindingRef.type != plDescType) {
288 CORE_LOG_W("RENDER_VALIDATION: Binding property descriptor set binding missmatch to pipeline "
289 "layout (set: %u, binding: %u)",
290 setIdx, bindingRef.binding);
291 }
292 }
293 } else {
294 CORE_LOG_W("RENDER_VALIDATION: Binding property descriptor set binding count missmatch."
295 "(set: %u, bindings: %u != bindings: %u",
296 setIdx, static_cast<uint32_t>(descRef.bindings.size()), static_cast<uint32_t>(plSet.bindings.size()));
297 }
298 }
299 #endif
300 }
301
ClearBindings()302 void ShaderPipelineBinder::ClearBindings()
303 {
304 auto ClearResourcesBindings = [](auto& resources) {
305 for (auto& ref : resources) {
306 ref = {};
307 }
308 };
309
310 for (auto& descRef : descriptorSetResources_) {
311 ClearResourcesBindings(descRef.buffers);
312 ClearResourcesBindings(descRef.images);
313 ClearResourcesBindings(descRef.samplers);
314 }
315 if (pipelineDescriptorSetBinder_) {
316 pipelineDescriptorSetBinder_->ClearBindings();
317 }
318 }
319
GetBindingValidity() const320 bool ShaderPipelineBinder::GetBindingValidity() const
321 {
322 bool valid = true;
323 auto checkValidity = [](const auto& vec, bool& valid) {
324 for (const auto& ref : vec) {
325 if (!ref.handle) {
326 valid = false;
327 }
328 }
329 };
330 for (const auto& ref : descriptorSetResources_) {
331 checkValidity(ref.buffers, valid);
332 checkValidity(ref.images, valid);
333 checkValidity(ref.samplers, valid);
334 }
335 return valid;
336 }
337
GetShaderHandle() const338 RenderHandleReference ShaderPipelineBinder::GetShaderHandle() const
339 {
340 return shader_;
341 }
342
Bind(const uint32_t set,const uint32_t binding,const RenderHandleReference & handle)343 void ShaderPipelineBinder::Bind(const uint32_t set, const uint32_t binding, const RenderHandleReference& handle)
344 {
345 const RenderHandleType type = handle.GetHandleType();
346 if (type == RenderHandleType::GPU_BUFFER) {
347 BindBuffer(set, binding, { handle, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
348 } else if (type == RenderHandleType::GPU_IMAGE) {
349 BindImage(set, binding,
350 { handle, PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS,
351 ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED, {} });
352 } else if (type == RenderHandleType::GPU_SAMPLER) {
353 BindSampler(set, binding, { handle });
354 }
355 }
356
SetUniformData(const uint32_t set,const uint32_t binding,const array_view<const uint8_t> data)357 void ShaderPipelineBinder::SetUniformData(
358 const uint32_t set, const uint32_t binding, const array_view<const uint8_t> data)
359 {
360 // not yet supported
361 PLUGIN_ASSERT(false);
362 }
363
SetPushConstantData(const array_view<const uint8_t> data)364 void ShaderPipelineBinder::SetPushConstantData(const array_view<const uint8_t> data)
365 {
366 if ((pipelineLayout_.pushConstant.byteSize > 0) && (!data.empty())) {
367 const size_t maxByteSize = Math::min(pushData_.size_in_bytes(), data.size_bytes());
368 CloneData(pushData_.data(), pushData_.size_in_bytes(), data.data(), maxByteSize);
369 }
370 }
371
BindBuffer(const uint32_t set,const uint32_t binding,const BindableBufferWithHandleReference & resource)372 void ShaderPipelineBinder::BindBuffer(
373 const uint32_t set, const uint32_t binding, const BindableBufferWithHandleReference& resource)
374 {
375 if (resource.handle && set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
376 const uint32_t setIdx = setToBinderIndex_[set];
377 if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
378 const RenderHandleType type = resource.handle.GetHandleType();
379 auto& setResources = descriptorSetResources_[setIdx];
380 bool validBinding = false;
381 if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
382 const uint32_t idx = setResources.bindingToIndex[binding];
383 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
384 const uint32_t resIdx = setResources.bindings[idx].resIdx;
385 if (resIdx < setResources.buffers.size()) {
386 validBinding = true;
387 setResources.buffers[resIdx] = resource;
388 }
389 }
390 }
391 if (validBinding && pipelineDescriptorSetBinder_) {
392 const BindableBuffer bindable {
393 resource.handle.GetHandle(),
394 resource.byteOffset,
395 resource.byteSize,
396 };
397 pipelineDescriptorSetBinder_->BindBuffer(set, binding, bindable);
398 }
399 }
400 }
401 }
402
BindBuffers(const uint32_t set,const uint32_t binding,const array_view<const BindableBufferWithHandleReference> resources)403 void ShaderPipelineBinder::BindBuffers(
404 const uint32_t set, const uint32_t binding, const array_view<const BindableBufferWithHandleReference> resources)
405 {
406 if ((!resources.empty()) && set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
407 const uint32_t setIdx = setToBinderIndex_[set];
408 if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
409 const RenderHandleType type = resources[0].handle.GetHandleType();
410 auto& setResources = descriptorSetResources_[setIdx];
411 bool validBinding = false;
412 if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
413 const uint32_t idx = setResources.bindingToIndex[binding];
414 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
415 const uint32_t resIdx = setResources.bindings[idx].resIdx;
416 if (resIdx < setResources.buffers.size()) {
417 validBinding = true;
418 setResources.buffers[resIdx] = resources[0];
419 }
420 }
421 }
422 if (validBinding && pipelineDescriptorSetBinder_) {
423 vector<BindableBuffer> bindables;
424 bindables.resize(resources.size());
425 for (size_t idx = 0; idx < resources.size(); ++idx) {
426 const auto& rRef = resources[idx];
427 bindables[idx] = BindableBuffer { rRef.handle.GetHandle(), rRef.byteOffset, rRef.byteSize };
428 }
429 pipelineDescriptorSetBinder_->BindBuffers(set, binding, bindables);
430 }
431 }
432 }
433 }
434
BindImage(const uint32_t set,const uint32_t binding,const BindableImageWithHandleReference & resource)435 void ShaderPipelineBinder::BindImage(
436 const uint32_t set, const uint32_t binding, const BindableImageWithHandleReference& resource)
437 {
438 if (resource.handle && (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT)) {
439 const uint32_t setIdx = setToBinderIndex_[set];
440 if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
441 const RenderHandleType type = resource.handle.GetHandleType();
442 auto& setResources = descriptorSetResources_[setIdx];
443 bool validBinding = false;
444 if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
445 const uint32_t idx = setResources.bindingToIndex[binding];
446 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
447 const uint32_t resIdx = setResources.bindings[idx].resIdx;
448 if (resIdx < setResources.images.size()) {
449 validBinding = true;
450 setResources.images[resIdx] = resource;
451 }
452 }
453 }
454 if (validBinding && pipelineDescriptorSetBinder_) {
455 const BindableImage bindable {
456 resource.handle.GetHandle(),
457 resource.mip,
458 resource.layer,
459 ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED,
460 resource.samplerHandle.GetHandle(),
461 };
462 pipelineDescriptorSetBinder_->BindImage(set, binding, bindable);
463 }
464 }
465 }
466 }
467
BindImages(const uint32_t set,const uint32_t binding,array_view<const BindableImageWithHandleReference> resources)468 void ShaderPipelineBinder::BindImages(
469 const uint32_t set, const uint32_t binding, array_view<const BindableImageWithHandleReference> resources)
470 {
471 if ((!resources.empty()) && (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT)) {
472 const uint32_t setIdx = setToBinderIndex_[set];
473 if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
474 const RenderHandleType type = resources[0U].handle.GetHandleType();
475 auto& setResources = descriptorSetResources_[setIdx];
476 bool validBinding = false;
477 if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
478 const uint32_t idx = setResources.bindingToIndex[binding];
479 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
480 const uint32_t resIdx = setResources.bindings[idx].resIdx;
481 if (resIdx < setResources.images.size()) {
482 validBinding = true;
483 setResources.images[resIdx] = resources[0U];
484 }
485 }
486 }
487 if (validBinding && pipelineDescriptorSetBinder_) {
488 vector<BindableImage> bindables;
489 bindables.resize(resources.size());
490 for (size_t idx = 0; idx < resources.size(); ++idx) {
491 const auto& rRef = resources[idx];
492 bindables[idx] = BindableImage { rRef.handle.GetHandle(), rRef.mip, rRef.layer,
493 ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED, rRef.samplerHandle.GetHandle() };
494 }
495 pipelineDescriptorSetBinder_->BindImages(set, binding, bindables);
496 }
497 }
498 }
499 }
500
BindSampler(const uint32_t set,const uint32_t binding,const BindableSamplerWithHandleReference & resource)501 void ShaderPipelineBinder::BindSampler(
502 const uint32_t set, const uint32_t binding, const BindableSamplerWithHandleReference& resource)
503 {
504 if (resource.handle && (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT)) {
505 const uint32_t setIdx = setToBinderIndex_[set];
506 if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
507 const RenderHandleType type = resource.handle.GetHandleType();
508 auto& setResources = descriptorSetResources_[setIdx];
509 bool validBinding = false;
510 if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
511 const uint32_t idx = setResources.bindingToIndex[binding];
512 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
513 const uint32_t resIdx = setResources.bindings[idx].resIdx;
514 if (resIdx < setResources.samplers.size()) {
515 validBinding = true;
516 setResources.samplers[resIdx] = resource;
517 }
518 }
519 }
520 if (validBinding && pipelineDescriptorSetBinder_) {
521 const BindableSampler bindable {
522 resource.handle.GetHandle(),
523 };
524 pipelineDescriptorSetBinder_->BindSampler(set, binding, bindable);
525 }
526 }
527 }
528 }
529
BindSamplers(const uint32_t set,const uint32_t binding,array_view<const BindableSamplerWithHandleReference> resources)530 void ShaderPipelineBinder::BindSamplers(
531 const uint32_t set, const uint32_t binding, array_view<const BindableSamplerWithHandleReference> resources)
532 {
533 if ((!resources.empty()) && (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT)) {
534 const uint32_t setIdx = setToBinderIndex_[set];
535 if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
536 const RenderHandleType type = resources[0U].handle.GetHandleType();
537 auto& setResources = descriptorSetResources_[setIdx];
538 bool validBinding = false;
539 if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
540 const uint32_t idx = setResources.bindingToIndex[binding];
541 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
542 const uint32_t resIdx = setResources.bindings[idx].resIdx;
543 if (resIdx < setResources.samplers.size()) {
544 validBinding = true;
545 setResources.samplers[resIdx] = resources[0U];
546 }
547 }
548 }
549 if (validBinding && pipelineDescriptorSetBinder_) {
550 vector<BindableSampler> bindables;
551 bindables.resize(resources.size());
552 for (size_t idx = 0; idx < resources.size(); ++idx) {
553 const auto& rRef = resources[idx];
554 bindables[idx] = BindableSampler { rRef.handle.GetHandle() };
555 }
556 pipelineDescriptorSetBinder_->BindSamplers(set, binding, bindables);
557 }
558 }
559 }
560 }
561
BindVertexBuffers(BASE_NS::array_view<const VertexBufferWithHandleReference> vertexBuffers)562 void ShaderPipelineBinder::BindVertexBuffers(BASE_NS::array_view<const VertexBufferWithHandleReference> vertexBuffers)
563 {
564 vertexBuffers_.clear();
565 vertexBuffers_.append(vertexBuffers.begin(), vertexBuffers.end());
566 }
567
BindIndexBuffer(const IndexBufferWithHandleReference & indexBuffer)568 void ShaderPipelineBinder::BindIndexBuffer(const IndexBufferWithHandleReference& indexBuffer)
569 {
570 indexBuffer_ = indexBuffer;
571 }
572
SetDrawCommand(const DrawCommand & drawCommand)573 void ShaderPipelineBinder::SetDrawCommand(const DrawCommand& drawCommand)
574 {
575 drawCommand_ = drawCommand;
576 }
577
SetDispatchCommand(const DispatchCommand & dispatchCommand)578 void ShaderPipelineBinder::SetDispatchCommand(const DispatchCommand& dispatchCommand)
579 {
580 dispatchCommand_ = dispatchCommand;
581 }
582
GetDescriptorSetLayoutBindingResources(const uint32_t set) const583 DescriptorSetLayoutBindingResources ShaderPipelineBinder::GetDescriptorSetLayoutBindingResources(
584 const uint32_t set) const
585 {
586 if (pipelineDescriptorSetBinder_) {
587 return pipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(set);
588 } else {
589 return {};
590 }
591 }
592
GetPushConstantData() const593 array_view<const uint8_t> ShaderPipelineBinder::GetPushConstantData() const
594 {
595 return pushData_;
596 }
597
GetProperties()598 IPropertyHandle* ShaderPipelineBinder::GetProperties()
599 {
600 return customPropertyData_.handle;
601 }
602
GetBindingProperties()603 IPropertyHandle* ShaderPipelineBinder::GetBindingProperties()
604 {
605 return bindingPropertyData_.handle;
606 }
607
GetResourceBinding(uint32_t set,uint32_t binding) const608 IShaderPipelineBinder::ResourceBinding ShaderPipelineBinder::GetResourceBinding(uint32_t set, uint32_t binding) const
609 {
610 if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
611 const uint32_t setIdx = setToBinderIndex_[set];
612 if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
613 const auto& setResources = descriptorSetResources_[setIdx];
614 if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
615 const uint32_t idx = setResources.bindingToIndex[binding];
616 if (idx < setResources.bindings.size()) {
617 IShaderPipelineBinder::ResourceBinding rb;
618 const auto& resBinding = setResources.bindings[idx];
619 rb.set = set;
620 rb.binding = binding;
621 rb.arrayOffset = resBinding.arrayoffset;
622 rb.descriptorCount = resBinding.descriptorCount;
623 if ((resBinding.type == RenderHandleType::GPU_BUFFER) &&
624 (resBinding.resIdx < setResources.buffers.size())) {
625 rb.handle = setResources.buffers[resBinding.resIdx].handle;
626 } else if ((resBinding.type == RenderHandleType::GPU_IMAGE) &&
627 (resBinding.resIdx < setResources.images.size())) {
628 rb.handle = setResources.images[resBinding.resIdx].handle;
629 } else if ((resBinding.type == RenderHandleType::GPU_SAMPLER) &&
630 (resBinding.resIdx < setResources.samplers.size())) {
631 rb.handle = setResources.samplers[resBinding.resIdx].handle;
632 }
633 return rb;
634 }
635 }
636 }
637 }
638 return {};
639 }
640
GetPropertyBindingView() const641 IShaderPipelineBinder::PropertyBindingView ShaderPipelineBinder::GetPropertyBindingView() const
642 {
643 PropertyBindingView cpbv;
644 cpbv.set = customPropertyData_.set;
645 cpbv.binding = customPropertyData_.binding;
646 cpbv.data =
647 (customPropertyData_.properties) ? customPropertyData_.properties->GetData() : array_view<const uint8_t> {};
648 return cpbv;
649 }
650
GetPropertyBindingByteSize() const651 uint32_t ShaderPipelineBinder::GetPropertyBindingByteSize() const
652 {
653 return (customPropertyData_.properties) ? static_cast<uint32_t>(customPropertyData_.properties->GetByteSize()) : 0U;
654 }
655
GetVertexBuffers() const656 array_view<const VertexBufferWithHandleReference> ShaderPipelineBinder::GetVertexBuffers() const
657 {
658 return vertexBuffers_;
659 }
660
GetIndexBuffer() const661 IndexBufferWithHandleReference ShaderPipelineBinder::GetIndexBuffer() const
662 {
663 return indexBuffer_;
664 }
665
GetDrawCommand() const666 IShaderPipelineBinder::DrawCommand ShaderPipelineBinder::GetDrawCommand() const
667 {
668 return drawCommand_;
669 }
670
GetDispatchCommand() const671 IShaderPipelineBinder::DispatchCommand ShaderPipelineBinder::GetDispatchCommand() const
672 {
673 return dispatchCommand_;
674 }
675
BindPropertyBindings()676 void ShaderPipelineBinder::BindPropertyBindings()
677 {
678 // fetch the bindings from properties, and try to bind them
679 if (bindingPropertyData_.properties && (bindingPropertyData_.properties->PropertyCount() > 0)) {
680 auto* bindingProperties = bindingPropertyData_.properties.get();
681 #if (RENDER_VALIDATION_ENABLED == 1)
682 if (bindingProperties->Owner()->MetaData().size() != bindingPropertyData_.setAndBindings.size()) {
683 PLUGIN_LOG_ONCE_W(
684 "ShaderPipelineBinder::BindPropertyBindings" + to_string(bindingPropertyData_.setAndBindings.size()),
685 "RENDER_VALIDATION: Shader pipeline binder property metadata size missmatch.");
686 }
687 #endif
688 const size_t count =
689 Math::min(bindingProperties->Owner()->MetaData().size(), bindingPropertyData_.setAndBindings.size());
690 for (size_t idx = 0; idx < count; ++idx) {
691 // the ordering should match with the bindings in the .shader file
692 const auto& prop = bindingProperties->Owner()->MetaData()[idx];
693 const auto& sb = bindingPropertyData_.setAndBindings[idx];
694 switch (prop.type) {
695 case PropertyType::BINDABLE_BUFFER_WITH_HANDLE_REFERENCE_T: {
696 BindBuffer(sb.set, sb.binding, bindingProperties->GetValue<BindableBufferWithHandleReference>(idx));
697 break;
698 }
699 case PropertyType::BINDABLE_IMAGE_WITH_HANDLE_REFERENCE_T: {
700 BindImage(sb.set, sb.binding, bindingProperties->GetValue<BindableImageWithHandleReference>(idx));
701 break;
702 }
703 case PropertyType::BINDABLE_SAMPLER_WITH_HANDLE_REFERENCE_T: {
704 BindSampler(sb.set, sb.binding,
705 bindingProperties->GetValue<BindableSamplerWithHandleReference>(idx));
706 break;
707 }
708 default: {
709 break;
710 }
711 }
712 }
713 }
714 }
715
GetPipelineLayout() const716 PipelineLayout ShaderPipelineBinder::GetPipelineLayout() const
717 {
718 return pipelineLayout_;
719 }
720
GetPipelineDescriptorSetBinder() const721 IPipelineDescriptorSetBinder* ShaderPipelineBinder::GetPipelineDescriptorSetBinder() const
722 {
723 if (pipelineDescriptorSetBinder_) {
724 return pipelineDescriptorSetBinder_.get();
725 } else {
726 return nullptr;
727 }
728 }
729
Ref()730 void ShaderPipelineBinder::Ref()
731 {
732 refcnt_.fetch_add(1, std::memory_order_relaxed);
733 }
734
Unref()735 void ShaderPipelineBinder::Unref()
736 {
737 if (std::atomic_fetch_sub_explicit(&refcnt_, 1, std::memory_order_release) == 1) {
738 std::atomic_thread_fence(std::memory_order_acquire);
739 delete this;
740 }
741 }
742 RENDER_END_NAMESPACE()
743