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