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_render_post_processes_generic.h"
17
18 #include <base/math/mathf.h>
19 #include <base/util/uid_util.h>
20 #include <core/plugin/intf_class_factory.h>
21 #include <core/property/property_handle_util.h>
22 #include <render/datastore/intf_render_data_store_manager.h>
23 #include <render/device/intf_gpu_resource_manager.h>
24 #include <render/device/pipeline_layout_desc.h>
25 #include <render/device/pipeline_state_desc.h>
26 #include <render/intf_render_context.h>
27 #include <render/namespace.h>
28 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
29 #include <render/nodecontext/intf_node_context_pso_manager.h>
30 #include <render/nodecontext/intf_render_command_list.h>
31 #include <render/nodecontext/intf_render_node_context_manager.h>
32 #include <render/nodecontext/intf_render_node_graph_share_manager.h>
33 #include <render/nodecontext/intf_render_node_parser_util.h>
34 #include <render/nodecontext/intf_render_node_util.h>
35 #include <render/nodecontext/intf_render_post_process.h>
36 #include <render/property/property_types.h>
37
38 #include "datastore/render_data_store_render_post_processes.h"
39 #include "default_engine_constants.h"
40 #include "device/gpu_resource_handle_util.h"
41 #include "util/log.h"
42
43 using namespace BASE_NS;
44 using namespace CORE_NS;
45
46 RENDER_BEGIN_NAMESPACE()
47 namespace {
48 constexpr string_view INPUT = "input";
49 constexpr string_view OUTPUT = "output";
50
GetImageRenderArea(const IRenderNodeGpuResourceManager & gpuResourceMgr,const RenderHandle handle)51 RenderPassDesc::RenderArea GetImageRenderArea(
52 const IRenderNodeGpuResourceManager& gpuResourceMgr, const RenderHandle handle)
53 {
54 const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(handle);
55 return { 0U, 0U, desc.width, desc.height };
56 }
57 } // namespace
58
InitNode(IRenderNodeContextManager & renderNodeContextMgr)59 void RenderNodeRenderPostProcessesGeneric::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
60 {
61 renderNodeContextMgr_ = &renderNodeContextMgr;
62
63 valid_ = false;
64 allPostProcesses_ = {};
65
66 ParseRenderNodeInputs();
67 UpdateImageData();
68 RegisterOutputs();
69 }
70
PreExecuteFrame()71 void RenderNodeRenderPostProcessesGeneric::PreExecuteFrame()
72 {
73 const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
74 inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
75 UpdateImageData();
76 ProcessPostProcessConfiguration();
77 RegisterOutputs();
78
79 // possible inits called here
80 if (allPostProcesses_.newPostProcesses) {
81 allPostProcesses_.newPostProcesses = false;
82
83 vector<DescriptorCounts> descriptorCounts;
84 descriptorCounts.reserve(allPostProcesses_.postProcessNodeInstances.size());
85
86 for (const auto& ppNodeRef : allPostProcesses_.postProcessNodeInstances) {
87 if (ppNodeRef.ppNode) {
88 const IRenderPostProcess::Ptr* rpp = nullptr;
89 for (const auto& ppRef : allPostProcesses_.pipeline.postProcesses) {
90 // match the id for client-side properties
91 if (ppNodeRef.id == ppRef.id) {
92 rpp = &ppRef.postProcess;
93 break;
94 }
95 }
96 if (rpp) {
97 ppNodeRef.ppNode->Init(*rpp, *renderNodeContextMgr_);
98 descriptorCounts.push_back(ppNodeRef.ppNode->GetRenderDescriptorCounts());
99 }
100 }
101 }
102 // add copy descriptor sets
103 descriptorCounts.push_back(renderCopy_.GetRenderDescriptorCounts());
104
105 // reset descriptor sets
106 INodeContextDescriptorSetManager& dsMgr = renderNodeContextMgr_->GetDescriptorSetManager();
107 dsMgr.ResetAndReserve(descriptorCounts);
108
109 renderCopy_.Init(*renderNodeContextMgr_);
110 } else if (copyInitNeeded_) {
111 vector<DescriptorCounts> descriptorCounts;
112
113 // add copy descriptor sets
114 descriptorCounts.push_back(renderCopy_.GetRenderDescriptorCounts());
115
116 // reset descriptor sets
117 INodeContextDescriptorSetManager& dsMgr = renderNodeContextMgr_->GetDescriptorSetManager();
118 dsMgr.ResetAndReserve(descriptorCounts);
119
120 renderCopy_.Init(*renderNodeContextMgr_);
121 }
122 copyInitNeeded_ = false;
123
124 RenderPassDesc::RenderArea renderArea =
125 GetImageRenderArea(renderNodeContextMgr_->GetGpuResourceManager(), builtInVariables_.output);
126 allPostProcesses_.postProcessCount = 0U;
127
128 const RenderHandle output =
129 RenderHandleUtil::IsValid(builtInVariables_.output) ? builtInVariables_.output : builtInVariables_.defOutput;
130 BindableImage biInput;
131 biInput.handle =
132 RenderHandleUtil::IsValid(builtInVariables_.input) ? builtInVariables_.input : builtInVariables_.defInput;
133 BindableImage biOutput;
134 biOutput.handle = output;
135
136 // pre-execute in correct order
137 const auto ppCount = static_cast<uint32_t>(allPostProcesses_.pipeline.postProcesses.size());
138 for (uint32_t ppIndex = 0; ppIndex < ppCount; ++ppIndex) {
139 const auto& ppRef = allPostProcesses_.pipeline.postProcesses[ppIndex];
140 for (auto& ppNodeRef : allPostProcesses_.postProcessNodeInstances) {
141 if (ppNodeRef.ppNode && (ppNodeRef.id == ppRef.id)) {
142 auto& ppNode = *ppNodeRef.ppNode;
143
144 CORE_NS::SetPropertyValue(ppNode.GetRenderInputProperties(), "input", biInput);
145 // try to force the final target for the final post process
146 // the effect might not accept this and then we need an extra blit in the end
147 if (ppIndex == (ppCount - 1U)) {
148 CORE_NS::SetPropertyValue(ppNode.GetRenderOutputProperties(), "output", biOutput);
149 }
150
151 ppNodeRef.ppNode->SetRenderAreaRequest({ renderArea });
152 ppNodeRef.ppNode->PreExecute();
153
154 // take output and route to next input
155 biInput = CORE_NS::GetPropertyValue<BindableImage>(ppNode.GetRenderOutputProperties(), "output");
156
157 allPostProcesses_.postProcessCount++;
158 break;
159 }
160 }
161 }
162 }
163
GetExecuteFlags() const164 IRenderNode::ExecuteFlags RenderNodeRenderPostProcessesGeneric::GetExecuteFlags() const
165 {
166 if (valid_ && (!allPostProcesses_.pipeline.postProcesses.empty())) {
167 return IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DEFAULT;
168 } else {
169 return IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE;
170 }
171 }
172
ExecuteFrame(IRenderCommandList & cmdList)173 void RenderNodeRenderPostProcessesGeneric::ExecuteFrame(IRenderCommandList& cmdList)
174 {
175 const RenderHandle output =
176 RenderHandleUtil::IsValid(builtInVariables_.output) ? builtInVariables_.output : builtInVariables_.defOutput;
177 BindableImage biInput;
178 biInput.handle =
179 RenderHandleUtil::IsValid(builtInVariables_.input) ? builtInVariables_.input : builtInVariables_.defInput;
180 BindableImage biOutput;
181 biOutput.handle = output;
182 const auto ppCount = static_cast<uint32_t>(allPostProcesses_.pipeline.postProcesses.size());
183 // execute in correct order
184 for (uint32_t ppIndex = 0; ppIndex < ppCount; ++ppIndex) {
185 const auto& ppRef = allPostProcesses_.pipeline.postProcesses[ppIndex];
186 for (auto& ppNodeRef : allPostProcesses_.postProcessNodeInstances) {
187 if (ppNodeRef.ppNode && (ppNodeRef.id == ppRef.id) && (ppNodeRef.ppNode->GetExecuteFlags() == 0U)) {
188 auto& ppNode = *ppNodeRef.ppNode;
189
190 CORE_NS::SetPropertyValue(ppNode.GetRenderInputProperties(), "input", biInput);
191 // try to force the final target for the final post process
192 // the effect might not accept this and then we need an extra blit in the end
193 if (ppIndex == (allPostProcesses_.postProcessCount - 1U)) {
194 CORE_NS::SetPropertyValue(ppNode.GetRenderOutputProperties(), "output", biOutput);
195 }
196
197 ppNode.Execute(cmdList);
198
199 // take output and route to next input
200 biInput = CORE_NS::GetPropertyValue<BindableImage>(ppNode.GetRenderOutputProperties(), "output");
201 }
202 }
203 }
204
205 if (biInput.handle != biOutput.handle) {
206 IRenderNodeCopyUtil::CopyInfo copyInfo;
207 copyInfo.input = biInput;
208 copyInfo.output = biOutput;
209 renderCopy_.PreExecute();
210 renderCopy_.Execute(cmdList, copyInfo);
211 }
212 }
213
RegisterOutputs()214 void RenderNodeRenderPostProcessesGeneric::RegisterOutputs()
215 {
216 const RenderHandle output = builtInVariables_.output;
217 IRenderNodeGraphShareManager& shrMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
218 RenderHandle registerOutput;
219 if (valid_) {
220 if (RenderHandleUtil::IsValid(output)) {
221 registerOutput = output;
222 }
223 }
224 if (!RenderHandleUtil::IsValid(registerOutput)) {
225 if (((jsonInputs_.defaultOutputImage == DefaultInOutImage::OUTPUT) ||
226 (jsonInputs_.defaultOutputImage == DefaultInOutImage::INPUT_OUTPUT_COPY)) &&
227 RenderHandleUtil::IsValid(output)) {
228 registerOutput = output;
229 } else if ((jsonInputs_.defaultOutputImage == DefaultInOutImage::INPUT) &&
230 RenderHandleUtil::IsValid(builtInVariables_.input)) {
231 registerOutput = builtInVariables_.input;
232 } else {
233 registerOutput = builtInVariables_.defOutput;
234 }
235 }
236 shrMgr.RegisterRenderNodeOutput("output", registerOutput);
237 }
238
ProcessPostProcessConfiguration()239 void RenderNodeRenderPostProcessesGeneric::ProcessPostProcessConfiguration()
240 {
241 if (!jsonInputs_.renderDataStore.dataStoreName.empty()) {
242 auto& dsMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
243 if (const IRenderDataStore* ds = dsMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName); ds) {
244 if (jsonInputs_.renderDataStore.typeName == RenderDataStoreRenderPostProcesses::TYPE_NAME) {
245 auto* const dataStore = static_cast<const IRenderDataStoreRenderPostProcesses*>(ds);
246 allPostProcesses_.pipeline = dataStore->GetData(jsonInputs_.renderDataStore.configurationName);
247 valid_ = true;
248 }
249 }
250 }
251 // process new instances
252 auto* renderClassFactory = renderNodeContextMgr_->GetRenderContext().GetInterface<IClassFactory>();
253 if (valid_ && renderClassFactory) {
254 auto& pp = allPostProcesses_;
255 for (const auto& ppRef : pp.pipeline.postProcesses) {
256 if (!ppRef.postProcess) {
257 continue;
258 }
259 bool createNew = true;
260 for (const auto& iRef : pp.postProcessNodeInstances) {
261 if (iRef.id == ppRef.id) {
262 createNew = false;
263 break;
264 }
265 }
266 if (createNew) {
267 IRenderPostProcessNode::Ptr rppn = CreateInstance<IRenderPostProcessNode>(
268 *renderClassFactory, ppRef.postProcess->GetRenderPostProcessNodeUid());
269 if (rppn) {
270 pp.postProcessNodeInstances.push_back({ ppRef.id, rppn });
271 pp.newPostProcesses = true; // flag for init and descriptor set management
272 } else {
273 PLUGIN_LOG_ONCE_W("pp_node_not_found_" + to_string(ppRef.id),
274 "Post process node not found (uid:%s)",
275 to_string(ppRef.postProcess->GetRenderPostProcessNodeUid()).c_str());
276 }
277 }
278 }
279 }
280 }
281
ParseRenderNodeInputs()282 void RenderNodeRenderPostProcessesGeneric::ParseRenderNodeInputs()
283 {
284 const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
285 const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
286 jsonInputs_.resources = parserUtil.GetInputResources(jsonVal, "resources");
287 jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
288
289 #if (RENDER_VALIDATION_ENABLED == 1)
290 if (jsonInputs_.renderDataStore.dataStoreName.empty()) {
291 PLUGIN_LOG_W("RENDER_VALIDATION: RN %s renderDataStore::dataStoreName missing.",
292 renderNodeContextMgr_->GetName().data());
293 }
294 if (jsonInputs_.renderDataStore.configurationName.empty()) {
295 PLUGIN_LOG_W("RENDER_VALIDATION: RN %s postProcess name missing.", renderNodeContextMgr_->GetName().data());
296 }
297 #endif
298
299 auto GetDefaultInOutImage = [](const string& ioStr, const DefaultInOutImage defaultImg) {
300 DefaultInOutImage defImg = defaultImg;
301 if (!ioStr.empty()) {
302 if (ioStr == "output") {
303 defImg = DefaultInOutImage::OUTPUT;
304 } else if (ioStr == "input_output_copy") {
305 defImg = DefaultInOutImage::INPUT_OUTPUT_COPY;
306 } else if (ioStr == "input") {
307 defImg = DefaultInOutImage::INPUT;
308 } else if (ioStr == "black") {
309 defImg = DefaultInOutImage::BLACK;
310 } else if (ioStr == "white") {
311 defImg = DefaultInOutImage::WHITE;
312 } else {
313 PLUGIN_LOG_W("RenderNodeRenderPostProcessesGeneric default input/output image not supported (%s)",
314 ioStr.c_str());
315 }
316 }
317 return defImg;
318 };
319 const auto defaultOutput = parserUtil.GetStringValue(jsonVal, "defaultOutputImage");
320 jsonInputs_.defaultOutputImage = GetDefaultInOutImage(defaultOutput, jsonInputs_.defaultOutputImage);
321 const auto defaultInput = parserUtil.GetStringValue(jsonVal, "defaultInputImage");
322 jsonInputs_.defaultInputImage = GetDefaultInOutImage(defaultOutput, jsonInputs_.defaultInputImage);
323
324 const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
325 inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
326
327 // process custom resources
328 for (uint32_t idx = 0; idx < static_cast<uint32_t>(jsonInputs_.resources.customInputImages.size()); ++idx) {
329 const auto& ref = jsonInputs_.resources.customInputImages[idx];
330 if (ref.usageName == INPUT) {
331 jsonInputs_.inputIdx = idx;
332 }
333 }
334 for (uint32_t idx = 0; idx < static_cast<uint32_t>(jsonInputs_.resources.customOutputImages.size()); ++idx) {
335 const auto& ref = jsonInputs_.resources.customOutputImages[idx];
336 if (ref.usageName == OUTPUT) {
337 jsonInputs_.outputIdx = idx;
338 }
339 }
340 }
341
UpdateImageData()342 void RenderNodeRenderPostProcessesGeneric::UpdateImageData()
343 {
344 const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
345 if (!RenderHandleUtil::IsValid(builtInVariables_.defBlackImage)) {
346 builtInVariables_.defBlackImage =
347 gpuResourceMgr.GetImageHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_IMAGE);
348 }
349 if (!RenderHandleUtil::IsValid(builtInVariables_.defWhiteImage)) {
350 builtInVariables_.defWhiteImage =
351 gpuResourceMgr.GetImageHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_IMAGE_WHITE);
352 }
353 if (!RenderHandleUtil::IsValid(builtInVariables_.defSampler)) {
354 builtInVariables_.defSampler =
355 gpuResourceMgr.GetSamplerHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP);
356 }
357 if (jsonInputs_.inputIdx < inputResources_.customInputImages.size()) {
358 builtInVariables_.input = inputResources_.customInputImages[jsonInputs_.inputIdx].handle;
359 }
360 if (jsonInputs_.outputIdx < inputResources_.customOutputImages.size()) {
361 builtInVariables_.output = inputResources_.customOutputImages[jsonInputs_.outputIdx].handle;
362 }
363
364 // default in / out if not correct
365 if (!RenderHandleUtil::IsValid(builtInVariables_.defInput)) {
366 if (jsonInputs_.defaultInputImage == DefaultInOutImage::WHITE) {
367 builtInVariables_.defInput = builtInVariables_.defWhiteImage;
368 } else if (jsonInputs_.defaultInputImage == DefaultInOutImage::BLACK) {
369 builtInVariables_.defInput = builtInVariables_.defBlackImage;
370 }
371 }
372 if (!RenderHandleUtil::IsValid(builtInVariables_.defOutput)) {
373 if (jsonInputs_.defaultOutputImage == DefaultInOutImage::WHITE) {
374 builtInVariables_.defOutput = builtInVariables_.defWhiteImage;
375 } else if (jsonInputs_.defaultOutputImage == DefaultInOutImage::BLACK) {
376 builtInVariables_.defOutput = builtInVariables_.defBlackImage;
377 }
378 }
379 }
380
381 // for plugin / factory interface
Create()382 IRenderNode* RenderNodeRenderPostProcessesGeneric::Create()
383 {
384 return new RenderNodeRenderPostProcessesGeneric();
385 }
386
Destroy(IRenderNode * instance)387 void RenderNodeRenderPostProcessesGeneric::Destroy(IRenderNode* instance)
388 {
389 delete static_cast<RenderNodeRenderPostProcessesGeneric*>(instance);
390 }
391 RENDER_END_NAMESPACE()
392