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_mip_chain_post_process.h"
17 
18 #include <algorithm>
19 
20 #include <base/containers/string_view.h>
21 #include <base/containers/type_traits.h>
22 #include <base/math/mathf.h>
23 #include <render/datastore/intf_render_data_store_manager.h>
24 #include <render/datastore/intf_render_data_store_pod.h>
25 #include <render/datastore/render_data_store_render_pods.h>
26 #include <render/device/intf_gpu_resource_manager.h>
27 #include <render/device/intf_shader_manager.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/shaders/common/render_post_process_structs_common.h>
36 
37 #include "datastore/render_data_store_pod.h"
38 #include "datastore/render_data_store_post_process.h"
39 #include "default_engine_constants.h"
40 #include "util/log.h"
41 
42 using namespace BASE_NS;
43 
44 RENDER_BEGIN_NAMESPACE()
45 namespace {
46 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
47 
48 constexpr uint32_t GLOBAL_POST_PROCESS_SET { 0u };
49 constexpr uint32_t LOCAL_POST_PROCESS_SET { 1u };
50 constexpr string_view RENDER_DATA_STORE_POD_NAME { RenderDataStorePod::TYPE_NAME };
51 constexpr string_view INPUT = "input";
52 constexpr string_view OUTPUT = "output";
53 
54 constexpr string_view POST_PROCESS_BASE_PIPELINE_LAYOUT { "renderpipelinelayouts://post_process_common.shaderpl" };
55 
56 constexpr uint32_t MAX_MIP_COUNT { 16u };
57 constexpr uint32_t MAX_PASS_PER_LEVEL_COUNT { 1u };
58 constexpr uint32_t MAX_LOCAL_BINDER_COUNT = MAX_MIP_COUNT * MAX_PASS_PER_LEVEL_COUNT;
59 
CreatePostProcessDataUniformBuffer(IRenderNodeGpuResourceManager & gpuResourceMgr,const RenderHandleReference & handle)60 RenderHandleReference CreatePostProcessDataUniformBuffer(
61     IRenderNodeGpuResourceManager& gpuResourceMgr, const RenderHandleReference& handle)
62 {
63     PLUGIN_STATIC_ASSERT(sizeof(GlobalPostProcessStruct) == sizeof(RenderPostProcessConfiguration));
64     PLUGIN_STATIC_ASSERT(
65         sizeof(LocalPostProcessStruct) == PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE);
66     return gpuResourceMgr.Create(
67         handle, GpuBufferDesc { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
68                     (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
69                     CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER,
70                     sizeof(GlobalPostProcessStruct) + sizeof(LocalPostProcessStruct) });
71 }
72 
GetBindableImage(const RenderHandle & res)73 inline BindableImage GetBindableImage(const RenderHandle& res)
74 {
75     return BindableImage { res, PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS,
76         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS, ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED, {} };
77 }
78 } // namespace
79 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)80 void RenderNodeMipChainPostProcess::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
81 {
82     renderNodeContextMgr_ = &renderNodeContextMgr;
83 
84     valid_ = true;
85     ubos_.postProcess =
86         CreatePostProcessDataUniformBuffer(renderNodeContextMgr.GetGpuResourceManager(), ubos_.postProcess);
87 
88     ParseRenderNodeInputs();
89     UpdateImageData();
90     ProcessPostProcessConfiguration();
91 
92     if (RenderHandleUtil::GetHandleType(pipelineData_.shader) != RenderHandleType::SHADER_STATE_OBJECT) {
93         PLUGIN_LOG_E("CORE_RN_MIP_CHAIN_POST_PROCESS needs a valid shader handle");
94     }
95 
96     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
97     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
98     const RenderHandleType handleType = RenderHandleUtil::GetHandleType(pipelineData_.shader);
99     if (handleType == RenderHandleType::SHADER_STATE_OBJECT) {
100         pipelineData_.graphics = true;
101     } else if (handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT) {
102         pipelineData_.graphics = false;
103         pipelineData_.threadGroupSize = shaderMgr.GetReflectionThreadGroupSize(pipelineData_.shader);
104         if (dispatchResources_.customInputBuffers.empty() && dispatchResources_.customInputImages.empty()) {
105             valid_ = false;
106             PLUGIN_LOG_W("CORE_RN_MIP_CHAIN_POST_PROCESS: dispatchResources (GPU buffer or GPU image) needed");
107         }
108     }
109 
110     {
111         if (!((handleType == RenderHandleType::SHADER_STATE_OBJECT) ||
112                 (handleType == RenderHandleType::COMPUTE_SHADER_STATE_OBJECT))) {
113             PLUGIN_LOG_E("RN:%s needs a valid shader handle", renderNodeContextMgr_->GetName().data());
114         }
115         pipelineData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayoutHandle(pipelineData_.shader);
116         pipelineData_.pipelineLayoutData = shaderMgr.GetPipelineLayout(pipelineData_.pipelineLayout);
117         if (pipelineData_.graphics) {
118             const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(pipelineData_.shader);
119             pipelineData_.pso = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(pipelineData_.shader,
120                 graphicsState, pipelineData_.pipelineLayoutData, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
121         } else {
122             pipelineData_.pso = renderNodeContextMgr.GetPsoManager().GetComputePsoHandle(
123                 pipelineData_.shader, pipelineData_.pipelineLayout, {});
124         }
125 
126         // NOTE: cannot be compared with shaderMgr.GetCompatibilityFlags due to missing pipeline layout handle
127         const RenderHandle basePlHandle = shaderMgr.GetPipelineLayoutHandle(POST_PROCESS_BASE_PIPELINE_LAYOUT);
128         const IShaderManager::CompatibilityFlags compatibilityFlags =
129             shaderMgr.GetCompatibilityFlags(basePlHandle, pipelineData_.pipelineLayout);
130         if ((compatibilityFlags & IShaderManager::CompatibilityFlagBits::COMPATIBLE_BIT) == 0) {
131             PLUGIN_LOG_E("RN:%s uncompatible pipeline layout to %s", renderNodeContextMgr_->GetName().data(),
132                 POST_PROCESS_BASE_PIPELINE_LAYOUT.data());
133         }
134     }
135 
136     {
137         DescriptorCounts dc = renderNodeUtil.GetDescriptorCounts(pipelineData_.pipelineLayoutData);
138         // NOTE: hard-coded mip chain
139         dc.counts.push_back({ CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, MAX_LOCAL_BINDER_COUNT });
140         dc.counts.push_back({ CORE_DESCRIPTOR_TYPE_SAMPLER, MAX_LOCAL_BINDER_COUNT });
141         const DescriptorCounts copyDc = renderCopy_.GetDescriptorCounts();
142         for (const auto& ref : copyDc.counts) {
143             dc.counts.push_back(ref);
144         }
145         renderNodeContextMgr.GetDescriptorSetManager().ResetAndReserve(dc);
146     }
147 
148     {
149         binders_.clear();
150         binders_.resize(MAX_LOCAL_BINDER_COUNT);
151 
152         INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr.GetDescriptorSetManager();
153         {
154             const auto& bindings =
155                 pipelineData_.pipelineLayoutData.descriptorSetLayouts[GLOBAL_POST_PROCESS_SET].bindings;
156             const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
157             globalSet0_ = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
158         }
159         const auto& bindings = pipelineData_.pipelineLayoutData.descriptorSetLayouts[LOCAL_POST_PROCESS_SET].bindings;
160         for (uint32_t idx = 0; idx < MAX_LOCAL_BINDER_COUNT; ++idx) {
161             const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
162             binders_[idx] = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
163         }
164     }
165 
166     renderCopy_.Init(renderNodeContextMgr, {});
167     RegisterOutputs(builtInVariables_.output);
168 }
169 
PreExecuteFrame()170 void RenderNodeMipChainPostProcess::PreExecuteFrame()
171 {
172     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
173     if (jsonInputs_.hasChangeableResourceHandles) {
174         inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
175     }
176     UpdateImageData();
177     ProcessPostProcessConfiguration();
178     if (pipelineData_.graphics && GetRequiresPreCopy()) {
179         RenderCopy::CopyInfo copyInfo { GetBindableImage(builtInVariables_.input),
180             GetBindableImage(builtInVariables_.output), {} };
181         renderCopy_.PreExecute(*renderNodeContextMgr_, copyInfo);
182     }
183     RegisterOutputs(builtInVariables_.output);
184 }
185 
ExecuteFrame(IRenderCommandList & cmdList)186 void RenderNodeMipChainPostProcess::ExecuteFrame(IRenderCommandList& cmdList)
187 {
188     if ((!ppLocalConfig_.variables.enabled) &&
189         (jsonInputs_.defaultOutputImage != DefaultOutputImage::INPUT_OUTPUT_COPY)) {
190         return;
191     }
192 
193     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
194     if (jsonInputs_.hasChangeableRenderPassHandles) {
195         inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
196     }
197     if (jsonInputs_.hasChangeableResourceHandles) {
198         inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
199     }
200     if (jsonInputs_.hasChangeableDispatchHandles) {
201         dispatchResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.dispatchResources);
202     }
203     if (useAutoBindSet0_) {
204         UpdateGlobalPostProcessUbo();
205     }
206 
207     if (pipelineData_.graphics) {
208         RenderGraphics(cmdList);
209     } else {
210         RenderCompute(cmdList);
211     }
212 }
213 
GetExecuteFlags() const214 IRenderNode::ExecuteFlags RenderNodeMipChainPostProcess::GetExecuteFlags() const
215 {
216     if ((!ppLocalConfig_.variables.enabled) &&
217         (jsonInputs_.defaultOutputImage != DefaultOutputImage::INPUT_OUTPUT_COPY)) {
218         return ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE;
219     }
220     return ExecuteFlagBits::EXECUTE_FLAG_BITS_DEFAULT;
221 }
222 
ProcessPostProcessConfiguration()223 void RenderNodeMipChainPostProcess::ProcessPostProcessConfiguration()
224 {
225     if (!jsonInputs_.renderDataStore.dataStoreName.empty()) {
226         auto& dsMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
227         if (const IRenderDataStore* ds = dsMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName)) {
228             if (jsonInputs_.renderDataStore.typeName == RenderDataStorePostProcess::TYPE_NAME) {
229                 auto* const dataStore = static_cast<IRenderDataStorePostProcess const*>(ds);
230                 ppLocalConfig_ = dataStore->Get(jsonInputs_.renderDataStore.configurationName, jsonInputs_.ppName);
231             }
232         }
233         if (const IRenderDataStorePod* ds =
234                 static_cast<const IRenderDataStorePod*>(dsMgr.GetRenderDataStore(RENDER_DATA_STORE_POD_NAME))) {
235             auto const dataView = ds->Get(jsonInputs_.renderDataStore.configurationName);
236             if (dataView.data() && (dataView.size_bytes() == sizeof(PostProcessConfiguration))) {
237                 ppGlobalConfig_ = *((const PostProcessConfiguration*)dataView.data());
238             }
239         }
240     } else if (jsonInputs_.ppName.empty()) {
241         // if trying to just use shader without post processing we enable running by default
242         ppLocalConfig_.variables.enabled = true;
243     }
244 }
245 
UpdateGlobalPostProcessUbo()246 void RenderNodeMipChainPostProcess::UpdateGlobalPostProcessUbo()
247 {
248     auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
249     const RenderPostProcessConfiguration rppc =
250         renderNodeContextMgr_->GetRenderNodeUtil().GetRenderPostProcessConfiguration(ppGlobalConfig_);
251     PLUGIN_STATIC_ASSERT(sizeof(GlobalPostProcessStruct) == sizeof(RenderPostProcessConfiguration));
252     PLUGIN_STATIC_ASSERT(sizeof(LocalPostProcessStruct) ==
253                          sizeof(IRenderDataStorePostProcess::PostProcess::Variables::customPropertyData));
254     if (auto data = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.postProcess.GetHandle())); data) {
255         const auto* dataEnd = data + sizeof(GlobalPostProcessStruct) + sizeof(LocalPostProcessStruct);
256         // global data
257         CloneData(data, size_t(dataEnd - data), &rppc, sizeof(GlobalPostProcessStruct));
258         // local data
259         data += sizeof(GlobalPostProcessStruct);
260         CloneData(
261             data, size_t(dataEnd - data), ppLocalConfig_.variables.customPropertyData, sizeof(LocalPostProcessStruct));
262         gpuResourceMgr.UnmapBuffer(ubos_.postProcess.GetHandle());
263     }
264 }
265 
266 // constants for RenderNodeMipChainPostProcess::RenderData
267 namespace {
268 constexpr bool USE_CUSTOM_BARRIERS = true;
269 
270 constexpr ImageResourceBarrier SRC_UNDEFINED { 0, CORE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, CORE_IMAGE_LAYOUT_UNDEFINED };
271 constexpr ImageResourceBarrier COL_ATTACHMENT { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
272     CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
273 constexpr ImageResourceBarrier SHDR_READ { CORE_ACCESS_SHADER_READ_BIT, CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
274     CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
275 // transition the final mip level to read only as well
276 constexpr ImageResourceBarrier FINAL_SRC { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
277     CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
278     CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
279 constexpr ImageResourceBarrier FINAL_DST { CORE_ACCESS_SHADER_READ_BIT,
280     CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // first possible shader read stage
281     CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
282 } // namespace
283 
GetRequiresPreCopy() const284 bool RenderNodeMipChainPostProcess::GetRequiresPreCopy() const
285 {
286     // check for first copy from another image
287     if (builtInVariables_.input != builtInVariables_.output) {
288         return true;
289     } else {
290         return false;
291     }
292 }
293 
GetBaseRenderPass()294 RenderPass RenderNodeMipChainPostProcess::GetBaseRenderPass()
295 {
296     RenderPass renderPass = renderNodeContextMgr_->GetRenderNodeUtil().CreateRenderPass(inputRenderPass_);
297     RenderHandle imageHandle = renderPass.renderPassDesc.attachmentHandles[0];
298     // find the target image if not provided with the render pass
299     if (!RenderHandleUtil::IsValid(imageHandle)) {
300         if ((!inputResources_.customOutputImages.empty()))
301             imageHandle = inputResources_.customOutputImages[0].handle;
302     }
303     renderPass.renderPassDesc.attachmentCount = 1;
304     renderPass.renderPassDesc.subpassCount = 1;
305     renderPass.renderPassDesc.attachments[0].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
306     renderPass.renderPassDesc.attachments[0].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
307     renderPass.renderPassDesc.attachmentHandles[0] = imageHandle;
308     renderPass.subpassStartIndex = 0;
309     auto& subpass = renderPass.subpassDesc;
310     subpass.colorAttachmentCount = 1;
311     subpass.colorAttachmentIndices[0] = 0;
312     return renderPass;
313 }
314 
UpdateGlobalSet(IRenderCommandList & cmdList)315 void RenderNodeMipChainPostProcess::UpdateGlobalSet(IRenderCommandList& cmdList)
316 {
317     auto& binder = *globalSet0_;
318     binder.ClearBindings();
319     uint32_t binding = 0u;
320     binder.BindBuffer(binding++, BindableBuffer { ubos_.postProcess.GetHandle() });
321     binder.BindBuffer(binding++, BindableBuffer { ubos_.postProcess.GetHandle(), sizeof(GlobalPostProcessStruct) });
322     cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
323 }
324 
RenderGraphics(IRenderCommandList & cmdList)325 void RenderNodeMipChainPostProcess::RenderGraphics(IRenderCommandList& cmdList)
326 {
327     RenderPass renderPass = GetBaseRenderPass();
328 
329     const RenderHandle imageHandle = renderPass.renderPassDesc.attachmentHandles[0];
330     if (!RenderHandleUtil::IsValid(imageHandle)) {
331         return; // early out
332     }
333     const GpuImageDesc imageDesc = renderNodeContextMgr_->GetGpuResourceManager().GetImageDescriptor(imageHandle);
334     if (imageDesc.mipCount <= 1U) {
335         return; // early out
336     }
337     renderPass.renderPassDesc.renderArea = { 0, 0, imageDesc.width, imageDesc.height };
338     // check for first copy from another image
339     if (builtInVariables_.input != builtInVariables_.output) {
340         renderCopy_.Execute(*renderNodeContextMgr_, cmdList);
341     }
342 
343     if constexpr (USE_CUSTOM_BARRIERS) {
344         cmdList.BeginDisableAutomaticBarrierPoints();
345     }
346 
347     UpdateGlobalSet(cmdList);
348 
349     ImageSubresourceRange imageSubresourceRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
350         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
351     for (uint32_t idx = 1U; idx < imageDesc.mipCount; ++idx) {
352         const uint32_t renderPassMipLevel = jsonInputs_.upRamp ? (imageDesc.mipCount - idx - 1) : idx;
353         const uint32_t inputMipLevel = jsonInputs_.upRamp ? (imageDesc.mipCount - idx) : (idx - 1);
354 
355         const uint32_t width = std::max(1u, imageDesc.width >> renderPassMipLevel);
356         const uint32_t height = std::max(1u, imageDesc.height >> renderPassMipLevel);
357         const float fWidth = static_cast<float>(width);
358         const float fHeight = static_cast<float>(height);
359 
360         renderPass.renderPassDesc.renderArea = { 0, 0, width, height };
361         renderPass.renderPassDesc.attachments[0].mipLevel = renderPassMipLevel;
362 
363         if constexpr (USE_CUSTOM_BARRIERS) {
364             imageSubresourceRange.baseMipLevel = renderPassMipLevel;
365             cmdList.CustomImageBarrier(imageHandle, SRC_UNDEFINED, COL_ATTACHMENT, imageSubresourceRange);
366 
367             imageSubresourceRange.baseMipLevel = inputMipLevel;
368             if (inputMipLevel == 0) {
369                 cmdList.CustomImageBarrier(imageHandle, SHDR_READ, imageSubresourceRange);
370             } else {
371                 cmdList.CustomImageBarrier(imageHandle, COL_ATTACHMENT, SHDR_READ, imageSubresourceRange);
372             }
373 
374             cmdList.AddCustomBarrierPoint();
375         }
376 
377         // update local descriptor set
378         {
379             // hard-coded
380             auto& binder = *binders_[idx];
381             uint32_t binding = 0;
382             binder.BindSampler(binding++, BindableSampler { samplerHandle_ });
383             binder.BindImage(binding++, BindableImage { imageHandle, inputMipLevel });
384             cmdList.UpdateDescriptorSet(
385                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
386 #if (RENDER_VALIDATION_ENABLED == 1)
387             if (!binder.GetDescriptorSetLayoutBindingValidity()) {
388                 PLUGIN_LOG_W("RN: %s, bindings missing", renderNodeContextMgr_->GetName().data());
389             }
390 #endif
391         }
392 
393         cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
394 
395         cmdList.SetDynamicStateViewport(ViewportDesc { 0.0f, 0.0f, fWidth, fHeight, 0.0f, 0.0f });
396         cmdList.SetDynamicStateScissor(ScissorDesc { 0, 0, width, height });
397 
398         cmdList.BindPipeline(pipelineData_.pso);
399 
400         // bind all sets
401         {
402             RenderHandle sets[2U] {};
403             sets[0U] = globalSet0_->GetDescriptorSetHandle();
404             sets[1U] = binders_[idx]->GetDescriptorSetHandle();
405             cmdList.BindDescriptorSets(0u, sets);
406         }
407 
408         // push constants
409         if (pipelineData_.pipelineLayoutData.pushConstant.byteSize > 0) {
410             const LocalPostProcessPushConstantStruct pc { { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight },
411                 ppLocalConfig_.variables.factor };
412             cmdList.PushConstantData(pipelineData_.pipelineLayoutData.pushConstant, arrayviewU8(pc));
413         }
414 
415         cmdList.Draw(3U, 1U, 0U, 0U);
416         cmdList.EndRenderPass();
417     }
418 
419     if constexpr (USE_CUSTOM_BARRIERS) {
420         if (imageDesc.mipCount > 1U) {
421             // transition the final mip level
422             imageSubresourceRange.baseMipLevel = imageDesc.mipCount - 1;
423             cmdList.CustomImageBarrier(imageHandle, FINAL_SRC, FINAL_DST, imageSubresourceRange);
424         }
425         cmdList.AddCustomBarrierPoint();
426         cmdList.EndDisableAutomaticBarrierPoints();
427     }
428 }
429 
RenderCompute(IRenderCommandList & cmdList)430 void RenderNodeMipChainPostProcess::RenderCompute(IRenderCommandList& cmdList)
431 {
432     // NOTE: not yet supported
433 }
434 
BindDefaultResources(const uint32_t set,const DescriptorSetLayoutBindingResources & bindings)435 void RenderNodeMipChainPostProcess::BindDefaultResources(
436     const uint32_t set, const DescriptorSetLayoutBindingResources& bindings)
437 {
438     // NOTE: not yet supported
439 }
440 
RegisterOutputs(const RenderHandle output)441 void RenderNodeMipChainPostProcess::RegisterOutputs(const RenderHandle output)
442 {
443     IRenderNodeGraphShareManager& shrMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
444     RenderHandle registerOutput;
445     if (ppLocalConfig_.variables.enabled) {
446         if (RenderHandleUtil::IsValid(output)) {
447             registerOutput = output;
448         }
449     }
450     if (!RenderHandleUtil::IsValid(registerOutput)) {
451         if (((jsonInputs_.defaultOutputImage == DefaultOutputImage::OUTPUT) ||
452                 (jsonInputs_.defaultOutputImage == DefaultOutputImage::INPUT_OUTPUT_COPY)) &&
453             RenderHandleUtil::IsValid(output)) {
454             registerOutput = output;
455         } else if ((jsonInputs_.defaultOutputImage == DefaultOutputImage::INPUT) &&
456                    RenderHandleUtil::IsValid(builtInVariables_.input)) {
457             registerOutput = builtInVariables_.input;
458         } else if (jsonInputs_.defaultOutputImage == DefaultOutputImage::WHITE) {
459             registerOutput = builtInVariables_.defWhiteImage;
460         } else {
461             registerOutput = builtInVariables_.defBlackImage;
462         }
463     }
464     shrMgr.RegisterRenderNodeOutput("output", registerOutput);
465 }
466 
ParseRenderNodeInputs()467 void RenderNodeMipChainPostProcess::ParseRenderNodeInputs()
468 {
469     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
470     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
471 
472     const auto shaderName = parserUtil.GetStringValue(jsonVal, "shader");
473     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
474     pipelineData_.shader = shaderMgr.GetShaderHandle(shaderName);
475     jsonInputs_.renderPass = parserUtil.GetInputRenderPass(jsonVal, "renderPass");
476     jsonInputs_.resources = parserUtil.GetInputResources(jsonVal, "resources");
477     jsonInputs_.dispatchResources = parserUtil.GetInputResources(jsonVal, "dispatchResources");
478     jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
479     jsonInputs_.renderDataStoreSpecialization =
480         parserUtil.GetRenderDataStore(jsonVal, "renderDataStoreShaderSpecialization");
481     const auto ramp = parserUtil.GetStringValue(jsonVal, "ramp");
482     jsonInputs_.upRamp = ramp == "up";
483     jsonInputs_.ppName = parserUtil.GetStringValue(jsonVal, "postProcess");
484 
485 #if (RENDER_VALIDATION_ENABLED == 1)
486     if (jsonInputs_.renderDataStore.dataStoreName.empty()) {
487         PLUGIN_LOG_W("RENDER_VALIDATION: RN %s renderDataStore::dataStoreName missing.",
488             renderNodeContextMgr_->GetName().data());
489     }
490     if (jsonInputs_.ppName.empty()) {
491         PLUGIN_LOG_W("RENDER_VALIDATION: RN %s postProcess name missing.", renderNodeContextMgr_->GetName().data());
492     }
493 #endif
494 
495     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
496     inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
497     inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
498     jsonInputs_.hasChangeableRenderPassHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.renderPass);
499     jsonInputs_.hasChangeableResourceHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.resources);
500     jsonInputs_.hasChangeableDispatchHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.dispatchResources);
501 
502     // process custom resources
503     for (uint32_t idx = 0; idx < static_cast<uint32_t>(jsonInputs_.resources.customInputImages.size()); ++idx) {
504         const auto& ref = jsonInputs_.resources.customInputImages[idx];
505         if (ref.usageName == INPUT) {
506             jsonInputs_.inputIdx = idx;
507         }
508     }
509     for (uint32_t idx = 0; idx < static_cast<uint32_t>(jsonInputs_.resources.customOutputImages.size()); ++idx) {
510         const auto& ref = jsonInputs_.resources.customOutputImages[idx];
511         if (ref.usageName == OUTPUT) {
512             jsonInputs_.outputIdx = idx;
513         }
514     }
515 
516     // pick a sampler from the input resources which matches the layout location set=1, binding=0
517     if (!inputResources_.samplers.empty()) {
518         if (auto pos = std::find_if(inputResources_.samplers.cbegin(), inputResources_.samplers.cend(),
519                 [](const RenderNodeResource& sampler) {
520                     return (sampler.set == 1U) && (sampler.binding == 0U) &&
521                            RenderHandleUtil::IsValid(sampler.handle) &&
522                            RenderHandleUtil::GetHandleType(sampler.handle) == RenderHandleType::GPU_SAMPLER;
523                 });
524             pos != inputResources_.samplers.cend()) {
525             samplerHandle_ = pos->handle;
526         }
527     }
528 }
529 
UpdateImageData()530 void RenderNodeMipChainPostProcess::UpdateImageData()
531 {
532     const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
533     if (!RenderHandleUtil::IsValid(builtInVariables_.defBuffer)) {
534         builtInVariables_.defBuffer = ubos_.postProcess.GetHandle();
535     }
536     if (!RenderHandleUtil::IsValid(builtInVariables_.defBlackImage)) {
537         builtInVariables_.defBlackImage =
538             gpuResourceMgr.GetImageHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_IMAGE);
539     }
540     if (!RenderHandleUtil::IsValid(builtInVariables_.defWhiteImage)) {
541         builtInVariables_.defWhiteImage =
542             gpuResourceMgr.GetImageHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_IMAGE_WHITE);
543     }
544     if (!RenderHandleUtil::IsValid(samplerHandle_)) {
545         builtInVariables_.defSampler =
546             gpuResourceMgr.GetSamplerHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP);
547         if (!RenderHandleUtil::IsValid(builtInVariables_.defSampler)) {
548             samplerHandle_ = builtInVariables_.defSampler;
549         }
550     }
551     if (jsonInputs_.inputIdx < inputResources_.customInputImages.size()) {
552         builtInVariables_.input = inputResources_.customInputImages[jsonInputs_.inputIdx].handle;
553     }
554     if (jsonInputs_.outputIdx < inputResources_.customOutputImages.size()) {
555         builtInVariables_.output = inputResources_.customOutputImages[jsonInputs_.outputIdx].handle;
556     }
557 }
558 
559 // for plugin / factory interface
Create()560 IRenderNode* RenderNodeMipChainPostProcess::Create()
561 {
562     return new RenderNodeMipChainPostProcess();
563 }
564 
Destroy(IRenderNode * instance)565 void RenderNodeMipChainPostProcess::Destroy(IRenderNode* instance)
566 {
567     delete static_cast<RenderNodeMipChainPostProcess*>(instance);
568 }
569 RENDER_END_NAMESPACE()
570