Blender V4.3
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
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"
20#include "eevee_shader.hh"
22#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. */
52 ATOMIC_RASTER = 0,
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. */
58 TILE_COPY = 1,
59};
60
61/* -------------------------------------------------------------------- */
73
75 int level = INT_MAX;
80
81 public:
82 ShadowTileMap(int tiles_index_)
83 {
84 tiles_index = tiles_index_;
85 /* For now just the same index. */
87 /* Avoid uninitialized data. */
88 this->grid_offset = int2(0);
89 this->grid_shift = int2(0);
90 this->set_dirty();
91 }
92
93 void sync_orthographic(const float4x4 &object_mat_,
94 int2 origin_offset,
95 int clipmap_level,
96 eShadowProjectionType projection_type_,
97 uint2 shadow_set_membership_ = ~uint2(0));
98
99 void sync_cubeface(eLightType light_type_,
100 const float4x4 &object_mat,
101 float near,
102 float far,
103 eCubeFace face,
104 uint2 shadow_set_membership_ = ~uint2(0));
105
106 void debug_draw() const;
107
109 {
110 is_dirty = true;
111 }
112
114 {
115 is_dirty = false;
116 }
117};
118
162
165/* -------------------------------------------------------------------- */
170/* Can be either a shadow caster or a shadow receiver. */
173 bool used = true;
174};
175
178/* -------------------------------------------------------------------- */
185 friend ShadowPunctual;
186 friend ShadowDirectional;
187 friend ShadowPipeline;
188 friend ShadowTileMapPool;
189
190 public:
191 /* Shadowing technique. */
193
196
199
200 private:
201 Instance &inst_;
202
203 ShadowSceneData &data_;
204
207
208 /* Used to call caster_update_ps_ only once per sync (Initialized on begin_sync). */
209 bool update_casters_ = false;
210
211 /* -------------------------------------------------------------------- */
215 PassSimple tilemap_setup_ps_ = {"TilemapSetup"};
216 PassMain tilemap_usage_ps_ = {"TagUsage"};
217 PassSimple tilemap_update_ps_ = {"TilemapUpdate"};
218
219 PassMain::Sub *tilemap_usage_transparent_ps_ = nullptr;
220 gpu::Batch *box_batch_ = nullptr;
221 /* Source texture for depth buffer analysis. */
222 GPUTexture *src_depth_tx_ = nullptr;
223
224 Framebuffer usage_tag_fb;
225
226 PassSimple caster_update_ps_ = {"CasterUpdate"};
227 PassSimple jittered_transparent_caster_update_ps_ = {"TransparentCasterUpdate"};
229 StorageVectorBuffer<uint, 128> past_casters_updated_ = {"PastCastersUpdated"};
230 StorageVectorBuffer<uint, 128> curr_casters_updated_ = {"CurrCastersUpdated"};
231 StorageVectorBuffer<uint, 128> jittered_transparent_casters_ = {"JitteredTransparentCasters"};
233 StorageVectorBuffer<uint, 128> curr_casters_ = {"CurrCasters"};
234
236 DispatchIndirectBuf clear_dispatch_buf_ = {"clear_dispatch_buf"};
238 DrawIndirectBuf tile_draw_buf_ = {"tile_draw_buf"};
240 StorageArrayBuffer<uint, SHADOW_RENDER_MAP_SIZE, true> dst_coord_buf_ = {"dst_coord_buf"};
242 StorageArrayBuffer<uint, SHADOW_RENDER_MAP_SIZE, true> src_coord_buf_ = {"src_coord_buf"};
244 StorageArrayBuffer<uint, SHADOW_RENDER_MAP_SIZE, true> render_map_buf_ = {"render_map_buf"};
246 ShadowRenderViewBuf render_view_buf_ = {"render_view_buf"};
247
248 int3 dispatch_depth_scan_size_;
249 int2 usage_tag_fb_resolution_;
250 int usage_tag_fb_lod_ = 5;
251 int max_view_per_tilemap_ = 1;
252 int2 input_depth_extent_;
253
254 /* Statistics that are read back to CPU after a few frame (to avoid stall). */
255 SwapChain<ShadowStatisticsBuf, 5> statistics_buf_;
256
259 /* -------------------------------------------------------------------- */
263 static constexpr eGPUTextureFormat atlas_type = GPU_R32UI;
265 Texture atlas_tx_ = {"shadow_atlas_tx_"};
266
268 ShadowPageHeapBuf pages_free_data_ = {"PagesFreeBuf"};
270 ShadowPageCacheBuf pages_cached_data_ = {"PagesCachedBuf"};
272 ShadowPagesInfoDataBuf pages_infos_data_ = {"PagesInfosBuf"};
273
274 int3 copy_dispatch_size_;
275 int3 scan_dispatch_size_;
276 int rendering_tilemap_;
277 int rendering_lod_;
278 bool do_full_update_ = true;
279
282 /* -------------------------------------------------------------------- */
286 class ShadowView : public View {
287 Instance &inst_;
288 ShadowRenderViewBuf &render_view_buf_;
289
290 public:
291 ShadowView(const char *name, Instance &inst, ShadowRenderViewBuf &render_view_buf)
292 : View(name, SHADOW_VIEW_MAX, true), inst_(inst), render_view_buf_(render_view_buf)
293 {
294 }
295
296 protected:
298 virtual void compute_visibility(ObjectBoundsBuf &bounds,
299 ObjectInfosBuf &infos,
300 uint resource_len,
301 bool debug_freeze) override;
302 };
303
305 ShadowView shadow_multi_view_ = {"ShadowMultiView", inst_, render_view_buf_};
307 Framebuffer render_fb_ = {"shadow_write_framebuffer"};
308
309 /* NOTE(Metal): Metal requires memoryless textures to be created which represent attachments in
310 * the shadow write frame-buffer. These textures do not occupy any physical memory, but require a
311 * Texture object containing its parameters. */
312 Texture shadow_depth_fb_tx_ = {"shadow_depth_fb_tx_"};
313 Texture shadow_depth_accum_tx_ = {"shadow_depth_accum_tx_"};
314
316 std::array<int4, 16> multi_viewports_;
317
320 /* -------------------------------------------------------------------- */
325 PassSimple debug_draw_ps_ = {"Shadow.Debug"};
326
331 /* Render setting that reduces the LOD for every light. */
332 float global_lod_bias_ = 0.0f;
334 int shadow_page_size_ = SHADOW_PAGE_RES;
336 int shadow_page_len_ = SHADOW_MAX_TILEMAP;
338 bool enabled_ = true;
339
340 public:
341 ShadowModule(Instance &inst, ShadowSceneData &data);
343
344 void init();
345
346 void begin_sync();
348 void sync_object(const Object *ob,
349 const ObjectHandle &handle,
350 const ResourceHandle &resource_handle,
351 bool is_alpha_blend,
352 bool has_transparent_shadows);
353 void end_sync();
354
356
357 /* Update all shadow regions visible inside the view.
358 * If called multiple time for the same view, it will only do the depth buffer scanning
359 * to check any new opaque surfaces.
360 * Expect the HiZ buffer to be up to date.
361 * Needs to be called after `LightModule::set_view();`. */
362 void set_view(View &view, int2 extent);
363
364 void debug_end_sync();
365 void debug_draw(View &view, GPUFrameBuffer *view_fb);
366
367 template<typename PassType> void bind_resources(PassType &pass)
368 {
369 pass.bind_texture(SHADOW_ATLAS_TEX_SLOT, &atlas_tx_);
371 }
372
374 {
375 return data_;
376 }
377
378 float global_lod_bias() const
379 {
380 return global_lod_bias_;
381 }
382
383 /* Set all shadows to update. To be called before `end_sync`. */
384 void reset()
385 {
386 do_full_update_ = true;
387 }
388
390 static float screen_pixel_radius(const float4x4 &wininv,
391 bool is_perspective,
392 const int2 &extent);
393
394 private:
395 void remove_unused();
396 void debug_page_map_call(DRWPass *pass);
397 bool shadow_update_finished(int loop_count);
398
400 float tilemap_pixel_radius();
401
402 /* Returns the maximum number of view per shadow projection for a single update loop. */
403 int max_view_per_tilemap();
404};
405
408/* -------------------------------------------------------------------- */
415 private:
416 ShadowModule &shadows_;
418 Vector<ShadowTileMap *> tilemaps_;
419
420 public:
423 : shadows_(other.shadows_), tilemaps_(std::move(other.tilemaps_)){};
424
426 {
427 shadows_.tilemap_pool.release(tilemaps_);
428 }
429
433 void release_excess_tilemaps(const Light &light);
434
438 void end_sync(Light &light);
439};
440
442 private:
443 ShadowModule &shadows_;
445 Vector<ShadowTileMap *> tilemaps_;
447 IndexRange levels_range = IndexRange(0);
448
449 public:
452 : shadows_(other.shadows_), tilemaps_(std::move(other.tilemaps_)){};
453
455 {
456 shadows_.tilemap_pool.release(tilemaps_);
457 }
458
462 void release_excess_tilemaps(const Light &light, const Camera &camera);
463
467 void end_sync(Light &light, const Camera &camera);
468
469 /* Return coverage of the whole tile-map in world unit. */
470 static float coverage_get(int lvl)
471 {
472 /* This function should be kept in sync with shadow_directional_level(). */
473 /* \note If we would to introduce a global scaling option it would be here. */
474 return exp2(lvl);
475 }
476
477 /* Return coverage of a single tile for a tile-map of this LOD in world unit. */
478 static float tile_size_get(int lvl)
479 {
480 return coverage_get(lvl) / SHADOW_TILEMAP_RES;
481 }
482
483 private:
484 IndexRange clipmap_level_range(const Camera &camera);
485 IndexRange cascade_level_range(const Light &light, const Camera &camera);
486
491 void cascade_tilemaps_distribution(Light &light, const Camera &camera);
492 void clipmap_tilemaps_distribution(Light &light, const Camera &camera);
493
494 void cascade_tilemaps_distribution_near_far_points(const Camera &camera,
495 const Light &light,
496 float3 &near_point,
497 float3 &far_point);
498
499 /* Choose between clip-map and cascade distribution of shadow-map precision depending on the
500 * camera projection type and bounds. */
501 static eShadowProjectionType directional_distribution_type_get(const Camera &camera);
502};
503
506} // namespace blender::eevee
unsigned int uint
eGPUTextureFormat
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:462
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()
Pool< ShadowDirectional > directional_pool
void bind_resources(PassType &pass)
void debug_draw(View &view, GPUFrameBuffer *view_fb)
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
static ShadowTechnique shadow_technique
void sync_object(const Object *ob, const ObjectHandle &handle, const ResourceHandle &resource_handle, bool is_alpha_blend, bool has_transparent_shadows)
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
SHADOW_TILEMAP_RES tiles_buf[] statistics_buf render_view_buf[SHADOW_VIEW_MAX] GPU_R32UI
PassType
detail::Pass< command::DrawCommandBuf > PassSimple
StorageArrayBuffer< ObjectBounds, 128 > ObjectBoundsBuf
Definition draw_view.hh:30
StorageArrayBuffer< ObjectInfos, 128 > ObjectInfosBuf
Definition draw_view.hh:31
draw::StorageBuffer< ShadowPagesInfoData > ShadowPagesInfoDataBuf
static constexpr const float shadow_face_mat[6][3][3]
draw::StorageBuffer< DrawCommand, true > DrawIndirectBuf
draw::StorageArrayBuffer< uint2, SHADOW_MAX_PAGE, true > ShadowPageCacheBuf
draw::StorageArrayBuffer< ShadowRenderView, SHADOW_VIEW_MAX, true > ShadowRenderViewBuf
static constexpr const float shadow_clipmap_scale_mat[4][4]
draw::StorageBuffer< DispatchCommand > DispatchIndirectBuf
draw::StorageVectorBuffer< uint, SHADOW_MAX_PAGE > ShadowPageHeapBuf
VecBase< uint32_t, 2 > uint2
VecBase< int32_t, 2 > int2
static struct PyModuleDef module
Definition python.cpp:991
__int64 int64_t
Definition stdint.h:89
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))