• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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/pipeline_layout_desc.h>
25 #include <render/device/pipeline_state_desc.h>
26 #include <render/namespace.h>
27 
28 #include "util/log.h"
29 
30 using namespace BASE_NS;
31 
RENDER_BEGIN_NAMESPACE()32 RENDER_BEGIN_NAMESPACE()
33 void ShaderPipelineBinder::Ref()
34 {
35     refcnt_.fetch_add(1, std::memory_order_relaxed);
36 }
37 
Unref()38 void ShaderPipelineBinder::Unref()
39 {
40     if (std::atomic_fetch_sub_explicit(&refcnt_, 1, std::memory_order_release) == 1) {
41         std::atomic_thread_fence(std::memory_order_acquire);
42         delete this;
43     }
44 }
45 
ShaderPipelineBinder(const RenderHandleReference & shader,const PipelineLayout & pipelineLayout)46 ShaderPipelineBinder::ShaderPipelineBinder(const RenderHandleReference& shader, const PipelineLayout& pipelineLayout)
47     : shader_(shader), pipelineLayout_(pipelineLayout)
48 {
49     for (uint32_t idx = 0; idx < pipelineLayout.descriptorSetCount; ++idx) {
50         const uint32_t set = pipelineLayout.descriptorSetLayouts[idx].set;
51         if (set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
52             descriptorSetResources_.emplace_back();
53             auto& resSet = descriptorSetResources_.back();
54             resSet.bindings.resize(pipelineLayout.descriptorSetLayouts[idx].bindings.size());
55             uint32_t bufferCount = 0;
56             uint32_t imageCount = 0;
57             uint32_t samplerCount = 0;
58             for (uint32_t bindingIdx = 0; bindingIdx < pipelineLayout.descriptorSetLayouts[idx].bindings.size();
59                  ++bindingIdx) {
60                 const auto& binding = pipelineLayout.descriptorSetLayouts[idx].bindings[bindingIdx];
61                 auto& resBinding = resSet.bindings[bindingIdx];
62                 resBinding.binding = binding.binding;
63                 resSet.bindingToIndex[resBinding.binding] = static_cast<uint8_t>(bindingIdx);
64                 resSet.maxBindingCount = Math::max(resSet.maxBindingCount, resBinding.binding);
65 
66                 if (binding.descriptorType == CORE_DESCRIPTOR_TYPE_SAMPLER) {
67                     resBinding.resIdx = samplerCount;
68                     resBinding.type = RenderHandleType::GPU_SAMPLER;
69                     samplerCount += binding.descriptorCount;
70                 } else if (((binding.descriptorType >= CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
71                                (binding.descriptorType <= CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE)) ||
72                            (binding.descriptorType == CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
73                     resBinding.resIdx = imageCount;
74                     resBinding.type = RenderHandleType::GPU_IMAGE;
75                     imageCount += binding.descriptorCount;
76                 } else if (((binding.descriptorType >= CORE_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) &&
77                                (binding.descriptorType <= CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) ||
78                            (binding.descriptorType == CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE)) {
79                     resBinding.resIdx = bufferCount;
80                     resBinding.type = RenderHandleType::GPU_BUFFER;
81                     bufferCount += binding.descriptorCount;
82                 }
83             }
84             // +1 for binding count
85             resSet.maxBindingCount =
86                 Math::min(resSet.maxBindingCount + 1, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT);
87 
88             resSet.buffers.resize(bufferCount);
89             resSet.images.resize(imageCount);
90             resSet.samplers.resize(samplerCount);
91         }
92     }
93     if (pipelineLayout_.pushConstant.byteSize > 0) {
94         pushData_.resize(pipelineLayout_.pushConstant.byteSize);
95         std::fill(pushData_.begin(), pushData_.end(), uint8_t(0));
96     }
97 }
98 
GetBindingValidity() const99 bool ShaderPipelineBinder::GetBindingValidity() const
100 {
101     bool valid = true;
102     auto checkValidity = [](const auto& vec, bool& valid) {
103         for (const auto ref : vec) {
104             if (!ref.handle) {
105                 valid = false;
106             }
107         }
108     };
109     for (const auto& ref : descriptorSetResources_) {
110         checkValidity(ref.buffers, valid);
111         checkValidity(ref.images, valid);
112         checkValidity(ref.samplers, valid);
113     }
114     return valid;
115 }
116 
GetShaderHandle() const117 RenderHandleReference ShaderPipelineBinder::GetShaderHandle() const
118 {
119     return shader_;
120 }
121 
Bind(const uint32_t set,const uint32_t binding,const RenderHandleReference & handle)122 void ShaderPipelineBinder::Bind(const uint32_t set, const uint32_t binding, const RenderHandleReference& handle)
123 {
124     const RenderHandleType type = handle.GetHandleType();
125     if (type == RenderHandleType::GPU_BUFFER) {
126         BindBuffer(set, binding, { handle, 0u, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE });
127     } else if (type == RenderHandleType::GPU_IMAGE) {
128         BindImage(set, binding,
129             { handle, PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS,
130                 {} });
131     } else if (type == RenderHandleType::GPU_SAMPLER) {
132         BindSampler(set, binding, { handle });
133     }
134 }
135 
SetUniformData(const uint32_t set,const uint32_t binding,const array_view<const uint8_t> data)136 void ShaderPipelineBinder::SetUniformData(
137     const uint32_t set, const uint32_t binding, const array_view<const uint8_t> data)
138 {}
139 
SetPushConstantData(const array_view<const uint8_t> data)140 void ShaderPipelineBinder::SetPushConstantData(const array_view<const uint8_t> data)
141 {
142     if ((pipelineLayout_.pushConstant.byteSize > 0) && (!data.empty())) {
143         const size_t maxByteSize = Math::min(pushData_.size_in_bytes(), data.size_bytes());
144         CloneData(pushData_.data(), pushData_.size_in_bytes(), data.data(), maxByteSize);
145     }
146 }
147 
BindBuffer(const uint32_t set,const uint32_t binding,const Buffer & resource)148 void ShaderPipelineBinder::BindBuffer(const uint32_t set, const uint32_t binding, const Buffer& resource)
149 {
150     if (resource.handle && (set < descriptorSetResources_.size())) {
151         const RenderHandleType type = resource.handle.GetHandleType();
152         auto& setResources = descriptorSetResources_[set];
153         if (binding < setResources.maxBindingCount) {
154             const uint32_t idx = setResources.bindingToIndex[binding];
155             if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
156                 const uint32_t resIdx = setResources.bindings[idx].resIdx;
157                 PLUGIN_ASSERT(resIdx < setResources.buffers.size());
158                 setResources.buffers[resIdx] = resource;
159             }
160         }
161     }
162 }
163 
BindImage(const uint32_t set,const uint32_t binding,const Image & resource)164 void ShaderPipelineBinder::BindImage(const uint32_t set, const uint32_t binding, const Image& resource)
165 {
166     if (resource.handle && (set < descriptorSetResources_.size())) {
167         const RenderHandleType type = resource.handle.GetHandleType();
168         auto& setResources = descriptorSetResources_[set];
169         if (binding < setResources.maxBindingCount) {
170             const uint32_t idx = setResources.bindingToIndex[binding];
171             if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
172                 const uint32_t resIdx = setResources.bindings[idx].resIdx;
173                 PLUGIN_ASSERT(resIdx < setResources.images.size());
174                 setResources.images[resIdx] = resource;
175             }
176         }
177     }
178 }
179 
BindSampler(const uint32_t set,const uint32_t binding,const Sampler & resource)180 void ShaderPipelineBinder::BindSampler(const uint32_t set, const uint32_t binding, const Sampler& resource)
181 {
182     if (resource.handle && (set < descriptorSetResources_.size())) {
183         const RenderHandleType type = resource.handle.GetHandleType();
184         auto& setResources = descriptorSetResources_[set];
185         if (binding < setResources.maxBindingCount) {
186             const uint32_t idx = setResources.bindingToIndex[binding];
187             if ((idx < setResources.bindings.size()) && (setResources.bindings[idx].type == type)) {
188                 const uint32_t resIdx = setResources.bindings[idx].resIdx;
189                 PLUGIN_ASSERT(resIdx < setResources.samplers.size());
190                 setResources.samplers[resIdx] = resource;
191             }
192         }
193     }
194 }
195 
GetDescriptorSetView(const uint32_t set) const196 IShaderPipelineBinder::DescriptorSetView ShaderPipelineBinder::GetDescriptorSetView(const uint32_t set) const
197 {
198     if (set < static_cast<uint32_t>(descriptorSetResources_.size())) {
199         const auto& ref = descriptorSetResources_[set];
200         return {
201             ref.buffers,
202             ref.images,
203             ref.samplers,
204             ref.bindings,
205         };
206     }
207     return {};
208 }
209 
GetPushData() const210 array_view<const uint8_t> ShaderPipelineBinder::GetPushData() const
211 {
212     return pushData_;
213 }
214 RENDER_END_NAMESPACE()
215