Blender V4.3
eevee_pipeline.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13#include "BLI_bounds.hh"
14#include "GPU_capabilities.hh"
15
16#include "eevee_instance.hh"
17#include "eevee_pipeline.hh"
18#include "eevee_shadow.hh"
19
20#include <iostream>
21
22#include "draw_common.hh"
23
24namespace blender::eevee {
25
26/* -------------------------------------------------------------------- */
33 const float background_opacity,
34 const float background_blur)
35{
36 Manager &manager = *inst_.manager;
37 RenderBuffers &rbufs = inst_.render_buffers;
38
39 world_ps_.init();
41 world_ps_.material_set(manager, gpumat);
42 world_ps_.push_constant("world_opacity_fade", background_opacity);
43 world_ps_.push_constant("world_background_blur", square_f(background_blur));
44 SphereProbeData &world_data = *static_cast<SphereProbeData *>(&inst_.light_probes.world_sphere_);
45 world_ps_.push_constant("world_coord_packed", reinterpret_cast<int4 *>(&world_data.atlas_coord));
46 world_ps_.bind_texture("utility_tx", inst_.pipelines.utility_tx);
47 /* RenderPasses & AOVs. */
48 world_ps_.bind_image("rp_color_img", &rbufs.rp_color_tx);
49 world_ps_.bind_image("rp_value_img", &rbufs.rp_value_tx);
50 world_ps_.bind_image("rp_cryptomatte_img", &rbufs.cryptomatte_tx);
51 /* Required by validation layers. */
52 world_ps_.bind_resources(inst_.cryptomatte);
53 world_ps_.bind_resources(inst_.uniform_data);
54 world_ps_.bind_resources(inst_.sampling);
55 world_ps_.bind_resources(inst_.sphere_probes);
56 world_ps_.bind_resources(inst_.volume_probes);
57 world_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
58 /* To allow opaque pass rendering over it. */
60
61 clear_ps_.init();
64 /* RenderPasses & AOVs. Cleared by background (even if bad practice). */
65 clear_ps_.bind_image("rp_color_img", &rbufs.rp_color_tx);
66 clear_ps_.bind_image("rp_value_img", &rbufs.rp_value_tx);
67 clear_ps_.bind_image("rp_cryptomatte_img", &rbufs.cryptomatte_tx);
68 /* Required by validation layers. */
69 clear_ps_.bind_resources(inst_.cryptomatte);
70 clear_ps_.bind_resources(inst_.uniform_data);
71 clear_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
72 /* To allow opaque pass rendering over it. */
74}
75
77{
78 inst_.manager->submit(clear_ps_, view);
79}
80
82{
83 inst_.manager->submit(world_ps_, view);
84}
85
88/* -------------------------------------------------------------------- */
93{
94 const int2 extent(1);
97 dummy_cryptomatte_tx_.ensure_2d(GPU_RGBA32F, extent, usage);
98 dummy_renderpass_tx_.ensure_2d(GPU_RGBA16F, extent, usage);
99 dummy_aov_color_tx_.ensure_2d_array(GPU_RGBA16F, extent, 1, usage);
100 dummy_aov_value_tx_.ensure_2d_array(GPU_R16F, extent, 1, usage);
101
102 PassSimple &pass = cubemap_face_ps_;
103 pass.init();
105
106 Manager &manager = *inst_.manager;
107 pass.material_set(manager, gpumat);
108 pass.push_constant("world_opacity_fade", 1.0f);
109 pass.push_constant("world_background_blur", 0.0f);
110 pass.push_constant("world_coord_packed", int4(0.0f));
111 pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
112 pass.bind_image("rp_normal_img", dummy_renderpass_tx_);
113 pass.bind_image("rp_light_img", dummy_renderpass_tx_);
114 pass.bind_image("rp_diffuse_color_img", dummy_renderpass_tx_);
115 pass.bind_image("rp_specular_color_img", dummy_renderpass_tx_);
116 pass.bind_image("rp_emission_img", dummy_renderpass_tx_);
117 pass.bind_image("rp_cryptomatte_img", dummy_cryptomatte_tx_);
118 pass.bind_image("rp_color_img", dummy_aov_color_tx_);
119 pass.bind_image("rp_value_img", dummy_aov_value_tx_);
120 pass.bind_image("aov_color_img", dummy_aov_color_tx_);
121 pass.bind_image("aov_value_img", dummy_aov_value_tx_);
122 pass.bind_ssbo("aov_buf", &inst_.film.aovs_info);
123 /* Required by validation layers. */
124 pass.bind_resources(inst_.cryptomatte);
125 pass.bind_resources(inst_.uniform_data);
126 pass.bind_resources(inst_.sampling);
127 pass.bind_resources(inst_.sphere_probes);
128 pass.bind_resources(inst_.volume_probes);
129 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
130}
131
133{
134 /* TODO(Miguel Pozo): All world probes are rendered as RAY_TYPE_GLOSSY. */
135 inst_.pipelines.data.is_sphere_probe = true;
137
138 inst_.manager->submit(cubemap_face_ps_, view);
139
140 inst_.pipelines.data.is_sphere_probe = false;
142}
143
146/* -------------------------------------------------------------------- */
152{
153 is_valid_ = (gpumat != nullptr) && (GPU_material_status(gpumat) == GPU_MAT_SUCCESS) &&
155 if (!is_valid_) {
156 /* Skip if the material has not compiled yet. */
157 return;
158 }
159
160 world_ps_.init();
163 world_ps_.bind_resources(inst_.uniform_data);
164 world_ps_.bind_resources(inst_.volume.properties);
165 world_ps_.bind_resources(inst_.sampling);
166
167 world_ps_.material_set(*inst_.manager, gpumat);
168 /* Bind correct dummy texture for attributes defaults. */
169 PassSimple::Sub *sub = volume_sub_pass(world_ps_, nullptr, nullptr, gpumat);
170
171 is_valid_ = (sub != nullptr);
172 if (is_valid_) {
173 world_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
174 /* Sync with object property pass. */
176 }
177}
178
180{
181 if (!is_valid_) {
182 /* Clear the properties buffer instead of rendering if there is no valid shader. */
183 inst_.volume.prop_scattering_tx_.clear(float4(0.0f));
184 inst_.volume.prop_extinction_tx_.clear(float4(0.0f));
185 inst_.volume.prop_emission_tx_.clear(float4(0.0f));
186 inst_.volume.prop_phase_tx_.clear(float4(0.0f));
187 inst_.volume.prop_phase_weight_tx_.clear(float4(0.0f));
188 return;
189 }
190
191 inst_.manager->submit(world_ps_, view);
192}
193
196/* -------------------------------------------------------------------- */
202{
203 render_ps_.init();
204
205 /* NOTE: TILE_COPY technique perform a three-pass implementation. First performing the clear
206 * directly on tile, followed by a fast depth-only pass, then storing the on-tile results into
207 * the shadow atlas during a final storage pass. This takes advantage of TBDR architecture,
208 * reducing overdraw and additional per-fragment calculations. */
209 bool shadow_update_tbdr = (ShadowModule::shadow_technique == ShadowTechnique::TILE_COPY);
210 if (shadow_update_tbdr) {
211 draw::PassMain::Sub &pass = render_ps_.sub("Shadow.TilePageClear");
213 pass.shader_set(inst_.shaders.static_shader_get(SHADOW_PAGE_TILE_CLEAR));
214 /* Only manually clear depth of the updated tiles.
215 * This is because the depth is initialized to near depth using attachments for fast clear and
216 * color is cleared to far depth. This way we can save a bit of bandwidth by only clearing
217 * the updated tiles depth to far depth and not touch the color attachment. */
219 pass.bind_ssbo("src_coord_buf", inst_.shadows.src_coord_buf_);
220 pass.draw_procedural_indirect(GPU_PRIM_TRIS, inst_.shadows.tile_draw_buf_);
221 }
222
223 {
224 /* Metal writes depth value in local tile memory, which is considered a color attachment. */
226
227 draw::PassMain::Sub &pass = render_ps_.sub("Shadow.Surface");
228 pass.state_set(state);
229 pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
230 pass.bind_ssbo(SHADOW_RENDER_VIEW_BUF_SLOT, &inst_.shadows.render_view_buf_);
231 if (!shadow_update_tbdr) {
232 /* We do not need all of the shadow information when using the TBDR-optimized approach. */
233 pass.bind_image(SHADOW_ATLAS_IMG_SLOT, inst_.shadows.atlas_tx_);
234 pass.bind_ssbo(SHADOW_RENDER_MAP_BUF_SLOT, &inst_.shadows.render_map_buf_);
235 pass.bind_ssbo(SHADOW_PAGE_INFO_SLOT, &inst_.shadows.pages_infos_data_);
236 }
237 pass.bind_resources(inst_.uniform_data);
238 pass.bind_resources(inst_.sampling);
239 surface_double_sided_ps_ = &pass.sub("Shadow.Surface.Double-Sided");
240 surface_single_sided_ps_ = &pass.sub("Shadow.Surface.Single-Sided");
241 surface_single_sided_ps_->state_set(state | DRW_STATE_CULL_BACK);
242 }
243
244 if (shadow_update_tbdr) {
245 draw::PassMain::Sub &pass = render_ps_.sub("Shadow.TilePageStore");
247 /* The most optimal way would be to only store pixels that have been rendered to (depth > 0).
248 * But that requires that the destination pages in the atlas would have been already cleared
249 * using compute. Experiments showed that it is faster to just copy the whole tiles back.
250 *
251 * For relative performance, raster-based clear within tile update adds around 0.1ms vs 0.25ms
252 * for compute based clear for a simple test case. */
253 pass.state_set(DRW_STATE_DEPTH_ALWAYS);
254 /* Metal have implicit sync with Raster Order Groups. Other backend need to have manual
255 * sub-pass transition to allow reading the frame-buffer. This is a no-op on Metal. */
256 pass.subpass_transition(GPU_ATTACHMENT_WRITE, {GPU_ATTACHMENT_READ});
257 pass.bind_image(SHADOW_ATLAS_IMG_SLOT, inst_.shadows.atlas_tx_);
258 pass.bind_ssbo("dst_coord_buf", inst_.shadows.dst_coord_buf_);
259 pass.bind_ssbo("src_coord_buf", inst_.shadows.src_coord_buf_);
260 pass.draw_procedural_indirect(GPU_PRIM_TRIS, inst_.shadows.tile_draw_buf_);
261 }
262}
263
265{
266 PassMain::Sub *pass = (material->blend_flag & MA_BL_CULL_BACKFACE_SHADOW) ?
267 surface_single_sided_ps_ :
268 surface_double_sided_ps_;
269 return &pass->sub(GPU_material_get_name(gpumat));
270}
271
273{
274 inst_.manager->submit(render_ps_, view);
275}
276
279/* -------------------------------------------------------------------- */
286{
287 camera_forward_ = inst_.camera.forward();
288 has_opaque_ = false;
289 has_transparent_ = false;
290
294 {
295 prepass_ps_.init();
296
297 {
298 /* Common resources. */
300 prepass_ps_.bind_resources(inst_.uniform_data);
301 prepass_ps_.bind_resources(inst_.velocity);
302 prepass_ps_.bind_resources(inst_.sampling);
303 }
304
305 prepass_double_sided_static_ps_ = &prepass_ps_.sub("DoubleSided.Static");
306 prepass_double_sided_static_ps_->state_set(state_depth_only);
307
308 prepass_single_sided_static_ps_ = &prepass_ps_.sub("SingleSided.Static");
309 prepass_single_sided_static_ps_->state_set(state_depth_only | DRW_STATE_CULL_BACK);
310
311 prepass_double_sided_moving_ps_ = &prepass_ps_.sub("DoubleSided.Moving");
312 prepass_double_sided_moving_ps_->state_set(state_depth_color);
313
314 prepass_single_sided_moving_ps_ = &prepass_ps_.sub("SingleSided.Moving");
315 prepass_single_sided_moving_ps_->state_set(state_depth_color | DRW_STATE_CULL_BACK);
316 }
317 {
318 opaque_ps_.init();
319
320 {
321 /* Common resources. */
323 opaque_ps_.bind_resources(inst_.uniform_data);
324 opaque_ps_.bind_resources(inst_.lights);
325 opaque_ps_.bind_resources(inst_.shadows);
326 opaque_ps_.bind_resources(inst_.volume.result);
327 opaque_ps_.bind_resources(inst_.sampling);
328 opaque_ps_.bind_resources(inst_.hiz_buffer.front);
329 opaque_ps_.bind_resources(inst_.volume_probes);
330 opaque_ps_.bind_resources(inst_.sphere_probes);
331 }
332
333 opaque_single_sided_ps_ = &opaque_ps_.sub("SingleSided");
334 opaque_single_sided_ps_->state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL |
336
337 opaque_double_sided_ps_ = &opaque_ps_.sub("DoubleSided");
338 opaque_double_sided_ps_->state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
339 }
340 {
341 transparent_ps_.init();
342 /* Workaround limitation of PassSortable. Use dummy pass that will be sorted first in all
343 * circumstances. */
344 PassMain::Sub &sub = transparent_ps_.sub("ResourceBind", -FLT_MAX);
345
346 /* Common resources. */
347
348 /* Textures. */
350
351 sub.bind_resources(inst_.uniform_data);
352 sub.bind_resources(inst_.lights);
353 sub.bind_resources(inst_.shadows);
354 sub.bind_resources(inst_.volume.result);
355 sub.bind_resources(inst_.sampling);
357 sub.bind_resources(inst_.volume_probes);
358 sub.bind_resources(inst_.sphere_probes);
359 }
360}
361
363 GPUMaterial *gpumat,
364 bool has_motion)
365{
367 "Forward Transparent should be registered directly without calling "
368 "PipelineModule::material_add()");
369 PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ?
370 (has_motion ? prepass_single_sided_moving_ps_ :
371 prepass_single_sided_static_ps_) :
372 (has_motion ? prepass_double_sided_moving_ps_ :
373 prepass_double_sided_static_ps_);
374
375 /* If material is fully additive or transparent, we can skip the opaque prepass. */
376 /* TODO(fclem): To skip it, we need to know if the transparent BSDF is fully white AND if there
377 * is no mix shader (could do better constant folding but that's expensive). */
378
379 has_opaque_ = true;
380 return &pass->sub(GPU_material_get_name(gpumat));
381}
382
384{
386 "Forward Transparent should be registered directly without calling "
387 "PipelineModule::material_add()");
388 PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? opaque_single_sided_ps_ :
389 opaque_double_sided_ps_;
390 has_opaque_ = true;
391 return &pass->sub(GPU_material_get_name(gpumat));
392}
393
395 ::Material *blender_mat,
396 GPUMaterial *gpumat)
397{
398 if ((blender_mat->blend_flag & MA_BL_HIDE_BACKFACE) == 0) {
399 return nullptr;
400 }
402 if (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) {
404 }
405 has_transparent_ = true;
406 float sorting_value = math::dot(float3(ob->object_to_world().location()), camera_forward_);
407 PassMain::Sub *pass = &transparent_ps_.sub(GPU_material_get_name(gpumat), sorting_value);
408 pass->state_set(state);
409 pass->material_set(*inst_.manager, gpumat);
410 return pass;
411}
412
414 ::Material *blender_mat,
415 GPUMaterial *gpumat)
416{
418 if (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) {
420 }
421 has_transparent_ = true;
422 float sorting_value = math::dot(float3(ob->object_to_world().location()), camera_forward_);
423 PassMain::Sub *pass = &transparent_ps_.sub(GPU_material_get_name(gpumat), sorting_value);
424 pass->state_set(state);
425 pass->material_set(*inst_.manager, gpumat);
426 return pass;
427}
428
430 Framebuffer &prepass_fb,
431 Framebuffer &combined_fb,
432 int2 extent)
433{
434 if (!has_transparent_ && !has_opaque_) {
435 inst_.volume.draw_resolve(view);
436 return;
437 }
438
439 DRW_stats_group_start("Forward.Opaque");
440
441 prepass_fb.bind();
442 inst_.manager->submit(prepass_ps_, view);
443
444 inst_.hiz_buffer.set_dirty();
445
446 inst_.shadows.set_view(view, extent);
447 inst_.volume_probes.set_view(view);
448 inst_.sphere_probes.set_view(view);
449
450 if (has_opaque_) {
451 combined_fb.bind();
452 inst_.manager->submit(opaque_ps_, view);
453 }
454
456
457 inst_.volume.draw_resolve(view);
458
459 if (has_transparent_) {
460 combined_fb.bind();
461 inst_.manager->submit(transparent_ps_, view);
462 }
463}
464
467/* -------------------------------------------------------------------- */
472{
480 /* G-buffer. */
483 /* RenderPasses & AOVs. */
486 /* Cryptomatte. */
488 /* Storage Buffer. */
489 /* Textures. */
491
496
497 /* Bind light resources for the NPR materials that gets rendered first.
498 * Non-NPR shaders will override these resource bindings. */
503
506
509
512
513 gbuffer_double_sided_ps_ = &gbuffer_ps_.sub("DoubleSided");
515
516 gbuffer_single_sided_ps_ = &gbuffer_ps_.sub("SingleSided");
518
520 closure_count_ = 0;
521}
522
524{
525 {
527 /* Textures. */
529
530 /* Make alpha hash scale sub-pixel so that it converges to a noise free image.
531 * If there is motion, use pixel scale for stability. */
532 bool alpha_hash_subpixel_scale = !inst_.is_viewport() || !inst_.velocity.camera_has_motion();
533 inst_.pipelines.data.alpha_hash_scale = alpha_hash_subpixel_scale ? 0.1f : 1.0f;
534
538
542
543 prepass_double_sided_static_ps_ = &prepass_ps_.sub("DoubleSided.Static");
545
546 prepass_single_sided_static_ps_ = &prepass_ps_.sub("SingleSided.Static");
548
549 prepass_double_sided_moving_ps_ = &prepass_ps_.sub("DoubleSided.Moving");
550 prepass_double_sided_moving_ps_->state_set(state_depth_color);
551
552 prepass_single_sided_moving_ps_ = &prepass_ps_.sub("SingleSided.Moving");
554 }
555
556 this->gbuffer_pass_sync(inst_);
557}
558
559void DeferredLayer::end_sync(bool is_first_pass,
560 bool is_last_pass,
561 bool next_layer_has_transmission)
562{
563 const SceneEEVEE &sce_eevee = inst_.scene->eevee;
564 const bool has_any_closure = closure_bits_ != 0;
565 /* We need the feedback output in case of refraction in the next pass (see #126455). */
566 const bool is_layer_refracted = (next_layer_has_transmission && has_any_closure);
567 const bool has_transmit_closure = (closure_bits_ & (CLOSURE_REFRACTION | CLOSURE_TRANSLUCENT));
568 const bool has_reflect_closure = (closure_bits_ & (CLOSURE_REFLECTION | CLOSURE_DIFFUSE));
569 use_raytracing_ = (has_transmit_closure || has_reflect_closure) &&
570 (sce_eevee.flag & SCE_EEVEE_SSR_ENABLED) != 0;
571
572 use_clamp_direct_ = sce_eevee.clamp_surface_direct != 0.0f;
573 use_clamp_indirect_ = sce_eevee.clamp_surface_indirect != 0.0f;
574
575 /* The first pass will never have any surfaces behind it. Nothing is refracted except the
576 * environment. So in this case, disable tracing and fallback to probe. */
577 use_screen_transmission_ = use_raytracing_ && has_transmit_closure && !is_first_pass;
578 use_screen_reflection_ = use_raytracing_ && has_reflect_closure;
579
580 use_split_radiance_ = use_raytracing_ || (use_clamp_direct_ || use_clamp_indirect_);
581 use_feedback_output_ = (use_raytracing_ || is_layer_refracted) &&
582 (!is_last_pass || use_screen_reflection_);
583
584 {
585 RenderBuffersInfoData &rbuf_data = inst_.render_buffers.data;
586
587 /* Add the stencil classification step at the end of the GBuffer pass. */
588 {
590 PassMain::Sub &sub = gbuffer_ps_.sub("StencilClassify");
591 sub.subpass_transition(GPU_ATTACHMENT_WRITE, /* Needed for depth test. */
593 GPU_ATTACHMENT_READ, /* Header. */
597 sub.shader_set(sh);
599 /* Binding any buffer to satisfy the binding. The buffer is not actually used. */
600 sub.bind_ssbo("dummy_workaround_buf", &inst_.film.aovs_info);
601 }
604 /* The shader sets the stencil directly in one full-screen pass. */
605 sub.state_stencil(uint8_t(StencilBits::HEADER_BITS), /* Set by shader */ 0x0u, 0xFFu);
607 }
608 else {
609 /* The shader cannot set the stencil directly. So we do one full-screen pass for each
610 * stencil bit we need to set and accumulate the result. */
611 auto set_bit = [&](StencilBits bit) {
612 sub.push_constant("current_bit", int(bit));
613 sub.state_stencil(uint8_t(bit), 0xFFu, 0xFFu);
615 };
616
617 if (closure_count_ > 0) {
618 set_bit(StencilBits::CLOSURE_COUNT_0);
619 }
620 if (closure_count_ > 1) {
621 set_bit(StencilBits::CLOSURE_COUNT_1);
622 }
624 set_bit(StencilBits::TRANSMISSION);
625 }
626 }
627 }
628
629 {
630 PassSimple &pass = eval_light_ps_;
631 pass.init();
632
633 /* TODO(fclem): Could also skip if no material uses thickness from shadow. */
635 PassSimple::Sub &sub = pass.sub("Eval.ThicknessFromShadow");
637 sub.bind_resources(inst_.lights);
638 sub.bind_resources(inst_.shadows);
640 sub.bind_resources(inst_.uniform_data);
641 sub.bind_resources(inst_.sampling);
642 sub.bind_texture("gbuf_header_tx", &inst_.gbuffer.header_tx);
643 sub.bind_image("gbuf_normal_img", &inst_.gbuffer.normal_tx);
645 /* Render where there is transmission and the thickness from shadow bit is set. */
646 uint8_t stencil_bits = uint8_t(StencilBits::TRANSMISSION) |
647 uint8_t(StencilBits::THICKNESS_FROM_SHADOW);
648 sub.state_stencil(0x0u, stencil_bits, stencil_bits);
651 }
652 {
653 const bool use_transmission = (closure_bits_ & CLOSURE_TRANSMISSION) != 0;
654 const bool use_split_indirect = !use_raytracing_ && use_split_radiance_;
655 PassSimple::Sub &sub = pass.sub("Eval.Light");
656 /* Use depth test to reject background pixels which have not been stencil cleared. */
657 /* WORKAROUND: Avoid rasterizer discard by enabling stencil write, but the shaders actually
658 * use no fragment output. */
663 /* Submit the more costly ones first to avoid long tail in occupancy.
664 * See page 78 of "SIGGRAPH 2023: Unreal Engine Substrate" by Hillaire & de Rousiers. */
665 for (int i = min_ii(3, closure_count_) - 1; i >= 0; i--) {
667 /* TODO(fclem): Could specialize directly with the pass index but this would break it for
668 * OpenGL and Vulkan implementation which aren't fully supporting the specialize
669 * constant. */
670 sub.specialize_constant(sh, "render_pass_shadow_id", rbuf_data.shadow_id);
671 sub.specialize_constant(sh, "use_split_indirect", use_split_indirect);
672 sub.specialize_constant(sh, "use_lightprobe_eval", !use_raytracing_);
673 sub.specialize_constant(sh, "use_transmission", false);
674 const ShadowSceneData &shadow_scene = inst_.shadows.get_data();
675 sub.specialize_constant(sh, "shadow_ray_count", &shadow_scene.ray_count);
676 sub.specialize_constant(sh, "shadow_ray_step_count", &shadow_scene.step_count);
677 sub.shader_set(sh);
678 sub.bind_image("direct_radiance_1_img", &direct_radiance_txs_[0]);
679 sub.bind_image("direct_radiance_2_img", &direct_radiance_txs_[1]);
680 sub.bind_image("direct_radiance_3_img", &direct_radiance_txs_[2]);
681 sub.bind_image("indirect_radiance_1_img", &indirect_result_.closures[0]);
682 sub.bind_image("indirect_radiance_2_img", &indirect_result_.closures[1]);
683 sub.bind_image("indirect_radiance_3_img", &indirect_result_.closures[2]);
684 sub.bind_resources(inst_.uniform_data);
685 sub.bind_resources(inst_.gbuffer);
686 sub.bind_resources(inst_.lights);
687 sub.bind_resources(inst_.shadows);
688 sub.bind_resources(inst_.sampling);
690 sub.bind_resources(inst_.sphere_probes);
691 sub.bind_resources(inst_.volume_probes);
692 uint8_t compare_mask = uint8_t(StencilBits::CLOSURE_COUNT_0) |
693 uint8_t(StencilBits::CLOSURE_COUNT_1) |
694 uint8_t(StencilBits::TRANSMISSION);
695 sub.state_stencil(0x0u, i + 1, compare_mask);
697 if (use_transmission) {
698 /* Separate pass for transmission BSDF as their evaluation is quite costly. */
699 sub.specialize_constant(sh, "use_transmission", true);
700 sub.shader_set(sh);
701 sub.state_stencil(0x0u, (i + 1) | uint8_t(StencilBits::TRANSMISSION), compare_mask);
703 }
704 }
705 }
706 }
707 {
708 PassSimple &pass = combine_ps_;
709 pass.init();
711 /* TODO(fclem): Could specialize directly with the pass index but this would break it for
712 * OpenGL and Vulkan implementation which aren't fully supporting the specialize
713 * constant. */
714 pass.specialize_constant(sh,
715 "render_pass_diffuse_light_enabled",
716 (rbuf_data.diffuse_light_id != -1) ||
717 (rbuf_data.diffuse_color_id != -1));
718 pass.specialize_constant(sh,
719 "render_pass_specular_light_enabled",
720 (rbuf_data.specular_light_id != -1) ||
721 (rbuf_data.specular_color_id != -1));
722 pass.specialize_constant(sh, "use_split_radiance", use_split_radiance_);
723 pass.specialize_constant(
724 sh, "use_radiance_feedback", use_feedback_output_ && use_clamp_direct_);
725 pass.specialize_constant(sh, "render_pass_normal_enabled", rbuf_data.normal_id != -1);
726 pass.shader_set(sh);
727 /* Use stencil test to reject pixels not written by this layer. */
729 /* Render where stencil is not 0. */
730 pass.state_stencil(0x0u, 0x0u, uint8_t(StencilBits::HEADER_BITS));
731 pass.bind_texture("direct_radiance_1_tx", &direct_radiance_txs_[0]);
732 pass.bind_texture("direct_radiance_2_tx", &direct_radiance_txs_[1]);
733 pass.bind_texture("direct_radiance_3_tx", &direct_radiance_txs_[2]);
734 pass.bind_texture("indirect_radiance_1_tx", &indirect_result_.closures[0]);
735 pass.bind_texture("indirect_radiance_2_tx", &indirect_result_.closures[1]);
736 pass.bind_texture("indirect_radiance_3_tx", &indirect_result_.closures[2]);
737 pass.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx);
738 pass.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx);
739 pass.bind_image("radiance_feedback_img", &radiance_feedback_tx_);
740 pass.bind_resources(inst_.gbuffer);
741 pass.bind_resources(inst_.uniform_data);
743 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
744 }
745 }
746}
747
749 GPUMaterial *gpumat,
750 bool has_motion)
751{
752 PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ?
753 (has_motion ? prepass_single_sided_moving_ps_ :
755 (has_motion ? prepass_double_sided_moving_ps_ :
757
758 return &pass->sub(GPU_material_get_name(gpumat));
759}
760
762{
763 eClosureBits closure_bits = shader_closure_bits_from_flag(gpumat);
764 if (closure_bits == eClosureBits(0)) {
765 /* Fix the case where there is no active closure in the shader.
766 * In this case we force the evaluation of emission to avoid disabling the entire layer by
767 * accident, see #126459. */
768 closure_bits |= CLOSURE_EMISSION;
769 }
770 closure_bits_ |= closure_bits;
772
773 bool has_shader_to_rgba = (closure_bits & CLOSURE_SHADER_TO_RGBA) != 0;
774 bool backface_culling = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) != 0;
775 bool use_thickness_from_shadow = (blender_mat->blend_flag & MA_BL_THICKNESS_FROM_SHADOW) != 0;
776
777 PassMain::Sub *pass = (has_shader_to_rgba) ?
778 ((backface_culling) ? gbuffer_single_sided_hybrid_ps_ :
780 ((backface_culling) ? gbuffer_single_sided_ps_ :
782
783 PassMain::Sub *material_pass = &pass->sub(GPU_material_get_name(gpumat));
784 /* Set stencil for some deferred specialized shaders. */
785 uint8_t material_stencil_bits = 0u;
786 if (use_thickness_from_shadow) {
787 material_stencil_bits |= uint8_t(StencilBits::THICKNESS_FROM_SHADOW);
788 }
789 /* We use this opportunity to clear the stencil bits. The undefined areas are discarded using the
790 * gbuf header value. */
791 material_pass->state_stencil(0xFFu, material_stencil_bits, 0xFFu);
792
793 return material_pass;
794}
795
796GPUTexture *DeferredLayer::render(View &main_view,
797 View &render_view,
798 Framebuffer &prepass_fb,
799 Framebuffer &combined_fb,
800 Framebuffer &gbuffer_fb,
801 int2 extent,
802 RayTraceBuffer &rt_buffer,
803 GPUTexture *radiance_behind_tx)
804{
805 if (closure_count_ == 0) {
806 return nullptr;
807 }
808
809 RenderBuffers &rb = inst_.render_buffers;
810
811 constexpr eGPUTextureUsage usage_read = GPU_TEXTURE_USAGE_SHADER_READ;
812 constexpr eGPUTextureUsage usage_write = GPU_TEXTURE_USAGE_SHADER_WRITE;
813 constexpr eGPUTextureUsage usage_rw = usage_read | usage_write;
814
815 if (use_screen_transmission_) {
816 /* Update for refraction. */
817 inst_.hiz_buffer.update();
818 }
819
820 GPU_framebuffer_bind(prepass_fb);
821 inst_.manager->submit(prepass_ps_, render_view);
822
823 inst_.hiz_buffer.swap_layer();
824 /* Update for lighting pass or AO node. */
825 inst_.hiz_buffer.update();
826
827 inst_.volume_probes.set_view(render_view);
828 inst_.sphere_probes.set_view(render_view);
829 inst_.shadows.set_view(render_view, extent);
830
831 inst_.gbuffer.bind(gbuffer_fb);
832 inst_.manager->submit(gbuffer_ps_, render_view);
833
834 for (int i = 0; i < ARRAY_SIZE(direct_radiance_txs_); i++) {
835 direct_radiance_txs_[i].acquire(
836 (closure_count_ > i) ? extent : int2(1), DEFERRED_RADIANCE_FORMAT, usage_rw);
837 }
838
839 if (use_raytracing_) {
840 indirect_result_ = inst_.raytracing.render(
841 rt_buffer, radiance_behind_tx, closure_bits_, main_view, render_view);
842 }
843 else if (use_split_radiance_) {
844 indirect_result_ = inst_.raytracing.alloc_only(rt_buffer);
845 }
846 else {
847 indirect_result_ = inst_.raytracing.alloc_dummy(rt_buffer);
848 }
849
850 GPU_framebuffer_bind(combined_fb);
851 inst_.manager->submit(eval_light_ps_, render_view);
852
853 inst_.subsurface.render(
854 direct_radiance_txs_[0], indirect_result_.closures[0], closure_bits_, render_view);
855
856 radiance_feedback_tx_ = rt_buffer.feedback_ensure(!use_feedback_output_, extent);
857
858 if (use_feedback_output_ && use_clamp_direct_) {
859 /* We need to do a copy before the combine pass (otherwise we have a dependency issue) to save
860 * the emission and the previous layer's radiance. */
861 GPU_texture_copy(radiance_feedback_tx_, rb.combined_tx);
862 }
863
864 GPU_framebuffer_bind(combined_fb);
865 inst_.manager->submit(combine_ps_);
866
867 if (use_feedback_output_ && !use_clamp_direct_) {
868 /* We skip writing the radiance during the combine pass. Do a simple fast copy. */
869 GPU_texture_copy(radiance_feedback_tx_, rb.combined_tx);
870 }
871
872 indirect_result_.release();
873
874 for (int i = 0; i < ARRAY_SIZE(direct_radiance_txs_); i++) {
875 direct_radiance_txs_[i].release();
876 }
877
878 inst_.pipelines.deferred.debug_draw(render_view, combined_fb);
879
880 return use_feedback_output_ ? radiance_feedback_tx_ : nullptr;
881}
882
885/* -------------------------------------------------------------------- */
892{
893 Instance &inst = opaque_layer_.inst_;
894
895 const bool use_raytracing = (inst.scene->eevee.flag & SCE_EEVEE_SSR_ENABLED) != 0;
896 use_combined_lightprobe_eval = !use_raytracing;
897
898 opaque_layer_.begin_sync();
899 refraction_layer_.begin_sync();
900}
901
903{
904 opaque_layer_.end_sync(true, refraction_layer_.is_empty(), refraction_layer_.has_transmission());
905 refraction_layer_.end_sync(opaque_layer_.is_empty(), true, false);
906
907 debug_pass_sync();
908}
909
910void DeferredPipeline::debug_pass_sync()
911{
912 Instance &inst = opaque_layer_.inst_;
913 if (!ELEM(inst.debug_mode,
916 {
917 return;
918 }
919
920 PassSimple &pass = debug_draw_ps_;
921 pass.init();
923 pass.shader_set(inst.shaders.static_shader_get(DEBUG_GBUFFER));
924 pass.push_constant("debug_mode", int(inst.debug_mode));
925 pass.bind_resources(inst.gbuffer);
926 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
927}
928
929void DeferredPipeline::debug_draw(draw::View &view, GPUFrameBuffer *combined_fb)
930{
931 Instance &inst = opaque_layer_.inst_;
932 if (!ELEM(inst.debug_mode,
935 {
936 return;
937 }
938
939 switch (inst.debug_mode) {
941 inst.info_append("Debug Mode: Deferred Lighting Cost");
942 break;
944 inst.info_append("Debug Mode: Gbuffer Storage Cost");
945 break;
946 default:
947 /* Nothing to display. */
948 return;
949 }
950
951 GPU_framebuffer_bind(combined_fb);
952 inst.manager->submit(debug_draw_ps_, view);
953}
954
956 GPUMaterial *gpumat,
957 bool has_motion)
958{
959 if (!use_combined_lightprobe_eval && (blender_mat->blend_flag & MA_BL_SS_REFRACTION)) {
960 return refraction_layer_.prepass_add(blender_mat, gpumat, has_motion);
961 }
962 else {
963 return opaque_layer_.prepass_add(blender_mat, gpumat, has_motion);
964 }
965}
966
968{
969 if (!use_combined_lightprobe_eval && (blender_mat->blend_flag & MA_BL_SS_REFRACTION)) {
970 return refraction_layer_.material_add(blender_mat, gpumat);
971 }
972 else {
973 return opaque_layer_.material_add(blender_mat, gpumat);
974 }
975}
976
978 View &render_view,
979 Framebuffer &prepass_fb,
980 Framebuffer &combined_fb,
981 Framebuffer &gbuffer_fb,
982 int2 extent,
983 RayTraceBuffer &rt_buffer_opaque_layer,
984 RayTraceBuffer &rt_buffer_refract_layer)
985{
986 GPUTexture *feedback_tx = nullptr;
987
988 DRW_stats_group_start("Deferred.Opaque");
989 feedback_tx = opaque_layer_.render(main_view,
990 render_view,
991 prepass_fb,
992 combined_fb,
993 gbuffer_fb,
994 extent,
995 rt_buffer_opaque_layer,
996 feedback_tx);
998
999 DRW_stats_group_start("Deferred.Refract");
1000 feedback_tx = refraction_layer_.render(main_view,
1001 render_view,
1002 prepass_fb,
1003 combined_fb,
1004 gbuffer_fb,
1005 extent,
1006 rt_buffer_refract_layer,
1007 feedback_tx);
1009}
1010
1013/* -------------------------------------------------------------------- */
1019{
1020 object_bounds_.clear();
1021 combined_screen_bounds_ = std::nullopt;
1022 use_hit_list = false;
1023 is_empty = true;
1024 finalized = false;
1025 has_scatter = false;
1026 has_absorption = false;
1027
1028 draw::PassMain &layer_pass = volume_layer_ps_;
1029 layer_pass.init();
1030 layer_pass.clear_stencil(0x0u);
1031 {
1032 PassMain::Sub &pass = layer_pass.sub("occupancy_ps");
1033 /* Always double sided to let all fragments be invoked. */
1035 pass.bind_resources(inst_.uniform_data);
1036 pass.bind_resources(inst_.volume.occupancy);
1037 pass.bind_resources(inst_.sampling);
1038 occupancy_ps_ = &pass;
1039 }
1040 {
1041 PassMain::Sub &pass = layer_pass.sub("material_ps");
1042 /* Double sided with stencil equal to ensure only one fragment is invoked per pixel. */
1044 pass.state_stencil(0x1u, 0x1u, 0x1u);
1045 pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
1046 pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
1047 pass.bind_resources(inst_.uniform_data);
1048 pass.bind_resources(inst_.volume.properties);
1049 pass.bind_resources(inst_.sampling);
1050 material_ps_ = &pass;
1051 }
1052}
1053
1055 const ::Material *blender_mat,
1056 GPUMaterial *gpumat)
1057{
1059 "Only volume material should be added here");
1060 bool use_fast_occupancy = (ob->type == OB_VOLUME) ||
1061 (blender_mat->volume_intersection_method == MA_VOLUME_ISECT_FAST);
1062 use_hit_list |= !use_fast_occupancy;
1063 is_empty = false;
1064
1065 PassMain::Sub *pass = &occupancy_ps_->sub(GPU_material_get_name(gpumat));
1066 pass->material_set(*inst_.manager, gpumat);
1067 pass->push_constant("use_fast_method", use_fast_occupancy);
1068 return pass;
1069}
1070
1072 const ::Material * /*blender_mat*/,
1073 GPUMaterial *gpumat)
1074{
1076 "Only volume material should be added here");
1078
1079 PassMain::Sub *pass = &material_ps_->sub(GPU_material_get_name(gpumat));
1080 pass->material_set(*inst_.manager, gpumat);
1082 has_scatter = true;
1083 }
1085 has_absorption = true;
1086 }
1087 return pass;
1088}
1089
1090bool VolumeLayer::bounds_overlaps(const VolumeObjectBounds &object_bounds) const
1091{
1092 /* First check the biggest area. */
1093 if (bounds::intersect(object_bounds.screen_bounds, combined_screen_bounds_)) {
1094 return true;
1095 }
1096 /* Check against individual bounds to try to squeeze the new object between them. */
1097 for (const std::optional<Bounds<float2>> &other_aabb : object_bounds_) {
1098 if (bounds::intersect(object_bounds.screen_bounds, other_aabb)) {
1099 return true;
1100 }
1101 }
1102 return false;
1103}
1104
1106{
1107 object_bounds_.append(object_bounds.screen_bounds);
1108 combined_screen_bounds_ = bounds::merge(combined_screen_bounds_, object_bounds.screen_bounds);
1109}
1110
1111void VolumeLayer::render(View &view, Texture &occupancy_tx)
1112{
1113 if (is_empty) {
1114 return;
1115 }
1116 if (finalized == false) {
1117 finalized = true;
1118 if (use_hit_list) {
1119 /* Add resolve pass only when needed. Insert after occupancy, before material pass. */
1122 occupancy_ps_->draw_procedural(GPU_PRIM_TRIS, 1, 3);
1123 }
1124 }
1125 /* TODO(fclem): Move this clear inside the render pass. */
1126 occupancy_tx.clear(uint4(0u));
1127 inst_.manager->submit(volume_layer_ps_, view);
1128}
1129
1132/* -------------------------------------------------------------------- */
1137{
1138 object_integration_range_ = std::nullopt;
1139 has_scatter_ = false;
1140 has_absorption_ = false;
1141 for (auto &layer : layers_) {
1142 layer->sync();
1143 }
1144}
1145
1146void VolumePipeline::render(View &view, Texture &occupancy_tx)
1147{
1148 for (auto &layer : layers_) {
1149 layer->render(view, occupancy_tx);
1150 }
1151}
1152
1154{
1155 /* TODO(fclem): For panoramic camera, we will have to do this check for each cube-face. */
1156 const float4x4 &view_matrix = camera.data_get().viewmat;
1157 /* Note in practice we only care about the projection type since we only care about 2D overlap,
1158 * and this is independent of FOV. */
1159 const float4x4 &projection_matrix = camera.data_get().winmat;
1160
1161 const Bounds<float3> bounds = BKE_object_boundbox_get(ob).value_or(Bounds(float3(0.0f)));
1162
1163 BoundBox bb;
1164 BKE_boundbox_init_from_minmax(&bb, bounds.min, bounds.max);
1165
1166 screen_bounds = std::nullopt;
1167 z_range = std::nullopt;
1168
1169 for (float3 l_corner : bb.vec) {
1170 float3 ws_corner = math::transform_point(ob->object_to_world(), l_corner);
1171 /* Split view and projection for precision. */
1172 float3 vs_corner = math::transform_point(view_matrix, ws_corner);
1173 float3 ss_corner = math::project_point(projection_matrix, vs_corner);
1174
1175 z_range = bounds::min_max(z_range, vs_corner.z);
1176 if (camera.is_perspective() && vs_corner.z >= 1.0e-8f) {
1177 /* If the object is crossing the z=0 plane, we can't determine its 2D bounds easily.
1178 * In this case, consider the object covering the whole screen.
1179 * Still continue the loop for the Z range. */
1180 screen_bounds = Bounds<float2>(float2(-1.0f), float2(1.0f));
1181 }
1182 else {
1184 }
1185 }
1186}
1187
1189{
1190 VolumeObjectBounds object_bounds(inst_.camera, ob);
1191 object_integration_range_ = bounds::merge(object_integration_range_, object_bounds.z_range);
1192
1193 /* Do linear search in all layers in order. This can be optimized. */
1194 for (auto &layer : layers_) {
1195 if (!layer->bounds_overlaps(object_bounds)) {
1196 layer->add_object_bound(object_bounds);
1197 return layer.get();
1198 }
1199 }
1200 /* No non-overlapping layer found. Create new one. */
1201 int64_t index = layers_.append_and_get_index(std::make_unique<VolumeLayer>(inst_));
1202 (*layers_[index]).add_object_bound(object_bounds);
1203 return layers_[index].get();
1204}
1205
1206std::optional<Bounds<float>> VolumePipeline::object_integration_range() const
1207{
1208 return object_integration_range_;
1209}
1210
1212{
1213 for (auto &layer : layers_) {
1214 if (layer->use_hit_list) {
1215 return true;
1216 }
1217 }
1218 return false;
1219}
1220
1223/* -------------------------------------------------------------------- */
1230{
1231 draw::PassMain &pass = opaque_layer_.prepass_ps_;
1232 pass.init();
1233 {
1234 /* Common resources. */
1235
1236 /* Textures. */
1237 pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
1238
1239 pass.bind_resources(inst_.uniform_data);
1240 pass.bind_resources(inst_.velocity);
1241 pass.bind_resources(inst_.sampling);
1242 }
1243
1245 /* Only setting up static pass because we don't use motion vectors for light-probes. */
1246 opaque_layer_.prepass_double_sided_static_ps_ = &pass.sub("DoubleSided");
1247 opaque_layer_.prepass_double_sided_static_ps_->state_set(state_depth_only);
1248 opaque_layer_.prepass_single_sided_static_ps_ = &pass.sub("SingleSided");
1249 opaque_layer_.prepass_single_sided_static_ps_->state_set(state_depth_only | DRW_STATE_CULL_BACK);
1250
1251 opaque_layer_.gbuffer_pass_sync(inst_);
1252}
1253
1255{
1256 {
1257 PassSimple &pass = eval_light_ps_;
1258 pass.init();
1259 /* Use depth test to reject background pixels. */
1261 pass.shader_set(inst_.shaders.static_shader_get(DEFERRED_CAPTURE_EVAL));
1262 pass.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx);
1263 pass.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx);
1264 pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
1265 pass.bind_resources(inst_.uniform_data);
1266 pass.bind_resources(inst_.gbuffer);
1267 pass.bind_resources(inst_.lights);
1268 pass.bind_resources(inst_.shadows);
1269 pass.bind_resources(inst_.sampling);
1270 pass.bind_resources(inst_.hiz_buffer.front);
1271 pass.bind_resources(inst_.volume_probes);
1273 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
1274 }
1275}
1276
1278{
1279 PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ?
1280 opaque_layer_.prepass_single_sided_static_ps_ :
1281 opaque_layer_.prepass_double_sided_static_ps_;
1282
1283 return &pass->sub(GPU_material_get_name(gpumat));
1284}
1285
1287{
1288 eClosureBits closure_bits = shader_closure_bits_from_flag(gpumat);
1289 if (closure_bits == eClosureBits(0)) {
1290 /* Fix the case where there is no active closure in the shader.
1291 * In this case we force the evaluation of emission to avoid disabling the entire layer by
1292 * accident, see #126459. */
1293 closure_bits |= CLOSURE_EMISSION;
1294 }
1295 opaque_layer_.closure_bits_ |= closure_bits;
1296 opaque_layer_.closure_count_ = max_ii(opaque_layer_.closure_count_, count_bits_i(closure_bits));
1297
1298 bool has_shader_to_rgba = (closure_bits & CLOSURE_SHADER_TO_RGBA) != 0;
1299 bool backface_culling = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) != 0;
1300
1301 PassMain::Sub *pass = (has_shader_to_rgba) ?
1302 ((backface_culling) ? opaque_layer_.gbuffer_single_sided_hybrid_ps_ :
1303 opaque_layer_.gbuffer_double_sided_hybrid_ps_) :
1304 ((backface_culling) ? opaque_layer_.gbuffer_single_sided_ps_ :
1305 opaque_layer_.gbuffer_double_sided_ps_);
1306
1307 return &pass->sub(GPU_material_get_name(gpumat));
1308}
1309
1311 Framebuffer &prepass_fb,
1312 Framebuffer &combined_fb,
1313 Framebuffer &gbuffer_fb,
1314 int2 extent)
1315{
1316 GPU_debug_group_begin("Probe.Render");
1317
1318 GPU_framebuffer_bind(prepass_fb);
1319 inst_.manager->submit(opaque_layer_.prepass_ps_, view);
1320
1322 inst_.hiz_buffer.update();
1323
1324 inst_.lights.set_view(view, extent);
1325 inst_.shadows.set_view(view, extent);
1326 inst_.volume_probes.set_view(view);
1327 inst_.sphere_probes.set_view(view);
1328
1329 /* Update for lighting pass. */
1330 inst_.hiz_buffer.update();
1331
1332 inst_.gbuffer.bind(gbuffer_fb);
1333 inst_.manager->submit(opaque_layer_.gbuffer_ps_, view);
1334
1335 GPU_framebuffer_bind(combined_fb);
1336 inst_.manager->submit(eval_light_ps_, view);
1337
1339}
1340
1343/* -------------------------------------------------------------------- */
1349{
1350 {
1351 prepass_ps_.init();
1353 prepass_ps_.bind_ubo(CLIP_PLANE_BUF, inst_.planar_probes.world_clip_buf_);
1356
1358
1359 prepass_double_sided_static_ps_ = &prepass_ps_.sub("DoubleSided.Static");
1360 prepass_double_sided_static_ps_->state_set(state_depth_only);
1361
1362 prepass_single_sided_static_ps_ = &prepass_ps_.sub("SingleSided.Static");
1364 }
1365
1366 this->gbuffer_pass_sync(inst_);
1367
1368 {
1369 PassSimple &pass = eval_light_ps_;
1370 pass.init();
1372 pass.shader_set(inst_.shaders.static_shader_get(DEFERRED_PLANAR_EVAL));
1373 pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
1374 pass.bind_resources(inst_.uniform_data);
1375 pass.bind_resources(inst_.gbuffer);
1376 pass.bind_resources(inst_.lights);
1377 pass.bind_resources(inst_.shadows);
1378 pass.bind_resources(inst_.sampling);
1379 pass.bind_resources(inst_.hiz_buffer.front);
1380 pass.bind_resources(inst_.sphere_probes);
1381 pass.bind_resources(inst_.volume_probes);
1383 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
1384 }
1385
1387 closure_count_ = 0;
1388}
1389
1391{
1392 /* No-op for now. */
1393}
1394
1402
1404{
1405 eClosureBits closure_bits = shader_closure_bits_from_flag(gpumat);
1406 if (closure_bits == eClosureBits(0)) {
1407 /* Fix the case where there is no active closure in the shader.
1408 * In this case we force the evaluation of emission to avoid disabling the entire layer by
1409 * accident, see #126459. */
1410 closure_bits |= CLOSURE_EMISSION;
1411 }
1412 closure_bits_ |= closure_bits;
1414
1415 bool has_shader_to_rgba = (closure_bits & CLOSURE_SHADER_TO_RGBA) != 0;
1416 bool backface_culling = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) != 0;
1417
1418 PassMain::Sub *pass = (has_shader_to_rgba) ?
1419 ((backface_culling) ? gbuffer_single_sided_hybrid_ps_ :
1421 ((backface_culling) ? gbuffer_single_sided_ps_ :
1423
1424 return &pass->sub(GPU_material_get_name(gpumat));
1425}
1426
1428 GPUTexture *depth_layer_tx,
1429 Framebuffer &gbuffer_fb,
1430 Framebuffer &combined_fb,
1431 int2 extent)
1432{
1433 GPU_debug_group_begin("Planar.Capture");
1434
1435 inst_.pipelines.data.is_sphere_probe = true;
1436 inst_.uniform_data.push_update();
1437
1438 GPU_framebuffer_bind(gbuffer_fb);
1439 GPU_framebuffer_clear_depth(gbuffer_fb, 1.0f);
1440 inst_.manager->submit(prepass_ps_, view);
1441
1442 /* TODO(fclem): This is the only place where we use the layer source to HiZ.
1443 * This is because the texture layer view is still a layer texture. */
1444 inst_.hiz_buffer.set_source(&depth_layer_tx, 0);
1445 inst_.hiz_buffer.update();
1446
1447 inst_.lights.set_view(view, extent);
1448 inst_.shadows.set_view(view, extent);
1449 inst_.volume_probes.set_view(view);
1450 inst_.sphere_probes.set_view(view);
1451
1452 inst_.gbuffer.bind(gbuffer_fb);
1453 inst_.manager->submit(gbuffer_ps_, view);
1454
1455 GPU_framebuffer_bind(combined_fb);
1456 inst_.manager->submit(eval_light_ps_, view);
1457
1458 inst_.pipelines.data.is_sphere_probe = false;
1459 inst_.uniform_data.push_update();
1460
1462}
1463
1466/* -------------------------------------------------------------------- */
1472{
1473 surface_ps_.init();
1474 /* Surfel output is done using a SSBO, so no need for a fragment shader output color or depth. */
1475 /* WORKAROUND: Avoid rasterizer discard, but the shaders actually use no fragment output. */
1477 surface_ps_.framebuffer_set(&inst_.volume_probes.bake.empty_raster_fb_);
1478
1479 surface_ps_.bind_ssbo(SURFEL_BUF_SLOT, &inst_.volume_probes.bake.surfels_buf_);
1480 surface_ps_.bind_ssbo(CAPTURE_BUF_SLOT, &inst_.volume_probes.bake.capture_info_buf_);
1481
1483 /* TODO(fclem): Remove. Bind to get the camera data,
1484 * but there should be no view dependent behavior during capture. */
1485 surface_ps_.bind_resources(inst_.uniform_data);
1486}
1487
1489{
1490 PassMain::Sub &sub_pass = surface_ps_.sub(GPU_material_get_name(gpumat));
1491 GPUPass *gpupass = GPU_material_get_pass(gpumat);
1492 sub_pass.shader_set(GPU_pass_shader_get(gpupass));
1493 sub_pass.push_constant("is_double_sided",
1495 return &sub_pass;
1496}
1497
1499{
1500 inst_.manager->submit(surface_ps_, view);
1501}
1502
1505} // namespace blender::eevee
void BKE_boundbox_init_from_minmax(BoundBox *bb, const float min[3], const float max[3])
std::optional< blender::Bounds< blender::float3 > > BKE_object_boundbox_get(const Object *ob)
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE float square_f(float a)
MINLINE int count_bits_i(unsigned int n)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
@ MA_BL_LIGHTPROBE_VOLUME_DOUBLE_SIDED
@ MA_BL_THICKNESS_FROM_SHADOW
@ MA_BL_CULL_BACKFACE
@ MA_BL_SS_REFRACTION
@ MA_BL_CULL_BACKFACE_SHADOW
@ MA_BL_HIDE_BACKFACE
@ MA_VOLUME_ISECT_FAST
@ OB_VOLUME
@ SCE_EEVEE_SSR_ENABLED
bool GPU_stencil_export_support()
bool GPU_stencil_clasify_buffer_workaround()
@ GPU_ATTACHMENT_WRITE
@ GPU_ATTACHMENT_READ
@ GPU_ATTACHMENT_IGNORE
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
GPUPass * GPU_material_get_pass(GPUMaterial *material)
bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag)
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
@ GPU_MATFLAG_VOLUME_SCATTER
@ GPU_MATFLAG_VOLUME_ABSORPTION
@ GPU_MATFLAG_TRANSPARENT
@ GPU_MAT_SUCCESS
const char * GPU_material_get_name(GPUMaterial *material)
bool GPU_material_has_volume_output(GPUMaterial *mat)
@ GPU_PRIM_TRIS
@ GPU_BARRIER_TEXTURE_FETCH
Definition GPU_state.hh:37
@ GPU_BARRIER_SHADER_IMAGE_ACCESS
Definition GPU_state.hh:35
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src)
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_SHADER_WRITE
struct GPUShader GPUShader
void submit(PassSimple &pass, View &view)
PassMain::Sub & sub(const char *name, float sorting_value)
Definition draw_pass.hh:528
void acquire(int2 extent, eGPUTextureFormat format, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL)
void clear(float4 values)
bool ensure_2d_array(eGPUTextureFormat format, int2 extent, int layers, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
bool ensure_2d(eGPUTextureFormat format, int2 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
void bind_texture(const char *name, GPUTexture *texture, GPUSamplerState state=sampler_auto)
void bind_resources(U &resources)
Definition draw_pass.hh:426
void bind_image(const char *name, GPUTexture *image)
void specialize_constant(GPUShader *shader, const char *name, const float &data)
void clear_stencil(uint8_t stencil)
Definition draw_pass.hh:921
void subpass_transition(GPUAttachmentState depth_attachment, Span< GPUAttachmentState > color_attachments)
Definition draw_pass.hh:983
void draw_procedural(GPUPrimType primitive, uint instance_len, uint vertex_len, uint vertex_first=-1, ResourceHandle handle={0}, uint custom_id=0)
Definition draw_pass.hh:833
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:616
void barrier(eGPUBarrier type)
Definition draw_pass.hh:943
void state_set(DRWState state, int clip_plane_count=0)
Definition draw_pass.hh:954
void bind_ubo(const char *name, GPUUniformBuf *buffer)
void framebuffer_set(GPUFrameBuffer **framebuffer)
Definition draw_pass.hh:977
void state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask)
Definition draw_pass.hh:966
void push_constant(const char *name, const float &data)
void material_set(Manager &manager, GPUMaterial *material)
void bind_ssbo(const char *name, GPUStorageBuf *buffer)
void shader_set(GPUShader *shader)
Definition draw_pass.hh:971
void sync(GPUMaterial *gpumat, float background_opacity, float background_blur)
const float3 & forward() const
PassMain::Sub * surface_material_add(::Material *blender_mat, GPUMaterial *gpumat)
GPUTexture * render(View &main_view, View &render_view, Framebuffer &prepass_fb, Framebuffer &combined_fb, Framebuffer &gbuffer_fb, int2 extent, RayTraceBuffer &rt_buffer, GPUTexture *radiance_behind_tx)
void end_sync(bool is_first_pass, bool is_last_pass, bool next_layer_has_transmission)
PassMain::Sub * prepass_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion)
PassMain::Sub * material_add(::Material *blender_mat, GPUMaterial *gpumat)
PassMain::Sub * material_add(::Material *material, GPUMaterial *gpumat)
void debug_draw(draw::View &view, GPUFrameBuffer *combined_fb)
PassMain::Sub * prepass_add(::Material *material, GPUMaterial *gpumat, bool has_motion)
void render(View &main_view, View &render_view, Framebuffer &prepass_fb, Framebuffer &combined_fb, Framebuffer &gbuffer_fb, int2 extent, RayTraceBuffer &rt_buffer_opaque_layer, RayTraceBuffer &rt_buffer_refract_layer)
void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, Framebuffer &gbuffer_fb, int2 extent)
PassMain::Sub * prepass_add(::Material *material, GPUMaterial *gpumat)
PassMain::Sub * material_add(::Material *material, GPUMaterial *gpumat)
AOVsInfoDataBuf aovs_info
Definition eevee_film.hh:53
PassMain::Sub * prepass_opaque_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion)
PassMain::Sub * material_opaque_add(::Material *blender_mat, GPUMaterial *gpumat)
PassMain::Sub * material_transparent_add(const Object *ob, ::Material *blender_mat, GPUMaterial *gpumat)
void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, int2 extent)
PassMain::Sub * prepass_transparent_add(const Object *ob, ::Material *blender_mat, GPUMaterial *gpumat)
struct blender::eevee::HiZBuffer::@195 front
void set_source(GPUTexture **texture, int layer=-1)
A running instance of the engine.
VolumeProbeModule volume_probes
SphereProbeModule sphere_probes
SubsurfaceModule subsurface
void info_append(const char *msg, Args &&...args)
PlanarProbeModule planar_probes
UniformDataModule uniform_data
LightProbeModule light_probes
void set_view(View &view, const int2 extent)
PassMain::Sub * prepass_add(::Material *material, GPUMaterial *gpumat)
PassMain::Sub * material_add(::Material *material, GPUMaterial *gpumat)
void render(View &view, GPUTexture *depth_layer_tx, Framebuffer &gbuffer, Framebuffer &combined_fb, int2 extent)
RayTraceResult alloc_only(RayTraceBuffer &rt_buffer)
RayTraceResult render(RayTraceBuffer &rt_buffer, GPUTexture *screen_radiance_back_tx, eClosureBits active_closures, View &main_view, View &render_view)
RayTraceResult alloc_dummy(RayTraceBuffer &rt_buffer)
GPUShader * static_shader_get(eShaderType shader_type)
const ShadowSceneData & get_data()
void set_view(View &view, int2 extent)
static ShadowTechnique shadow_technique
PassMain::Sub * surface_material_add(::Material *material, GPUMaterial *gpumat)
void render(View &view, Texture &occupancy_tx)
bool bounds_overlaps(const VolumeObjectBounds &object_aabb) const
PassMain::Sub * occupancy_add(const Object *ob, const ::Material *blender_mat, GPUMaterial *gpumat)
void add_object_bound(const VolumeObjectBounds &object_aabb)
PassMain::Sub * material_add(const Object *ob, const ::Material *blender_mat, GPUMaterial *gpumat)
struct blender::eevee::VolumeModule::@197 properties
struct blender::eevee::VolumeModule::@198 occupancy
struct blender::eevee::VolumeModule::@196 result
std::optional< Bounds< float > > object_integration_range() const
VolumeLayer * register_and_get_layer(Object *ob)
void render(View &view, Texture &occupancy_tx)
void sync(GPUMaterial *gpumat)
additional_info("compositor_sum_float_shared") .push_constant(Type additional_info("compositor_sum_float_shared") .push_constant(Type GPU_RGBA32F
void DRW_stats_group_start(const char *name)
void DRW_stats_group_end()
DRWState
Definition draw_state.hh:25
@ DRW_STATE_STENCIL_EQUAL
Definition draw_state.hh:47
@ DRW_STATE_STENCIL_ALWAYS
Definition draw_state.hh:46
@ DRW_STATE_DEPTH_LESS
Definition draw_state.hh:37
@ DRW_STATE_DEPTH_EQUAL
Definition draw_state.hh:39
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_BLEND_ADD_FULL
Definition draw_state.hh:53
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
@ DRW_STATE_CULL_BACK
Definition draw_state.hh:43
@ DRW_STATE_STENCIL_NEQUAL
Definition draw_state.hh:48
@ DRW_STATE_DEPTH_ALWAYS
Definition draw_state.hh:36
@ DRW_STATE_BLEND_CUSTOM
Definition draw_state.hh:63
@ DRW_STATE_DEPTH_GREATER
Definition draw_state.hh:40
@ DRW_STATE_WRITE_STENCIL
Definition draw_state.hh:32
#define RBUFS_UTILITY_TEX_SLOT
#define CAPTURE_BUF_SLOT
#define RBUFS_CRYPTOMATTE_SLOT
#define GBUF_CLOSURE_SLOT
#define SHADOW_ATLAS_IMG_SLOT
#define SHADOW_RENDER_MAP_BUF_SLOT
#define DEFERRED_RADIANCE_FORMAT
#define RBUFS_VALUE_SLOT
#define RBUFS_COLOR_SLOT
#define SHADOW_RENDER_VIEW_BUF_SLOT
#define SHADOW_PAGE_INFO_SLOT
#define GBUF_NORMAL_SLOT
#define CLIP_PLANE_BUF
#define SURFEL_BUF_SLOT
GPUShader * GPU_pass_shader_get(GPUPass *pass)
static ulong state[N]
std::optional< Bounds< T > > intersect(const std::optional< Bounds< T > > &a, const std::optional< Bounds< T > > &b)
Bounds< T > merge(const Bounds< T > &a, const Bounds< T > &b)
Definition BLI_bounds.hh:24
std::optional< Bounds< T > > min_max(const std::optional< Bounds< T > > &a, const T &b)
Definition BLI_bounds.hh:46
detail::Pass< command::DrawCommandBuf > PassSimple
PassMain::Sub * volume_sub_pass(PassMain::Sub &ps, Scene *scene, Object *ob, GPUMaterial *gpu_material)
static eClosureBits shader_closure_bits_from_flag(const GPUMaterial *gpumat)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
VectorT project_point(const MatT &mat, const VectorT &point)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
VecBase< int32_t, 4 > int4
VecBase< uint32_t, 4 > uint4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
#define FLT_MAX
Definition stdcycles.h:14
__int64 int64_t
Definition stdint.h:89
unsigned char uint8_t
Definition stdint.h:78
float vec[8][3]
float clamp_surface_direct
float clamp_surface_indirect
struct SceneEEVEE eevee
VecBase< T, 2 > xy() const
PassMain::Sub * gbuffer_double_sided_hybrid_ps_
PassMain::Sub * prepass_double_sided_static_ps_
PassMain::Sub * prepass_single_sided_static_ps_
void gbuffer_pass_sync(Instance &inst)
PassMain::Sub * prepass_double_sided_moving_ps_
PassMain::Sub * gbuffer_single_sided_hybrid_ps_
PassMain::Sub * prepass_single_sided_moving_ps_
void bind(Framebuffer &gbuffer_fb)
GPUTexture * feedback_ensure(bool is_dummy, int2 extent)
RayTraceResultTexture closures[3]
void render(GPUTexture *direct_diffuse_light_tx, GPUTexture *indirect_diffuse_light_tx, eClosureBits active_closures, View &view)
std::optional< Bounds< float2 > > screen_bounds
VolumeObjectBounds(const Camera &camera, Object *ob)
std::optional< Bounds< float > > z_range