Blender V5.0
eevee_shadow.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#pragma once
12
13#include "BLI_pool.hh"
14#include "BLI_vector.hh"
15
16#include "GPU_batch.hh"
17
18#include "eevee_camera.hh"
19#include "eevee_material.hh"
21#include "eevee_sync.hh"
23
24namespace blender::eevee {
25
26class Instance;
27class ShadowModule;
28class ShadowPipeline;
29struct Light;
30
31/* To be applied after view matrix. Follow same order as eCubeFace. */
32constexpr static const float shadow_face_mat[6][3][3] = {
33 {{+1, +0, +0}, {+0, +1, +0}, {+0, +0, +1}}, /* Z_NEG */
34 {{+0, +0, -1}, {-1, +0, +0}, {+0, +1, +0}}, /* X_POS */
35 {{+0, +0, +1}, {+1, +0, +0}, {+0, +1, +0}}, /* X_NEG */
36 {{+1, +0, +0}, {+0, +0, -1}, {+0, +1, +0}}, /* Y_POS */
37 {{-1, +0, +0}, {+0, +0, +1}, {+0, +1, +0}}, /* Y_NEG */
38 {{+1, +0, +0}, {+0, -1, +0}, {+0, +0, -1}}, /* Z_POS */
39};
40
41/* Converts to [-SHADOW_TILEMAP_RES / 2..SHADOW_TILEMAP_RES / 2] for XY and [0..1] for Z. */
42constexpr static const float shadow_clipmap_scale_mat[4][4] = {{SHADOW_TILEMAP_RES / 2, 0, 0, 0},
43 {0, SHADOW_TILEMAP_RES / 2, 0, 0},
44 {0, 0, 0.5, 0},
45 {0, 0, 0.5, 1}};
46
47/* Technique used for updating the virtual shadow map contents. */
48enum class ShadowTechnique {
49 /* Default virtual shadow map update using large virtual framebuffer to rasterize geometry with
50 * per-fragment textureAtomicMin to perform depth-test and indirectly store nearest depth value
51 * in the shadow atlas. */
53
54 /* Tile-architecture optimized virtual shadow map update, leveraging on-tile memory for clearing
55 * and depth-testing during geometry rasterization to avoid atomic operations, simplify mesh
56 * depth shader and only perform a single storage operation per pixel. This technique performs
57 * a 3-pass solution, first clearing tiles, updating depth and storing final results. */
59};
60
69
70/* -------------------------------------------------------------------- */
78
82
84 int level = INT_MAX;
89
90 public:
91 ShadowTileMap(int tiles_index_) : ShadowTileMapData{}
92 {
93 tiles_index = tiles_index_;
94 /* For now just the same index. */
96 /* Avoid uninitialized data. */
97 this->grid_offset = int2(0);
98 this->grid_shift = int2(0);
99 this->set_dirty();
100 }
101
102 void sync_orthographic(const float4x4 &object_mat_,
103 int2 origin_offset,
104 int clipmap_level,
105 eShadowProjectionType projection_type_,
106 uint2 shadow_set_membership_ = ~uint2(0));
107
108 void sync_cubeface(eLightType light_type_,
109 const float4x4 &object_mat,
110 float near,
111 float far,
112 eCubeFace face,
113 uint2 shadow_set_membership_ = ~uint2(0));
114
115 void debug_draw() const;
116
118 {
119 is_dirty = true;
120 }
121
123 {
124 is_dirty = false;
125 }
126};
127
171
173
174/* -------------------------------------------------------------------- */
178
179/* Can be either a shadow caster or a shadow receiver. */
184
186
187/* -------------------------------------------------------------------- */
192
193class ShadowPunctual;
195
197 friend ShadowPunctual;
198 friend ShadowDirectional;
199 friend ShadowPipeline;
200 friend ShadowTileMapPool;
201
202 public:
203 /* Shadowing technique. */
205
207 ShadowTileMapPool tilemap_pool;
208
211
212 private:
213 Instance &inst_;
214
215 ShadowSceneData &data_;
216
219
220 /* Used to call caster_update_ps_ only once per sync (Initialized on begin_sync). */
221 bool update_casters_ = false;
222
223 /* -------------------------------------------------------------------- */
226
227 PassSimple tilemap_setup_ps_ = {"TilemapSetup"};
228 PassMain tilemap_usage_ps_ = {"TagUsage"};
229 PassSimple tilemap_update_ps_ = {"TilemapUpdate"};
230
231 PassMain::Sub *tilemap_usage_transparent_ps_ = nullptr;
232 gpu::Batch *box_batch_ = nullptr;
233 /* Source texture for depth buffer analysis. */
234 gpu::Texture *src_depth_tx_ = nullptr;
235
236 Framebuffer usage_tag_fb;
237
238 PassSimple caster_update_ps_ = {"CasterUpdate"};
239 PassSimple jittered_transparent_caster_update_ps_ = {"TransparentCasterUpdate"};
241 StorageVectorBuffer<uint, 128> past_casters_updated_ = {"PastCastersUpdated"};
242 StorageVectorBuffer<uint, 128> curr_casters_updated_ = {"CurrCastersUpdated"};
243 StorageVectorBuffer<uint, 128> jittered_transparent_casters_ = {"JitteredTransparentCasters"};
245 StorageVectorBuffer<uint, 128> curr_casters_ = {"CurrCasters"};
246
248 DispatchIndirectBuf clear_dispatch_buf_ = {"clear_dispatch_buf"};
250 DrawIndirectBuf tile_draw_buf_ = {"tile_draw_buf"};
252 StorageArrayBuffer<uint, SHADOW_RENDER_MAP_SIZE, true> dst_coord_buf_ = {"dst_coord_buf"};
254 StorageArrayBuffer<uint, SHADOW_RENDER_MAP_SIZE, true> src_coord_buf_ = {"src_coord_buf"};
256 StorageArrayBuffer<uint, SHADOW_RENDER_MAP_SIZE, true> render_map_buf_ = {"render_map_buf"};
258 ShadowRenderViewBuf render_view_buf_ = {"render_view_buf"};
259
260 int3 dispatch_depth_scan_size_;
261 int2 usage_tag_fb_resolution_;
262 int usage_tag_fb_lod_ = 5;
263 int max_view_per_tilemap_ = 1;
264 int2 input_depth_extent_;
265
266 /* Statistics that are read back to CPU after a few frame (to avoid stall). */
267 SwapChain<ShadowStatisticsBuf, 5> statistics_buf_;
268
270
271 /* -------------------------------------------------------------------- */
274
275 static constexpr gpu::TextureFormat atlas_type = gpu::TextureFormat::UINT_32;
277 Texture atlas_tx_ = {"shadow_atlas_tx_"};
278
280 ShadowPageHeapBuf pages_free_data_ = {"PagesFreeBuf"};
282 ShadowPageCacheBuf pages_cached_data_ = {"PagesCachedBuf"};
284 ShadowPagesInfoDataBuf pages_infos_data_ = {"PagesInfosBuf"};
285
286 int3 copy_dispatch_size_;
287 int3 scan_dispatch_size_;
288 int rendering_tilemap_;
289 int rendering_lod_;
290 bool do_full_update_ = true;
291
293
294 /* -------------------------------------------------------------------- */
297
298 class ShadowView : public View {
299 Instance &inst_;
300 ShadowRenderViewBuf &render_view_buf_;
301
302 public:
303 ShadowView(const char *name, Instance &inst, ShadowRenderViewBuf &render_view_buf)
304 : View(name, SHADOW_VIEW_MAX, true), inst_(inst), render_view_buf_(render_view_buf)
305 {
306 }
307
308 protected:
310 virtual void compute_visibility(ObjectBoundsBuf &bounds,
311 ObjectInfosBuf &infos,
312 uint resource_len,
313 bool debug_freeze) override;
314 };
315
317 ShadowView shadow_multi_view_ = {"ShadowMultiView", inst_, render_view_buf_};
319 Framebuffer render_fb_ = {"shadow_write_framebuffer"};
320
321 /* NOTE(Metal): Metal requires memoryless textures to be created which represent attachments in
322 * the shadow write frame-buffer. These textures do not occupy any physical memory, but require a
323 * Texture object containing its parameters. */
324 Texture shadow_depth_fb_tx_ = {"shadow_depth_fb_tx_"};
325 Texture shadow_depth_accum_tx_ = {"shadow_depth_accum_tx_"};
326
328 std::array<int4, 16> multi_viewports_;
329
331
332 /* -------------------------------------------------------------------- */
335
337 PassSimple debug_draw_ps_ = {"Shadow.Debug"};
338
340
342
343 /* Render setting that reduces the LOD for every light. */
344 float global_lod_bias_ = 0.0f;
346 int shadow_page_size_ = SHADOW_PAGE_RES;
348 int shadow_page_len_ = SHADOW_MAX_TILEMAP;
350 bool enabled_ = true;
351
352 public:
353 ShadowModule(Instance &inst, ShadowSceneData &data);
354
356 {
357 GPU_BATCH_DISCARD_SAFE(box_batch_);
358 }
359
360 void init();
361
362 void begin_sync();
364 void sync_object(const Object *ob,
365 const ObjectHandle &handle,
366 const ResourceHandleRange &resource_handle,
367 bool is_alpha_blend,
368 bool has_transparent_shadows);
369 void end_sync();
370
372
373 /* Update all shadow regions visible inside the view.
374 * If called multiple time for the same view, it will only do the depth buffer scanning
375 * to check any new opaque surfaces.
376 * Expect the HiZ buffer to be up to date.
377 * Needs to be called after `LightModule::set_view();`. */
378 void set_view(View &view, int2 extent);
379
380 void debug_end_sync();
381 void debug_draw(View &view, gpu::FrameBuffer *view_fb);
382
383 template<typename PassType> void bind_resources(PassType &pass)
384 {
385 pass.bind_texture(SHADOW_ATLAS_TEX_SLOT, &atlas_tx_);
386 pass.bind_texture(SHADOW_TILEMAPS_TEX_SLOT, &tilemap_pool.tilemap_tx);
387 }
388
390 {
391 return data_;
392 }
393
394 float global_lod_bias() const
395 {
396 return global_lod_bias_;
397 }
398
399 /* Set all shadows to update. To be called before `end_sync`. */
400 void reset()
401 {
402 do_full_update_ = true;
403 }
404
406 static float screen_pixel_radius(const float4x4 &wininv,
407 bool is_perspective,
408 const int2 &extent);
409
410 private:
411 void remove_unused();
412 bool shadow_update_finished(int loop_count);
413
415 float tilemap_pixel_radius();
416
417 /* Returns the maximum number of view per shadow projection for a single update loop. */
418 int max_view_per_tilemap();
419};
420
422
423/* -------------------------------------------------------------------- */
428
430 private:
431 ShadowModule &shadows_;
433 Vector<ShadowTileMap *> tilemaps_;
434
435 public:
438 : shadows_(other.shadows_), tilemaps_(std::move(other.tilemaps_)) {};
439
441 {
442 shadows_.tilemap_pool.release(tilemaps_);
443 }
444
448 void release_excess_tilemaps(const Light &light);
449
453 void end_sync(Light &light);
454};
455
457 private:
458 ShadowModule &shadows_;
460 Vector<ShadowTileMap *> tilemaps_;
462 IndexRange levels_range = IndexRange(0);
463
464 public:
467 : shadows_(other.shadows_), tilemaps_(std::move(other.tilemaps_)) {};
468
470 {
471 shadows_.tilemap_pool.release(tilemaps_);
472 }
473
477 void release_excess_tilemaps(const Light &light, const Camera &camera);
478
482 void end_sync(Light &light, const Camera &camera);
483
484 /* Return coverage of the whole tile-map in world unit. */
485 static float coverage_get(int lvl)
486 {
487 /* This function should be kept in sync with shadow_directional_level(). */
488 /* \note If we would to introduce a global scaling option it would be here. */
489 return exp2(lvl);
490 }
491
492 /* Return coverage of a single tile for a tile-map of this LOD in world unit. */
493 static float tile_size_get(int lvl)
494 {
495 return coverage_get(lvl) / SHADOW_TILEMAP_RES;
496 }
497
498 private:
499 IndexRange clipmap_level_range(const Camera &camera);
500 IndexRange cascade_level_range(const Light &light, const Camera &camera);
501
506 void cascade_tilemaps_distribution(Light &light, const Camera &camera);
507 void clipmap_tilemaps_distribution(Light &light, const Camera &camera);
508
509 void cascade_tilemaps_distribution_near_far_points(const Camera &camera,
510 const Light &light,
511 float3 &near_point,
512 float3 &far_point);
513
514 /* Choose between clip-map and cascade distribution of shadow-map precision depending on the
515 * camera projection type and bounds. */
516 static eShadowProjectionType directional_distribution_type_get(const Camera &camera);
517};
518
520
521} // namespace blender::eevee
unsigned int uint
static AppView * view
static void View(GHOST_IWindow *window, bool stereo, int eye=0)
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:197
BMesh const char void * data
return true
long long int int64_t
NonCopyable(const NonCopyable &other)=delete
NonMovable(NonMovable &&other)=delete
View(const char *name, int view_len=1, bool procedural=false)
Definition draw_view.hh:70
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:499
A running instance of the engine.
static float coverage_get(int lvl)
ShadowDirectional(ShadowModule &module)
static float tile_size_get(int lvl)
void end_sync(Light &light, const Camera &camera)
ShadowDirectional(ShadowDirectional &&other)
void release_excess_tilemaps(const Light &light, const Camera &camera)
ShadowModule(Instance &inst, ShadowSceneData &data)
ShadowTileMapPool tilemap_pool
const ShadowSceneData & get_data()
void sync_object(const Object *ob, const ObjectHandle &handle, const ResourceHandleRange &resource_handle, bool is_alpha_blend, bool has_transparent_shadows)
Pool< ShadowDirectional > directional_pool
void bind_resources(PassType &pass)
static float screen_pixel_radius(const float4x4 &wininv, bool is_perspective, const int2 &extent)
void set_view(View &view, int2 extent)
Pool< ShadowPunctual > punctual_pool
void debug_draw(View &view, gpu::FrameBuffer *view_fb)
static ShadowTechnique shadow_technique
ShadowPunctual(ShadowPunctual &&other)
ShadowPunctual(ShadowModule &module)
void release_excess_tilemaps(const Light &light)
#define SHADOW_TILEMAP_RES
#define SHADOW_PAGE_RES
#define SHADOW_MAX_TILEMAP
#define SHADOW_TILEMAP_PER_ROW
#define SHADOW_VIEW_MAX
#define SHADOW_TILEDATA_PER_TILEMAP
#define SHADOW_ATLAS_TEX_SLOT
#define SHADOW_TILEMAPS_TEX_SLOT
#define exp2
PassType
detail::Pass< command::DrawCommandBuf > PassSimple
draw::StorageBuffer< DrawCommand, true > DrawIndirectBuf
Definition draw_pass.hh:71
detail::Pass< command::DrawMultiBuf > PassMain
StorageArrayBuffer< ObjectBounds, 128 > ObjectBoundsBuf
Definition draw_view.hh:33
draw::StorageBuffer< DispatchCommand > DispatchIndirectBuf
Definition draw_pass.hh:70
StorageArrayBuffer< ObjectInfos, 128 > ObjectInfosBuf
Definition draw_view.hh:34
draw::StorageBuffer< ShadowPagesInfoData > ShadowPagesInfoDataBuf
static constexpr const float shadow_face_mat[6][3][3]
draw::StorageArrayBuffer< ShadowTileDataPacked, SHADOW_MAX_TILE, true > ShadowTileDataBuf
draw::StorageArrayBuffer< ShadowTileMapClip, SHADOW_MAX_TILEMAP, true > ShadowTileMapClipBuf
draw::StorageArrayBuffer< uint2, SHADOW_MAX_PAGE, true > ShadowPageCacheBuf
draw::StorageArrayBuffer< ShadowRenderView, SHADOW_VIEW_MAX, true > ShadowRenderViewBuf
draw::StorageBuffer< ShadowStatistics > ShadowStatisticsBuf
draw::StorageVectorBuffer< ShadowTileMapData, SHADOW_MAX_TILEMAP > ShadowTileMapDataBuf
static constexpr const float shadow_clipmap_scale_mat[4][4]
draw::StorageVectorBuffer< uint, SHADOW_MAX_PAGE > ShadowPageHeapBuf
VecBase< uint32_t, 2 > uint2
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
static struct PyModuleDef module
Definition python.cpp:796
const char * name
ResourceHandleRange resource_handle
ShadowTileMapDataBuf tilemaps_data
ShadowTileMapDataBuf tilemaps_unused
void release(Span< ShadowTileMap * > free_list)
ShadowTileMapClipBuf tilemaps_clip
void end_sync(ShadowModule &module)
Pool< ShadowTileMap > tilemap_pool
static constexpr int64_t maps_per_row
void sync_orthographic(const float4x4 &object_mat_, int2 origin_offset, int clipmap_level, eShadowProjectionType projection_type_, uint2 shadow_set_membership_=~uint2(0))
static constexpr int64_t tile_map_resolution
static constexpr int64_t tiles_count
ShadowTileMap(int tiles_index_)
void sync_cubeface(eLightType light_type_, const float4x4 &object_mat, float near, float far, eCubeFace face, uint2 shadow_set_membership_=~uint2(0))