• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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