From 3b2267ba6d0db3e6db4a0f95c58f7c7e300fec92 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Wed, 27 Apr 2022 13:42:50 +1000 Subject: Splitting tonemapper into its own class --- servers/rendering/renderer_rd/SCsub | 1 + servers/rendering/renderer_rd/effects/SCsub | 5 + .../rendering/renderer_rd/effects/tone_mapper.cpp | 280 +++++++++++++ .../rendering/renderer_rd/effects/tone_mapper.h | 155 +++++++ servers/rendering/renderer_rd/effects_rd.cpp | 201 +-------- servers/rendering/renderer_rd/effects_rd.h | 104 ----- .../renderer_rd/renderer_scene_render_rd.cpp | 16 +- .../renderer_rd/renderer_scene_render_rd.h | 2 + servers/rendering/renderer_rd/shaders/SCsub | 2 + .../rendering/renderer_rd/shaders/effects/SCsub | 17 + .../renderer_rd/shaders/effects/tonemap.glsl | 457 +++++++++++++++++++++ servers/rendering/renderer_rd/shaders/tonemap.glsl | 457 --------------------- 12 files changed, 931 insertions(+), 766 deletions(-) create mode 100644 servers/rendering/renderer_rd/effects/SCsub create mode 100644 servers/rendering/renderer_rd/effects/tone_mapper.cpp create mode 100644 servers/rendering/renderer_rd/effects/tone_mapper.h create mode 100644 servers/rendering/renderer_rd/shaders/effects/SCsub create mode 100644 servers/rendering/renderer_rd/shaders/effects/tonemap.glsl delete mode 100644 servers/rendering/renderer_rd/shaders/tonemap.glsl diff --git a/servers/rendering/renderer_rd/SCsub b/servers/rendering/renderer_rd/SCsub index d3ad381965..774a6b7951 100644 --- a/servers/rendering/renderer_rd/SCsub +++ b/servers/rendering/renderer_rd/SCsub @@ -4,6 +4,7 @@ Import("env") env.add_source_files(env.servers_sources, "*.cpp") +SConscript("effects/SCsub") SConscript("forward_clustered/SCsub") SConscript("forward_mobile/SCsub") SConscript("shaders/SCsub") diff --git a/servers/rendering/renderer_rd/effects/SCsub b/servers/rendering/renderer_rd/effects/SCsub new file mode 100644 index 0000000000..86681f9c74 --- /dev/null +++ b/servers/rendering/renderer_rd/effects/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp new file mode 100644 index 0000000000..7eb15f418b --- /dev/null +++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp @@ -0,0 +1,280 @@ +/*************************************************************************/ +/* tone_mapper.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "tone_mapper.h" +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" +#include "servers/rendering/renderer_rd/storage_rd/material_storage.h" +#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h" + +using namespace RendererRD; + +ToneMapper::ToneMapper() { + { + // Initialize tonemapper + Vector tonemap_modes; + tonemap_modes.push_back("\n"); + tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n"); + tonemap_modes.push_back("\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define SUBPASS\n"); + tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n"); + + // multiview versions of our shaders + tonemap_modes.push_back("\n#define MULTIVIEW\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n"); + + tonemap.shader.initialize(tonemap_modes); + + if (!RendererCompositorRD::singleton->is_xr_enabled()) { + tonemap.shader.set_variant_enabled(TONEMAP_MODE_NORMAL_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, false); + } + + tonemap.shader_version = tonemap.shader.version_create(); + + for (int i = 0; i < TONEMAP_MODE_MAX; i++) { + if (tonemap.shader.is_variant_enabled(i)) { + tonemap.pipelines[i].setup(tonemap.shader.version_get_shader(tonemap.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } else { + tonemap.pipelines[i].clear(); + } + } + } + + // TODO maybe centralise this in mesh_storage? + { //create index array for copy shaders + Vector pv; + pv.resize(6 * 4); + { + uint8_t *w = pv.ptrw(); + int *p32 = (int *)w; + p32[0] = 0; + p32[1] = 1; + p32[2] = 2; + p32[3] = 0; + p32[4] = 2; + p32[5] = 3; + } + index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); + index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6); + } +} + +ToneMapper::~ToneMapper() { + RD::get_singleton()->free(index_buffer); //array gets freed as dependency + tonemap.shader.version_free(tonemap.shader_version); +} + +void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); + + tonemap.push_constant.use_bcs = p_settings.use_bcs; + tonemap.push_constant.bcs[0] = p_settings.brightness; + tonemap.push_constant.bcs[1] = p_settings.contrast; + tonemap.push_constant.bcs[2] = p_settings.saturation; + + tonemap.push_constant.use_glow = p_settings.use_glow; + tonemap.push_constant.glow_intensity = p_settings.glow_intensity; + tonemap.push_constant.glow_map_strength = p_settings.glow_map_strength; + tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something + tonemap.push_constant.glow_levels[1] = p_settings.glow_levels[1]; + tonemap.push_constant.glow_levels[2] = p_settings.glow_levels[2]; + tonemap.push_constant.glow_levels[3] = p_settings.glow_levels[3]; + tonemap.push_constant.glow_levels[4] = p_settings.glow_levels[4]; + tonemap.push_constant.glow_levels[5] = p_settings.glow_levels[5]; + tonemap.push_constant.glow_levels[6] = p_settings.glow_levels[6]; + tonemap.push_constant.glow_texture_size[0] = p_settings.glow_texture_size.x; + tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y; + tonemap.push_constant.glow_mode = p_settings.glow_mode; + + int mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL; + if (p_settings.use_1d_color_correction) { + mode += 2; + } + + tonemap.push_constant.tonemapper = p_settings.tonemap_mode; + tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; + tonemap.push_constant.exposure = p_settings.exposure; + tonemap.push_constant.white = p_settings.white; + tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey; + tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; + + tonemap.push_constant.use_color_correction = p_settings.use_color_correction; + + tonemap.push_constant.use_fxaa = p_settings.use_fxaa; + tonemap.push_constant.use_debanding = p_settings.use_debanding; + tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; + tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; + + if (p_settings.view_count > 1) { + // Use MULTIVIEW versions + mode += 6; + } + + RID default_shader = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + RID default_mipmap_shader = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_color; + u_source_color.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u_source_color.binding = 0; + u_source_color.append_id(default_shader); + u_source_color.append_id(p_source_color); + + RD::Uniform u_exposure_texture; + u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u_exposure_texture.binding = 0; + u_exposure_texture.append_id(default_shader); + u_exposure_texture.append_id(p_settings.exposure_texture); + + RD::Uniform u_glow_texture; + u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u_glow_texture.binding = 0; + u_glow_texture.append_id(default_mipmap_shader); + u_glow_texture.append_id(p_settings.glow_texture); + + RD::Uniform u_glow_map; + u_glow_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u_glow_map.binding = 1; + u_glow_map.append_id(default_mipmap_shader); + u_glow_map.append_id(p_settings.glow_map); + + RD::Uniform u_color_correction_texture; + u_color_correction_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u_color_correction_texture.binding = 0; + u_color_correction_texture.append_id(default_shader); + u_color_correction_texture.append_id(p_settings.color_correction_texture); + + RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode); + ERR_FAIL_COND(shader.is_null()); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass())); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_exposure_texture), 1); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_glow_texture, u_glow_map), 2); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + +void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) { + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); + + tonemap.push_constant.use_bcs = p_settings.use_bcs; + tonemap.push_constant.bcs[0] = p_settings.brightness; + tonemap.push_constant.bcs[1] = p_settings.contrast; + tonemap.push_constant.bcs[2] = p_settings.saturation; + + ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses."); + tonemap.push_constant.use_glow = p_settings.use_glow; + + int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS; + if (p_settings.view_count > 1) { + // Use MULTIVIEW versions + mode += 6; + } + + tonemap.push_constant.tonemapper = p_settings.tonemap_mode; + tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; + tonemap.push_constant.exposure = p_settings.exposure; + tonemap.push_constant.white = p_settings.white; + tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey; + + tonemap.push_constant.use_color_correction = p_settings.use_color_correction; + + tonemap.push_constant.use_debanding = p_settings.use_debanding; + tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; + + RID default_shader = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + RID default_mipmap_shader = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_color; + u_source_color.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT; + u_source_color.binding = 0; + u_source_color.append_id(p_source_color); + + RD::Uniform u_exposure_texture; + u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u_exposure_texture.binding = 0; + u_exposure_texture.append_id(default_shader); + u_exposure_texture.append_id(p_settings.exposure_texture); + + RD::Uniform u_glow_texture; + u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u_glow_texture.binding = 0; + u_glow_texture.append_id(default_mipmap_shader); + u_glow_texture.append_id(p_settings.glow_texture); + + RD::Uniform u_glow_map; + u_glow_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u_glow_map.binding = 1; + u_glow_map.append_id(default_mipmap_shader); + u_glow_map.append_id(p_settings.glow_map); + + RD::Uniform u_color_correction_texture; + u_color_correction_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u_color_correction_texture.binding = 0; + u_color_correction_texture.append_id(default_shader); + u_color_correction_texture.append_id(p_settings.color_correction_texture); + + RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode); + ERR_FAIL_COND(shader.is_null()); + + RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass())); + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0); + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 1, u_exposure_texture), 1); // should be set to a default texture, it's ignored + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 2, u_glow_texture, u_glow_map), 2); // should be set to a default texture, it's ignored + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3); + RD::get_singleton()->draw_list_bind_index_array(p_subpass_draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant)); + RD::get_singleton()->draw_list_draw(p_subpass_draw_list, true); +} diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.h b/servers/rendering/renderer_rd/effects/tone_mapper.h new file mode 100644 index 0000000000..357e814845 --- /dev/null +++ b/servers/rendering/renderer_rd/effects/tone_mapper.h @@ -0,0 +1,155 @@ +/*************************************************************************/ +/* tone_mapper.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TONE_MAPPER_RD_H +#define TONE_MAPPER_RD_H + +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/shaders/effects/tonemap.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" + +#include "servers/rendering_server.h" + +namespace RendererRD { + +class ToneMapper { +private: + enum TonemapMode { + TONEMAP_MODE_NORMAL, + TONEMAP_MODE_BICUBIC_GLOW_FILTER, + TONEMAP_MODE_1D_LUT, + TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT, + TONEMAP_MODE_SUBPASS, + TONEMAP_MODE_SUBPASS_1D_LUT, + + TONEMAP_MODE_NORMAL_MULTIVIEW, + TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, + TONEMAP_MODE_1D_LUT_MULTIVIEW, + TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, + TONEMAP_MODE_SUBPASS_MULTIVIEW, + TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, + + TONEMAP_MODE_MAX + }; + + struct TonemapPushConstant { + float bcs[3]; // 12 - 12 + uint32_t use_bcs; // 4 - 16 + + uint32_t use_glow; // 4 - 20 + uint32_t use_auto_exposure; // 4 - 24 + uint32_t use_color_correction; // 4 - 28 + uint32_t tonemapper; // 4 - 32 + + uint32_t glow_texture_size[2]; // 8 - 40 + float glow_intensity; // 4 - 44 + float glow_map_strength; // 4 - 48 + + uint32_t glow_mode; // 4 - 52 + float glow_levels[7]; // 28 - 80 + + float exposure; // 4 - 84 + float white; // 4 - 88 + float auto_exposure_grey; // 4 - 92 + float luminance_multiplier; // 4 - 96 + + float pixel_size[2]; // 8 - 104 + uint32_t use_fxaa; // 4 - 108 + uint32_t use_debanding; // 4 - 112 + }; + + /* tonemap actually writes to a framebuffer, which is + * better to do using the raster pipeline rather than + * compute, as that framebuffer might be in different formats + */ + struct Tonemap { + TonemapPushConstant push_constant; + TonemapShaderRD shader; + RID shader_version; + PipelineCacheRD pipelines[TONEMAP_MODE_MAX]; + } tonemap; + + RID index_buffer; + RID index_array; + +public: + ToneMapper(); + ~ToneMapper(); + + struct TonemapSettings { + bool use_glow = false; + enum GlowMode { + GLOW_MODE_ADD, + GLOW_MODE_SCREEN, + GLOW_MODE_SOFTLIGHT, + GLOW_MODE_REPLACE, + GLOW_MODE_MIX + }; + + GlowMode glow_mode = GLOW_MODE_ADD; + float glow_intensity = 1.0; + float glow_map_strength = 0.0f; + float glow_levels[7] = { 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 }; + Vector2i glow_texture_size; + bool glow_use_bicubic_upscale = false; + RID glow_texture; + RID glow_map; + + RS::EnvironmentToneMapper tonemap_mode = RS::ENV_TONE_MAPPER_LINEAR; + float exposure = 1.0; + float white = 1.0; + + bool use_auto_exposure = false; + float auto_exposure_grey = 0.5; + RID exposure_texture; + float luminance_multiplier = 1.0; + + bool use_bcs = false; + float brightness = 1.0; + float contrast = 1.0; + float saturation = 1.0; + + bool use_color_correction = false; + bool use_1d_color_correction = false; + RID color_correction_texture; + + bool use_fxaa = false; + bool use_debanding = false; + Vector2i texture_size; + uint32_t view_count = 1; + }; + + void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); + void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings); +}; + +} // namespace RendererRD + +#endif // !TONE_MAPPER_RD_H diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index a5a9dae0b9..f05027d569 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -70,28 +70,6 @@ RID EffectsRD::_get_uniform_set_from_image(RID p_image) { return uniform_set; } -RID EffectsRD::_get_uniform_set_for_input(RID p_texture) { - if (input_to_uniform_set_cache.has(p_texture)) { - RID uniform_set = input_to_uniform_set_cache[p_texture]; - if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - return uniform_set; - } - } - - Vector uniforms; - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT; - u.binding = 0; - u.append_id(p_texture); - uniforms.push_back(u); - // This is specific to our subpass shader - RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, TONEMAP_MODE_SUBPASS), 0); - - input_to_uniform_set_cache[p_texture] = uniform_set; - - return uniform_set; -} - RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { if (texture_to_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_uniform_set_cache[p_texture]; @@ -108,50 +86,13 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) u.append_id(p_texture); uniforms.push_back(u); // anything with the same configuration (one texture in binding 0 for set 0), is good - RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 0); + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, 0), 0); texture_to_uniform_set_cache[p_texture] = uniform_set; return uniform_set; } -RID EffectsRD::_get_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps) { - TexturePair tp; - tp.texture1 = p_texture1; - tp.texture2 = p_texture2; - - if (texture_pair_to_uniform_set_cache.has(tp)) { - RID uniform_set = texture_pair_to_uniform_set_cache[tp]; - if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - return uniform_set; - } - } - - Vector uniforms; - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; - u.binding = 0; - u.append_id(p_use_mipmaps ? default_mipmap_sampler : default_sampler); - u.append_id(p_texture1); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; - u.binding = 1; - u.append_id(p_use_mipmaps ? default_mipmap_sampler : default_sampler); - u.append_id(p_texture2); - uniforms.push_back(u); - } - // anything with the same configuration (one texture in binding 0 for set 0), is good - RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 2); - - texture_pair_to_uniform_set_cache[tp] = uniform_set; - - return uniform_set; -} - RID EffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { if (texture_to_compute_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_compute_uniform_set_cache[p_texture]; @@ -851,105 +792,6 @@ void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffe RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER); } -void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { - memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); - - tonemap.push_constant.use_bcs = p_settings.use_bcs; - tonemap.push_constant.bcs[0] = p_settings.brightness; - tonemap.push_constant.bcs[1] = p_settings.contrast; - tonemap.push_constant.bcs[2] = p_settings.saturation; - - tonemap.push_constant.use_glow = p_settings.use_glow; - tonemap.push_constant.glow_intensity = p_settings.glow_intensity; - tonemap.push_constant.glow_map_strength = p_settings.glow_map_strength; - tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something - tonemap.push_constant.glow_levels[1] = p_settings.glow_levels[1]; - tonemap.push_constant.glow_levels[2] = p_settings.glow_levels[2]; - tonemap.push_constant.glow_levels[3] = p_settings.glow_levels[3]; - tonemap.push_constant.glow_levels[4] = p_settings.glow_levels[4]; - tonemap.push_constant.glow_levels[5] = p_settings.glow_levels[5]; - tonemap.push_constant.glow_levels[6] = p_settings.glow_levels[6]; - tonemap.push_constant.glow_texture_size[0] = p_settings.glow_texture_size.x; - tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y; - tonemap.push_constant.glow_mode = p_settings.glow_mode; - - int mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL; - if (p_settings.use_1d_color_correction) { - mode += 2; - } - - tonemap.push_constant.tonemapper = p_settings.tonemap_mode; - tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; - tonemap.push_constant.exposure = p_settings.exposure; - tonemap.push_constant.white = p_settings.white; - tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey; - tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; - - tonemap.push_constant.use_color_correction = p_settings.use_color_correction; - - tonemap.push_constant.use_fxaa = p_settings.use_fxaa; - tonemap.push_constant.use_debanding = p_settings.use_debanding; - tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; - tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; - - if (p_settings.view_count > 1) { - // Use MULTIVIEW versions - mode += 6; - } - - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass())); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture_pair(p_settings.glow_texture, p_settings.glow_map, true), 2); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - - RD::get_singleton()->draw_list_set_push_constant(draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); -} - -void EffectsRD::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) { - memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); - - tonemap.push_constant.use_bcs = p_settings.use_bcs; - tonemap.push_constant.bcs[0] = p_settings.brightness; - tonemap.push_constant.bcs[1] = p_settings.contrast; - tonemap.push_constant.bcs[2] = p_settings.saturation; - - ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses."); - tonemap.push_constant.use_glow = p_settings.use_glow; - - int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS; - if (p_settings.view_count > 1) { - // Use MULTIVIEW versions - mode += 6; - } - - tonemap.push_constant.tonemapper = p_settings.tonemap_mode; - tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; - tonemap.push_constant.exposure = p_settings.exposure; - tonemap.push_constant.white = p_settings.white; - tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey; - - tonemap.push_constant.use_color_correction = p_settings.use_color_correction; - - tonemap.push_constant.use_debanding = p_settings.use_debanding; - tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; - - RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass())); - RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_for_input(p_source_color), 0); - RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); // should be set to a default texture, it's ignored - RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture_pair(p_settings.glow_texture, p_settings.glow_map, true), 2); // should be set to a default texture, it's ignored - RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3); - - RD::get_singleton()->draw_list_bind_index_array(p_subpass_draw_list, index_array); - - RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant)); - RD::get_singleton()->draw_list_draw(p_subpass_draw_list, true); -} - void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer."); @@ -2420,46 +2262,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { } } - { - // Initialize tonemapper - Vector tonemap_modes; - tonemap_modes.push_back("\n"); - tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n"); - tonemap_modes.push_back("\n#define USE_1D_LUT\n"); - tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); - tonemap_modes.push_back("\n#define SUBPASS\n"); - tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n"); - - // multiview versions of our shaders - tonemap_modes.push_back("\n#define MULTIVIEW\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n"); - - tonemap.shader.initialize(tonemap_modes); - - if (!RendererCompositorRD::singleton->is_xr_enabled()) { - tonemap.shader.set_variant_enabled(TONEMAP_MODE_NORMAL_MULTIVIEW, false); - tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false); - tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false); - tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false); - tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_MULTIVIEW, false); - tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, false); - } - - tonemap.shader_version = tonemap.shader.version_create(); - - for (int i = 0; i < TONEMAP_MODE_MAX; i++) { - if (tonemap.shader.is_variant_enabled(i)) { - tonemap.pipelines[i].setup(tonemap.shader.version_get_shader(tonemap.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); - } else { - tonemap.pipelines[i].clear(); - } - } - } - if (prefer_raster_effects) { Vector luminance_reduce_modes; luminance_reduce_modes.push_back("\n#define FIRST_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FIRST @@ -3076,5 +2878,4 @@ EffectsRD::~EffectsRD() { copy_to_fb.shader.version_free(copy_to_fb.shader_version); cube_to_dp.shader.version_free(cube_to_dp.shader_version); sort.shader.version_free(sort.shader_version); - tonemap.shader.version_free(tonemap.shader_version); } diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index eca5e09800..8174e30238 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -65,7 +65,6 @@ #include "servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/ssil_interleave.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/tonemap.glsl.gen.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering_server.h" @@ -248,61 +247,6 @@ private: PipelineCacheRD raster_pipeline; } roughness; - enum TonemapMode { - TONEMAP_MODE_NORMAL, - TONEMAP_MODE_BICUBIC_GLOW_FILTER, - TONEMAP_MODE_1D_LUT, - TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT, - TONEMAP_MODE_SUBPASS, - TONEMAP_MODE_SUBPASS_1D_LUT, - - TONEMAP_MODE_NORMAL_MULTIVIEW, - TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, - TONEMAP_MODE_1D_LUT_MULTIVIEW, - TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, - TONEMAP_MODE_SUBPASS_MULTIVIEW, - TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, - - TONEMAP_MODE_MAX - }; - - struct TonemapPushConstant { - float bcs[3]; // 12 - 12 - uint32_t use_bcs; // 4 - 16 - - uint32_t use_glow; // 4 - 20 - uint32_t use_auto_exposure; // 4 - 24 - uint32_t use_color_correction; // 4 - 28 - uint32_t tonemapper; // 4 - 32 - - uint32_t glow_texture_size[2]; // 8 - 40 - float glow_intensity; // 4 - 44 - float glow_map_strength; // 4 - 48 - - uint32_t glow_mode; // 4 - 52 - float glow_levels[7]; // 28 - 80 - - float exposure; // 4 - 84 - float white; // 4 - 88 - float auto_exposure_grey; // 4 - 92 - float luminance_multiplier; // 4 - 96 - - float pixel_size[2]; // 8 - 104 - uint32_t use_fxaa; // 4 - 108 - uint32_t use_debanding; // 4 - 112 - }; - - /* tonemap actually writes to a framebuffer, which is - * better to do using the raster pipeline rather than - * compute, as that framebuffer might be in different formats - */ - struct Tonemap { - TonemapPushConstant push_constant; - TonemapShaderRD shader; - RID shader_version; - PipelineCacheRD pipelines[TONEMAP_MODE_MAX]; - } tonemap; - enum LuminanceReduceMode { LUMINANCE_REDUCE_READ, LUMINANCE_REDUCE, @@ -884,9 +828,7 @@ private: Map texture_sampler_to_compute_uniform_set_cache; RID _get_uniform_set_from_image(RID p_texture); - RID _get_uniform_set_for_input(RID p_texture); RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); - RID _get_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler); RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false); @@ -936,49 +878,6 @@ public: void bokeh_dof(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); void bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); - struct TonemapSettings { - bool use_glow = false; - enum GlowMode { - GLOW_MODE_ADD, - GLOW_MODE_SCREEN, - GLOW_MODE_SOFTLIGHT, - GLOW_MODE_REPLACE, - GLOW_MODE_MIX - }; - - GlowMode glow_mode = GLOW_MODE_ADD; - float glow_intensity = 1.0; - float glow_map_strength = 0.0f; - float glow_levels[7] = { 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 }; - Vector2i glow_texture_size; - bool glow_use_bicubic_upscale = false; - RID glow_texture; - RID glow_map; - - RS::EnvironmentToneMapper tonemap_mode = RS::ENV_TONE_MAPPER_LINEAR; - float exposure = 1.0; - float white = 1.0; - - bool use_auto_exposure = false; - float auto_exposure_grey = 0.5; - RID exposure_texture; - float luminance_multiplier = 1.0; - - bool use_bcs = false; - float brightness = 1.0; - float contrast = 1.0; - float saturation = 1.0; - - bool use_color_correction = false; - bool use_1d_color_correction = false; - RID color_correction_texture; - - bool use_fxaa = false; - bool use_debanding = false; - Vector2i texture_size; - uint32_t view_count = 1; - }; - struct SSAOSettings { float radius = 1.0; float intensity = 2.0; @@ -1017,9 +916,6 @@ public: Size2i quarter_screen_size = Size2i(); }; - void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); - void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings); - void downsample_depth(RID p_depth_buffer, const Vector &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const CameraMatrix &p_projection); void gather_ssao(RD::ComputeListID p_compute_list, const Vector p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index bdbc228bde..535f5ad9c5 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -2486,7 +2486,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende { RD::get_singleton()->draw_command_begin_label("Tonemap"); - EffectsRD::TonemapSettings tonemap; + RendererRD::ToneMapper::TonemapSettings tonemap; if (can_use_effects && env && env->auto_exposure && rb->luminance.current.is_valid()) { tonemap.use_auto_exposure = true; @@ -2498,7 +2498,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende if (can_use_effects && env && env->glow_enabled) { tonemap.use_glow = true; - tonemap.glow_mode = EffectsRD::TonemapSettings::GlowMode(env->glow_blend_mode); + tonemap.glow_mode = RendererRD::ToneMapper::TonemapSettings::GlowMode(env->glow_blend_mode); tonemap.glow_intensity = env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_MIX ? env->glow_mix : env->glow_intensity; for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) { tonemap.glow_levels[i] = env->glow_levels[i]; @@ -2556,7 +2556,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier(); tonemap.view_count = p_render_data->view_count; - storage->get_effects()->tonemapper(rb->internal_texture, texture_storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); + tone_mapper->tonemapper(rb->internal_texture, texture_storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); RD::get_singleton()->draw_command_end_label(); } @@ -2587,7 +2587,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass(); - EffectsRD::TonemapSettings tonemap; + RendererRD::ToneMapper::TonemapSettings tonemap; if (env) { tonemap.tonemap_mode = env->tone_mapper; @@ -2637,7 +2637,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier(); tonemap.view_count = p_render_data->view_count; - storage->get_effects()->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap); + tone_mapper->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap); RD::get_singleton()->draw_command_end_label(); } @@ -5838,11 +5838,17 @@ void fog() { light_projectors_set_filter(RS::LightProjectorFilter(int(GLOBAL_GET("rendering/textures/light_projectors/filter")))); cull_argument.set_page_pool(&cull_argument_pool); + + tone_mapper = memnew(RendererRD::ToneMapper); } RendererSceneRenderRD::~RendererSceneRenderRD() { RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + if (tone_mapper) { + memdelete(tone_mapper); + } + for (const KeyValue &E : shadow_cubemaps) { RD::get_singleton()->free(E.value.cubemap); } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index b2c8daffb1..3bfe37b413 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -35,6 +35,7 @@ #include "core/templates/rid_owner.h" #include "servers/rendering/renderer_compositor.h" #include "servers/rendering/renderer_rd/cluster_builder_rd.h" +#include "servers/rendering/renderer_rd/effects/tone_mapper.h" #include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" #include "servers/rendering/renderer_rd/renderer_scene_gi_rd.h" #include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h" @@ -93,6 +94,7 @@ class RendererSceneRenderRD : public RendererSceneRender { protected: RendererStorageRD *storage = nullptr; + RendererRD::ToneMapper *tone_mapper = nullptr; double time; double time_step = 0; diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub index fc513d3fb9..acb843bfb6 100644 --- a/servers/rendering/renderer_rd/shaders/SCsub +++ b/servers/rendering/renderer_rd/shaders/SCsub @@ -15,3 +15,5 @@ if "RD_GLSL" in env["BUILDERS"]: # compile shaders for glsl_file in glsl_files: env.RD_GLSL(glsl_file) + +SConscript("effects/SCsub") diff --git a/servers/rendering/renderer_rd/shaders/effects/SCsub b/servers/rendering/renderer_rd/shaders/effects/SCsub new file mode 100644 index 0000000000..fc513d3fb9 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/SCsub @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +Import("env") + +if "RD_GLSL" in env["BUILDERS"]: + # find all include files + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + + # find all shader code(all glsl files excluding our include files) + glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] + + # make sure we recompile shaders if include files change + env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files) + + # compile shaders + for glsl_file in glsl_files: + env.RD_GLSL(glsl_file) diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl new file mode 100644 index 0000000000..19a9350137 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl @@ -0,0 +1,457 @@ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#endif +#endif + +layout(location = 0) out vec2 uv_interp; + +void main() { + vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + uv_interp = base_arr[gl_VertexIndex]; + gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); +} + +#[fragment] + +#version 450 + +#VERSION_DEFINES + +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#endif //MULTIVIEW + +layout(location = 0) in vec2 uv_interp; + +#ifdef SUBPASS +layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color; +#elif defined(MULTIVIEW) +layout(set = 0, binding = 0) uniform sampler2DArray source_color; +#else +layout(set = 0, binding = 0) uniform sampler2D source_color; +#endif + +layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; +layout(set = 2, binding = 0) uniform sampler2D source_glow; +layout(set = 2, binding = 1) uniform sampler2D glow_map; + +#ifdef USE_1D_LUT +layout(set = 3, binding = 0) uniform sampler2D source_color_correction; +#else +layout(set = 3, binding = 0) uniform sampler3D source_color_correction; +#endif + +layout(push_constant, std430) uniform Params { + vec3 bcs; + bool use_bcs; + + bool use_glow; + bool use_auto_exposure; + bool use_color_correction; + uint tonemapper; + + uvec2 glow_texture_size; + float glow_intensity; + float glow_map_strength; + + uint glow_mode; + float glow_levels[7]; + + float exposure; + float white; + float auto_exposure_grey; + float luminance_multiplier; + + vec2 pixel_size; + bool use_fxaa; + bool use_debanding; +} +params; + +layout(location = 0) out vec4 frag_color; + +#ifdef USE_GLOW_FILTER_BICUBIC +// w0, w1, w2, and w3 are the four cubic B-spline basis functions +float w0(float a) { + return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f); +} + +float w1(float a) { + return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f); +} + +float w2(float a) { + return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f); +} + +float w3(float a) { + return (1.0f / 6.0f) * (a * a * a); +} + +// g0 and g1 are the two amplitude functions +float g0(float a) { + return w0(a) + w1(a); +} + +float g1(float a) { + return w2(a) + w3(a); +} + +// h0 and h1 are the two offset functions +float h0(float a) { + return -1.0f + w1(a) / (w0(a) + w1(a)); +} + +float h1(float a) { + return 1.0f + w3(a) / (w2(a) + w3(a)); +} + +vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { + float lod = float(p_lod); + vec2 tex_size = vec2(params.glow_texture_size >> p_lod); + vec2 pixel_size = vec2(1.0f) / tex_size; + + uv = uv * tex_size + vec2(0.5f); + + vec2 iuv = floor(uv); + vec2 fuv = fract(uv); + + float g0x = g0(fuv.x); + float g1x = g1(fuv.x); + float h0x = h0(fuv.x); + float h1x = h1(fuv.x); + float h0y = h0(fuv.y); + float h1y = h1(fuv.y); + + vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5f)) * pixel_size; + vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5f)) * pixel_size; + vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; + vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; + + return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) + + (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); +} + +#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) + +#else + +#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod)) + +#endif + +vec3 tonemap_filmic(vec3 color, float white) { + // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers + // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values) + // has no effect on the curve's general shape or visual properties + const float exposure_bias = 2.0f; + const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance + const float B = 0.30f * exposure_bias; + const float C = 0.10f; + const float D = 0.20f; + const float E = 0.01f; + const float F = 0.30f; + + vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F; + float white_tonemapped = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F; + + return color_tonemapped / white_tonemapped; +} + +// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl +// (MIT License). +vec3 tonemap_aces(vec3 color, float white) { + const float exposure_bias = 1.8f; + const float A = 0.0245786f; + const float B = 0.000090537f; + const float C = 0.983729f; + const float D = 0.432951f; + const float E = 0.238081f; + + // Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias` + const mat3 rgb_to_rrt = mat3( + vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias), + vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias), + vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias)); + + const mat3 odt_to_rgb = mat3( + vec3(1.60475f, -0.53108f, -0.07367f), + vec3(-0.10208f, 1.10813f, -0.00605f), + vec3(-0.00327f, -0.07276f, 1.07602f)); + + color *= rgb_to_rrt; + vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E); + color_tonemapped *= odt_to_rgb; + + white *= exposure_bias; + float white_tonemapped = (white * (white + A) - B) / (white * (C * white + D) + E); + + return color_tonemapped / white_tonemapped; +} + +vec3 tonemap_reinhard(vec3 color, float white) { + return (white * color + color) / (color * white + white); +} + +vec3 linear_to_srgb(vec3 color) { + //if going to srgb, clamp from 0 to 1. + color = clamp(color, vec3(0.0), vec3(1.0)); + const vec3 a = vec3(0.055f); + return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); +} + +#define TONEMAPPER_LINEAR 0 +#define TONEMAPPER_REINHARD 1 +#define TONEMAPPER_FILMIC 2 +#define TONEMAPPER_ACES 3 + +vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color + // Ensure color values passed to tonemappers are positive. + // They can be negative in the case of negative lights, which leads to undesired behavior. + if (params.tonemapper == TONEMAPPER_LINEAR) { + return color; + } else if (params.tonemapper == TONEMAPPER_REINHARD) { + return tonemap_reinhard(max(vec3(0.0f), color), white); + } else if (params.tonemapper == TONEMAPPER_FILMIC) { + return tonemap_filmic(max(vec3(0.0f), color), white); + } else { // TONEMAPPER_ACES + return tonemap_aces(max(vec3(0.0f), color), white); + } +} + +vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels + vec3 glow = vec3(0.0f); + + if (params.glow_levels[0] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb * params.glow_levels[0]; + } + + if (params.glow_levels[1] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb * params.glow_levels[1]; + } + + if (params.glow_levels[2] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb * params.glow_levels[2]; + } + + if (params.glow_levels[3] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb * params.glow_levels[3]; + } + + if (params.glow_levels[4] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb * params.glow_levels[4]; + } + + if (params.glow_levels[5] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb * params.glow_levels[5]; + } + + if (params.glow_levels[6] > 0.0001) { + glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb * params.glow_levels[6]; + } + + return glow; +} + +#define GLOW_MODE_ADD 0 +#define GLOW_MODE_SCREEN 1 +#define GLOW_MODE_SOFTLIGHT 2 +#define GLOW_MODE_REPLACE 3 +#define GLOW_MODE_MIX 4 + +vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode + if (params.glow_mode == GLOW_MODE_ADD) { + return color + glow; + } else if (params.glow_mode == GLOW_MODE_SCREEN) { + //need color clamping + return max((color + glow) - (color * glow), vec3(0.0)); + } else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) { + //need color clamping + glow = glow * vec3(0.5f) + vec3(0.5f); + + color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r))); + color.g = (glow.g <= 0.5f) ? (color.g - (1.0f - 2.0f * glow.g) * color.g * (1.0f - color.g)) : (((glow.g > 0.5f) && (color.g <= 0.25f)) ? (color.g + (2.0f * glow.g - 1.0f) * (4.0f * color.g * (4.0f * color.g + 1.0f) * (color.g - 1.0f) + 7.0f * color.g)) : (color.g + (2.0f * glow.g - 1.0f) * (sqrt(color.g) - color.g))); + color.b = (glow.b <= 0.5f) ? (color.b - (1.0f - 2.0f * glow.b) * color.b * (1.0f - color.b)) : (((glow.b > 0.5f) && (color.b <= 0.25f)) ? (color.b + (2.0f * glow.b - 1.0f) * (4.0f * color.b * (4.0f * color.b + 1.0f) * (color.b - 1.0f) + 7.0f * color.b)) : (color.b + (2.0f * glow.b - 1.0f) * (sqrt(color.b) - color.b))); + return color; + } else { //replace + return glow; + } +} + +vec3 apply_bcs(vec3 color, vec3 bcs) { + color = mix(vec3(0.0f), color, bcs.x); + color = mix(vec3(0.5f), color, bcs.y); + color = mix(vec3(dot(vec3(1.0f), color) * 0.33333f), color, bcs.z); + + return color; +} +#ifdef USE_1D_LUT +vec3 apply_color_correction(vec3 color) { + color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r; + color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g; + color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b; + return color; +} +#else +vec3 apply_color_correction(vec3 color) { + return textureLod(source_color_correction, color, 0.0).rgb; +} +#endif + +#ifndef SUBPASS +vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { + const float FXAA_REDUCE_MIN = (1.0 / 128.0); + const float FXAA_REDUCE_MUL = (1.0 / 8.0); + const float FXAA_SPAN_MAX = 8.0; + +#ifdef MULTIVIEW + vec3 rgbNW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; + vec3 rgbNE = textureLod(source_color, vec3(uv_interp + vec2(1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; + vec3 rgbSW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; + vec3 rgbSE = textureLod(source_color, vec3(uv_interp + vec2(1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; +#else + vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; + vec3 rgbNE = textureLod(source_color, uv_interp + vec2(1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; + vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; + vec3 rgbSE = textureLod(source_color, uv_interp + vec2(1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; +#endif + vec3 rgbM = color; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), + FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * + params.pixel_size; + +#ifdef MULTIVIEW + vec3 rgbA = 0.5 * exposure * (textureLod(source_color, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz) * params.luminance_multiplier; + vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz) * params.luminance_multiplier; +#else + vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * params.luminance_multiplier; + vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz) * params.luminance_multiplier; +#endif + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) { + return rgbA; + } else { + return rgbB; + } +} +#endif // !SUBPASS + +// From https://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf +// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom) +// NOTE: `frag_coord` is in pixels (i.e. not normalized UV). +vec3 screen_space_dither(vec2 frag_coord) { + // Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR. + vec3 dither = vec3(dot(vec2(171.0, 231.0), frag_coord)); + dither.rgb = fract(dither.rgb / vec3(103.0, 71.0, 97.0)); + + // Subtract 0.5 to avoid slightly brightening the whole viewport. + return (dither.rgb - 0.5) / 255.0; +} + +void main() { +#ifdef SUBPASS + // SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer + vec3 color = subpassLoad(input_color).rgb * params.luminance_multiplier; +#elif defined(MULTIVIEW) + vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb * params.luminance_multiplier; +#else + vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb * params.luminance_multiplier; +#endif + + // Exposure + + float exposure = params.exposure; + +#ifndef SUBPASS + if (params.use_auto_exposure) { + exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r * params.luminance_multiplier / params.auto_exposure_grey); + } +#endif + + color *= exposure; + + // Early Tonemap & SRGB Conversion +#ifndef SUBPASS + if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) { + vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier; + if (params.glow_map_strength > 0.001) { + glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); + } + color.rgb = mix(color.rgb, glow, params.glow_intensity); + } + + if (params.use_fxaa) { + color = do_fxaa(color, exposure, uv_interp); + } +#endif + + if (params.use_debanding) { + // For best results, debanding should be done before tonemapping. + // Otherwise, we're adding noise to an already-quantized image. + color += screen_space_dither(gl_FragCoord.xy); + } + + color = apply_tonemapping(color, params.white); + + color = linear_to_srgb(color); // regular linear -> SRGB conversion + +#ifndef SUBPASS + // Glow + if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) { + vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier; + if (params.glow_map_strength > 0.001) { + glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); + } + + // high dynamic range -> SRGB + glow = apply_tonemapping(glow, params.white); + glow = linear_to_srgb(glow); + + color = apply_glow(color, glow); + } +#endif + + // Additional effects + + if (params.use_bcs) { + color = apply_bcs(color, params.bcs); + } + + if (params.use_color_correction) { + color = apply_color_correction(color); + } + + frag_color = vec4(color, 1.0f); +} diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl deleted file mode 100644 index 19a9350137..0000000000 --- a/servers/rendering/renderer_rd/shaders/tonemap.glsl +++ /dev/null @@ -1,457 +0,0 @@ -#[vertex] - -#version 450 - -#VERSION_DEFINES - -#ifdef MULTIVIEW -#ifdef has_VK_KHR_multiview -#extension GL_EXT_multiview : enable -#endif -#endif - -layout(location = 0) out vec2 uv_interp; - -void main() { - vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); - uv_interp = base_arr[gl_VertexIndex]; - gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0); -} - -#[fragment] - -#version 450 - -#VERSION_DEFINES - -#ifdef MULTIVIEW -#ifdef has_VK_KHR_multiview -#extension GL_EXT_multiview : enable -#define ViewIndex gl_ViewIndex -#else // has_VK_KHR_multiview -#define ViewIndex 0 -#endif // has_VK_KHR_multiview -#endif //MULTIVIEW - -layout(location = 0) in vec2 uv_interp; - -#ifdef SUBPASS -layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color; -#elif defined(MULTIVIEW) -layout(set = 0, binding = 0) uniform sampler2DArray source_color; -#else -layout(set = 0, binding = 0) uniform sampler2D source_color; -#endif - -layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; -layout(set = 2, binding = 0) uniform sampler2D source_glow; -layout(set = 2, binding = 1) uniform sampler2D glow_map; - -#ifdef USE_1D_LUT -layout(set = 3, binding = 0) uniform sampler2D source_color_correction; -#else -layout(set = 3, binding = 0) uniform sampler3D source_color_correction; -#endif - -layout(push_constant, std430) uniform Params { - vec3 bcs; - bool use_bcs; - - bool use_glow; - bool use_auto_exposure; - bool use_color_correction; - uint tonemapper; - - uvec2 glow_texture_size; - float glow_intensity; - float glow_map_strength; - - uint glow_mode; - float glow_levels[7]; - - float exposure; - float white; - float auto_exposure_grey; - float luminance_multiplier; - - vec2 pixel_size; - bool use_fxaa; - bool use_debanding; -} -params; - -layout(location = 0) out vec4 frag_color; - -#ifdef USE_GLOW_FILTER_BICUBIC -// w0, w1, w2, and w3 are the four cubic B-spline basis functions -float w0(float a) { - return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f); -} - -float w1(float a) { - return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f); -} - -float w2(float a) { - return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f); -} - -float w3(float a) { - return (1.0f / 6.0f) * (a * a * a); -} - -// g0 and g1 are the two amplitude functions -float g0(float a) { - return w0(a) + w1(a); -} - -float g1(float a) { - return w2(a) + w3(a); -} - -// h0 and h1 are the two offset functions -float h0(float a) { - return -1.0f + w1(a) / (w0(a) + w1(a)); -} - -float h1(float a) { - return 1.0f + w3(a) / (w2(a) + w3(a)); -} - -vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { - float lod = float(p_lod); - vec2 tex_size = vec2(params.glow_texture_size >> p_lod); - vec2 pixel_size = vec2(1.0f) / tex_size; - - uv = uv * tex_size + vec2(0.5f); - - vec2 iuv = floor(uv); - vec2 fuv = fract(uv); - - float g0x = g0(fuv.x); - float g1x = g1(fuv.x); - float h0x = h0(fuv.x); - float h1x = h1(fuv.x); - float h0y = h0(fuv.y); - float h1y = h1(fuv.y); - - vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5f)) * pixel_size; - vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5f)) * pixel_size; - vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; - vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; - - return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) + - (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); -} - -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) - -#else - -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod)) - -#endif - -vec3 tonemap_filmic(vec3 color, float white) { - // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers - // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values) - // has no effect on the curve's general shape or visual properties - const float exposure_bias = 2.0f; - const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance - const float B = 0.30f * exposure_bias; - const float C = 0.10f; - const float D = 0.20f; - const float E = 0.01f; - const float F = 0.30f; - - vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F; - float white_tonemapped = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F; - - return color_tonemapped / white_tonemapped; -} - -// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl -// (MIT License). -vec3 tonemap_aces(vec3 color, float white) { - const float exposure_bias = 1.8f; - const float A = 0.0245786f; - const float B = 0.000090537f; - const float C = 0.983729f; - const float D = 0.432951f; - const float E = 0.238081f; - - // Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias` - const mat3 rgb_to_rrt = mat3( - vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias), - vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias), - vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias)); - - const mat3 odt_to_rgb = mat3( - vec3(1.60475f, -0.53108f, -0.07367f), - vec3(-0.10208f, 1.10813f, -0.00605f), - vec3(-0.00327f, -0.07276f, 1.07602f)); - - color *= rgb_to_rrt; - vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E); - color_tonemapped *= odt_to_rgb; - - white *= exposure_bias; - float white_tonemapped = (white * (white + A) - B) / (white * (C * white + D) + E); - - return color_tonemapped / white_tonemapped; -} - -vec3 tonemap_reinhard(vec3 color, float white) { - return (white * color + color) / (color * white + white); -} - -vec3 linear_to_srgb(vec3 color) { - //if going to srgb, clamp from 0 to 1. - color = clamp(color, vec3(0.0), vec3(1.0)); - const vec3 a = vec3(0.055f); - return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); -} - -#define TONEMAPPER_LINEAR 0 -#define TONEMAPPER_REINHARD 1 -#define TONEMAPPER_FILMIC 2 -#define TONEMAPPER_ACES 3 - -vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color - // Ensure color values passed to tonemappers are positive. - // They can be negative in the case of negative lights, which leads to undesired behavior. - if (params.tonemapper == TONEMAPPER_LINEAR) { - return color; - } else if (params.tonemapper == TONEMAPPER_REINHARD) { - return tonemap_reinhard(max(vec3(0.0f), color), white); - } else if (params.tonemapper == TONEMAPPER_FILMIC) { - return tonemap_filmic(max(vec3(0.0f), color), white); - } else { // TONEMAPPER_ACES - return tonemap_aces(max(vec3(0.0f), color), white); - } -} - -vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels - vec3 glow = vec3(0.0f); - - if (params.glow_levels[0] > 0.0001) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb * params.glow_levels[0]; - } - - if (params.glow_levels[1] > 0.0001) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb * params.glow_levels[1]; - } - - if (params.glow_levels[2] > 0.0001) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb * params.glow_levels[2]; - } - - if (params.glow_levels[3] > 0.0001) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb * params.glow_levels[3]; - } - - if (params.glow_levels[4] > 0.0001) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb * params.glow_levels[4]; - } - - if (params.glow_levels[5] > 0.0001) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb * params.glow_levels[5]; - } - - if (params.glow_levels[6] > 0.0001) { - glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb * params.glow_levels[6]; - } - - return glow; -} - -#define GLOW_MODE_ADD 0 -#define GLOW_MODE_SCREEN 1 -#define GLOW_MODE_SOFTLIGHT 2 -#define GLOW_MODE_REPLACE 3 -#define GLOW_MODE_MIX 4 - -vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode - if (params.glow_mode == GLOW_MODE_ADD) { - return color + glow; - } else if (params.glow_mode == GLOW_MODE_SCREEN) { - //need color clamping - return max((color + glow) - (color * glow), vec3(0.0)); - } else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) { - //need color clamping - glow = glow * vec3(0.5f) + vec3(0.5f); - - color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r))); - color.g = (glow.g <= 0.5f) ? (color.g - (1.0f - 2.0f * glow.g) * color.g * (1.0f - color.g)) : (((glow.g > 0.5f) && (color.g <= 0.25f)) ? (color.g + (2.0f * glow.g - 1.0f) * (4.0f * color.g * (4.0f * color.g + 1.0f) * (color.g - 1.0f) + 7.0f * color.g)) : (color.g + (2.0f * glow.g - 1.0f) * (sqrt(color.g) - color.g))); - color.b = (glow.b <= 0.5f) ? (color.b - (1.0f - 2.0f * glow.b) * color.b * (1.0f - color.b)) : (((glow.b > 0.5f) && (color.b <= 0.25f)) ? (color.b + (2.0f * glow.b - 1.0f) * (4.0f * color.b * (4.0f * color.b + 1.0f) * (color.b - 1.0f) + 7.0f * color.b)) : (color.b + (2.0f * glow.b - 1.0f) * (sqrt(color.b) - color.b))); - return color; - } else { //replace - return glow; - } -} - -vec3 apply_bcs(vec3 color, vec3 bcs) { - color = mix(vec3(0.0f), color, bcs.x); - color = mix(vec3(0.5f), color, bcs.y); - color = mix(vec3(dot(vec3(1.0f), color) * 0.33333f), color, bcs.z); - - return color; -} -#ifdef USE_1D_LUT -vec3 apply_color_correction(vec3 color) { - color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r; - color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g; - color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b; - return color; -} -#else -vec3 apply_color_correction(vec3 color) { - return textureLod(source_color_correction, color, 0.0).rgb; -} -#endif - -#ifndef SUBPASS -vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { - const float FXAA_REDUCE_MIN = (1.0 / 128.0); - const float FXAA_REDUCE_MUL = (1.0 / 8.0); - const float FXAA_SPAN_MAX = 8.0; - -#ifdef MULTIVIEW - vec3 rgbNW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbNE = textureLod(source_color, vec3(uv_interp + vec2(1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbSW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbSE = textureLod(source_color, vec3(uv_interp + vec2(1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; -#else - vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbNE = textureLod(source_color, uv_interp + vec2(1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbSE = textureLod(source_color, uv_interp + vec2(1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; -#endif - vec3 rgbM = color; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), - FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * - params.pixel_size; - -#ifdef MULTIVIEW - vec3 rgbA = 0.5 * exposure * (textureLod(source_color, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz) * params.luminance_multiplier; - vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz) * params.luminance_multiplier; -#else - vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * params.luminance_multiplier; - vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz) * params.luminance_multiplier; -#endif - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) { - return rgbA; - } else { - return rgbB; - } -} -#endif // !SUBPASS - -// From https://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf -// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom) -// NOTE: `frag_coord` is in pixels (i.e. not normalized UV). -vec3 screen_space_dither(vec2 frag_coord) { - // Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR. - vec3 dither = vec3(dot(vec2(171.0, 231.0), frag_coord)); - dither.rgb = fract(dither.rgb / vec3(103.0, 71.0, 97.0)); - - // Subtract 0.5 to avoid slightly brightening the whole viewport. - return (dither.rgb - 0.5) / 255.0; -} - -void main() { -#ifdef SUBPASS - // SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer - vec3 color = subpassLoad(input_color).rgb * params.luminance_multiplier; -#elif defined(MULTIVIEW) - vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb * params.luminance_multiplier; -#else - vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb * params.luminance_multiplier; -#endif - - // Exposure - - float exposure = params.exposure; - -#ifndef SUBPASS - if (params.use_auto_exposure) { - exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r * params.luminance_multiplier / params.auto_exposure_grey); - } -#endif - - color *= exposure; - - // Early Tonemap & SRGB Conversion -#ifndef SUBPASS - if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) { - vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier; - if (params.glow_map_strength > 0.001) { - glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); - } - color.rgb = mix(color.rgb, glow, params.glow_intensity); - } - - if (params.use_fxaa) { - color = do_fxaa(color, exposure, uv_interp); - } -#endif - - if (params.use_debanding) { - // For best results, debanding should be done before tonemapping. - // Otherwise, we're adding noise to an already-quantized image. - color += screen_space_dither(gl_FragCoord.xy); - } - - color = apply_tonemapping(color, params.white); - - color = linear_to_srgb(color); // regular linear -> SRGB conversion - -#ifndef SUBPASS - // Glow - if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) { - vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier; - if (params.glow_map_strength > 0.001) { - glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength); - } - - // high dynamic range -> SRGB - glow = apply_tonemapping(glow, params.white); - glow = linear_to_srgb(glow); - - color = apply_glow(color, glow); - } -#endif - - // Additional effects - - if (params.use_bcs) { - color = apply_bcs(color, params.bcs); - } - - if (params.use_color_correction) { - color = apply_color_correction(color); - } - - frag_color = vec4(color, 1.0f); -} -- cgit v1.2.3