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 "pipeline_layout_loader.h"
17
18 #include <base/math/mathf.h>
19 #include <core/io/intf_file_manager.h>
20 #include <render/device/pipeline_layout_desc.h>
21 #include <render/namespace.h>
22
23 #include "json_util.h"
24 #include "util/log.h"
25
26 using namespace BASE_NS;
27 using namespace CORE_NS;
28
29 RENDER_BEGIN_NAMESPACE()
30 // clang-format off
31 RENDER_JSON_SERIALIZE_ENUM(ShaderStageFlagBits,
32 {
33 { (ShaderStageFlagBits)0, nullptr },
34 { ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT, "vertex_bit" },
35 { ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT, "fragment_bit" },
36 { ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT, "compute_bit" },
37 })
38
39 RENDER_JSON_SERIALIZE_ENUM(AdditionalDescriptorTypeImageFlagBits,
40 {
41 { (AdditionalDescriptorTypeImageFlagBits)0, nullptr },
42 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DEPTH_BIT, "image_depth_bit" },
43 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_ARRAY_BIT, "image_array_bit" },
44 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_MULTISAMPLE_BIT, "image_multisample_bit" },
45 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_SAMPLED_BIT, "image_sampled_bit" },
46 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_LOAD_STORE_BIT, "image_load_store_bit" },
47 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_1D_BIT,
48 "image_dimension_1d_bit" },
49 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_2D_BIT,
50 "image_dimension_2d_bit" },
51 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_3D_BIT,
52 "image_dimension_3d_bit" },
53 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_CUBE_BIT,
54 "image_dimension_cube_bit" },
55 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_BUFFER_BIT,
56 "image_dimension_buffer_bit" },
57 { AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_SUBPASS_BIT,
58 "image_dimension_subpass_bit" },
59 })
60
61 RENDER_JSON_SERIALIZE_ENUM(DescriptorType,
62 {
63 { DescriptorType::CORE_DESCRIPTOR_TYPE_MAX_ENUM, nullptr }, // default
64 { DescriptorType::CORE_DESCRIPTOR_TYPE_SAMPLER, "sampler" },
65 { DescriptorType::CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, "combined_image_sampler" },
66 { DescriptorType::CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, "sampled_image" },
67 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE, "storage_image" },
68 { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "uniform_texel_buffer" },
69 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, "storage_texel_buffer" },
70 { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "uniform_buffer" },
71 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, "storage_buffer" },
72 { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, "uniform_buffer_dynamic" },
73 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, "storage_buffer_dynamic" },
74 { DescriptorType::CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "input_attachment" },
75 { DescriptorType::CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE, "acceleration_structure" },
76 })
77 // clang-format on
FromJson(const json::value & jsonData,JsonContext<DescriptorSetLayoutBinding> & context)78 void FromJson(const json::value& jsonData, JsonContext<DescriptorSetLayoutBinding>& context)
79 {
80 SafeGetJsonValue(jsonData, "binding", context.error, context.data.binding);
81 SafeGetJsonEnum(jsonData, "descriptorType", context.error, context.data.descriptorType);
82 SafeGetJsonValue(jsonData, "descriptorCount", context.error, context.data.descriptorCount);
83 SafeGetJsonBitfield<ShaderStageFlagBits>(
84 jsonData, "shaderStageFlags", context.error, context.data.shaderStageFlags);
85 SafeGetJsonBitfield<AdditionalDescriptorTypeImageFlagBits>(
86 jsonData, "additionalDescriptorTypeFlags", context.error, context.data.additionalDescriptorTypeFlags);
87 }
88
FromJson(const json::value & jsonData,JsonContext<DescriptorSetLayout> & context)89 void FromJson(const json::value& jsonData, JsonContext<DescriptorSetLayout>& context)
90 {
91 SafeGetJsonValue(jsonData, "set", context.error, context.data.set);
92
93 PipelineLayoutLoader::LoadResult loadResult;
94 ParseArray<decltype(context.data.bindings)::value_type>(jsonData, "bindings", context.data.bindings, loadResult);
95 context.error = loadResult.error;
96 // NOTE: does not fetch descriptor set arrays
97 }
98
Load(const json::value & jsonData,const string_view uri,PipelineLayout & pl,string & renderSlotName,bool & defaultRenderSlot)99 PipelineLayoutLoader::LoadResult Load(const json::value& jsonData, [[maybe_unused]] const string_view uri,
100 PipelineLayout& pl, string& renderSlotName, bool& defaultRenderSlot)
101 {
102 PipelineLayoutLoader::LoadResult result;
103 pl = {}; // reset
104
105 SafeGetJsonValue(jsonData, "renderSlot", result.error, renderSlotName);
106 SafeGetJsonValue(jsonData, "renderSlotDefault", result.error, defaultRenderSlot);
107
108 if (const auto pcIter = jsonData.find("pushConstant"); pcIter) {
109 SafeGetJsonValue(*pcIter, "size", result.error, pl.pushConstant.byteSize);
110 SafeGetJsonValue(*pcIter, "byteSize", result.error, pl.pushConstant.byteSize);
111 SafeGetJsonBitfield<ShaderStageFlagBits>(
112 *pcIter, "shaderStageFlags", result.error, pl.pushConstant.shaderStageFlags);
113 #if (RENDER_VALIDATION_ENABLED == 1)
114 if (pl.pushConstant.byteSize > PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE) {
115 PLUGIN_LOG_W(
116 "RENDER_VALIDATION: Invalid push constant size clamped (name:%s). push constant size %u <= %u",
117 uri.data(), pl.pushConstant.byteSize, PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE);
118 }
119 #endif
120 pl.pushConstant.byteSize =
121 Math::min(PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE, pl.pushConstant.byteSize);
122 }
123
124 vector<DescriptorSetLayout> descriptorSetLayouts;
125 ParseArray<decltype(descriptorSetLayouts)::value_type>(
126 jsonData, "descriptorSetLayouts", descriptorSetLayouts, result);
127 if (!descriptorSetLayouts.empty()) {
128 const auto inputDescriptorSetCount = static_cast<uint32_t>(descriptorSetLayouts.size());
129 #if (RENDER_VALIDATION_ENABLED == 1)
130 if (inputDescriptorSetCount > PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
131 PLUGIN_LOG_W("RENDER_VALIDATION: Invalid pipeline layout sizes clamped (name:%s). Set count %u <= %u",
132 uri.data(), inputDescriptorSetCount, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT);
133 }
134 for (const auto& descRef : descriptorSetLayouts) {
135 if (descRef.bindings.size() > PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
136 PLUGIN_LOG_W(
137 "RENDER_VALIDATION: Binding count exceeds the maximum (name:%s). Binding count count %u <= %u",
138 uri.data(), static_cast<uint32_t>(descRef.bindings.size()),
139 PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT);
140 }
141 for (const auto& bindingRef : descRef.bindings) {
142 if (bindingRef.descriptorType == DescriptorType::CORE_DESCRIPTOR_TYPE_MAX_ENUM) {
143 PLUGIN_LOG_W("RENDER_VALIDATION: Unknown descriptor type (name:%s) (set:%u, binding:%u).",
144 uri.data(), descRef.set, bindingRef.binding);
145 }
146 }
147 }
148 #endif
149 // pipeline layout descriptor sets might have gaps and only some sets defined
150 for (uint32_t idx = 0; idx < inputDescriptorSetCount; ++idx) {
151 const uint32_t setIndex = descriptorSetLayouts[idx].set;
152 if (setIndex < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
153 pl.descriptorSetLayouts[setIndex] = move(descriptorSetLayouts[idx]);
154 pl.descriptorSetCount++;
155 }
156 }
157 // reassure
158 pl.descriptorSetCount = Math::min(pl.descriptorSetCount, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT);
159 } else {
160 result.error += "invalid descriptor set layout count";
161 }
162
163 result.success = result.error.empty();
164 if (!result.success) {
165 PLUGIN_LOG_E("error loading pipeline layout from json: %s", result.error.c_str());
166 }
167
168 return result;
169 }
170
GetUri() const171 string_view PipelineLayoutLoader::GetUri() const
172 {
173 return uri_;
174 }
175
GetPipelineLayout() const176 const PipelineLayout& PipelineLayoutLoader::GetPipelineLayout() const
177 {
178 return pipelineLayout_;
179 }
180
GetRenderSlot() const181 BASE_NS::string_view PipelineLayoutLoader::GetRenderSlot() const
182 {
183 return renderSlotName_;
184 }
185
GetDefaultRenderSlot() const186 bool PipelineLayoutLoader::GetDefaultRenderSlot() const
187 {
188 return renderSlotDefaultPl_;
189 }
190
Load(const string_view jsonString)191 PipelineLayoutLoader::LoadResult PipelineLayoutLoader::Load(const string_view jsonString)
192 {
193 if (json::value jsonData = json::parse(jsonString.data()); jsonData) {
194 return RENDER_NS::Load(jsonData, uri_, pipelineLayout_, renderSlotName_, renderSlotDefaultPl_);
195 }
196 return LoadResult("Invalid json file.");
197 }
198
Load(IFileManager & fileManager,const string_view uri)199 PipelineLayoutLoader::LoadResult PipelineLayoutLoader::Load(IFileManager& fileManager, const string_view uri)
200 {
201 uri_ = uri;
202
203 IFile::Ptr file = fileManager.OpenFile(uri);
204 if (!file) {
205 PLUGIN_LOG_E("Error loading '%s'", string(uri).c_str());
206 return LoadResult("Failed to open file.");
207 }
208
209 const uint64_t byteLength = file->GetLength();
210
211 string raw;
212 raw.resize(static_cast<size_t>(byteLength));
213
214 if (file->Read(raw.data(), byteLength) != byteLength) {
215 PLUGIN_LOG_E("Error loading '%s'", string(uri).c_str());
216 return LoadResult("Failed to read file.");
217 }
218
219 return Load(string_view(raw));
220 }
221 RENDER_END_NAMESPACE()
222