| 1 | /**************************************************************************/ |
| 2 | /* tone_mapper.cpp */ |
| 3 | /**************************************************************************/ |
| 4 | /* This file is part of: */ |
| 5 | /* GODOT ENGINE */ |
| 6 | /* https://godotengine.org */ |
| 7 | /**************************************************************************/ |
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
| 10 | /* */ |
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
| 12 | /* a copy of this software and associated documentation files (the */ |
| 13 | /* "Software"), to deal in the Software without restriction, including */ |
| 14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
| 16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
| 17 | /* the following conditions: */ |
| 18 | /* */ |
| 19 | /* The above copyright notice and this permission notice shall be */ |
| 20 | /* included in all copies or substantial portions of the Software. */ |
| 21 | /* */ |
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| 29 | /**************************************************************************/ |
| 30 | |
| 31 | #include "tone_mapper.h" |
| 32 | #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" |
| 33 | #include "servers/rendering/renderer_rd/storage_rd/material_storage.h" |
| 34 | #include "servers/rendering/renderer_rd/uniform_set_cache_rd.h" |
| 35 | |
| 36 | using namespace RendererRD; |
| 37 | |
| 38 | ToneMapper::ToneMapper() { |
| 39 | { |
| 40 | // Initialize tonemapper |
| 41 | Vector<String> tonemap_modes; |
| 42 | tonemap_modes.push_back("\n" ); |
| 43 | tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n" ); |
| 44 | tonemap_modes.push_back("\n#define USE_1D_LUT\n" ); |
| 45 | tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n" ); |
| 46 | tonemap_modes.push_back("\n#define SUBPASS\n" ); |
| 47 | tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n" ); |
| 48 | |
| 49 | // multiview versions of our shaders |
| 50 | tonemap_modes.push_back("\n#define MULTIVIEW\n" ); |
| 51 | tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n" ); |
| 52 | tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n" ); |
| 53 | tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n" ); |
| 54 | tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n" ); |
| 55 | tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n" ); |
| 56 | |
| 57 | tonemap.shader.initialize(tonemap_modes); |
| 58 | |
| 59 | if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) { |
| 60 | tonemap.shader.set_variant_enabled(TONEMAP_MODE_NORMAL_MULTIVIEW, false); |
| 61 | tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false); |
| 62 | tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false); |
| 63 | tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false); |
| 64 | tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_MULTIVIEW, false); |
| 65 | tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, false); |
| 66 | } |
| 67 | |
| 68 | tonemap.shader_version = tonemap.shader.version_create(); |
| 69 | |
| 70 | for (int i = 0; i < TONEMAP_MODE_MAX; i++) { |
| 71 | if (tonemap.shader.is_variant_enabled(i)) { |
| 72 | 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); |
| 73 | } else { |
| 74 | tonemap.pipelines[i].clear(); |
| 75 | } |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | ToneMapper::~ToneMapper() { |
| 81 | tonemap.shader.version_free(tonemap.shader_version); |
| 82 | } |
| 83 | |
| 84 | void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { |
| 85 | UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); |
| 86 | ERR_FAIL_NULL(uniform_set_cache); |
| 87 | MaterialStorage *material_storage = MaterialStorage::get_singleton(); |
| 88 | ERR_FAIL_NULL(material_storage); |
| 89 | |
| 90 | memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); |
| 91 | |
| 92 | tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0; |
| 93 | tonemap.push_constant.bcs[0] = p_settings.brightness; |
| 94 | tonemap.push_constant.bcs[1] = p_settings.contrast; |
| 95 | tonemap.push_constant.bcs[2] = p_settings.saturation; |
| 96 | |
| 97 | tonemap.push_constant.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0; |
| 98 | tonemap.push_constant.glow_intensity = p_settings.glow_intensity; |
| 99 | tonemap.push_constant.glow_map_strength = p_settings.glow_map_strength; |
| 100 | tonemap.push_constant.glow_levels[0] = p_settings.glow_levels[0]; // clean this up to just pass by pointer or something |
| 101 | tonemap.push_constant.glow_levels[1] = p_settings.glow_levels[1]; |
| 102 | tonemap.push_constant.glow_levels[2] = p_settings.glow_levels[2]; |
| 103 | tonemap.push_constant.glow_levels[3] = p_settings.glow_levels[3]; |
| 104 | tonemap.push_constant.glow_levels[4] = p_settings.glow_levels[4]; |
| 105 | tonemap.push_constant.glow_levels[5] = p_settings.glow_levels[5]; |
| 106 | tonemap.push_constant.glow_levels[6] = p_settings.glow_levels[6]; |
| 107 | tonemap.push_constant.glow_texture_size[0] = p_settings.glow_texture_size.x; |
| 108 | tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y; |
| 109 | tonemap.push_constant.glow_mode = p_settings.glow_mode; |
| 110 | |
| 111 | int mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL; |
| 112 | if (p_settings.use_1d_color_correction) { |
| 113 | mode += 2; |
| 114 | } |
| 115 | |
| 116 | tonemap.push_constant.tonemapper = p_settings.tonemap_mode; |
| 117 | tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0; |
| 118 | tonemap.push_constant.exposure = p_settings.exposure; |
| 119 | tonemap.push_constant.white = p_settings.white; |
| 120 | tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale; |
| 121 | tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; |
| 122 | |
| 123 | tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0; |
| 124 | |
| 125 | tonemap.push_constant.flags |= p_settings.use_fxaa ? TONEMAP_FLAG_USE_FXAA : 0; |
| 126 | tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0; |
| 127 | tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; |
| 128 | tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; |
| 129 | |
| 130 | tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0; |
| 131 | |
| 132 | if (p_settings.view_count > 1) { |
| 133 | // Use MULTIVIEW versions |
| 134 | mode += 6; |
| 135 | } |
| 136 | |
| 137 | RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
| 138 | RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
| 139 | |
| 140 | RD::Uniform u_source_color(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_color })); |
| 141 | |
| 142 | RD::Uniform u_exposure_texture; |
| 143 | u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
| 144 | u_exposure_texture.binding = 0; |
| 145 | u_exposure_texture.append_id(default_sampler); |
| 146 | u_exposure_texture.append_id(p_settings.exposure_texture); |
| 147 | |
| 148 | RD::Uniform u_glow_texture; |
| 149 | u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
| 150 | u_glow_texture.binding = 0; |
| 151 | u_glow_texture.append_id(default_mipmap_sampler); |
| 152 | u_glow_texture.append_id(p_settings.glow_texture); |
| 153 | |
| 154 | RD::Uniform u_glow_map; |
| 155 | u_glow_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
| 156 | u_glow_map.binding = 1; |
| 157 | u_glow_map.append_id(default_mipmap_sampler); |
| 158 | u_glow_map.append_id(p_settings.glow_map); |
| 159 | |
| 160 | RD::Uniform u_color_correction_texture; |
| 161 | u_color_correction_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
| 162 | u_color_correction_texture.binding = 0; |
| 163 | u_color_correction_texture.append_id(default_sampler); |
| 164 | u_color_correction_texture.append_id(p_settings.color_correction_texture); |
| 165 | |
| 166 | RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode); |
| 167 | ERR_FAIL_COND(shader.is_null()); |
| 168 | |
| 169 | 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); |
| 170 | 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())); |
| 171 | RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0); |
| 172 | RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_exposure_texture), 1); |
| 173 | RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_glow_texture, u_glow_map), 2); |
| 174 | RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3); |
| 175 | |
| 176 | RD::get_singleton()->draw_list_set_push_constant(draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant)); |
| 177 | RD::get_singleton()->draw_list_draw(draw_list, false, 1u, 3u); |
| 178 | RD::get_singleton()->draw_list_end(); |
| 179 | } |
| 180 | |
| 181 | void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) { |
| 182 | UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); |
| 183 | ERR_FAIL_NULL(uniform_set_cache); |
| 184 | MaterialStorage *material_storage = MaterialStorage::get_singleton(); |
| 185 | ERR_FAIL_NULL(material_storage); |
| 186 | |
| 187 | memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); |
| 188 | |
| 189 | tonemap.push_constant.flags |= p_settings.use_bcs ? TONEMAP_FLAG_USE_BCS : 0; |
| 190 | tonemap.push_constant.bcs[0] = p_settings.brightness; |
| 191 | tonemap.push_constant.bcs[1] = p_settings.contrast; |
| 192 | tonemap.push_constant.bcs[2] = p_settings.saturation; |
| 193 | |
| 194 | ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses." ); |
| 195 | tonemap.push_constant.flags |= p_settings.use_glow ? TONEMAP_FLAG_USE_GLOW : 0; |
| 196 | |
| 197 | int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS; |
| 198 | if (p_settings.view_count > 1) { |
| 199 | // Use MULTIVIEW versions |
| 200 | mode += 6; |
| 201 | } |
| 202 | |
| 203 | tonemap.push_constant.tonemapper = p_settings.tonemap_mode; |
| 204 | tonemap.push_constant.flags |= p_settings.use_auto_exposure ? TONEMAP_FLAG_USE_AUTO_EXPOSURE : 0; |
| 205 | tonemap.push_constant.exposure = p_settings.exposure; |
| 206 | tonemap.push_constant.white = p_settings.white; |
| 207 | tonemap.push_constant.auto_exposure_scale = p_settings.auto_exposure_scale; |
| 208 | |
| 209 | tonemap.push_constant.flags |= p_settings.use_color_correction ? TONEMAP_FLAG_USE_COLOR_CORRECTION : 0; |
| 210 | |
| 211 | tonemap.push_constant.flags |= p_settings.use_debanding ? TONEMAP_FLAG_USE_DEBANDING : 0; |
| 212 | tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; |
| 213 | |
| 214 | tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0; |
| 215 | |
| 216 | RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
| 217 | RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
| 218 | |
| 219 | RD::Uniform u_source_color; |
| 220 | u_source_color.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT; |
| 221 | u_source_color.binding = 0; |
| 222 | u_source_color.append_id(p_source_color); |
| 223 | |
| 224 | RD::Uniform u_exposure_texture; |
| 225 | u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
| 226 | u_exposure_texture.binding = 0; |
| 227 | u_exposure_texture.append_id(default_sampler); |
| 228 | u_exposure_texture.append_id(p_settings.exposure_texture); |
| 229 | |
| 230 | RD::Uniform u_glow_texture; |
| 231 | u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
| 232 | u_glow_texture.binding = 0; |
| 233 | u_glow_texture.append_id(default_mipmap_sampler); |
| 234 | u_glow_texture.append_id(p_settings.glow_texture); |
| 235 | |
| 236 | RD::Uniform u_glow_map; |
| 237 | u_glow_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
| 238 | u_glow_map.binding = 1; |
| 239 | u_glow_map.append_id(default_mipmap_sampler); |
| 240 | u_glow_map.append_id(p_settings.glow_map); |
| 241 | |
| 242 | RD::Uniform u_color_correction_texture; |
| 243 | u_color_correction_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
| 244 | u_color_correction_texture.binding = 0; |
| 245 | u_color_correction_texture.append_id(default_sampler); |
| 246 | u_color_correction_texture.append_id(p_settings.color_correction_texture); |
| 247 | |
| 248 | RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode); |
| 249 | ERR_FAIL_COND(shader.is_null()); |
| 250 | |
| 251 | 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())); |
| 252 | RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 0, u_source_color), 0); |
| 253 | 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 |
| 254 | 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 |
| 255 | RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, uniform_set_cache->get_cache(shader, 3, u_color_correction_texture), 3); |
| 256 | |
| 257 | RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant)); |
| 258 | RD::get_singleton()->draw_list_draw(p_subpass_draw_list, false, 1u, 3u); |
| 259 | } |
| 260 | |