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_post_process_util.h"
17 
18 #include <render/datastore/intf_render_data_store_manager.h>
19 #include <render/datastore/intf_render_data_store_pod.h>
20 #include <render/datastore/render_data_store_render_pods.h>
21 #include <render/device/intf_gpu_resource_manager.h>
22 #include <render/device/intf_shader_manager.h>
23 #include <render/device/pipeline_state_desc.h>
24 #include <render/intf_render_context.h>
25 #include <render/namespace.h>
26 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
27 #include <render/nodecontext/intf_node_context_pso_manager.h>
28 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
29 #include <render/nodecontext/intf_render_command_list.h>
30 #include <render/nodecontext/intf_render_node.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 
36 #include "datastore/render_data_store_pod.h"
37 #include "datastore/render_data_store_post_process.h"
38 #include "default_engine_constants.h"
39 #include "device/gpu_resource_handle_util.h"
40 #include "nodecontext/pipeline_descriptor_set_binder.h"
41 #include "util/log.h"
42 
43 // shaders
44 #include <render/shaders/common/render_post_process_layout_common.h>
45 #include <render/shaders/common/render_post_process_structs_common.h>
46 
47 using namespace BASE_NS;
48 using namespace CORE_NS;
49 
50 RENDER_BEGIN_NAMESPACE()
51 namespace {
52 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
53 
54 constexpr uint32_t UBO_OFFSET_ALIGNMENT { PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
55 constexpr uint32_t MAX_POST_PROCESS_EFFECT_COUNT { 8 };
56 constexpr uint32_t POST_PROCESS_UBO_BYTE_SIZE { sizeof(GlobalPostProcessStruct) +
57                                                 sizeof(LocalPostProcessStruct) * MAX_POST_PROCESS_EFFECT_COUNT };
58 
59 constexpr string_view INPUT_COLOR = "color";
60 constexpr string_view INPUT_DEPTH = "depth";
61 constexpr string_view INPUT_VELOCITY = "velocity";
62 constexpr string_view INPUT_HISTORY = "history";
63 constexpr string_view INPUT_HISTORY_NEXT = "history_next";
64 
65 constexpr string_view COMBINED_SHADER_NAME = "rendershaders://shader/fullscreen_combined_post_process.shader";
66 constexpr string_view FXAA_SHADER_NAME = "rendershaders://shader/fullscreen_fxaa.shader";
67 constexpr string_view TAA_SHADER_NAME = "rendershaders://shader/fullscreen_taa.shader";
68 constexpr string_view DOF_BLUR_SHADER_NAME = "rendershaders://shader/depth_of_field_blur.shader";
69 constexpr string_view DOF_SHADER_NAME = "rendershaders://shader/depth_of_field.shader";
70 constexpr string_view COPY_SHADER_NAME = "rendershaders://shader/fullscreen_copy.shader";
71 
CreateRenderPass(const IRenderNodeGpuResourceManager & gpuResourceMgr,const RenderHandle input)72 RenderPass CreateRenderPass(const IRenderNodeGpuResourceManager& gpuResourceMgr, const RenderHandle input)
73 {
74     const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(input);
75     RenderPass rp;
76     rp.renderPassDesc.attachmentCount = 1u;
77     rp.renderPassDesc.attachmentHandles[0u] = input;
78     rp.renderPassDesc.attachments[0u].loadOp = AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
79     rp.renderPassDesc.attachments[0u].storeOp = AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_STORE;
80     rp.renderPassDesc.renderArea = { 0, 0, desc.width, desc.height };
81 
82     rp.renderPassDesc.subpassCount = 1u;
83     rp.subpassDesc.colorAttachmentCount = 1u;
84     rp.subpassDesc.colorAttachmentIndices[0u] = 0u;
85     rp.subpassStartIndex = 0u;
86     return rp;
87 }
88 
CreatePostProcessDataUniformBuffer(IRenderNodeGpuResourceManager & gpuResourceMgr,const RenderHandleReference & handle)89 RenderHandleReference CreatePostProcessDataUniformBuffer(
90     IRenderNodeGpuResourceManager& gpuResourceMgr, const RenderHandleReference& handle)
91 {
92     PLUGIN_STATIC_ASSERT(sizeof(GlobalPostProcessStruct) == sizeof(RenderPostProcessConfiguration));
93     PLUGIN_STATIC_ASSERT(sizeof(LocalPostProcessStruct) == UBO_OFFSET_ALIGNMENT);
94     return gpuResourceMgr.Create(
95         handle, GpuBufferDesc { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
96                     (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
97                     CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER, POST_PROCESS_UBO_BYTE_SIZE });
98 }
99 
FillTmpImageDesc(GpuImageDesc & desc)100 void FillTmpImageDesc(GpuImageDesc& desc)
101 {
102     desc.imageType = CORE_IMAGE_TYPE_2D;
103     desc.imageViewType = CORE_IMAGE_VIEW_TYPE_2D;
104     desc.engineCreationFlags = EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS |
105                                EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS;
106     desc.usageFlags =
107         ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT;
108     // don't want this multisampled even if the final output would be.
109     desc.sampleCountFlags = SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT;
110     desc.layerCount = 1U;
111     desc.mipCount = 1U;
112 }
113 
IsValidHandle(const BindableImage & img)114 inline bool IsValidHandle(const BindableImage& img)
115 {
116     return RenderHandleUtil::IsValid(img.handle);
117 }
118 } // namespace
119 
Init(IRenderNodeContextManager & renderNodeContextMgr,const IRenderNodePostProcessUtil::PostProcessInfo & postProcessInfo)120 void RenderNodePostProcessUtil::Init(
121     IRenderNodeContextManager& renderNodeContextMgr, const IRenderNodePostProcessUtil::PostProcessInfo& postProcessInfo)
122 {
123     renderNodeContextMgr_ = &renderNodeContextMgr;
124     postProcessInfo_ = postProcessInfo;
125     ParseRenderNodeInputs();
126     UpdateImageData();
127 
128     deviceBackendType_ = renderNodeContextMgr_->GetRenderContext().GetDevice().GetBackendType();
129 
130     auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
131     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
132     samplers_.nearest =
133         gpuResourceMgr.GetSamplerHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_NEAREST_CLAMP);
134     samplers_.linear =
135         gpuResourceMgr.GetSamplerHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP);
136     samplers_.mipLinear =
137         gpuResourceMgr.GetSamplerHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP);
138     ubos_.postProcess = CreatePostProcessDataUniformBuffer(gpuResourceMgr, ubos_.postProcess);
139 
140     InitCreateShaderResources();
141 
142     if ((!IsValidHandle(images_.input)) || (!IsValidHandle(images_.output))) {
143         validInputs_ = false;
144         PLUGIN_LOG_E("RN: %s, expects custom input and output image", renderNodeContextMgr_->GetName().data());
145     }
146 
147     if (jsonInputs_.renderDataStore.dataStoreName.empty()) {
148         PLUGIN_LOG_W("RenderNodeCombinedPostProcess: render data store configuration not set in render node graph");
149     }
150     if (jsonInputs_.renderDataStore.typeName != RenderDataStorePod::TYPE_NAME) {
151         PLUGIN_LOG_E("RenderNodeCombinedPostProcess: render data store type name not supported (%s != %s)",
152             jsonInputs_.renderDataStore.typeName.data(), RenderDataStorePod::TYPE_NAME);
153         validInputs_ = false;
154     }
155 
156     {
157         vector<DescriptorCounts> descriptorCounts;
158         descriptorCounts.reserve(16U);
159         descriptorCounts.push_back(renderBloom_.GetDescriptorCounts());
160         descriptorCounts.push_back(renderBlur_.GetDescriptorCounts());
161         descriptorCounts.push_back(renderBloom_.GetDescriptorCounts());
162         descriptorCounts.push_back(renderMotionBlur_.GetDescriptorCounts());
163         descriptorCounts.push_back(renderCopy_.GetDescriptorCounts());
164         descriptorCounts.push_back(renderCopyLayer_.GetDescriptorCounts());
165         descriptorCounts.push_back(renderNodeUtil.GetDescriptorCounts(combineData_.pipelineLayout));
166         descriptorCounts.push_back(renderNodeUtil.GetDescriptorCounts(fxaaData_.pipelineLayout));
167         descriptorCounts.push_back(renderNodeUtil.GetDescriptorCounts(taaData_.pipelineLayout));
168         descriptorCounts.push_back(renderNodeUtil.GetDescriptorCounts(dofBlurData_.pipelineLayout));
169         descriptorCounts.push_back(renderNearBlur_.GetDescriptorCounts());
170         descriptorCounts.push_back(renderFarBlur_.GetDescriptorCounts());
171         descriptorCounts.push_back(renderNodeUtil.GetDescriptorCounts(dofData_.pipelineLayout));
172         descriptorCounts.push_back(renderNodeUtil.GetDescriptorCounts(copyData_.pipelineLayout));
173         renderNodeContextMgr.GetDescriptorSetManager().ResetAndReserve(descriptorCounts);
174     }
175     // bloom does not do combine, and does not render to output with this combined post process
176     ProcessPostProcessConfiguration();
177     {
178         const RenderBloom::BloomInfo bloomInfo { images_.input, {}, ubos_.postProcess.GetHandle(),
179             ppConfig_.bloomConfiguration.useCompute };
180         renderBloom_.Init(renderNodeContextMgr, bloomInfo);
181     }
182     {
183         RenderBlur::BlurInfo blurInfo { images_.output, ubos_.postProcess.GetHandle(), false,
184             CORE_BLUR_TYPE_DOWNSCALE_RGBA, CORE_BLUR_TYPE_RGBA_DOF };
185         renderBlur_.Init(renderNodeContextMgr, blurInfo);
186         renderNearBlur_.Init(renderNodeContextMgr, blurInfo);
187         renderFarBlur_.Init(renderNodeContextMgr, blurInfo);
188     }
189     {
190         RenderMotionBlur::MotionBlurInfo motionBlurInfo {};
191         renderMotionBlur_.Init(renderNodeContextMgr, motionBlurInfo);
192     }
193     renderCopy_.Init(renderNodeContextMgr, {});
194     if (deviceBackendType_ != DeviceBackendType::VULKAN) {
195         // prepare for possible layer copy
196         renderCopyLayer_.Init(renderNodeContextMgr, {});
197     }
198 
199     InitCreateBinders();
200 
201     if ((!jsonInputs_.resources.customOutputImages.empty()) && (!inputResources_.customOutputImages.empty()) &&
202         (RenderHandleUtil::IsValid(inputResources_.customOutputImages[0].handle))) {
203         IRenderNodeGraphShareManager& shrMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
204         shrMgr.RegisterRenderNodeOutput(
205             jsonInputs_.resources.customOutputImages[0u].name, inputResources_.customOutputImages[0u].handle);
206     }
207 }
208 
PreExecute(const IRenderNodePostProcessUtil::PostProcessInfo & postProcessInfo)209 void RenderNodePostProcessUtil::PreExecute(const IRenderNodePostProcessUtil::PostProcessInfo& postProcessInfo)
210 {
211     postProcessInfo_ = postProcessInfo;
212     if (!validInputs_) {
213         return;
214     }
215 
216     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
217     if (jsonInputs_.hasChangeableResourceHandles) {
218         inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
219     }
220     UpdateImageData();
221 
222     auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
223     const GpuImageDesc inputDesc = gpuResourceMgr.GetImageDescriptor(images_.input.handle);
224     const GpuImageDesc outputDesc = gpuResourceMgr.GetImageDescriptor(images_.output.handle);
225     outputSize_ = { outputDesc.width, outputDesc.height };
226 #if (RENDER_VALIDATION_ENABLED == 1)
227     if ((ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_TAA_BIT) &&
228         (!validInputsForTaa_)) {
229         PLUGIN_LOG_ONCE_W(renderNodeContextMgr_->GetName() + "_taa_depth_vel",
230             "RENDER_VALIDATION: Default TAA post process needs output depth, velocity, and history.");
231     }
232     if ((ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_DOF_BIT) &&
233         (!validInputsForDof_)) {
234         PLUGIN_LOG_ONCE_W(renderNodeContextMgr_->GetName() + "_dof_depth",
235             "RENDER_VALIDATION: Default DOF post process needs output depth.");
236     }
237     if ((ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_MOTION_BLUR_BIT) &&
238         (!validInputsForMb_)) {
239         PLUGIN_LOG_ONCE_W(renderNodeContextMgr_->GetName() + "_mb_vel",
240             "RENDER_VALIDATION: Default motion blur post process needs output (samplable) velocity.");
241     }
242 #endif
243 
244     // process this frame's enabled post processes here
245     // bloom might need target updates, no further processing is needed
246     ProcessPostProcessConfiguration();
247 
248     // post process
249     const bool fxaaEnabled =
250         ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_FXAA_BIT;
251     const bool motionBlurEnabled =
252         validInputsForMb_ &&
253         (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_MOTION_BLUR_BIT);
254     const bool dofEnabled =
255         validInputsForDof_ &&
256         (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_DOF_BIT);
257 
258     ti_.idx = 0;
259     const bool basicImagesNeeded = fxaaEnabled || motionBlurEnabled || dofEnabled;
260     const bool mipImageNeeded = dofEnabled;
261     const auto nearMips = static_cast<uint32_t>(Math::ceilToInt(ppConfig_.dofConfiguration.nearBlur));
262     const auto farMips = static_cast<uint32_t>(Math::ceilToInt(ppConfig_.dofConfiguration.farBlur));
263     const bool mipCountChanged = (nearMips != ti_.mipCount[0U]) || (farMips != ti_.mipCount[1U]);
264     const bool sizeChanged = (ti_.targetSize.x != static_cast<float>(outputSize_.x)) ||
265                              (ti_.targetSize.y != static_cast<float>(outputSize_.y));
266     if (sizeChanged) {
267         ti_.targetSize.x = Math::max(1.0f, static_cast<float>(outputSize_.x));
268         ti_.targetSize.y = Math::max(1.0f, static_cast<float>(outputSize_.y));
269         ti_.targetSize.z = 1.f / ti_.targetSize.x;
270         ti_.targetSize.w = 1.f / ti_.targetSize.y;
271     }
272     if (basicImagesNeeded) {
273         if ((!ti_.images[0U]) || sizeChanged) {
274 #if (RENDER_VALIDATION_ENABLED == 1)
275             PLUGIN_LOG_I("RENDER_VALIDATION: post process temporary images re-created (size:%ux%u)", outputSize_.x,
276                 outputSize_.y);
277 #endif
278             GpuImageDesc tmpDesc = outputDesc;
279             FillTmpImageDesc(tmpDesc);
280             ti_.images[0U] = gpuResourceMgr.Create(ti_.images[0U], tmpDesc);
281             ti_.images[1U] = gpuResourceMgr.Create(ti_.images[1U], tmpDesc);
282             ti_.imageCount = 2U;
283         }
284     } else {
285         ti_.images[0U] = {};
286         ti_.images[1U] = {};
287     }
288     if (mipImageNeeded) {
289         if ((!ti_.mipImages[0U]) || sizeChanged || mipCountChanged) {
290 #if (RENDER_VALIDATION_ENABLED == 1)
291             PLUGIN_LOG_I("RENDER_VALIDATION: post process temporary mip image re-created (size:%ux%u)", outputSize_.x,
292                 outputSize_.y);
293 #endif
294             GpuImageDesc tmpDesc = outputDesc;
295             FillTmpImageDesc(tmpDesc);
296             tmpDesc.mipCount = nearMips;
297             ti_.mipImages[0] = gpuResourceMgr.Create(ti_.mipImages[0U], tmpDesc);
298             tmpDesc.mipCount = farMips;
299             ti_.mipImages[1] = gpuResourceMgr.Create(ti_.mipImages[1U], tmpDesc);
300             ti_.mipImageCount = 2U;
301             ti_.mipCount[0U] = nearMips;
302             ti_.mipCount[1U] = farMips;
303         }
304     } else {
305         ti_.mipImages[0U] = {};
306         ti_.mipImages[1U] = {};
307     }
308     if ((!basicImagesNeeded) && (!mipImageNeeded)) {
309         ti_ = {};
310     }
311 
312     BindableImage postTaaBloomInput = images_.input;
313     // prepare for possible layer copy
314     if ((deviceBackendType_ != DeviceBackendType::VULKAN) &&
315         (images_.input.layer != PipelineStateConstants::GPU_IMAGE_ALL_LAYERS)) {
316         if (sizeChanged || (!ti_.layerCopyImage)) {
317             GpuImageDesc tmpDesc = inputDesc; // NOTE: input desc
318             FillTmpImageDesc(tmpDesc);
319             ti_.layerCopyImage = gpuResourceMgr.Create(ti_.layerCopyImage, tmpDesc);
320         }
321 
322         BindableImage layerCopyOutput;
323         layerCopyOutput.handle = ti_.layerCopyImage.GetHandle();
324         RenderCopy::CopyInfo layerCopyInfo;
325         layerCopyInfo.input = images_.input;
326         layerCopyInfo.output = layerCopyOutput;
327         layerCopyInfo.copyType = RenderCopy::CopyType::LAYER_COPY;
328         renderCopyLayer_.PreExecute(*renderNodeContextMgr_, layerCopyInfo);
329 
330         // postTaa bloom input
331         postTaaBloomInput = layerCopyOutput;
332     }
333 
334     if (validInputsForTaa_ &&
335         (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_TAA_BIT)) {
336         postTaaBloomInput = images_.historyNext;
337     }
338 
339     if (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_BLOOM_BIT) {
340         const RenderBloom::BloomInfo bloomInfo { postTaaBloomInput, {}, ubos_.postProcess.GetHandle(),
341             ppConfig_.bloomConfiguration.useCompute };
342         renderBloom_.PreExecute(*renderNodeContextMgr_, bloomInfo, ppConfig_);
343     }
344 
345     // needs to evaluate what is the final effect, where we will use the final target
346     // the final target (output) might a swapchain which cannot be sampled
347     framePostProcessInOut_.clear();
348     // after bloom or TAA
349     BindableImage input = postTaaBloomInput;
350     const bool postProcessNeeded = (ppConfig_.enableFlags != 0);
351     const bool sameInputOutput = (images_.input.handle == images_.output.handle);
352     // combine
353     if (postProcessNeeded && (!sameInputOutput)) {
354         const BindableImage output =
355             (basicImagesNeeded || mipImageNeeded) ? GetIntermediateImage(input.handle) : images_.output;
356         framePostProcessInOut_.push_back({ input, output });
357         input = framePostProcessInOut_.back().output;
358     }
359     if (fxaaEnabled) {
360         framePostProcessInOut_.push_back({ input, GetIntermediateImage(input.handle) });
361         input = framePostProcessInOut_.back().output;
362     }
363     if (motionBlurEnabled) {
364         framePostProcessInOut_.push_back({ input, GetIntermediateImage(input.handle) });
365         input = framePostProcessInOut_.back().output;
366     }
367     if (dofEnabled) {
368         framePostProcessInOut_.push_back({ input, GetIntermediateImage(input.handle) });
369         input = framePostProcessInOut_.back().output;
370     }
371     if (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_BLUR_BIT) {
372         framePostProcessInOut_.push_back({ input, input });
373         input = framePostProcessInOut_.back().output;
374     }
375     // finalize
376     if (!framePostProcessInOut_.empty()) {
377         framePostProcessInOut_.back().output = images_.output;
378     }
379 
380     uint32_t ppIdx = 0U;
381     if (postProcessNeeded && (!sameInputOutput)) {
382         ppIdx++;
383     }
384     if (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_FXAA_BIT) {
385         ppIdx++;
386     }
387     if (motionBlurEnabled) {
388         const auto& inOut = framePostProcessInOut_[ppIdx++];
389         const RenderMotionBlur::MotionBlurInfo info { inOut.input.handle, inOut.output.handle, images_.velocity.handle,
390             images_.depth.handle, ubos_.postProcess.GetHandle(),
391             sizeof(GlobalPostProcessStruct) + PP_MB_IDX * UBO_OFFSET_ALIGNMENT, outputSize_ };
392         renderMotionBlur_.PreExecute(*renderNodeContextMgr_, info, ppConfig_);
393     }
394 
395     if (dofEnabled) {
396         auto nearMip = GetMipImage(input.handle);
397         RenderBlur::BlurInfo blurInfo { nearMip, ubos_.postProcess.GetHandle(), false, CORE_BLUR_TYPE_DOWNSCALE_RGBA,
398             CORE_BLUR_TYPE_RGBA_DOF };
399         renderNearBlur_.PreExecute(*renderNodeContextMgr_, blurInfo, ppConfig_);
400 
401         blurInfo.blurTarget = GetMipImage(nearMip.handle);
402         renderFarBlur_.PreExecute(*renderNodeContextMgr_, blurInfo, ppConfig_);
403         ppIdx++;
404     }
405 
406     if (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_BLUR_BIT) {
407         const auto& inOut = framePostProcessInOut_[ppIdx++];
408         RenderBlur::BlurInfo blurInfo { inOut.output, ubos_.postProcess.GetHandle(), false };
409         renderBlur_.PreExecute(*renderNodeContextMgr_, blurInfo, ppConfig_);
410     }
411 
412     PLUGIN_ASSERT(ppIdx == framePostProcessInOut_.size());
413 
414     if ((!jsonInputs_.resources.customOutputImages.empty()) && (!inputResources_.customOutputImages.empty()) &&
415         (RenderHandleUtil::IsValid(inputResources_.customOutputImages[0].handle))) {
416         IRenderNodeGraphShareManager& shrMgr = renderNodeContextMgr_->GetRenderNodeGraphShareManager();
417         shrMgr.RegisterRenderNodeOutput(
418             jsonInputs_.resources.customOutputImages[0u].name, inputResources_.customOutputImages[0u].handle);
419     }
420 }
421 
Execute(IRenderCommandList & cmdList)422 void RenderNodePostProcessUtil::Execute(IRenderCommandList& cmdList)
423 {
424     if (!validInputs_) {
425         return;
426     }
427     UpdatePostProcessData(ppConfig_);
428 
429     // prepare for possible layer copy
430     if ((deviceBackendType_ != DeviceBackendType::VULKAN) &&
431         (images_.input.layer != PipelineStateConstants::GPU_IMAGE_ALL_LAYERS)) {
432         renderCopyLayer_.Execute(*renderNodeContextMgr_, cmdList);
433     }
434 
435     if (validInputsForTaa_ &&
436         (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_TAA_BIT)) {
437         ExecuteTAA(cmdList, { images_.input, images_.historyNext });
438     }
439 
440     // ppConfig_ is already up-to-date from PreExecuteFrame
441     if (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_BLOOM_BIT) {
442         renderBloom_.Execute(*renderNodeContextMgr_, cmdList, ppConfig_);
443     }
444 
445     // post process
446     const bool fxaaEnabled =
447         ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_FXAA_BIT;
448     const bool motionBlurEnabled =
449         validInputsForMb_ &&
450         (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_MOTION_BLUR_BIT);
451     const bool dofEnabled =
452         validInputsForDof_ &&
453         (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_DOF_BIT);
454 
455     // after bloom or TAA
456     const bool postProcessNeeded = (ppConfig_.enableFlags != 0);
457     const bool sameInputOutput = (images_.input.handle == images_.output.handle);
458 
459 #if (RENDER_VALIDATION_ENABLED == 1)
460     if (postProcessNeeded && sameInputOutput) {
461         PLUGIN_LOG_ONCE_W(renderNodeContextMgr_->GetName().data(),
462             "%s: combined post process shader not supported for same input/output ATM.",
463             renderNodeContextMgr_->GetName().data());
464     }
465 #endif
466     uint32_t ppIdx = 0U;
467     if (postProcessNeeded && (!sameInputOutput)) {
468         ExecuteCombine(cmdList, framePostProcessInOut_[ppIdx++]);
469     }
470 
471     if (fxaaEnabled) {
472         ExecuteFXAA(cmdList, framePostProcessInOut_[ppIdx++]);
473     }
474 
475     if (motionBlurEnabled) {
476         const auto& inOut = framePostProcessInOut_[ppIdx++];
477         RenderMotionBlur::MotionBlurInfo info { inOut.input.handle, inOut.output.handle, images_.velocity.handle,
478             images_.depth.handle, ubos_.postProcess.GetHandle(),
479             sizeof(GlobalPostProcessStruct) + PP_MB_IDX * UBO_OFFSET_ALIGNMENT, outputSize_ };
480         renderMotionBlur_.Execute(*renderNodeContextMgr_, cmdList, info, ppConfig_);
481     }
482     if (dofEnabled) {
483         const auto& inOut = framePostProcessInOut_[ppIdx++];
484         ExecuteDof(cmdList, inOut);
485     }
486 
487     // post blur
488     if (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_BLUR_BIT) {
489         ppIdx++;
490         // NOTE: add ppConfig
491         renderBlur_.Execute(*renderNodeContextMgr_, cmdList, ppConfig_);
492     }
493 
494     PLUGIN_ASSERT(ppIdx == framePostProcessInOut_.size());
495 
496     // if all flags are zero and output is different than input
497     // we need to execute a copy
498     if ((!postProcessNeeded) && (!sameInputOutput)) {
499         ExecuteBlit(cmdList, { images_.input, images_.output });
500     }
501 }
502 
ExecuteCombine(IRenderCommandList & cmdList,const InputOutput & inOut)503 void RenderNodePostProcessUtil::ExecuteCombine(IRenderCommandList& cmdList, const InputOutput& inOut)
504 {
505     const RenderHandle bloomImage =
506         (ppConfig_.enableFlags & PostProcessConfiguration::PostProcessEnableFlagBits::ENABLE_BLOOM_BIT)
507             ? renderBloom_.GetFinalTarget()
508             : aimg_.black;
509 
510     auto& effect = combineData_;
511     const RenderPass renderPass = CreateRenderPass(renderNodeContextMgr_->GetGpuResourceManager(), inOut.output.handle);
512     if (!RenderHandleUtil::IsValid(effect.pso)) {
513         auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
514         const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
515         const RenderHandle graphicsStateHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(effect.shader);
516         effect.pso = psoMgr.GetGraphicsPsoHandle(effect.shader, graphicsStateHandle, effect.pipelineLayout, {}, {},
517             { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
518     }
519 
520     cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
521     cmdList.BindPipeline(effect.pso);
522 
523     {
524         RenderHandle sets[2U] {};
525         DescriptorSetLayoutBindingResources resources[2U] {};
526         {
527             const RenderHandle ubo = ubos_.postProcess.GetHandle();
528             PLUGIN_ASSERT(binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_COMBINED_IDX]);
529             auto& binder = *binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_COMBINED_IDX];
530             binder.ClearBindings();
531             uint32_t binding = 0u;
532             binder.BindBuffer(binding, ubo, 0);
533             binder.BindBuffer(++binding, ubo, sizeof(GlobalPostProcessStruct) + PP_COMBINED_IDX * UBO_OFFSET_ALIGNMENT);
534             sets[0U] = binder.GetDescriptorSetHandle();
535             resources[0U] = binder.GetDescriptorSetLayoutBindingResources();
536         }
537         {
538             auto& binder = *binders_.combineBinder;
539             binder.ClearBindings();
540             uint32_t binding = 0u;
541             BindableImage mainInput = inOut.input;
542             mainInput.samplerHandle = samplers_.linear;
543             binder.BindImage(binding++, mainInput);
544             binder.BindImage(binding++, bloomImage, samplers_.linear);
545             binder.BindImage(binding++, images_.dirtMask, samplers_.linear);
546             sets[1U] = binder.GetDescriptorSetHandle();
547             resources[1U] = binder.GetDescriptorSetLayoutBindingResources();
548         }
549         cmdList.UpdateDescriptorSets(sets, resources);
550         cmdList.BindDescriptorSets(0u, sets);
551     }
552 
553     // dynamic state
554     cmdList.SetDynamicStateViewport(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultViewport(renderPass));
555     cmdList.SetDynamicStateScissor(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultScissor(renderPass));
556 
557     if (effect.pipelineLayout.pushConstant.byteSize > 0) {
558         const float fWidth = static_cast<float>(renderPass.renderPassDesc.renderArea.extentWidth);
559         const float fHeight = static_cast<float>(renderPass.renderPassDesc.renderArea.extentHeight);
560         const LocalPostProcessPushConstantStruct pc { { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight }, {} };
561         cmdList.PushConstantData(effect.pipelineLayout.pushConstant, arrayviewU8(pc));
562     }
563 
564     cmdList.Draw(3u, 1u, 0u, 0u);
565     cmdList.EndRenderPass();
566 }
567 
ExecuteFXAA(IRenderCommandList & cmdList,const InputOutput & inOut)568 void RenderNodePostProcessUtil::ExecuteFXAA(IRenderCommandList& cmdList, const InputOutput& inOut)
569 {
570     auto renderPass = CreateRenderPass(renderNodeContextMgr_->GetGpuResourceManager(), inOut.output.handle);
571     if (!RenderHandleUtil::IsValid(fxaaData_.pso)) {
572         auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
573         const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
574         const RenderHandle gfxHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(fxaaData_.shader);
575         fxaaData_.pso = psoMgr.GetGraphicsPsoHandle(
576             fxaaData_.shader, gfxHandle, fxaaData_.pl, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
577     }
578 
579     cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
580     cmdList.BindPipeline(fxaaData_.pso);
581 
582     {
583         RenderHandle sets[2U] {};
584         DescriptorSetLayoutBindingResources resources[2U] {};
585         {
586             const RenderHandle ubo = ubos_.postProcess.GetHandle();
587             PLUGIN_ASSERT(binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_FXAA_IDX]);
588             auto& binder = *binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_FXAA_IDX];
589             binder.ClearBindings();
590             uint32_t binding = 0u;
591             binder.BindBuffer(binding, ubo, 0u);
592             binder.BindBuffer(++binding, ubo, sizeof(GlobalPostProcessStruct) + PP_FXAA_IDX * UBO_OFFSET_ALIGNMENT);
593             sets[0U] = binder.GetDescriptorSetHandle();
594             resources[0U] = binder.GetDescriptorSetLayoutBindingResources();
595         }
596         {
597             auto& binder = *binders_.fxaaBinder;
598             binder.ClearBindings();
599             uint32_t binding = 0u;
600             binder.BindImage(binding, inOut.input);
601             binder.BindSampler(++binding, samplers_.linear);
602             sets[1U] = binder.GetDescriptorSetHandle();
603             resources[1U] = binder.GetDescriptorSetLayoutBindingResources();
604         }
605         cmdList.UpdateDescriptorSets(sets, resources);
606         cmdList.BindDescriptorSets(0u, sets);
607     }
608 
609     {
610         const LocalPostProcessPushConstantStruct pc { ti_.targetSize,
611             PostProcessConversionHelper::GetFactorFxaa(ppConfig_) };
612         cmdList.PushConstantData(fxaaData_.pipelineLayout.pushConstant, arrayviewU8(pc));
613     }
614 
615     // dynamic state
616     cmdList.SetDynamicStateViewport(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultViewport(renderPass));
617     cmdList.SetDynamicStateScissor(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultScissor(renderPass));
618 
619     cmdList.Draw(3u, 1u, 0u, 0u);
620     cmdList.EndRenderPass();
621 }
622 
ExecuteTAA(IRenderCommandList & cmdList,const InputOutput & inOut)623 void RenderNodePostProcessUtil::ExecuteTAA(IRenderCommandList& cmdList, const InputOutput& inOut)
624 {
625     auto renderPass = CreateRenderPass(renderNodeContextMgr_->GetGpuResourceManager(), inOut.output.handle);
626     if (!RenderHandleUtil::IsValid(taaData_.pso)) {
627         const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
628         auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
629         const RenderHandle gfxHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(taaData_.shader);
630         taaData_.pso = psoMgr.GetGraphicsPsoHandle(
631             taaData_.shader, gfxHandle, taaData_.pl, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
632     }
633 
634     cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
635     cmdList.BindPipeline(taaData_.pso);
636 
637     {
638         RenderHandle sets[2U] {};
639         DescriptorSetLayoutBindingResources resources[2U] {};
640         {
641             const RenderHandle ubo = ubos_.postProcess.GetHandle();
642             PLUGIN_ASSERT(binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_TAA_IDX]);
643             auto& binder = *binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_TAA_IDX];
644             binder.ClearBindings();
645             uint32_t binding = 0u;
646             binder.BindBuffer(binding++, ubo, 0u);
647             binder.BindBuffer(binding++, ubo, sizeof(GlobalPostProcessStruct) + PP_TAA_IDX * UBO_OFFSET_ALIGNMENT);
648             sets[0U] = binder.GetDescriptorSetHandle();
649             resources[0U] = binder.GetDescriptorSetLayoutBindingResources();
650         }
651         {
652             auto& binder = *binders_.taaBinder;
653             binder.ClearBindings();
654             uint32_t binding = 0u;
655             binder.BindImage(binding, images_.depth.handle);
656             binder.BindImage(++binding, inOut.input.handle);
657             binder.BindImage(++binding, images_.velocity.handle);
658             binder.BindImage(++binding, images_.history.handle);
659             binder.BindSampler(++binding, samplers_.linear);
660             sets[1U] = binder.GetDescriptorSetHandle();
661             resources[1U] = binder.GetDescriptorSetLayoutBindingResources();
662         }
663         cmdList.UpdateDescriptorSets(sets, resources);
664         cmdList.BindDescriptorSets(0U, sets);
665     }
666 
667     if (taaData_.pipelineLayout.pushConstant.byteSize > 0) {
668         const float fWidth = static_cast<float>(renderPass.renderPassDesc.renderArea.extentWidth);
669         const float fHeight = static_cast<float>(renderPass.renderPassDesc.renderArea.extentHeight);
670         const LocalPostProcessPushConstantStruct pc { { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight },
671             PostProcessConversionHelper::GetFactorTaa(ppConfig_) };
672         cmdList.PushConstantData(taaData_.pipelineLayout.pushConstant, arrayviewU8(pc));
673     }
674 
675     // dynamic state
676     cmdList.SetDynamicStateViewport(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultViewport(renderPass));
677     cmdList.SetDynamicStateScissor(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultScissor(renderPass));
678 
679     cmdList.Draw(3u, 1u, 0u, 0u);
680     cmdList.EndRenderPass();
681 }
682 
ExecuteDofBlur(IRenderCommandList & cmdList,const InputOutput & inOut)683 void RenderNodePostProcessUtil::ExecuteDofBlur(IRenderCommandList& cmdList, const InputOutput& inOut)
684 {
685     RenderPass rp;
686     {
687         const GpuImageDesc desc =
688             renderNodeContextMgr_->GetGpuResourceManager().GetImageDescriptor(ti_.mipImages[0U].GetHandle());
689         rp.renderPassDesc.attachmentCount = 2u;
690         rp.renderPassDesc.attachmentHandles[0u] = ti_.mipImages[0U].GetHandle();
691         rp.renderPassDesc.attachments[0u].loadOp = AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
692         rp.renderPassDesc.attachments[0u].storeOp = AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_STORE;
693         rp.renderPassDesc.attachmentHandles[1u] = ti_.mipImages[1U].GetHandle();
694         rp.renderPassDesc.attachments[1u].loadOp = AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
695         rp.renderPassDesc.attachments[1u].storeOp = AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_STORE;
696         rp.renderPassDesc.renderArea = { 0, 0, desc.width, desc.height };
697 
698         rp.renderPassDesc.subpassCount = 1u;
699         rp.subpassDesc.colorAttachmentCount = 2u;
700         rp.subpassDesc.colorAttachmentIndices[0u] = 0u;
701         rp.subpassDesc.colorAttachmentIndices[1u] = 1u;
702         rp.subpassStartIndex = 0u;
703     }
704     if (!RenderHandleUtil::IsValid(dofBlurData_.pso)) {
705         auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
706         const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
707         const RenderHandle gfxHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(dofBlurData_.shader);
708         dofBlurData_.pso = psoMgr.GetGraphicsPsoHandle(
709             dofBlurData_.shader, gfxHandle, dofBlurData_.pl, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
710     }
711     cmdList.BeginRenderPass(rp.renderPassDesc, rp.subpassStartIndex, rp.subpassDesc);
712     cmdList.BindPipeline(dofBlurData_.pso);
713 
714     {
715         RenderHandle sets[2U] {};
716         DescriptorSetLayoutBindingResources resources[2U] {};
717         {
718             // NOTE: this updated descriptor set is used in dof
719             const RenderHandle ubo = ubos_.postProcess.GetHandle();
720             PLUGIN_ASSERT(binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_DOF_IDX]);
721             auto& binder = *binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_DOF_IDX];
722             binder.ClearBindings();
723             uint32_t binding = 0u;
724             binder.BindBuffer(binding, ubo, 0u);
725             binder.BindBuffer(++binding, ubo, sizeof(GlobalPostProcessStruct) + PP_DOF_IDX * UBO_OFFSET_ALIGNMENT);
726             sets[0U] = binder.GetDescriptorSetHandle();
727             resources[0U] = binder.GetDescriptorSetLayoutBindingResources();
728         }
729         {
730             auto& binder = *binders_.dofBlurBinder;
731             binder.ClearBindings();
732             uint32_t binding = 0u;
733             BindableImage input = inOut.input;
734             input.samplerHandle = samplers_.mipLinear;
735             binder.BindImage(binding, input);
736             BindableImage depth = images_.depth;
737             depth.samplerHandle = samplers_.nearest;
738             binder.BindImage(++binding, depth);
739             sets[1U] = binder.GetDescriptorSetHandle();
740             resources[1U] = binder.GetDescriptorSetLayoutBindingResources();
741         }
742         cmdList.UpdateDescriptorSets(sets, resources);
743         cmdList.BindDescriptorSets(0U, sets);
744     }
745 
746     {
747         const float fWidth = static_cast<float>(rp.renderPassDesc.renderArea.extentWidth);
748         const float fHeight = static_cast<float>(rp.renderPassDesc.renderArea.extentHeight);
749         const LocalPostProcessPushConstantStruct pc { { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight }, {} };
750         cmdList.PushConstantData(dofBlurData_.pipelineLayout.pushConstant, arrayviewU8(pc));
751     }
752 
753     // dynamic state
754     cmdList.SetDynamicStateViewport(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultViewport(rp));
755     cmdList.SetDynamicStateScissor(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultScissor(rp));
756 
757     cmdList.Draw(3u, 1u, 0u, 0u);
758     cmdList.EndRenderPass();
759     const auto maxMipLevel = ppConfig_.blurConfiguration.maxMipLevel;
760     ppConfig_.blurConfiguration.maxMipLevel = static_cast<uint32_t>(Math::round(ppConfig_.dofConfiguration.nearBlur));
761     renderNearBlur_.Execute(*renderNodeContextMgr_, cmdList, ppConfig_);
762     ppConfig_.blurConfiguration.maxMipLevel = static_cast<uint32_t>(Math::round(ppConfig_.dofConfiguration.farBlur));
763     renderFarBlur_.Execute(*renderNodeContextMgr_, cmdList, ppConfig_);
764     ppConfig_.blurConfiguration.maxMipLevel = maxMipLevel;
765 }
766 
ExecuteDof(IRenderCommandList & cmdList,const InputOutput & inOut)767 void RenderNodePostProcessUtil::ExecuteDof(IRenderCommandList& cmdList, const InputOutput& inOut)
768 {
769     // NOTE: updates set 0 for dof
770     ExecuteDofBlur(cmdList, inOut);
771 
772     auto renderPass = CreateRenderPass(renderNodeContextMgr_->GetGpuResourceManager(), inOut.output.handle);
773     if (!RenderHandleUtil::IsValid(dofData_.pso)) {
774         auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
775         const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
776         const RenderHandle gfxHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(dofData_.shader);
777         dofData_.pso = psoMgr.GetGraphicsPsoHandle(
778             dofData_.shader, gfxHandle, dofData_.pl, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
779     }
780 
781     cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
782     cmdList.BindPipeline(dofData_.pso);
783 
784     RenderHandle sets[2u] {};
785     {
786         // NOTE: descriptor set updated by DOF blur
787         PLUGIN_ASSERT(binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_DOF_IDX]);
788         auto& binder = *binders_.globalSet0[POST_PROCESS_UBO_INDICES::PP_DOF_IDX];
789         sets[0u] = binder.GetDescriptorSetHandle();
790     }
791     {
792         auto& binder = *binders_.dofBinder;
793         binder.ClearBindings();
794         uint32_t binding = 0u;
795         BindableImage input = inOut.input;
796         input.samplerHandle = samplers_.mipLinear;
797         binder.BindImage(binding, input);
798         binder.BindImage(++binding, ti_.mipImages[0U].GetHandle(), samplers_.mipLinear);
799         binder.BindImage(++binding, ti_.mipImages[1U].GetHandle(), samplers_.mipLinear);
800         BindableImage depth = images_.depth;
801         depth.samplerHandle = samplers_.nearest;
802         binder.BindImage(++binding, depth);
803 
804         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
805         sets[1u] = binder.GetDescriptorSetHandle();
806     }
807     cmdList.BindDescriptorSets(0u, sets);
808 
809     {
810         const float fWidth = static_cast<float>(renderPass.renderPassDesc.renderArea.extentWidth);
811         const float fHeight = static_cast<float>(renderPass.renderPassDesc.renderArea.extentHeight);
812         const LocalPostProcessPushConstantStruct pc { { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight }, {} };
813         cmdList.PushConstantData(dofData_.pipelineLayout.pushConstant, arrayviewU8(pc));
814     }
815 
816     // dynamic state
817     cmdList.SetDynamicStateViewport(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultViewport(renderPass));
818     cmdList.SetDynamicStateScissor(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultScissor(renderPass));
819 
820     cmdList.Draw(3u, 1u, 0u, 0u);
821     cmdList.EndRenderPass();
822 }
823 
ExecuteBlit(IRenderCommandList & cmdList,const InputOutput & inOut)824 void RenderNodePostProcessUtil::ExecuteBlit(IRenderCommandList& cmdList, const InputOutput& inOut)
825 {
826     // extra blit from input to ouput
827     if (RenderHandleUtil::IsGpuImage(inOut.input.handle) && RenderHandleUtil::IsGpuImage(inOut.output.handle)) {
828 #if (RENDER_VALIDATION_ENABLED == 1)
829         PLUGIN_LOG_ONCE_W(renderNodeContextMgr_->GetName().data(),
830             "RENDER_PERFORMANCE_VALIDATION: Extra blit from input to output (RN: %s)",
831             renderNodeContextMgr_->GetName().data());
832 #endif
833         auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
834 
835         RenderPass renderPass = CreateRenderPass(gpuResourceMgr, inOut.output.handle);
836         auto& effect = copyData_;
837         if (!RenderHandleUtil::IsValid(effect.pso)) {
838             auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
839             const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
840             const RenderHandle graphicsStateHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(effect.shader);
841             effect.pso = psoMgr.GetGraphicsPsoHandle(effect.shader, graphicsStateHandle, effect.pipelineLayout, {}, {},
842                 { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
843         }
844 
845         cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
846         cmdList.BindPipeline(effect.pso);
847 
848         {
849             auto& binder = *binders_.copyBinder;
850             binder.ClearBindings();
851             uint32_t binding = 0u;
852             binder.BindSampler(binding, samplers_.linear);
853             binder.BindImage(++binding, inOut.input);
854             cmdList.UpdateDescriptorSet(
855                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
856             cmdList.BindDescriptorSet(0u, binder.GetDescriptorSetHandle());
857         }
858 
859         // dynamic state
860         const ViewportDesc viewportDesc = renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultViewport(renderPass);
861         const ScissorDesc scissorDesc = renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultScissor(renderPass);
862         cmdList.SetDynamicStateViewport(viewportDesc);
863         cmdList.SetDynamicStateScissor(scissorDesc);
864 
865         cmdList.Draw(3u, 1u, 0u, 0u);
866         cmdList.EndRenderPass();
867     }
868 }
869 
UpdatePostProcessData(const PostProcessConfiguration & postProcessConfiguration)870 void RenderNodePostProcessUtil::UpdatePostProcessData(const PostProcessConfiguration& postProcessConfiguration)
871 {
872     auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
873     const RenderPostProcessConfiguration rppc =
874         renderNodeContextMgr_->GetRenderNodeUtil().GetRenderPostProcessConfiguration(postProcessConfiguration);
875     PLUGIN_STATIC_ASSERT(sizeof(GlobalPostProcessStruct) == sizeof(RenderPostProcessConfiguration));
876     if (auto* const data = reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(ubos_.postProcess.GetHandle())); data) {
877         const auto* dataEnd = data + POST_PROCESS_UBO_BYTE_SIZE;
878         if (!CloneData(data, size_t(dataEnd - data), &rppc, sizeof(RenderPostProcessConfiguration))) {
879             PLUGIN_LOG_E("post process ubo copying failed.");
880         }
881         {
882             auto* localData = data + (sizeof(RenderPostProcessConfiguration) + PP_TAA_IDX * UBO_OFFSET_ALIGNMENT);
883             auto factor = PostProcessConversionHelper::GetFactorTaa(postProcessConfiguration);
884             CloneData(localData, size_t(dataEnd - localData), &factor, sizeof(factor));
885         }
886         {
887             auto* localData = data + (sizeof(RenderPostProcessConfiguration) + PP_BLOOM_IDX * UBO_OFFSET_ALIGNMENT);
888             auto factor = PostProcessConversionHelper::GetFactorBloom(postProcessConfiguration);
889             CloneData(localData, size_t(dataEnd - localData), &factor, sizeof(factor));
890         }
891         {
892             auto* localData = data + (sizeof(RenderPostProcessConfiguration) + PP_BLUR_IDX * UBO_OFFSET_ALIGNMENT);
893             auto factor = PostProcessConversionHelper::GetFactorBlur(postProcessConfiguration);
894             CloneData(localData, size_t(dataEnd - localData), &factor, sizeof(factor));
895         }
896         {
897             auto* localData = data + (sizeof(RenderPostProcessConfiguration) + PP_FXAA_IDX * UBO_OFFSET_ALIGNMENT);
898             auto factor = PostProcessConversionHelper::GetFactorFxaa(postProcessConfiguration);
899             CloneData(localData, size_t(dataEnd - localData), &factor, sizeof(factor));
900         }
901         {
902             auto* localData = data + (sizeof(RenderPostProcessConfiguration) + PP_DOF_IDX * UBO_OFFSET_ALIGNMENT);
903             auto factors = PostProcessConversionHelper::GetFactorDof(postProcessConfiguration);
904             CloneData(localData, size_t(dataEnd - localData), &factors, sizeof(factors));
905             localData += sizeof(factors);
906             factors = PostProcessConversionHelper::GetFactorDof2(postProcessConfiguration);
907             CloneData(localData, size_t(dataEnd - localData), &factors, sizeof(factors));
908         }
909         {
910             auto* localData = data + (sizeof(RenderPostProcessConfiguration) + PP_MB_IDX * UBO_OFFSET_ALIGNMENT);
911             auto factor = PostProcessConversionHelper::GetFactorMotionBlur(postProcessConfiguration);
912             CloneData(localData, size_t(dataEnd - localData), &factor, sizeof(factor));
913         }
914 
915         gpuResourceMgr.UnmapBuffer(ubos_.postProcess.GetHandle());
916     }
917 }
918 
ProcessPostProcessConfiguration()919 void RenderNodePostProcessUtil::ProcessPostProcessConfiguration()
920 {
921     if (!jsonInputs_.renderDataStore.dataStoreName.empty()) {
922         auto& dsMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
923         if (const IRenderDataStore* ds = dsMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName); ds) {
924             if (jsonInputs_.renderDataStore.typeName == RenderDataStorePod::TYPE_NAME) {
925                 auto const dataStore = static_cast<IRenderDataStorePod const*>(ds);
926                 auto const dataView = dataStore->Get(jsonInputs_.renderDataStore.configurationName);
927                 if (dataView.data() && (dataView.size_bytes() == sizeof(PostProcessConfiguration))) {
928                     ppConfig_ = *((const PostProcessConfiguration*)dataView.data());
929                     if (RenderHandleUtil::IsValid(ppConfig_.bloomConfiguration.dirtMaskImage)) {
930                         images_.dirtMask = ppConfig_.bloomConfiguration.dirtMaskImage;
931                     } else {
932                         images_.dirtMask = aimg_.black;
933                     }
934                 }
935             }
936         }
937     }
938 }
939 
InitCreateShaderResources()940 void RenderNodePostProcessUtil::InitCreateShaderResources()
941 {
942     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
943 
944     combineData_ = {};
945     copyData_ = {};
946     fxaaData_ = {};
947     taaData_ = {};
948     dofData_ = {};
949     dofBlurData_ = {};
950 
951     combineData_.shader = shaderMgr.GetShaderHandle(COMBINED_SHADER_NAME);
952     combineData_.pl = shaderMgr.GetPipelineLayoutHandleByShaderHandle(combineData_.shader);
953     if (!RenderHandleUtil::IsValid(combineData_.pl)) {
954         combineData_.pl = shaderMgr.GetReflectionPipelineLayoutHandle(combineData_.shader);
955     }
956     combineData_.pipelineLayout = shaderMgr.GetPipelineLayout(combineData_.pl);
957     copyData_.shader = shaderMgr.GetShaderHandle(COPY_SHADER_NAME);
958     copyData_.pl = shaderMgr.GetPipelineLayoutHandleByShaderHandle(copyData_.shader);
959     if (!RenderHandleUtil::IsValid(copyData_.pl)) {
960         copyData_.pl = shaderMgr.GetReflectionPipelineLayoutHandle(copyData_.shader);
961     }
962     copyData_.pipelineLayout = shaderMgr.GetPipelineLayout(copyData_.pl);
963 
964     fxaaData_.shader = shaderMgr.GetShaderHandle(FXAA_SHADER_NAME);
965     fxaaData_.pl = shaderMgr.GetPipelineLayoutHandleByShaderHandle(fxaaData_.shader);
966     if (!RenderHandleUtil::IsValid(fxaaData_.pl)) {
967         fxaaData_.pl = shaderMgr.GetReflectionPipelineLayoutHandle(fxaaData_.shader);
968     }
969     fxaaData_.pipelineLayout = shaderMgr.GetPipelineLayout(fxaaData_.pl);
970     taaData_.shader = shaderMgr.GetShaderHandle(TAA_SHADER_NAME);
971     taaData_.pl = shaderMgr.GetPipelineLayoutHandleByShaderHandle(taaData_.shader);
972     if (!RenderHandleUtil::IsValid(taaData_.pl)) {
973         taaData_.pl = shaderMgr.GetReflectionPipelineLayoutHandle(taaData_.shader);
974     }
975     taaData_.pipelineLayout = shaderMgr.GetPipelineLayout(taaData_.pl);
976 
977     dofData_.shader = shaderMgr.GetShaderHandle(DOF_SHADER_NAME);
978     dofData_.pl = shaderMgr.GetPipelineLayoutHandleByShaderHandle(dofData_.shader);
979     if (!RenderHandleUtil::IsValid(dofData_.pl)) {
980         dofData_.pl = shaderMgr.GetReflectionPipelineLayoutHandle(dofData_.shader);
981     }
982     dofData_.pipelineLayout = shaderMgr.GetPipelineLayout(dofData_.pl);
983 
984     dofBlurData_.shader = shaderMgr.GetShaderHandle(DOF_BLUR_SHADER_NAME);
985     dofBlurData_.pl = shaderMgr.GetPipelineLayoutHandleByShaderHandle(dofBlurData_.shader);
986     if (!RenderHandleUtil::IsValid(dofBlurData_.pl)) {
987         dofBlurData_.pl = shaderMgr.GetReflectionPipelineLayoutHandle(dofBlurData_.shader);
988     }
989     dofBlurData_.pipelineLayout = shaderMgr.GetPipelineLayout(dofBlurData_.pl);
990 }
991 
InitCreateBinders()992 void RenderNodePostProcessUtil::InitCreateBinders()
993 {
994     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
995     {
996         constexpr uint32_t globalSetIdx = 0u;
997         constexpr uint32_t localSetIdx = 1u;
998 
999         for (uint32_t idx = 0; idx < POST_PROCESS_UBO_INDICES::PP_COUNT_IDX; ++idx) {
1000             binders_.globalSet0[idx] = descriptorSetMgr.CreateDescriptorSetBinder(
1001                 descriptorSetMgr.CreateDescriptorSet(globalSetIdx, combineData_.pipelineLayout),
1002                 combineData_.pipelineLayout.descriptorSetLayouts[globalSetIdx].bindings);
1003         }
1004 
1005         binders_.combineBinder = descriptorSetMgr.CreateDescriptorSetBinder(
1006             descriptorSetMgr.CreateDescriptorSet(localSetIdx, combineData_.pipelineLayout),
1007             combineData_.pipelineLayout.descriptorSetLayouts[localSetIdx].bindings);
1008         binders_.fxaaBinder = descriptorSetMgr.CreateDescriptorSetBinder(
1009             descriptorSetMgr.CreateDescriptorSet(localSetIdx, fxaaData_.pipelineLayout),
1010             fxaaData_.pipelineLayout.descriptorSetLayouts[localSetIdx].bindings);
1011         binders_.taaBinder = descriptorSetMgr.CreateDescriptorSetBinder(
1012             descriptorSetMgr.CreateDescriptorSet(localSetIdx, taaData_.pipelineLayout),
1013             taaData_.pipelineLayout.descriptorSetLayouts[localSetIdx].bindings);
1014         binders_.dofBlurBinder = descriptorSetMgr.CreateDescriptorSetBinder(
1015             descriptorSetMgr.CreateDescriptorSet(localSetIdx, dofBlurData_.pipelineLayout),
1016             dofBlurData_.pipelineLayout.descriptorSetLayouts[localSetIdx].bindings);
1017         binders_.dofBinder = descriptorSetMgr.CreateDescriptorSetBinder(
1018             descriptorSetMgr.CreateDescriptorSet(localSetIdx, dofData_.pipelineLayout),
1019             dofData_.pipelineLayout.descriptorSetLayouts[localSetIdx].bindings);
1020     }
1021     binders_.copyBinder =
1022         descriptorSetMgr.CreateDescriptorSetBinder(descriptorSetMgr.CreateDescriptorSet(0u, copyData_.pipelineLayout),
1023             copyData_.pipelineLayout.descriptorSetLayouts[0u].bindings);
1024 }
1025 
ParseRenderNodeInputs()1026 void RenderNodePostProcessUtil::ParseRenderNodeInputs()
1027 {
1028     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
1029     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
1030     jsonInputs_.resources = parserUtil.GetInputResources(jsonVal, "resources");
1031     jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
1032 
1033     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
1034     inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
1035     jsonInputs_.hasChangeableResourceHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.resources);
1036 
1037     // process custom inputs
1038     for (uint32_t idx = 0; idx < static_cast<uint32_t>(jsonInputs_.resources.customInputImages.size()); ++idx) {
1039         const auto& ref = jsonInputs_.resources.customInputImages[idx];
1040         if (ref.usageName == INPUT_COLOR) {
1041             jsonInputs_.colorIndex = idx;
1042         } else if (ref.usageName == INPUT_DEPTH) {
1043             jsonInputs_.depthIndex = idx;
1044         } else if (ref.usageName == INPUT_VELOCITY) {
1045             jsonInputs_.velocityIndex = idx;
1046         } else if (ref.usageName == INPUT_HISTORY) {
1047             jsonInputs_.historyIndex = idx;
1048         } else if (ref.usageName == INPUT_HISTORY_NEXT) {
1049             jsonInputs_.historyNextIndex = idx;
1050         }
1051     }
1052 }
1053 
UpdateImageData()1054 void RenderNodePostProcessUtil::UpdateImageData()
1055 {
1056     if ((!RenderHandleUtil::IsValid(aimg_.black)) || (!RenderHandleUtil::IsValid(aimg_.white))) {
1057         auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
1058         aimg_.black = gpuResourceMgr.GetImageHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_IMAGE);
1059         aimg_.white = gpuResourceMgr.GetImageHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_IMAGE_WHITE);
1060     }
1061 
1062     if (postProcessInfo_.parseRenderNodeInputs) {
1063         if (inputResources_.customInputImages.empty() || inputResources_.customOutputImages.empty()) {
1064             return; // early out
1065         }
1066 
1067         images_.input.handle = inputResources_.customInputImages[0].handle;
1068         images_.output.handle = inputResources_.customOutputImages[0].handle;
1069         if (jsonInputs_.depthIndex < inputResources_.customInputImages.size()) {
1070             images_.depth.handle = inputResources_.customInputImages[jsonInputs_.depthIndex].handle;
1071         }
1072         if (jsonInputs_.velocityIndex < inputResources_.customInputImages.size()) {
1073             images_.velocity.handle = inputResources_.customInputImages[jsonInputs_.velocityIndex].handle;
1074         }
1075         if (jsonInputs_.historyIndex < inputResources_.customInputImages.size()) {
1076             images_.history.handle = inputResources_.customInputImages[jsonInputs_.historyIndex].handle;
1077         }
1078         if (jsonInputs_.historyNextIndex < inputResources_.customInputImages.size()) {
1079             images_.historyNext.handle = inputResources_.customInputImages[jsonInputs_.historyNextIndex].handle;
1080         }
1081     } else {
1082         images_.input = postProcessInfo_.imageData.input;
1083         images_.output = postProcessInfo_.imageData.output;
1084         images_.depth = postProcessInfo_.imageData.depth;
1085         images_.velocity = postProcessInfo_.imageData.velocity;
1086         images_.history = postProcessInfo_.imageData.history;
1087         images_.historyNext = postProcessInfo_.imageData.historyNext;
1088     }
1089 
1090     validInputsForTaa_ = false;
1091     validInputsForDof_ = false;
1092     validInputsForMb_ = false;
1093     bool validDepth = false;
1094     bool validHistory = false;
1095     bool validVelocity = false;
1096     if (IsValidHandle(images_.depth) && (images_.depth.handle != aimg_.white)) {
1097         const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
1098         const GpuImageDesc& desc = gpuResourceMgr.GetImageDescriptor(images_.depth.handle);
1099         if (desc.usageFlags & CORE_IMAGE_USAGE_SAMPLED_BIT) {
1100             validDepth = true;
1101         }
1102     } else {
1103         images_.depth.handle = aimg_.white; // default depth
1104     }
1105     if (IsValidHandle(images_.velocity) && (images_.velocity.handle != aimg_.black)) {
1106         const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
1107         const GpuImageDesc& desc = gpuResourceMgr.GetImageDescriptor(images_.velocity.handle);
1108         if (desc.usageFlags & CORE_IMAGE_USAGE_SAMPLED_BIT) {
1109             validVelocity = true;
1110         }
1111     } else {
1112         images_.velocity.handle = aimg_.black; // default velocity
1113     }
1114     if (IsValidHandle(images_.history) && IsValidHandle(images_.historyNext)) {
1115         const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
1116         const GpuImageDesc& velDesc = gpuResourceMgr.GetImageDescriptor(images_.velocity.handle);
1117         if (velDesc.usageFlags & CORE_IMAGE_USAGE_SAMPLED_BIT) {
1118             validHistory = true;
1119         }
1120     }
1121     if (!RenderHandleUtil::IsValid(images_.dirtMask)) {
1122         images_.dirtMask = aimg_.black; // default dirt mask
1123     }
1124 
1125     validInputsForDof_ = validDepth;
1126     validInputsForTaa_ = validDepth && validHistory; // TAA can be used without velocities
1127     validInputsForMb_ = validVelocity;
1128 }
1129 
1130 ///////////////////////////////////////////////////////////////////////////////////////////////////
1131 
Init(IRenderNodeContextManager & renderNodeContextMgr,const IRenderNodePostProcessUtil::PostProcessInfo & postProcessInfo)1132 void RenderNodePostProcessUtilImpl::Init(
1133     IRenderNodeContextManager& renderNodeContextMgr, const IRenderNodePostProcessUtil::PostProcessInfo& postProcessInfo)
1134 {
1135     rn_.Init(renderNodeContextMgr, postProcessInfo);
1136 }
1137 
PreExecute(const IRenderNodePostProcessUtil::PostProcessInfo & postProcessInfo)1138 void RenderNodePostProcessUtilImpl::PreExecute(const IRenderNodePostProcessUtil::PostProcessInfo& postProcessInfo)
1139 {
1140     rn_.PreExecute(postProcessInfo);
1141 }
1142 
Execute(IRenderCommandList & cmdList)1143 void RenderNodePostProcessUtilImpl::Execute(IRenderCommandList& cmdList)
1144 {
1145     rn_.Execute(cmdList);
1146 }
1147 
GetInterface(const Uid & uid) const1148 const IInterface* RenderNodePostProcessUtilImpl::GetInterface(const Uid& uid) const
1149 {
1150     if ((uid == IRenderNodePostProcessUtil::UID) || (uid == IInterface::UID)) {
1151         return this;
1152     }
1153     return nullptr;
1154 }
1155 
GetInterface(const Uid & uid)1156 IInterface* RenderNodePostProcessUtilImpl::GetInterface(const Uid& uid)
1157 {
1158     if ((uid == IRenderNodePostProcessUtil::UID) || (uid == IInterface::UID)) {
1159         return this;
1160     }
1161     return nullptr;
1162 }
1163 
Ref()1164 void RenderNodePostProcessUtilImpl::Ref()
1165 {
1166     refCount_++;
1167 }
1168 
Unref()1169 void RenderNodePostProcessUtilImpl::Unref()
1170 {
1171     if (--refCount_ == 0) {
1172         delete this;
1173     }
1174 }
1175 RENDER_END_NAMESPACE()
1176