/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "render_node_back_buffer.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "device/gpu_resource_handle_util.h"
#include "util/log.h"
// shaders
#include "render/shaders/common/render_post_process_structs_common.h"
RENDER_BEGIN_NAMESPACE()
namespace {
constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
PostProcessTonemapStruct FillPushConstant(
const GpuImageDesc& dstImageDesc, const RenderPostProcessConfiguration& currentRenderPostProcessConfiguration_)
{
PostProcessTonemapStruct pushData;
const float fWidth = static_cast(dstImageDesc.width);
const float fHeight = static_cast(dstImageDesc.height);
pushData.texSizeInvTexSize[0u] = fWidth;
pushData.texSizeInvTexSize[1u] = fHeight;
pushData.texSizeInvTexSize[2u] = 1.0f / fWidth;
pushData.texSizeInvTexSize[3u] = 1.0f / fHeight;
pushData.flags = currentRenderPostProcessConfiguration_.flags;
pushData.tonemap = currentRenderPostProcessConfiguration_.factors[PostProcessConfiguration::INDEX_TONEMAP];
pushData.vignette = currentRenderPostProcessConfiguration_.factors[PostProcessConfiguration::INDEX_VIGNETTE];
pushData.colorFringe = currentRenderPostProcessConfiguration_.factors[PostProcessConfiguration::INDEX_COLOR_FRINGE];
pushData.dither = currentRenderPostProcessConfiguration_.factors[PostProcessConfiguration::INDEX_DITHER];
return pushData;
}
} // namespace
void RenderNodeBackBuffer::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
{
renderNodeContextMgr_ = &renderNodeContextMgr;
ParseRenderNodeInputs();
psoHandle_ = {};
if (jsonInputs_.renderDataStore.dataStoreName.empty()) {
PLUGIN_LOG_V("RenderNodeBackBuffer: render data store configuration not set in render node graph");
}
const auto& renderNodeUtil = renderNodeContextMgr.GetRenderNodeUtil();
renderPass_ = renderNodeUtil.CreateRenderPass(inputRenderPass_);
pipelineLayout_ = renderNodeUtil.CreatePipelineLayout(shader_);
{
const DescriptorCounts dc = renderNodeUtil.GetDescriptorCounts(pipelineLayout_);
renderNodeContextMgr.GetDescriptorSetManager().ResetAndReserve(dc);
}
pipelineDescriptorSetBinder_ = renderNodeUtil.CreatePipelineDescriptorSetBinder(pipelineLayout_);
renderNodeUtil.BindResourcesToBinder(inputResources_, *pipelineDescriptorSetBinder_);
}
void RenderNodeBackBuffer::ExecuteFrame(IRenderCommandList& cmdList)
{
const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
const PostProcessConfiguration ppConfig = GetPostProcessConfiguration(renderDataStoreMgr);
const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
if (jsonInputs_.hasChangeableRenderPassHandles) {
inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
}
if (jsonInputs_.hasChangeableResourceHandles) {
inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
renderNodeUtil.BindResourcesToBinder(inputResources_, *pipelineDescriptorSetBinder_);
}
// Size update mut be done before specialization
const RenderHandle dstImageHandle = UpdateColorAttachmentSize();
CheckForPsoSpecilization(ppConfig);
const uint32_t firstSetIndex = pipelineDescriptorSetBinder_->GetFirstSet();
for (auto refIndex : pipelineDescriptorSetBinder_->GetSetIndices()) {
const auto descHandle = pipelineDescriptorSetBinder_->GetDescriptorSetHandle(refIndex);
const auto bindings = pipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(refIndex);
cmdList.UpdateDescriptorSet(descHandle, bindings);
}
cmdList.BeginRenderPass(renderPass_.renderPassDesc, renderPass_.subpassStartIndex, renderPass_.subpassDesc);
cmdList.BindPipeline(psoHandle_);
// bind all sets
cmdList.BindDescriptorSets(firstSetIndex, pipelineDescriptorSetBinder_->GetDescriptorSetHandles());
// dynamic state
cmdList.SetDynamicStateViewport(currentViewportDesc_);
cmdList.SetDynamicStateScissor(currentScissorDesc_);
const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
const GpuImageDesc dstImageDesc = gpuResourceMgr.GetImageDescriptor(dstImageHandle);
if (pipelineLayout_.pushConstant.byteSize > 0) {
const PostProcessTonemapStruct pushData =
FillPushConstant(dstImageDesc, currentRenderPostProcessConfiguration_);
cmdList.PushConstant(pipelineLayout_.pushConstant, reinterpret_cast(&pushData));
}
cmdList.Draw(3u, 1u, 0u, 0u); // vertexCount 3, drawing one triangle
cmdList.EndRenderPass();
}
void RenderNodeBackBuffer::CheckForPsoSpecilization(const PostProcessConfiguration& postProcessConfiguration)
{
const RenderPostProcessConfiguration renderPostProcessConfiguration =
renderNodeContextMgr_->GetRenderNodeUtil().GetRenderPostProcessConfiguration(postProcessConfiguration);
if (!RenderHandleUtil::IsValid(psoHandle_)) {
auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
const RenderHandle graphicsState =
renderNodeContextMgr_->GetShaderManager().GetGraphicsStateHandleByShaderHandle(shader_);
psoHandle_ = psoMgr.GetGraphicsPsoHandle(
shader_, graphicsState, pipelineLayout_, {}, {}, { DYNAMIC_STATES, BASE_NS::countof(DYNAMIC_STATES) });
}
// store new values
currentRenderPostProcessConfiguration_ = renderPostProcessConfiguration;
}
PostProcessConfiguration RenderNodeBackBuffer::GetPostProcessConfiguration(
const IRenderNodeRenderDataStoreManager& dataStoreMgr)
{
if (!jsonInputs_.renderDataStore.dataStoreName.empty()) {
auto const dataStore = static_cast(
dataStoreMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName));
if (dataStore) {
auto const dataView = dataStore->Get(jsonInputs_.renderDataStore.configurationName);
const PostProcessConfiguration* data = (const PostProcessConfiguration*)dataView.data();
if (data) {
return *data;
}
}
}
return {};
}
RenderHandle RenderNodeBackBuffer::UpdateColorAttachmentSize()
{
const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
RenderHandle dstImageHandle;
if (!inputRenderPass_.attachments.empty()) {
dstImageHandle = inputRenderPass_.attachments[0].handle;
const GpuImageDesc& desc = gpuResourceMgr.GetImageDescriptor(inputRenderPass_.attachments[0].handle);
if (desc.width != currentBackBuffer_.width || desc.height != currentBackBuffer_.height ||
desc.format != currentBackBuffer_.format) {
currentBackBuffer_.width = desc.width;
currentBackBuffer_.height = desc.height;
currentBackBuffer_.format = desc.format;
// re-create render pass (swapchain/backbuffer size may have changed)
const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
renderPass_ = renderNodeUtil.CreateRenderPass(inputRenderPass_);
currentViewportDesc_.x = 0.0f;
currentViewportDesc_.y = 0.0f;
currentViewportDesc_.width = static_cast(currentBackBuffer_.width);
currentViewportDesc_.height = static_cast(currentBackBuffer_.height);
currentScissorDesc_.offsetX = 0;
currentScissorDesc_.offsetY = 0;
currentScissorDesc_.extentWidth = currentBackBuffer_.width;
currentScissorDesc_.extentHeight = currentBackBuffer_.height;
}
}
return dstImageHandle;
}
void RenderNodeBackBuffer::ParseRenderNodeInputs()
{
const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
jsonInputs_.renderPass = parserUtil.GetInputRenderPass(jsonVal, "renderPass");
jsonInputs_.resources = parserUtil.GetInputResources(jsonVal, "resources");
jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
const auto shaderName = parserUtil.GetStringValue(jsonVal, "shader");
const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
shader_ = shaderMgr.GetShaderHandle(shaderName);
const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
jsonInputs_.hasChangeableRenderPassHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.renderPass);
jsonInputs_.hasChangeableResourceHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.resources);
}
// for plugin / factory interface
IRenderNode* RenderNodeBackBuffer::Create()
{
return new RenderNodeBackBuffer();
}
void RenderNodeBackBuffer::Destroy(IRenderNode* instance)
{
delete static_cast(instance);
}
RENDER_END_NAMESPACE()