#include "tonemap.h" #include #include #include #include #include #include #include #include #include #include #include #include "core/frame/resources.h" struct TonemapPush { float exposure; int mode; int bloomEnabled; float bloomThreshold; float bloomIntensity; }; void TonemapPass::init(EngineContext *context) { _context = context; _inputSetLayout = _context->getDescriptorLayouts()->singleImageLayout(); const VkFormat ldrFormat = (_context && _context->getSwapchain()) ? _context->getSwapchain()->swapchainImageFormat() : VK_FORMAT_B8G8R8A8_UNORM; GraphicsPipelineCreateInfo info{}; info.vertexShaderPath = _context->getAssets()->shaderPath("fullscreen.vert.spv"); info.fragmentShaderPath = _context->getAssets()->shaderPath("tonemap.frag.spv"); info.setLayouts = { _inputSetLayout }; VkPushConstantRange pcr{}; pcr.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; pcr.offset = 0; pcr.size = sizeof(TonemapPush); info.pushConstants = { pcr }; info.configure = [ldrFormat](PipelineBuilder &b) { b.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); b.set_polygon_mode(VK_POLYGON_MODE_FILL); b.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE); b.set_multisampling_none(); b.disable_depthtest(); b.disable_blending(); b.set_color_attachment_format(ldrFormat); }; _context->pipelines->createGraphicsPipeline("tonemap", info); MaterialPipeline mp{}; _context->pipelines->getMaterialPipeline("tonemap", mp); _pipeline = mp.pipeline; _pipelineLayout = mp.layout; } void TonemapPass::cleanup() { _deletionQueue.flush(); } void TonemapPass::execute(VkCommandBuffer) { // Executed via render graph. } RGImageHandle TonemapPass::register_graph(RenderGraph *graph, RGImageHandle hdrInput) { if (!graph || !hdrInput.valid()) return {}; const VkFormat ldrFormat = (_context && _context->getSwapchain()) ? _context->getSwapchain()->swapchainImageFormat() : VK_FORMAT_B8G8R8A8_UNORM; RGImageDesc desc{}; desc.name = "ldr.tonemap"; desc.format = ldrFormat; desc.extent = _context->getDrawExtent(); desc.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; RGImageHandle ldr = graph->create_image(desc); graph->add_pass( "Tonemap", RGPassType::Graphics, [hdrInput, ldr](RGPassBuilder &builder, EngineContext *) { builder.read(hdrInput, RGImageUsage::SampledFragment); builder.write_color(ldr, true /*clear*/); }, [this, hdrInput](VkCommandBuffer cmd, const RGPassResources &res, EngineContext *ctx) { draw_tonemap(cmd, ctx, res, hdrInput); } ); return ldr; } void TonemapPass::draw_tonemap(VkCommandBuffer cmd, EngineContext *ctx, const RGPassResources &res, RGImageHandle hdrInput) { if (!ctx || !ctx->currentFrame) return; VkDevice device = ctx->getDevice()->device(); VkImageView hdrView = res.image_view(hdrInput); if (hdrView == VK_NULL_HANDLE) return; VkDescriptorSet set = ctx->currentFrame->_frameDescriptors.allocate(device, _inputSetLayout); DescriptorWriter writer; writer.write_image(0, hdrView, ctx->getSamplers()->defaultLinear(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); writer.update_set(device, set); ctx->pipelines->getGraphics("tonemap", _pipeline, _pipelineLayout); vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipeline); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipelineLayout, 0, 1, &set, 0, nullptr); TonemapPush push{}; push.exposure = _exposure; push.mode = _mode; push.bloomEnabled = _bloomEnabled ? 1 : 0; push.bloomThreshold = _bloomThreshold; push.bloomIntensity = _bloomIntensity; vkCmdPushConstants(cmd, _pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(TonemapPush), &push); VkExtent2D extent = ctx->getDrawExtent(); VkViewport vp{0.f, 0.f, (float)extent.width, (float)extent.height, 0.f, 1.f}; VkRect2D sc{{0,0}, extent}; vkCmdSetViewport(cmd, 0, 1, &vp); vkCmdSetScissor(cmd, 0, 1, &sc); vkCmdDraw(cmd, 3, 1, 0, 0); }