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