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