/*
* 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_fullscreen_generic.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "util/log.h"
using namespace BASE_NS;
RENDER_BEGIN_NAMESPACE()
void RenderNodeFullscreenGeneric::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
{
renderNodeContextMgr_ = &renderNodeContextMgr;
pipelineData_ = {};
ParseRenderNodeInputs();
useDataStoreShaderSpecialization_ = !jsonInputs_.renderDataStoreSpecialization.dataStoreName.empty();
const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
if (RenderHandleUtil::GetHandleType(pipelineData_.shader) != RenderHandleType::SHADER_STATE_OBJECT) {
PLUGIN_LOG_E("RenderNodeFullscreenGeneric needs a valid shader handle");
}
if (useDataStoreShaderSpecialization_) {
const ShaderSpecializationConstantView sscv = shaderMgr.GetReflectionSpecialization(pipelineData_.shader);
shaderSpecializationData_.constants.resize(sscv.constants.size());
shaderSpecializationData_.data.resize(sscv.constants.size());
for (size_t idx = 0; idx < shaderSpecializationData_.constants.size(); ++idx) {
shaderSpecializationData_.constants[idx] = sscv.constants[idx];
shaderSpecializationData_.data[idx] = ~0u;
}
useDataStoreShaderSpecialization_ = !sscv.constants.empty();
}
const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
pipelineData_.pipelineLayout = shaderMgr.GetPipelineLayoutHandleByShaderHandle(pipelineData_.shader);
if (!RenderHandleUtil::IsValid(pipelineData_.pipelineLayout)) {
pipelineData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayoutHandle(pipelineData_.shader);
}
pipelineData_.graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(pipelineData_.shader);
pipelineData_.pipelineLayoutData = shaderMgr.GetPipelineLayout(pipelineData_.pipelineLayout);
pipelineData_.pso = GetPsoHandle();
{
const DescriptorCounts dc = renderNodeUtil.GetDescriptorCounts(pipelineData_.pipelineLayoutData);
renderNodeContextMgr.GetDescriptorSetManager().ResetAndReserve(dc);
}
pipelineDescriptorSetBinder_ = renderNodeUtil.CreatePipelineDescriptorSetBinder(pipelineData_.pipelineLayoutData);
renderNodeUtil.BindResourcesToBinder(inputResources_, *pipelineDescriptorSetBinder_);
useDataStorePushConstant_ = (pipelineData_.pipelineLayoutData.pushConstant.byteSize > 0) &&
(!jsonInputs_.renderDataStore.dataStoreName.empty()) &&
(!jsonInputs_.renderDataStore.configurationName.empty());
}
void RenderNodeFullscreenGeneric::PreExecuteFrame()
{
// re-create needed gpu resources
}
void RenderNodeFullscreenGeneric::ExecuteFrame(IRenderCommandList& cmdList)
{
if (!RENDER_NS::RenderHandleUtil::IsValid(pipelineData_.pso)) {
return;
}
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_);
}
const RenderPass renderPass = renderNodeUtil.CreateRenderPass(inputRenderPass_);
const ViewportDesc viewportDesc = renderNodeUtil.CreateDefaultViewport(renderPass);
const ScissorDesc scissorDesc = renderNodeUtil.CreateDefaultScissor(renderPass);
const auto setIndices = pipelineDescriptorSetBinder_->GetSetIndices();
const uint32_t firstSetIndex = pipelineDescriptorSetBinder_->GetFirstSet();
for (auto refIndex : setIndices) {
const auto descHandle = pipelineDescriptorSetBinder_->GetDescriptorSetHandle(refIndex);
const auto bindings = pipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(refIndex);
cmdList.UpdateDescriptorSet(descHandle, bindings);
}
#if (RENDER_VALIDATION_ENABLED == 1)
if (!pipelineDescriptorSetBinder_->GetPipelineDescriptorSetLayoutBindingValidity()) {
PLUGIN_LOG_ONCE_E(renderNodeContextMgr_->GetName() + "_RCL_UpdateDescriptorSet_invalid_",
"RENDER_VALIDATION: RenderNodeFullscreenGeneric: bindings missing (RN: %s)",
renderNodeContextMgr_->GetName().data());
}
#endif
cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
const RenderHandle psoHandle = GetPsoHandle();
cmdList.BindPipeline(psoHandle);
// bind all sets from the first on-wards
cmdList.BindDescriptorSets(firstSetIndex, pipelineDescriptorSetBinder_->GetDescriptorSetHandles());
// dynamic state
cmdList.SetDynamicStateViewport(viewportDesc);
cmdList.SetDynamicStateScissor(scissorDesc);
if (renderPass.subpassDesc.fragmentShadingRateAttachmentCount > 0) {
cmdList.SetDynamicStateFragmentShadingRate(
{ 1u, 1u }, FragmentShadingRateCombinerOps { CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE,
CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE });
}
// push constants
if (useDataStorePushConstant_) {
const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
const auto dataStore = static_cast(
renderDataStoreMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName));
if (dataStore) {
const auto dataView = dataStore->Get(jsonInputs_.renderDataStore.configurationName);
if (!dataView.empty()) {
cmdList.PushConstant(pipelineData_.pipelineLayoutData.pushConstant, dataView.data());
}
}
}
cmdList.Draw(3u, 1u, 0u, 0u); // vertex count, instance count, first vertex, first instance
cmdList.EndRenderPass();
}
RenderHandle RenderNodeFullscreenGeneric::GetPsoHandle()
{
// controlled by count
constexpr DynamicStateEnum dynamicStates[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR,
CORE_DYNAMIC_STATE_ENUM_FRAGMENT_SHADING_RATE };
if (useDataStoreShaderSpecialization_) {
const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
const auto dataStore = static_cast(
renderDataStoreMgr.GetRenderDataStore(jsonInputs_.renderDataStoreSpecialization.dataStoreName));
if (dataStore) {
const auto dataView = dataStore->Get(jsonInputs_.renderDataStoreSpecialization.configurationName);
if (dataView.data() && (dataView.size_bytes() == sizeof(ShaderSpecializationRenderPod))) {
const auto* spec = reinterpret_cast(dataView.data());
bool valuesChanged = false;
const uint32_t specializationCount = Math::min(
Math::min(spec->specializationConstantCount,
static_cast(shaderSpecializationData_.constants.size())),
ShaderSpecializationRenderPod::MAX_SPECIALIZATION_CONSTANT_COUNT);
for (uint32_t idx = 0; idx < specializationCount; ++idx) {
const auto& ref = shaderSpecializationData_.constants[idx];
const uint32_t constantId = ref.offset / sizeof(uint32_t);
const uint32_t specId = ref.id;
if (specId < ShaderSpecializationRenderPod::MAX_SPECIALIZATION_CONSTANT_COUNT) {
if (shaderSpecializationData_.data[constantId] != spec->specializationFlags[specId].value) {
shaderSpecializationData_.data[constantId] = spec->specializationFlags[specId].value;
valuesChanged = true;
}
}
}
if (valuesChanged) {
const ShaderSpecializationConstantDataView specialization {
{ shaderSpecializationData_.constants.data(), specializationCount },
{ shaderSpecializationData_.data.data(), specializationCount }
};
const uint32_t dynamicStateCount =
(inputRenderPass_.fragmentShadingRateAttachmentIndex != ~0u) ? 3u : 2u;
pipelineData_.pso = renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(
pipelineData_.shader, pipelineData_.graphicsState, pipelineData_.pipelineLayout, {},
specialization, { dynamicStates, dynamicStateCount });
}
} else {
#if (RENDER_VALIDATION_ENABLED == 1)
const string logName = "RenderNodeFullscreenGeneric_ShaderSpecialization" +
string(jsonInputs_.renderDataStoreSpecialization.configurationName);
PLUGIN_LOG_ONCE_E(logName.c_str(),
"RENDER_VALIDATION: RenderNodeFullscreenGeneric shader specilization render data store size "
"mismatch, name: %s, size:%u, podsize%u",
jsonInputs_.renderDataStoreSpecialization.configurationName.c_str(),
static_cast(sizeof(ShaderSpecializationRenderPod)),
static_cast(dataView.size_bytes()));
#endif
}
}
} else if (!RenderHandleUtil::IsValid(pipelineData_.pso)) {
const uint32_t dynamicStateCount = (inputRenderPass_.fragmentShadingRateAttachmentIndex != ~0u) ? 3u : 2u;
pipelineData_.pso = renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(pipelineData_.shader,
pipelineData_.graphicsState, pipelineData_.pipelineLayout, {}, {}, { dynamicStates, dynamicStateCount });
}
return pipelineData_.pso;
}
void RenderNodeFullscreenGeneric::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");
jsonInputs_.renderDataStoreSpecialization =
parserUtil.GetRenderDataStore(jsonVal, "renderDataStoreShaderSpecialization");
const auto shaderName = parserUtil.GetStringValue(jsonVal, "shader");
const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
pipelineData_.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* RenderNodeFullscreenGeneric::Create()
{
return new RenderNodeFullscreenGeneric();
}
void RenderNodeFullscreenGeneric::Destroy(IRenderNode* instance)
{
delete static_cast(instance);
}
RENDER_END_NAMESPACE()