Files
Seele/src/Engine/Graphics/RenderPass/LightCullingPass.cpp
T
2023-11-01 23:12:30 +01:00

290 lines
12 KiB
C++

#include "LightCullingPass.h"
#include "Graphics/Graphics.h"
#include "Scene/Scene.h"
#include "Actor/CameraActor.h"
#include "Component/Camera.h"
#include "RenderGraph.h"
using namespace Seele;
LightCullingPass::LightCullingPass(Gfx::PGraphics graphics, PScene scene)
: RenderPass(graphics, scene)
{
}
LightCullingPass::~LightCullingPass()
{
}
void LightCullingPass::beginFrame(const Component::Camera& cam)
{
uint32_t viewportWidth = viewport->getSizeX();
uint32_t viewportHeight = viewport->getSizeY();
DataSource uniformUpdate;
viewParams.viewMatrix = cam.getViewMatrix();
viewParams.projectionMatrix = viewport->getProjectionMatrix();
viewParams.cameraPosition = Vector4(cam.getCameraPosition(), 1);
viewParams.screenDimensions = Vector2(static_cast<float>(viewportWidth), static_cast<float>(viewportHeight));
uniformUpdate.size = sizeof(ViewParameter);
uniformUpdate.data = (uint8*)&viewParams;
viewParamsBuffer->updateContents(uniformUpdate);
DataSource counterReset;
uint32 reset = 0;
counterReset.data = (uint8*)&reset;
counterReset.size = sizeof(uint32);
oLightIndexCounter->updateContents(counterReset);
tLightIndexCounter->updateContents(counterReset);
cullingDescriptorLayout->reset();
lightEnvDescriptorLayout->reset();
cullingDescriptorSet = cullingDescriptorLayout->allocateDescriptorSet();
lightEnvDescriptorSet = lightEnvDescriptorLayout->allocateDescriptorSet();
cullingDescriptorSet->updateBuffer(0, viewParamsBuffer);
cullingDescriptorSet->updateBuffer(1, dispatchParamsBuffer);
cullingDescriptorSet->updateBuffer(3, oLightIndexCounter);
cullingDescriptorSet->updateBuffer(4, tLightIndexCounter);
cullingDescriptorSet->updateBuffer(5, oLightIndexList);
cullingDescriptorSet->updateBuffer(6, tLightIndexList);
cullingDescriptorSet->updateTexture(7, oLightGrid);
cullingDescriptorSet->updateTexture(8, tLightGrid);
cullingDescriptorSet->updateBuffer(9, frustumBuffer);
lightEnvDescriptorSet->updateBuffer(0, passData.lightEnv.directionalLights);
lightEnvDescriptorSet->updateBuffer(1, passData.lightEnv.numDirectional);
lightEnvDescriptorSet->updateBuffer(2, passData.lightEnv.pointLights);
lightEnvDescriptorSet->updateBuffer(3, passData.lightEnv.numPoints);
lightEnvDescriptorSet->writeChanges();
//std::cout << "LightCulling beginFrame()" << std::endl;
//co_return;
}
void LightCullingPass::render()
{
oLightIndexList->pipelineBarrier(
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
oLightGrid->pipelineBarrier(
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
depthAttachment->pipelineBarrier(
Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
depthAttachment->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL);
depthAttachment->transferOwnership(Gfx::QueueType::COMPUTE);
cullingDescriptorSet->updateTexture(2, depthAttachment);
cullingDescriptorSet->writeChanges();
Gfx::PComputeCommand computeCommand = graphics->createComputeCommand("CullingCommand");
computeCommand->bindPipeline(cullingPipeline);
Array<Gfx::PDescriptorSet> descriptorSets = {cullingDescriptorSet, lightEnvDescriptorSet};
computeCommand->bindDescriptor(descriptorSets);
//computeCommand->dispatch(dispatchParams.numThreadGroups.x, dispatchParams.numThreadGroups.y, dispatchParams.numThreadGroups.z);
Array<Gfx::PComputeCommand> commands = {computeCommand};
graphics->executeCommands(commands);
depthAttachment->changeLayout(Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
depthAttachment->transferOwnership(Gfx::QueueType::GRAPHICS);
//std::cout << "LightCulling render()" << std::endl;
//co_return;
}
void LightCullingPass::endFrame()
{
//std::cout << "LightCulling endFrame()" << std::endl;
//co_return;
}
void LightCullingPass::publishOutputs()
{
setupFrustums();
uint32_t viewportWidth = viewport->getSizeX();
uint32_t viewportHeight = viewport->getSizeY();
glm::uvec3 numThreadGroups = glm::ceil(glm::vec3(viewportWidth / (float)BLOCK_SIZE, viewportHeight / (float)BLOCK_SIZE, 1));
dispatchParams.numThreadGroups = numThreadGroups;
dispatchParams.numThreads = numThreadGroups * glm::uvec3(BLOCK_SIZE, BLOCK_SIZE, 1);
cullingDescriptorLayout = graphics->createDescriptorLayout("CullingLayout");
//ViewParams
cullingDescriptorLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
//Dispatchparams
cullingDescriptorLayout->addDescriptorBinding(1, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
//DepthTexture
cullingDescriptorLayout->addDescriptorBinding(2, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
//o_lightIndexCounter
cullingDescriptorLayout->addDescriptorBinding(3, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
//t_lightIndexCounter
cullingDescriptorLayout->addDescriptorBinding(4, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
//o_lightIndexList
cullingDescriptorLayout->addDescriptorBinding(5, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
//t_lightIndexList
cullingDescriptorLayout->addDescriptorBinding(6, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
//o_lightGrid
cullingDescriptorLayout->addDescriptorBinding(7, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_IMAGE);
//t_lightGrid
cullingDescriptorLayout->addDescriptorBinding(8, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_IMAGE);
//Frustums
cullingDescriptorLayout->addDescriptorBinding(9, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, viewportWidth * viewportHeight);
lightEnvDescriptorLayout = graphics->createDescriptorLayout("LightEnv");
// Directional Lights
lightEnvDescriptorLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, MAX_DIRECTIONAL_LIGHTS);
lightEnvDescriptorLayout->addDescriptorBinding(1, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
// Point Lights
lightEnvDescriptorLayout->addDescriptorBinding(2, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, MAX_POINT_LIGHTS);
lightEnvDescriptorLayout->addDescriptorBinding(3, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
cullingLayout = graphics->createPipelineLayout();
cullingLayout->addDescriptorLayout(0, cullingDescriptorLayout);
cullingLayout->addDescriptorLayout(1, lightEnvDescriptorLayout);
cullingLayout->create();
ShaderCreateInfo createInfo;
createInfo.name = "Culling";
createInfo.mainModule = "LightCulling";
createInfo.entryPoint = "cullLights";
createInfo.defines["INDEX_VIEW_PARAMS"] = "0";
createInfo.defines["INDEX_LIGHT_ENV"] = "1";
createInfo.defines["NUM_MATERIAL_TEXCOORDS"] = "0";
cullingShader = graphics->createComputeShader(createInfo);
Gfx::ComputePipelineCreateInfo pipelineInfo;
pipelineInfo.computeShader = cullingShader;
pipelineInfo.pipelineLayout = cullingLayout;
cullingPipeline = graphics->createComputePipeline(pipelineInfo);
uint32 counterReset = 0;
ShaderBufferCreateInfo structInfo =
{
.sourceData = {
.size = sizeof(uint32),
.data = (uint8*)&counterReset,
.owner = Gfx::QueueType::COMPUTE,
},
.stride = sizeof(uint32),
.bDynamic = true,
};
oLightIndexCounter = graphics->createShaderBuffer(structInfo);
tLightIndexCounter = graphics->createShaderBuffer(structInfo);
structInfo = {
.sourceData = {
.size = (uint32)sizeof(uint32)
* dispatchParams.numThreadGroups.x
* dispatchParams.numThreadGroups.y
* dispatchParams.numThreadGroups.z * 200,
.data = nullptr,
.owner = Gfx::QueueType::COMPUTE
},
.stride = sizeof(uint32),
.bDynamic = false,
};
oLightIndexList = graphics->createShaderBuffer(structInfo);
tLightIndexList = graphics->createShaderBuffer(structInfo);
resources->registerBufferOutput("LIGHTCULLING_OLIGHTLIST", oLightIndexList);
resources->registerBufferOutput("LIGHTCULLING_TLIGHTLIST", tLightIndexList);
TextureCreateInfo textureInfo = {
.width = dispatchParams.numThreadGroups.x,
.height = dispatchParams.numThreadGroups.y,
.format = Gfx::SE_FORMAT_R32G32_UINT,
.usage = Gfx::SE_IMAGE_USAGE_STORAGE_BIT,
};
oLightGrid = graphics->createTexture2D(textureInfo);
tLightGrid = graphics->createTexture2D(textureInfo);
resources->registerTextureOutput("LIGHTCULLING_OLIGHTGRID", oLightGrid);
resources->registerTextureOutput("LIGHTCULLING_TLIGHTGRID", tLightGrid);
}
void LightCullingPass::createRenderPass()
{
depthAttachment = resources->requestRenderTarget("DEPTHPREPASS_DEPTH")->getTexture();
}
void LightCullingPass::modifyRenderPassMacros(Map<const char*, const char*>&)
{
}
void LightCullingPass::setupFrustums()
{
uint32_t viewportWidth = viewport->getSizeX();
uint32_t viewportHeight = viewport->getSizeY();
glm::uvec3 numThreads = glm::ceil(glm::vec3(viewportWidth / (float)BLOCK_SIZE, viewportHeight / (float)BLOCK_SIZE, 1));
glm::uvec3 numThreadGroups = glm::ceil(glm::vec3(numThreads.x / (float)BLOCK_SIZE, numThreads.y / (float)BLOCK_SIZE, 1));
viewParams = {
.viewMatrix = Matrix4(),
.projectionMatrix = Matrix4(),
.cameraPosition = Vector4(),
.screenDimensions = glm::vec2(viewportWidth, viewportHeight),
};
dispatchParams.numThreads = numThreads;
dispatchParams.numThreadGroups = numThreadGroups;
Gfx::PDescriptorLayout frustumDescriptorLayout = graphics->createDescriptorLayout("FrustumLayout");
frustumDescriptorLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
frustumDescriptorLayout->addDescriptorBinding(1, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
frustumDescriptorLayout->addDescriptorBinding(2, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
frustumLayout = graphics->createPipelineLayout();
frustumLayout->addDescriptorLayout(0, frustumDescriptorLayout);
frustumLayout->create();
ShaderCreateInfo createInfo;
createInfo.name = "Frustum";
createInfo.mainModule = "ComputeFrustums";
createInfo.entryPoint = "computeFrustums";
createInfo.defines["INDEX_VIEW_PARAMS"] = "0";
frustumShader = graphics->createComputeShader(createInfo);
Gfx::ComputePipelineCreateInfo pipelineInfo;
pipelineInfo.computeShader = frustumShader;
pipelineInfo.pipelineLayout = frustumLayout;
frustumPipeline = graphics->createComputePipeline(pipelineInfo);
DataSource resourceInfo;
UniformBufferCreateInfo uniformInfo;
resourceInfo.size = sizeof(ViewParameter);
resourceInfo.data = (uint8*)&viewParams;
resourceInfo.owner = Gfx::QueueType::COMPUTE;
uniformInfo.sourceData = resourceInfo;
uniformInfo.bDynamic = false;
viewParamsBuffer = graphics->createUniformBuffer(uniformInfo);
resourceInfo.size = sizeof(DispatchParams);
resourceInfo.data = (uint8*)&dispatchParams;
uniformInfo.sourceData = resourceInfo;
uniformInfo.bDynamic = false;
dispatchParamsBuffer = graphics->createUniformBuffer(uniformInfo);
ShaderBufferCreateInfo structuredInfo = {
.sourceData = {
.size = sizeof(Frustum) * numThreads.x * numThreads.y * numThreads.z,
.data = nullptr,
},
.stride = sizeof(Frustum),
.bDynamic = false,
};
frustumBuffer = graphics->createShaderBuffer(structuredInfo);
frustumDescriptorSet = frustumDescriptorLayout->allocateDescriptorSet();
frustumDescriptorSet->updateBuffer(0, viewParamsBuffer);
frustumDescriptorSet->updateBuffer(1, dispatchParamsBuffer);
frustumDescriptorSet->updateBuffer(2, frustumBuffer);
frustumDescriptorSet->writeChanges();
Gfx::PComputeCommand command = graphics->createComputeCommand("FrustumCommand");
command->bindPipeline(frustumPipeline);
command->bindDescriptor(frustumDescriptorSet);
command->dispatch(numThreadGroups.x, numThreadGroups.y, numThreadGroups.z);
Array<Gfx::PComputeCommand> commands = {command};
graphics->executeCommands(commands);
frustumBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
}