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 "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, "image_dimension_1d_bit"},
48 {AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_2D_BIT, "image_dimension_2d_bit"},
49 {AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_3D_BIT, "image_dimension_3d_bit"},
50 {AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_CUBE_BIT,
51 "image_dimension_cube_bit"},
52 {AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_BUFFER_BIT,
53 "image_dimension_buffer_bit"},
54 {AdditionalDescriptorTypeImageFlagBits::CORE_DESCRIPTOR_TYPE_IMAGE_DIMENSION_SUBPASS_BIT,
55 "image_dimension_subpass_bit"},
56 })
57
58 RENDER_JSON_SERIALIZE_ENUM(DescriptorType,
59 {
60 { DescriptorType::CORE_DESCRIPTOR_TYPE_MAX_ENUM, nullptr }, // default
61 { DescriptorType::CORE_DESCRIPTOR_TYPE_SAMPLER, "sampler" },
62 { DescriptorType::CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, "combined_image_sampler" },
63 { DescriptorType::CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, "sampled_image" },
64 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE, "storage_image" },
65 { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "uniform_texel_buffer" },
66 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, "storage_texel_buffer" },
67 { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "uniform_buffer" },
68 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, "storage_buffer" },
69 { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, "uniform_buffer_dynamic" },
70 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, "storage_buffer_dynamic" },
71 { DescriptorType::CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "input_attachment" },
72 { DescriptorType::CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE, "acceleration_structure" },
73 })
74 // clang-format on
FromJson(const json::value & jsonData,JsonContext<DescriptorSetLayoutBinding> & context)75 void FromJson(const json::value& jsonData, JsonContext<DescriptorSetLayoutBinding>& context)
76 {
77 SafeGetJsonValue(jsonData, "binding", context.error, context.data.binding);
78 SafeGetJsonEnum(jsonData, "descriptorType", context.error, context.data.descriptorType);
79 SafeGetJsonValue(jsonData, "descriptorCount", context.error, context.data.descriptorCount);
80 SafeGetJsonBitfield<ShaderStageFlagBits>(
81 jsonData, "shaderStageFlags", context.error, context.data.shaderStageFlags);
82 SafeGetJsonBitfield<AdditionalDescriptorTypeImageFlagBits>(
83 jsonData, "additionalDescriptorTypeFlags", context.error, context.data.additionalDescriptorTypeFlags);
84 }
85
FromJson(const json::value & jsonData,JsonContext<DescriptorSetLayout> & context)86 void FromJson(const json::value& jsonData, JsonContext<DescriptorSetLayout>& context)
87 {
88 SafeGetJsonValue(jsonData, "set", context.error, context.data.set);
89
90 PipelineLayoutLoader::LoadResult loadResult;
91 ParseArray<decltype(context.data.bindings)::value_type>(jsonData, "bindings", context.data.bindings, loadResult);
92 context.error = loadResult.error;
93 // NOTE: does not fetch descriptor set arrays
94 }
95
Load(const json::value & jsonData,const string_view uri,PipelineLayout & pl,string & renderSlotName,bool & defaultRenderSlot)96 PipelineLayoutLoader::LoadResult Load(const json::value& jsonData, [[maybe_unused]] const string_view uri,
97 PipelineLayout& pl, string& renderSlotName, bool& defaultRenderSlot)
98 {
99 PipelineLayoutLoader::LoadResult result;
100 pl = {}; // reset
101
102 SafeGetJsonValue(jsonData, "renderSlot", result.error, renderSlotName);
103 SafeGetJsonValue(jsonData, "renderSlotDefault", result.error, defaultRenderSlot);
104 if (!defaultRenderSlot) {
105 SafeGetJsonValue(jsonData, "renderSlotDefaultPipelineLayout", result.error, defaultRenderSlot);
106 }
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("RENDER_VALIDATION: Invalid push constant size clamped (name:%s). push constant size %u <= %u",
116 uri.data(), pl.pushConstant.byteSize, PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE);
117 }
118 #endif
119 pl.pushConstant.byteSize =
120 Math::min(PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE, pl.pushConstant.byteSize);
121 }
122
123 vector<DescriptorSetLayout> descriptorSetLayouts;
124 ParseArray<decltype(descriptorSetLayouts)::value_type>(
125 jsonData, "descriptorSetLayouts", descriptorSetLayouts, result);
126 if (!descriptorSetLayouts.empty()) {
127 const auto inputDescriptorSetCount = static_cast<uint32_t>(descriptorSetLayouts.size());
128 #if (RENDER_VALIDATION_ENABLED == 1)
129 if (inputDescriptorSetCount > PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
130 PLUGIN_LOG_W("RENDER_VALIDATION: Invalid pipeline layout sizes clamped (name:%s). Set count %u <= %u",
131 uri.data(), inputDescriptorSetCount, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT);
132 }
133 for (const auto& descRef : descriptorSetLayouts) {
134 if (descRef.bindings.size() > PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
135 PLUGIN_LOG_W(
136 "RENDER_VALIDATION: Binding count exceeds the maximum (name:%s). Binding count count %u <= %u",
137 uri.data(), static_cast<uint32_t>(descRef.bindings.size()),
138 PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT);
139 }
140 for (const auto& bindingRef : descRef.bindings) {
141 if (bindingRef.descriptorType == DescriptorType::CORE_DESCRIPTOR_TYPE_MAX_ENUM) {
142 PLUGIN_LOG_W("RENDER_VALIDATION: Unknown descriptor type (name:%s) (set:%u, binding:%u).",
143 uri.data(), descRef.set, bindingRef.binding);
144 }
145 }
146 }
147 #endif
148 // pipeline layout descriptor sets might have gaps and only some sets defined
149 for (uint32_t idx = 0; idx < inputDescriptorSetCount; ++idx) {
150 const uint32_t setIndex = descriptorSetLayouts[idx].set;
151 if (setIndex < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
152 pl.descriptorSetLayouts[setIndex] = move(descriptorSetLayouts[idx]);
153 }
154 }
155 } else {
156 result.error += "invalid descriptor set layout count";
157 }
158
159 result.success = result.error.empty();
160 if (!result.success) {
161 PLUGIN_LOG_E("error loading pipeline layout from json: %s", result.error.c_str());
162 }
163
164 return result;
165 }
166
GetUri() const167 string_view PipelineLayoutLoader::GetUri() const
168 {
169 return uri_;
170 }
171
GetPipelineLayout() const172 const PipelineLayout& PipelineLayoutLoader::GetPipelineLayout() const
173 {
174 return pipelineLayout_;
175 }
176
GetRenderSlot() const177 BASE_NS::string_view PipelineLayoutLoader::GetRenderSlot() const
178 {
179 return renderSlotName_;
180 }
181
GetDefaultRenderSlot() const182 bool PipelineLayoutLoader::GetDefaultRenderSlot() const
183 {
184 return renderSlotDefaultPl_;
185 }
186
Load(const string_view jsonString)187 PipelineLayoutLoader::LoadResult PipelineLayoutLoader::Load(const string_view jsonString)
188 {
189 if (json::value jsonData = json::parse(jsonString.data()); jsonData) {
190 return RENDER_NS::Load(jsonData, uri_, pipelineLayout_, renderSlotName_, renderSlotDefaultPl_);
191 }
192 return LoadResult("Invalid json file.");
193 }
194
Load(IFileManager & fileManager,const string_view uri)195 PipelineLayoutLoader::LoadResult PipelineLayoutLoader::Load(IFileManager& fileManager, const string_view uri)
196 {
197 uri_ = uri;
198
199 IFile::Ptr file = fileManager.OpenFile(uri);
200 if (!file) {
201 PLUGIN_LOG_E("Error loading '%s'", string(uri).c_str());
202 return LoadResult("Failed to open file.");
203 }
204
205 const uint64_t byteLength = file->GetLength();
206
207 string raw;
208 raw.resize(static_cast<size_t>(byteLength));
209
210 if (file->Read(raw.data(), byteLength) != byteLength) {
211 PLUGIN_LOG_E("Error loading '%s'", string(uri).c_str());
212 return LoadResult("Failed to read file.");
213 }
214
215 return Load(string_view(raw));
216 }
217 RENDER_END_NAMESPACE()
218