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
12
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/* -------------------------------------------------------------------- */
31
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();
40 world_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
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. */
59 world_ps_.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
60
61 clear_ps_.init();
62 clear_ps_.state_set(DRW_STATE_WRITE_COLOR);
63 clear_ps_.shader_set(inst_.shaders.static_shader_get(RENDERPASS_CLEAR));
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. */
73 clear_ps_.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
74}
75
77{
78 inst_.manager->submit(clear_ps_, view);
79}
80
82{
83 inst_.manager->submit(world_ps_, view);
84}
85
87
88/* -------------------------------------------------------------------- */
91
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;
136 inst_.uniform_data.push_update();
137
138 inst_.manager->submit(cubemap_face_ps_, view);
139
140 inst_.pipelines.data.is_sphere_probe = false;
141 inst_.uniform_data.push_update();
142}
143
145
146/* -------------------------------------------------------------------- */
150
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();
161 world_ps_.state_set(DRW_STATE_WRITE_COLOR);
162 world_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
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. */
175 world_ps_.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
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
195
196/* -------------------------------------------------------------------- */
200
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");
246 pass.shader_set(inst_.shaders.static_shader_get(SHADOW_PAGE_TILE_STORE));
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. */
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. */
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{
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
278
279/* -------------------------------------------------------------------- */
284
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. */
299 prepass_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
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. */
322 opaque_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
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. */
349 sub.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
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);
356 sub.bind_resources(inst_.hiz_buffer.front);
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
466
467/* -------------------------------------------------------------------- */
470
472{
473 gbuffer_ps_.init();
474 gbuffer_ps_.subpass_transition(GPU_ATTACHMENT_WRITE,
480 /* G-buffer. */
483 /* RenderPasses & AOVs. */
486 /* Cryptomatte. */
488 /* Storage Buffer. */
489 /* Textures. */
491
492 gbuffer_ps_.bind_resources(inst.uniform_data);
493 gbuffer_ps_.bind_resources(inst.sampling);
494 gbuffer_ps_.bind_resources(inst.hiz_buffer.front);
495 gbuffer_ps_.bind_resources(inst.cryptomatte);
496
497 /* Bind light resources for the NPR materials that gets rendered first.
498 * Non-NPR shaders will override these resource bindings. */
499 gbuffer_ps_.bind_resources(inst.lights);
500 gbuffer_ps_.bind_resources(inst.shadows);
501 gbuffer_ps_.bind_resources(inst.sphere_probes);
502 gbuffer_ps_.bind_resources(inst.volume_probes);
503
506
507 gbuffer_single_sided_hybrid_ps_ = &gbuffer_ps_.sub("DoubleSided");
509
510 gbuffer_double_sided_hybrid_ps_ = &gbuffer_ps_.sub("SingleSided");
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 {
526 prepass_ps_.init();
527 /* Textures. */
528 prepass_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
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
535 prepass_ps_.bind_resources(inst_.uniform_data);
536 prepass_ps_.bind_resources(inst_.velocity);
537 prepass_ps_.bind_resources(inst_.sampling);
538
542
543 prepass_double_sided_static_ps_ = &prepass_ps_.sub("DoubleSided.Static");
544 prepass_double_sided_static_ps_->state_set(state_depth_only);
545
546 prepass_single_sided_static_ps_ = &prepass_ps_.sub("SingleSided.Static");
547 prepass_single_sided_static_ps_->state_set(state_depth_only | DRW_STATE_CULL_BACK);
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");
553 prepass_single_sided_moving_ps_->state_set(state_depth_color | DRW_STATE_CULL_BACK);
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 {
589 GPUShader *sh = inst_.shaders.static_shader_get(DEFERRED_TILE_CLASSIFY);
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");
636 sub.shader_set(inst_.shaders.static_shader_get(DEFERRED_THICKNESS_AMEND));
637 sub.bind_resources(inst_.lights);
638 sub.bind_resources(inst_.shadows);
639 sub.bind_resources(inst_.hiz_buffer.front);
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. */
660 sub.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
661 sub.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx);
662 sub.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx);
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--) {
666 GPUShader *sh = inst_.shaders.static_shader_get(eShaderType(DEFERRED_LIGHT_SINGLE + 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);
689 sub.bind_resources(inst_.hiz_buffer.front);
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();
710 GPUShader *sh = inst_.shaders.static_shader_get(DEFERRED_COMBINE);
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_);
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
884
885/* -------------------------------------------------------------------- */
890
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
1012
1013/* -------------------------------------------------------------------- */
1017
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);
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
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. */
1120 occupancy_ps_->shader_set(inst_.shaders.static_shader_get(VOLUME_OCCUPANCY_CONVERT));
1121 occupancy_ps_->barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
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
1131
1132/* -------------------------------------------------------------------- */
1135
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
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;
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
1222
1223/* -------------------------------------------------------------------- */
1228
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
1321 inst_.hiz_buffer.set_source(&inst_.render_buffers.depth_tx);
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
1342
1343/* -------------------------------------------------------------------- */
1347
1349{
1350 {
1351 prepass_ps_.init();
1352 prepass_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
1353 prepass_ps_.bind_ubo(CLIP_PLANE_BUF, inst_.planar_probes.world_clip_buf_);
1354 prepass_ps_.bind_resources(inst_.uniform_data);
1355 prepass_ps_.bind_resources(inst_.sampling);
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");
1363 prepass_single_sided_static_ps_->state_set(state_depth_only | DRW_STATE_CULL_BACK);
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
1465
1466/* -------------------------------------------------------------------- */
1470
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. */
1476 surface_ps_.state_set(DRW_STATE_WRITE_STENCIL);
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
1482 surface_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
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
1504
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
static AppView * view
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
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
struct GPUShader GPUShader
void submit(PassSimple &pass, View &view)
void clear(float4 values)
void bind_texture(const char *name, GPUTexture *texture, GPUSamplerState state=sampler_auto)
void bind_resources(U &resources)
Definition draw_pass.hh:426
void draw_procedural_indirect(GPUPrimType primitive, StorageBuffer< DrawCommand, true > &indirect_buffer, ResourceHandle handle={0})
Definition draw_pass.hh:860
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 submit(command::RecordingState &state) const
Definition draw_pass.hh:624
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 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
detail::PassBase< command::DrawCommandBuf > Sub
Definition draw_pass.hh:462
void sync(GPUMaterial *gpumat, float background_opacity, float background_blur)
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)
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::@333276274241261234242230221004020010346271237200 front
A running instance of the engine.
VolumeProbeModule volume_probes
SphereProbeModule sphere_probes
void info_append(const char *msg, Args &&...args)
UniformDataModule uniform_data
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)
GPUShader * static_shader_get(eShaderType shader_type)
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)
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
PassMain::Sub * volume_sub_pass(PassMain::Sub &ps, Scene *scene, Object *ob, GPUMaterial *gpu_material)
detail::Pass< command::DrawCommandBuf > PassSimple
detail::Pass< command::DrawMultiBuf > PassMain
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
MatBase< float, 4, 4 > float4x4
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_
GPUTexture * feedback_ensure(bool is_dummy, int2 extent)
std::optional< Bounds< float2 > > screen_bounds
VolumeObjectBounds(const Camera &camera, Object *ob)
std::optional< Bounds< float > > z_range