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 "render_node_graph_loader.h"
17
18 #include <charconv>
19
20 #include <base/containers/fixed_string.h>
21 #include <base/containers/vector.h>
22 #include <base/math/matrix_util.h>
23 #include <core/io/intf_file.h>
24 #include <core/io/intf_file_manager.h>
25 #include <render/namespace.h>
26 #include <render/nodecontext/intf_render_node_graph_manager.h>
27 #include <render/render_data_structures.h>
28
29 #include "json_util.h"
30 #include "util/log.h"
31
32 using namespace BASE_NS;
33 using namespace CORE_NS;
34
35 RENDER_BEGIN_NAMESPACE()
36 RENDER_JSON_SERIALIZE_ENUM(GpuQueue::QueueType,
37 { { GpuQueue::QueueType::UNDEFINED, nullptr }, { GpuQueue::QueueType::GRAPHICS, "graphics" },
38 { GpuQueue::QueueType::COMPUTE, "compute" }, { GpuQueue::QueueType::TRANSFER, "transfer" } })
39
40 namespace {
41 constexpr size_t VERSION_SIZE { 5u };
42 constexpr uint32_t VERSION_MAJOR { 22u };
43 constexpr size_t MAX_OUTPUT_RESOURCE_COUNT { 32u };
44 constexpr size_t MAX_RNG_RENDER_NODE_COUNT { 256u };
45
ParseQueueWaitSignals(const json::value & node,RenderNodeDesc & data,IRenderNodeGraphLoader::LoadResult & nodeResult)46 void ParseQueueWaitSignals(
47 const json::value& node, RenderNodeDesc& data, [[maybe_unused]] IRenderNodeGraphLoader::LoadResult& nodeResult)
48 {
49 if (auto const queueSignals = node.find("gpuQueueWaitSignals"); queueSignals) {
50 if (auto const typeNames = queueSignals->find("typeNames"); typeNames) {
51 if (typeNames->is_array()) {
52 FromJson(*typeNames, data.description.gpuQueueWaitForSignals.typeNames);
53 }
54 }
55 if (auto const nodeNames = queueSignals->find("nodeNames"); nodeNames) {
56 if (nodeNames->is_array()) {
57 FromJson(*nodeNames, data.description.gpuQueueWaitForSignals.nodeNames);
58 }
59 }
60 #if (RENDER_VALIDATION_ENABLED == 1)
61 if (data.description.gpuQueueWaitForSignals.nodeNames.size() >
62 PipelineStateConstants::MAX_RENDER_NODE_GPU_WAIT_SIGNALS) {
63 nodeResult.error += "gpuQueueWaitSignal count must be smaller than" +
64 to_string(PipelineStateConstants::MAX_RENDER_NODE_GPU_WAIT_SIGNALS) + ")\n";
65 }
66 if (data.description.gpuQueueWaitForSignals.typeNames.size() >
67 PipelineStateConstants::MAX_RENDER_NODE_GPU_WAIT_SIGNALS) {
68 nodeResult.error += "gpuQueueWaitSignal count must be smaller than" +
69 to_string(PipelineStateConstants::MAX_RENDER_NODE_GPU_WAIT_SIGNALS) + ")\n";
70 }
71 #endif
72 }
73 }
74
ParseRenderNode(const json::value & node,RenderNodeDesc & data)75 IRenderNodeGraphLoader::LoadResult ParseRenderNode(const json::value& node, RenderNodeDesc& data)
76 {
77 IRenderNodeGraphLoader::LoadResult nodeResult;
78
79 SafeGetJsonValue(node, "typeName", nodeResult.error, data.typeName);
80 SafeGetJsonValue(node, "nodeName", nodeResult.error, data.nodeName);
81 // render node specific json
82 data.nodeJson = json::to_string(node);
83 SafeGetJsonValue(node, "nodeDataStoreName", nodeResult.error, data.description.nodeDataStoreName);
84
85 if (auto const queue = node.find("queue"); queue) {
86 SafeGetJsonEnum(*queue, "type", nodeResult.error, data.description.queue.type);
87 SafeGetJsonValue(*queue, "index", nodeResult.error, data.description.queue.index);
88 }
89
90 if (auto const cpuDependencies = node.find("cpuDependencies"); cpuDependencies) {
91 if (auto const typeNames = cpuDependencies->find("typeNames"); typeNames) {
92 if (typeNames->is_array()) {
93 FromJson(*typeNames, data.description.cpuDependencies.typeNames);
94 }
95 }
96 if (auto const nodeNames = cpuDependencies->find("nodeNames"); nodeNames) {
97 if (nodeNames->is_array()) {
98 FromJson(*nodeNames, data.description.cpuDependencies.nodeNames);
99 }
100 }
101 }
102 ParseQueueWaitSignals(node, data, nodeResult);
103
104 return nodeResult;
105 }
106
ParseOutputResources(const json::value & node,RenderNodeGraphOutputResource & data)107 IRenderNodeGraphLoader::LoadResult ParseOutputResources(const json::value& node, RenderNodeGraphOutputResource& data)
108 {
109 IRenderNodeGraphLoader::LoadResult nodeResult;
110
111 SafeGetJsonValue(node, "nodeName", nodeResult.error, data.nodeName);
112 SafeGetJsonValue(node, "name", nodeResult.error, data.name);
113
114 return nodeResult;
115 }
116
CompatibilityCheck(const json::value & json,RenderNodeGraphLoader::LoadResult & result)117 void CompatibilityCheck(const json::value& json, RenderNodeGraphLoader::LoadResult& result)
118 {
119 string ver;
120 string type;
121 uint32_t verMajor { ~0u };
122 uint32_t verMinor { ~0u };
123 if (const json::value* iter = json.find("compatibility_info"); iter) {
124 SafeGetJsonValue(*iter, "version", result.error, ver);
125 SafeGetJsonValue(*iter, "type", result.error, type);
126 if (ver.size() == VERSION_SIZE) {
127 if (const auto delim = ver.find('.'); delim != string::npos) {
128 std::from_chars(ver.data(), ver.data() + delim, verMajor);
129 std::from_chars(ver.data() + delim + 1, ver.data() + ver.size(), verMinor);
130 }
131 }
132 }
133 if ((type != "rendernodegraph") || (verMajor != VERSION_MAJOR)) {
134 result.error += "invalid render node graph type (" + type + ") and/or version (" + ver + ").";
135 result.success = false;
136 }
137 }
138
GetRenderNodeDescs(const json::value & json,string & error)139 vector<RenderNodeDesc> GetRenderNodeDescs(const json::value& json, string& error)
140 {
141 vector<RenderNodeDesc> nodeDescriptors;
142 if (const auto nodes = json.find("nodes"); nodes) {
143 if (nodes->is_array()) {
144 nodeDescriptors.reserve(nodes->array_.size());
145 for (auto const& node : nodes->array_) {
146 RenderNodeDesc data;
147 RenderNodeGraphLoader::LoadResult nodeResult = ParseRenderNode(node, data);
148 if (nodeResult.error.empty()) {
149 nodeDescriptors.push_back(move(data));
150 } else {
151 error += nodeResult.error;
152 }
153 }
154 } else {
155 error += "\"nodes\" must to be an array.";
156 }
157 }
158 if (nodeDescriptors.size() > MAX_RNG_RENDER_NODE_COUNT) {
159 nodeDescriptors.resize(MAX_RNG_RENDER_NODE_COUNT);
160 #if (RENDER_VALIDATION_ENABLED == 1)
161 PLUGIN_LOG_W("Render node graph max render node count exceeded");
162 #endif
163 }
164 return nodeDescriptors;
165 }
166
GetRenderNodeOutputResources(const json::value & json,string & error)167 vector<RenderNodeGraphOutputResource> GetRenderNodeOutputResources(const json::value& json, string& error)
168 {
169 vector<RenderNodeGraphOutputResource> outputResources;
170 if (const auto nodes = json.find("renderNodeGraphOutputResources"); nodes) {
171 outputResources.reserve(nodes->array_.size());
172 for (auto const& node : nodes->array_) {
173 RenderNodeGraphOutputResource data;
174 RenderNodeGraphLoader::LoadResult nodeResult = ParseOutputResources(node, data);
175 if (nodeResult.error.empty()) {
176 outputResources.push_back(move(data));
177 } else {
178 error += nodeResult.error;
179 }
180 }
181 }
182 if (outputResources.size() > MAX_OUTPUT_RESOURCE_COUNT) {
183 outputResources.resize(MAX_OUTPUT_RESOURCE_COUNT);
184 #if (RENDER_VALIDATION_ENABLED == 1)
185 PLUGIN_LOG_W("Render node graph max output resource count exceeded");
186 #endif
187 }
188 return outputResources;
189 }
190
LoadFromNullTerminated(const string_view uri,const string_view jsonString)191 IRenderNodeGraphLoader::LoadResult LoadFromNullTerminated(const string_view uri, const string_view jsonString)
192 {
193 if (const auto json = json::parse(jsonString.data()); json) {
194 IRenderNodeGraphLoader::LoadResult finalResult;
195 CompatibilityCheck(json, finalResult);
196 if (!finalResult.success) {
197 return finalResult; // compatibility check failed
198 }
199
200 string renderNodeGraphName;
201 string renderNodeGraphDataStoreName;
202 SafeGetJsonValue(json, "renderNodeGraphName", finalResult.error, renderNodeGraphName);
203 SafeGetJsonValue(json, "renderNodeGraphDataStoreName", finalResult.error, renderNodeGraphDataStoreName);
204
205 vector<RenderNodeDesc> nodeDescriptors = GetRenderNodeDescs(json, finalResult.error);
206 vector<RenderNodeGraphOutputResource> outputResources = GetRenderNodeOutputResources(json, finalResult.error);
207
208 finalResult.success = finalResult.error.empty();
209 if (finalResult.error.empty()) {
210 finalResult.desc.renderNodeGraphName = renderNodeGraphName;
211 finalResult.desc.renderNodeGraphDataStoreName = renderNodeGraphDataStoreName;
212 finalResult.desc.renderNodeGraphUri = uri;
213 finalResult.desc.nodes = move(nodeDescriptors);
214 finalResult.desc.outputResources = move(outputResources);
215 }
216
217 return finalResult;
218 } else {
219 return IRenderNodeGraphLoader::LoadResult("Invalid render node graph json file.");
220 }
221 }
222 } // namespace
223
RenderNodeGraphLoader(IFileManager & fileManager)224 RenderNodeGraphLoader::RenderNodeGraphLoader(IFileManager& fileManager) : fileManager_(fileManager) {}
225
Load(const string_view uri)226 RenderNodeGraphLoader::LoadResult RenderNodeGraphLoader::Load(const string_view uri)
227 {
228 IFile::Ptr file = fileManager_.OpenFile(uri);
229 if (!file) {
230 PLUGIN_LOG_D("Error loading '%s'", string(uri).c_str());
231 return LoadResult("Failed to open file.");
232 }
233
234 const uint64_t byteLength = file->GetLength();
235
236 string raw(static_cast<size_t>(byteLength), string::value_type());
237 if (file->Read(raw.data(), byteLength) != byteLength) {
238 PLUGIN_LOG_D("Error loading '%s'", string(uri).c_str());
239 return LoadResult("Failed to read file.");
240 }
241
242 return LoadFromNullTerminated(uri, raw);
243 }
244
LoadString(const string_view jsonString)245 RenderNodeGraphLoader::LoadResult RenderNodeGraphLoader::LoadString(const string_view jsonString)
246 {
247 // make sure the input is zero terminated before parsing.
248 const auto asString = string(jsonString);
249 return LoadFromNullTerminated("", asString);
250 }
251 RENDER_END_NAMESPACE()
252