adding basic tone mapping

This commit is contained in:
Dynamitos
2025-03-10 18:35:35 +01:00
parent 6f0e2fe7e7
commit a957b05615
20 changed files with 314 additions and 37 deletions
-1
View File
@@ -35,7 +35,6 @@ struct WindowCreateInfo {
struct ViewportCreateInfo {
URect dimensions;
float fieldOfView = glm::radians(70.0f);
Gfx::SeSampleCountFlags numSamples;
};
// doesnt own the data, only proxy it
struct DataSource {
+12 -12
View File
@@ -189,7 +189,7 @@ void BasePass::render() {
.pipelineLayout = collection->pipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
.samples = msColorAttachment.getNumSamples(),
},
.rasterizationState =
{
@@ -210,7 +210,7 @@ void BasePass::render() {
.pipelineLayout = collection->pipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
.samples = msColorAttachment.getNumSamples(),
},
.rasterizationState =
{
@@ -231,7 +231,7 @@ void BasePass::render() {
Gfx::SE_SHADER_STAGE_FRAGMENT_BIT,
0, sizeof(VertexData::DrawCallOffsets), &drawCall.offsets);
if (graphics->supportMeshShading()) {
//command->drawMesh(drawCall.instanceMeshData.size(), 1, 1);
command->drawMesh(drawCall.instanceMeshData.size(), 1, 1);
} else {
command->bindIndexBuffer(vertexData->getIndexBuffer());
for (const auto& meshData : drawCall.instanceMeshData) {
@@ -287,7 +287,7 @@ void BasePass::render() {
.pipelineLayout = collection->pipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
.samples = msColorAttachment.getNumSamples(),
},
.rasterizationState =
{
@@ -314,7 +314,7 @@ void BasePass::render() {
.pipelineLayout = collection->pipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
.samples = msColorAttachment.getNumSamples(),
},
.rasterizationState =
{
@@ -345,7 +345,7 @@ void BasePass::render() {
Gfx::SE_SHADER_STAGE_FRAGMENT_BIT,
0, sizeof(VertexData::DrawCallOffsets), &t.offsets);
if (graphics->supportMeshShading()) {
//transparentCommand->drawMesh(1, 1, 1);
transparentCommand->drawMesh(1, 1, 1);
} else {
// command->bindIndexBuffer(t.vertexData->getIndexBuffer());
// for (const auto& meshData : drawCall.instanceMeshData) {
@@ -396,7 +396,7 @@ void BasePass::publishOutputs() {
.format = Gfx::SE_FORMAT_D32_SFLOAT,
.width = viewport->getOwner()->getFramebufferWidth(),
.height = viewport->getOwner()->getFramebufferHeight(),
.samples = viewport->getSamples(),
.samples = Gfx::SE_SAMPLE_COUNT_4_BIT,
.usage = Gfx::SE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
});
@@ -404,7 +404,7 @@ void BasePass::publishOutputs() {
.format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT,
.width = viewport->getOwner()->getFramebufferWidth(),
.height = viewport->getOwner()->getFramebufferHeight(),
.samples = viewport->getSamples(),
.samples = Gfx::SE_SAMPLE_COUNT_4_BIT, // todo: configure
.usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
});
@@ -417,7 +417,7 @@ void BasePass::publishOutputs() {
Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_DONT_CARE);
msDepthAttachment.clear.depthStencil.depth = 0.0f;
colorAttachment = Gfx::RenderTargetAttachment(viewport, Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
colorAttachment = Gfx::RenderTargetAttachment(basePassColor, 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);
msColorAttachment =
@@ -437,7 +437,7 @@ void BasePass::publishOutputs() {
}
void BasePass::createRenderPass() {
RenderPass::beginFrame(Component::Camera());
//RenderPass::beginFrame(Component::Camera());
//terrainRenderer = new TerrainRenderer(graphics, scene, viewParamsLayout, viewParamsSet);
cullingBuffer = resources->requestBuffer("CULLINGBUFFER");
timestamps = resources->requestTimestampQuery("TIMESTAMPS");
@@ -538,7 +538,7 @@ void BasePass::createRenderPass() {
.pipelineLayout = debugPipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
.samples = msColorAttachment.getNumSamples(),
},
.rasterizationState =
{
@@ -612,7 +612,7 @@ void BasePass::createRenderPass() {
.pipelineLayout = pipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
.samples = msColorAttachment.getNumSamples(),
},
.rasterizationState =
{
@@ -17,6 +17,8 @@ target_sources(Engine
RenderPass.cpp
TerrainRenderer.h
TerrainRenderer.cpp
ToneMappingPass.h
ToneMappingPass.cpp
UIPass.h
UIPass.cpp
VisibilityPass.h
@@ -31,6 +33,7 @@ target_sources(Engine
CachedDepthPass.h
DepthCullingPass.h
LightCullingPass.h
ToneMappingPass.h
RayTracingPass.h
RenderGraph.h
RenderGraphResources.h
@@ -297,7 +297,7 @@ void TerrainRenderer::setViewport(Gfx::PViewport _viewport, Gfx::PRenderPass ren
.pipelineLayout = meshUpdater.pipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
.samples = Gfx::SE_SAMPLE_COUNT_1_BIT,
},
.rasterizationState =
{
@@ -0,0 +1,112 @@
#include "ToneMappingPass.h"
using namespace Seele;
ToneMappingPass::ToneMappingPass(Gfx::PGraphics graphics) : RenderPass(graphics) {
layout = graphics->createDescriptorLayout("ToneMappingDescriptor");
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = "offset",
.uniformLength = sizeof(Vector4),
});
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = "slope",
.uniformLength = sizeof(Vector4),
});
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = "power",
.uniformLength = sizeof(Vector4),
});
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = "sat",
.uniformLength = sizeof(float),
});
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = "hdrInputTexture",
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
});
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = "hdrSampler",
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER,
});
layout->create();
pipelineLayout = graphics->createPipelineLayout("ToneMappingLayout");
pipelineLayout->addDescriptorLayout(layout);
graphics->beginShaderCompilation(ShaderCompilationInfo{
.name = "ToneMapping",
.modules = {"FullScreenQuad", "ToneMapping"},
.entryPoints = {{"quadMain", "FullScreenQuad"}, {"toneMapping", "ToneMapping"}},
.rootSignature = pipelineLayout,
});
pipelineLayout->create();
vert = graphics->createVertexShader({0});
frag = graphics->createFragmentShader({1});
sampler = graphics->createSampler({});
}
ToneMappingPass::~ToneMappingPass() {}
void ToneMappingPass::beginFrame(const Component::Camera& cam) { RenderPass::beginFrame(cam); }
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,
Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
layout->reset();
set = layout->allocateDescriptorSet();
set->updateTexture("hdrInputTexture", 0, hdrInputTexture.getTexture());
set->updateSampler("hdrSampler", 0, sampler);
set->writeChanges();
graphics->beginRenderPass(renderPass);
Gfx::ORenderCommand command = graphics->createRenderCommand("ToneMapping");
command->setViewport(viewport);
command->bindPipeline(pipeline);
command->bindDescriptor({set});
command->draw(3, 1, 0, 0);
graphics->executeCommands(std::move(command));
graphics->endRenderPass();
}
void ToneMappingPass::endFrame() {}
void ToneMappingPass::publishOutputs() {
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,
},
};
renderPass = graphics->createRenderPass(targetLayout, dependency, viewport, "ToneMappingPass");
pipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{
.vertexShader = vert,
.fragmentShader = frag,
.renderPass = renderPass,
.pipelineLayout = pipelineLayout,
.colorBlend =
{
.attachmentCount = 1,
},
});
}
@@ -0,0 +1,33 @@
#pragma once
#include "RenderPass.h"
#include "Graphics/Shader.h"
namespace Seele
{
class ToneMappingPass : public RenderPass {
public:
ToneMappingPass(Gfx::PGraphics graphics);
ToneMappingPass(ToneMappingPass&&) = default;
ToneMappingPass& operator=(ToneMappingPass&&) = default;
virtual ~ToneMappingPass();
virtual void beginFrame(const Component::Camera& cam) override;
virtual void render() override;
virtual void endFrame() override;
virtual void publishOutputs() override;
virtual void createRenderPass() override;
private:
// non-hdr swapchain output
Gfx::RenderTargetAttachment colorAttachment;
Gfx::RenderTargetAttachment hdrInputTexture;
Gfx::OSampler sampler;
Gfx::ODescriptorLayout layout;
Gfx::PDescriptorSet set;
Gfx::OPipelineLayout pipelineLayout;
Gfx::OVertexShader vert;
Gfx::OFragmentShader frag;
Gfx::PGraphicsPipeline pipeline;
};
}
@@ -458,7 +458,7 @@ void WaterRenderer::setViewport(Gfx::PViewport _viewport, Gfx::PRenderPass rende
.pipelineLayout = waterLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
.samples = Gfx::SE_SAMPLE_COUNT_4_BIT,
},
.rasterizationState =
{
+2 -1
View File
@@ -35,7 +35,8 @@ class RenderTargetAttachment {
}
SeSampleCountFlags getNumSamples() const {
if (viewport != nullptr) {
return viewport->getSamples();
// viewport backbuffers are not multisampled themselves
return Gfx::SE_SAMPLE_COUNT_1_BIT;
}
return texture->getNumSamples();
}
+6 -7
View File
@@ -55,6 +55,7 @@ void VertexData::updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transfo
matData.instances.resize(referencedInstance->getId() + 1);
}
BatchedDrawCall& matInstanceData = matData.instances[referencedInstance->getId()];
matInstanceData.materialInstance = referencedInstance;
for (const auto& data : meshData[mesh->id]) {
if (mat->hasTransparency()) {
auto params = referencedInstance->getMaterialOffsets();
@@ -75,7 +76,6 @@ void VertexData::updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transfo
.rayTracingScene = mesh->blas,
});
} else { // opaque
matInstanceData.materialInstance = referencedInstance;
matInstanceData.rayTracingData.add(mesh->blas);
matInstanceData.instanceData.add(inst);
matInstanceData.instanceMeshData.add(data);
@@ -138,13 +138,12 @@ void VertexData::createDescriptors() {
void VertexData::loadMesh(MeshId id, Array<uint32> loadedIndices, Array<Meshlet> loadedMeshlets) {
std::unique_lock l(vertexDataLock);
uint32 numMeshData = (loadedMeshlets.size() + 2047) / 2048; // todo: magic number
for (uint32 n = 0; n < numMeshData; ++n) {
uint32 meshletsToProcess = std::min<uint32>(loadedMeshlets.size() - n * 2048, 2048);
for (auto&& chunk : loadedMeshlets | std::views::chunk(2048)) {
uint32 meshletOffset = meshlets.size();
AABB meshAABB;
for (uint32 i = 0; i < meshletsToProcess; ++i) {
Meshlet& m = loadedMeshlets[n * 2048 + i];
uint32 numMeshlets = 0;
for (auto&& m : chunk) {
numMeshlets++;
//...
meshAABB = meshAABB.combine(m.boundingBox);
uint32 vertexOffset = vertexIndices.size();
@@ -165,7 +164,7 @@ void VertexData::loadMesh(MeshId id, Array<uint32> loadedIndices, Array<Meshlet>
}
meshData[id].add(MeshData{
.bounding = meshAABB, //.toSphere(),
.numMeshlets = (uint32)meshletsToProcess,
.numMeshlets = numMeshlets,
.meshletOffset = meshletOffset,
});
}
+1 -1
View File
@@ -172,7 +172,7 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::RenderTargetLayout _layout, Arra
.colorAttachmentCount = (uint32)colorRefs.size(),
.pColorAttachments = colorRefs.data(),
.pResolveAttachments = resolveRefs.size() > 0 ? resolveRefs.data() : nullptr,
.pDepthStencilAttachment = &depthRef,
.pDepthStencilAttachment = layout.depthAttachment.getTexture() != nullptr ? &depthRef : nullptr,
};
Array<VkSubpassDependency2> dep;
for (const auto& d : dependencies) {
+1 -1
View File
@@ -10,7 +10,7 @@ Window::~Window() {}
Viewport::Viewport(PWindow owner, const ViewportCreateInfo& viewportInfo)
: sizeX(std::min(owner->getFramebufferWidth(), viewportInfo.dimensions.size.x)),
sizeY(std::min(owner->getFramebufferHeight(), viewportInfo.dimensions.size.y)), offsetX(viewportInfo.dimensions.offset.x),
offsetY(viewportInfo.dimensions.offset.y), fieldOfView(viewportInfo.fieldOfView), samples(viewportInfo.numSamples), owner(owner) {}
offsetY(viewportInfo.dimensions.offset.y), fieldOfView(viewportInfo.fieldOfView), owner(owner) {}
Viewport::~Viewport() {}
-2
View File
@@ -52,7 +52,6 @@ class Viewport {
constexpr uint32 getOffsetY() const { return offsetY; }
constexpr float getContentScaleX() const { return owner->getContentScaleX(); }
constexpr float getContentScaleY() const { return owner->getContentScaleY(); }
constexpr Gfx::SeSampleCountFlags getSamples() const { return samples; }
Matrix4 getProjectionMatrix() const;
protected:
@@ -61,7 +60,6 @@ class Viewport {
uint32 offsetX;
uint32 offsetY;
float fieldOfView;
Gfx::SeSampleCountFlags samples;
PWindow owner;
};
DEFINE_REF(Viewport)