• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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