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 | |