no message
This commit is contained in:
476
cocos/renderer/pipeline/deferred/BloomStage.cpp
Normal file
476
cocos/renderer/pipeline/deferred/BloomStage.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "BloomStage.h"
|
||||
#include "../PipelineStateManager.h"
|
||||
#include "../PipelineUBO.h"
|
||||
#include "../RenderPipeline.h"
|
||||
#include "../RenderQueue.h"
|
||||
#include "frame-graph/DevicePass.h"
|
||||
#include "frame-graph/PassNodeBuilder.h"
|
||||
#include "frame-graph/Resource.h"
|
||||
#include "gfx-base/GFXBuffer.h"
|
||||
#include "gfx-base/GFXCommandBuffer.h"
|
||||
#include "gfx-base/GFXDef-common.h"
|
||||
#include "gfx-base/GFXDevice.h"
|
||||
#include "gfx-base/GFXFramebuffer.h"
|
||||
#include "gfx-base/states/GFXSampler.h"
|
||||
#include "pipeline/Define.h"
|
||||
#include "pipeline/UIPhase.h"
|
||||
#include "profiler/Profiler.h"
|
||||
#include "renderer/pipeline/deferred/DeferredPipelineSceneData.h"
|
||||
#include "scene/Camera.h"
|
||||
#include "scene/Pass.h"
|
||||
#include "scene/RenderScene.h"
|
||||
#include "scene/SubModel.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
namespace {
|
||||
const ccstd::string BLOOM_STAGE_NAME = "BloomStage";
|
||||
|
||||
framegraph::StringHandle prefilterTexHandle = framegraph::FrameGraph::stringToHandle("prefilterTex");
|
||||
framegraph::StringHandle downsampleTexHandles[MAX_BLOOM_FILTER_PASS_NUM];
|
||||
framegraph::StringHandle upsampleTexHandles[MAX_BLOOM_FILTER_PASS_NUM];
|
||||
framegraph::StringHandle prefilterPassHandle;
|
||||
framegraph::StringHandle downsamplePassHandles[MAX_BLOOM_FILTER_PASS_NUM];
|
||||
framegraph::StringHandle upsamplePassHandles[MAX_BLOOM_FILTER_PASS_NUM];
|
||||
framegraph::StringHandle combinePassHandle;
|
||||
|
||||
void initStrHandle() {
|
||||
prefilterPassHandle = framegraph::FrameGraph::stringToHandle("bloomPrefilterPass");
|
||||
|
||||
ccstd::string tmp;
|
||||
for (int i = 0; i < MAX_BLOOM_FILTER_PASS_NUM; ++i) {
|
||||
tmp = ccstd::string("bloomDownsamplePass") + std::to_string(i);
|
||||
downsamplePassHandles[i] = framegraph::FrameGraph::stringToHandle(tmp.c_str());
|
||||
|
||||
tmp = ccstd::string("bloomDownsampleTex") + std::to_string(i);
|
||||
downsampleTexHandles[i] = framegraph::FrameGraph::stringToHandle(tmp.c_str());
|
||||
|
||||
tmp = ccstd::string("bloomUpsamplePass") + std::to_string(i);
|
||||
upsamplePassHandles[i] = framegraph::FrameGraph::stringToHandle(tmp.c_str());
|
||||
|
||||
tmp = ccstd::string("bloomUpsampleTex") + std::to_string(i);
|
||||
upsampleTexHandles[i] = framegraph::FrameGraph::stringToHandle(tmp.c_str());
|
||||
}
|
||||
|
||||
combinePassHandle = framegraph::FrameGraph::stringToHandle("bloomCombinePass");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
RenderStageInfo BloomStage::initInfo = {
|
||||
BLOOM_STAGE_NAME,
|
||||
static_cast<uint32_t>(DeferredStagePriority::BLOOM),
|
||||
0,
|
||||
{ccnew RenderQueueDesc{true, RenderQueueSortMode::BACK_TO_FRONT, {"default"}}},
|
||||
};
|
||||
const RenderStageInfo &BloomStage::getInitializeInfo() { return BloomStage::initInfo; }
|
||||
|
||||
BloomStage::BloomStage() = default;
|
||||
|
||||
bool BloomStage::initialize(const RenderStageInfo &info) {
|
||||
RenderStage::initialize(info);
|
||||
initStrHandle();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BloomStage::activate(RenderPipeline *pipeline, RenderFlow *flow) {
|
||||
RenderStage::activate(pipeline, flow);
|
||||
|
||||
_phaseID = getPhaseID("default");
|
||||
}
|
||||
|
||||
void BloomStage::destroy() {
|
||||
CC_SAFE_DELETE(_prefilterUBO);
|
||||
CC_SAFE_DELETE(_combineUBO);
|
||||
for (int i = 0; i < MAX_BLOOM_FILTER_PASS_NUM; ++i) {
|
||||
CC_SAFE_DELETE(_downsampleUBO[i]);
|
||||
|
||||
CC_SAFE_DELETE(_upsampleUBO[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void BloomStage::render(scene::Camera *camera) {
|
||||
CC_PROFILE(BloomStageRender);
|
||||
auto *pipeline = _pipeline;
|
||||
CC_ASSERT_NOT_NULL(pipeline);
|
||||
if (!pipeline->isBloomEnabled() || pipeline->getPipelineSceneData()->getRenderObjects().empty()) return;
|
||||
|
||||
if (_prefilterUBO == nullptr) {
|
||||
_prefilterUBO = _device->createBuffer({gfx::BufferUsage::UNIFORM, gfx::MemoryUsage::DEVICE | gfx::MemoryUsage::HOST, UBOBloom::SIZE});
|
||||
_combineUBO = _device->createBuffer({gfx::BufferUsage::UNIFORM, gfx::MemoryUsage::DEVICE | gfx::MemoryUsage::HOST, UBOBloom::SIZE});
|
||||
for (int i = 0; i < MAX_BLOOM_FILTER_PASS_NUM; ++i) {
|
||||
_downsampleUBO[i] = _device->createBuffer({gfx::BufferUsage::UNIFORM, gfx::MemoryUsage::DEVICE | gfx::MemoryUsage::HOST, UBOBloom::SIZE});
|
||||
_upsampleUBO[i] = _device->createBuffer({gfx::BufferUsage::UNIFORM, gfx::MemoryUsage::DEVICE | gfx::MemoryUsage::HOST, UBOBloom::SIZE});
|
||||
}
|
||||
|
||||
gfx::SamplerInfo info{
|
||||
gfx::Filter::LINEAR,
|
||||
gfx::Filter::LINEAR,
|
||||
gfx::Filter::NONE,
|
||||
gfx::Address::CLAMP,
|
||||
gfx::Address::CLAMP,
|
||||
gfx::Address::CLAMP,
|
||||
};
|
||||
_sampler = pipeline->getDevice()->getSampler(info);
|
||||
}
|
||||
|
||||
if (hasFlag(static_cast<gfx::ClearFlags>(camera->getClearFlag()), gfx::ClearFlagBit::COLOR)) {
|
||||
_clearColors[0].x = camera->getClearColor().x;
|
||||
_clearColors[0].y = camera->getClearColor().y;
|
||||
_clearColors[0].z = camera->getClearColor().z;
|
||||
}
|
||||
_clearColors[0].w = camera->getClearColor().w;
|
||||
|
||||
framegraph::RenderTargetAttachment::Descriptor colorAttachmentInfo;
|
||||
colorAttachmentInfo.usage = framegraph::RenderTargetAttachment::Usage::COLOR;
|
||||
colorAttachmentInfo.loadOp = gfx::LoadOp::CLEAR;
|
||||
colorAttachmentInfo.clearColor = _clearColors[0];
|
||||
colorAttachmentInfo.endAccesses = gfx::AccessFlagBit::FRAGMENT_SHADER_READ_TEXTURE;
|
||||
|
||||
auto insertPoint = static_cast<uint32_t>(CommonInsertPoint::DIP_BLOOM);
|
||||
|
||||
// prefilter pass
|
||||
struct PrefilterRenderData {
|
||||
framegraph::TextureHandle inputTexHandle;
|
||||
framegraph::TextureHandle outputTexHandle;
|
||||
gfx::Sampler *sampler;
|
||||
gfx::Buffer *bloomUBO;
|
||||
float textureSize[4];
|
||||
};
|
||||
|
||||
auto *stage = static_cast<BloomStage *>(pipeline->getRenderstageByName(BLOOM_STAGE_NAME));
|
||||
CC_ASSERT_NOT_NULL(stage);
|
||||
int iterations = stage->getIterations();
|
||||
float intensity = stage->getIntensity();
|
||||
float threshold = stage->getThreshold();
|
||||
|
||||
_renderArea = RenderPipeline::getRenderArea(camera);
|
||||
_inputAssembler = pipeline->getIAByRenderArea(_renderArea);
|
||||
_renderArea.width >>= 1;
|
||||
_renderArea.height >>= 1;
|
||||
float shadingScale{_pipeline->getPipelineSceneData()->getShadingScale()};
|
||||
auto prefilterSetup = [&](framegraph::PassNodeBuilder &builder, PrefilterRenderData &data) {
|
||||
data.sampler = _sampler;
|
||||
// read lightingout as input
|
||||
data.inputTexHandle = framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(RenderPipeline::fgStrHandleOutColorTexture));
|
||||
if (!data.inputTexHandle.isValid()) {
|
||||
framegraph::Texture::Descriptor colorTexInfo;
|
||||
colorTexInfo.format = gfx::Format::RGBA16F;
|
||||
colorTexInfo.usage = gfx::TextureUsageBit::COLOR_ATTACHMENT | gfx::TextureUsageBit::SAMPLED;
|
||||
colorTexInfo.width = static_cast<uint32_t>(static_cast<float>(pipeline->getWidth()) * shadingScale);
|
||||
colorTexInfo.height = static_cast<uint32_t>(static_cast<float>(pipeline->getHeight()) * shadingScale);
|
||||
|
||||
data.inputTexHandle = builder.create(
|
||||
RenderPipeline::fgStrHandleOutColorTexture, colorTexInfo);
|
||||
}
|
||||
|
||||
data.inputTexHandle = builder.read(data.inputTexHandle);
|
||||
builder.writeToBlackboard(RenderPipeline::fgStrHandleOutColorTexture, data.inputTexHandle);
|
||||
|
||||
// write to bloom prefilter texture
|
||||
data.outputTexHandle = framegraph::TextureHandle(builder.readFromBlackboard(prefilterTexHandle));
|
||||
if (!data.outputTexHandle.isValid()) {
|
||||
framegraph::Texture::Descriptor colorTexInfo;
|
||||
colorTexInfo.format = gfx::Format::RGBA16F;
|
||||
colorTexInfo.usage = gfx::TextureUsageBit::COLOR_ATTACHMENT | gfx::TextureUsageBit::SAMPLED;
|
||||
colorTexInfo.width = static_cast<uint32_t>(static_cast<float>(_renderArea.width) * shadingScale);
|
||||
colorTexInfo.height = static_cast<uint32_t>(static_cast<float>(_renderArea.height) * shadingScale);
|
||||
|
||||
data.outputTexHandle = builder.create(prefilterTexHandle, colorTexInfo);
|
||||
}
|
||||
data.outputTexHandle = builder.write(data.outputTexHandle, colorAttachmentInfo);
|
||||
builder.writeToBlackboard(prefilterTexHandle, data.outputTexHandle);
|
||||
|
||||
// Update threshold
|
||||
data.bloomUBO = stage->getPrefilterUBO();
|
||||
data.textureSize[2] = threshold;
|
||||
};
|
||||
|
||||
auto prefilterExec = [this, camera](PrefilterRenderData const &data, const framegraph::DevicePassResourceTable &table) {
|
||||
auto *pipeline = _pipeline;
|
||||
gfx::RenderPass *renderPass = table.getRenderPass();
|
||||
|
||||
auto *cmdBf = pipeline->getCommandBuffers()[0];
|
||||
const ccstd::array<uint32_t, 1> globalOffsets = {_pipeline->getPipelineUBO()->getCurrentCameraUBOOffset()};
|
||||
cmdBf->bindDescriptorSet(globalSet, pipeline->getDescriptorSet(), utils::toUint(globalOffsets.size()), globalOffsets.data());
|
||||
|
||||
auto *sceneData = static_cast<DeferredPipelineSceneData *>(pipeline->getPipelineSceneData());
|
||||
scene::Pass *pass = sceneData->getBloomPrefilterPass();
|
||||
gfx::Shader *shader = sceneData->getBloomPrefilterPassShader();
|
||||
gfx::PipelineState *pso = PipelineStateManager::getOrCreatePipelineState(
|
||||
pass, shader, _inputAssembler, renderPass);
|
||||
CC_ASSERT_NOT_NULL(pso);
|
||||
|
||||
data.bloomUBO->update(data.textureSize, sizeof(data.textureSize));
|
||||
|
||||
pass->getDescriptorSet()->bindBuffer(0, data.bloomUBO);
|
||||
pass->getDescriptorSet()->bindTexture(1, table.getRead(data.inputTexHandle));
|
||||
pass->getDescriptorSet()->bindSampler(1, data.sampler);
|
||||
pass->getDescriptorSet()->update();
|
||||
|
||||
cmdBf->bindDescriptorSet(materialSet, pass->getDescriptorSet());
|
||||
cmdBf->bindPipelineState(pso);
|
||||
cmdBf->bindInputAssembler(_inputAssembler);
|
||||
cmdBf->draw(_inputAssembler);
|
||||
};
|
||||
|
||||
pipeline->getFrameGraph().addPass<PrefilterRenderData>(insertPoint, prefilterPassHandle, prefilterSetup, prefilterExec);
|
||||
|
||||
struct ScalingSampleRenderData {
|
||||
framegraph::TextureHandle inputTexHandle;
|
||||
framegraph::TextureHandle outputTexHandle;
|
||||
gfx::Sampler *sampler;
|
||||
gfx::Buffer *bloomUBO;
|
||||
float textureSize[4];
|
||||
int index;
|
||||
};
|
||||
// downsample pass
|
||||
for (int i = 0; i < iterations; ++i) {
|
||||
_renderArea.width >>= 1;
|
||||
_renderArea.height >>= 1;
|
||||
|
||||
auto downsampleSetup = [&, i](framegraph::PassNodeBuilder &builder, ScalingSampleRenderData &data) {
|
||||
data.sampler = _sampler;
|
||||
data.index = i;
|
||||
// read from prefilter texture or last downsample texture
|
||||
if (data.index == 0) {
|
||||
data.inputTexHandle = builder.read(framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(prefilterTexHandle)));
|
||||
builder.writeToBlackboard(prefilterTexHandle, data.inputTexHandle);
|
||||
} else {
|
||||
data.inputTexHandle = builder.read(framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(downsampleTexHandles[data.index - 1])));
|
||||
builder.writeToBlackboard(downsampleTexHandles[data.index - 1], data.inputTexHandle);
|
||||
}
|
||||
|
||||
// write to downsample texture
|
||||
data.outputTexHandle = framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(downsampleTexHandles[data.index]));
|
||||
if (!data.outputTexHandle.isValid()) {
|
||||
framegraph::Texture::Descriptor colorTexInfo;
|
||||
colorTexInfo.format = gfx::Format::RGBA16F;
|
||||
colorTexInfo.usage = gfx::TextureUsageBit::COLOR_ATTACHMENT | gfx::TextureUsageBit::SAMPLED;
|
||||
colorTexInfo.width = static_cast<uint32_t>(static_cast<float>(_renderArea.width) * shadingScale);
|
||||
colorTexInfo.height = static_cast<uint32_t>(static_cast<float>(_renderArea.height) * shadingScale);
|
||||
|
||||
data.outputTexHandle = builder.create(downsampleTexHandles[data.index], colorTexInfo);
|
||||
}
|
||||
data.outputTexHandle = builder.write(data.outputTexHandle, colorAttachmentInfo);
|
||||
builder.writeToBlackboard(downsampleTexHandles[data.index], data.outputTexHandle);
|
||||
|
||||
// Update cc_textureSize
|
||||
data.bloomUBO = stage->getDownsampleUBO()[data.index];
|
||||
data.textureSize[0] = static_cast<float>(static_cast<uint32_t>(static_cast<float>(_renderArea.width) * shadingScale) << 1);
|
||||
data.textureSize[1] = static_cast<float>(static_cast<uint32_t>(static_cast<float>(_renderArea.height) * shadingScale) << 1);
|
||||
};
|
||||
|
||||
auto downsampleExec = [this, camera](ScalingSampleRenderData const &data, const framegraph::DevicePassResourceTable &table) {
|
||||
auto *pipeline = _pipeline;
|
||||
gfx::RenderPass *renderPass = table.getRenderPass();
|
||||
|
||||
auto *cmdBf = pipeline->getCommandBuffers()[0];
|
||||
const ccstd::array<uint32_t, 1> globalOffsets = {_pipeline->getPipelineUBO()->getCurrentCameraUBOOffset()};
|
||||
cmdBf->bindDescriptorSet(globalSet, pipeline->getDescriptorSet(), utils::toUint(globalOffsets.size()), globalOffsets.data());
|
||||
|
||||
auto *const sceneData = static_cast<DeferredPipelineSceneData *>(pipeline->getPipelineSceneData());
|
||||
scene::Pass *pass = sceneData->getBloomDownSamplePasses()[data.index];
|
||||
gfx::Shader *shader = sceneData->getBloomDownSamplePassShader();
|
||||
gfx::PipelineState *pso = PipelineStateManager::getOrCreatePipelineState(
|
||||
pass, shader, _inputAssembler, renderPass);
|
||||
CC_ASSERT_NOT_NULL(pso);
|
||||
|
||||
data.bloomUBO->update(data.textureSize, sizeof(data.textureSize));
|
||||
|
||||
pass->getDescriptorSet()->bindBuffer(0, data.bloomUBO);
|
||||
pass->getDescriptorSet()->bindTexture(1, table.getRead(data.inputTexHandle));
|
||||
pass->getDescriptorSet()->bindSampler(1, data.sampler);
|
||||
pass->getDescriptorSet()->update();
|
||||
|
||||
cmdBf->bindDescriptorSet(materialSet, pass->getDescriptorSet());
|
||||
cmdBf->bindPipelineState(pso);
|
||||
cmdBf->bindInputAssembler(_inputAssembler);
|
||||
cmdBf->draw(_inputAssembler);
|
||||
};
|
||||
|
||||
pipeline->getFrameGraph().addPass<ScalingSampleRenderData>(++insertPoint, downsamplePassHandles[i], downsampleSetup, downsampleExec);
|
||||
}
|
||||
|
||||
// upsample pass
|
||||
for (int i = 0; i < iterations; ++i) {
|
||||
_renderArea.width <<= 1;
|
||||
_renderArea.height <<= 1;
|
||||
|
||||
auto upsampleSetup = [&, i](framegraph::PassNodeBuilder &builder, ScalingSampleRenderData &data) {
|
||||
data.index = i;
|
||||
data.sampler = _sampler;
|
||||
// read from last downsample texture or last upsample texture
|
||||
if (data.index == 0) {
|
||||
data.inputTexHandle = builder.read(framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(downsampleTexHandles[iterations - 1])));
|
||||
builder.writeToBlackboard(downsampleTexHandles[iterations - 1], data.inputTexHandle);
|
||||
} else {
|
||||
data.inputTexHandle = builder.read(framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(upsampleTexHandles[data.index - 1])));
|
||||
builder.writeToBlackboard(upsampleTexHandles[data.index - 1], data.inputTexHandle);
|
||||
}
|
||||
|
||||
// write to downsample texture
|
||||
data.outputTexHandle = framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(upsampleTexHandles[data.index]));
|
||||
if (!data.outputTexHandle.isValid()) {
|
||||
framegraph::Texture::Descriptor colorTexInfo;
|
||||
colorTexInfo.format = gfx::Format::RGBA16F;
|
||||
colorTexInfo.usage = gfx::TextureUsageBit::COLOR_ATTACHMENT | gfx::TextureUsageBit::SAMPLED;
|
||||
colorTexInfo.width = static_cast<uint32_t>(static_cast<float>(_renderArea.width) * shadingScale);
|
||||
colorTexInfo.height = static_cast<uint32_t>(static_cast<float>(_renderArea.height) * shadingScale);
|
||||
|
||||
data.outputTexHandle = builder.create(
|
||||
upsampleTexHandles[data.index], colorTexInfo);
|
||||
}
|
||||
data.outputTexHandle = builder.write(data.outputTexHandle, colorAttachmentInfo);
|
||||
builder.writeToBlackboard(upsampleTexHandles[data.index], data.outputTexHandle);
|
||||
|
||||
// Update cc_textureSize
|
||||
data.bloomUBO = stage->getUpsampleUBO()[data.index];
|
||||
data.textureSize[0] = static_cast<float>(static_cast<uint32_t>(static_cast<float>(_renderArea.width) * shadingScale) >> 1);
|
||||
data.textureSize[1] = static_cast<float>(static_cast<uint32_t>(static_cast<float>(_renderArea.height) * shadingScale) >> 1);
|
||||
};
|
||||
|
||||
auto upsampleExec = [this, camera](ScalingSampleRenderData const &data, const framegraph::DevicePassResourceTable &table) {
|
||||
auto *pipeline = _pipeline;
|
||||
gfx::RenderPass *renderPass = table.getRenderPass();
|
||||
|
||||
auto *cmdBf = pipeline->getCommandBuffers()[0];
|
||||
const ccstd::array<uint32_t, 1> globalOffsets = {_pipeline->getPipelineUBO()->getCurrentCameraUBOOffset()};
|
||||
cmdBf->bindDescriptorSet(globalSet, pipeline->getDescriptorSet(), utils::toUint(globalOffsets.size()), globalOffsets.data());
|
||||
|
||||
auto *const sceneData = static_cast<DeferredPipelineSceneData *>(pipeline->getPipelineSceneData());
|
||||
scene::Pass *pass = sceneData->getBloomUpSamplePasses()[data.index];
|
||||
gfx::Shader *shader = sceneData->getBloomUpSamplePassShader();
|
||||
gfx::PipelineState *pso = PipelineStateManager::getOrCreatePipelineState(
|
||||
pass, shader, _inputAssembler, renderPass);
|
||||
CC_ASSERT_NOT_NULL(pso);
|
||||
|
||||
data.bloomUBO->update(data.textureSize, sizeof(data.textureSize));
|
||||
|
||||
pass->getDescriptorSet()->bindBuffer(0, data.bloomUBO);
|
||||
pass->getDescriptorSet()->bindTexture(1, table.getRead(data.inputTexHandle));
|
||||
pass->getDescriptorSet()->bindSampler(1, data.sampler);
|
||||
pass->getDescriptorSet()->update();
|
||||
|
||||
cmdBf->bindDescriptorSet(materialSet, pass->getDescriptorSet());
|
||||
cmdBf->bindPipelineState(pso);
|
||||
cmdBf->bindInputAssembler(_inputAssembler);
|
||||
cmdBf->draw(_inputAssembler);
|
||||
};
|
||||
|
||||
pipeline->getFrameGraph().addPass<ScalingSampleRenderData>(++insertPoint, upsamplePassHandles[i], upsampleSetup, upsampleExec);
|
||||
}
|
||||
|
||||
// combine pass
|
||||
struct CombineRenderData {
|
||||
framegraph::TextureHandle lightingOutTexHandle;
|
||||
framegraph::TextureHandle upsampleTexHandle;
|
||||
framegraph::TextureHandle bloomOutTexHandle;
|
||||
gfx::Sampler *sampler;
|
||||
gfx::Buffer *bloomUBO;
|
||||
float textureSize[4];
|
||||
};
|
||||
|
||||
_renderArea.width <<= 1;
|
||||
_renderArea.height <<= 1;
|
||||
|
||||
auto combineSetup = [&](framegraph::PassNodeBuilder &builder, CombineRenderData &data) {
|
||||
data.sampler = _sampler;
|
||||
|
||||
// read lighting result or last upsample texture
|
||||
data.lightingOutTexHandle = builder.read(framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(RenderPipeline::fgStrHandleOutColorTexture)));
|
||||
builder.writeToBlackboard(RenderPipeline::fgStrHandleOutColorTexture, data.lightingOutTexHandle);
|
||||
|
||||
data.upsampleTexHandle = builder.read(framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(upsampleTexHandles[iterations - 1])));
|
||||
builder.writeToBlackboard(upsampleTexHandles[iterations - 1], data.upsampleTexHandle);
|
||||
|
||||
// write to bloomOut texture
|
||||
data.bloomOutTexHandle = framegraph::TextureHandle(
|
||||
builder.readFromBlackboard(RenderPipeline::fgStrHandleBloomOutTexture));
|
||||
if (!data.bloomOutTexHandle.isValid()) {
|
||||
framegraph::Texture::Descriptor colorTexInfo;
|
||||
colorTexInfo.format = gfx::Format::RGBA16F;
|
||||
colorTexInfo.usage = gfx::TextureUsageBit::COLOR_ATTACHMENT | gfx::TextureUsageBit::SAMPLED;
|
||||
colorTexInfo.width = static_cast<uint32_t>(static_cast<float>(_renderArea.width) * shadingScale);
|
||||
colorTexInfo.height = static_cast<uint32_t>(static_cast<float>(_renderArea.height) * shadingScale);
|
||||
|
||||
data.bloomOutTexHandle = builder.create(
|
||||
RenderPipeline::fgStrHandleBloomOutTexture, colorTexInfo);
|
||||
}
|
||||
data.bloomOutTexHandle = builder.write(data.bloomOutTexHandle, colorAttachmentInfo);
|
||||
builder.writeToBlackboard(RenderPipeline::fgStrHandleBloomOutTexture, data.bloomOutTexHandle);
|
||||
|
||||
// Update intensity
|
||||
data.bloomUBO = stage->getCombineUBO();
|
||||
data.textureSize[3] = intensity;
|
||||
};
|
||||
|
||||
auto combineExec = [this, camera](CombineRenderData const &data, const framegraph::DevicePassResourceTable &table) {
|
||||
auto *pipeline = _pipeline;
|
||||
gfx::RenderPass *renderPass = table.getRenderPass();
|
||||
|
||||
auto *cmdBf = pipeline->getCommandBuffers()[0];
|
||||
const ccstd::array<uint32_t, 1> globalOffsets = {_pipeline->getPipelineUBO()->getCurrentCameraUBOOffset()};
|
||||
cmdBf->bindDescriptorSet(globalSet, pipeline->getDescriptorSet(), utils::toUint(globalOffsets.size()), globalOffsets.data());
|
||||
|
||||
auto *const sceneData = static_cast<DeferredPipelineSceneData *>(pipeline->getPipelineSceneData());
|
||||
scene::Pass *pass = sceneData->getBloomCombinePass();
|
||||
gfx::Shader *shader = sceneData->getBloomCombinePassShader();
|
||||
gfx::PipelineState *pso = PipelineStateManager::getOrCreatePipelineState(
|
||||
pass, shader, _inputAssembler, renderPass);
|
||||
CC_ASSERT_NOT_NULL(pso);
|
||||
|
||||
data.bloomUBO->update(data.textureSize, sizeof(data.textureSize));
|
||||
|
||||
pass->getDescriptorSet()->bindBuffer(0, data.bloomUBO);
|
||||
pass->getDescriptorSet()->bindTexture(1, table.getRead(data.lightingOutTexHandle));
|
||||
pass->getDescriptorSet()->bindTexture(2, table.getRead(data.upsampleTexHandle));
|
||||
pass->getDescriptorSet()->bindSampler(1, data.sampler);
|
||||
pass->getDescriptorSet()->bindSampler(2, data.sampler);
|
||||
pass->getDescriptorSet()->update();
|
||||
|
||||
cmdBf->bindDescriptorSet(materialSet, pass->getDescriptorSet());
|
||||
cmdBf->bindPipelineState(pso);
|
||||
cmdBf->bindInputAssembler(_inputAssembler);
|
||||
cmdBf->draw(_inputAssembler);
|
||||
};
|
||||
|
||||
pipeline->getFrameGraph().addPass<CombineRenderData>(++insertPoint, combinePassHandle, combineSetup, combineExec);
|
||||
}
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
88
cocos/renderer/pipeline/deferred/BloomStage.h
Normal file
88
cocos/renderer/pipeline/deferred/BloomStage.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../RenderStage.h"
|
||||
#include "base/std/container/array.h"
|
||||
#include "frame-graph/Handle.h"
|
||||
#include "pipeline/Enum.h"
|
||||
|
||||
#define MAX_BLOOM_FILTER_PASS_NUM 6
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
|
||||
struct CC_DLL UBOBloom {
|
||||
static constexpr uint32_t TEXTURE_SIZE_OFFSET = 0;
|
||||
static constexpr uint32_t COUNT = UBOBloom::TEXTURE_SIZE_OFFSET + 4;
|
||||
static constexpr uint32_t SIZE = UBOBloom::COUNT * 4;
|
||||
};
|
||||
|
||||
class CC_DLL BloomStage : public RenderStage {
|
||||
public:
|
||||
using SampleUBOArray = ccstd::array<gfx::Buffer *, MAX_BLOOM_FILTER_PASS_NUM>;
|
||||
|
||||
BloomStage();
|
||||
~BloomStage() override = default;
|
||||
|
||||
static const RenderStageInfo &getInitializeInfo();
|
||||
bool initialize(const RenderStageInfo &info) override;
|
||||
void activate(RenderPipeline *pipeline, RenderFlow *flow) override;
|
||||
void destroy() override;
|
||||
void render(scene::Camera *camera) override;
|
||||
|
||||
gfx::Buffer *getPrefilterUBO() { return _prefilterUBO; }
|
||||
SampleUBOArray &getDownsampleUBO() { return _downsampleUBO; }
|
||||
SampleUBOArray &getUpsampleUBO() { return _upsampleUBO; }
|
||||
gfx::Buffer *getCombineUBO() { return _combineUBO; }
|
||||
gfx::Sampler *getSampler() const { return _sampler; }
|
||||
|
||||
inline float getThreshold() const { return _threshold; }
|
||||
inline void setThreshold(float value) { _threshold = value; }
|
||||
inline float getIntensity() const { return _intensity; }
|
||||
inline void setIntensity(float value) { _intensity = value; }
|
||||
inline int getIterations() const { return _iterations; }
|
||||
inline void setIterations(int value) {
|
||||
_iterations = std::max(1, std::min(value, MAX_BLOOM_FILTER_PASS_NUM));
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t _phaseID = 0;
|
||||
|
||||
static RenderStageInfo initInfo;
|
||||
|
||||
float _threshold = 1.0F;
|
||||
float _intensity = 0.8F;
|
||||
int _iterations = 2;
|
||||
gfx::Sampler *_sampler = nullptr;
|
||||
gfx::Buffer *_prefilterUBO = nullptr;
|
||||
SampleUBOArray _downsampleUBO{};
|
||||
SampleUBOArray _upsampleUBO{};
|
||||
gfx::Buffer *_combineUBO = nullptr;
|
||||
framegraph::StringHandle _fgStrHandleBloomOut;
|
||||
};
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
221
cocos/renderer/pipeline/deferred/DeferredPipeline.cpp
Normal file
221
cocos/renderer/pipeline/deferred/DeferredPipeline.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "DeferredPipeline.h"
|
||||
#include "../GlobalDescriptorSetManager.h"
|
||||
#include "../PipelineUBO.h"
|
||||
#include "../RenderPipeline.h"
|
||||
#include "../SceneCulling.h"
|
||||
#include "../helper/Utils.h"
|
||||
#include "../shadow/ShadowFlow.h"
|
||||
#include "DeferredPipelineSceneData.h"
|
||||
#include "MainFlow.h"
|
||||
#include "gfx-base/GFXBuffer.h"
|
||||
#include "gfx-base/GFXCommandBuffer.h"
|
||||
#include "gfx-base/GFXDef.h"
|
||||
#include "gfx-base/GFXDescriptorSet.h"
|
||||
#include "gfx-base/GFXDevice.h"
|
||||
#include "gfx-base/GFXSwapchain.h"
|
||||
#include "gfx-base/states/GFXTextureBarrier.h"
|
||||
#include "pipeline/ClusterLightCulling.h"
|
||||
#include "profiler/Profiler.h"
|
||||
#include "scene/RenderWindow.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
|
||||
#define TO_VEC3(dst, src, offset) \
|
||||
dst[offset] = (src).x; \
|
||||
(dst)[(offset) + 1] = (src).y; \
|
||||
(dst)[(offset) + 2] = (src).z;
|
||||
#define TO_VEC4(dst, src, offset) \
|
||||
dst[offset] = (src).x; \
|
||||
(dst)[(offset) + 1] = (src).y; \
|
||||
(dst)[(offset) + 2] = (src).z; \
|
||||
(dst)[(offset) + 3] = (src).w;
|
||||
|
||||
DeferredPipeline::DeferredPipeline() {
|
||||
_pipelineSceneData = ccnew DeferredPipelineSceneData();
|
||||
}
|
||||
|
||||
DeferredPipeline::~DeferredPipeline() = default;
|
||||
|
||||
framegraph::StringHandle DeferredPipeline::fgStrHandleGbufferTexture[GBUFFER_COUNT] = {
|
||||
framegraph::FrameGraph::stringToHandle("gbufferAlbedoTexture"),
|
||||
framegraph::FrameGraph::stringToHandle("gbufferNormalTexture"),
|
||||
framegraph::FrameGraph::stringToHandle("gbufferEmissiveTexture")};
|
||||
|
||||
framegraph::StringHandle DeferredPipeline::fgStrHandleGbufferPass = framegraph::FrameGraph::stringToHandle("deferredGbufferPass");
|
||||
framegraph::StringHandle DeferredPipeline::fgStrHandleLightingPass = framegraph::FrameGraph::stringToHandle("deferredLightingPass");
|
||||
framegraph::StringHandle DeferredPipeline::fgStrHandleTransparentPass = framegraph::FrameGraph::stringToHandle("deferredTransparentPass");
|
||||
framegraph::StringHandle DeferredPipeline::fgStrHandleSsprPass = framegraph::FrameGraph::stringToHandle("deferredSSPRPass");
|
||||
|
||||
bool DeferredPipeline::initialize(const RenderPipelineInfo &info) {
|
||||
RenderPipeline::initialize(info);
|
||||
|
||||
if (_flows.empty()) {
|
||||
auto *shadowFlow = ccnew ShadowFlow;
|
||||
shadowFlow->initialize(ShadowFlow::getInitializeInfo());
|
||||
_flows.emplace_back(shadowFlow);
|
||||
|
||||
auto *mainFlow = ccnew MainFlow;
|
||||
mainFlow->initialize(MainFlow::getInitializeInfo());
|
||||
_flows.emplace_back(mainFlow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeferredPipeline::activate(gfx::Swapchain *swapchain) {
|
||||
_macros["CC_PIPELINE_TYPE"] = 1;
|
||||
|
||||
if (!RenderPipeline::activate(swapchain)) {
|
||||
CC_LOG_ERROR("RenderPipeline active failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!activeRenderer(swapchain)) {
|
||||
CC_LOG_ERROR("DeferredPipeline startup failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeferredPipeline::render(const ccstd::vector<scene::Camera *> &cameras) {
|
||||
CC_PROFILE(DeferredPipelineRender);
|
||||
#if CC_USE_GEOMETRY_RENDERER
|
||||
updateGeometryRenderer(cameras); // for capability
|
||||
#endif
|
||||
|
||||
auto *device = gfx::Device::getInstance();
|
||||
bool enableOcclusionQuery = isOcclusionQueryEnabled();
|
||||
if (enableOcclusionQuery) {
|
||||
device->getQueryPoolResults(_queryPools[0]);
|
||||
}
|
||||
|
||||
_commandBuffers[0]->begin();
|
||||
|
||||
if (enableOcclusionQuery) {
|
||||
_commandBuffers[0]->resetQueryPool(_queryPools[0]);
|
||||
}
|
||||
|
||||
_pipelineUBO->updateMultiCameraUBO(_globalDSManager, cameras);
|
||||
_pipelineUBO->updateGlobalUBO(cameras[0]);
|
||||
|
||||
ensureEnoughSize(cameras);
|
||||
decideProfilerCamera(cameras);
|
||||
|
||||
for (auto *camera : cameras) {
|
||||
sceneCulling(this, camera);
|
||||
|
||||
if (_clusterEnabled) {
|
||||
_clusterComp->clusterLightCulling(camera);
|
||||
}
|
||||
|
||||
for (auto const &flow : _flows) {
|
||||
flow->render(camera);
|
||||
}
|
||||
_fg.compile();
|
||||
_fg.execute();
|
||||
_fg.reset();
|
||||
|
||||
_pipelineUBO->incCameraUBOOffset();
|
||||
}
|
||||
|
||||
if (enableOcclusionQuery) {
|
||||
_commandBuffers[0]->completeQueryPool(_queryPools[0]);
|
||||
}
|
||||
|
||||
_commandBuffers[0]->end();
|
||||
_device->flushCommands(_commandBuffers);
|
||||
_device->getQueue()->submit(_commandBuffers);
|
||||
|
||||
RenderPipeline::framegraphGC();
|
||||
}
|
||||
|
||||
void DeferredPipeline::onGlobalPipelineStateChanged() {
|
||||
_pipelineSceneData->updatePipelineSceneData();
|
||||
}
|
||||
|
||||
bool DeferredPipeline::activeRenderer(gfx::Swapchain *swapchain) {
|
||||
_commandBuffers.push_back(_device->getCommandBuffer());
|
||||
_queryPools.push_back(_device->getQueryPool());
|
||||
|
||||
gfx::Sampler *const sampler = getGlobalDSManager()->getPointSampler();
|
||||
|
||||
// Main light sampler binding
|
||||
_descriptorSet->bindSampler(SHADOWMAP::BINDING, sampler);
|
||||
_descriptorSet->bindSampler(SPOTSHADOWMAP::BINDING, sampler);
|
||||
_descriptorSet->update();
|
||||
|
||||
// update global defines when all states initialized.
|
||||
_macros["CC_USE_HDR"] = static_cast<bool>(_pipelineSceneData->isHDR());
|
||||
_macros["CC_SUPPORT_FLOAT_TEXTURE"] = hasAnyFlags(_device->getFormatFeatures(gfx::Format::RGBA32F), gfx::FormatFeature::RENDER_TARGET | gfx::FormatFeature::SAMPLED_TEXTURE);
|
||||
|
||||
// step 2 create index buffer
|
||||
uint32_t ibStride = 4;
|
||||
uint32_t ibSize = ibStride * 6;
|
||||
if (_quadIB == nullptr) {
|
||||
_quadIB = _device->createBuffer({gfx::BufferUsageBit::INDEX | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE, ibSize, ibStride});
|
||||
}
|
||||
|
||||
if (_quadIB == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int ibData[] = {0, 1, 2, 1, 3, 2};
|
||||
_quadIB->update(ibData, sizeof(ibData));
|
||||
|
||||
_width = swapchain->getWidth();
|
||||
_height = swapchain->getHeight();
|
||||
|
||||
if (_clusterEnabled) {
|
||||
// cluster component resource
|
||||
_clusterComp = ccnew ClusterLightCulling(this);
|
||||
_clusterComp->initialize(this->getDevice());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeferredPipeline::destroy() {
|
||||
destroyQuadInputAssembler();
|
||||
|
||||
for (auto &it : _renderPasses) {
|
||||
it.second->destroy();
|
||||
}
|
||||
_renderPasses.clear();
|
||||
|
||||
_queryPools.clear();
|
||||
_commandBuffers.clear();
|
||||
|
||||
CC_SAFE_DELETE(_clusterComp);
|
||||
|
||||
return RenderPipeline::destroy();
|
||||
}
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
84
cocos/renderer/pipeline/deferred/DeferredPipeline.h
Normal file
84
cocos/renderer/pipeline/deferred/DeferredPipeline.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/std/container/array.h"
|
||||
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "pipeline/Enum.h"
|
||||
#include "pipeline/RenderPipeline.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
class ClusterLightCulling;
|
||||
|
||||
struct UBOGlobal;
|
||||
struct UBOCamera;
|
||||
struct UBOShadow;
|
||||
|
||||
class CC_DLL DeferredPipeline : public RenderPipeline {
|
||||
public:
|
||||
DeferredPipeline();
|
||||
~DeferredPipeline() override;
|
||||
|
||||
bool initialize(const RenderPipelineInfo &info) override;
|
||||
bool destroy() override;
|
||||
bool activate(gfx::Swapchain *swapchain) override;
|
||||
void render(const ccstd::vector<scene::Camera *> &cameras) override;
|
||||
void onGlobalPipelineStateChanged() override;
|
||||
|
||||
inline gfx::Buffer *getLightsUBO() const { return _lightsUBO; }
|
||||
inline const LightList &getValidLights() const { return _validLights; }
|
||||
inline const gfx::BufferList &getLightBuffers() const { return _lightBuffers; }
|
||||
inline const UintList &getLightIndexOffsets() const { return _lightIndexOffsets; }
|
||||
inline const UintList &getLightIndices() const { return _lightIndices; }
|
||||
|
||||
private:
|
||||
bool activeRenderer(gfx::Swapchain *swapchain);
|
||||
|
||||
gfx::Buffer *_lightsUBO = nullptr;
|
||||
LightList _validLights;
|
||||
gfx::BufferList _lightBuffers;
|
||||
UintList _lightIndexOffsets;
|
||||
UintList _lightIndices;
|
||||
|
||||
ClusterLightCulling *_clusterComp{nullptr};
|
||||
|
||||
public:
|
||||
static constexpr uint32_t GBUFFER_COUNT = 3;
|
||||
|
||||
// deferred resource names
|
||||
static framegraph::StringHandle fgStrHandleGbufferTexture[GBUFFER_COUNT];
|
||||
|
||||
// deferred pass names
|
||||
static framegraph::StringHandle fgStrHandleGbufferPass;
|
||||
static framegraph::StringHandle fgStrHandleLightingPass;
|
||||
static framegraph::StringHandle fgStrHandleTransparentPass;
|
||||
static framegraph::StringHandle fgStrHandleSsprPass;
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
177
cocos/renderer/pipeline/deferred/DeferredPipelineSceneData.cpp
Normal file
177
cocos/renderer/pipeline/deferred/DeferredPipelineSceneData.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "renderer/pipeline/deferred/DeferredPipelineSceneData.h"
|
||||
#include "renderer/pipeline/RenderPipeline.h"
|
||||
#include "renderer/pipeline/deferred/BloomStage.h"
|
||||
#include "scene/Pass.h"
|
||||
#include "scene/Shadow.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
|
||||
DeferredPipelineSceneData::DeferredPipelineSceneData() = default;
|
||||
DeferredPipelineSceneData::~DeferredPipelineSceneData() = default;
|
||||
|
||||
void DeferredPipelineSceneData::activate(gfx::Device *device) {
|
||||
PipelineSceneData::activate(device);
|
||||
initPipelinePassInfo();
|
||||
}
|
||||
|
||||
void DeferredPipelineSceneData::updatePipelineSceneData() {
|
||||
updatePipelinePassInfo();
|
||||
}
|
||||
|
||||
void DeferredPipelineSceneData::initPipelinePassInfo() {
|
||||
// builtin deferred material
|
||||
_lightingMaterial = ccnew Material();
|
||||
_lightingMaterial->setUuid("builtin-deferred-material");
|
||||
IMaterialInfo materialInfo;
|
||||
materialInfo.effectName = "pipeline/deferred-lighting";
|
||||
_lightingMaterial->initialize(materialInfo);
|
||||
for (const auto &pass : *_lightingMaterial->getPasses()) {
|
||||
pass->tryCompile();
|
||||
}
|
||||
|
||||
_bloomMaterial = ccnew Material();
|
||||
_bloomMaterial->setUuid("builtin-bloom-material");
|
||||
materialInfo.effectName = "pipeline/bloom";
|
||||
_bloomMaterial->initialize(materialInfo);
|
||||
for (const auto &pass : *_bloomMaterial->getPasses()) {
|
||||
pass->tryCompile();
|
||||
}
|
||||
|
||||
_postProcessMaterial = ccnew Material();
|
||||
_postProcessMaterial->setUuid("builtin-post-process-material");
|
||||
#if ENABLE_ANTIALIAS_FXAA > 0
|
||||
_antiAliasing = AntiAliasing::FXAA;
|
||||
#endif
|
||||
materialInfo.effectName = "pipeline/post-process";
|
||||
MacroRecord record{{"ANTIALIAS_TYPE", static_cast<int32_t>(_antiAliasing)}};
|
||||
materialInfo.defines = record;
|
||||
_postProcessMaterial->initialize(materialInfo);
|
||||
for (const auto &pass : *_postProcessMaterial->getPasses()) {
|
||||
pass->tryCompile();
|
||||
}
|
||||
|
||||
updatePipelinePassInfo();
|
||||
}
|
||||
|
||||
void DeferredPipelineSceneData::setAntiAliasing(AntiAliasing value) {
|
||||
_antiAliasing = value;
|
||||
if (_postProcessMaterial) {
|
||||
auto &defines = (*_postProcessMaterial->getPasses())[0]->getDefines();
|
||||
defines.emplace("ANTIALIAS_TYPE", static_cast<int32_t>(value));
|
||||
auto *renderMat = ccnew Material();
|
||||
IMaterialInfo materialInfo;
|
||||
materialInfo.effectAsset = _postProcessMaterial->getEffectAsset();
|
||||
materialInfo.defines = defines;
|
||||
renderMat->initialize(materialInfo);
|
||||
for (const auto &pass : *renderMat->getPasses()) {
|
||||
pass->tryCompile();
|
||||
}
|
||||
_postProcessMaterial = renderMat;
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredPipelineSceneData::updateBloomPass() {
|
||||
if (!_bloomMaterial) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto &bloomPasses = *_bloomMaterial->getPasses();
|
||||
_bloomPrefilterPass = bloomPasses[BLOOM_PREFILTERPASS_INDEX];
|
||||
_bloomPrefilterPass->beginChangeStatesSilently();
|
||||
_bloomPrefilterPass->tryCompile();
|
||||
_bloomPrefilterPass->endChangeStatesSilently();
|
||||
_bloomPrefilterPassShader = _bloomPrefilterPass->getShaderVariant();
|
||||
|
||||
for (uint32_t i = 0; i < MAX_BLOOM_FILTER_PASS_NUM; ++i) {
|
||||
scene::Pass *downsamplePass = bloomPasses[BLOOM_DOWNSAMPLEPASS_INDEX + i];
|
||||
downsamplePass->beginChangeStatesSilently();
|
||||
downsamplePass->tryCompile();
|
||||
downsamplePass->endChangeStatesSilently();
|
||||
|
||||
scene::Pass *upsamplePass = bloomPasses[BLOOM_UPSAMPLEPASS_INDEX + i];
|
||||
upsamplePass->beginChangeStatesSilently();
|
||||
upsamplePass->tryCompile();
|
||||
upsamplePass->endChangeStatesSilently();
|
||||
|
||||
_bloomUpSamplePasses.emplace_back(upsamplePass);
|
||||
_bloomDownSamplePasses.emplace_back(downsamplePass);
|
||||
}
|
||||
|
||||
_bloomCombinePass = bloomPasses[BLOOM_COMBINEPASS_INDEX];
|
||||
_bloomCombinePass->beginChangeStatesSilently();
|
||||
_bloomCombinePass->tryCompile();
|
||||
_bloomCombinePass->endChangeStatesSilently();
|
||||
_bloomCombinePassShader = _bloomCombinePass->getShaderVariant();
|
||||
|
||||
_bloomUpSamplePassShader = bloomPasses[BLOOM_UPSAMPLEPASS_INDEX]->getShaderVariant();
|
||||
_bloomDownSamplePassShader = bloomPasses[BLOOM_DOWNSAMPLEPASS_INDEX]->getShaderVariant();
|
||||
}
|
||||
|
||||
void DeferredPipelineSceneData::updatePostProcessPass() {
|
||||
if (!_postProcessMaterial) {
|
||||
return;
|
||||
}
|
||||
|
||||
_postPass = (*_postProcessMaterial->getPasses())[0];
|
||||
_postPass->beginChangeStatesSilently();
|
||||
_postPass->tryCompile();
|
||||
_postPass->endChangeStatesSilently();
|
||||
|
||||
_postPassShader = _postPass->getShaderVariant();
|
||||
}
|
||||
|
||||
void DeferredPipelineSceneData::updatePipelinePassInfo() {
|
||||
updateBloomPass();
|
||||
updatePostProcessPass();
|
||||
updateDeferredPassInfo();
|
||||
}
|
||||
|
||||
void DeferredPipelineSceneData::updateDeferredPassInfo() {
|
||||
updateDeferredLightPass();
|
||||
}
|
||||
|
||||
void DeferredPipelineSceneData::updateDeferredLightPass() {
|
||||
if (!_lightingMaterial) {
|
||||
return;
|
||||
}
|
||||
|
||||
// It's temporary solution for main light shadowmap
|
||||
if (RenderPipeline::getInstance()) {
|
||||
RenderPipeline::getInstance()->setValue("CC_RECEIVE_SHADOW", 1);
|
||||
}
|
||||
|
||||
_lightPass = (*_lightingMaterial->getPasses())[0];
|
||||
_lightPass->beginChangeStatesSilently();
|
||||
_lightPass->tryCompile();
|
||||
_lightPass->endChangeStatesSilently();
|
||||
|
||||
_lightPassShader = _lightPass->getShaderVariant();
|
||||
}
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
119
cocos/renderer/pipeline/deferred/DeferredPipelineSceneData.h
Normal file
119
cocos/renderer/pipeline/deferred/DeferredPipelineSceneData.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Ptr.h"
|
||||
#include "renderer/pipeline/PipelineSceneData.h"
|
||||
|
||||
#define BLOOM_PREFILTERPASS_INDEX 0
|
||||
#define BLOOM_DOWNSAMPLEPASS_INDEX 1
|
||||
#define BLOOM_UPSAMPLEPASS_INDEX (BLOOM_DOWNSAMPLEPASS_INDEX + 1)
|
||||
#define BLOOM_COMBINEPASS_INDEX (BLOOM_UPSAMPLEPASS_INDEX + 1)
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
|
||||
enum class AntiAliasing {
|
||||
NONE,
|
||||
FXAA
|
||||
};
|
||||
|
||||
class DeferredPipelineSceneData : public PipelineSceneData {
|
||||
public:
|
||||
DeferredPipelineSceneData();
|
||||
~DeferredPipelineSceneData() override;
|
||||
|
||||
void activate(gfx::Device *device) override;
|
||||
void updatePipelineSceneData() override;
|
||||
|
||||
void initPipelinePassInfo();
|
||||
|
||||
void setAntiAliasing(AntiAliasing value);
|
||||
inline AntiAliasing getAntiAliasing() const { return _antiAliasing; }
|
||||
|
||||
inline Material *getBloomMaterial() const { return _bloomMaterial; }
|
||||
inline void setBloomMaterial(Material *mat) {
|
||||
if (mat == _bloomMaterial.get()) {
|
||||
return;
|
||||
}
|
||||
_bloomMaterial = mat;
|
||||
updatePipelinePassInfo();
|
||||
}
|
||||
|
||||
inline Material *getPostProcessMaterial() const { return _postProcessMaterial; }
|
||||
inline void setPostProcessMaterial(Material *mat) {
|
||||
if (mat == _postProcessMaterial.get()) {
|
||||
return;
|
||||
}
|
||||
_postProcessMaterial = mat;
|
||||
updatePipelinePassInfo();
|
||||
}
|
||||
|
||||
inline void setLightingMaterial(Material *mat) { _lightingMaterial = mat; }
|
||||
inline Material *getLightingMaterial() const { return _lightingMaterial; }
|
||||
inline gfx::Shader *getLightPassShader() const { return _lightPassShader; }
|
||||
inline scene::Pass *getLightPass() const { return _lightPass; }
|
||||
inline gfx::Shader *getBloomPrefilterPassShader() const { return _bloomPrefilterPassShader; }
|
||||
inline scene::Pass *getBloomPrefilterPass() const { return _bloomPrefilterPass; }
|
||||
inline const ccstd::vector<scene::Pass *> &getBloomUpSamplePasses() const { return _bloomUpSamplePasses; }
|
||||
inline gfx::Shader *getBloomUpSamplePassShader() const { return _bloomUpSamplePassShader; }
|
||||
inline const ccstd::vector<scene::Pass *> &getBloomDownSamplePasses() const { return _bloomDownSamplePasses; }
|
||||
inline gfx::Shader *getBloomDownSamplePassShader() const { return _bloomDownSamplePassShader; }
|
||||
inline scene::Pass *getBloomCombinePass() const { return _bloomCombinePass; }
|
||||
inline gfx::Shader *getBloomCombinePassShader() const { return _bloomCombinePassShader; }
|
||||
|
||||
inline gfx::Shader *getPostPassShader() const { return _postPassShader; }
|
||||
inline scene::Pass *getPostPass() const { return _postPass; }
|
||||
|
||||
private:
|
||||
void updateBloomPass();
|
||||
void updatePostProcessPass();
|
||||
void updatePipelinePassInfo();
|
||||
void updateDeferredPassInfo();
|
||||
void updateDeferredLightPass();
|
||||
|
||||
IntrusivePtr<Material> _postProcessMaterial;
|
||||
gfx::Shader *_postPassShader{nullptr}; // weak reference
|
||||
scene::Pass *_postPass{nullptr}; // weak reference
|
||||
|
||||
IntrusivePtr<Material> _lightingMaterial;
|
||||
gfx::Shader *_lightPassShader{nullptr}; // weak reference
|
||||
scene::Pass *_lightPass{nullptr}; // weak reference
|
||||
|
||||
IntrusivePtr<Material> _bloomMaterial;
|
||||
scene::Pass *_bloomPrefilterPass{nullptr}; // weak reference
|
||||
gfx::Shader *_bloomPrefilterPassShader{nullptr}; // weak reference
|
||||
scene::Pass *_bloomCombinePass{nullptr}; // weak reference
|
||||
gfx::Shader *_bloomCombinePassShader{nullptr}; // weak reference
|
||||
ccstd::vector<scene::Pass *> _bloomUpSamplePasses; // weak reference
|
||||
gfx::Shader *_bloomUpSamplePassShader{nullptr}; // weak reference
|
||||
ccstd::vector<scene::Pass *> _bloomDownSamplePasses; // weak reference
|
||||
gfx::Shader *_bloomDownSamplePassShader{nullptr}; // weak reference
|
||||
|
||||
AntiAliasing _antiAliasing{AntiAliasing::NONE};
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
235
cocos/renderer/pipeline/deferred/GbufferStage.cpp
Normal file
235
cocos/renderer/pipeline/deferred/GbufferStage.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "GbufferStage.h"
|
||||
#include "../InstancedBuffer.h"
|
||||
#include "../PipelineSceneData.h"
|
||||
#include "../PipelineUBO.h"
|
||||
#include "../PlanarShadowQueue.h"
|
||||
#include "../RenderInstancedQueue.h"
|
||||
#include "../RenderQueue.h"
|
||||
#include "DeferredPipeline.h"
|
||||
#include "MainFlow.h"
|
||||
#include "frame-graph/DevicePass.h"
|
||||
#include "frame-graph/DevicePassResourceTable.h"
|
||||
#include "frame-graph/Resource.h"
|
||||
#include "gfx-base/GFXDevice.h"
|
||||
#include "profiler/Profiler.h"
|
||||
#include "scene/Camera.h"
|
||||
#include "scene/Model.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
RenderStageInfo GbufferStage::initInfo = {
|
||||
"GbufferStage",
|
||||
static_cast<uint32_t>(DeferredStagePriority::GBUFFER),
|
||||
static_cast<uint32_t>(RenderFlowTag::SCENE),
|
||||
{ccnew RenderQueueDesc{false, RenderQueueSortMode::FRONT_TO_BACK, {"default"}},
|
||||
ccnew RenderQueueDesc{true, RenderQueueSortMode::BACK_TO_FRONT, {"default", "planarShadow"}}}};
|
||||
const RenderStageInfo &GbufferStage::getInitializeInfo() { return GbufferStage::initInfo; }
|
||||
|
||||
GbufferStage::GbufferStage() {
|
||||
_instancedQueue = ccnew RenderInstancedQueue;
|
||||
}
|
||||
|
||||
GbufferStage::~GbufferStage() = default;
|
||||
|
||||
bool GbufferStage::initialize(const RenderStageInfo &info) {
|
||||
RenderStage::initialize(info);
|
||||
_renderQueueDescriptors = info.renderQueues;
|
||||
_phaseID = getPhaseID("default");
|
||||
return true;
|
||||
}
|
||||
|
||||
void GbufferStage::activate(RenderPipeline *pipeline, RenderFlow *flow) {
|
||||
RenderStage::activate(pipeline, flow);
|
||||
|
||||
for (const auto &descriptor : _renderQueueDescriptors) {
|
||||
uint32_t phase = convertPhase(descriptor->stages);
|
||||
RenderQueueSortFunc sortFunc = convertQueueSortFunc(descriptor->sortMode);
|
||||
RenderQueueCreateInfo info = {descriptor->isTransparent, phase, sortFunc};
|
||||
_renderQueues.emplace_back(ccnew RenderQueue(_pipeline, std::move(info), true));
|
||||
}
|
||||
_planarShadowQueue = ccnew PlanarShadowQueue(_pipeline);
|
||||
}
|
||||
|
||||
void GbufferStage::destroy() {
|
||||
CC_SAFE_DELETE(_instancedQueue);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_planarShadowQueue);
|
||||
RenderStage::destroy();
|
||||
}
|
||||
|
||||
void GbufferStage::dispenseRenderObject2Queues() {
|
||||
_instancedQueue->clear();
|
||||
|
||||
const auto &renderObjects = _pipeline->getPipelineSceneData()->getRenderObjects();
|
||||
for (auto *queue : _renderQueues) {
|
||||
queue->clear();
|
||||
}
|
||||
|
||||
uint32_t subModelIdx = 0;
|
||||
uint32_t passIdx = 0;
|
||||
size_t k = 0;
|
||||
for (auto ro : renderObjects) {
|
||||
const auto *const model = ro.model;
|
||||
const auto &subModels = model->getSubModels();
|
||||
const auto subModelCount = subModels.size();
|
||||
for (subModelIdx = 0; subModelIdx < subModelCount; ++subModelIdx) {
|
||||
const auto &subModel = subModels[subModelIdx];
|
||||
const auto &passes = *(subModel->getPasses());
|
||||
const auto passCount = passes.size();
|
||||
for (passIdx = 0; passIdx < passCount; ++passIdx) {
|
||||
const auto &pass = passes[passIdx];
|
||||
if (pass->getPhase() != _phaseID) continue;
|
||||
if (pass->getBatchingScheme() == scene::BatchingSchemes::INSTANCING) {
|
||||
auto *instancedBuffer = pass->getInstancedBuffer();
|
||||
instancedBuffer->merge(subModel, passIdx);
|
||||
_instancedQueue->add(instancedBuffer);
|
||||
} else {
|
||||
for (k = 0; k < _renderQueues.size(); k++) {
|
||||
_renderQueues[k]->insertRenderPass(ro, subModelIdx, passIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto *queue : _renderQueues) {
|
||||
queue->sort();
|
||||
}
|
||||
}
|
||||
void GbufferStage::recordCommands(DeferredPipeline *pipeline, scene::Camera *camera, gfx::RenderPass *renderPass) {
|
||||
auto *cmdBuff = pipeline->getCommandBuffers()[0];
|
||||
|
||||
// DescriptorSet bindings
|
||||
const ccstd::array<uint32_t, 1> globalOffsets = {_pipeline->getPipelineUBO()->getCurrentCameraUBOOffset()};
|
||||
cmdBuff->bindDescriptorSet(globalSet, pipeline->getDescriptorSet(), utils::toUint(globalOffsets.size()), globalOffsets.data());
|
||||
|
||||
// record commands
|
||||
_renderQueues[0]->recordCommandBuffer(_device, camera, renderPass, cmdBuff);
|
||||
_instancedQueue->recordCommandBuffer(_device, renderPass, cmdBuff);
|
||||
}
|
||||
|
||||
void GbufferStage::render(scene::Camera *camera) {
|
||||
CC_PROFILE(GbufferStageRender);
|
||||
struct RenderData {
|
||||
framegraph::TextureHandle gbuffer[4];
|
||||
framegraph::TextureHandle depth;
|
||||
};
|
||||
|
||||
auto *pipeline = static_cast<DeferredPipeline *>(_pipeline);
|
||||
float shadingScale{_pipeline->getPipelineSceneData()->getShadingScale()};
|
||||
_renderArea = RenderPipeline::getRenderArea(camera);
|
||||
|
||||
auto gbufferSetup = [&](framegraph::PassNodeBuilder &builder, RenderData &data) {
|
||||
builder.subpass();
|
||||
|
||||
// gbuffer setup
|
||||
gfx::TextureInfo gbufferInfo = {
|
||||
gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::COLOR_ATTACHMENT | gfx::TextureUsageBit::INPUT_ATTACHMENT,
|
||||
gfx::Format::RGBA8,
|
||||
static_cast<uint32_t>(static_cast<float>(pipeline->getWidth()) * shadingScale),
|
||||
static_cast<uint32_t>(static_cast<float>(pipeline->getHeight()) * shadingScale),
|
||||
};
|
||||
gfx::TextureInfo gbufferInfoFloat = {
|
||||
gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::COLOR_ATTACHMENT | gfx::TextureUsageBit::INPUT_ATTACHMENT,
|
||||
gfx::Format::RGBA16F,
|
||||
static_cast<uint32_t>(static_cast<float>(pipeline->getWidth()) * shadingScale),
|
||||
static_cast<uint32_t>(static_cast<float>(pipeline->getHeight()) * shadingScale),
|
||||
};
|
||||
for (int i = 0; i < DeferredPipeline::GBUFFER_COUNT - 1; ++i) {
|
||||
if (i != 0) { // normals need more precision
|
||||
data.gbuffer[i] = builder.create(DeferredPipeline::fgStrHandleGbufferTexture[i], gbufferInfoFloat);
|
||||
} else {
|
||||
data.gbuffer[i] = builder.create(DeferredPipeline::fgStrHandleGbufferTexture[i], gbufferInfo);
|
||||
}
|
||||
}
|
||||
|
||||
auto subpassEnabled = _device->hasFeature(gfx::Feature::INPUT_ATTACHMENT_BENEFIT);
|
||||
if (subpassEnabled) {
|
||||
// when subpass enabled, the color result (gles2/gles3) will write to gbuffer[2] and the blit to color texture, so the format should be RGBA16F
|
||||
data.gbuffer[2] = builder.create(DeferredPipeline::fgStrHandleGbufferTexture[2], gbufferInfoFloat);
|
||||
} else {
|
||||
data.gbuffer[2] = builder.create(DeferredPipeline::fgStrHandleGbufferTexture[2], gbufferInfo);
|
||||
}
|
||||
|
||||
gfx::Color clearColor{0.0, 0.0, 0.0, 0.0};
|
||||
|
||||
framegraph::RenderTargetAttachment::Descriptor colorInfo;
|
||||
colorInfo.usage = framegraph::RenderTargetAttachment::Usage::COLOR;
|
||||
colorInfo.loadOp = gfx::LoadOp::CLEAR;
|
||||
colorInfo.clearColor = clearColor;
|
||||
colorInfo.beginAccesses = gfx::AccessFlagBit::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT;
|
||||
colorInfo.endAccesses = gfx::AccessFlagBit::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT;
|
||||
for (int i = 0; i < DeferredPipeline::GBUFFER_COUNT; ++i) {
|
||||
data.gbuffer[i] = builder.write(data.gbuffer[i], colorInfo);
|
||||
builder.writeToBlackboard(DeferredPipeline::fgStrHandleGbufferTexture[i], data.gbuffer[i]);
|
||||
}
|
||||
|
||||
// depth setup
|
||||
gfx::TextureInfo depthTexInfo = {
|
||||
gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::DEPTH_STENCIL_ATTACHMENT | gfx::TextureUsageBit::SAMPLED,
|
||||
gfx::Format::DEPTH_STENCIL,
|
||||
static_cast<uint32_t>(static_cast<float>(pipeline->getWidth()) * shadingScale),
|
||||
static_cast<uint32_t>(static_cast<float>(pipeline->getHeight()) * shadingScale),
|
||||
};
|
||||
|
||||
depthTexInfo.usage |= gfx::TextureUsageBit::INPUT_ATTACHMENT;
|
||||
|
||||
data.depth = builder.create(DeferredPipeline::fgStrHandleOutDepthTexture, depthTexInfo);
|
||||
|
||||
framegraph::RenderTargetAttachment::Descriptor depthInfo;
|
||||
depthInfo.usage = framegraph::RenderTargetAttachment::Usage::DEPTH_STENCIL;
|
||||
depthInfo.loadOp = gfx::LoadOp::CLEAR;
|
||||
depthInfo.clearDepth = camera->getClearDepth();
|
||||
depthInfo.clearStencil = camera->getClearStencil();
|
||||
depthInfo.endAccesses = gfx::AccessFlagBit::DEPTH_STENCIL_ATTACHMENT_WRITE;
|
||||
data.depth = builder.write(data.depth, depthInfo);
|
||||
builder.writeToBlackboard(DeferredPipeline::fgStrHandleOutDepthTexture, data.depth);
|
||||
|
||||
// viewport setup
|
||||
builder.setViewport(pipeline->getViewport(camera), pipeline->getScissor(camera));
|
||||
};
|
||||
|
||||
auto gbufferExec = [this, camera](const RenderData & /*data*/, const framegraph::DevicePassResourceTable &table) {
|
||||
recordCommands(static_cast<DeferredPipeline *>(_pipeline), camera, table.getRenderPass());
|
||||
};
|
||||
|
||||
// Command 'updateBuffer' must be recorded outside render passes, cannot put them in execute lambda
|
||||
dispenseRenderObject2Queues();
|
||||
auto *cmdBuff = pipeline->getCommandBuffers()[0];
|
||||
_instancedQueue->uploadBuffers(cmdBuff);
|
||||
|
||||
// if empty == true, gbuffer and lightig passes will be ignored
|
||||
bool empty = _renderQueues[0]->empty() && _instancedQueue->empty();
|
||||
if (!empty) {
|
||||
pipeline->getFrameGraph().addPass<RenderData>(static_cast<uint32_t>(DeferredInsertPoint::DIP_GBUFFER), DeferredPipeline::fgStrHandleGbufferPass, gbufferSetup, gbufferExec);
|
||||
}
|
||||
}
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
67
cocos/renderer/pipeline/deferred/GbufferStage.h
Normal file
67
cocos/renderer/pipeline/deferred/GbufferStage.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pipeline/RenderStage.h"
|
||||
|
||||
namespace cc {
|
||||
namespace scene {
|
||||
class Camera;
|
||||
}
|
||||
namespace pipeline {
|
||||
|
||||
class RenderFlow;
|
||||
class RenderInstancedQueue;
|
||||
class RenderAdditiveLightQueue;
|
||||
class PlanarShadowQueue;
|
||||
struct DeferredRenderData;
|
||||
class DeferredPipeline;
|
||||
struct RenderPass;
|
||||
|
||||
class CC_DLL GbufferStage : public RenderStage {
|
||||
public:
|
||||
static const RenderStageInfo &getInitializeInfo();
|
||||
|
||||
GbufferStage();
|
||||
~GbufferStage() override;
|
||||
|
||||
bool initialize(const RenderStageInfo &info) override;
|
||||
void activate(RenderPipeline *pipeline, RenderFlow *flow) override;
|
||||
void destroy() override;
|
||||
void render(scene::Camera *camera) override;
|
||||
|
||||
private:
|
||||
void dispenseRenderObject2Queues();
|
||||
void recordCommands(DeferredPipeline *pipeline, scene::Camera *camera, gfx::RenderPass *renderPass);
|
||||
|
||||
static RenderStageInfo initInfo;
|
||||
PlanarShadowQueue *_planarShadowQueue = nullptr;
|
||||
RenderInstancedQueue *_instancedQueue = nullptr;
|
||||
uint32_t _phaseID = 0;
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
1019
cocos/renderer/pipeline/deferred/LightingStage.cpp
Normal file
1019
cocos/renderer/pipeline/deferred/LightingStage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
101
cocos/renderer/pipeline/deferred/LightingStage.h
Normal file
101
cocos/renderer/pipeline/deferred/LightingStage.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../RenderStage.h"
|
||||
#include "ReflectionComp.h"
|
||||
#include "scene/Camera.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
|
||||
class RenderFlow;
|
||||
class RenderInstancedQueue;
|
||||
class RenderAdditiveLightQueue;
|
||||
class PlanarShadowQueue;
|
||||
struct DeferredRenderData;
|
||||
class DeferredPipeline;
|
||||
|
||||
struct RenderElem {
|
||||
RenderObject renderObject;
|
||||
gfx::DescriptorSet *set;
|
||||
uint32_t modelIndex;
|
||||
uint32_t passIndex;
|
||||
};
|
||||
|
||||
class CC_DLL LightingStage : public RenderStage {
|
||||
public:
|
||||
static const RenderStageInfo &getInitializeInfo();
|
||||
|
||||
LightingStage();
|
||||
~LightingStage() override;
|
||||
|
||||
bool initialize(const RenderStageInfo &info) override;
|
||||
void activate(RenderPipeline *pipeline, RenderFlow *flow) override;
|
||||
void destroy() override;
|
||||
void render(scene::Camera *camera) override;
|
||||
|
||||
private:
|
||||
void gatherLights(scene::Camera *camera);
|
||||
void initLightingBuffer();
|
||||
void fgLightingPass(scene::Camera *camera);
|
||||
void fgTransparent(scene::Camera *camera);
|
||||
void fgSsprPass(scene::Camera *camera);
|
||||
|
||||
void putTransparentObj2Queue();
|
||||
|
||||
static RenderStageInfo initInfo;
|
||||
PlanarShadowQueue *_planarShadowQueue{nullptr};
|
||||
uint32_t _phaseID{0};
|
||||
|
||||
gfx::Buffer *_deferredLitsBufs{nullptr};
|
||||
gfx::Buffer *_deferredLitsBufView{nullptr};
|
||||
ccstd::vector<float> _lightBufferData;
|
||||
uint32_t _lightBufferStride{0};
|
||||
uint32_t _lightBufferElementCount{0};
|
||||
bool _isTransparentQueueEmpty{true};
|
||||
float _lightMeterScale{10000.0};
|
||||
gfx::DescriptorSet *_descriptorSet{nullptr};
|
||||
gfx::DescriptorSetLayout *_descLayout{nullptr};
|
||||
uint32_t _maxDeferredLights{UBODeferredLight::LIGHTS_PER_PASS};
|
||||
|
||||
ReflectionComp *_reflectionComp{nullptr};
|
||||
RenderQueue *_reflectionRenderQueue{nullptr};
|
||||
uint32_t _reflectionPhaseID{0};
|
||||
|
||||
ccstd::vector<RenderElem> _reflectionElems;
|
||||
uint32_t _denoiseIndex = 0; // use to get corrrect texture string handle
|
||||
|
||||
gfx::Sampler *_defaultSampler{nullptr};
|
||||
|
||||
// SSPR texture size
|
||||
uint32_t _ssprTexWidth = 0;
|
||||
uint32_t _ssprTexHeight = 0;
|
||||
Mat4 _matViewProj;
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
86
cocos/renderer/pipeline/deferred/MainFlow.cpp
Normal file
86
cocos/renderer/pipeline/deferred/MainFlow.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "MainFlow.h"
|
||||
#include "BloomStage.h"
|
||||
#include "DeferredPipeline.h"
|
||||
#include "GbufferStage.h"
|
||||
#include "LightingStage.h"
|
||||
#include "PostProcessStage.h"
|
||||
#include "gfx-base/GFXDescriptorSet.h"
|
||||
#include "gfx-base/GFXDevice.h"
|
||||
#include "pipeline/SceneCulling.h"
|
||||
#include "profiler/Profiler.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
RenderFlowInfo MainFlow::initInfo = {
|
||||
"MainFlow",
|
||||
static_cast<uint32_t>(DeferredFlowPriority::MAIN),
|
||||
static_cast<uint32_t>(RenderFlowTag::SCENE),
|
||||
{},
|
||||
};
|
||||
const RenderFlowInfo &MainFlow::getInitializeInfo() { return MainFlow::initInfo; }
|
||||
|
||||
MainFlow::~MainFlow() = default;
|
||||
|
||||
bool MainFlow::initialize(const RenderFlowInfo &info) {
|
||||
RenderFlow::initialize(info);
|
||||
|
||||
if (_stages.empty()) {
|
||||
_isResourceOwner = true;
|
||||
|
||||
auto *gbufferStage = ccnew GbufferStage;
|
||||
gbufferStage->initialize(GbufferStage::getInitializeInfo());
|
||||
_stages.emplace_back(gbufferStage);
|
||||
auto *lightingStage = ccnew LightingStage;
|
||||
lightingStage->initialize(LightingStage::getInitializeInfo());
|
||||
_stages.emplace_back(lightingStage);
|
||||
auto *bloomStage = ccnew BloomStage;
|
||||
bloomStage->initialize(BloomStage::getInitializeInfo());
|
||||
_stages.emplace_back(bloomStage);
|
||||
auto *postProcessStage = ccnew PostProcessStage;
|
||||
postProcessStage->initialize(PostProcessStage::getInitializeInfo());
|
||||
_stages.emplace_back(postProcessStage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainFlow::activate(RenderPipeline *pipeline) {
|
||||
RenderFlow::activate(pipeline);
|
||||
}
|
||||
|
||||
void MainFlow::render(scene::Camera *camera) {
|
||||
CC_PROFILE(MainFlowRender);
|
||||
RenderFlow::render(camera);
|
||||
}
|
||||
|
||||
void MainFlow::destroy() {
|
||||
RenderFlow::destroy();
|
||||
}
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
52
cocos/renderer/pipeline/deferred/MainFlow.h
Normal file
52
cocos/renderer/pipeline/deferred/MainFlow.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../RenderFlow.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
|
||||
class GbufferStage;
|
||||
|
||||
class CC_DLL MainFlow : public RenderFlow {
|
||||
public:
|
||||
static const RenderFlowInfo &getInitializeInfo();
|
||||
|
||||
MainFlow() = default;
|
||||
~MainFlow() override;
|
||||
|
||||
bool initialize(const RenderFlowInfo &info) override;
|
||||
void activate(RenderPipeline *pipeline) override;
|
||||
void destroy() override;
|
||||
void render(scene::Camera *camera) override;
|
||||
|
||||
private:
|
||||
static RenderFlowInfo initInfo;
|
||||
};
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
241
cocos/renderer/pipeline/deferred/PostProcessStage.cpp
Normal file
241
cocos/renderer/pipeline/deferred/PostProcessStage.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "PostProcessStage.h"
|
||||
#include "frame-graph/DevicePass.h"
|
||||
#include "frame-graph/PassNodeBuilder.h"
|
||||
#include "frame-graph/Resource.h"
|
||||
#include "gfx-base/GFXDevice.h"
|
||||
#include "pipeline/Define.h"
|
||||
#include "pipeline/UIPhase.h"
|
||||
#include "pipeline/helper/Utils.h"
|
||||
#include "profiler/Profiler.h"
|
||||
#include "renderer/pipeline/GlobalDescriptorSetManager.h"
|
||||
#include "renderer/pipeline/PipelineStateManager.h"
|
||||
#include "renderer/pipeline/PipelineUBO.h"
|
||||
#include "renderer/pipeline/RenderPipeline.h"
|
||||
#include "renderer/pipeline/RenderQueue.h"
|
||||
#include "renderer/pipeline/UIPhase.h"
|
||||
#include "renderer/pipeline/deferred/DeferredPipelineSceneData.h"
|
||||
#include "scene/Camera.h"
|
||||
#include "scene/Pass.h"
|
||||
#include "scene/RenderWindow.h"
|
||||
#include "scene/SubModel.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
namespace {
|
||||
const ccstd::string STAGE_NAME = "PostProcessStage";
|
||||
}
|
||||
|
||||
RenderStageInfo PostProcessStage::initInfo = {
|
||||
STAGE_NAME,
|
||||
static_cast<uint32_t>(DeferredStagePriority::POSTPROCESS),
|
||||
0,
|
||||
{ccnew RenderQueueDesc{true, RenderQueueSortMode::BACK_TO_FRONT, {"default"}}},
|
||||
};
|
||||
const RenderStageInfo &PostProcessStage::getInitializeInfo() { return PostProcessStage::initInfo; }
|
||||
|
||||
PostProcessStage::PostProcessStage() {
|
||||
_uiPhase = ccnew UIPhase;
|
||||
}
|
||||
|
||||
bool PostProcessStage::initialize(const RenderStageInfo &info) {
|
||||
RenderStage::initialize(info);
|
||||
_renderQueueDescriptors = info.renderQueues;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PostProcessStage::activate(RenderPipeline *pipeline, RenderFlow *flow) {
|
||||
RenderStage::activate(pipeline, flow);
|
||||
_uiPhase->activate(pipeline);
|
||||
_phaseID = getPhaseID("default");
|
||||
|
||||
for (const auto &descriptor : _renderQueueDescriptors) {
|
||||
uint32_t phase = 0;
|
||||
for (const auto &stage : descriptor->stages) {
|
||||
phase |= getPhaseID(stage);
|
||||
}
|
||||
|
||||
std::function<int(const RenderPass &, const RenderPass &)> sortFunc = opaqueCompareFn;
|
||||
switch (descriptor->sortMode) {
|
||||
case RenderQueueSortMode::BACK_TO_FRONT:
|
||||
sortFunc = transparentCompareFn;
|
||||
break;
|
||||
case RenderQueueSortMode::FRONT_TO_BACK:
|
||||
sortFunc = opaqueCompareFn;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
RenderQueueCreateInfo info = {descriptor->isTransparent, phase, sortFunc};
|
||||
_renderQueues.emplace_back(ccnew RenderQueue(_pipeline, std::move(info)));
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessStage::destroy() {
|
||||
CC_SAFE_DELETE(_uiPhase);
|
||||
}
|
||||
|
||||
void PostProcessStage::render(scene::Camera *camera) {
|
||||
CC_PROFILE(PostProcessStageRender);
|
||||
static framegraph::StringHandle fgStrHandlePostProcessOutTexture = framegraph::FrameGraph::stringToHandle("postProcessOutputTexture");
|
||||
struct RenderData {
|
||||
framegraph::TextureHandle outColorTex; // read from lighting output
|
||||
framegraph::TextureHandle backBuffer; // write to back buffer
|
||||
framegraph::TextureHandle depth;
|
||||
};
|
||||
|
||||
if (hasFlag(static_cast<gfx::ClearFlags>(camera->getClearFlag()), gfx::ClearFlagBit::COLOR)) {
|
||||
_clearColors[0].x = camera->getClearColor().x;
|
||||
_clearColors[0].y = camera->getClearColor().y;
|
||||
_clearColors[0].z = camera->getClearColor().z;
|
||||
}
|
||||
_clearColors[0].w = camera->getClearColor().w;
|
||||
_renderArea = RenderPipeline::getRenderArea(camera);
|
||||
_inputAssembler = _pipeline->getIAByRenderArea(_renderArea);
|
||||
auto *pipeline = _pipeline;
|
||||
float shadingScale{_pipeline->getPipelineSceneData()->getShadingScale()};
|
||||
auto postSetup = [&](framegraph::PassNodeBuilder &builder, RenderData &data) {
|
||||
if (pipeline->isBloomEnabled()) {
|
||||
data.outColorTex = framegraph::TextureHandle(builder.readFromBlackboard(RenderPipeline::fgStrHandleBloomOutTexture));
|
||||
} else {
|
||||
data.outColorTex = framegraph::TextureHandle(builder.readFromBlackboard(RenderPipeline::fgStrHandleOutColorTexture));
|
||||
}
|
||||
|
||||
if (!data.outColorTex.isValid()) {
|
||||
framegraph::Texture::Descriptor colorTexInfo;
|
||||
colorTexInfo.format = gfx::Format::RGBA16F;
|
||||
colorTexInfo.usage = gfx::TextureUsageBit::COLOR_ATTACHMENT | gfx::TextureUsageBit::SAMPLED;
|
||||
colorTexInfo.width = static_cast<uint32_t>(static_cast<float>(pipeline->getWidth()) * shadingScale);
|
||||
colorTexInfo.height = static_cast<uint32_t>(static_cast<float>(pipeline->getHeight()) * shadingScale);
|
||||
|
||||
data.outColorTex = builder.create(RenderPipeline::fgStrHandleOutColorTexture, colorTexInfo);
|
||||
}
|
||||
|
||||
data.outColorTex = builder.read(data.outColorTex);
|
||||
builder.writeToBlackboard(RenderPipeline::fgStrHandleOutColorTexture, data.outColorTex);
|
||||
|
||||
framegraph::RenderTargetAttachment::Descriptor colorAttachmentInfo;
|
||||
colorAttachmentInfo.usage = framegraph::RenderTargetAttachment::Usage::COLOR;
|
||||
colorAttachmentInfo.clearColor = _clearColors[0];
|
||||
colorAttachmentInfo.loadOp = gfx::LoadOp::CLEAR;
|
||||
|
||||
auto clearFlags = static_cast<gfx::ClearFlagBit>(camera->getClearFlag());
|
||||
if (!hasFlag(clearFlags, gfx::ClearFlagBit::COLOR)) {
|
||||
if (hasFlag(clearFlags, static_cast<gfx::ClearFlagBit>(skyboxFlag))) {
|
||||
colorAttachmentInfo.loadOp = gfx::LoadOp::DISCARD;
|
||||
} else {
|
||||
colorAttachmentInfo.loadOp = gfx::LoadOp::LOAD;
|
||||
}
|
||||
}
|
||||
|
||||
colorAttachmentInfo.beginAccesses = colorAttachmentInfo.endAccesses =
|
||||
camera->getWindow()->getSwapchain()
|
||||
? gfx::AccessFlagBit::COLOR_ATTACHMENT_WRITE
|
||||
: gfx::AccessFlagBit::FRAGMENT_SHADER_READ_TEXTURE;
|
||||
|
||||
gfx::TextureInfo textureInfo = {
|
||||
gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::COLOR_ATTACHMENT,
|
||||
gfx::Format::RGBA8,
|
||||
static_cast<uint32_t>(static_cast<float>(camera->getWindow()->getWidth()) * shadingScale),
|
||||
static_cast<uint32_t>(static_cast<float>(camera->getWindow()->getHeight()) * shadingScale),
|
||||
};
|
||||
if (shadingScale != 1.F) {
|
||||
textureInfo.usage |= gfx::TextureUsageBit::TRANSFER_SRC;
|
||||
}
|
||||
data.backBuffer = builder.create(fgStrHandlePostProcessOutTexture, textureInfo);
|
||||
data.backBuffer = builder.write(data.backBuffer, colorAttachmentInfo);
|
||||
builder.writeToBlackboard(fgStrHandlePostProcessOutTexture, data.backBuffer);
|
||||
|
||||
// depth
|
||||
framegraph::RenderTargetAttachment::Descriptor depthAttachmentInfo;
|
||||
depthAttachmentInfo.usage = framegraph::RenderTargetAttachment::Usage::DEPTH_STENCIL;
|
||||
depthAttachmentInfo.loadOp = gfx::LoadOp::CLEAR;
|
||||
depthAttachmentInfo.beginAccesses = depthAttachmentInfo.endAccesses = gfx::AccessFlagBit::DEPTH_STENCIL_ATTACHMENT_WRITE;
|
||||
|
||||
data.depth = framegraph::TextureHandle(builder.readFromBlackboard(RenderPipeline::fgStrHandleOutDepthTexture));
|
||||
if (!data.depth.isValid()) {
|
||||
gfx::TextureInfo depthTexInfo{
|
||||
gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::DEPTH_STENCIL_ATTACHMENT,
|
||||
gfx::Format::DEPTH_STENCIL,
|
||||
static_cast<uint32_t>(static_cast<float>(pipeline->getWidth()) * shadingScale),
|
||||
static_cast<uint32_t>(static_cast<float>(pipeline->getHeight()) * shadingScale),
|
||||
};
|
||||
data.depth = builder.create(RenderPipeline::fgStrHandleOutDepthTexture, depthTexInfo);
|
||||
}
|
||||
data.depth = builder.write(data.depth, depthAttachmentInfo);
|
||||
builder.writeToBlackboard(RenderPipeline::fgStrHandleOutDepthTexture, data.depth);
|
||||
|
||||
builder.setViewport(pipeline->getViewport(camera), pipeline->getScissor(camera));
|
||||
};
|
||||
|
||||
auto postExec = [this, camera](RenderData const &data, const framegraph::DevicePassResourceTable &table) {
|
||||
auto *pipeline = _pipeline;
|
||||
gfx::RenderPass *renderPass = table.getRenderPass();
|
||||
|
||||
auto *cmdBuff = pipeline->getCommandBuffers()[0];
|
||||
const ccstd::array<uint32_t, 1> globalOffsets = {_pipeline->getPipelineUBO()->getCurrentCameraUBOOffset()};
|
||||
cmdBuff->bindDescriptorSet(globalSet, pipeline->getDescriptorSet(), utils::toUint(globalOffsets.size()), globalOffsets.data());
|
||||
|
||||
if (!pipeline->getPipelineSceneData()->getRenderObjects().empty()) {
|
||||
// post process
|
||||
auto *const sceneData = static_cast<DeferredPipelineSceneData *>(pipeline->getPipelineSceneData());
|
||||
scene::Pass *pv = sceneData->getPostPass();
|
||||
gfx::Shader *sd = sceneData->getPostPassShader();
|
||||
float shadingScale{sceneData->getShadingScale()};
|
||||
// get pso and draw quad
|
||||
gfx::PipelineState *pso = PipelineStateManager::getOrCreatePipelineState(pv, sd, _inputAssembler, renderPass);
|
||||
pipeline::GlobalDSManager *globalDS = pipeline->getGlobalDSManager();
|
||||
gfx::Sampler *sampler = shadingScale < 1.F ? globalDS->getPointSampler() : globalDS->getLinearSampler();
|
||||
|
||||
pv->getDescriptorSet()->bindTexture(0, table.getRead(data.outColorTex));
|
||||
pv->getDescriptorSet()->bindSampler(0, sampler);
|
||||
pv->getDescriptorSet()->update();
|
||||
|
||||
cmdBuff->bindPipelineState(pso);
|
||||
cmdBuff->bindDescriptorSet(materialSet, pv->getDescriptorSet());
|
||||
cmdBuff->bindInputAssembler(_inputAssembler);
|
||||
cmdBuff->draw(_inputAssembler);
|
||||
}
|
||||
|
||||
_uiPhase->render(camera, renderPass);
|
||||
renderProfiler(renderPass, cmdBuff, pipeline->getProfiler(), camera);
|
||||
#if CC_USE_DEBUG_RENDERER
|
||||
renderDebugRenderer(renderPass, cmdBuff, pipeline->getPipelineSceneData(), camera);
|
||||
#endif
|
||||
};
|
||||
|
||||
// add pass
|
||||
pipeline->getFrameGraph().addPass<RenderData>(static_cast<uint32_t>(CommonInsertPoint::DIP_POSTPROCESS), RenderPipeline::fgStrHandlePostprocessPass, postSetup, postExec);
|
||||
pipeline->getFrameGraph().presentFromBlackboard(fgStrHandlePostProcessOutTexture, camera->getWindow()->getFramebuffer()->getColorTextures()[0], shadingScale == 1.F);
|
||||
}
|
||||
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
55
cocos/renderer/pipeline/deferred/PostProcessStage.h
Normal file
55
cocos/renderer/pipeline/deferred/PostProcessStage.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../RenderStage.h"
|
||||
#include "frame-graph/Handle.h"
|
||||
#include "pipeline/Enum.h"
|
||||
|
||||
namespace cc {
|
||||
namespace pipeline {
|
||||
|
||||
class UIPhase;
|
||||
|
||||
class CC_DLL PostProcessStage : public RenderStage {
|
||||
public:
|
||||
PostProcessStage();
|
||||
~PostProcessStage() override = default;
|
||||
|
||||
static const RenderStageInfo &getInitializeInfo();
|
||||
bool initialize(const RenderStageInfo &info) override;
|
||||
void activate(RenderPipeline *pipeline, RenderFlow *flow) override;
|
||||
void destroy() override;
|
||||
void render(scene::Camera *camera) override;
|
||||
|
||||
private:
|
||||
UIPhase *_uiPhase = nullptr;
|
||||
uint32_t _phaseID = 0;
|
||||
|
||||
static RenderStageInfo initInfo;
|
||||
};
|
||||
} // namespace pipeline
|
||||
} // namespace cc
|
||||
593
cocos/renderer/pipeline/deferred/ReflectionComp.cpp
Normal file
593
cocos/renderer/pipeline/deferred/ReflectionComp.cpp
Normal file
@@ -0,0 +1,593 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ReflectionComp.h"
|
||||
#include "../Define.h"
|
||||
#include "base/Log.h"
|
||||
#include "base/StringUtil.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
ReflectionComp::~ReflectionComp() {
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compShader[0]);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compShader[1]);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compDescriptorSetLayout);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compPipelineLayout);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compPipelineState[0]);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compPipelineState[1]);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compDescriptorSet);
|
||||
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compDenoiseShader[0]);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compDenoiseShader[1]);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compDenoiseDescriptorSetLayout);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compDenoisePipelineLayout);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compDenoisePipelineState[0]);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compDenoisePipelineState[1]);
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compDenoiseDescriptorSet);
|
||||
|
||||
CC_SAFE_DESTROY_AND_DELETE(_localDescriptorSetLayout);
|
||||
|
||||
CC_SAFE_DESTROY_AND_DELETE(_compConstantsBuffer);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ConstantBuffer {
|
||||
Mat4 matView;
|
||||
Mat4 matProjInv;
|
||||
Mat4 matViewProj;
|
||||
Mat4 matViewProjInv;
|
||||
Vec4 viewPort; // viewport of lighting pass
|
||||
Vec2 texSize; // texture size of reflect texture
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void ReflectionComp::applyTexSize(uint32_t width, uint32_t height, const Mat4 &matView,
|
||||
const Mat4 &matViewProj, const Mat4 &matViewProjInv,
|
||||
const Mat4 &matProjInv, const Vec4 &viewPort) {
|
||||
uint32_t globalWidth = width;
|
||||
uint32_t globalHeight = height;
|
||||
uint32_t groupWidth = this->getGroupSizeX();
|
||||
uint32_t groupHeight = this->getGroupSizeY();
|
||||
|
||||
_dispatchInfo = {(globalWidth - 1) / groupWidth + 1, (globalHeight - 1) / groupHeight + 1, 1};
|
||||
_denoiseDispatchInfo = {((globalWidth - 1) / 2) / groupWidth + 1, ((globalHeight - 1) / 2) / groupHeight + 1, 1};
|
||||
|
||||
ConstantBuffer constants;
|
||||
constants.matView = matView;
|
||||
constants.matProjInv = matProjInv;
|
||||
constants.matViewProj = matViewProj;
|
||||
constants.matViewProjInv = matViewProjInv;
|
||||
constants.viewPort = viewPort;
|
||||
constants.texSize = {float(width), float(height)};
|
||||
constants.viewPort = viewPort;
|
||||
|
||||
if (_compConstantsBuffer) {
|
||||
_compConstantsBuffer->update(&constants, sizeof(constants));
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectionComp::init(gfx::Device *dev, uint32_t groupSizeX, uint32_t groupSizeY) {
|
||||
if (!dev->hasFeature(gfx::Feature::COMPUTE_SHADER)) return;
|
||||
|
||||
_device = dev;
|
||||
_groupSizeX = groupSizeX;
|
||||
_groupSizeY = groupSizeY;
|
||||
|
||||
gfx::SamplerInfo samplerInfo;
|
||||
samplerInfo.minFilter = gfx::Filter::POINT;
|
||||
samplerInfo.magFilter = gfx::Filter::POINT;
|
||||
_sampler = _device->getSampler(samplerInfo);
|
||||
|
||||
uint32_t maxInvocations = _device->getCapabilities().maxComputeWorkGroupInvocations;
|
||||
CC_ASSERT(_groupSizeX * _groupSizeY <= maxInvocations); // maxInvocations is too small
|
||||
CC_LOG_INFO(" work group size: %dx%d", _groupSizeX, _groupSizeY);
|
||||
|
||||
gfx::DescriptorSetLayoutInfo layoutInfo = {pipeline::localDescriptorSetLayout.bindings};
|
||||
_localDescriptorSetLayout = _device->createDescriptorSetLayout(layoutInfo);
|
||||
|
||||
gfx::GeneralBarrierInfo infoPre = {
|
||||
gfx::AccessFlagBit::COLOR_ATTACHMENT_WRITE,
|
||||
gfx::AccessFlagBit::COMPUTE_SHADER_READ_TEXTURE,
|
||||
};
|
||||
|
||||
gfx::TextureBarrierInfo infoBeforeDenoise = {
|
||||
gfx::AccessFlagBit::COMPUTE_SHADER_WRITE,
|
||||
gfx::AccessFlagBit::COMPUTE_SHADER_READ_TEXTURE,
|
||||
};
|
||||
|
||||
gfx::TextureBarrierInfo infoBeforeDenoise2 = {
|
||||
gfx::AccessFlagBit::NONE,
|
||||
gfx::AccessFlagBit::COMPUTE_SHADER_WRITE,
|
||||
};
|
||||
|
||||
gfx::TextureBarrierInfo infoAfterDenoise = {
|
||||
gfx::AccessFlagBit::COMPUTE_SHADER_WRITE,
|
||||
gfx::AccessFlagBit::FRAGMENT_SHADER_READ_TEXTURE,
|
||||
};
|
||||
|
||||
_barrierPre = _device->getGeneralBarrier(infoPre);
|
||||
_barrierBeforeDenoise.push_back(_device->getTextureBarrier(infoBeforeDenoise));
|
||||
_barrierBeforeDenoise.push_back(_device->getTextureBarrier(infoBeforeDenoise2));
|
||||
_barrierAfterDenoise.push_back(_device->getTextureBarrier(infoAfterDenoise));
|
||||
|
||||
_compConstantsBuffer = _device->createBuffer({gfx::BufferUsage::UNIFORM,
|
||||
gfx::MemoryUsage::DEVICE | gfx::MemoryUsage::HOST,
|
||||
(sizeof(Mat4) * 4 + sizeof(Vec2) + sizeof(Vec4) + 15) / 16 * 16});
|
||||
|
||||
initReflectionRes();
|
||||
initDenoiseRes();
|
||||
}
|
||||
|
||||
void ReflectionComp::getReflectorShader(ShaderSources<ComputeShaderSource> &sources, bool useEnvmap) const {
|
||||
sources.glsl4 = StringUtil::format(
|
||||
R"(
|
||||
#define CC_USE_ENVMAP %d
|
||||
|
||||
layout(local_size_x = %d, local_size_y = %d, local_size_z = 1) in;
|
||||
|
||||
layout(set = 0, binding = 0) uniform Constants
|
||||
{
|
||||
mat4 matView;
|
||||
mat4 matProjInv;
|
||||
mat4 matViewProj;
|
||||
mat4 matViewProjInv;
|
||||
vec4 viewPort;
|
||||
vec2 texSize;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 1, std140) uniform CCLocal
|
||||
{
|
||||
mat4 cc_matWorld;
|
||||
mat4 cc_matWorldIT;
|
||||
vec4 cc_lightingMapUVParam;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 2) uniform sampler2D lightingTex;
|
||||
layout(set = 0, binding = 3) uniform sampler2D depth;
|
||||
layout(set = 0, binding = 4, rgba8) writeonly uniform lowp image2D reflectionTex;
|
||||
|
||||
vec4 screen2WS(vec3 coord) {
|
||||
vec4 ndc = vec4(
|
||||
2.0 * (coord.x - viewPort.x) / viewPort.z - 1.0,
|
||||
2.0 * (coord.y - viewPort.y) / viewPort.w - 1.0,
|
||||
coord.z,
|
||||
1.0
|
||||
);
|
||||
|
||||
vec4 world = matViewProjInv * ndc;
|
||||
world = world / world.w;
|
||||
return world;
|
||||
}
|
||||
|
||||
void main() {
|
||||
float _HorizontalPlaneHeightWS = 0.01;
|
||||
_HorizontalPlaneHeightWS = (cc_matWorld * vec4(0,0,0,1)).y;
|
||||
vec2 uv = vec2(gl_GlobalInvocationID.xy) / texSize;
|
||||
vec4 depValue = texture(depth, uv);
|
||||
vec2 screenPos = vec2(uv * vec2(viewPort.z, viewPort.w) + vec2(viewPort.x, viewPort.y));
|
||||
vec3 posWS = screen2WS(vec3(screenPos, depValue.r)).xyz;
|
||||
if(posWS.y <= _HorizontalPlaneHeightWS) return;
|
||||
|
||||
#if CC_USE_ENVMAP
|
||||
imageStore(reflectionTex, ivec2(gl_GlobalInvocationID.xy), vec4(0, 0, 0, 1));
|
||||
#endif
|
||||
|
||||
vec3 reflectedPosWS = posWS;
|
||||
reflectedPosWS.y = reflectedPosWS.y - _HorizontalPlaneHeightWS;
|
||||
reflectedPosWS.y = reflectedPosWS.y * -1.0;
|
||||
reflectedPosWS.y = reflectedPosWS.y + _HorizontalPlaneHeightWS;
|
||||
|
||||
vec4 reflectedPosCS = matViewProj * vec4(reflectedPosWS, 1);
|
||||
vec2 reflectedPosNDCxy = reflectedPosCS.xy / reflectedPosCS.w;//posCS -> posNDC
|
||||
vec2 reflectedScreenUV = reflectedPosNDCxy * 0.5 + 0.5; //posNDC
|
||||
|
||||
vec2 earlyExitTest = abs(reflectedScreenUV - 0.5);
|
||||
if (earlyExitTest.x >= 0.5 || earlyExitTest.y >= 0.5) return;
|
||||
|
||||
vec4 inputPixelSceneColor = texture(lightingTex, uv);
|
||||
imageStore(reflectionTex, ivec2(reflectedScreenUV * texSize), inputPixelSceneColor);
|
||||
})",
|
||||
useEnvmap, _groupSizeX, _groupSizeY);
|
||||
sources.glsl3 = StringUtil::format(
|
||||
R"(
|
||||
#define CC_USE_ENVMAP %d
|
||||
|
||||
layout(local_size_x = %d, local_size_y = %d, local_size_z = 1) in;
|
||||
|
||||
layout(std140) uniform Constants
|
||||
{
|
||||
mat4 matView;
|
||||
mat4 matProjInv;
|
||||
mat4 matViewProj;
|
||||
mat4 matViewProjInv;
|
||||
vec4 viewPort;
|
||||
vec2 texSize;
|
||||
};
|
||||
uniform sampler2D lightingTex;
|
||||
uniform sampler2D depth;
|
||||
layout(rgba8) writeonly uniform lowp image2D reflectionTex;
|
||||
|
||||
layout(std140) uniform CCLocal
|
||||
{
|
||||
mat4 cc_matWorld;
|
||||
mat4 cc_matWorldIT;
|
||||
vec4 cc_lightingMapUVParam;
|
||||
};
|
||||
|
||||
vec4 screen2WS(vec3 coord) {
|
||||
vec4 ndc = vec4(
|
||||
2.0 * (coord.x - viewPort.x) / viewPort.z - 1.0,
|
||||
2.0 * (coord.y - viewPort.y) / viewPort.w - 1.0,
|
||||
2.0 * coord.z - 1.0,
|
||||
1.0
|
||||
);
|
||||
|
||||
vec4 world = matViewProjInv * ndc;
|
||||
world = world / world.w;
|
||||
return world;
|
||||
}
|
||||
|
||||
void main() {
|
||||
float _HorizontalPlaneHeightWS = 0.01;
|
||||
_HorizontalPlaneHeightWS = (cc_matWorld * vec4(0,0,0,1)).y;
|
||||
vec2 uv = vec2(gl_GlobalInvocationID.xy) / texSize;
|
||||
vec4 depValue = texture(depth, uv);
|
||||
vec2 screenPos = uv * vec2(viewPort.z, viewPort.w) + vec2(viewPort.x, viewPort.y);
|
||||
vec3 posWS = screen2WS(vec3(screenPos, depValue.r)).xyz;
|
||||
if(posWS.y <= _HorizontalPlaneHeightWS) return;
|
||||
|
||||
#if CC_USE_ENVMAP
|
||||
if (posWS.y - 0.5 > _HorizontalPlaneHeightWS) imageStore(reflectionTex, ivec2(gl_GlobalInvocationID.xy), vec4(0, 0, 0, 1));
|
||||
#endif
|
||||
|
||||
vec3 reflectedPosWS = posWS;
|
||||
reflectedPosWS.y = reflectedPosWS.y - _HorizontalPlaneHeightWS;
|
||||
reflectedPosWS.y = reflectedPosWS.y * -1.0;
|
||||
reflectedPosWS.y = reflectedPosWS.y + _HorizontalPlaneHeightWS;
|
||||
|
||||
vec4 reflectedPosCS = matViewProj * vec4(reflectedPosWS, 1);
|
||||
vec2 reflectedPosNDCxy = reflectedPosCS.xy / reflectedPosCS.w;//posCS -> posNDC
|
||||
vec2 reflectedScreenUV = reflectedPosNDCxy * 0.5 + 0.5; //posNDC
|
||||
|
||||
vec2 earlyExitTest = abs(reflectedScreenUV - 0.5);
|
||||
if (earlyExitTest.x >= 0.5 || earlyExitTest.y >= 0.5) return;
|
||||
|
||||
vec4 inputPixelSceneColor = texture(lightingTex, uv);
|
||||
imageStore(reflectionTex, ivec2(reflectedScreenUV * texSize), inputPixelSceneColor);
|
||||
})",
|
||||
useEnvmap, _groupSizeX, _groupSizeY);
|
||||
}
|
||||
|
||||
void ReflectionComp::initReflectionRes() {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ShaderSources<ComputeShaderSource> sources;
|
||||
getReflectorShader(sources, i);
|
||||
|
||||
gfx::ShaderInfo shaderInfo;
|
||||
shaderInfo.name = "Compute ";
|
||||
shaderInfo.stages = {{gfx::ShaderStageFlagBit::COMPUTE, getAppropriateShaderSource(sources)}};
|
||||
shaderInfo.blocks = {
|
||||
{0, 0, "Constants", {
|
||||
{"matView", gfx::Type::MAT4, 1},
|
||||
{"matProjInv", gfx::Type::MAT4, 1},
|
||||
{"matViewProj", gfx::Type::MAT4, 1},
|
||||
{"matViewProjInv", gfx::Type::MAT4, 1},
|
||||
{"viewPort", gfx::Type::FLOAT4, 1},
|
||||
{"texSize", gfx::Type::FLOAT2, 1},
|
||||
},
|
||||
1},
|
||||
{0, 1, "CCLocal", {{"cc_matWorld", gfx::Type::MAT4, 1}, {"cc_matWorldIT", gfx::Type::MAT4, 1}, {"cc_lightingMapUVParam", gfx::Type::FLOAT4, 1}}, 1}};
|
||||
shaderInfo.samplerTextures = {
|
||||
{0, 2, "lightingTex", gfx::Type::SAMPLER2D, 1},
|
||||
{0, 3, "depth", gfx::Type::SAMPLER2D, 1}};
|
||||
shaderInfo.images = {
|
||||
{0, 4, "reflectionTex", gfx::Type::IMAGE2D, 1, gfx::MemoryAccessBit::WRITE_ONLY}};
|
||||
_compShader[i] = _device->createShader(shaderInfo);
|
||||
}
|
||||
|
||||
gfx::DescriptorSetLayoutInfo dslInfo;
|
||||
dslInfo.bindings.push_back({0, gfx::DescriptorType::UNIFORM_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
|
||||
dslInfo.bindings.push_back({1, gfx::DescriptorType::UNIFORM_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
|
||||
dslInfo.bindings.push_back({2, gfx::DescriptorType::SAMPLER_TEXTURE, 1, gfx::ShaderStageFlagBit::COMPUTE});
|
||||
dslInfo.bindings.push_back({3, gfx::DescriptorType::SAMPLER_TEXTURE, 1, gfx::ShaderStageFlagBit::COMPUTE});
|
||||
dslInfo.bindings.push_back({4, gfx::DescriptorType::STORAGE_IMAGE, 1, gfx::ShaderStageFlagBit::COMPUTE});
|
||||
|
||||
_compDescriptorSetLayout = _device->createDescriptorSetLayout(dslInfo);
|
||||
_compDescriptorSet = _device->createDescriptorSet({_compDescriptorSetLayout});
|
||||
|
||||
_compPipelineLayout = _device->createPipelineLayout({{_compDescriptorSetLayout}});
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
gfx::PipelineStateInfo pipelineInfo;
|
||||
pipelineInfo.shader = _compShader[i];
|
||||
pipelineInfo.pipelineLayout = _compPipelineLayout;
|
||||
pipelineInfo.bindPoint = gfx::PipelineBindPoint::COMPUTE;
|
||||
|
||||
_compPipelineState[i] = _device->createPipelineState(pipelineInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectionComp::getDenoiseShader(ShaderSources<ComputeShaderSource> &sources, bool useEnvmap) const {
|
||||
sources.glsl4 = StringUtil::format(
|
||||
R"(
|
||||
#define CC_USE_ENVMAP %d
|
||||
layout(local_size_x = %d, local_size_y = %d, local_size_z = 1) in;
|
||||
layout(set = 0, binding = 1) uniform sampler2D reflectionTex;
|
||||
layout(set = 1, binding = %d, rgba8) writeonly uniform lowp image2D denoiseTex;
|
||||
|
||||
#if CC_USE_ENVMAP == 1
|
||||
layout(set = 0, binding = 2) uniform samplerCube envMap;
|
||||
layout(set = 0, binding = 3) uniform sampler2D depth;
|
||||
layout(set = 0, binding = 0) uniform Constants
|
||||
{
|
||||
mat4 matView;
|
||||
mat4 matProjInv;
|
||||
mat4 matViewProj;
|
||||
mat4 matViewProjInv;
|
||||
vec4 viewPort;
|
||||
vec2 texSize;
|
||||
};
|
||||
|
||||
vec4 screen2ES(vec3 coord) {
|
||||
vec4 ndc = vec4(2.0 * (coord.x - viewPort.x) / viewPort.z - 1.0,
|
||||
2.0 * (coord.y - viewPort.y) / viewPort.w - 1.0,
|
||||
coord.z,
|
||||
1.0);
|
||||
|
||||
vec4 eye = matProjInv * ndc;
|
||||
eye = eye / eye.w;
|
||||
return eye;
|
||||
}
|
||||
|
||||
vec3 calEnvmapUV(vec3 eyeCoord) {
|
||||
vec4 planeNornalWS = vec4(0, 1.0, 0, 1.0);
|
||||
vec3 planeNormalES = normalize((matView * planeNornalWS).xyz);
|
||||
vec3 incidenceES = normalize(eyeCoord);
|
||||
return normalize(reflect(incidenceES, planeNormalES));
|
||||
}
|
||||
|
||||
vec4 sampleEnvmap(ivec2 id) {
|
||||
vec2 uv = vec2(id) / texSize;
|
||||
vec4 depValue = texture(depth, uv);
|
||||
vec2 screenPos = uv * vec2(viewPort.z, viewPort.w) + vec2(viewPort.x, viewPort.y);
|
||||
vec3 posES = screen2ES(vec3(screenPos, depValue.r)).xyz;
|
||||
vec3 envmapUV = calEnvmapUV(posES);
|
||||
return texture(envMap, envmapUV);
|
||||
}
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
ivec2 id = ivec2(gl_GlobalInvocationID.xy) * 2;
|
||||
|
||||
vec4 center = texelFetch(reflectionTex, id + ivec2(0, 0), 0);
|
||||
vec4 right = texelFetch(reflectionTex, id + ivec2(0, 1), 0);
|
||||
vec4 bottom = texelFetch(reflectionTex, id + ivec2(1, 0), 0);
|
||||
vec4 bottomRight = texelFetch(reflectionTex, id + ivec2(1, 1), 0);
|
||||
|
||||
vec4 best = center;
|
||||
best = right.a > best.a + 0.1 ? right : best;
|
||||
best = bottom.a > best.a + 0.1 ? bottom : best;
|
||||
best = bottomRight.a > best.a + 0.1 ? bottomRight : best;
|
||||
|
||||
#if !CC_USE_ENVMAP
|
||||
vec4 res = best.a > center.a + 0.1 ? best : center;
|
||||
if (res.xyz != vec3(0, 0, 0)) imageStore(denoiseTex, id + ivec2(0, 0), res);
|
||||
|
||||
res = best.a > right.a + 0.1 ? best : right;
|
||||
if (res.xyz != vec3(0, 0, 0)) imageStore(denoiseTex, id + ivec2(0, 1), res);
|
||||
|
||||
res = best.a > bottom.a + 0.1 ? best : bottom;
|
||||
if (res.xyz != vec3(0,0, 0)) imageStore(denoiseTex, id + ivec2(1, 0), res);
|
||||
|
||||
res = best.a > bottomRight.a + 0.1 ? best : bottomRight;
|
||||
if (res.xyz != vec3(0, 0, 0)) imageStore(denoiseTex, id + ivec2(1, 1), res);
|
||||
#else
|
||||
vec4 res = best.a > center.a + 0.1 ? best : center;
|
||||
res = res == vec4(0, 0, 0, 0) ? sampleEnvmap(id) : res;
|
||||
imageStore(denoiseTex, id + ivec2(0, 0), res);
|
||||
|
||||
res = best.a > right.a + 0.1 ? best : right;
|
||||
res = res == vec4(0, 0, 0, 0) ? sampleEnvmap(id + ivec2(0, 1)) : res;
|
||||
imageStore(denoiseTex, id + ivec2(0, 1), res);
|
||||
|
||||
res = best.a > bottom.a + 0.1 ? best : bottom;
|
||||
res = res == vec4(0, 0, 0, 0) ? sampleEnvmap(id + ivec2(1, 0)) : res;
|
||||
imageStore(denoiseTex, id + ivec2(1, 0), res);
|
||||
|
||||
res = best.a > bottomRight.a + 0.1 ? best : bottomRight;
|
||||
res = res == vec4(0, 0, 0, 0) ? sampleEnvmap(id + ivec2(1, 1)) : res;
|
||||
imageStore(denoiseTex, id + ivec2(1, 1), res);
|
||||
#endif
|
||||
})",
|
||||
useEnvmap, _groupSizeX, _groupSizeY, pipeline::REFLECTIONSTORAGE::BINDING);
|
||||
sources.glsl3 = StringUtil::format(
|
||||
R"(
|
||||
#define CC_USE_ENVMAP %d
|
||||
layout(local_size_x = %d, local_size_y = %d, local_size_z = 1) in;
|
||||
uniform sampler2D reflectionTex;
|
||||
|
||||
#if CC_USE_ENVMAP
|
||||
uniform samplerCube envMap;
|
||||
uniform sampler2D depth;
|
||||
layout(std140) uniform Constants
|
||||
{
|
||||
mat4 matView;
|
||||
mat4 matProjInv;
|
||||
mat4 matViewProj;
|
||||
mat4 matViewProjInv;
|
||||
vec4 viewPort;
|
||||
vec2 texSize;
|
||||
};
|
||||
#endif
|
||||
|
||||
layout(rgba8) writeonly uniform lowp image2D denoiseTex;
|
||||
|
||||
#if CC_USE_ENVMAP
|
||||
vec4 screen2ES(vec3 coord) {
|
||||
vec4 ndc = vec4(2.0 * (coord.x - viewPort.x) / viewPort.z - 1.0,
|
||||
2.0 * (coord.y - viewPort.y) / viewPort.w - 1.0,
|
||||
2.0 * coord.z - 1.0,
|
||||
1.0);
|
||||
|
||||
vec4 eye = matProjInv * ndc;
|
||||
eye = eye / eye.w;
|
||||
return eye;
|
||||
}
|
||||
|
||||
vec3 calEnvmapUV(vec3 eyeCoord) {
|
||||
vec4 planeNornalWS = vec4(0, 1.0, 0, 1.0);
|
||||
vec3 planeNormalES = normalize((matView * planeNornalWS).xyz);
|
||||
vec3 incidenceES = normalize(eyeCoord);
|
||||
return normalize(reflect(incidenceES, planeNormalES));
|
||||
}
|
||||
|
||||
vec4 sampleEnvmap(ivec2 id) {
|
||||
vec2 uv = vec2(id) / texSize;
|
||||
vec4 depValue = texture(depth, uv);
|
||||
vec2 screenPos = uv * vec2(viewPort.z, viewPort.w) + vec2(viewPort.x, viewPort.y);
|
||||
vec3 posES = screen2ES(vec3(screenPos, depValue.r)).xyz;
|
||||
vec3 envmapUV = calEnvmapUV(posES);
|
||||
return texture(envMap, envmapUV);
|
||||
}
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
ivec2 id = ivec2(gl_GlobalInvocationID.xy) * 2;
|
||||
|
||||
vec4 center = texelFetch(reflectionTex, id + ivec2(0, 0), 0);
|
||||
vec4 right = texelFetch(reflectionTex, id + ivec2(0, 1), 0);
|
||||
vec4 bottom = texelFetch(reflectionTex, id + ivec2(1, 0), 0);
|
||||
vec4 bottomRight = texelFetch(reflectionTex, id + ivec2(1, 1), 0);
|
||||
|
||||
vec4 best = center;
|
||||
best = right.a > best.a + 0.1 ? right : best;
|
||||
best = bottom.a > best.a + 0.1 ? bottom : best;
|
||||
best = bottomRight.a > best.a + 0.1 ? bottomRight : best;
|
||||
|
||||
#if !CC_USE_ENVMAP
|
||||
vec4 res = best.a > center.a + 0.1 ? best : center;
|
||||
if (res.xyz != vec3(0, 0, 0)) imageStore(denoiseTex, id + ivec2(0, 0), res);
|
||||
|
||||
res = best.a > right.a + 0.1 ? best : right;
|
||||
if (res.xyz != vec3(0, 0, 0)) imageStore(denoiseTex, id + ivec2(0, 1), res);
|
||||
|
||||
res = best.a > bottom.a + 0.1 ? best : bottom;
|
||||
if (res.xyz != vec3(0,0, 0)) imageStore(denoiseTex, id + ivec2(1, 0), res);
|
||||
|
||||
res = best.a > bottomRight.a + 0.1 ? best : bottomRight;
|
||||
if (res.xyz != vec3(0, 0, 0)) imageStore(denoiseTex, id + ivec2(1, 1), res);
|
||||
#else
|
||||
vec4 res = best.a > center.a + 0.1 ? best : center;
|
||||
res = res == vec4(0, 0, 0, 0) ? sampleEnvmap(id) : res;
|
||||
imageStore(denoiseTex, id + ivec2(0, 0), res);
|
||||
|
||||
res = best.a > right.a + 0.1 ? best : right;
|
||||
res = res == vec4(0, 0, 0, 0) ? sampleEnvmap(id + ivec2(0, 1)) : res;
|
||||
imageStore(denoiseTex, id + ivec2(0, 1), res);
|
||||
|
||||
res = best.a > bottom.a + 0.1 ? best : bottom;
|
||||
res = res == vec4(0, 0, 0, 0) ? sampleEnvmap(id + ivec2(1, 0)) : res;
|
||||
imageStore(denoiseTex, id + ivec2(1, 0), res);
|
||||
|
||||
res = best.a > bottomRight.a + 0.1 ? best : bottomRight;
|
||||
res = res == vec4(0, 0, 0, 0) ? sampleEnvmap(id + ivec2(1, 1)) : res;
|
||||
imageStore(denoiseTex, id + ivec2(1, 1), res);
|
||||
#endif
|
||||
})",
|
||||
useEnvmap, _groupSizeX, _groupSizeY);
|
||||
}
|
||||
|
||||
void ReflectionComp::initDenoiseRes() {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ShaderSources<ComputeShaderSource> sources;
|
||||
getDenoiseShader(sources, i);
|
||||
|
||||
gfx::ShaderInfo shaderInfo;
|
||||
shaderInfo.name = "Compute ";
|
||||
shaderInfo.stages = {{gfx::ShaderStageFlagBit::COMPUTE, getAppropriateShaderSource(sources)}};
|
||||
|
||||
if (i == 0) {
|
||||
shaderInfo.blocks = {};
|
||||
shaderInfo.samplerTextures = {
|
||||
{0, 1, "reflectionTex", gfx::Type::SAMPLER2D, 1}};
|
||||
} else {
|
||||
shaderInfo.blocks = {
|
||||
{0, 0, "Constants", {
|
||||
{"matView", gfx::Type::MAT4, 1},
|
||||
{"matProjInv", gfx::Type::MAT4, 1},
|
||||
{"matViewProj", gfx::Type::MAT4, 1},
|
||||
{"matViewProjInv", gfx::Type::MAT4, 1},
|
||||
{"viewPort", gfx::Type::FLOAT4, 1},
|
||||
{"texSize", gfx::Type::FLOAT2, 1},
|
||||
},
|
||||
1},
|
||||
};
|
||||
shaderInfo.samplerTextures = {
|
||||
{0, 1, "reflectionTex", gfx::Type::SAMPLER2D, 1},
|
||||
{0, 2, "envMap", gfx::Type::SAMPLER_CUBE, 1},
|
||||
{0, 3, "depth", gfx::Type::SAMPLER2D, 1}};
|
||||
}
|
||||
|
||||
shaderInfo.images = {
|
||||
{1, 12, "denoiseTex", gfx::Type::IMAGE2D, 1, gfx::MemoryAccessBit::WRITE_ONLY}};
|
||||
|
||||
_compDenoiseShader[i] = _device->createShader(shaderInfo);
|
||||
}
|
||||
|
||||
gfx::DescriptorSetLayoutInfo dslInfo;
|
||||
dslInfo.bindings.push_back({0, gfx::DescriptorType::UNIFORM_BUFFER, 1, gfx::ShaderStageFlagBit::COMPUTE});
|
||||
dslInfo.bindings.push_back({1, gfx::DescriptorType::SAMPLER_TEXTURE, 1, gfx::ShaderStageFlagBit::COMPUTE});
|
||||
dslInfo.bindings.push_back({2, gfx::DescriptorType::SAMPLER_TEXTURE, 1, gfx::ShaderStageFlagBit::COMPUTE});
|
||||
dslInfo.bindings.push_back({3, gfx::DescriptorType::SAMPLER_TEXTURE, 1, gfx::ShaderStageFlagBit::COMPUTE});
|
||||
_compDenoiseDescriptorSetLayout = _device->createDescriptorSetLayout(dslInfo);
|
||||
_compDenoisePipelineLayout = _device->createPipelineLayout({{_compDenoiseDescriptorSetLayout, _localDescriptorSetLayout}});
|
||||
_compDenoiseDescriptorSet = _device->createDescriptorSet({_compDenoiseDescriptorSetLayout});
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
gfx::PipelineStateInfo pipelineInfo;
|
||||
pipelineInfo.shader = _compDenoiseShader[i];
|
||||
pipelineInfo.pipelineLayout = _compDenoisePipelineLayout;
|
||||
pipelineInfo.bindPoint = gfx::PipelineBindPoint::COMPUTE;
|
||||
|
||||
_compDenoisePipelineState[i] = _device->createPipelineState(pipelineInfo);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T &ReflectionComp::getAppropriateShaderSource(ShaderSources<T> &sources) {
|
||||
switch (_device->getGfxAPI()) {
|
||||
case gfx::API::GLES2:
|
||||
return sources.glsl1;
|
||||
case gfx::API::GLES3:
|
||||
return sources.glsl3;
|
||||
case gfx::API::METAL:
|
||||
case gfx::API::VULKAN:
|
||||
return sources.glsl4;
|
||||
default: break;
|
||||
}
|
||||
return sources.glsl4;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
111
cocos/renderer/pipeline/deferred/ReflectionComp.h
Normal file
111
cocos/renderer/pipeline/deferred/ReflectionComp.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/TypeDef.h"
|
||||
#include "math/Mat4.h"
|
||||
#include "math/Vec2.h"
|
||||
#include "math/Vec4.h"
|
||||
#include "renderer/gfx-base/GFXDef.h"
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
using ComputeShaderSource = ccstd::string;
|
||||
|
||||
template <typename T>
|
||||
struct ShaderSources {
|
||||
T glsl4;
|
||||
T glsl3;
|
||||
T glsl1;
|
||||
};
|
||||
|
||||
class ReflectionComp {
|
||||
public:
|
||||
ReflectionComp() = default;
|
||||
~ReflectionComp();
|
||||
void init(gfx::Device *dev, uint32_t groupSizeX, uint32_t groupSizeY);
|
||||
void getReflectorShader(ShaderSources<ComputeShaderSource> &sources, bool useEnvmap) const;
|
||||
void getDenoiseShader(ShaderSources<ComputeShaderSource> &sources, bool useEnvmap) const;
|
||||
void initReflectionRes();
|
||||
void initDenoiseRes();
|
||||
void initDenoiseResEnvmap();
|
||||
void applyTexSize(uint32_t width, uint32_t height, const Mat4 &matView,
|
||||
const Mat4 &matViewProj, const Mat4 &matViewProjInv,
|
||||
const Mat4 &matProjInv, const Vec4 &viewPort);
|
||||
|
||||
inline gfx::DescriptorSet *getDescriptorSet() { return _compDescriptorSet; }
|
||||
inline const gfx::PipelineState *getPipelineState(bool useEnvmap) { return _compPipelineState[useEnvmap]; }
|
||||
inline gfx::DescriptorSet *getDenoiseDescriptorSet() { return _compDenoiseDescriptorSet; }
|
||||
inline const gfx::PipelineState *getDenoisePipelineState(bool useEnvmap) { return _compDenoisePipelineState[useEnvmap]; }
|
||||
inline const gfx::PipelineState *getDenoisePipelineStateEnvmap() { return _compDenoisePipelineStateEnvmap; }
|
||||
inline const gfx::GeneralBarrier *getBarrierPre() { return _barrierPre; }
|
||||
inline const gfx::TextureBarrierList &getBarrierBeforeDenoise() { return _barrierBeforeDenoise; }
|
||||
inline const gfx::TextureBarrierList &getBarrierAfterDenoise() { return _barrierAfterDenoise; }
|
||||
inline const gfx::DispatchInfo &getDispatchInfo() { return _dispatchInfo; }
|
||||
inline const gfx::DispatchInfo &getDenoiseDispatchInfo() { return _denoiseDispatchInfo; }
|
||||
inline uint32_t getGroupSizeX() const { return _groupSizeX; }
|
||||
inline uint32_t getGroupSizeY() const { return _groupSizeY; }
|
||||
|
||||
inline gfx::Buffer *getConstantsBuffer() { return _compConstantsBuffer; }
|
||||
inline gfx::Sampler *getSampler() { return _sampler; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
T &getAppropriateShaderSource(ShaderSources<T> &sources);
|
||||
|
||||
gfx::Device *_device{nullptr};
|
||||
|
||||
gfx::Shader *_compShader[2]{nullptr};
|
||||
gfx::DescriptorSetLayout *_compDescriptorSetLayout{nullptr};
|
||||
gfx::PipelineLayout *_compPipelineLayout{nullptr};
|
||||
gfx::PipelineState *_compPipelineState[2]{nullptr};
|
||||
gfx::DescriptorSet *_compDescriptorSet{nullptr};
|
||||
|
||||
gfx::Shader *_compDenoiseShader[2]{nullptr};
|
||||
gfx::DescriptorSetLayout *_compDenoiseDescriptorSetLayout{nullptr};
|
||||
gfx::PipelineLayout *_compDenoisePipelineLayout{nullptr};
|
||||
gfx::PipelineState *_compDenoisePipelineState[2]{nullptr};
|
||||
gfx::PipelineState *_compDenoisePipelineStateEnvmap{nullptr};
|
||||
gfx::DescriptorSet *_compDenoiseDescriptorSet{nullptr};
|
||||
|
||||
gfx::DescriptorSetLayout *_localDescriptorSetLayout{nullptr};
|
||||
|
||||
gfx::Buffer *_compConstantsBuffer{nullptr};
|
||||
gfx::Sampler *_sampler{nullptr};
|
||||
|
||||
gfx::GeneralBarrier *_barrierPre{nullptr};
|
||||
|
||||
gfx::TextureBarrierList _barrierBeforeDenoise;
|
||||
gfx::TextureBarrierList _barrierAfterDenoise;
|
||||
|
||||
gfx::DispatchInfo _dispatchInfo;
|
||||
gfx::DispatchInfo _denoiseDispatchInfo;
|
||||
|
||||
uint32_t _groupSizeX{8};
|
||||
uint32_t _groupSizeY{8};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
Reference in New Issue
Block a user