Blender V4.3
eevee_pipeline.hh
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#pragma once
14
15#include "BLI_math_bits.h"
16
17#include "DRW_render.hh"
18#include "draw_shader_shared.hh"
19
20#include "eevee_lut.hh"
21#include "eevee_raytrace.hh"
22#include "eevee_subsurface.hh"
23
24namespace blender::eevee {
25
26class Instance;
27struct RayTraceBuffer;
28
29/* -------------------------------------------------------------------- */
36 private:
37 Instance &inst_;
38
39 PassSimple clear_ps_ = {"World.Background.Clear"};
40 PassSimple world_ps_ = {"World.Background"};
41
42 public:
43 BackgroundPipeline(Instance &inst) : inst_(inst){};
44
45 void sync(GPUMaterial *gpumat, float background_opacity, float background_blur);
46 void clear(View &view);
47 void render(View &view);
48};
49
52/* -------------------------------------------------------------------- */
59 private:
60 Instance &inst_;
61
62 /* Dummy textures: required to reuse background shader and avoid another shader variation. */
63 Texture dummy_renderpass_tx_;
64 Texture dummy_cryptomatte_tx_;
65 Texture dummy_aov_color_tx_;
66 Texture dummy_aov_value_tx_;
67
68 PassSimple cubemap_face_ps_ = {"World.Probe"};
69
70 public:
71 WorldPipeline(Instance &inst) : inst_(inst){};
72
73 void sync(GPUMaterial *gpumat);
74 void render(View &view);
75
76}; // namespace blender::eevee
77
80/* -------------------------------------------------------------------- */
86 private:
87 Instance &inst_;
88 bool is_valid_;
89
90 PassSimple world_ps_ = {"World.Volume"};
91
92 public:
93 WorldVolumePipeline(Instance &inst) : inst_(inst){};
94
95 void sync(GPUMaterial *gpumat);
96 void render(View &view);
97};
98
101/* -------------------------------------------------------------------- */
107 private:
108 Instance &inst_;
109
110 /* Shadow update pass. */
111 PassMain render_ps_ = {"Shadow.Surface"};
112 /* Shadow surface render sub-passes. */
113 PassMain::Sub *surface_double_sided_ps_ = nullptr;
114 PassMain::Sub *surface_single_sided_ps_ = nullptr;
115
116 public:
117 ShadowPipeline(Instance &inst) : inst_(inst){};
118
120
121 void sync();
122
123 void render(View &view);
124};
125
128/* -------------------------------------------------------------------- */
135 private:
136 Instance &inst_;
137
138 PassMain prepass_ps_ = {"Prepass"};
139 PassMain::Sub *prepass_single_sided_static_ps_ = nullptr;
140 PassMain::Sub *prepass_single_sided_moving_ps_ = nullptr;
141 PassMain::Sub *prepass_double_sided_static_ps_ = nullptr;
142 PassMain::Sub *prepass_double_sided_moving_ps_ = nullptr;
143
144 PassMain opaque_ps_ = {"Shading"};
145 PassMain::Sub *opaque_single_sided_ps_ = nullptr;
146 PassMain::Sub *opaque_double_sided_ps_ = nullptr;
147
148 PassSortable transparent_ps_ = {"Forward.Transparent"};
149 float3 camera_forward_;
150
151 bool has_opaque_ = false;
152 bool has_transparent_ = false;
153
154 public:
155 ForwardPipeline(Instance &inst) : inst_(inst){};
156
157 void sync();
158
159 PassMain::Sub *prepass_opaque_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion);
161
163 ::Material *blender_mat,
164 GPUMaterial *gpumat);
166 ::Material *blender_mat,
167 GPUMaterial *gpumat);
168
169 void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, int2 extent);
170};
171
174/* -------------------------------------------------------------------- */
179 PassMain prepass_ps_ = {"Prepass"};
184
185 PassMain gbuffer_ps_ = {"Shading"};
186 /* Shaders that use the ClosureToRGBA node needs to be rendered first.
187 * Consider they hybrid forward and deferred. */
192
193 /* Closures bits from the materials in this pass. */
195 /* Maximum closure count considering all material in this pass. */
197
198 /* Stencil values used during the deferred pipeline. */
199 enum class StencilBits : uint8_t {
200 /* Bits 0 to 1 are reserved for closure count [0..3]. */
201 CLOSURE_COUNT_0 = (1u << 0u),
202 CLOSURE_COUNT_1 = (1u << 1u),
203 /* Set for pixels have a transmission closure. */
204 TRANSMISSION = (1u << 2u),
207
208 /* Set for materials that uses the shadow amend pass. */
209 THICKNESS_FROM_SHADOW = (1u << 3u),
212 };
213
214 /* Return the amount of gbuffer layer needed. */
216 {
217 /* Diffuse and translucent require only one layer. */
219 /* SSS require an additional layer compared to diffuse. */
221 /* Reflection and refraction can have at most two layers. */
224 return count;
225 }
226
227 /* Return the amount of gbuffer layer needed. */
229 {
230 /* TODO(fclem): We could count the number of different tangent frame in the shader and use
231 * min(tangent_frame_count, closure_count) once we have the normal reuse optimization.
232 * For now, allocate a split normal layer for each Closure. */
236 /* Count the additional infos layer needed by some closures. */
238 return count;
239 }
240
241 void gbuffer_pass_sync(Instance &inst);
242};
243
244class DeferredPipeline;
245
247 friend DeferredPipeline;
248
249 private:
250 Instance &inst_;
251
252 static constexpr int max_lighting_tile_count_ = 128 * 128;
253
254 /* Evaluate all light objects contribution. */
255 PassSimple eval_light_ps_ = {"EvalLights"};
256 /* Combine direct and indirect light contributions and apply BSDF color. */
257 PassSimple combine_ps_ = {"Combine"};
258
268 TextureFromPool direct_radiance_txs_[3] = {
269 {"direct_radiance_1"}, {"direct_radiance_2"}, {"direct_radiance_3"}};
270 /* NOTE: Only used when `use_split_radiance` is true. */
271 TextureFromPool indirect_radiance_txs_[3] = {
272 {"indirect_radiance_1"}, {"indirect_radiance_2"}, {"indirect_radiance_3"}};
273 /* Used when there is no indirect radiance buffer. */
274 Texture dummy_black = {"dummy_black"};
275 /* Reference to ray-tracing results. */
276 GPUTexture *radiance_feedback_tx_ = nullptr;
277
282 Texture tile_mask_tx_ = {"tile_mask_tx_"};
283
284 RayTraceResult indirect_result_;
285
286 bool use_split_radiance_ = true;
287 /* Output radiance from the combine shader instead of copy. Allow passing unclamped result. */
288 bool use_feedback_output_ = false;
289 bool use_raytracing_ = false;
290 bool use_screen_transmission_ = false;
291 bool use_screen_reflection_ = false;
292 bool use_clamp_direct_ = false;
293 bool use_clamp_indirect_ = false;
294
295 public:
296 DeferredLayer(Instance &inst) : inst_(inst)
297 {
298 float4 data(0.0f);
300 int2(1),
302 data);
303 }
304
305 void begin_sync();
306 void end_sync(bool is_first_pass, bool is_last_pass, bool next_layer_has_transmission);
307
308 PassMain::Sub *prepass_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion);
309 PassMain::Sub *material_add(::Material *blender_mat, GPUMaterial *gpumat);
310
311 bool is_empty() const
312 {
313 return closure_count_ == 0;
314 }
315
316 bool has_transmission() const
317 {
319 }
320
321 /* Returns the radiance buffer to feed the next layer. */
322 GPUTexture *render(View &main_view,
323 View &render_view,
324 Framebuffer &prepass_fb,
325 Framebuffer &combined_fb,
326 Framebuffer &gbuffer_fb,
327 int2 extent,
328 RayTraceBuffer &rt_buffer,
329 GPUTexture *radiance_behind_tx);
330};
331
333 friend DeferredLayer;
334
335 private:
336 /* Gbuffer filling passes. We could have an arbitrary number of them but for now we just have
337 * a hardcoded number of them. */
338 DeferredLayer opaque_layer_;
339 DeferredLayer refraction_layer_;
340 DeferredLayer volumetric_layer_;
341
342 PassSimple debug_draw_ps_ = {"debug_gbuffer"};
343
344 bool use_combined_lightprobe_eval;
345
346 public:
348 : opaque_layer_(inst), refraction_layer_(inst), volumetric_layer_(inst){};
349
350 void begin_sync();
351 void end_sync();
352
353 PassMain::Sub *prepass_add(::Material *material, GPUMaterial *gpumat, bool has_motion);
355
356 void render(View &main_view,
357 View &render_view,
358 Framebuffer &prepass_fb,
359 Framebuffer &combined_fb,
360 Framebuffer &gbuffer_fb,
361 int2 extent,
362 RayTraceBuffer &rt_buffer_opaque_layer,
363 RayTraceBuffer &rt_buffer_refract_layer);
364
365 /* Return the maximum amount of gbuffer layer needed. */
367 {
368 return max_ii(opaque_layer_.closure_layer_count(), refraction_layer_.closure_layer_count());
369 }
370
371 /* Return the maximum amount of gbuffer layer needed. */
373 {
374 return max_ii(opaque_layer_.normal_layer_count(), refraction_layer_.normal_layer_count());
375 }
376
377 void debug_draw(draw::View &view, GPUFrameBuffer *combined_fb);
378
379 bool is_empty() const
380 {
381 return opaque_layer_.is_empty() && refraction_layer_.is_empty();
382 }
383
384 private:
385 void debug_pass_sync();
386};
387
390/* -------------------------------------------------------------------- */
396 /* Screen 2D bounds for layer intersection check. */
397 std::optional<Bounds<float2>> screen_bounds;
398 /* Combined bounds in Z. Allow tighter integration bounds. */
399 std::optional<Bounds<float>> z_range;
400
401 VolumeObjectBounds(const Camera &camera, Object *ob);
402};
403
408 public:
409 bool use_hit_list = false;
410 bool is_empty = true;
411 bool finalized = false;
412 bool has_scatter = false;
413 bool has_absorption = false;
414
415 private:
416 Instance &inst_;
417
418 PassMain volume_layer_ps_ = {"Volume.Layer"};
419 /* Sub-passes of volume_layer_ps. */
420 PassMain::Sub *occupancy_ps_;
421 PassMain::Sub *material_ps_;
422 /* List of bounds from all objects contained inside this pass. */
424 /* Combined bounds from object_bounds_. */
425 std::optional<Bounds<float2>> combined_screen_bounds_;
426
427 public:
428 VolumeLayer(Instance &inst) : inst_(inst)
429 {
430 this->sync();
431 }
432
434 const ::Material *blender_mat,
435 GPUMaterial *gpumat);
437 const ::Material *blender_mat,
438 GPUMaterial *gpumat);
439
440 /* Return true if the given bounds overlaps any of the contained object in this layer. */
441 bool bounds_overlaps(const VolumeObjectBounds &object_aabb) const;
442
443 void add_object_bound(const VolumeObjectBounds &object_aabb);
444
445 void sync();
446 void render(View &view, Texture &occupancy_tx);
447};
448
450 private:
451 Instance &inst_;
452
454
455 /* Combined bounds in Z. Allow tighter integration bounds. */
456 std::optional<Bounds<float>> object_integration_range_;
457 /* Aggregated properties of all volume objects. */
458 bool has_scatter_ = false;
459 bool has_absorption_ = false;
460
461 public:
462 VolumePipeline(Instance &inst) : inst_(inst){};
463
464 void sync();
465 void render(View &view, Texture &occupancy_tx);
466
472
473 std::optional<Bounds<float>> object_integration_range() const;
474
475 bool has_scatter() const
476 {
477 for (auto &layer : layers_) {
478 if (layer->has_scatter) {
479 return true;
480 }
481 }
482 return false;
483 }
484 bool has_absorption() const
485 {
486 for (auto &layer : layers_) {
487 if (layer->has_absorption) {
488 return true;
489 }
490 }
491 return false;
492 }
493
494 /* Returns true if any volume layer uses the hist list. */
495 bool use_hit_list() const;
496};
497
500/* -------------------------------------------------------------------- */
505 private:
506 Instance &inst_;
507
508 DeferredLayerBase opaque_layer_;
509
510 PassSimple eval_light_ps_ = {"EvalLights"};
511
512 public:
513 DeferredProbePipeline(Instance &inst) : inst_(inst){};
514
515 void begin_sync();
516 void end_sync();
517
518 PassMain::Sub *prepass_add(::Material *material, GPUMaterial *gpumat);
520
521 void render(View &view,
522 Framebuffer &prepass_fb,
523 Framebuffer &combined_fb,
524 Framebuffer &gbuffer_fb,
525 int2 extent);
526
527 /* Return the maximum amount of gbuffer layer needed. */
529 {
530 return opaque_layer_.closure_layer_count();
531 }
532
533 /* Return the maximum amount of gbuffer layer needed. */
535 {
536 return opaque_layer_.normal_layer_count();
537 }
538};
539
542/* -------------------------------------------------------------------- */
547 private:
548 Instance &inst_;
549
550 PassSimple eval_light_ps_ = {"EvalLights"};
551
552 public:
553 PlanarProbePipeline(Instance &inst) : inst_(inst){};
554
555 void begin_sync();
556 void end_sync();
557
558 PassMain::Sub *prepass_add(::Material *material, GPUMaterial *gpumat);
560
561 void render(View &view,
562 GPUTexture *depth_layer_tx,
563 Framebuffer &gbuffer,
564 Framebuffer &combined_fb,
565 int2 extent);
566};
567
570/* -------------------------------------------------------------------- */
576 private:
577 Instance &inst_;
578
579 PassMain surface_ps_ = {"Capture.Surface"};
580
581 public:
582 CapturePipeline(Instance &inst) : inst_(inst){};
583
585
586 void sync();
587 void render(View &view);
588};
589
592/* -------------------------------------------------------------------- */
598class UtilityTexture : public Texture {
599 struct Layer {
601 };
602
603 static constexpr int lut_size = UTIL_TEX_SIZE;
604 static constexpr int lut_size_sqr = lut_size * lut_size;
605 static constexpr int layer_count = UTIL_BTDF_LAYER + UTIL_BTDF_LAYER_COUNT;
606
607 public:
609 : Texture("UtilityTx",
612 int2(lut_size),
613 layer_count,
614 nullptr)
615 {
616 Vector<Layer> data(layer_count);
617 {
618 Layer &layer = data[UTIL_BLUE_NOISE_LAYER];
619 memcpy(layer.data, lut::blue_noise, sizeof(layer));
620 }
621 {
622 Layer &layer = data[UTIL_SSS_TRANSMITTANCE_PROFILE_LAYER];
623 for (auto y : IndexRange(lut_size)) {
624 for (auto x : IndexRange(lut_size)) {
625 /* Repeatedly stored on every row for correct interpolation. */
626 layer.data[y][x][0] = lut::burley_sss_profile[x][0];
627 layer.data[y][x][1] = lut::random_walk_sss_profile[x][0];
628 layer.data[y][x][2] = 0.0f;
630 }
631 }
633 }
634 {
635 Layer &layer = data[UTIL_LTC_MAT_LAYER];
636 memcpy(layer.data, lut::ltc_mat_ggx, sizeof(layer));
637 }
638 {
639 Layer &layer = data[UTIL_BSDF_LAYER];
640 for (auto x : IndexRange(lut_size)) {
641 for (auto y : IndexRange(lut_size)) {
642 layer.data[y][x][0] = lut::brdf_ggx[y][x][0];
643 layer.data[y][x][1] = lut::brdf_ggx[y][x][1];
644 layer.data[y][x][2] = lut::brdf_ggx[y][x][2];
645 layer.data[y][x][3] = 0.0f;
646 }
647 }
648 }
649 {
650 for (auto layer_id : IndexRange(16)) {
651 Layer &layer = data[UTIL_BTDF_LAYER + layer_id];
652 for (auto x : IndexRange(lut_size)) {
653 for (auto y : IndexRange(lut_size)) {
654 layer.data[y][x][0] = lut::bsdf_ggx[layer_id][y][x][0];
655 layer.data[y][x][1] = lut::bsdf_ggx[layer_id][y][x][1];
656 layer.data[y][x][2] = lut::bsdf_ggx[layer_id][y][x][2];
657 layer.data[y][x][3] = lut::btdf_ggx[layer_id][y][x][0];
658 }
659 }
660 }
661 }
662 GPU_texture_update_mipmap(*this, 0, GPU_DATA_FLOAT, data.data());
663 }
664
666};
667
670/* -------------------------------------------------------------------- */
677 public:
688
691
692 public:
694 : background(inst),
695 world(inst),
696 world_volume(inst),
697 probe(inst),
698 planar(inst),
699 deferred(inst),
700 forward(inst),
701 shadow(inst),
702 volume(inst),
703 capture(inst),
704 data(data){};
705
707 {
708 data.is_sphere_probe = false;
710 planar.begin_sync();
712 forward.sync();
713 shadow.sync();
714 volume.sync();
715 capture.sync();
716 }
717
718 void end_sync()
719 {
720 probe.end_sync();
721 planar.end_sync();
723 }
724
725 PassMain::Sub *material_add(Object * /*ob*/ /* TODO remove. */,
726 ::Material *blender_mat,
727 GPUMaterial *gpumat,
728 eMaterialPipeline pipeline_type,
729 eMaterialProbe probe_capture)
730 {
731 if (probe_capture == MAT_PROBE_REFLECTION) {
732 switch (pipeline_type) {
734 return probe.prepass_add(blender_mat, gpumat);
736 return probe.material_add(blender_mat, gpumat);
737 default:
739 break;
740 }
741 }
742 if (probe_capture == MAT_PROBE_PLANAR) {
743 switch (pipeline_type) {
745 return planar.prepass_add(blender_mat, gpumat);
747 return planar.material_add(blender_mat, gpumat);
748 default:
750 break;
751 }
752 }
753
754 switch (pipeline_type) {
756 return deferred.prepass_add(blender_mat, gpumat, false);
758 return forward.prepass_opaque_add(blender_mat, gpumat, false);
760 BLI_assert_msg(0, "Overlap prepass should register to the forward pipeline directly.");
761 return nullptr;
762
764 return deferred.prepass_add(blender_mat, gpumat, true);
766 return forward.prepass_opaque_add(blender_mat, gpumat, true);
767
769 return deferred.material_add(blender_mat, gpumat);
770 case MAT_PIPE_FORWARD:
771 return forward.material_opaque_add(blender_mat, gpumat);
772 case MAT_PIPE_SHADOW:
773 return shadow.surface_material_add(blender_mat, gpumat);
774 case MAT_PIPE_CAPTURE:
775 return capture.surface_material_add(blender_mat, gpumat);
776
779 BLI_assert_msg(0, "Volume shaders must register to the volume pipeline directly.");
780 return nullptr;
781
783 /* Should be handled by the `probe_capture == MAT_PROBE_PLANAR` case. */
785 return nullptr;
786 }
787 return nullptr;
788 }
789};
790
793} // namespace blender::eevee
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE int max_ii(int a, int b)
MINLINE int count_bits_i(unsigned int n)
@ GPU_DATA_FLOAT
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_SHADER_WRITE
void GPU_texture_update_mipmap(GPUTexture *texture, int mip_level, eGPUDataFormat data_format, const void *pixels)
bool ensure_2d(eGPUTextureFormat format, int2 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
void sync(GPUMaterial *gpumat, float background_opacity, float background_blur)
PassMain::Sub * surface_material_add(::Material *blender_mat, GPUMaterial *gpumat)
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)
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)
PassMain::Sub * prepass_transparent_add(const Object *ob, ::Material *blender_mat, GPUMaterial *gpumat)
A running instance of the engine.
PipelineModule(Instance &inst, PipelineInfoData &data)
PassMain::Sub * material_add(Object *, ::Material *blender_mat, GPUMaterial *gpumat, eMaterialPipeline pipeline_type, eMaterialProbe probe_capture)
PassMain::Sub * prepass_add(::Material *material, GPUMaterial *gpumat)
PassMain::Sub * material_add(::Material *material, GPUMaterial *gpumat)
PassMain::Sub * surface_material_add(::Material *material, GPUMaterial *gpumat)
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 sync(GPUMaterial *gpumat)
#define RAYTRACE_RADIANCE_FORMAT
#define UTIL_DISK_INTEGRAL_COMP
#define UTIL_BSDF_LAYER
#define UTIL_BTDF_LAYER
#define UTIL_DISK_INTEGRAL_LAYER
#define UTIL_BTDF_LAYER_COUNT
#define UTIL_LTC_MAT_LAYER
#define UTIL_SSS_TRANSMITTANCE_PROFILE_LAYER
#define UTIL_TEX_SIZE
#define UTIL_BLUE_NOISE_LAYER
int count
const float ltc_mat_ggx[64][64][4]
Definition eevee_lut.cc:13
const float burley_sss_profile[64][1]
const float brdf_ggx[64][64][3]
const float random_walk_sss_profile[64][1]
const float ltc_disk_integral[64][64][1]
const float btdf_ggx[16][64][64][1]
const float bsdf_ggx[16][64][64][3]
const float blue_noise[64][64][4]
@ MAT_PIPE_PREPASS_FORWARD_VELOCITY
@ MAT_PIPE_PREPASS_DEFERRED_VELOCITY
VecBase< int32_t, 2 > int2
unsigned char uint8_t
Definition stdint.h:78
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_
std::optional< Bounds< float2 > > screen_bounds
VolumeObjectBounds(const Camera &camera, Object *ob)
std::optional< Bounds< float > > z_range