1 | /**************************************************************************/ |
2 | /* ss_effects.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 "ss_effects.h" |
32 | |
33 | #include "core/config/project_settings.h" |
34 | #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" |
35 | #include "servers/rendering/renderer_rd/storage_rd/material_storage.h" |
36 | #include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h" |
37 | #include "servers/rendering/renderer_rd/uniform_set_cache_rd.h" |
38 | |
39 | using namespace RendererRD; |
40 | |
41 | SSEffects *SSEffects::singleton = nullptr; |
42 | |
43 | static _FORCE_INLINE_ void store_camera(const Projection &p_mtx, float *p_array) { |
44 | for (int i = 0; i < 4; i++) { |
45 | for (int j = 0; j < 4; j++) { |
46 | p_array[i * 4 + j] = p_mtx.columns[i][j]; |
47 | } |
48 | } |
49 | } |
50 | |
51 | SSEffects::SSEffects() { |
52 | singleton = this; |
53 | |
54 | // Initialize depth buffer for screen space effects |
55 | { |
56 | Vector<String> downsampler_modes; |
57 | downsampler_modes.push_back("\n" ); |
58 | downsampler_modes.push_back("\n#define USE_HALF_SIZE\n" ); |
59 | downsampler_modes.push_back("\n#define GENERATE_MIPS\n" ); |
60 | downsampler_modes.push_back("\n#define GENERATE_MIPS\n#define USE_HALF_SIZE\n" ); |
61 | downsampler_modes.push_back("\n#define USE_HALF_BUFFERS\n" ); |
62 | downsampler_modes.push_back("\n#define USE_HALF_BUFFERS\n#define USE_HALF_SIZE\n" ); |
63 | downsampler_modes.push_back("\n#define GENERATE_MIPS\n#define GENERATE_FULL_MIPS" ); |
64 | |
65 | ss_effects.downsample_shader.initialize(downsampler_modes); |
66 | |
67 | ss_effects.downsample_shader_version = ss_effects.downsample_shader.version_create(); |
68 | |
69 | for (int i = 0; i < SS_EFFECTS_MAX; i++) { |
70 | ss_effects.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, i)); |
71 | } |
72 | |
73 | ss_effects.gather_constants_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSEffectsGatherConstants)); |
74 | SSEffectsGatherConstants gather_constants; |
75 | |
76 | const int sub_pass_count = 5; |
77 | for (int pass = 0; pass < 4; pass++) { |
78 | for (int subPass = 0; subPass < sub_pass_count; subPass++) { |
79 | int a = pass; |
80 | |
81 | int spmap[5]{ 0, 1, 4, 3, 2 }; |
82 | int b = spmap[subPass]; |
83 | |
84 | float ca, sa; |
85 | float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f; |
86 | |
87 | ca = Math::cos(angle0); |
88 | sa = Math::sin(angle0); |
89 | |
90 | float scale = 1.0f + (a - 1.5f + (b - (sub_pass_count - 1.0f) * 0.5f) / float(sub_pass_count)) * 0.07f; |
91 | |
92 | gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 0] = scale * ca; |
93 | gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 1] = scale * -sa; |
94 | gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 2] = -scale * sa; |
95 | gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 3] = -scale * ca; |
96 | } |
97 | } |
98 | |
99 | RD::get_singleton()->buffer_update(ss_effects.gather_constants_buffer, 0, sizeof(SSEffectsGatherConstants), &gather_constants); |
100 | } |
101 | |
102 | // Initialize Screen Space Indirect Lighting (SSIL) |
103 | ssil_set_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality" ))), GLOBAL_GET("rendering/environment/ssil/half_size" ), GLOBAL_GET("rendering/environment/ssil/adaptive_target" ), GLOBAL_GET("rendering/environment/ssil/blur_passes" ), GLOBAL_GET("rendering/environment/ssil/fadeout_from" ), GLOBAL_GET("rendering/environment/ssil/fadeout_to" )); |
104 | |
105 | { |
106 | Vector<String> ssil_modes; |
107 | ssil_modes.push_back("\n" ); |
108 | ssil_modes.push_back("\n#define SSIL_BASE\n" ); |
109 | ssil_modes.push_back("\n#define ADAPTIVE\n" ); |
110 | |
111 | ssil.gather_shader.initialize(ssil_modes); |
112 | |
113 | ssil.gather_shader_version = ssil.gather_shader.version_create(); |
114 | |
115 | for (int i = SSIL_GATHER; i <= SSIL_GATHER_ADAPTIVE; i++) { |
116 | ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.gather_shader.version_get_shader(ssil.gather_shader_version, i)); |
117 | } |
118 | ssil.projection_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSILProjectionUniforms)); |
119 | } |
120 | |
121 | { |
122 | Vector<String> ssil_modes; |
123 | ssil_modes.push_back("\n#define GENERATE_MAP\n" ); |
124 | ssil_modes.push_back("\n#define PROCESS_MAPA\n" ); |
125 | ssil_modes.push_back("\n#define PROCESS_MAPB\n" ); |
126 | |
127 | ssil.importance_map_shader.initialize(ssil_modes); |
128 | |
129 | ssil.importance_map_shader_version = ssil.importance_map_shader.version_create(); |
130 | |
131 | for (int i = SSIL_GENERATE_IMPORTANCE_MAP; i <= SSIL_PROCESS_IMPORTANCE_MAPB; i++) { |
132 | ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, i - SSIL_GENERATE_IMPORTANCE_MAP)); |
133 | } |
134 | ssil.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); |
135 | int zero[1] = { 0 }; |
136 | RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero); |
137 | RD::get_singleton()->set_resource_name(ssil.importance_map_load_counter, "Importance Map Load Counter" ); |
138 | |
139 | Vector<RD::Uniform> uniforms; |
140 | { |
141 | RD::Uniform u; |
142 | u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; |
143 | u.binding = 0; |
144 | u.append_id(ssil.importance_map_load_counter); |
145 | uniforms.push_back(u); |
146 | } |
147 | ssil.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, 2), 2); |
148 | RD::get_singleton()->set_resource_name(ssil.counter_uniform_set, "Load Counter Uniform Set" ); |
149 | } |
150 | |
151 | { |
152 | Vector<String> ssil_modes; |
153 | ssil_modes.push_back("\n#define MODE_NON_SMART\n" ); |
154 | ssil_modes.push_back("\n#define MODE_SMART\n" ); |
155 | ssil_modes.push_back("\n#define MODE_WIDE\n" ); |
156 | |
157 | ssil.blur_shader.initialize(ssil_modes); |
158 | |
159 | ssil.blur_shader_version = ssil.blur_shader.version_create(); |
160 | for (int i = SSIL_BLUR_PASS; i <= SSIL_BLUR_PASS_WIDE; i++) { |
161 | ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.blur_shader.version_get_shader(ssil.blur_shader_version, i - SSIL_BLUR_PASS)); |
162 | } |
163 | } |
164 | |
165 | { |
166 | Vector<String> ssil_modes; |
167 | ssil_modes.push_back("\n#define MODE_NON_SMART\n" ); |
168 | ssil_modes.push_back("\n#define MODE_SMART\n" ); |
169 | ssil_modes.push_back("\n#define MODE_HALF\n" ); |
170 | |
171 | ssil.interleave_shader.initialize(ssil_modes); |
172 | |
173 | ssil.interleave_shader_version = ssil.interleave_shader.version_create(); |
174 | for (int i = SSIL_INTERLEAVE; i <= SSIL_INTERLEAVE_HALF; i++) { |
175 | ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.interleave_shader.version_get_shader(ssil.interleave_shader_version, i - SSIL_INTERLEAVE)); |
176 | } |
177 | } |
178 | |
179 | // Initialize Screen Space Ambient Occlusion (SSAO) |
180 | ssao_set_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality" ))), GLOBAL_GET("rendering/environment/ssao/half_size" ), GLOBAL_GET("rendering/environment/ssao/adaptive_target" ), GLOBAL_GET("rendering/environment/ssao/blur_passes" ), GLOBAL_GET("rendering/environment/ssao/fadeout_from" ), GLOBAL_GET("rendering/environment/ssao/fadeout_to" )); |
181 | |
182 | { |
183 | RD::SamplerState sampler; |
184 | sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; |
185 | sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; |
186 | sampler.mip_filter = RD::SAMPLER_FILTER_NEAREST; |
187 | sampler.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; |
188 | sampler.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; |
189 | sampler.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; |
190 | sampler.max_lod = 4; |
191 | |
192 | uint32_t pipeline = 0; |
193 | { |
194 | Vector<String> ssao_modes; |
195 | |
196 | ssao_modes.push_back("\n" ); |
197 | ssao_modes.push_back("\n#define SSAO_BASE\n" ); |
198 | ssao_modes.push_back("\n#define ADAPTIVE\n" ); |
199 | |
200 | ssao.gather_shader.initialize(ssao_modes); |
201 | |
202 | ssao.gather_shader_version = ssao.gather_shader.version_create(); |
203 | |
204 | for (int i = 0; i <= SSAO_GATHER_ADAPTIVE; i++) { |
205 | ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i)); |
206 | pipeline++; |
207 | } |
208 | } |
209 | |
210 | { |
211 | Vector<String> ssao_modes; |
212 | ssao_modes.push_back("\n#define GENERATE_MAP\n" ); |
213 | ssao_modes.push_back("\n#define PROCESS_MAPA\n" ); |
214 | ssao_modes.push_back("\n#define PROCESS_MAPB\n" ); |
215 | |
216 | ssao.importance_map_shader.initialize(ssao_modes); |
217 | |
218 | ssao.importance_map_shader_version = ssao.importance_map_shader.version_create(); |
219 | |
220 | for (int i = SSAO_GENERATE_IMPORTANCE_MAP; i <= SSAO_PROCESS_IMPORTANCE_MAPB; i++) { |
221 | ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP)); |
222 | |
223 | pipeline++; |
224 | } |
225 | |
226 | ssao.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); |
227 | int zero[1] = { 0 }; |
228 | RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero); |
229 | RD::get_singleton()->set_resource_name(ssao.importance_map_load_counter, "Importance Map Load Counter" ); |
230 | |
231 | Vector<RD::Uniform> uniforms; |
232 | { |
233 | RD::Uniform u; |
234 | u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; |
235 | u.binding = 0; |
236 | u.append_id(ssao.importance_map_load_counter); |
237 | uniforms.push_back(u); |
238 | } |
239 | ssao.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2), 2); |
240 | RD::get_singleton()->set_resource_name(ssao.counter_uniform_set, "Load Counter Uniform Set" ); |
241 | } |
242 | |
243 | { |
244 | Vector<String> ssao_modes; |
245 | ssao_modes.push_back("\n#define MODE_NON_SMART\n" ); |
246 | ssao_modes.push_back("\n#define MODE_SMART\n" ); |
247 | ssao_modes.push_back("\n#define MODE_WIDE\n" ); |
248 | |
249 | ssao.blur_shader.initialize(ssao_modes); |
250 | |
251 | ssao.blur_shader_version = ssao.blur_shader.version_create(); |
252 | |
253 | for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_PASS_WIDE; i++) { |
254 | ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS)); |
255 | |
256 | pipeline++; |
257 | } |
258 | } |
259 | |
260 | { |
261 | Vector<String> ssao_modes; |
262 | ssao_modes.push_back("\n#define MODE_NON_SMART\n" ); |
263 | ssao_modes.push_back("\n#define MODE_SMART\n" ); |
264 | ssao_modes.push_back("\n#define MODE_HALF\n" ); |
265 | |
266 | ssao.interleave_shader.initialize(ssao_modes); |
267 | |
268 | ssao.interleave_shader_version = ssao.interleave_shader.version_create(); |
269 | for (int i = SSAO_INTERLEAVE; i <= SSAO_INTERLEAVE_HALF; i++) { |
270 | ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE)); |
271 | RD::get_singleton()->set_resource_name(ssao.pipelines[pipeline], "Interleave Pipeline " + itos(i)); |
272 | pipeline++; |
273 | } |
274 | } |
275 | |
276 | ERR_FAIL_COND(pipeline != SSAO_MAX); |
277 | |
278 | ss_effects.mirror_sampler = RD::get_singleton()->sampler_create(sampler); |
279 | } |
280 | |
281 | // Screen Space Reflections |
282 | ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality" ))); |
283 | |
284 | { |
285 | Vector<RD::PipelineSpecializationConstant> specialization_constants; |
286 | |
287 | { |
288 | RD::PipelineSpecializationConstant sc; |
289 | sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; |
290 | sc.constant_id = 0; // SSR_USE_FULL_PROJECTION_MATRIX |
291 | sc.bool_value = false; |
292 | specialization_constants.push_back(sc); |
293 | } |
294 | |
295 | { |
296 | Vector<String> ssr_scale_modes; |
297 | ssr_scale_modes.push_back("\n" ); |
298 | |
299 | ssr_scale.shader.initialize(ssr_scale_modes); |
300 | ssr_scale.shader_version = ssr_scale.shader.version_create(); |
301 | |
302 | for (int v = 0; v < SSR_VARIATIONS; v++) { |
303 | specialization_constants.ptrw()[0].bool_value = (v & SSR_MULTIVIEW) ? true : false; |
304 | ssr_scale.pipelines[v] = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0), specialization_constants); |
305 | } |
306 | } |
307 | |
308 | { |
309 | Vector<String> ssr_modes; |
310 | ssr_modes.push_back("\n" ); // SCREEN_SPACE_REFLECTION_NORMAL |
311 | ssr_modes.push_back("\n#define MODE_ROUGH\n" ); // SCREEN_SPACE_REFLECTION_ROUGH |
312 | |
313 | ssr.shader.initialize(ssr_modes); |
314 | ssr.shader_version = ssr.shader.version_create(); |
315 | |
316 | for (int v = 0; v < SSR_VARIATIONS; v++) { |
317 | specialization_constants.ptrw()[0].bool_value = (v & SSR_MULTIVIEW) ? true : false; |
318 | for (int i = 0; i < SCREEN_SPACE_REFLECTION_MAX; i++) { |
319 | ssr.pipelines[v][i] = RD::get_singleton()->compute_pipeline_create(ssr.shader.version_get_shader(ssr.shader_version, i), specialization_constants); |
320 | } |
321 | } |
322 | } |
323 | |
324 | { |
325 | Vector<String> ssr_filter_modes; |
326 | ssr_filter_modes.push_back("\n" ); // SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL |
327 | ssr_filter_modes.push_back("\n#define VERTICAL_PASS\n" ); // SCREEN_SPACE_REFLECTION_FILTER_VERTICAL |
328 | |
329 | ssr_filter.shader.initialize(ssr_filter_modes); |
330 | ssr_filter.shader_version = ssr_filter.shader.version_create(); |
331 | |
332 | for (int v = 0; v < SSR_VARIATIONS; v++) { |
333 | specialization_constants.ptrw()[0].bool_value = (v & SSR_MULTIVIEW) ? true : false; |
334 | for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) { |
335 | ssr_filter.pipelines[v][i] = RD::get_singleton()->compute_pipeline_create(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i), specialization_constants); |
336 | } |
337 | } |
338 | } |
339 | } |
340 | |
341 | // Subsurface scattering |
342 | sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality" ))); |
343 | sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale" ); |
344 | sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale" ); |
345 | |
346 | { |
347 | Vector<String> sss_modes; |
348 | sss_modes.push_back("\n#define USE_11_SAMPLES\n" ); |
349 | sss_modes.push_back("\n#define USE_17_SAMPLES\n" ); |
350 | sss_modes.push_back("\n#define USE_25_SAMPLES\n" ); |
351 | |
352 | sss.shader.initialize(sss_modes); |
353 | |
354 | sss.shader_version = sss.shader.version_create(); |
355 | |
356 | for (int i = 0; i < sss_modes.size(); i++) { |
357 | sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i)); |
358 | } |
359 | } |
360 | } |
361 | |
362 | SSEffects::~SSEffects() { |
363 | { |
364 | // Cleanup SS Reflections |
365 | ssr.shader.version_free(ssr.shader_version); |
366 | ssr_filter.shader.version_free(ssr_filter.shader_version); |
367 | ssr_scale.shader.version_free(ssr_scale.shader_version); |
368 | |
369 | if (ssr.ubo.is_valid()) { |
370 | RD::get_singleton()->free(ssr.ubo); |
371 | } |
372 | } |
373 | |
374 | { |
375 | // Cleanup SS downsampler |
376 | ss_effects.downsample_shader.version_free(ss_effects.downsample_shader_version); |
377 | |
378 | RD::get_singleton()->free(ss_effects.mirror_sampler); |
379 | RD::get_singleton()->free(ss_effects.gather_constants_buffer); |
380 | } |
381 | |
382 | { |
383 | // Cleanup SSIL |
384 | ssil.blur_shader.version_free(ssil.blur_shader_version); |
385 | ssil.gather_shader.version_free(ssil.gather_shader_version); |
386 | ssil.interleave_shader.version_free(ssil.interleave_shader_version); |
387 | ssil.importance_map_shader.version_free(ssil.importance_map_shader_version); |
388 | |
389 | RD::get_singleton()->free(ssil.importance_map_load_counter); |
390 | RD::get_singleton()->free(ssil.projection_uniform_buffer); |
391 | } |
392 | |
393 | { |
394 | // Cleanup SSAO |
395 | ssao.blur_shader.version_free(ssao.blur_shader_version); |
396 | ssao.gather_shader.version_free(ssao.gather_shader_version); |
397 | ssao.interleave_shader.version_free(ssao.interleave_shader_version); |
398 | ssao.importance_map_shader.version_free(ssao.importance_map_shader_version); |
399 | |
400 | RD::get_singleton()->free(ssao.importance_map_load_counter); |
401 | } |
402 | |
403 | { |
404 | // Cleanup Subsurface scattering |
405 | sss.shader.version_free(sss.shader_version); |
406 | } |
407 | |
408 | singleton = nullptr; |
409 | } |
410 | |
411 | /* SS Downsampler */ |
412 | |
413 | void SSEffects::downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_view, const Projection &p_projection) { |
414 | UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); |
415 | ERR_FAIL_NULL(uniform_set_cache); |
416 | MaterialStorage *material_storage = MaterialStorage::get_singleton(); |
417 | ERR_FAIL_NULL(material_storage); |
418 | |
419 | uint32_t view_count = p_render_buffers->get_view_count(); |
420 | Size2i full_screen_size = p_render_buffers->get_internal_size(); |
421 | Size2i size((full_screen_size.x + 1) / 2, (full_screen_size.y + 1) / 2); |
422 | |
423 | // Make sure our buffers exist, buffers are automatically cleared if view count or size changes. |
424 | if (!p_render_buffers->has_texture(RB_SCOPE_SSDS, RB_LINEAR_DEPTH)) { |
425 | p_render_buffers->create_texture(RB_SCOPE_SSDS, RB_LINEAR_DEPTH, RD::DATA_FORMAT_R16_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, size, view_count * 4, 5); |
426 | } |
427 | |
428 | // Downsample and deinterleave the depth buffer for SSAO and SSIL |
429 | RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); |
430 | |
431 | int downsample_mode = SS_EFFECTS_DOWNSAMPLE; |
432 | bool use_mips = ssao_quality > RS::ENV_SSAO_QUALITY_MEDIUM || ssil_quality > RS::ENV_SSIL_QUALITY_MEDIUM; |
433 | |
434 | if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW && ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { |
435 | downsample_mode = SS_EFFECTS_DOWNSAMPLE_HALF; |
436 | } else if (use_mips) { |
437 | downsample_mode = SS_EFFECTS_DOWNSAMPLE_MIPMAP; |
438 | } |
439 | |
440 | bool use_half_size = false; |
441 | bool use_full_mips = false; |
442 | |
443 | if (ssao_half_size && ssil_half_size) { |
444 | downsample_mode++; |
445 | use_half_size = true; |
446 | } else if (ssao_half_size != ssil_half_size) { |
447 | if (use_mips) { |
448 | downsample_mode = SS_EFFECTS_DOWNSAMPLE_FULL_MIPS; |
449 | use_full_mips = true; |
450 | } else { |
451 | // Only need the first two mipmaps, but the cost to generate the next two is trivial |
452 | // TODO investigate the benefit of a shader version to generate only 2 mips |
453 | downsample_mode = SS_EFFECTS_DOWNSAMPLE_MIPMAP; |
454 | use_mips = true; |
455 | } |
456 | } |
457 | |
458 | RID shader = ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, downsample_mode); |
459 | int depth_index = use_half_size ? 1 : 0; |
460 | |
461 | RD::get_singleton()->draw_command_begin_label("Downsample Depth" ); |
462 | |
463 | RID downsample_uniform_set; |
464 | if (use_mips) { |
465 | // Grab our downsample uniform set from cache, these are automatically cleaned up if the depth textures are cleared. |
466 | // This also ensures we can switch between left eye and right eye uniform sets without recreating the uniform twice a frame. |
467 | Vector<RD::Uniform> u_depths; |
468 | |
469 | // Note, use_full_mips is true if either SSAO or SSIL uses half size, but the other full size and we're using mips. |
470 | // That means we're filling all 5 levels. |
471 | // In this scenario `depth_index` will be 0. |
472 | for (int i = 0; i < (use_full_mips ? 4 : 3); i++) { |
473 | RID depth_mipmap = p_render_buffers->get_texture_slice(RB_SCOPE_SSDS, RB_LINEAR_DEPTH, p_view * 4, depth_index + i + 1, 4, 1); |
474 | |
475 | RD::Uniform u_depth; |
476 | u_depth.uniform_type = RD::UNIFORM_TYPE_IMAGE; |
477 | u_depth.binding = i; |
478 | u_depth.append_id(depth_mipmap); |
479 | u_depths.push_back(u_depth); |
480 | } |
481 | |
482 | // This before only used SS_EFFECTS_DOWNSAMPLE_MIPMAP or SS_EFFECTS_DOWNSAMPLE_FULL_MIPS |
483 | downsample_uniform_set = uniform_set_cache->get_cache_vec(shader, 2, u_depths); |
484 | } |
485 | |
486 | float depth_linearize_mul = -p_projection.columns[3][2] * 0.5; |
487 | float depth_linearize_add = p_projection.columns[2][2]; |
488 | if (depth_linearize_mul * depth_linearize_add < 0) { |
489 | depth_linearize_add = -depth_linearize_add; |
490 | } |
491 | |
492 | ss_effects.downsample_push_constant.orthogonal = p_projection.is_orthogonal(); |
493 | ss_effects.downsample_push_constant.z_near = depth_linearize_mul; |
494 | ss_effects.downsample_push_constant.z_far = depth_linearize_add; |
495 | if (ss_effects.downsample_push_constant.orthogonal) { |
496 | ss_effects.downsample_push_constant.z_near = p_projection.get_z_near(); |
497 | ss_effects.downsample_push_constant.z_far = p_projection.get_z_far(); |
498 | } |
499 | ss_effects.downsample_push_constant.pixel_size[0] = 1.0 / full_screen_size.x; |
500 | ss_effects.downsample_push_constant.pixel_size[1] = 1.0 / full_screen_size.y; |
501 | ss_effects.downsample_push_constant.radius_sq = 1.0; |
502 | |
503 | RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
504 | |
505 | RID depth_texture = p_render_buffers->get_depth_texture(p_view); |
506 | RID depth_mipmap = p_render_buffers->get_texture_slice(RB_SCOPE_SSDS, RB_LINEAR_DEPTH, p_view * 4, depth_index, 4, 1); |
507 | |
508 | RD::Uniform u_depth_buffer(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, depth_texture })); |
509 | RD::Uniform u_depth_mipmap(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ depth_mipmap })); |
510 | |
511 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ss_effects.pipelines[downsample_mode]); |
512 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_depth_buffer), 0); |
513 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth_mipmap), 1); |
514 | if (use_mips) { |
515 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, downsample_uniform_set, 2); |
516 | } |
517 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ss_effects.downsample_push_constant, sizeof(SSEffectsDownsamplePushConstant)); |
518 | |
519 | if (use_half_size) { |
520 | size.x = MAX(1, size.x >> 1); |
521 | size.y = MAX(1, size.y >> 1); |
522 | } |
523 | |
524 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1); |
525 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
526 | RD::get_singleton()->draw_command_end_label(); |
527 | |
528 | RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); |
529 | |
530 | ss_effects.used_full_mips_last_frame = use_full_mips; |
531 | ss_effects.used_half_size_last_frame = use_half_size; |
532 | ss_effects.used_mips_last_frame = use_mips; |
533 | } |
534 | |
535 | /* SSIL */ |
536 | |
537 | void SSEffects::ssil_set_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { |
538 | ssil_quality = p_quality; |
539 | ssil_half_size = p_half_size; |
540 | ssil_adaptive_target = p_adaptive_target; |
541 | ssil_blur_passes = p_blur_passes; |
542 | ssil_fadeout_from = p_fadeout_from; |
543 | ssil_fadeout_to = p_fadeout_to; |
544 | } |
545 | |
546 | void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const RID *p_ssil_slices, const RID *p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set) { |
547 | UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); |
548 | ERR_FAIL_NULL(uniform_set_cache); |
549 | |
550 | RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); |
551 | if ((ssil_quality == RS::ENV_SSIL_QUALITY_ULTRA) && !p_adaptive_base_pass) { |
552 | RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1); |
553 | } |
554 | RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_projection_uniform_set, 3); |
555 | |
556 | RID shader = ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0); |
557 | |
558 | for (int i = 0; i < 4; i++) { |
559 | if ((ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { |
560 | continue; |
561 | } |
562 | |
563 | RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_slices[i] })); |
564 | RD::Uniform u_edges_slice(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_edges_slices[i] })); |
565 | |
566 | ssil.gather_push_constant.pass_coord_offset[0] = i % 2; |
567 | ssil.gather_push_constant.pass_coord_offset[1] = i / 2; |
568 | ssil.gather_push_constant.pass_uv_offset[0] = ((i % 2) - 0.0) / p_settings.full_screen_size.x; |
569 | ssil.gather_push_constant.pass_uv_offset[1] = ((i / 2) - 0.0) / p_settings.full_screen_size.y; |
570 | ssil.gather_push_constant.pass = i; |
571 | RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, uniform_set_cache->get_cache(shader, 2, u_ssil_slice, u_edges_slice), 2); |
572 | RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssil.gather_push_constant, sizeof(SSILGatherPushConstant)); |
573 | |
574 | Size2i size; |
575 | // Calculate size same way as we created the buffer |
576 | if (ssil_half_size) { |
577 | size.x = (p_settings.full_screen_size.x + 3) / 4; |
578 | size.y = (p_settings.full_screen_size.y + 3) / 4; |
579 | } else { |
580 | size.x = (p_settings.full_screen_size.x + 1) / 2; |
581 | size.y = (p_settings.full_screen_size.y + 1) / 2; |
582 | } |
583 | |
584 | RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1); |
585 | } |
586 | RD::get_singleton()->compute_list_add_barrier(p_compute_list); |
587 | } |
588 | |
589 | void SSEffects::ssil_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSILRenderBuffers &p_ssil_buffers, const SSILSettings &p_settings) { |
590 | if (p_ssil_buffers.half_size != ssil_half_size) { |
591 | p_render_buffers->clear_context(RB_SCOPE_SSIL); |
592 | } |
593 | |
594 | p_ssil_buffers.half_size = ssil_half_size; |
595 | if (p_ssil_buffers.half_size) { |
596 | p_ssil_buffers.buffer_width = (p_settings.full_screen_size.x + 3) / 4; |
597 | p_ssil_buffers.buffer_height = (p_settings.full_screen_size.y + 3) / 4; |
598 | p_ssil_buffers.half_buffer_width = (p_settings.full_screen_size.x + 7) / 8; |
599 | p_ssil_buffers.half_buffer_height = (p_settings.full_screen_size.y + 7) / 8; |
600 | } else { |
601 | p_ssil_buffers.buffer_width = (p_settings.full_screen_size.x + 1) / 2; |
602 | p_ssil_buffers.buffer_height = (p_settings.full_screen_size.y + 1) / 2; |
603 | p_ssil_buffers.half_buffer_width = (p_settings.full_screen_size.x + 3) / 4; |
604 | p_ssil_buffers.half_buffer_height = (p_settings.full_screen_size.y + 3) / 4; |
605 | } |
606 | |
607 | uint32_t view_count = p_render_buffers->get_view_count(); |
608 | Size2i full_size = Size2i(p_ssil_buffers.buffer_width, p_ssil_buffers.buffer_height); |
609 | Size2i half_size = Size2i(p_ssil_buffers.half_buffer_width, p_ssil_buffers.half_buffer_height); |
610 | |
611 | // We create our intermediate and final results as render buffers. |
612 | // These are automatically cached and cleaned up when our viewport resizes |
613 | // or when our viewport gets destroyed. |
614 | |
615 | if (!p_render_buffers->has_texture(RB_SCOPE_SSIL, RB_FINAL)) { // We don't strictly have to check if it exists but we only want to clear it when we create it... |
616 | RID final = p_render_buffers->create_texture(RB_SCOPE_SSIL, RB_FINAL, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT); |
617 | RD::get_singleton()->texture_clear(final, Color(0, 0, 0, 0), 0, 1, 0, view_count); |
618 | } |
619 | |
620 | if (!p_render_buffers->has_texture(RB_SCOPE_SSIL, RB_LAST_FRAME)) { |
621 | RID last_frame = p_render_buffers->create_texture(RB_SCOPE_SSIL, RB_LAST_FRAME, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT, RD::TEXTURE_SAMPLES_1, p_settings.full_screen_size, 0, 6); |
622 | RD::get_singleton()->texture_clear(last_frame, Color(0, 0, 0, 0), 0, 6, 0, view_count); |
623 | } |
624 | |
625 | // As we're not clearing these, and render buffers will return the cached texture if it already exists, |
626 | // we don't first check has_texture here |
627 | |
628 | p_render_buffers->create_texture(RB_SCOPE_SSIL, RB_DEINTERLEAVED, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, full_size, 4 * view_count); |
629 | p_render_buffers->create_texture(RB_SCOPE_SSIL, RB_DEINTERLEAVED_PONG, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, full_size, 4 * view_count); |
630 | p_render_buffers->create_texture(RB_SCOPE_SSIL, RB_EDGES, RD::DATA_FORMAT_R8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, full_size, 4 * view_count); |
631 | p_render_buffers->create_texture(RB_SCOPE_SSIL, RB_IMPORTANCE_MAP, RD::DATA_FORMAT_R8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, half_size); |
632 | p_render_buffers->create_texture(RB_SCOPE_SSIL, RB_IMPORTANCE_PONG, RD::DATA_FORMAT_R8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, half_size); |
633 | } |
634 | |
635 | void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_render_buffers, SSILRenderBuffers &p_ssil_buffers, uint32_t p_view, RID p_normal_buffer, const Projection &p_projection, const Projection &p_last_projection, const SSILSettings &p_settings) { |
636 | UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); |
637 | ERR_FAIL_NULL(uniform_set_cache); |
638 | MaterialStorage *material_storage = MaterialStorage::get_singleton(); |
639 | ERR_FAIL_NULL(material_storage); |
640 | |
641 | RD::get_singleton()->draw_command_begin_label("Process Screen Space Indirect Lighting" ); |
642 | |
643 | // Obtain our (cached) buffer slices for the view we are rendering. |
644 | RID last_frame = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_LAST_FRAME, p_view, 0, 1, 6); |
645 | RID deinterleaved = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_DEINTERLEAVED, p_view * 4, 0, 4, 1); |
646 | RID deinterleaved_pong = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_DEINTERLEAVED_PONG, 4 * p_view, 0, 4, 1); |
647 | RID edges = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_EDGES, 4 * p_view, 0, 4, 1); |
648 | RID importance_map = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_IMPORTANCE_MAP, p_view, 0); |
649 | RID importance_pong = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_IMPORTANCE_PONG, p_view, 0); |
650 | |
651 | RID deinterleaved_slices[4]; |
652 | RID deinterleaved_pong_slices[4]; |
653 | RID edges_slices[4]; |
654 | for (uint32_t i = 0; i < 4; i++) { |
655 | deinterleaved_slices[i] = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_DEINTERLEAVED, p_view * 4 + i, 0); |
656 | deinterleaved_pong_slices[i] = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_DEINTERLEAVED_PONG, p_view * 4 + i, 0); |
657 | edges_slices[i] = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_EDGES, p_view * 4 + i, 0); |
658 | } |
659 | |
660 | //Store projection info before starting the compute list |
661 | SSILProjectionUniforms projection_uniforms; |
662 | store_camera(p_last_projection, projection_uniforms.inv_last_frame_projection_matrix); |
663 | |
664 | RD::get_singleton()->buffer_update(ssil.projection_uniform_buffer, 0, sizeof(SSILProjectionUniforms), &projection_uniforms); |
665 | |
666 | memset(&ssil.gather_push_constant, 0, sizeof(SSILGatherPushConstant)); |
667 | |
668 | RID shader = ssil.gather_shader.version_get_shader(ssil.gather_shader_version, SSIL_GATHER); |
669 | RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
670 | RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
671 | |
672 | RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); |
673 | { |
674 | RD::get_singleton()->draw_command_begin_label("Gather Samples" ); |
675 | ssil.gather_push_constant.screen_size[0] = p_settings.full_screen_size.x; |
676 | ssil.gather_push_constant.screen_size[1] = p_settings.full_screen_size.y; |
677 | |
678 | ssil.gather_push_constant.half_screen_pixel_size[0] = 2.0 / p_settings.full_screen_size.x; |
679 | ssil.gather_push_constant.half_screen_pixel_size[1] = 2.0 / p_settings.full_screen_size.y; |
680 | if (ssil_half_size) { |
681 | ssil.gather_push_constant.half_screen_pixel_size[0] *= 2.0; |
682 | ssil.gather_push_constant.half_screen_pixel_size[1] *= 2.0; |
683 | } |
684 | ssil.gather_push_constant.half_screen_pixel_size_x025[0] = ssil.gather_push_constant.half_screen_pixel_size[0] * 0.75; |
685 | ssil.gather_push_constant.half_screen_pixel_size_x025[1] = ssil.gather_push_constant.half_screen_pixel_size[1] * 0.75; |
686 | float tan_half_fov_x = 1.0 / p_projection.columns[0][0]; |
687 | float tan_half_fov_y = 1.0 / p_projection.columns[1][1]; |
688 | ssil.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0; |
689 | ssil.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0; |
690 | ssil.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0; |
691 | ssil.gather_push_constant.NDC_to_view_add[1] = tan_half_fov_y; |
692 | ssil.gather_push_constant.z_near = p_projection.get_z_near(); |
693 | ssil.gather_push_constant.z_far = p_projection.get_z_far(); |
694 | ssil.gather_push_constant.is_orthogonal = p_projection.is_orthogonal(); |
695 | |
696 | ssil.gather_push_constant.radius = p_settings.radius; |
697 | float radius_near_limit = (p_settings.radius * 1.2f); |
698 | if (ssil_quality <= RS::ENV_SSIL_QUALITY_LOW) { |
699 | radius_near_limit *= 1.50f; |
700 | |
701 | if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { |
702 | ssil.gather_push_constant.radius *= 0.8f; |
703 | } |
704 | } |
705 | radius_near_limit /= tan_half_fov_y; |
706 | ssil.gather_push_constant.intensity = p_settings.intensity * Math_PI; |
707 | ssil.gather_push_constant.fade_out_mul = -1.0 / (ssil_fadeout_to - ssil_fadeout_from); |
708 | ssil.gather_push_constant.fade_out_add = ssil_fadeout_from / (ssil_fadeout_to - ssil_fadeout_from) + 1.0; |
709 | ssil.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit; |
710 | ssil.gather_push_constant.neg_inv_radius = -1.0 / ssil.gather_push_constant.radius; |
711 | ssil.gather_push_constant.normal_rejection_amount = p_settings.normal_rejection; |
712 | |
713 | ssil.gather_push_constant.load_counter_avg_div = 9.0 / float((p_ssil_buffers.half_buffer_width) * (p_ssil_buffers.half_buffer_height) * 255); |
714 | ssil.gather_push_constant.adaptive_sample_limit = ssil_adaptive_target; |
715 | |
716 | ssil.gather_push_constant.quality = MAX(0, ssil_quality - 1); |
717 | ssil.gather_push_constant.size_multiplier = ssil_half_size ? 2 : 1; |
718 | |
719 | // We are using our uniform cache so our uniform sets are automatically freed when our textures are freed. |
720 | // It also ensures that we're reusing the right cached entry in a multiview situation without us having to |
721 | // remember each instance of the uniform set. |
722 | |
723 | RID projection_uniform_set; |
724 | { |
725 | RD::Uniform u_last_frame; |
726 | u_last_frame.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
727 | u_last_frame.binding = 0; |
728 | u_last_frame.append_id(default_mipmap_sampler); |
729 | u_last_frame.append_id(last_frame); |
730 | |
731 | RD::Uniform u_projection; |
732 | u_projection.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; |
733 | u_projection.binding = 1; |
734 | u_projection.append_id(ssil.projection_uniform_buffer); |
735 | |
736 | projection_uniform_set = uniform_set_cache->get_cache(shader, 3, u_last_frame, u_projection); |
737 | } |
738 | |
739 | RID gather_uniform_set; |
740 | { |
741 | RID depth_texture_view = p_render_buffers->get_texture_slice(RB_SCOPE_SSDS, RB_LINEAR_DEPTH, p_view * 4, ssil_half_size ? 1 : 0, 4, 4); |
742 | |
743 | RD::Uniform u_depth_texture_view; |
744 | u_depth_texture_view.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
745 | u_depth_texture_view.binding = 0; |
746 | u_depth_texture_view.append_id(ss_effects.mirror_sampler); |
747 | u_depth_texture_view.append_id(depth_texture_view); |
748 | |
749 | RD::Uniform u_normal_buffer; |
750 | u_normal_buffer.uniform_type = RD::UNIFORM_TYPE_IMAGE; |
751 | u_normal_buffer.binding = 1; |
752 | u_normal_buffer.append_id(p_normal_buffer); |
753 | |
754 | RD::Uniform u_gather_constants_buffer; |
755 | u_gather_constants_buffer.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; |
756 | u_gather_constants_buffer.binding = 2; |
757 | u_gather_constants_buffer.append_id(ss_effects.gather_constants_buffer); |
758 | |
759 | gather_uniform_set = uniform_set_cache->get_cache(shader, 0, u_depth_texture_view, u_normal_buffer, u_gather_constants_buffer); |
760 | } |
761 | |
762 | RID importance_map_uniform_set; |
763 | { |
764 | RD::Uniform u_pong; |
765 | u_pong.uniform_type = RD::UNIFORM_TYPE_IMAGE; |
766 | u_pong.binding = 0; |
767 | u_pong.append_id(deinterleaved_pong); |
768 | |
769 | RD::Uniform u_importance_map; |
770 | u_importance_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
771 | u_importance_map.binding = 1; |
772 | u_importance_map.append_id(default_sampler); |
773 | u_importance_map.append_id(importance_map); |
774 | |
775 | RD::Uniform u_load_counter; |
776 | u_load_counter.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; |
777 | u_load_counter.binding = 2; |
778 | u_load_counter.append_id(ssil.importance_map_load_counter); |
779 | |
780 | RID shader_adaptive = ssil.gather_shader.version_get_shader(ssil.gather_shader_version, SSIL_GATHER_ADAPTIVE); |
781 | importance_map_uniform_set = uniform_set_cache->get_cache(shader_adaptive, 1, u_pong, u_importance_map, u_load_counter); |
782 | } |
783 | |
784 | if (ssil_quality == RS::ENV_SSIL_QUALITY_ULTRA) { |
785 | RD::get_singleton()->draw_command_begin_label("Generate Importance Map" ); |
786 | ssil.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width; |
787 | ssil.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height; |
788 | ssil.importance_map_push_constant.intensity = p_settings.intensity * Math_PI; |
789 | |
790 | //base pass |
791 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_BASE]); |
792 | gather_ssil(compute_list, deinterleaved_pong_slices, edges_slices, p_settings, true, gather_uniform_set, importance_map_uniform_set, projection_uniform_set); |
793 | |
794 | //generate importance map |
795 | RID gen_imp_shader = ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, 0); |
796 | RD::Uniform u_ssil_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, deinterleaved_pong })); |
797 | RD::Uniform u_importance_map(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ importance_map })); |
798 | |
799 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GENERATE_IMPORTANCE_MAP]); |
800 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(gen_imp_shader, 0, u_ssil_pong_with_sampler), 0); |
801 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(gen_imp_shader, 1, u_importance_map), 1); |
802 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant)); |
803 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssil_buffers.half_buffer_width, p_ssil_buffers.half_buffer_height, 1); |
804 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
805 | |
806 | // process Importance Map A |
807 | RID proc_imp_shader_a = ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, 1); |
808 | RD::Uniform u_importance_map_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, importance_map })); |
809 | RD::Uniform u_importance_map_pong(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ importance_pong })); |
810 | |
811 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPA]); |
812 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_a, 0, u_importance_map_with_sampler), 0); |
813 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_a, 1, u_importance_map_pong), 1); |
814 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant)); |
815 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssil_buffers.half_buffer_width, p_ssil_buffers.half_buffer_height, 1); |
816 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
817 | |
818 | // process Importance Map B |
819 | RID proc_imp_shader_b = ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, 2); |
820 | RD::Uniform u_importance_map_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, importance_pong })); |
821 | |
822 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPB]); |
823 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_b, 0, u_importance_map_pong_with_sampler), 0); |
824 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_b, 1, u_importance_map), 1); |
825 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssil.counter_uniform_set, 2); |
826 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant)); |
827 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssil_buffers.half_buffer_width, p_ssil_buffers.half_buffer_height, 1); |
828 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
829 | |
830 | RD::get_singleton()->draw_command_end_label(); // Importance Map |
831 | |
832 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_ADAPTIVE]); |
833 | } else { |
834 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER]); |
835 | } |
836 | |
837 | gather_ssil(compute_list, deinterleaved_slices, edges_slices, p_settings, false, gather_uniform_set, importance_map_uniform_set, projection_uniform_set); |
838 | RD::get_singleton()->draw_command_end_label(); //Gather |
839 | } |
840 | |
841 | { |
842 | RD::get_singleton()->draw_command_begin_label("Edge Aware Blur" ); |
843 | ssil.blur_push_constant.edge_sharpness = 1.0 - p_settings.sharpness; |
844 | ssil.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width; |
845 | ssil.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height; |
846 | |
847 | int blur_passes = ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW ? ssil_blur_passes : 1; |
848 | |
849 | shader = ssil.blur_shader.version_get_shader(ssil.blur_shader_version, 0); |
850 | |
851 | for (int pass = 0; pass < blur_passes; pass++) { |
852 | int blur_pipeline = SSIL_BLUR_PASS; |
853 | if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { |
854 | blur_pipeline = SSIL_BLUR_PASS_SMART; |
855 | if (pass < blur_passes - 2) { |
856 | blur_pipeline = SSIL_BLUR_PASS_WIDE; |
857 | } |
858 | } |
859 | |
860 | RID blur_shader = ssil.blur_shader.version_get_shader(ssil.blur_shader_version, blur_pipeline - SSIL_BLUR_PASS); |
861 | |
862 | for (int i = 0; i < 4; i++) { |
863 | if ((ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { |
864 | continue; |
865 | } |
866 | |
867 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[blur_pipeline]); |
868 | if (pass % 2 == 0) { |
869 | if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { |
870 | RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, deinterleaved_slices[i] })); |
871 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 0, u_ssil_slice), 0); |
872 | } else { |
873 | RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ ss_effects.mirror_sampler, deinterleaved_slices[i] })); |
874 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 0, u_ssil_slice), 0); |
875 | } |
876 | |
877 | RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ deinterleaved_pong_slices[i] })); |
878 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 1, u_ssil_pong_slice), 1); |
879 | } else { |
880 | if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { |
881 | RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, deinterleaved_pong_slices[i] })); |
882 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 0, u_ssil_pong_slice), 0); |
883 | } else { |
884 | RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ ss_effects.mirror_sampler, deinterleaved_pong_slices[i] })); |
885 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 0, u_ssil_pong_slice), 0); |
886 | } |
887 | |
888 | RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ deinterleaved_slices[i] })); |
889 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 1, u_ssil_slice), 1); |
890 | } |
891 | |
892 | RD::Uniform u_edges_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ edges_slices[i] })); |
893 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 2, u_edges_slice), 2); |
894 | |
895 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.blur_push_constant, sizeof(SSILBlurPushConstant)); |
896 | |
897 | // Use the size of the actual buffer we're processing here or we won't cover the entire image. |
898 | int x_groups = p_ssil_buffers.buffer_width; |
899 | int y_groups = p_ssil_buffers.buffer_height; |
900 | |
901 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, x_groups, y_groups, 1); |
902 | if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { |
903 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
904 | } |
905 | } |
906 | } |
907 | |
908 | RD::get_singleton()->draw_command_end_label(); // Blur |
909 | } |
910 | |
911 | { |
912 | RD::get_singleton()->draw_command_begin_label("Interleave Buffers" ); |
913 | ssil.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness; |
914 | ssil.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; |
915 | ssil.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; |
916 | ssil.interleave_push_constant.size_modifier = uint32_t(ssil_half_size ? 4 : 2); |
917 | |
918 | int interleave_pipeline = SSIL_INTERLEAVE_HALF; |
919 | if (ssil_quality == RS::ENV_SSIL_QUALITY_LOW) { |
920 | interleave_pipeline = SSIL_INTERLEAVE; |
921 | } else if (ssil_quality >= RS::ENV_SSIL_QUALITY_MEDIUM) { |
922 | interleave_pipeline = SSIL_INTERLEAVE_SMART; |
923 | } |
924 | |
925 | shader = ssil.interleave_shader.version_get_shader(ssil.interleave_shader_version, 0); |
926 | |
927 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[interleave_pipeline]); |
928 | |
929 | RID final = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_FINAL, p_view, 0); |
930 | RD::Uniform u_destination(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ final })); |
931 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_destination), 0); |
932 | |
933 | if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW && ssil_blur_passes % 2 == 0) { |
934 | RD::Uniform u_ssil(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, deinterleaved })); |
935 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil), 1); |
936 | } else { |
937 | RD::Uniform u_ssil_pong(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, deinterleaved_pong })); |
938 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil_pong), 1); |
939 | } |
940 | |
941 | RD::Uniform u_edges(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ edges })); |
942 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_edges), 2); |
943 | |
944 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.interleave_push_constant, sizeof(SSILInterleavePushConstant)); |
945 | |
946 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.full_screen_size.x, p_settings.full_screen_size.y, 1); |
947 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
948 | RD::get_singleton()->draw_command_end_label(); // Interleave |
949 | } |
950 | |
951 | RD::get_singleton()->draw_command_end_label(); // SSIL |
952 | |
953 | RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); |
954 | |
955 | int zero[1] = { 0 }; |
956 | RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier |
957 | } |
958 | |
959 | /* SSAO */ |
960 | |
961 | void SSEffects::ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { |
962 | ssao_quality = p_quality; |
963 | ssao_half_size = p_half_size; |
964 | ssao_adaptive_target = p_adaptive_target; |
965 | ssao_blur_passes = p_blur_passes; |
966 | ssao_fadeout_from = p_fadeout_from; |
967 | ssao_fadeout_to = p_fadeout_to; |
968 | } |
969 | |
970 | void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const RID *p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) { |
971 | UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); |
972 | ERR_FAIL_NULL(uniform_set_cache); |
973 | |
974 | RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); |
975 | if ((ssao_quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) { |
976 | RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1); |
977 | } |
978 | |
979 | RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 1); // |
980 | |
981 | for (int i = 0; i < 4; i++) { |
982 | if ((ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { |
983 | continue; |
984 | } |
985 | |
986 | RD::Uniform u_ao_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ao_slices[i] })); |
987 | |
988 | ssao.gather_push_constant.pass_coord_offset[0] = i % 2; |
989 | ssao.gather_push_constant.pass_coord_offset[1] = i / 2; |
990 | ssao.gather_push_constant.pass_uv_offset[0] = ((i % 2) - 0.0) / p_settings.full_screen_size.x; |
991 | ssao.gather_push_constant.pass_uv_offset[1] = ((i / 2) - 0.0) / p_settings.full_screen_size.y; |
992 | ssao.gather_push_constant.pass = i; |
993 | RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, uniform_set_cache->get_cache(shader, 2, u_ao_slice), 2); |
994 | RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant)); |
995 | |
996 | Size2i size; |
997 | // Make sure we use the same size as with which our buffer was created |
998 | if (ssao_half_size) { |
999 | size.x = (p_settings.full_screen_size.x + 3) / 4; |
1000 | size.y = (p_settings.full_screen_size.y + 3) / 4; |
1001 | } else { |
1002 | size.x = (p_settings.full_screen_size.x + 1) / 2; |
1003 | size.y = (p_settings.full_screen_size.y + 1) / 2; |
1004 | } |
1005 | |
1006 | RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1); |
1007 | } |
1008 | RD::get_singleton()->compute_list_add_barrier(p_compute_list); |
1009 | } |
1010 | |
1011 | void SSEffects::ssao_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORenderBuffers &p_ssao_buffers, const SSAOSettings &p_settings) { |
1012 | if (p_ssao_buffers.half_size != ssao_half_size) { |
1013 | p_render_buffers->clear_context(RB_SCOPE_SSAO); |
1014 | } |
1015 | |
1016 | p_ssao_buffers.half_size = ssao_half_size; |
1017 | if (ssao_half_size) { |
1018 | p_ssao_buffers.buffer_width = (p_settings.full_screen_size.x + 3) / 4; |
1019 | p_ssao_buffers.buffer_height = (p_settings.full_screen_size.y + 3) / 4; |
1020 | p_ssao_buffers.half_buffer_width = (p_settings.full_screen_size.x + 7) / 8; |
1021 | p_ssao_buffers.half_buffer_height = (p_settings.full_screen_size.y + 7) / 8; |
1022 | } else { |
1023 | p_ssao_buffers.buffer_width = (p_settings.full_screen_size.x + 1) / 2; |
1024 | p_ssao_buffers.buffer_height = (p_settings.full_screen_size.y + 1) / 2; |
1025 | p_ssao_buffers.half_buffer_width = (p_settings.full_screen_size.x + 3) / 4; |
1026 | p_ssao_buffers.half_buffer_height = (p_settings.full_screen_size.y + 3) / 4; |
1027 | } |
1028 | |
1029 | uint32_t view_count = p_render_buffers->get_view_count(); |
1030 | Size2i full_size = Size2i(p_ssao_buffers.buffer_width, p_ssao_buffers.buffer_height); |
1031 | Size2i half_size = Size2i(p_ssao_buffers.half_buffer_width, p_ssao_buffers.half_buffer_height); |
1032 | |
1033 | // As we're not clearing these, and render buffers will return the cached texture if it already exists, |
1034 | // we don't first check has_texture here |
1035 | |
1036 | p_render_buffers->create_texture(RB_SCOPE_SSAO, RB_DEINTERLEAVED, RD::DATA_FORMAT_R8G8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, full_size, 4 * view_count); |
1037 | p_render_buffers->create_texture(RB_SCOPE_SSAO, RB_DEINTERLEAVED_PONG, RD::DATA_FORMAT_R8G8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, full_size, 4 * view_count); |
1038 | p_render_buffers->create_texture(RB_SCOPE_SSAO, RB_IMPORTANCE_MAP, RD::DATA_FORMAT_R8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, half_size); |
1039 | p_render_buffers->create_texture(RB_SCOPE_SSAO, RB_IMPORTANCE_PONG, RD::DATA_FORMAT_R8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, half_size); |
1040 | p_render_buffers->create_texture(RB_SCOPE_SSAO, RB_FINAL, RD::DATA_FORMAT_R8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1); |
1041 | } |
1042 | |
1043 | void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORenderBuffers &p_ssao_buffers, uint32_t p_view, RID p_normal_buffer, const Projection &p_projection, const SSAOSettings &p_settings) { |
1044 | UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); |
1045 | ERR_FAIL_NULL(uniform_set_cache); |
1046 | MaterialStorage *material_storage = MaterialStorage::get_singleton(); |
1047 | ERR_FAIL_NULL(material_storage); |
1048 | |
1049 | // Obtain our (cached) buffer slices for the view we are rendering. |
1050 | RID ao_deinterleaved = p_render_buffers->get_texture_slice(RB_SCOPE_SSAO, RB_DEINTERLEAVED, p_view * 4, 0, 4, 1); |
1051 | RID ao_pong = p_render_buffers->get_texture_slice(RB_SCOPE_SSAO, RB_DEINTERLEAVED_PONG, p_view * 4, 0, 4, 1); |
1052 | RID importance_map = p_render_buffers->get_texture_slice(RB_SCOPE_SSAO, RB_IMPORTANCE_MAP, p_view, 0); |
1053 | RID importance_pong = p_render_buffers->get_texture_slice(RB_SCOPE_SSAO, RB_IMPORTANCE_PONG, p_view, 0); |
1054 | RID ao_final = p_render_buffers->get_texture_slice(RB_SCOPE_SSAO, RB_FINAL, p_view, 0); |
1055 | |
1056 | RID ao_deinterleaved_slices[4]; |
1057 | RID ao_pong_slices[4]; |
1058 | for (uint32_t i = 0; i < 4; i++) { |
1059 | ao_deinterleaved_slices[i] = p_render_buffers->get_texture_slice(RB_SCOPE_SSAO, RB_DEINTERLEAVED, p_view * 4 + i, 0); |
1060 | ao_pong_slices[i] = p_render_buffers->get_texture_slice(RB_SCOPE_SSAO, RB_DEINTERLEAVED_PONG, p_view * 4 + i, 0); |
1061 | } |
1062 | |
1063 | RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); |
1064 | memset(&ssao.gather_push_constant, 0, sizeof(SSAOGatherPushConstant)); |
1065 | /* FIRST PASS */ |
1066 | |
1067 | RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, SSAO_GATHER); |
1068 | RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
1069 | |
1070 | RD::get_singleton()->draw_command_begin_label("Process Screen Space Ambient Occlusion" ); |
1071 | /* SECOND PASS */ |
1072 | // Sample SSAO |
1073 | { |
1074 | RD::get_singleton()->draw_command_begin_label("Gather Samples" ); |
1075 | ssao.gather_push_constant.screen_size[0] = p_settings.full_screen_size.x; |
1076 | ssao.gather_push_constant.screen_size[1] = p_settings.full_screen_size.y; |
1077 | |
1078 | ssao.gather_push_constant.half_screen_pixel_size[0] = 2.0 / p_settings.full_screen_size.x; |
1079 | ssao.gather_push_constant.half_screen_pixel_size[1] = 2.0 / p_settings.full_screen_size.y; |
1080 | if (ssao_half_size) { |
1081 | ssao.gather_push_constant.half_screen_pixel_size[0] *= 2.0; |
1082 | ssao.gather_push_constant.half_screen_pixel_size[1] *= 2.0; |
1083 | } |
1084 | ssao.gather_push_constant.half_screen_pixel_size_x025[0] = ssao.gather_push_constant.half_screen_pixel_size[0] * 0.75; |
1085 | ssao.gather_push_constant.half_screen_pixel_size_x025[1] = ssao.gather_push_constant.half_screen_pixel_size[1] * 0.75; |
1086 | float tan_half_fov_x = 1.0 / p_projection.columns[0][0]; |
1087 | float tan_half_fov_y = 1.0 / p_projection.columns[1][1]; |
1088 | ssao.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0; |
1089 | ssao.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0; |
1090 | ssao.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0; |
1091 | ssao.gather_push_constant.NDC_to_view_add[1] = tan_half_fov_y; |
1092 | ssao.gather_push_constant.is_orthogonal = p_projection.is_orthogonal(); |
1093 | |
1094 | ssao.gather_push_constant.radius = p_settings.radius; |
1095 | float radius_near_limit = (p_settings.radius * 1.2f); |
1096 | if (ssao_quality <= RS::ENV_SSAO_QUALITY_LOW) { |
1097 | radius_near_limit *= 1.50f; |
1098 | |
1099 | if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { |
1100 | ssao.gather_push_constant.radius *= 0.8f; |
1101 | } |
1102 | } |
1103 | radius_near_limit /= tan_half_fov_y; |
1104 | ssao.gather_push_constant.intensity = p_settings.intensity; |
1105 | ssao.gather_push_constant.shadow_power = p_settings.power; |
1106 | ssao.gather_push_constant.shadow_clamp = 0.98; |
1107 | ssao.gather_push_constant.fade_out_mul = -1.0 / (ssao_fadeout_to - ssao_fadeout_from); |
1108 | ssao.gather_push_constant.fade_out_add = ssao_fadeout_from / (ssao_fadeout_to - ssao_fadeout_from) + 1.0; |
1109 | ssao.gather_push_constant.horizon_angle_threshold = p_settings.horizon; |
1110 | ssao.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit; |
1111 | ssao.gather_push_constant.neg_inv_radius = -1.0 / ssao.gather_push_constant.radius; |
1112 | |
1113 | ssao.gather_push_constant.load_counter_avg_div = 9.0 / float((p_ssao_buffers.half_buffer_width) * (p_ssao_buffers.half_buffer_height) * 255); |
1114 | ssao.gather_push_constant.adaptive_sample_limit = ssao_adaptive_target; |
1115 | |
1116 | ssao.gather_push_constant.detail_intensity = p_settings.detail; |
1117 | ssao.gather_push_constant.quality = MAX(0, ssao_quality - 1); |
1118 | ssao.gather_push_constant.size_multiplier = ssao_half_size ? 2 : 1; |
1119 | |
1120 | // We are using our uniform cache so our uniform sets are automatically freed when our textures are freed. |
1121 | // It also ensures that we're reusing the right cached entry in a multiview situation without us having to |
1122 | // remember each instance of the uniform set. |
1123 | RID gather_uniform_set; |
1124 | { |
1125 | RID depth_texture_view = p_render_buffers->get_texture_slice(RB_SCOPE_SSDS, RB_LINEAR_DEPTH, p_view * 4, ssao_half_size ? 1 : 0, 4, 4); |
1126 | |
1127 | RD::Uniform u_depth_texture_view; |
1128 | u_depth_texture_view.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
1129 | u_depth_texture_view.binding = 0; |
1130 | u_depth_texture_view.append_id(ss_effects.mirror_sampler); |
1131 | u_depth_texture_view.append_id(depth_texture_view); |
1132 | |
1133 | RD::Uniform u_normal_buffer; |
1134 | u_normal_buffer.uniform_type = RD::UNIFORM_TYPE_IMAGE; |
1135 | u_normal_buffer.binding = 1; |
1136 | u_normal_buffer.append_id(p_normal_buffer); |
1137 | |
1138 | RD::Uniform u_gather_constants_buffer; |
1139 | u_gather_constants_buffer.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; |
1140 | u_gather_constants_buffer.binding = 2; |
1141 | u_gather_constants_buffer.append_id(ss_effects.gather_constants_buffer); |
1142 | |
1143 | gather_uniform_set = uniform_set_cache->get_cache(shader, 0, u_depth_texture_view, u_normal_buffer, u_gather_constants_buffer); |
1144 | } |
1145 | |
1146 | RID importance_map_uniform_set; |
1147 | { |
1148 | RD::Uniform u_pong; |
1149 | u_pong.uniform_type = RD::UNIFORM_TYPE_IMAGE; |
1150 | u_pong.binding = 0; |
1151 | u_pong.append_id(ao_pong); |
1152 | |
1153 | RD::Uniform u_importance_map; |
1154 | u_importance_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; |
1155 | u_importance_map.binding = 1; |
1156 | u_importance_map.append_id(default_sampler); |
1157 | u_importance_map.append_id(importance_map); |
1158 | |
1159 | RD::Uniform u_load_counter; |
1160 | u_load_counter.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; |
1161 | u_load_counter.binding = 2; |
1162 | u_load_counter.append_id(ssao.importance_map_load_counter); |
1163 | |
1164 | RID shader_adaptive = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, SSAO_GATHER_ADAPTIVE); |
1165 | importance_map_uniform_set = uniform_set_cache->get_cache(shader_adaptive, 1, u_pong, u_importance_map, u_load_counter); |
1166 | } |
1167 | |
1168 | if (ssao_quality == RS::ENV_SSAO_QUALITY_ULTRA) { |
1169 | RD::get_singleton()->draw_command_begin_label("Generate Importance Map" ); |
1170 | ssao.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width; |
1171 | ssao.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height; |
1172 | ssao.importance_map_push_constant.intensity = p_settings.intensity; |
1173 | ssao.importance_map_push_constant.power = p_settings.power; |
1174 | |
1175 | //base pass |
1176 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE]); |
1177 | gather_ssao(compute_list, ao_pong_slices, p_settings, true, gather_uniform_set, RID()); |
1178 | |
1179 | //generate importance map |
1180 | RID gen_imp_shader = ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 0); |
1181 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GENERATE_IMPORTANCE_MAP]); |
1182 | |
1183 | RD::Uniform u_ao_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, ao_pong })); |
1184 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(gen_imp_shader, 0, u_ao_pong_with_sampler), 0); |
1185 | |
1186 | RD::Uniform u_importance_map(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ importance_map })); |
1187 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(gen_imp_shader, 1, u_importance_map), 1); |
1188 | |
1189 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant)); |
1190 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssao_buffers.half_buffer_width, p_ssao_buffers.half_buffer_height, 1); |
1191 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1192 | |
1193 | //process importance map A |
1194 | RID proc_imp_shader_a = ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 1); |
1195 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPA]); |
1196 | |
1197 | RD::Uniform u_importance_map_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, importance_map })); |
1198 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_a, 0, u_importance_map_with_sampler), 0); |
1199 | |
1200 | RD::Uniform u_importance_map_pong(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ importance_pong })); |
1201 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_a, 1, u_importance_map_pong), 1); |
1202 | |
1203 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant)); |
1204 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssao_buffers.half_buffer_width, p_ssao_buffers.half_buffer_height, 1); |
1205 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1206 | |
1207 | //process Importance Map B |
1208 | RID proc_imp_shader_b = ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2); |
1209 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPB]); |
1210 | |
1211 | RD::Uniform u_importance_map_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, importance_pong })); |
1212 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_b, 0, u_importance_map_pong_with_sampler), 0); |
1213 | |
1214 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_b, 1, u_importance_map), 1); |
1215 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssao.counter_uniform_set, 2); |
1216 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant)); |
1217 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssao_buffers.half_buffer_width, p_ssao_buffers.half_buffer_height, 1); |
1218 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1219 | |
1220 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_ADAPTIVE]); |
1221 | RD::get_singleton()->draw_command_end_label(); // Importance Map |
1222 | } else { |
1223 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER]); |
1224 | } |
1225 | |
1226 | gather_ssao(compute_list, ao_deinterleaved_slices, p_settings, false, gather_uniform_set, importance_map_uniform_set); |
1227 | RD::get_singleton()->draw_command_end_label(); // Gather SSAO |
1228 | } |
1229 | |
1230 | // /* THIRD PASS */ |
1231 | // // Blur |
1232 | // |
1233 | { |
1234 | RD::get_singleton()->draw_command_begin_label("Edge Aware Blur" ); |
1235 | ssao.blur_push_constant.edge_sharpness = 1.0 - p_settings.sharpness; |
1236 | ssao.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width; |
1237 | ssao.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height; |
1238 | |
1239 | int blur_passes = ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW ? ssao_blur_passes : 1; |
1240 | |
1241 | shader = ssao.blur_shader.version_get_shader(ssao.blur_shader_version, 0); |
1242 | |
1243 | for (int pass = 0; pass < blur_passes; pass++) { |
1244 | int blur_pipeline = SSAO_BLUR_PASS; |
1245 | if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { |
1246 | if (pass < blur_passes - 2) { |
1247 | blur_pipeline = SSAO_BLUR_PASS_WIDE; |
1248 | } else { |
1249 | blur_pipeline = SSAO_BLUR_PASS_SMART; |
1250 | } |
1251 | } |
1252 | |
1253 | for (int i = 0; i < 4; i++) { |
1254 | if ((ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { |
1255 | continue; |
1256 | } |
1257 | |
1258 | RID blur_shader = ssao.blur_shader.version_get_shader(ssao.blur_shader_version, blur_pipeline - SSAO_BLUR_PASS); |
1259 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[blur_pipeline]); |
1260 | if (pass % 2 == 0) { |
1261 | if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { |
1262 | RD::Uniform u_ao_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, ao_deinterleaved_slices[i] })); |
1263 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 0, u_ao_slices_with_sampler), 0); |
1264 | } else { |
1265 | RD::Uniform u_ao_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ ss_effects.mirror_sampler, ao_deinterleaved_slices[i] })); |
1266 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 0, u_ao_slices_with_sampler), 0); |
1267 | } |
1268 | |
1269 | RD::Uniform u_ao_pong_slices(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ ao_pong_slices[i] })); |
1270 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 1, u_ao_pong_slices), 1); |
1271 | } else { |
1272 | if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { |
1273 | RD::Uniform u_ao_pong_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, ao_pong_slices[i] })); |
1274 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 0, u_ao_pong_slices_with_sampler), 0); |
1275 | } else { |
1276 | RD::Uniform u_ao_pong_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ ss_effects.mirror_sampler, ao_pong_slices[i] })); |
1277 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 0, u_ao_pong_slices_with_sampler), 0); |
1278 | } |
1279 | |
1280 | RD::Uniform u_ao_slices(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ ao_deinterleaved_slices[i] })); |
1281 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(blur_shader, 1, u_ao_slices), 1); |
1282 | } |
1283 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); |
1284 | |
1285 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssao_buffers.buffer_width, p_ssao_buffers.buffer_height, 1); |
1286 | } |
1287 | |
1288 | if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { |
1289 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1290 | } |
1291 | } |
1292 | RD::get_singleton()->draw_command_end_label(); // Blur |
1293 | } |
1294 | |
1295 | /* FOURTH PASS */ |
1296 | // Interleave buffers |
1297 | // back to full size |
1298 | { |
1299 | RD::get_singleton()->draw_command_begin_label("Interleave Buffers" ); |
1300 | ssao.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness; |
1301 | ssao.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; |
1302 | ssao.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; |
1303 | ssao.interleave_push_constant.size_modifier = uint32_t(ssao_half_size ? 4 : 2); |
1304 | |
1305 | shader = ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, 0); |
1306 | |
1307 | int interleave_pipeline = SSAO_INTERLEAVE_HALF; |
1308 | if (ssao_quality == RS::ENV_SSAO_QUALITY_LOW) { |
1309 | interleave_pipeline = SSAO_INTERLEAVE; |
1310 | } else if (ssao_quality >= RS::ENV_SSAO_QUALITY_MEDIUM) { |
1311 | interleave_pipeline = SSAO_INTERLEAVE_SMART; |
1312 | } |
1313 | |
1314 | RID interleave_shader = ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, interleave_pipeline - SSAO_INTERLEAVE); |
1315 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[interleave_pipeline]); |
1316 | |
1317 | RD::Uniform u_upscale_buffer(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ ao_final })); |
1318 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(interleave_shader, 0, u_upscale_buffer), 0); |
1319 | |
1320 | if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW && ssao_blur_passes % 2 == 0) { |
1321 | RD::Uniform u_ao(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, ao_deinterleaved })); |
1322 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(interleave_shader, 1, u_ao), 1); |
1323 | } else { |
1324 | RD::Uniform u_ao(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, ao_pong })); |
1325 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(interleave_shader, 1, u_ao), 1); |
1326 | } |
1327 | |
1328 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.interleave_push_constant, sizeof(SSAOInterleavePushConstant)); |
1329 | |
1330 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.full_screen_size.x, p_settings.full_screen_size.y, 1); |
1331 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1332 | RD::get_singleton()->draw_command_end_label(); // Interleave |
1333 | } |
1334 | RD::get_singleton()->draw_command_end_label(); //SSAO |
1335 | RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //wait for upcoming transfer |
1336 | |
1337 | int zero[1] = { 0 }; |
1338 | RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier |
1339 | } |
1340 | |
1341 | /* Screen Space Reflection */ |
1342 | |
1343 | void SSEffects::ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { |
1344 | ssr_roughness_quality = p_quality; |
1345 | } |
1346 | |
1347 | void SSEffects::ssr_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format) { |
1348 | if (p_ssr_buffers.roughness_quality != ssr_roughness_quality) { |
1349 | // Buffers will already be cleared if view count or viewport size has changed, also cleared them if we change roughness. |
1350 | p_render_buffers->clear_context(RB_SCOPE_SSR); |
1351 | } |
1352 | |
1353 | Size2i internal_size = p_render_buffers->get_internal_size(); |
1354 | p_ssr_buffers.size = Size2i(internal_size.x / 2, internal_size.y / 2); |
1355 | p_ssr_buffers.roughness_quality = ssr_roughness_quality; |
1356 | |
1357 | // We are using barriers so we do not need to allocate textures for both views on anything but output... |
1358 | |
1359 | p_render_buffers->create_texture(RB_SCOPE_SSR, RB_DEPTH_SCALED, RD::DATA_FORMAT_R32_SFLOAT, RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, p_ssr_buffers.size, 1); |
1360 | p_render_buffers->create_texture(RB_SCOPE_SSR, RB_NORMAL_SCALED, RD::DATA_FORMAT_R8G8B8A8_UNORM, RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, p_ssr_buffers.size, 1); |
1361 | |
1362 | if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED && !p_render_buffers->has_texture(RB_SCOPE_SSR, RB_BLUR_RADIUS)) { |
1363 | p_render_buffers->create_texture(RB_SCOPE_SSR, RB_BLUR_RADIUS, RD::DATA_FORMAT_R8_UNORM, RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT, RD::TEXTURE_SAMPLES_1, p_ssr_buffers.size, 2); // 2 layers, for our two blur stages |
1364 | } |
1365 | |
1366 | p_render_buffers->create_texture(RB_SCOPE_SSR, RB_INTERMEDIATE, p_color_format, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, p_ssr_buffers.size, 1); |
1367 | p_render_buffers->create_texture(RB_SCOPE_SSR, RB_OUTPUT, p_color_format, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT, RD::TEXTURE_SAMPLES_1, p_ssr_buffers.size); |
1368 | } |
1369 | |
1370 | void SSEffects::screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RID *p_normal_roughness_slices, const RID *p_metallic_slices, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const Projection *p_projections, const Vector3 *p_eye_offsets) { |
1371 | UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); |
1372 | ERR_FAIL_NULL(uniform_set_cache); |
1373 | MaterialStorage *material_storage = MaterialStorage::get_singleton(); |
1374 | ERR_FAIL_NULL(material_storage); |
1375 | |
1376 | uint32_t view_count = p_render_buffers->get_view_count(); |
1377 | |
1378 | RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
1379 | |
1380 | { |
1381 | // Store some scene data in a UBO, in the near future we will use a UBO shared with other shaders |
1382 | ScreenSpaceReflectionSceneData scene_data; |
1383 | |
1384 | if (ssr.ubo.is_null()) { |
1385 | ssr.ubo = RD::get_singleton()->uniform_buffer_create(sizeof(ScreenSpaceReflectionSceneData)); |
1386 | } |
1387 | |
1388 | for (uint32_t v = 0; v < view_count; v++) { |
1389 | store_camera(p_projections[v], scene_data.projection[v]); |
1390 | store_camera(p_projections[v].inverse(), scene_data.inv_projection[v]); |
1391 | scene_data.eye_offset[v][0] = p_eye_offsets[v].x; |
1392 | scene_data.eye_offset[v][1] = p_eye_offsets[v].y; |
1393 | scene_data.eye_offset[v][2] = p_eye_offsets[v].z; |
1394 | scene_data.eye_offset[v][3] = 0.0; |
1395 | } |
1396 | |
1397 | RD::get_singleton()->buffer_update(ssr.ubo, 0, sizeof(ScreenSpaceReflectionSceneData), &scene_data, RD::BARRIER_MASK_COMPUTE); |
1398 | } |
1399 | |
1400 | uint32_t pipeline_specialization = 0; |
1401 | if (view_count > 1) { |
1402 | pipeline_specialization |= SSR_MULTIVIEW; |
1403 | } |
1404 | |
1405 | RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); |
1406 | |
1407 | for (uint32_t v = 0; v < view_count; v++) { |
1408 | // get buffers we need to use for this view |
1409 | RID diffuse_slice = p_render_buffers->get_internal_texture(v); |
1410 | RID depth_slice = p_render_buffers->get_depth_texture(v); |
1411 | RID depth_scaled = p_render_buffers->get_texture(RB_SCOPE_SSR, RB_DEPTH_SCALED); |
1412 | RID normal_scaled = p_render_buffers->get_texture(RB_SCOPE_SSR, RB_NORMAL_SCALED); |
1413 | RID intermediate = p_render_buffers->get_texture(RB_SCOPE_SSR, RB_INTERMEDIATE); |
1414 | RID output = p_render_buffers->get_texture_slice(RB_SCOPE_SSR, RB_OUTPUT, v, 0); |
1415 | |
1416 | RID blur_radius[2]; |
1417 | if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) { |
1418 | blur_radius[0] = p_render_buffers->get_texture_slice(RB_SCOPE_SSR, RB_BLUR_RADIUS, 0, 0); |
1419 | blur_radius[1] = p_render_buffers->get_texture_slice(RB_SCOPE_SSR, RB_BLUR_RADIUS, 1, 0); |
1420 | } |
1421 | |
1422 | RD::get_singleton()->draw_command_begin_label(String("SSR View " ) + itos(v)); |
1423 | |
1424 | { //scale color and depth to half |
1425 | RD::get_singleton()->draw_command_begin_label("SSR Scale" ); |
1426 | |
1427 | ScreenSpaceReflectionScalePushConstant push_constant; |
1428 | push_constant.view_index = v; |
1429 | push_constant.camera_z_far = p_projections[v].get_z_far(); |
1430 | push_constant.camera_z_near = p_projections[v].get_z_near(); |
1431 | push_constant.orthogonal = p_projections[v].is_orthogonal(); |
1432 | push_constant.filter = false; // Enabling causes artifacts. |
1433 | push_constant.screen_size[0] = p_ssr_buffers.size.x; |
1434 | push_constant.screen_size[1] = p_ssr_buffers.size.y; |
1435 | |
1436 | RID shader = ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0); |
1437 | |
1438 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_scale.pipelines[pipeline_specialization]); |
1439 | |
1440 | RD::Uniform u_diffuse(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, diffuse_slice })); |
1441 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_diffuse), 0); |
1442 | |
1443 | RD::Uniform u_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, depth_slice })); |
1444 | RD::Uniform u_normal_roughness(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_normal_roughness_slices[v] })); |
1445 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth, u_normal_roughness), 1); |
1446 | |
1447 | RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ intermediate })); |
1448 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_intermediate), 2); |
1449 | |
1450 | RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ depth_scaled })); |
1451 | RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ normal_scaled })); |
1452 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_scale_depth, u_scale_normal), 3); |
1453 | |
1454 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ScreenSpaceReflectionScalePushConstant)); |
1455 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssr_buffers.size.width, p_ssr_buffers.size.height, 1); |
1456 | |
1457 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1458 | |
1459 | RD::get_singleton()->draw_command_end_label(); |
1460 | } |
1461 | |
1462 | { |
1463 | RD::get_singleton()->draw_command_begin_label("SSR main" ); |
1464 | |
1465 | ScreenSpaceReflectionPushConstant push_constant; |
1466 | push_constant.view_index = v; |
1467 | push_constant.camera_z_far = p_projections[v].get_z_far(); |
1468 | push_constant.camera_z_near = p_projections[v].get_z_near(); |
1469 | push_constant.orthogonal = p_projections[v].is_orthogonal(); |
1470 | push_constant.screen_size[0] = p_ssr_buffers.size.x; |
1471 | push_constant.screen_size[1] = p_ssr_buffers.size.y; |
1472 | push_constant.curve_fade_in = p_fade_in; |
1473 | push_constant.distance_fade = p_fade_out; |
1474 | push_constant.num_steps = p_max_steps; |
1475 | push_constant.depth_tolerance = p_tolerance; |
1476 | push_constant.use_half_res = true; |
1477 | push_constant.proj_info[0] = -2.0f / (p_ssr_buffers.size.width * p_projections[v].columns[0][0]); |
1478 | push_constant.proj_info[1] = -2.0f / (p_ssr_buffers.size.height * p_projections[v].columns[1][1]); |
1479 | push_constant.proj_info[2] = (1.0f - p_projections[v].columns[0][2]) / p_projections[v].columns[0][0]; |
1480 | push_constant.proj_info[3] = (1.0f + p_projections[v].columns[1][2]) / p_projections[v].columns[1][1]; |
1481 | |
1482 | ScreenSpaceReflectionMode mode = (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL; |
1483 | RID shader = ssr.shader.version_get_shader(ssr.shader_version, mode); |
1484 | |
1485 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[pipeline_specialization][mode]); |
1486 | |
1487 | RD::Uniform u_scene_data(RD::UNIFORM_TYPE_UNIFORM_BUFFER, 0, ssr.ubo); |
1488 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 4, u_scene_data), 4); |
1489 | |
1490 | // read from intermediate |
1491 | RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ intermediate })); |
1492 | RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ depth_scaled })); |
1493 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_intermediate, u_scale_depth), 0); |
1494 | |
1495 | if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) { |
1496 | // write to output and blur radius |
1497 | RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ output })); |
1498 | RD::Uniform u_blur_radius(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ blur_radius[0] })); |
1499 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_output, u_blur_radius), 1); |
1500 | } else { |
1501 | // We are only writing output |
1502 | RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ output })); |
1503 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_output), 1); |
1504 | } |
1505 | |
1506 | RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ normal_scaled })); |
1507 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_scale_normal), 2); |
1508 | |
1509 | RD::Uniform u_metallic(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_metallic_slices[v] })); |
1510 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_metallic), 3); |
1511 | |
1512 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ScreenSpaceReflectionPushConstant)); |
1513 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssr_buffers.size.width, p_ssr_buffers.size.height, 1); |
1514 | |
1515 | RD::get_singleton()->draw_command_end_label(); |
1516 | } |
1517 | |
1518 | if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) { |
1519 | RD::get_singleton()->draw_command_begin_label("SSR filter" ); |
1520 | //blur |
1521 | |
1522 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1523 | |
1524 | ScreenSpaceReflectionFilterPushConstant push_constant; |
1525 | push_constant.view_index = v; |
1526 | push_constant.orthogonal = p_projections[v].is_orthogonal(); |
1527 | push_constant.edge_tolerance = Math::sin(Math::deg_to_rad(15.0)); |
1528 | push_constant.proj_info[0] = -2.0f / (p_ssr_buffers.size.width * p_projections[v].columns[0][0]); |
1529 | push_constant.proj_info[1] = -2.0f / (p_ssr_buffers.size.height * p_projections[v].columns[1][1]); |
1530 | push_constant.proj_info[2] = (1.0f - p_projections[v].columns[0][2]) / p_projections[v].columns[0][0]; |
1531 | push_constant.proj_info[3] = (1.0f + p_projections[v].columns[1][2]) / p_projections[v].columns[1][1]; |
1532 | push_constant.vertical = 0; |
1533 | if (ssr_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_LOW) { |
1534 | push_constant.steps = p_max_steps / 3; |
1535 | push_constant.increment = 3; |
1536 | } else if (ssr_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_MEDIUM) { |
1537 | push_constant.steps = p_max_steps / 2; |
1538 | push_constant.increment = 2; |
1539 | } else { |
1540 | push_constant.steps = p_max_steps; |
1541 | push_constant.increment = 1; |
1542 | } |
1543 | |
1544 | push_constant.screen_size[0] = p_ssr_buffers.size.width; |
1545 | push_constant.screen_size[1] = p_ssr_buffers.size.height; |
1546 | |
1547 | // Horizontal pass |
1548 | |
1549 | SSRReflectionMode mode = SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL; |
1550 | |
1551 | RID shader = ssr_filter.shader.version_get_shader(ssr_filter.shader_version, mode); |
1552 | |
1553 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[pipeline_specialization][mode]); |
1554 | |
1555 | RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ output })); |
1556 | RD::Uniform u_blur_radius(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ blur_radius[0] })); |
1557 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_output, u_blur_radius), 0); |
1558 | |
1559 | RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ normal_scaled })); |
1560 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_scale_normal), 1); |
1561 | |
1562 | RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ intermediate })); |
1563 | RD::Uniform u_blur_radius2(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ blur_radius[1] })); |
1564 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_intermediate, u_blur_radius2), 2); |
1565 | |
1566 | RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ depth_scaled })); |
1567 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_scale_depth), 3); |
1568 | |
1569 | RD::Uniform u_scene_data(RD::UNIFORM_TYPE_UNIFORM_BUFFER, 0, ssr.ubo); |
1570 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 4, u_scene_data), 4); |
1571 | |
1572 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant)); |
1573 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssr_buffers.size.width, p_ssr_buffers.size.height, 1); |
1574 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1575 | |
1576 | // Vertical pass |
1577 | |
1578 | mode = SCREEN_SPACE_REFLECTION_FILTER_VERTICAL; |
1579 | shader = ssr_filter.shader.version_get_shader(ssr_filter.shader_version, mode); |
1580 | |
1581 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[pipeline_specialization][mode]); |
1582 | |
1583 | push_constant.vertical = 1; |
1584 | |
1585 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_intermediate, u_blur_radius2), 0); |
1586 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_scale_normal), 1); |
1587 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_output), 2); |
1588 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_scale_depth), 3); |
1589 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 4, u_scene_data), 4); |
1590 | |
1591 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant)); |
1592 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssr_buffers.size.width, p_ssr_buffers.size.height, 1); |
1593 | |
1594 | if (v != view_count - 1) { |
1595 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1596 | } |
1597 | |
1598 | RD::get_singleton()->draw_command_end_label(); |
1599 | } |
1600 | |
1601 | RD::get_singleton()->draw_command_end_label(); |
1602 | } |
1603 | |
1604 | RD::get_singleton()->compute_list_end(); |
1605 | } |
1606 | |
1607 | /* Subsurface scattering */ |
1608 | |
1609 | void SSEffects::sss_set_quality(RS::SubSurfaceScatteringQuality p_quality) { |
1610 | sss_quality = p_quality; |
1611 | } |
1612 | |
1613 | RS::SubSurfaceScatteringQuality SSEffects::sss_get_quality() const { |
1614 | return sss_quality; |
1615 | } |
1616 | |
1617 | void SSEffects::sss_set_scale(float p_scale, float p_depth_scale) { |
1618 | sss_scale = p_scale; |
1619 | sss_depth_scale = p_depth_scale; |
1620 | } |
1621 | |
1622 | void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size) { |
1623 | UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); |
1624 | ERR_FAIL_NULL(uniform_set_cache); |
1625 | MaterialStorage *material_storage = MaterialStorage::get_singleton(); |
1626 | ERR_FAIL_NULL(material_storage); |
1627 | |
1628 | RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); |
1629 | |
1630 | // Our intermediate buffer is only created if we haven't created it already. |
1631 | RD::DataFormat format = p_render_buffers->get_base_data_format(); |
1632 | uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; |
1633 | uint32_t layers = 1; // We only need one layer, we're handling one view at a time |
1634 | uint32_t mipmaps = 1; // Image::get_image_required_mipmaps(p_screen_size.x, p_screen_size.y, Image::FORMAT_RGBAH); |
1635 | RID intermediate = p_render_buffers->create_texture(SNAME("SSR" ), SNAME("intermediate" ), format, usage_bits, RD::TEXTURE_SAMPLES_1, p_screen_size, layers, mipmaps); |
1636 | |
1637 | Plane p = p_camera.xform4(Plane(1, 0, -1, 1)); |
1638 | p.normal /= p.d; |
1639 | float unit_size = p.normal.x; |
1640 | |
1641 | { //scale color and depth to half |
1642 | RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); |
1643 | |
1644 | sss.push_constant.camera_z_far = p_camera.get_z_far(); |
1645 | sss.push_constant.camera_z_near = p_camera.get_z_near(); |
1646 | sss.push_constant.orthogonal = p_camera.is_orthogonal(); |
1647 | sss.push_constant.unit_size = unit_size; |
1648 | sss.push_constant.screen_size[0] = p_screen_size.x; |
1649 | sss.push_constant.screen_size[1] = p_screen_size.y; |
1650 | sss.push_constant.vertical = false; |
1651 | sss.push_constant.scale = sss_scale; |
1652 | sss.push_constant.depth_scale = sss_depth_scale; |
1653 | |
1654 | RID shader = sss.shader.version_get_shader(sss.shader_version, sss_quality - 1); |
1655 | RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[sss_quality - 1]); |
1656 | |
1657 | RD::Uniform u_diffuse_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_diffuse })); |
1658 | RD::Uniform u_diffuse(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_diffuse })); |
1659 | RD::Uniform u_intermediate_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, intermediate })); |
1660 | RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ intermediate })); |
1661 | RD::Uniform u_depth_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_depth })); |
1662 | |
1663 | // horizontal |
1664 | |
1665 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_diffuse_with_sampler), 0); |
1666 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_intermediate), 1); |
1667 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_depth_with_sampler), 2); |
1668 | |
1669 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant)); |
1670 | |
1671 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1); |
1672 | |
1673 | RD::get_singleton()->compute_list_add_barrier(compute_list); |
1674 | |
1675 | // vertical |
1676 | |
1677 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_intermediate_with_sampler), 0); |
1678 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_diffuse), 1); |
1679 | RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_depth_with_sampler), 2); |
1680 | |
1681 | sss.push_constant.vertical = true; |
1682 | RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant)); |
1683 | |
1684 | RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1); |
1685 | |
1686 | RD::get_singleton()->compute_list_end(); |
1687 | } |
1688 | } |
1689 | |