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_format_serialization.h"
24 #include "json_util.h"
25 #include "util/log.h"
26
27 using namespace BASE_NS;
28 using namespace CORE_NS;
29
30 RENDER_BEGIN_NAMESPACE()
31 // clang-format off
32 CORE_JSON_SERIALIZE_ENUM(ShaderStageFlagBits,
33 {
34 { (ShaderStageFlagBits)0, nullptr },
35 { ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT, "vertex_bit" },
36 { ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT, "fragment_bit" },
37 { ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT, "compute_bit" },
38 })
39
40 CORE_JSON_SERIALIZE_ENUM(DescriptorType,
41 {
42 { DescriptorType::CORE_DESCRIPTOR_TYPE_MAX_ENUM, nullptr }, // default
43 { DescriptorType::CORE_DESCRIPTOR_TYPE_SAMPLER, "sampler" },
44 { DescriptorType::CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, "combined_image_sampler" },
45 { DescriptorType::CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, "sampled_image" },
46 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE, "storage_image" },
47 { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "uniform_texel_buffer" },
48 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, "storage_texel_buffer" },
49 { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "uniform_buffer" },
50 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, "storage_buffer" },
51 { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, "uniform_buffer_dynamic" },
52 { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, "storage_buffer_dynamic" },
53 { DescriptorType::CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "input_attachment" },
54 { DescriptorType::CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE, "acceleration_structure" },
55 })
56 // clang-format on
57 void FromJson(const json::value& jsonData, JsonContext<DescriptorSetLayoutBinding>& context)
58 {
59 SafeGetJsonValue(jsonData, "binding", context.error, context.data.binding);
60 SafeGetJsonEnum(jsonData, "descriptorType", context.error, context.data.descriptorType);
61 SafeGetJsonValue(jsonData, "descriptorCount", context.error, context.data.descriptorCount);
62 SafeGetJsonBitfield<ShaderStageFlagBits>(
63 jsonData, "shaderStageFlags", context.error, context.data.shaderStageFlags);
64 }
65
FromJson(const json::value & jsonData,JsonContext<DescriptorSetLayout> & context)66 void FromJson(const json::value& jsonData, JsonContext<DescriptorSetLayout>& context)
67 {
68 SafeGetJsonValue(jsonData, "set", context.error, context.data.set);
69
70 PipelineLayoutLoader::LoadResult loadResult;
71 ParseArray<decltype(context.data.bindings)::value_type>(jsonData, "bindings", context.data.bindings, loadResult);
72 context.error = loadResult.error;
73 // NOTE: does not fetch descriptor set arrays
74 }
75
Load(const json::value & jsonData,const string_view uri,PipelineLayout & pl)76 PipelineLayoutLoader::LoadResult Load(const json::value& jsonData, const string_view uri, PipelineLayout& pl)
77 {
78 PipelineLayoutLoader::LoadResult result;
79 pl = {}; // reset
80
81 if (const auto pcIter = jsonData.find("pushConstant"); pcIter) {
82 SafeGetJsonValue(*pcIter, "size", result.error, pl.pushConstant.byteSize);
83 SafeGetJsonValue(*pcIter, "byteSize", result.error, pl.pushConstant.byteSize);
84 SafeGetJsonBitfield<ShaderStageFlagBits>(
85 *pcIter, "shaderStageFlags", result.error, pl.pushConstant.shaderStageFlags);
86 #if (RENDER_VALIDATION_ENABLED == 1)
87 if (pl.pushConstant.byteSize > PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE) {
88 PLUGIN_LOG_W("RENDER_VALIDATION: Invalid push constant size clamped (name:%s). push constant size %u <= %u",
89 uri.data(), pl.pushConstant.byteSize, PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE);
90 }
91 #endif
92 pl.pushConstant.byteSize =
93 Math::min(PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE, pl.pushConstant.byteSize);
94 }
95
96 vector<DescriptorSetLayout> descriptorSetLayouts;
97 ParseArray<decltype(descriptorSetLayouts)::value_type>(
98 jsonData, "descriptorSetLayouts", descriptorSetLayouts, result);
99 if (!descriptorSetLayouts.empty()) {
100 const uint32_t inputDescriptorSetCount = static_cast<uint32_t>(descriptorSetLayouts.size());
101 #if (RENDER_VALIDATION_ENABLED == 1)
102 if (inputDescriptorSetCount > PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
103 PLUGIN_LOG_W("RENDER_VALIDATION: Invalid pipeline layout sizes clamped (name:%s). Set count %u <= %u",
104 uri.data(), inputDescriptorSetCount, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT);
105 }
106 for (const auto& descRef : descriptorSetLayouts) {
107 if (descRef.bindings.size() > PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) {
108 PLUGIN_LOG_W(
109 "RENDER_VALIDATION: Binding count exceeds the maximum (name:%s). Binding count count %u <= %u",
110 uri.data(), static_cast<uint32_t>(descRef.bindings.size()),
111 PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT);
112 }
113 for (const auto& bindingRef : descRef.bindings) {
114 if (bindingRef.descriptorType == DescriptorType::CORE_DESCRIPTOR_TYPE_MAX_ENUM) {
115 PLUGIN_LOG_W("RENDER_VALIDATION: Unknown descriptor type (name:%s) (set:%u, binding:%u).",
116 uri.data(), descRef.set, bindingRef.binding);
117 }
118 }
119 }
120 #endif
121 // pipeline layout descriptor sets might have gaps and only some sets defined
122 for (uint32_t idx = 0; idx < inputDescriptorSetCount; ++idx) {
123 const uint32_t setIndex = descriptorSetLayouts[idx].set;
124 if (setIndex < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
125 pl.descriptorSetLayouts[setIndex] = move(descriptorSetLayouts[idx]);
126 pl.descriptorSetCount++;
127 }
128 }
129 // reassure
130 pl.descriptorSetCount = Math::min(pl.descriptorSetCount, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT);
131 } else {
132 result.error += "invalid descriptor set layout count";
133 }
134
135 result.success = result.error.empty();
136 if (!result.success) {
137 PLUGIN_LOG_E("error loading pipeline layout from json: %s", result.error.c_str());
138 }
139
140 return result;
141 }
142
GetUri() const143 string_view PipelineLayoutLoader::GetUri() const
144 {
145 return uri_;
146 }
147
GetPipelineLayout() const148 const PipelineLayout& PipelineLayoutLoader::GetPipelineLayout() const
149 {
150 return pipelineLayout_;
151 }
152
Load(const string_view jsonString)153 PipelineLayoutLoader::LoadResult PipelineLayoutLoader::Load(const string_view jsonString)
154 {
155 if (json::value jsonData = json::parse(jsonString.data()); jsonData) {
156 return RENDER_NS::Load(jsonData, uri_, pipelineLayout_);
157 }
158 return LoadResult("Invalid json file.");
159 }
160
Load(IFileManager & fileManager,const string_view uri)161 PipelineLayoutLoader::LoadResult PipelineLayoutLoader::Load(IFileManager& fileManager, const string_view uri)
162 {
163 uri_ = uri;
164
165 IFile::Ptr file = fileManager.OpenFile(uri);
166 if (!file) {
167 PLUGIN_LOG_E("Error loading '%s'", string(uri).c_str());
168 return LoadResult("Failed to open file.");
169 }
170
171 const uint64_t byteLength = file->GetLength();
172
173 string raw;
174 raw.resize(static_cast<size_t>(byteLength));
175
176 if (file->Read(raw.data(), byteLength) != byteLength) {
177 PLUGIN_LOG_E("Error loading '%s'", string(uri).c_str());
178 return LoadResult("Failed to read file.");
179 }
180
181 return Load(string_view(raw));
182 }
183 RENDER_END_NAMESPACE()
184