1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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 = static_cast<uint32_t>(setProp->unsigned_);
59                     }
60                     if (const auto setProp = propRef.find(DESCRIPTOR_SET_BINDING); setProp && setProp->is_number()) {
61                         cpd.binding = static_cast<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 = static_cast<uint32_t>(dataObject.value.unsigned_);
137                                     } else if (dataObject.key == DESCRIPTOR_SET_BINDING &&
138                                                dataObject.value.is_number()) {
139                                         binding = static_cast<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 
177 struct DescriptorCountValues {
178     uint32_t count { 0U };
179     uint32_t arrayCount { 0U };
180 };
181 } // namespace
182 
ShaderPipelineBinderPropertyBindingSignal(ShaderPipelineBinder & shaderPipelineBinder)183 ShaderPipelineBinderPropertyBindingSignal::ShaderPipelineBinderPropertyBindingSignal(
184     ShaderPipelineBinder& shaderPipelineBinder)
185     : shaderPipelineBinder_(shaderPipelineBinder)
186 {}
187 
Signal()188 void ShaderPipelineBinderPropertyBindingSignal::Signal()
189 {
190     shaderPipelineBinder_.BindPropertyBindings();
191 }
192 
ShaderPipelineBinder(IShaderManager & shaderMgr,const RenderHandleReference & shader,const PipelineLayout & pipelineLayout)193 ShaderPipelineBinder::ShaderPipelineBinder(
194     IShaderManager& shaderMgr, const RenderHandleReference& shader, const PipelineLayout& pipelineLayout)
195     : shaderMgr_(shaderMgr), shader_(shader), pipelineLayout_(pipelineLayout), renderHandleType_(shader.GetHandleType())
196 {
197 #if (RENDER_VALIDATION_ENABLED == 1)
198     if (!((renderHandleType_ == RenderHandleType::SHADER_STATE_OBJECT) ||
199             (renderHandleType_ == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT))) {
200         PLUGIN_LOG_W("RENDER_VALIDATION: Invalid handle for shader pipeline binder (type:%hhu)", renderHandleType_);
201     }
202 #endif
203     InitCustomProperties();
204     pipelineDescriptorSetBinder_ = CreatePipelineDescriptorSetBinder(pipelineLayout_);
205     // process with pipeline descriptor set binder
206     if (pipelineDescriptorSetBinder_) {
207         const array_view<const uint32_t> setIndices = pipelineDescriptorSetBinder_->GetSetIndices();
208         descriptorSetResources_.resize(setIndices.size());
209         uint32_t vecIdx = 0U;
210         for (const auto& setIdx : setIndices) {
211             const DescriptorSetLayoutBindingResources descSetBindingRes =
212                 pipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(setIdx);
213             auto& descSetRes = descriptorSetResources_[vecIdx];
214             // resize
215             descSetRes.bindings.resize(descSetBindingRes.bindings.size());
216             descSetRes.buffers.resize(descSetBindingRes.buffers.size());
217             descSetRes.images.resize(descSetBindingRes.images.size());
218             descSetRes.samplers.resize(descSetBindingRes.samplers.size());
219             // set bindings
220             for (size_t idx = 0; idx < descSetBindingRes.bindings.size(); ++idx) {
221                 const auto& ref = descSetBindingRes.bindings[idx];
222                 if (ref.binding.binding >= PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
223                     continue;
224                 }
225                 // indirection
226                 descSetRes.bindingToIndex[ref.binding.binding] = static_cast<uint8_t>(idx);
227 
228                 const RenderHandleType type = DescriptorSetBinderUtil::GetRenderHandleType(ref.binding.descriptorType);
229                 descSetRes.bindings[idx].binding = ref.binding.binding;
230                 descSetRes.bindings[idx].resIdx = ref.resourceIndex;
231                 descSetRes.bindings[idx].type = type;
232                 descSetRes.bindings[idx].descriptorCount = ref.binding.descriptorCount;
233                 if (type == RenderHandleType::GPU_BUFFER) {
234                     descSetRes.bindings[idx].arrayoffset = descSetBindingRes.buffers[ref.resourceIndex].arrayOffset;
235                 } else if (type == RenderHandleType::GPU_IMAGE) {
236                     descSetRes.bindings[idx].arrayoffset = descSetBindingRes.images[ref.resourceIndex].arrayOffset;
237                 } else if (type == RenderHandleType::GPU_SAMPLER) {
238                     descSetRes.bindings[idx].arrayoffset = descSetBindingRes.samplers[ref.resourceIndex].arrayOffset;
239                 }
240             }
241             setToBinderIndex_[setIdx] = vecIdx++;
242         }
243     }
244     if (pipelineLayout_.pushConstant.byteSize > 0) {
245         pushData_.resize(pipelineLayout_.pushConstant.byteSize);
246         std::fill(pushData_.begin(), pushData_.end(), uint8_t(0));
247     }
248     EvaluateCustomPropertyBindings();
249 }
250 
InitCustomProperties()251 void ShaderPipelineBinder::InitCustomProperties()
252 {
253     // fetch custom properties if any
254     if (const auto* metaJson = shaderMgr_.GetMaterialMetadata(shader_); (metaJson && metaJson->is_array())) {
255         customPropertyData_.properties =
256             make_unique<CustomPropertyPodContainer>(CUSTOM_PROPERTY_POD_CONTAINER_BYTE_SIZE);
257         bindingPropertyData_.bindingSignal = make_unique<ShaderPipelineBinderPropertyBindingSignal>(*this);
258         if (bindingPropertyData_.bindingSignal) {
259             bindingPropertyData_.properties =
260                 make_unique<CustomPropertyBindingContainer>(*bindingPropertyData_.bindingSignal);
261         }
262         if (customPropertyData_.properties && bindingPropertyData_.properties) {
263             UpdateCustomPropertyMetadata(*metaJson, customPropertyData_);
264             customPropertyData_.handle = customPropertyData_.properties.get();
265 
266             UpdateBindingPropertyMetadata(
267                 *metaJson, *bindingPropertyData_.properties, bindingPropertyData_.setAndBindings);
268             bindingPropertyData_.handle = bindingPropertyData_.properties.get();
269         }
270     }
271 }
272 
EvaluateCustomPropertyBindings()273 void ShaderPipelineBinder::EvaluateCustomPropertyBindings()
274 {
275 #if (RENDER_VALIDATION_ENABLED == 1)
276     for (uint32_t setIdx = 0; setIdx < static_cast<uint32_t>(descriptorSetResources_.size()); ++setIdx) {
277         const auto& descRef = descriptorSetResources_[setIdx];
278         const auto& plSet = pipelineLayout_.descriptorSetLayouts[setIdx];
279         for (const auto& bindingRef : descRef.bindings) {
280             bool valid = (bindingRef.binding < static_cast<uint32_t>(plSet.bindings.size()));
281             if (valid) {
282                 const RenderHandleType plDescType =
283                     DescriptorSetBinderUtil::GetRenderHandleType(plSet.bindings[bindingRef.binding].descriptorType);
284                 valid = valid && (bindingRef.type != plDescType);
285             }
286             if (valid) {
287                 CORE_LOG_W("RENDER_VALIDATION: Binding property descriptor set binding missmatch to pipeline layout "
288                            "(set: %u, binding: %u)",
289                     setIdx, bindingRef.binding);
290             }
291         }
292     }
293 #endif
294 }
295 
ClearBindings()296 void ShaderPipelineBinder::ClearBindings()
297 {
298     auto ClearResourcesBindings = [](auto& resources) {
299         for (auto& ref : resources) {
300             ref = {};
301         }
302     };
303 
304     for (auto& descRef : descriptorSetResources_) {
305         ClearResourcesBindings(descRef.buffers);
306         ClearResourcesBindings(descRef.images);
307         ClearResourcesBindings(descRef.samplers);
308     }
309     if (pipelineDescriptorSetBinder_) {
310         pipelineDescriptorSetBinder_->ClearBindings();
311     }
312 }
313 
GetBindingValidity() const314 bool ShaderPipelineBinder::GetBindingValidity() const
315 {
316     bool valid = true;
317     auto checkValidity = [](const auto& vec, bool& valid) {
318         for (const auto& ref : vec) {
319             if (!ref.handle) {
320                 valid = false;
321             }
322         }
323     };
324     for (const auto& ref : descriptorSetResources_) {
325         checkValidity(ref.buffers, valid);
326         checkValidity(ref.images, valid);
327         checkValidity(ref.samplers, valid);
328     }
329     return valid;
330 }
331 
GetShaderHandle() const332 RenderHandleReference ShaderPipelineBinder::GetShaderHandle() const
333 {
334     return shader_;
335 }
336 
Bind(const uint32_t set,const uint32_t binding,const RenderHandleReference & handle)337 void ShaderPipelineBinder::Bind(const uint32_t set, const uint32_t binding, const RenderHandleReference& handle)
338 {
339     const RenderHandleType type = handle.GetHandleType();
340     if (type == RenderHandleType::GPU_BUFFER) {
341         BindBuffer(set, binding, { handle, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
342     } else if (type == RenderHandleType::GPU_IMAGE) {
343         BindImage(set, binding,
344             { handle, PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS,
345                 {} });
346     } else if (type == RenderHandleType::GPU_SAMPLER) {
347         BindSampler(set, binding, { handle });
348     }
349 }
350 
SetUniformData(const uint32_t set,const uint32_t binding,const array_view<const uint8_t> data)351 void ShaderPipelineBinder::SetUniformData(
352     const uint32_t set, const uint32_t binding, const array_view<const uint8_t> data)
353 {
354     // not yet supported
355     PLUGIN_ASSERT(false);
356 }
357 
SetPushConstantData(const array_view<const uint8_t> data)358 void ShaderPipelineBinder::SetPushConstantData(const array_view<const uint8_t> data)
359 {
360     if ((pipelineLayout_.pushConstant.byteSize > 0) && (!data.empty())) {
361         const size_t maxByteSize = Math::min(pushData_.size_in_bytes(), data.size_bytes());
362         CloneData(pushData_.data(), pushData_.size_in_bytes(), data.data(), maxByteSize);
363     }
364 }
365 
BindBuffer(const uint32_t set,const uint32_t binding,const BindableBufferWithHandleReference & resource)366 void ShaderPipelineBinder::BindBuffer(
367     const uint32_t set, const uint32_t binding, const BindableBufferWithHandleReference& resource)
368 {
369     if (resource.handle && set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
370         const uint32_t setIdx = setToBinderIndex_[set];
371         if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
372             const RenderHandleType type = resource.handle.GetHandleType();
373             auto& setResources = descriptorSetResources_[setIdx];
374             bool validBinding = false;
375             if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
376                 const uint32_t idx = setResources.bindingToIndex[binding];
377                 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
378                     const uint32_t resIdx = setResources.bindings[idx].resIdx;
379                     if (resIdx < setResources.buffers.size()) {
380                         validBinding = true;
381                         setResources.buffers[resIdx] = resource;
382                     }
383                 }
384             }
385             if (validBinding && pipelineDescriptorSetBinder_) {
386                 const BindableBuffer bindable {
387                     resource.handle.GetHandle(),
388                     resource.byteOffset,
389                     resource.byteSize,
390                 };
391                 pipelineDescriptorSetBinder_->BindBuffer(set, binding, bindable);
392             }
393         }
394     }
395 }
396 
BindBuffers(const uint32_t set,const uint32_t binding,const array_view<const BindableBufferWithHandleReference> resources)397 void ShaderPipelineBinder::BindBuffers(
398     const uint32_t set, const uint32_t binding, const array_view<const BindableBufferWithHandleReference> resources)
399 {
400     if ((!resources.empty()) && set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
401         const uint32_t setIdx = setToBinderIndex_[set];
402         if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
403             const RenderHandleType type = resources[0].handle.GetHandleType();
404             auto& setResources = descriptorSetResources_[setIdx];
405             bool validBinding = false;
406             if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
407                 const uint32_t idx = setResources.bindingToIndex[binding];
408                 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
409                     const uint32_t resIdx = setResources.bindings[idx].resIdx;
410                     if (resIdx < setResources.buffers.size()) {
411                         validBinding = true;
412                         setResources.buffers[resIdx] = resources[0];
413                     }
414                 }
415             }
416             if (validBinding && pipelineDescriptorSetBinder_) {
417                 vector<BindableBuffer> bindables;
418                 bindables.resize(resources.size());
419                 for (size_t idx = 0; idx < resources.size(); ++idx) {
420                     const auto& rRef = resources[idx];
421                     bindables[idx] = BindableBuffer { rRef.handle.GetHandle(), rRef.byteOffset, rRef.byteSize };
422                 }
423                 pipelineDescriptorSetBinder_->BindBuffers(set, binding, bindables);
424             }
425         }
426     }
427 }
428 
BindImage(const uint32_t set,const uint32_t binding,const BindableImageWithHandleReference & resource)429 void ShaderPipelineBinder::BindImage(
430     const uint32_t set, const uint32_t binding, const BindableImageWithHandleReference& resource)
431 {
432     if (resource.handle && (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT)) {
433         const uint32_t setIdx = setToBinderIndex_[set];
434         if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
435             const RenderHandleType type = resource.handle.GetHandleType();
436             auto& setResources = descriptorSetResources_[setIdx];
437             bool validBinding = false;
438             if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
439                 const uint32_t idx = setResources.bindingToIndex[binding];
440                 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
441                     const uint32_t resIdx = setResources.bindings[idx].resIdx;
442                     if (resIdx < setResources.images.size()) {
443                         validBinding = true;
444                         setResources.images[resIdx] = resource;
445                     }
446                 }
447             }
448             if (validBinding && pipelineDescriptorSetBinder_) {
449                 const BindableImage bindable {
450                     resource.handle.GetHandle(),
451                     resource.mip,
452                     resource.layer,
453                     ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED,
454                     resource.samplerHandle.GetHandle(),
455                 };
456                 pipelineDescriptorSetBinder_->BindImage(set, binding, bindable);
457             }
458         }
459     }
460 }
461 
BindImages(const uint32_t set,const uint32_t binding,array_view<const BindableImageWithHandleReference> resources)462 void ShaderPipelineBinder::BindImages(
463     const uint32_t set, const uint32_t binding, array_view<const BindableImageWithHandleReference> resources)
464 {
465     if ((!resources.empty()) && (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT)) {
466         const uint32_t setIdx = setToBinderIndex_[set];
467         if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
468             const RenderHandleType type = resources[0U].handle.GetHandleType();
469             auto& setResources = descriptorSetResources_[setIdx];
470             bool validBinding = false;
471             if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
472                 const uint32_t idx = setResources.bindingToIndex[binding];
473                 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
474                     const uint32_t resIdx = setResources.bindings[idx].resIdx;
475                     if (resIdx < setResources.images.size()) {
476                         validBinding = true;
477                         setResources.images[resIdx] = resources[0U];
478                     }
479                 }
480             }
481             if (validBinding && pipelineDescriptorSetBinder_) {
482                 vector<BindableImage> bindables;
483                 bindables.resize(resources.size());
484                 for (size_t idx = 0; idx < resources.size(); ++idx) {
485                     const auto& rRef = resources[idx];
486                     bindables[idx] = BindableImage { rRef.handle.GetHandle(), rRef.mip, rRef.layer,
487                         ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED, rRef.samplerHandle.GetHandle() };
488                 }
489                 pipelineDescriptorSetBinder_->BindImages(set, binding, bindables);
490             }
491         }
492     }
493 }
494 
BindSampler(const uint32_t set,const uint32_t binding,const BindableSamplerWithHandleReference & resource)495 void ShaderPipelineBinder::BindSampler(
496     const uint32_t set, const uint32_t binding, const BindableSamplerWithHandleReference& resource)
497 {
498     if (resource.handle && (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT)) {
499         const uint32_t setIdx = setToBinderIndex_[set];
500         if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
501             const RenderHandleType type = resource.handle.GetHandleType();
502             auto& setResources = descriptorSetResources_[setIdx];
503             bool validBinding = false;
504             if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
505                 const uint32_t idx = setResources.bindingToIndex[binding];
506                 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
507                     const uint32_t resIdx = setResources.bindings[idx].resIdx;
508                     if (resIdx < setResources.samplers.size()) {
509                         validBinding = true;
510                         setResources.samplers[resIdx] = resource;
511                     }
512                 }
513             }
514             if (validBinding && pipelineDescriptorSetBinder_) {
515                 const BindableSampler bindable {
516                     resource.handle.GetHandle(),
517                 };
518                 pipelineDescriptorSetBinder_->BindSampler(set, binding, bindable);
519             }
520         }
521     }
522 }
523 
BindSamplers(const uint32_t set,const uint32_t binding,array_view<const BindableSamplerWithHandleReference> resources)524 void ShaderPipelineBinder::BindSamplers(
525     const uint32_t set, const uint32_t binding, array_view<const BindableSamplerWithHandleReference> resources)
526 {
527     if ((!resources.empty()) && (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT)) {
528         const uint32_t setIdx = setToBinderIndex_[set];
529         if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
530             const RenderHandleType type = resources[0U].handle.GetHandleType();
531             auto& setResources = descriptorSetResources_[setIdx];
532             bool validBinding = false;
533             if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
534                 const uint32_t idx = setResources.bindingToIndex[binding];
535                 if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
536                     const uint32_t resIdx = setResources.bindings[idx].resIdx;
537                     if (resIdx < setResources.samplers.size()) {
538                         validBinding = true;
539                         setResources.samplers[resIdx] = resources[0U];
540                     }
541                 }
542             }
543             if (validBinding && pipelineDescriptorSetBinder_) {
544                 vector<BindableSampler> bindables;
545                 bindables.resize(resources.size());
546                 for (size_t idx = 0; idx < resources.size(); ++idx) {
547                     const auto& rRef = resources[idx];
548                     bindables[idx] = BindableSampler { rRef.handle.GetHandle() };
549                 }
550                 pipelineDescriptorSetBinder_->BindSamplers(set, binding, bindables);
551             }
552         }
553     }
554 }
555 
BindVertexBuffers(BASE_NS::array_view<const VertexBufferWithHandleReference> vertexBuffers)556 void ShaderPipelineBinder::BindVertexBuffers(BASE_NS::array_view<const VertexBufferWithHandleReference> vertexBuffers)
557 {
558     vertexBuffers_.clear();
559     vertexBuffers_.append(vertexBuffers.begin(), vertexBuffers.end());
560 }
561 
BindIndexBuffer(const IndexBufferWithHandleReference & indexBuffer)562 void ShaderPipelineBinder::BindIndexBuffer(const IndexBufferWithHandleReference& indexBuffer)
563 {
564     indexBuffer_ = indexBuffer;
565 }
566 
SetDrawCommand(const DrawCommand & drawCommand)567 void ShaderPipelineBinder::SetDrawCommand(const DrawCommand& drawCommand)
568 {
569     drawCommand_ = drawCommand;
570 }
571 
SetDispatchCommand(const DispatchCommand & dispatchCommand)572 void ShaderPipelineBinder::SetDispatchCommand(const DispatchCommand& dispatchCommand)
573 {
574     dispatchCommand_ = dispatchCommand;
575 }
576 
GetDescriptorSetLayoutBindingResources(const uint32_t set) const577 DescriptorSetLayoutBindingResources ShaderPipelineBinder::GetDescriptorSetLayoutBindingResources(
578     const uint32_t set) const
579 {
580     if (pipelineDescriptorSetBinder_) {
581         return pipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(set);
582     } else {
583         return {};
584     }
585 }
586 
GetPushConstantData() const587 array_view<const uint8_t> ShaderPipelineBinder::GetPushConstantData() const
588 {
589     return pushData_;
590 }
591 
GetProperties()592 IPropertyHandle* ShaderPipelineBinder::GetProperties()
593 {
594     return customPropertyData_.handle;
595 }
596 
GetBindingProperties()597 IPropertyHandle* ShaderPipelineBinder::GetBindingProperties()
598 {
599     return bindingPropertyData_.handle;
600 }
601 
GetResourceBinding(uint32_t set,uint32_t binding) const602 IShaderPipelineBinder::ResourceBinding ShaderPipelineBinder::GetResourceBinding(uint32_t set, uint32_t binding) const
603 {
604     if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
605         const uint32_t setIdx = setToBinderIndex_[set];
606         if (setIdx < static_cast<uint32_t>(descriptorSetResources_.size())) {
607             const auto& setResources = descriptorSetResources_[setIdx];
608             if (binding < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
609                 const uint32_t idx = setResources.bindingToIndex[binding];
610                 if (idx < setResources.bindings.size()) {
611                     IShaderPipelineBinder::ResourceBinding rb;
612                     const auto& resBinding = setResources.bindings[idx];
613                     rb.set = set;
614                     rb.binding = binding;
615                     rb.arrayOffset = resBinding.arrayoffset;
616                     rb.descriptorCount = resBinding.descriptorCount;
617                     if ((resBinding.type == RenderHandleType::GPU_BUFFER) &&
618                         (resBinding.resIdx < setResources.buffers.size())) {
619                         rb.handle = setResources.buffers[resBinding.resIdx].handle;
620                     } else if ((resBinding.type == RenderHandleType::GPU_IMAGE) &&
621                                (resBinding.resIdx < setResources.images.size())) {
622                         rb.handle = setResources.images[resBinding.resIdx].handle;
623                     } else if ((resBinding.type == RenderHandleType::GPU_SAMPLER) &&
624                                (resBinding.resIdx < setResources.samplers.size())) {
625                         rb.handle = setResources.samplers[resBinding.resIdx].handle;
626                     }
627                     return rb;
628                 }
629             }
630         }
631     }
632     return {};
633 }
634 
GetPropertyBindingView() const635 IShaderPipelineBinder::PropertyBindingView ShaderPipelineBinder::GetPropertyBindingView() const
636 {
637     PropertyBindingView cpbv;
638     cpbv.set = customPropertyData_.set;
639     cpbv.binding = customPropertyData_.binding;
640     cpbv.data =
641         (customPropertyData_.properties) ? customPropertyData_.properties->GetData() : array_view<const uint8_t> {};
642     return cpbv;
643 }
644 
GetPropertyBindingByteSize() const645 uint32_t ShaderPipelineBinder::GetPropertyBindingByteSize() const
646 {
647     return (customPropertyData_.properties) ? static_cast<uint32_t>(customPropertyData_.properties->GetByteSize()) : 0U;
648 }
649 
GetVertexBuffers() const650 array_view<const VertexBufferWithHandleReference> ShaderPipelineBinder::GetVertexBuffers() const
651 {
652     return vertexBuffers_;
653 }
654 
GetIndexBuffer() const655 IndexBufferWithHandleReference ShaderPipelineBinder::GetIndexBuffer() const
656 {
657     return indexBuffer_;
658 }
659 
GetDrawCommand() const660 IShaderPipelineBinder::DrawCommand ShaderPipelineBinder::GetDrawCommand() const
661 {
662     return drawCommand_;
663 }
664 
GetDispatchCommand() const665 IShaderPipelineBinder::DispatchCommand ShaderPipelineBinder::GetDispatchCommand() const
666 {
667     return dispatchCommand_;
668 }
669 
BindPropertyBindings()670 void ShaderPipelineBinder::BindPropertyBindings()
671 {
672     // fetch the bindings from properties, and try to bind them
673     if (bindingPropertyData_.properties && (bindingPropertyData_.properties->PropertyCount() > 0)) {
674         auto* bindingProperties = bindingPropertyData_.properties.get();
675         PLUGIN_ASSERT(bindingProperties->Owner()->MetaData().size() == bindingPropertyData_.setAndBindings.size());
676         for (size_t idx = 0; idx < bindingProperties->Owner()->MetaData().size(); ++idx) {
677             // the ordering should match with the bindings in the .shader file
678             const auto& prop = bindingProperties->Owner()->MetaData()[idx];
679             const auto& sb = bindingPropertyData_.setAndBindings[idx];
680             switch (prop.type) {
681                 case PropertyType::BINDABLE_BUFFER_WITH_HANDLE_REFERENCE_T: {
682                     BindBuffer(sb.set, sb.binding, bindingProperties->GetValue<BindableBufferWithHandleReference>(idx));
683                 }
684                     break;
685                 case PropertyType::BINDABLE_IMAGE_WITH_HANDLE_REFERENCE_T: {
686                     BindImage(sb.set, sb.binding, bindingProperties->GetValue<BindableImageWithHandleReference>(idx));
687                 }
688                     break;
689                 case PropertyType::BINDABLE_SAMPLER_WITH_HANDLE_REFERENCE_T: {
690                     BindSampler(
691                         sb.set, sb.binding, bindingProperties->GetValue<BindableSamplerWithHandleReference>(idx));
692                 }
693                     break;
694                 default: {
695                 }
696                     break;
697             }
698         }
699     }
700 }
701 
GetPipelineLayout() const702 PipelineLayout ShaderPipelineBinder::GetPipelineLayout() const
703 {
704     return pipelineLayout_;
705 }
706 
GetPipelineDescriptorSetBinder() const707 IPipelineDescriptorSetBinder* ShaderPipelineBinder::GetPipelineDescriptorSetBinder() const
708 {
709     if (pipelineDescriptorSetBinder_) {
710         return pipelineDescriptorSetBinder_.get();
711     } else {
712         return nullptr;
713     }
714 }
715 
Ref()716 void ShaderPipelineBinder::Ref()
717 {
718     refcnt_.fetch_add(1, std::memory_order_relaxed);
719 }
720 
Unref()721 void ShaderPipelineBinder::Unref()
722 {
723     if (std::atomic_fetch_sub_explicit(&refcnt_, 1, std::memory_order_release) == 1) {
724         std::atomic_thread_fence(std::memory_order_acquire);
725         delete this;
726     }
727 }
728 RENDER_END_NAMESPACE()
729