2025-03-10 18:35:35 +01:00
|
|
|
#include "ToneMappingPass.h"
|
|
|
|
|
|
|
|
|
|
using namespace Seele;
|
|
|
|
|
|
|
|
|
|
ToneMappingPass::ToneMappingPass(Gfx::PGraphics graphics) : RenderPass(graphics) {
|
2025-03-11 22:08:23 +01:00
|
|
|
tonemappingLayout = graphics->createDescriptorLayout("ToneMappingDescriptor");
|
|
|
|
|
tonemappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
2025-03-10 18:35:35 +01:00
|
|
|
.name = "offset",
|
|
|
|
|
.uniformLength = sizeof(Vector4),
|
|
|
|
|
});
|
2025-03-11 22:08:23 +01:00
|
|
|
tonemappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
2025-03-10 18:35:35 +01:00
|
|
|
.name = "slope",
|
|
|
|
|
.uniformLength = sizeof(Vector4),
|
|
|
|
|
});
|
2025-03-11 22:08:23 +01:00
|
|
|
tonemappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
2025-03-10 18:35:35 +01:00
|
|
|
.name = "power",
|
|
|
|
|
.uniformLength = sizeof(Vector4),
|
|
|
|
|
});
|
2025-03-11 22:08:23 +01:00
|
|
|
tonemappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
2025-03-10 18:35:35 +01:00
|
|
|
.name = "sat",
|
|
|
|
|
.uniformLength = sizeof(float),
|
|
|
|
|
});
|
2025-03-11 22:08:23 +01:00
|
|
|
tonemappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
2025-03-10 18:35:35 +01:00
|
|
|
.name = "hdrInputTexture",
|
|
|
|
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
|
|
|
|
});
|
2025-03-11 22:08:23 +01:00
|
|
|
tonemappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
2025-03-10 18:35:35 +01:00
|
|
|
.name = "hdrSampler",
|
|
|
|
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER,
|
|
|
|
|
});
|
2025-03-11 22:08:23 +01:00
|
|
|
tonemappingLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
|
|
|
|
.name = "averageLuminance",
|
|
|
|
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
|
|
|
});
|
|
|
|
|
tonemappingLayout->create();
|
|
|
|
|
tonemappingPipelineLayout = graphics->createPipelineLayout("ToneMappingLayout");
|
|
|
|
|
tonemappingPipelineLayout->addDescriptorLayout(tonemappingLayout);
|
|
|
|
|
|
2025-03-10 18:35:35 +01:00
|
|
|
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
|
|
|
|
.name = "ToneMapping",
|
|
|
|
|
.modules = {"FullScreenQuad", "ToneMapping"},
|
2025-03-11 22:08:23 +01:00
|
|
|
.entryPoints =
|
|
|
|
|
{
|
|
|
|
|
{"quadMain", "FullScreenQuad"},
|
|
|
|
|
{"toneMapping", "ToneMapping"},
|
|
|
|
|
},
|
|
|
|
|
.rootSignature = tonemappingPipelineLayout,
|
2025-03-10 18:35:35 +01:00
|
|
|
});
|
2025-03-11 22:08:23 +01:00
|
|
|
tonemappingPipelineLayout->create();
|
2025-03-10 18:35:35 +01:00
|
|
|
vert = graphics->createVertexShader({0});
|
|
|
|
|
frag = graphics->createFragmentShader({1});
|
2025-03-11 22:08:23 +01:00
|
|
|
|
|
|
|
|
histogramLayout = graphics->createDescriptorLayout("pHistogramParams");
|
|
|
|
|
histogramLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
|
|
|
|
.name = "minLogLum",
|
|
|
|
|
.uniformLength = sizeof(float),
|
|
|
|
|
});
|
|
|
|
|
histogramLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
|
|
|
|
.name = "inverseLogLumRange",
|
|
|
|
|
.uniformLength = sizeof(float),
|
|
|
|
|
});
|
|
|
|
|
histogramLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
|
|
|
|
.name = "timeCoeff",
|
|
|
|
|
.uniformLength = sizeof(float),
|
|
|
|
|
});
|
|
|
|
|
histogramLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
|
|
|
|
.name = "numPixels",
|
|
|
|
|
.uniformLength = sizeof(uint32),
|
|
|
|
|
});
|
|
|
|
|
histogramLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
|
|
|
|
.name = "hdrImage",
|
|
|
|
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
|
|
|
|
});
|
|
|
|
|
histogramLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
|
|
|
|
.name = "histogram",
|
|
|
|
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
|
|
|
});
|
|
|
|
|
histogramLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
|
|
|
|
.name = "averageLuminance",
|
|
|
|
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
|
|
|
});
|
|
|
|
|
histogramLayout->create();
|
|
|
|
|
histogramPipelineLayout = graphics->createPipelineLayout("HistogramPipelineLayout");
|
|
|
|
|
histogramPipelineLayout->addDescriptorLayout(histogramLayout);
|
|
|
|
|
|
|
|
|
|
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
|
|
|
|
.name = "Exposure",
|
|
|
|
|
.modules = {"Exposure"},
|
|
|
|
|
.entryPoints =
|
|
|
|
|
{
|
|
|
|
|
{"histogram", "Exposure"},
|
|
|
|
|
{"exposure", "Exposure"},
|
|
|
|
|
},
|
|
|
|
|
.rootSignature = histogramPipelineLayout,
|
|
|
|
|
});
|
|
|
|
|
histogramPipelineLayout->create();
|
|
|
|
|
histogramShader = graphics->createComputeShader({0});
|
|
|
|
|
histogramPipeline = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
|
|
|
|
.computeShader = histogramShader,
|
|
|
|
|
.pipelineLayout = histogramPipelineLayout,
|
|
|
|
|
});
|
|
|
|
|
exposureShader = graphics->createComputeShader({1});
|
|
|
|
|
exposurePipeline = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
|
|
|
|
.computeShader = exposureShader,
|
|
|
|
|
.pipelineLayout = histogramPipelineLayout,
|
|
|
|
|
});
|
|
|
|
|
histogramBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
|
|
|
|
.sourceData =
|
|
|
|
|
{
|
|
|
|
|
.size = sizeof(uint32) * 256,
|
|
|
|
|
},
|
|
|
|
|
.name = "HistogramBuffer",
|
|
|
|
|
});
|
|
|
|
|
luminanceBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
|
|
|
|
.sourceData =
|
|
|
|
|
{
|
|
|
|
|
.size = sizeof(uint32),
|
|
|
|
|
},
|
|
|
|
|
.name = "LuminanceBuffer",
|
|
|
|
|
});
|
2025-03-10 18:35:35 +01:00
|
|
|
sampler = graphics->createSampler({});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ToneMappingPass::~ToneMappingPass() {}
|
|
|
|
|
|
2025-04-11 23:13:19 +02:00
|
|
|
void ToneMappingPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) { RenderPass::beginFrame(cam, transform); }
|
2025-03-10 18:35:35 +01:00
|
|
|
|
|
|
|
|
void ToneMappingPass::render() {
|
|
|
|
|
hdrInputTexture.getTexture()->changeLayout(Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
|
|
|
Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT,
|
2025-03-11 22:08:23 +01:00
|
|
|
Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
2025-03-10 18:35:35 +01:00
|
|
|
|
2025-03-11 22:08:23 +01:00
|
|
|
histogramLayout->reset();
|
2025-03-26 13:38:48 +01:00
|
|
|
histogramSet = histogramLayout->allocateDescriptorSet();
|
2025-03-11 22:08:23 +01:00
|
|
|
histogramSet->updateConstants("minLogLum", 0, &minLogLum);
|
|
|
|
|
histogramSet->updateConstants("inverseLogLumRange", 0, &inverseLogLumRange);
|
|
|
|
|
histogramSet->updateConstants("timeCoeff", 0, &timeCoeff);
|
|
|
|
|
histogramSet->updateConstants("numPixels", 0, &numPixels);
|
|
|
|
|
histogramSet->updateTexture("hdrImage", 0, hdrInputTexture.getTexture());
|
|
|
|
|
histogramSet->updateBuffer("histogram", 0, histogramBuffer);
|
|
|
|
|
histogramSet->updateBuffer("averageLuminance", 0, luminanceBuffer);
|
|
|
|
|
histogramSet->writeChanges();
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
Gfx::OComputeCommand computeCommand = graphics->createComputeCommand("HistogramCommand");
|
|
|
|
|
computeCommand->bindPipeline(histogramPipeline);
|
|
|
|
|
computeCommand->bindDescriptor({histogramSet});
|
|
|
|
|
computeCommand->dispatch(threadGroups.x, threadGroups.y, 1);
|
|
|
|
|
graphics->executeCommands(std::move(computeCommand));
|
|
|
|
|
}
|
|
|
|
|
histogramBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
|
|
|
|
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
|
|
|
|
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
|
|
|
|
{
|
|
|
|
|
Gfx::OComputeCommand computeCommand = graphics->createComputeCommand("ExposureCommand");
|
|
|
|
|
computeCommand->bindPipeline(exposurePipeline);
|
|
|
|
|
computeCommand->bindDescriptor({histogramSet});
|
|
|
|
|
computeCommand->dispatch(1, 1, 1);
|
|
|
|
|
graphics->executeCommands(std::move(computeCommand));
|
|
|
|
|
}
|
|
|
|
|
luminanceBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
|
|
|
|
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
|
|
|
|
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
|
|
|
|
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT | Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
|
|
|
|
|
|
|
|
|
tonemappingLayout->reset();
|
|
|
|
|
Gfx::PDescriptorSet tonemappingSet = tonemappingLayout->allocateDescriptorSet();
|
|
|
|
|
tonemappingSet->updateConstants("offset", 0, &offset);
|
|
|
|
|
tonemappingSet->updateConstants("slope", 0, &slope);
|
|
|
|
|
tonemappingSet->updateConstants("power", 0, &power);
|
|
|
|
|
tonemappingSet->updateConstants("sat", 0, &sat);
|
|
|
|
|
tonemappingSet->updateTexture("hdrInputTexture", 0, hdrInputTexture.getTexture());
|
|
|
|
|
tonemappingSet->updateSampler("hdrSampler", 0, sampler);
|
|
|
|
|
tonemappingSet->updateBuffer("averageLuminance", 0, luminanceBuffer);
|
|
|
|
|
tonemappingSet->writeChanges();
|
2025-03-10 18:35:35 +01:00
|
|
|
graphics->beginRenderPass(renderPass);
|
|
|
|
|
Gfx::ORenderCommand command = graphics->createRenderCommand("ToneMapping");
|
|
|
|
|
command->setViewport(viewport);
|
|
|
|
|
command->bindPipeline(pipeline);
|
2025-03-11 22:08:23 +01:00
|
|
|
command->bindDescriptor({tonemappingSet});
|
2025-03-10 18:35:35 +01:00
|
|
|
command->draw(3, 1, 0, 0);
|
|
|
|
|
graphics->executeCommands(std::move(command));
|
|
|
|
|
graphics->endRenderPass();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ToneMappingPass::endFrame() {}
|
|
|
|
|
|
|
|
|
|
void ToneMappingPass::publishOutputs() {
|
2025-03-11 22:08:23 +01:00
|
|
|
numPixels = viewport->getWidth() * viewport->getHeight();
|
|
|
|
|
threadGroups = UVector2((viewport->getWidth() + 15) / 16, (viewport->getHeight() + 15) / 16);
|
2025-03-10 18:35:35 +01:00
|
|
|
colorAttachment = Gfx::RenderTargetAttachment(viewport, Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
|
|
|
Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, Gfx::SE_ATTACHMENT_STORE_OP_STORE);
|
|
|
|
|
resources->registerRenderPassOutput("TONEMAPPING_COLOR", colorAttachment);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ToneMappingPass::createRenderPass() {
|
|
|
|
|
hdrInputTexture = resources->requestRenderTarget("BASEPASS_COLOR");
|
|
|
|
|
Gfx::RenderTargetLayout targetLayout = Gfx::RenderTargetLayout{
|
|
|
|
|
.colorAttachments = {colorAttachment},
|
|
|
|
|
};
|
|
|
|
|
Array<Gfx::SubPassDependency> dependency = {
|
|
|
|
|
{
|
|
|
|
|
.srcSubpass = ~0U,
|
|
|
|
|
.dstSubpass = 0,
|
|
|
|
|
.srcStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
|
|
.dstStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
|
|
.srcAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
|
|
|
.dstAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.srcSubpass = 0,
|
|
|
|
|
.dstSubpass = ~0U,
|
|
|
|
|
.srcStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
|
|
.dstStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
|
|
.srcAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
|
|
|
.dstAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
|
|
|
},
|
|
|
|
|
};
|
2025-04-11 21:02:52 +02:00
|
|
|
renderPass = graphics->createRenderPass(targetLayout, dependency, "ToneMappingPass");
|
2025-03-10 18:35:35 +01:00
|
|
|
pipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{
|
|
|
|
|
.vertexShader = vert,
|
|
|
|
|
.fragmentShader = frag,
|
|
|
|
|
.renderPass = renderPass,
|
2025-03-11 22:08:23 +01:00
|
|
|
.pipelineLayout = tonemappingPipelineLayout,
|
2025-03-10 18:35:35 +01:00
|
|
|
.colorBlend =
|
|
|
|
|
{
|
|
|
|
|
.attachmentCount = 1,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|