mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 15:36:14 +03:00
411 lines
17 KiB
C++
411 lines
17 KiB
C++
#include "../deferred_renderer.h"
|
|
#include "../render_scene.h"
|
|
#include "../renderer.h"
|
|
#include "../scene_textures.h"
|
|
|
|
namespace engine
|
|
{
|
|
|
|
struct SSGIPush
|
|
{
|
|
vec3 probe0Pos;
|
|
float probe0ValidFactor;
|
|
vec3 probe1Pos;
|
|
float probe1ValidFactor;
|
|
|
|
vec4 boxExtentData0;
|
|
vec4 boxExtentData1;
|
|
vec4 boxExtentData2;
|
|
};
|
|
|
|
struct RTGIPush
|
|
{
|
|
float rayMinRange;
|
|
float rayMaxRange;
|
|
};
|
|
|
|
struct SSGIReprojectPush
|
|
{
|
|
float kMinAlpha;
|
|
float kMinAlphaMoment;
|
|
};
|
|
|
|
struct SSGIBlurPush
|
|
{
|
|
int kStepSize;
|
|
};
|
|
|
|
class SSGIPass : public PassInterface
|
|
{
|
|
public:
|
|
std::unique_ptr<ComputePipeResources> intersect;
|
|
std::unique_ptr<ComputePipeResources> filter;
|
|
std::unique_ptr<ComputePipeResources> reproject;
|
|
|
|
std::unique_ptr<ComputePipeResources> rtPipe;
|
|
|
|
public:
|
|
virtual void onInit() override
|
|
{
|
|
{
|
|
VkDescriptorSetLayout intersectLayout = VK_NULL_HANDLE;
|
|
|
|
getContext()->descriptorFactoryBegin()
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 0) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 3) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 4) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 5) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 6) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 7) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 8) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 9) //
|
|
.buildNoInfoPush(intersectLayout);
|
|
|
|
std::vector<VkDescriptorSetLayout> intersectLayouts =
|
|
{
|
|
intersectLayout,
|
|
getContext()->getSamplerCache().getCommonDescriptorSetLayout(),
|
|
getRenderer()->getBlueNoise().spp_1_buffer.setLayouts
|
|
};
|
|
|
|
intersect = std::make_unique<ComputePipeResources>("shader/ssgi_intersect.glsl", sizeof(SSGIPush), intersectLayouts);
|
|
}
|
|
{
|
|
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
|
|
|
|
getContext()->descriptorFactoryBegin()
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 0) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 3) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,4) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 5) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 6) //
|
|
.buildNoInfoPush(layout);
|
|
|
|
std::vector<VkDescriptorSetLayout> layouts =
|
|
{
|
|
layout,
|
|
getContext()->getSamplerCache().getCommonDescriptorSetLayout(),
|
|
};
|
|
|
|
filter = std::make_unique<ComputePipeResources>("shader/ssgi_blur.glsl", sizeof(SSGIBlurPush), layouts);
|
|
}
|
|
|
|
{
|
|
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
|
|
|
|
getContext()->descriptorFactoryBegin()
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 0) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,2) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 3) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 4) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 5) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 6) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 7) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 8) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 9) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,10) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,11) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,12) //
|
|
.buildNoInfoPush(layout);
|
|
|
|
std::vector<VkDescriptorSetLayout> layouts =
|
|
{
|
|
layout,
|
|
getContext()->getSamplerCache().getCommonDescriptorSetLayout()
|
|
};
|
|
|
|
reproject = std::make_unique<ComputePipeResources>("shader/ssgi_reproject.glsl", sizeof(SSGIReprojectPush), layouts);
|
|
}
|
|
|
|
{
|
|
VkDescriptorSetLayout rtSetLayout = VK_NULL_HANDLE;
|
|
getContext()->descriptorFactoryBegin()
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 0) //
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1) // inFrameData
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 2) // AS
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 3) // inDepth
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4)
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 5) // inDepth
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 6) // inDepth
|
|
.buildNoInfoPush(rtSetLayout);
|
|
|
|
std::vector<VkDescriptorSetLayout> layouts{
|
|
rtSetLayout,
|
|
m_context->getSamplerCache().getCommonDescriptorSetLayout(),
|
|
getRenderer()->getBlueNoise().spp_1_buffer.setLayouts,
|
|
m_context->getBindlessSSBOSetLayout()
|
|
, m_context->getBindlessSSBOSetLayout()
|
|
, m_context->getBindlessSamplerSetLayout()
|
|
, m_context->getBindlessTextureSetLayout()
|
|
};
|
|
|
|
rtPipe = std::make_unique<ComputePipeResources>("shader/ssgi_rt.glsl", sizeof(RTGIPush), layouts);
|
|
}
|
|
}
|
|
|
|
virtual void release() override
|
|
{
|
|
intersect.reset();
|
|
filter.reset();
|
|
reproject.reset();
|
|
rtPipe.reset();
|
|
}
|
|
};
|
|
|
|
|
|
PoolImageSharedRef DeferredRenderer::renderSSGI(
|
|
VkCommandBuffer cmd,
|
|
GBufferTextures* inGBuffers,
|
|
RenderScene* scene,
|
|
BufferParameterHandle perFrameGPU,
|
|
PoolImageSharedRef inHiz,
|
|
const SkyLightRenderContext& inSky,
|
|
ReflectionProbeContext& reflectionProbeContext)
|
|
{
|
|
if (!inSky.skylightRadiance)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
const uint32_t objectCount = (uint32_t)scene->getObjectCollector().size();
|
|
if (objectCount <= 0)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
auto* pass = getContext()->getPasses().get<SSGIPass>();
|
|
auto* rtPool = &getContext()->getRenderTargetPools();
|
|
|
|
auto gbufferB = inGBuffers->vertexNormal;
|
|
|
|
|
|
|
|
auto historyColor = m_history.prevHdrBeforeAA ? m_history.prevHdrBeforeAA : inGBuffers->hdrSceneColor;
|
|
|
|
auto& gbufferA = inGBuffers->gbufferA->getImage();
|
|
auto& gbufferS = inGBuffers->gbufferS->getImage();
|
|
auto& gbufferV = inGBuffers->gbufferV->getImage();
|
|
auto& sceneDepthZ = inGBuffers->depthTexture->getImage();
|
|
inGBuffers->gbufferId->getImage().transitionShaderReadOnly(cmd);
|
|
|
|
gbufferA.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
gbufferB->getImage().transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
gbufferS.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
gbufferV.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
sceneDepthZ.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT));
|
|
inHiz->getImage().transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
|
|
PoolImageSharedRef ssgiIntersect = rtPool->createPoolImage(
|
|
"SSGI intersect",
|
|
gbufferB->getImage().getExtent().width / 2,
|
|
gbufferB->getImage().getExtent().height / 2,
|
|
VK_FORMAT_R16G16B16A16_SFLOAT,
|
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
|
|
|
gbufferB->getImage().transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
historyColor->getImage().transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
ssgiIntersect->getImage().transitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL, buildBasicImageSubresource());
|
|
|
|
if (scene->isTLASValid() && false)
|
|
{
|
|
ScopePerframeMarker tonemapperMarker(cmd, "rt-intersect", { 1.0f, 1.0f, 0.0f, 1.0f }, &m_gpuTimer);
|
|
|
|
RTGIPush pushConst;
|
|
pushConst.rayMinRange = 0.1f;
|
|
pushConst.rayMaxRange = 200.0f;
|
|
|
|
pass->rtPipe->bindAndPushConst(cmd, &pushConst);
|
|
|
|
PushSetBuilder(cmd)
|
|
.addUAV(ssgiIntersect)
|
|
.addBuffer(perFrameGPU)
|
|
.addAS(scene->getTLAS())
|
|
.addSRV(sceneDepthZ, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT))
|
|
.addBuffer(scene->getObjectBufferGPU())
|
|
.addSRV(inSky.skylightRadiance, buildBasicImageSubresourceCube(), VK_IMAGE_VIEW_TYPE_CUBE)
|
|
.addSRV(gbufferB)
|
|
.push(pass->rtPipe.get());
|
|
|
|
pass->rtPipe->bindSet(cmd, std::vector<VkDescriptorSet>{
|
|
getContext()->getSamplerCache().getCommonDescriptorSet(),
|
|
getRenderer()->getBlueNoise().spp_8_buffer.set,
|
|
getContext()->getBindlessSSBOSet(),
|
|
getContext()->getBindlessSSBOSet(),
|
|
getContext()->getBindlessSamplerSet(),
|
|
getContext()->getBindlessTexture().getSet(),
|
|
}, 1);
|
|
|
|
vkCmdDispatch(cmd, getGroupCount(
|
|
ssgiIntersect->getImage().getExtent().width, 8),
|
|
getGroupCount(ssgiIntersect->getImage().getExtent().height, 8), 1);
|
|
}
|
|
else
|
|
{
|
|
ScopePerframeMarker tonemapperMarker(cmd, "ssgi-intersect", { 1.0f, 1.0f, 0.0f, 1.0f }, &m_gpuTimer);
|
|
|
|
SSGIPush pushConst;
|
|
|
|
pass->intersect->bindAndPushConst(cmd, &pushConst);
|
|
PushSetBuilder(cmd)
|
|
.addSRV(inHiz)
|
|
.addSRV(inGBuffers->depthTexture, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT))
|
|
.addSRV(gbufferB)
|
|
.addSRV(inGBuffers->gbufferV)
|
|
.addSRV(historyColor)
|
|
.addBuffer(perFrameGPU)
|
|
.addUAV(ssgiIntersect)
|
|
.addSRV(reflectionProbeContext.probe0 ? reflectionProbeContext.probe0 : inSky.skylightRadiance, buildBasicImageSubresourceCube(), VK_IMAGE_VIEW_TYPE_CUBE)
|
|
.addSRV(reflectionProbeContext.probe1 ? reflectionProbeContext.probe1 : inSky.skylightRadiance, buildBasicImageSubresourceCube(), VK_IMAGE_VIEW_TYPE_CUBE)
|
|
.addSRV(inSky.skylightRadiance, buildBasicImageSubresourceCube(), VK_IMAGE_VIEW_TYPE_CUBE)
|
|
.push(pass->intersect.get());
|
|
|
|
pass->intersect->bindSet(cmd, std::vector<VkDescriptorSet>
|
|
{
|
|
getContext()->getSamplerCache().getCommonDescriptorSet(),
|
|
getRenderer()->getBlueNoise().spp_1_buffer.set
|
|
}, 1);
|
|
|
|
vkCmdDispatch(cmd,
|
|
getGroupCount(ssgiIntersect->getImage().getExtent().width, 8),
|
|
getGroupCount(ssgiIntersect->getImage().getExtent().height, 8), 1);
|
|
|
|
}
|
|
|
|
ssgiIntersect->getImage().transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
|
|
|
|
|
|
PoolImageSharedRef fullResIntersec = rtPool->createPoolImage(
|
|
"SSGI intersect full",
|
|
gbufferB->getImage().getExtent().width / 2,
|
|
gbufferB->getImage().getExtent().height / 2,
|
|
VK_FORMAT_R16G16B16A16_SFLOAT,
|
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
|
|
|
PoolImageSharedRef fullResIntersec1 = rtPool->createPoolImage(
|
|
"SSGI intersect full1",
|
|
gbufferB->getImage().getExtent().width / 2,
|
|
gbufferB->getImage().getExtent().height / 2,
|
|
VK_FORMAT_R16G16B16A16_SFLOAT,
|
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
|
|
|
|
|
PoolImageSharedRef temporalImage = rtPool->createPoolImage(
|
|
"SSGI temporal full",
|
|
gbufferB->getImage().getExtent().width / 2,
|
|
gbufferB->getImage().getExtent().height / 2,
|
|
VK_FORMAT_R16G16B16A16_SFLOAT,
|
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
|
|
|
PoolImageSharedRef moment = rtPool->createPoolImage(
|
|
"SSGI moment full",
|
|
gbufferB->getImage().getExtent().width / 2,
|
|
gbufferB->getImage().getExtent().height / 2,
|
|
VK_FORMAT_R16G16B16A16_SFLOAT,
|
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
|
|
|
{
|
|
|
|
|
|
ScopePerframeMarker tonemapperMarker(cmd, "ssgi-filter half", { 1.0f, 1.0f, 0.0f, 1.0f }, & m_gpuTimer);
|
|
|
|
{
|
|
temporalImage->getImage().transitionGeneral(cmd);
|
|
moment->getImage().transitionGeneral(cmd);
|
|
|
|
SSGIReprojectPush pushConst;
|
|
pushConst.kMinAlpha = 0.01f;
|
|
pushConst.kMinAlphaMoment = 0.2f;
|
|
|
|
pass->reproject->bindAndPushConst(cmd, &pushConst);
|
|
PushSetBuilder(cmd)
|
|
.addSRV(inGBuffers->depthTexture, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT))
|
|
.addSRV(inGBuffers->gbufferV)
|
|
.addBuffer(perFrameGPU)
|
|
.addSRV(ssgiIntersect)
|
|
.addSRV(m_history.ssgiHistory ? m_history.ssgiHistory : ssgiIntersect)
|
|
.addUAV(temporalImage)
|
|
.addSRV(m_history.ssgiMomentHistory ? m_history.ssgiMomentHistory : ssgiIntersect)
|
|
.addUAV(moment)
|
|
.addSRV(gbufferB)
|
|
.addSRV(m_history.prevGBufferB ? m_history.prevGBufferB : gbufferB)
|
|
.addSRV(m_history.prevDepth ? m_history.prevDepth : inGBuffers->depthTexture, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT))
|
|
.addSRV(inGBuffers->gbufferId)
|
|
.addSRV(m_history.prevGBufferID ? m_history.prevGBufferID : inGBuffers->gbufferId)
|
|
.push(pass->reproject.get());
|
|
|
|
pass->reproject->bindSet(cmd, std::vector<VkDescriptorSet>
|
|
{
|
|
getContext()->getSamplerCache().getCommonDescriptorSet(),
|
|
}, 1);
|
|
|
|
vkCmdDispatch(cmd,
|
|
getGroupCount(temporalImage->getImage().getExtent().width, 8),
|
|
getGroupCount(temporalImage->getImage().getExtent().height, 8), 1);
|
|
|
|
temporalImage->getImage().transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
moment->getImage().transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, buildBasicImageSubresource());
|
|
}
|
|
|
|
m_history.ssgiHistory = temporalImage;
|
|
m_history.ssgiMomentHistory = moment;
|
|
|
|
auto In = temporalImage;
|
|
auto Out = fullResIntersec;
|
|
|
|
const uint kFilterNum = 4;
|
|
|
|
pass->filter->bind(cmd);
|
|
pass->filter->bindSet(cmd, std::vector<VkDescriptorSet>
|
|
{
|
|
getContext()->getSamplerCache().getCommonDescriptorSet(),
|
|
}, 1);
|
|
for(uint i = 0; i < kFilterNum; i ++)
|
|
{
|
|
In->getImage().transitionShaderReadOnly(cmd);
|
|
Out->getImage().transitionGeneral(cmd);
|
|
|
|
SSGIBlurPush pushConst;
|
|
pushConst.kStepSize = 1 << i;
|
|
|
|
pass->filter->pushConst(cmd, &pushConst);
|
|
|
|
PushSetBuilder(cmd)
|
|
.addSRV(inGBuffers->depthTexture, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT))
|
|
.addSRV(gbufferB)
|
|
.addSRV(In)
|
|
.addUAV(Out)
|
|
.addBuffer(perFrameGPU)
|
|
.addSRV(m_history.prevNormalVertex ? m_history.prevNormalVertex : gbufferB)
|
|
.addSRV(m_history.prevDepth ? m_history.prevDepth : inGBuffers->depthTexture, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT))
|
|
.push(pass->filter.get());
|
|
|
|
vkCmdDispatch(cmd,
|
|
getGroupCount(fullResIntersec->getImage().getExtent().width, 8),
|
|
getGroupCount(fullResIntersec->getImage().getExtent().height, 8), 1);
|
|
|
|
|
|
auto tempOut = Out;
|
|
Out = In;
|
|
In = tempOut;
|
|
if (i == 0)
|
|
{
|
|
Out = fullResIntersec1;
|
|
}
|
|
}
|
|
|
|
|
|
fullResIntersec = In;
|
|
fullResIntersec->getImage().transitionShaderReadOnly(cmd);
|
|
}
|
|
|
|
|
|
return fullResIntersec;
|
|
}
|
|
} |