Blender V5.0
eevee_shadow.cc
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#include "BLI_math_matrix.hh"
12#include "GPU_batch_utils.hh"
13#include "GPU_compute.hh"
14
15#include "GPU_context.hh"
16#include "eevee_instance.hh"
17
18#include "GPU_debug.hh"
19#include "draw_cache.hh"
20#include "draw_debug.hh"
21
22namespace blender::eevee {
23
25
26/* -------------------------------------------------------------------- */
30
32 int2 origin_offset,
33 int clipmap_level,
34 eShadowProjectionType projection_type_,
35 uint2 shadow_set_membership_)
36{
37 if ((projection_type != projection_type_) || (level != clipmap_level) ||
38 (shadow_set_membership_ != shadow_set_membership))
39 {
40 set_dirty();
41 }
42 projection_type = projection_type_;
43 level = clipmap_level;
45 shadow_set_membership = shadow_set_membership_;
46
47 grid_shift = origin_offset - grid_offset;
48 grid_offset = origin_offset;
49
50 if (!equals_m4m4(object_mat.ptr(), object_mat_.ptr())) {
51 object_mat = object_mat_;
52 set_dirty();
53 }
54
55 float tile_size = ShadowDirectional::tile_size_get(level);
56
57 /* object_mat is a rotation matrix. Reduce imprecision by taking the transpose which is also the
58 * inverse in this particular case. */
60
62 center_offset = float2(grid_offset) * tile_size;
63
68 /* Near/far is computed on GPU using casters bounds. */
69 -1.0f,
70 1.0f);
71}
72
74 const float4x4 &object_mat_,
75 float near_,
76 float far_,
77 eCubeFace face,
78 uint2 shadow_set_membership_)
79{
81 (shadow_set_membership_ != shadow_set_membership))
82 {
83 set_dirty();
84 }
86 cubeface = face;
87 grid_offset = int2(0);
88 light_type = light_type_;
89 shadow_set_membership = shadow_set_membership_;
90
91 if ((clip_near != near_) || (clip_far != far_)) {
92 set_dirty();
93 }
94
95 clip_near = near_;
96 half_size = near_;
97 clip_far = far_;
98 center_offset = float2(0.0f);
99
100 if (!equals_m4m4(object_mat.ptr(), object_mat_.ptr())) {
101 object_mat = object_mat_;
102 set_dirty();
103 }
104
108
109 /* Same thing as inversion but avoid precision issues. */
111 /* Update corners. */
112 corners[0] = float4(viewinv.location(), 0.0f);
113 corners[1] = float4(math::transform_point(viewinv, float3(-far_, -far_, -far_)), 0.0f);
114 corners[2] = float4(math::transform_point(viewinv, float3(far_, -far_, -far_)), 0.0f);
115 corners[3] = float4(math::transform_point(viewinv, float3(-far_, far_, -far_)), 0.0f);
116 /* Store deltas. */
117 corners[2] = (corners[2] - corners[1]) / float(SHADOW_TILEMAP_RES);
118 corners[3] = (corners[3] - corners[1]) / float(SHADOW_TILEMAP_RES);
119}
120
122{
124 const float4 debug_color[6] = {
125 {1.0f, 0.1f, 0.1f, 1.0f},
126 {0.1f, 1.0f, 0.1f, 1.0f},
127 {0.0f, 0.2f, 1.0f, 1.0f},
128 {1.0f, 1.0f, 0.3f, 1.0f},
129 {0.1f, 0.1f, 0.1f, 1.0f},
130 {1.0f, 1.0f, 1.0f, 1.0f},
131 };
132 float4 color = debug_color
133 [((projection_type == SHADOW_PROJECTION_CUBEFACE ? int(cubeface) : level) + 9999) % 6];
134
135 float4x4 persinv = winmat * viewmat;
137}
138
140
141/* -------------------------------------------------------------------- */
145
147{
149 /* Reverse order to help debugging (first allocated tile-map will get 0). */
150 for (int i = SHADOW_MAX_TILEMAP - 1; i >= 0; i--) {
152 }
153
154 int2 extent;
157
160 tilemap_tx.ensure_2d(gpu::TextureFormat::UINT_32, extent, usage);
161 tilemap_tx.clear(uint4(0));
162}
163
165{
166 if (free_indices.is_empty()) {
167 /* Grow the tile-map buffer. See `end_sync`. */
168 for (auto i : IndexRange(free_indices.size(), SHADOW_MAX_TILEMAP)) {
170 }
171 }
172 int index = free_indices.pop_last();
173 return &tilemap_pool.construct(ShadowTileMap(index));
174}
175
177{
178 for (ShadowTileMap *map : free_list) {
179 free_indices.append(map->tiles_index);
180 tilemap_pool.destruct(*map);
181 }
182}
183
185{
186 tilemaps_data.push_update();
187
188 uint needed_tilemap_capacity = (free_indices.size() + tilemap_pool.size());
189 if (needed_tilemap_capacity != (tiles_data.size() / SHADOW_TILEDATA_PER_TILEMAP)) {
190 tiles_data.resize(needed_tilemap_capacity * SHADOW_TILEDATA_PER_TILEMAP);
191 tilemaps_clip.resize(needed_tilemap_capacity);
192 /* We reallocated the tile-map buffer, discarding all the data it contained.
193 * We need to re-initialize the page heaps. */
194 module.do_full_update_ = true;
195 }
196
197 tilemaps_unused.clear();
198 int64_t newly_unused_count = free_indices.size() - last_free_len;
199 if (newly_unused_count > 0) {
200 /* Upload tile-map indices which pages needs to be pushed back to the free page heap. */
201 Span<uint> newly_unused_indices = free_indices.as_span().slice(last_free_len,
202 newly_unused_count);
203 for (uint index : newly_unused_indices) {
204 /* Push a dummy tile-map to a unused tile-map buffer. It is then processed through the some
205 * of the setup steps to release the pages. */
206 ShadowTileMapData tilemap_data = {};
207 tilemap_data.tiles_index = index;
208 tilemap_data.clip_data_index = -1;
209 tilemap_data.grid_shift = int2(SHADOW_TILEMAP_RES);
211
212 tilemaps_unused.append(tilemap_data);
213 }
214 tilemaps_unused.push_update();
215 }
216
218}
219
221
222/* -------------------------------------------------------------------- */
226
228{
229 int tilemaps_needed = light_local_tilemap_count(light);
230 if (tilemaps_.size() <= tilemaps_needed) {
231 return;
232 }
233 auto span = tilemaps_.as_span();
234 shadows_.tilemap_pool.release(span.drop_front(tilemaps_needed));
235 tilemaps_ = span.take_front(tilemaps_needed);
236}
237
239{
240 ShadowTileMapPool &tilemap_pool = shadows_.tilemap_pool;
241
242 float4x4 object_to_world = light.object_to_world;
243
244 /* Acquire missing tile-maps. */
245 int tilemaps_needed = light_local_tilemap_count(light);
246 while (tilemaps_.size() < tilemaps_needed) {
247 tilemaps_.append(tilemap_pool.acquire());
248 }
249
250 float near = int_as_float(light.clip_near);
251 float far = int_as_float(light.clip_far);
252 for (int i : tilemaps_.index_range()) {
253 eCubeFace face = eCubeFace(Z_NEG + i);
254 tilemaps_[face]->sync_cubeface(
255 light.type, object_to_world, near, far, face, light.shadow_set_membership);
256 }
257
258 light.local.tilemaps_count = tilemaps_needed;
259 light.tilemap_index = tilemap_pool.tilemaps_data.size();
260 for (ShadowTileMap *tilemap : tilemaps_) {
261 /* Add shadow tile-maps grouped by lights to the GPU buffer. */
262 tilemap_pool.tilemaps_data.append(*tilemap);
263 tilemap->set_updated();
264 }
265}
266
268
269/* -------------------------------------------------------------------- */
285
286eShadowProjectionType ShadowDirectional::directional_distribution_type_get(const Camera &camera)
287{
288 /* TODO(fclem): Enable the cascade projection if the FOV is tiny in perspective mode. */
290}
291
292/************************************************************************
293 * Cascade Distribution *
294 ************************************************************************/
295
296void ShadowDirectional::cascade_tilemaps_distribution_near_far_points(const Camera &camera,
297 const Light &light,
298 float3 &near_point,
299 float3 &far_point)
300{
301 const CameraData &cam_data = camera.data_get();
302 /* Ideally we should only take the intersection with the scene bounds. */
304 light.object_to_world, camera.position() - camera.forward() * cam_data.clip_far);
306 light.object_to_world, camera.position() - camera.forward() * cam_data.clip_near);
307}
308
309IndexRange ShadowDirectional::cascade_level_range(const Light &light, const Camera &camera)
310{
311 /* NOTE: All tile-maps are meant to have the same LOD
312 * but we still return a range starting at the unique LOD. */
313
314 using namespace blender::math;
315
316 /* 16 is arbitrary. To avoid too much tile-map per directional lights. */
317 const int max_tilemap_per_shadows = 16;
318 const CameraData &cam_data = camera.data_get();
319
320 float3 near_point, far_point;
321 cascade_tilemaps_distribution_near_far_points(camera, light, near_point, far_point);
322
323 /* This gives the maximum resolution in depth we can have with a fixed set of tile-maps. Gives
324 * the best results when view direction is orthogonal to the light direction. */
325 float depth_range_in_shadow_space = distance(far_point.xy(), near_point.xy());
326 float min_depth_tilemap_size = 2 * (depth_range_in_shadow_space / max_tilemap_per_shadows);
327 /* This allow coverage of the whole view with a single tile-map if camera forward is colinear
328 * with the light direction. */
329 float min_diagonal_tilemap_size = cam_data.screen_diagonal_length;
330
331 if (camera.is_perspective()) {
332 /* Use the far plane diagonal if using perspective. */
333 min_diagonal_tilemap_size *= cam_data.clip_far / cam_data.clip_near;
334 }
335
336 /* TODO(fclem): Zoomed in camera can have very small diagonal size which will then result in
337 * negative lod_level. Since negative ranges are not supported inside `IndexRange` we have to
338 * ensure this doesn't happen. */
339 min_diagonal_tilemap_size = max(min_diagonal_tilemap_size, 0.5f);
340
341 /* Level of detail (or size) of every tile-maps of this light. */
342 /* TODO(fclem): Add support for lod bias from light. */
343 int lod_level = ceil(log2(max_ff(min_depth_tilemap_size, min_diagonal_tilemap_size)) + 0.5);
344
345 /* Tile-maps "rotate" around the first one so their effective range is only half their size. */
346 float per_tilemap_coverage = ShadowDirectional::coverage_get(lod_level) * 0.5f;
347 /* Number of tile-maps needed to cover the whole view. */
348 /* NOTE: floor + 0.5 to avoid 0 when parallel. */
349 int tilemap_len = ceil(0.5f + depth_range_in_shadow_space / per_tilemap_coverage);
350 return IndexRange(lod_level, tilemap_len);
351}
352
353void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera &camera)
354{
355 using namespace blender::math;
356
357 float4x4 object_mat = light.object_to_world;
358 object_mat.location() = float3(0.0f);
359
360 /* All tile-maps use the first level size. */
361 float half_size = ShadowDirectional::coverage_get(levels_range.first()) / 2.0f;
362 float tile_size = ShadowDirectional::tile_size_get(levels_range.first());
363
364 float3 near_point, far_point;
365 cascade_tilemaps_distribution_near_far_points(camera, light, near_point, far_point);
366
367 float2 local_view_direction = normalize(far_point.xy() - near_point.xy());
368 float2 farthest_tilemap_center = local_view_direction * half_size * (levels_range.size() - 1);
369
370 /* Offset for smooth level transitions. */
371 light.object_to_world.x.w = near_point.x;
372 light.object_to_world.y.w = near_point.y;
373 light.object_to_world.z.w = near_point.z;
374
375 /* Offset in tiles from the scene origin to the center of the first tile-maps. */
376 int2 origin_offset = int2(round(float2(near_point) / tile_size));
377 /* Offset in tiles between the first and the last tile-maps. */
378 int2 offset_vector = int2(round(farthest_tilemap_center / tile_size));
379
380 light.sun.clipmap_base_offset_neg = int2(0); /* Unused. */
381 light.sun.clipmap_base_offset_pos = (offset_vector * (1 << 16)) /
382 max_ii(levels_range.size() - 1, 1);
383
384 /* \note cascade_level_range starts the range at the unique LOD to apply to all tile-maps. */
385 int level = levels_range.first();
386 for (int i : IndexRange(levels_range.size())) {
387 ShadowTileMap *tilemap = tilemaps_[i];
388
389 /* Equal spacing between cascades layers since we want uniform shadow density. */
390 int2 level_offset = origin_offset +
391 shadow_cascade_grid_offset(light.sun.clipmap_base_offset_pos, i);
392 tilemap->sync_orthographic(
393 object_mat, level_offset, level, SHADOW_PROJECTION_CASCADE, light.shadow_set_membership);
394
395 /* Add shadow tile-maps grouped by lights to the GPU buffer. */
396 shadows_.tilemap_pool.tilemaps_data.append(*tilemap);
397 tilemap->set_updated();
398 }
399
400 light.sun.clipmap_origin = float2(origin_offset) * tile_size;
401
402 light.type = LIGHT_SUN_ORTHO;
403
404 /* Not really clip-maps, but this is in order to make #light_tilemap_max_get() work and determine
405 * the scaling. */
406 light.sun.clipmap_lod_min = levels_range.first();
407 light.sun.clipmap_lod_max = levels_range.last();
408}
409
410/************************************************************************
411 * Clip-map Distribution *
412 ************************************************************************/
413
414IndexRange ShadowDirectional::clipmap_level_range(const Camera &cam)
415{
416 using namespace blender::math;
417 /* Covers the closest points of the view. */
418 /* FIXME: IndexRange does not support negative indices. Clamp to 0 for now. */
419 int min_level = max(0.0f, floor(log2(abs(cam.data_get().clip_near))));
420 /* Covers the farthest points of the view. */
421 int max_level = ceil(log2(cam.bound_radius() + distance(cam.bound_center(), cam.position())));
422 /* We actually need to cover a bit more because of clipmap origin snapping. */
423 max_level = max(min_level, max_level) + 1;
424 IndexRange range(min_level, max_level - min_level + 1);
425 /* 32 to be able to pack offset into a single int2.
426 * The maximum level count is bounded by the mantissa of a 32bit float. */
427 const int max_tilemap_per_shadows = 24;
428 /* Take top-most level to still cover the whole view. */
429 range = range.take_back(max_tilemap_per_shadows);
430
431 return range;
432}
433
434void ShadowDirectional::clipmap_tilemaps_distribution(Light &light, const Camera &camera)
435{
436 float4x4 object_mat = light.object_to_world;
437 object_mat.location() = float3(0.0f);
438
439 for (int lod : IndexRange(levels_range.size())) {
440 ShadowTileMap *tilemap = tilemaps_[lod];
441
442 int level = levels_range.first() + lod;
443 /* Compute full offset from world origin to the smallest clipmap tile centered around the
444 * camera position. The offset is computed in smallest tile unit. */
445 float tile_size = ShadowDirectional::tile_size_get(level);
446 /* Moving to light space by multiplying by the transpose (which is the inverse). */
447 float2 light_space_camera_position = camera.position() * float2x3(object_mat.view<2, 3>());
448 int2 level_offset = int2(math::round(light_space_camera_position / tile_size));
449
450 tilemap->sync_orthographic(
451 object_mat, level_offset, level, SHADOW_PROJECTION_CLIPMAP, light.shadow_set_membership);
452
453 /* Add shadow tile-maps grouped by lights to the GPU buffer. */
454 shadows_.tilemap_pool.tilemaps_data.append(*tilemap);
455 tilemap->set_updated();
456 }
457
458 int2 pos_offset = int2(0);
459 int2 neg_offset = int2(0);
460 for (int lod : IndexRange(levels_range.size() - 1)) {
461 /* Since offset can only differ by one tile from the higher level, we can compress that as a
462 * single integer where one bit contains offset between 2 levels. Then a single bit shift in
463 * the shader gives the number of tile to offset in the given tile-map space. However we need
464 * also the sign of the offset for each level offset. To this end, we split the negative
465 * offsets to a separate int. */
466 int2 lvl_offset_next = tilemaps_[lod + 1]->grid_offset;
467 int2 lvl_offset = tilemaps_[lod]->grid_offset;
468 int2 lvl_delta = lvl_offset - (lvl_offset_next * 2);
469 BLI_assert(math::abs(lvl_delta.x) <= 1 && math::abs(lvl_delta.y) <= 1);
470 pos_offset |= math::max(lvl_delta, int2(0)) << lod;
471 neg_offset |= math::max(-lvl_delta, int2(0)) << lod;
472 }
473
474 /* Number of levels is limited to 32 by `clipmap_level_range()` for this reason. */
475 light.sun.clipmap_base_offset_pos = pos_offset;
476 light.sun.clipmap_base_offset_neg = neg_offset;
477
478 float tile_size_max = ShadowDirectional::tile_size_get(levels_range.last());
479 int2 level_offset_max = tilemaps_[levels_range.size() - 1]->grid_offset;
480
481 light.type = LIGHT_SUN;
482
483 /* Used for selecting the clipmap level. */
484 float3 location = transform_direction_transposed(light.object_to_world, camera.position());
485 /* Offset for smooth level transitions. */
486 light.object_to_world.x.w = location.x;
487 light.object_to_world.y.w = location.y;
488 light.object_to_world.z.w = location.z;
489 /* Used as origin for the clipmap_base_offset trick. */
490 light.sun.clipmap_origin = float2(level_offset_max * tile_size_max);
491
492 light.sun.clipmap_lod_min = levels_range.first();
493 light.sun.clipmap_lod_max = levels_range.last();
494}
495
497{
498 IndexRange levels_new = directional_distribution_type_get(camera) == SHADOW_PROJECTION_CASCADE ?
499 cascade_level_range(light, camera) :
500 clipmap_level_range(camera);
501
502 if (levels_range == levels_new) {
503 return;
504 }
505
506 IndexRange isect_range = levels_range.intersect(levels_new);
507 IndexRange before_range(levels_range.start(), isect_range.start() - levels_range.start());
508 IndexRange after_range(isect_range.one_after_last(),
509 levels_range.one_after_last() - isect_range.one_after_last());
510
511 auto span = tilemaps_.as_span();
512 shadows_.tilemap_pool.release(span.slice(before_range.shift(-levels_range.start())));
513 shadows_.tilemap_pool.release(span.slice(after_range.shift(-levels_range.start())));
514 tilemaps_ = span.slice(isect_range.shift(-levels_range.start()));
515 levels_range = isect_range;
516}
517
518void ShadowDirectional::end_sync(Light &light, const Camera &camera)
519{
520 ShadowTileMapPool &tilemap_pool = shadows_.tilemap_pool;
521 IndexRange levels_new = directional_distribution_type_get(camera) == SHADOW_PROJECTION_CASCADE ?
522 cascade_level_range(light, camera) :
523 clipmap_level_range(camera);
524
525 if (levels_range != levels_new) {
526 /* Acquire missing tile-maps. */
527 IndexRange isect_range = levels_new.intersect(levels_range);
528 int64_t before_range = isect_range.start() - levels_new.start();
529 int64_t after_range = levels_new.one_after_last() - isect_range.one_after_last();
530
531 Vector<ShadowTileMap *> cached_tilemaps = tilemaps_;
532 tilemaps_.clear();
533 for (int64_t i = 0; i < before_range; i++) {
534 tilemaps_.append(tilemap_pool.acquire());
535 }
536 /* Keep cached LOD's. */
537 tilemaps_.extend(cached_tilemaps);
538 for (int64_t i = 0; i < after_range; i++) {
539 tilemaps_.append(tilemap_pool.acquire());
540 }
541 levels_range = levels_new;
542 }
543
544 light.tilemap_index = tilemap_pool.tilemaps_data.size();
545 light.clip_near = 0x7F7FFFFF; /* floatBitsToOrderedInt(FLT_MAX) */
546 light.clip_far = int(0xFF7FFFFFu ^ 0x7FFFFFFFu); /* floatBitsToOrderedInt(-FLT_MAX) */
547
548 if (directional_distribution_type_get(camera) == SHADOW_PROJECTION_CASCADE) {
549 cascade_tilemaps_distribution(light, camera);
550 }
551 else {
552 clipmap_tilemaps_distribution(light, camera);
553 }
554}
555
557
558/* -------------------------------------------------------------------- */
562
564{
565 for (int i = 0; i < statistics_buf_.size(); i++) {
566 UNUSED_VARS(i);
567 statistics_buf_.current().clear_to_zero();
568 statistics_buf_.swap();
569 }
570}
571
573{
574 /* Temp: Disable TILE_COPY path while efficient solution for parameter buffer overflow is
575 * identified. This path can be re-enabled in future. */
576#if 0
577 /* Determine shadow update technique and atlas format.
578 * NOTE(Metal): Metal utilizes a tile-optimized approach for Apple Silicon's architecture. */
579 const bool is_metal_backend = (GPU_backend_get_type() == GPU_BACKEND_METAL);
580 const bool is_tile_based_arch = (GPU_platform_architecture() == GPU_ARCHITECTURE_TBDR);
581 if (is_metal_backend && is_tile_based_arch) {
583 }
584 else
585#endif
586 {
588 }
589
590 ::Scene &scene = *inst_.scene;
591
592 global_lod_bias_ = (1.0f - scene.eevee.shadow_resolution_scale) * SHADOW_TILEMAP_LOD;
593
594 bool update_lights = false;
595 bool enable_shadow = (scene.eevee.flag & SCE_EEVEE_SHADOW_ENABLED) != 0;
596 bool use_jitter = enable_shadow &&
597 (inst_.is_image_render ||
598 (!inst_.is_navigating && !inst_.is_transforming && !inst_.is_playback &&
600 update_lights |= assign_if_different(enabled_, enable_shadow);
601 update_lights |= assign_if_different(data_.use_jitter, bool32_t(use_jitter));
602 if (update_lights) {
603 /* Force light reset. */
604 for (Light &light : inst_.lights.light_map_.values()) {
605 light.initialized = false;
606 }
607 }
608
609 data_.ray_count = clamp_i(scene.eevee.shadow_ray_count, 1, SHADOW_MAX_RAY);
610 data_.step_count = clamp_i(scene.eevee.shadow_step_count, 1, SHADOW_MAX_STEP);
611
612 /* Pool size is in MBytes. */
613 const size_t pool_byte_size = enabled_ ? scene.eevee.shadow_pool_size * square_i(1024) : 1;
614 const size_t page_byte_size = square_i(shadow_page_size_) * sizeof(int);
615 shadow_page_len_ = int(divide_ceil_ul(pool_byte_size, page_byte_size));
616 shadow_page_len_ = min_ii(shadow_page_len_, SHADOW_MAX_PAGE);
617
618 const int2 atlas_extent = shadow_page_size_ * int2(SHADOW_PAGE_PER_ROW);
619 const int atlas_layers = divide_ceil_u(shadow_page_len_, SHADOW_PAGE_PER_LAYER);
620
623 tex_usage |= GPU_TEXTURE_USAGE_ATOMIC;
624 }
625 if (atlas_tx_.ensure_2d_array(atlas_type, atlas_extent, atlas_layers, tex_usage)) {
626 /* Global update. */
627 do_full_update_ = true;
628 }
629
630 /* Make allocation safe. Avoids crash later on. */
631 if (!atlas_tx_.is_valid()) {
632 atlas_tx_.ensure_2d_array(ShadowModule::atlas_type, int2(1), 1);
633 inst_.info_append_i18n(
634 "Error: Could not allocate shadow atlas. Most likely out of GPU memory.");
635 }
636
637 /* Read end of the swap-chain to avoid stall. */
638 if (inst_.is_viewport()) {
639 if (inst_.sampling.finished_viewport()) {
640 /* Swap enough to read the last one. */
641 for (int i = 0; i < statistics_buf_.size(); i++) {
642 statistics_buf_.swap();
643 }
644 }
645 else {
646 statistics_buf_.swap();
647 }
648 statistics_buf_.current().read();
649 ShadowStatistics stats = statistics_buf_.current();
650
651 if (stats.page_used_count > shadow_page_len_ && enabled_) {
652 inst_.info_append_i18n(
653 "Error: Shadow buffer full, may result in missing shadows and lower "
654 "performance. ({} / {})",
655 stats.page_used_count,
656 shadow_page_len_);
657 }
658 if (stats.view_needed_count > SHADOW_VIEW_MAX && enabled_) {
659 inst_.info_append_i18n("Error: Too many shadow updates, some shadows might be incorrect.");
660 }
661 }
662
663 atlas_tx_.filter_mode(false);
664
665 /* Create different viewport to support different update region size. The most fitting viewport
666 * is then selected during the tilemap finalize stage in `viewport_select`. */
667 for (int i = 0; i < multi_viewports_.size(); i++) {
670 int size_in_tile = min_ii(1 << i, SHADOW_TILEMAP_RES);
671 multi_viewports_[i][0] = 0;
672 multi_viewports_[i][1] = 0;
673 multi_viewports_[i][2] = size_in_tile * shadow_page_size_;
674 multi_viewports_[i][3] = size_in_tile * shadow_page_size_;
675 }
676}
677
679{
680 past_casters_updated_.clear();
681 curr_casters_updated_.clear();
682 curr_casters_.clear();
683 jittered_transparent_casters_.clear();
684 update_casters_ = true;
685
686 if (box_batch_ == nullptr) {
687 box_batch_ = GPU_batch_unit_cube();
688 }
689
690 {
691 Manager &manager = *inst_.manager;
692
693 PassMain &pass = tilemap_usage_ps_;
694 pass.init();
695
696 if (inst_.is_baking()) {
697 SurfelBuf &surfels_buf = inst_.volume_probes.bake.surfels_buf_;
698 CaptureInfoBuf &capture_info_buf = inst_.volume_probes.bake.capture_info_buf_;
699 float surfel_coverage_area = inst_.volume_probes.bake.surfel_density_;
700
701 /* Directional shadows. */
703 int directional_level = std::max(0, int(std::ceil(log2(surfel_coverage_area / texel_size))));
704
705 PassMain::Sub &sub = pass.sub("Surfels");
706 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_SURFELS));
707 sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
708 sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
709 sub.bind_ssbo("surfel_buf", &surfels_buf);
710 sub.bind_ssbo("capture_info_buf", &capture_info_buf);
711 sub.push_constant("directional_level", directional_level);
712 sub.bind_resources(inst_.uniform_data);
713 sub.bind_resources(inst_.lights);
714 sub.dispatch(&inst_.volume_probes.bake.dispatch_per_surfel_);
715
716 /* Skip opaque and transparent tagging for light baking. */
717 return;
718 }
719
720 {
721 /* Use depth buffer to tag needed shadow pages for opaque geometry. */
722 PassMain::Sub &sub = pass.sub("Opaque");
723 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_OPAQUE));
724 sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
725 sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
726 sub.bind_texture("depth_tx", &src_depth_tx_);
727 sub.push_constant("input_depth_extent", &input_depth_extent_);
728 sub.bind_resources(inst_.lights);
729 sub.bind_resources(inst_.uniform_data);
730 sub.bind_resources(inst_.hiz_buffer.front);
731 sub.dispatch(&dispatch_depth_scan_size_);
732 }
733 {
734 /* Use bounding boxes for transparent geometry. */
735 PassMain::Sub &sub = pass.sub("Transparent");
736 /* WORKAROUND: The DRW_STATE_WRITE_STENCIL is here only to avoid enabling the rasterizer
737 * discard inside draw manager. */
739 sub.state_stencil(0, 0, 0);
740 sub.framebuffer_set(&usage_tag_fb);
741 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT));
742 sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
743 sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
744 sub.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
745 sub.push_constant("fb_resolution", &usage_tag_fb_resolution_);
746 sub.push_constant("fb_lod", &usage_tag_fb_lod_);
747 sub.bind_resources(inst_.uniform_data);
748 sub.bind_resources(inst_.hiz_buffer.front);
749 sub.bind_resources(inst_.lights);
750
751 tilemap_usage_transparent_ps_ = &sub;
752 }
753 }
754}
755
757 const ObjectHandle &handle,
758 const ResourceHandleRange &resource_handle,
759 bool is_alpha_blend,
760 bool has_transparent_shadows)
761{
762 bool is_shadow_caster = !(ob->visibility_flag & OB_HIDE_SHADOW);
763 if (!is_shadow_caster && !is_alpha_blend) {
764 return;
765 }
766
767 ShadowObject &shadow_ob = objects_.lookup_or_add_default(handle.object_key);
768 shadow_ob.used = true;
769 const bool is_initialized = shadow_ob.resource_handle.is_valid();
770 const bool has_jittered_transparency = has_transparent_shadows && data_.use_jitter;
771 if (is_shadow_caster && (handle.recalc || !is_initialized || has_jittered_transparency)) {
772 if (handle.recalc && is_initialized) {
773 past_casters_updated_.append(shadow_ob.resource_handle.raw());
774 }
775
776 if (has_jittered_transparency) {
777 jittered_transparent_casters_.append(resource_handle.raw());
778 }
779 else {
780 curr_casters_updated_.append(resource_handle.raw());
781 }
782 }
783 shadow_ob.resource_handle = resource_handle;
784
785 if (is_shadow_caster) {
786 curr_casters_.append(resource_handle.raw());
787 }
788
789 if (is_alpha_blend && !inst_.is_baking()) {
790 tilemap_usage_transparent_ps_->draw(box_batch_, resource_handle);
791 }
792}
793
795{
796 /* Delete unused shadows first to release tile-maps that could be reused for new lights. */
797 for (Light &light : inst_.lights.light_map_.values()) {
798 /* Do not discard lights in baking mode. See WORKAROUND in `surfels_create`. */
799 if ((!light.used || !enabled_) && !inst_.is_baking()) {
800 light.shadow_discard_safe(*this);
801 }
802 else if (light.directional != nullptr) {
803 light.directional->release_excess_tilemaps(light, inst_.camera);
804 }
805 else if (light.punctual != nullptr) {
806 light.punctual->release_excess_tilemaps(light);
807 }
808 }
809
810 /* Allocate new tile-maps and fill shadow data of the lights. */
811 tilemap_pool.tilemaps_data.clear();
812 for (Light &light : inst_.lights.light_map_.values()) {
813 if (enabled_ == false) {
814 light.tilemap_index = LIGHT_NO_SHADOW;
815 }
816 else if (light.directional != nullptr) {
817 light.directional->end_sync(light, inst_.camera);
818 }
819 else if (light.punctual != nullptr) {
820 light.punctual->end_sync(light);
821 }
822 else {
823 light.tilemap_index = LIGHT_NO_SHADOW;
824 }
825 }
826 tilemap_pool.end_sync(*this);
827
828 /* Search for deleted or updated shadow casters */
829 auto it_end = objects_.items().end();
830 for (auto it = objects_.items().begin(); it != it_end; ++it) {
831 ShadowObject &shadow_ob = (*it).value;
832 /* Do not discard casters in baking mode. See WORKAROUND in `surfels_create`. */
833 if (!shadow_ob.used && !inst_.is_baking()) {
834 /* May not be a caster, but it does not matter, be conservative. */
835 past_casters_updated_.append(shadow_ob.resource_handle.raw());
836 objects_.remove(it);
837 }
838 else {
839 /* Clear for next sync. */
840 shadow_ob.used = false;
841 }
842 }
843 past_casters_updated_.push_update();
844 curr_casters_updated_.push_update();
845 jittered_transparent_casters_.push_update();
846
847 curr_casters_.push_update();
848
849 if (do_full_update_) {
850 do_full_update_ = false;
851 /* Put all pages in the free heap. */
852 for (uint i : IndexRange(shadow_page_len_)) {
853 uint3 page = {i % SHADOW_PAGE_PER_ROW,
856 pages_free_data_[i] = shadow_page_pack(page);
857 }
858 for (uint i : IndexRange(shadow_page_len_, SHADOW_MAX_PAGE - shadow_page_len_)) {
859 pages_free_data_[i] = 0xFFFFFFFFu;
860 }
861 pages_free_data_.push_update();
862
863 /* Clear tiles to not reference any page. */
864 tilemap_pool.tiles_data.clear_to_zero();
865 tilemap_pool.tilemaps_clip.clear_to_zero();
866
867 /* Clear cached page buffer. */
868 GPU_storagebuf_clear(pages_cached_data_, -1);
869
870 /* Reset info to match new state. */
871 pages_infos_data_.page_free_count = shadow_page_len_;
872 pages_infos_data_.page_alloc_count = 0;
873 pages_infos_data_.page_cached_next = 0u;
874 pages_infos_data_.page_cached_start = 0u;
875 pages_infos_data_.page_cached_end = 0u;
876 pages_infos_data_.push_update();
877 }
878
879 {
880 Manager &manager = *inst_.manager;
881
882 {
883 PassSimple &pass = tilemap_setup_ps_;
884 pass.init();
885
886 {
887 /* Clear tile-map clip buffer. */
888 PassSimple::Sub &sub = pass.sub("ClearClipmap");
889 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_CLIPMAP_CLEAR));
890 sub.bind_ssbo("tilemaps_clip_buf", tilemap_pool.tilemaps_clip);
891 sub.push_constant("tilemaps_clip_buf_len", int(tilemap_pool.tilemaps_clip.size()));
892 sub.dispatch(int3(
893 divide_ceil_u(tilemap_pool.tilemaps_clip.size(), SHADOW_CLIPMAP_GROUP_SIZE), 1, 1));
895 }
896
897 {
898 /* Compute near/far clip distances for directional shadows based on casters bounds. */
899 PassSimple::Sub &sub = pass.sub("DirectionalBounds");
900 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_BOUNDS));
901 sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
902 sub.bind_ssbo("tilemaps_clip_buf", tilemap_pool.tilemaps_clip);
903 sub.bind_ssbo("casters_id_buf", curr_casters_);
904 sub.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
905 sub.push_constant("resource_len", int(curr_casters_.size()));
906 sub.bind_resources(inst_.lights);
907 sub.dispatch(int3(
908 divide_ceil_u(std::max(curr_casters_.size(), int64_t(1)), SHADOW_BOUNDS_GROUP_SIZE),
909 1,
910 1));
912 }
913 {
914 /* Clear usage bits. Tag update from the tile-map for sun shadow clip-maps shifting. */
915 PassSimple::Sub &sub = pass.sub("Init");
916 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_INIT));
917 sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
918 sub.bind_ssbo("tilemaps_clip_buf", tilemap_pool.tilemaps_clip);
919 sub.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
920 sub.bind_ssbo("pages_cached_buf", pages_cached_data_);
921 sub.dispatch(int3(1, 1, tilemap_pool.tilemaps_data.size()));
922 /* Free unused tiles from tile-maps not used by any shadow. */
923 if (tilemap_pool.tilemaps_unused.size() > 0) {
924 sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_unused);
925 sub.dispatch(int3(1, 1, tilemap_pool.tilemaps_unused.size()));
926 }
928 }
929 }
930
931 {
932 /* Mark for update all shadow pages touching an updated shadow caster. */
933 PassSimple &pass = caster_update_ps_;
934 pass.init();
935 pass.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_UPDATE));
936 pass.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
937 pass.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
938 /* Past caster transforms. */
939 if (past_casters_updated_.size() > 0) {
940 pass.bind_ssbo("bounds_buf", &manager.bounds_buf.previous());
941 pass.bind_ssbo("resource_ids_buf", past_casters_updated_);
942 pass.dispatch(int3(past_casters_updated_.size(), 1, tilemap_pool.tilemaps_data.size()));
943 }
944 /* Current caster transforms. */
945 if (curr_casters_updated_.size() > 0) {
946 pass.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
947 pass.bind_ssbo("resource_ids_buf", curr_casters_updated_);
948 pass.dispatch(int3(curr_casters_updated_.size(), 1, tilemap_pool.tilemaps_data.size()));
949 }
951 }
952
953 {
954 /* Mark for update all shadow pages touching a jittered transparency shadow caster. */
955 PassSimple &pass = jittered_transparent_caster_update_ps_;
956 pass.init();
957 if (jittered_transparent_casters_.size() > 0) {
958 pass.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_UPDATE));
959 pass.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
960 pass.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
961 pass.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
962 pass.bind_ssbo("resource_ids_buf", jittered_transparent_casters_);
963 pass.dispatch(
964 int3(jittered_transparent_casters_.size(), 1, tilemap_pool.tilemaps_data.size()));
966 }
967 }
968
969 /* Non volume usage tagging happens between these two steps.
970 * (Setup at begin_sync) */
971
972 if (inst_.volume.needs_shadow_tagging() && !inst_.is_baking()) {
973 PassMain::Sub &sub = tilemap_usage_ps_.sub("World Volume");
974 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_VOLUME));
975 sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
976 sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
977 sub.bind_resources(inst_.uniform_data);
978 sub.bind_resources(inst_.hiz_buffer.front);
979 sub.bind_resources(inst_.sampling);
980 sub.bind_resources(inst_.lights);
981 sub.bind_resources(inst_.volume.properties);
982 sub.bind_resources(inst_.volume.result);
984 sub.dispatch(math::divide_ceil(inst_.volume.grid_size(), int3(VOLUME_GROUP_SIZE)));
985 }
986
987 {
988 PassSimple &pass = tilemap_update_ps_;
989 pass.init();
990 {
991 /* Mark tiles that are redundant in the mipmap chain as unused. */
992 PassSimple::Sub &sub = pass.sub("MaskLod");
993 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_PAGE_MASK));
994 sub.push_constant("max_view_per_tilemap", &max_view_per_tilemap_);
995 sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
996 sub.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
997 sub.dispatch(int3(1, 1, tilemap_pool.tilemaps_data.size()));
999 }
1000 {
1001 /* Free unused pages & Reclaim cached pages. */
1002 PassSimple::Sub &sub = pass.sub("Free");
1003 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_PAGE_FREE));
1004 sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
1005 sub.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
1006 sub.bind_ssbo("pages_infos_buf", pages_infos_data_);
1007 sub.bind_ssbo("pages_free_buf", pages_free_data_);
1008 sub.bind_ssbo("pages_cached_buf", pages_cached_data_);
1009 sub.dispatch(int3(1, 1, tilemap_pool.tilemaps_data.size()));
1010 /* Free unused tiles from tile-maps not used by any shadow. */
1011 if (tilemap_pool.tilemaps_unused.size() > 0) {
1012 sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_unused);
1013 sub.dispatch(int3(1, 1, tilemap_pool.tilemaps_unused.size()));
1014 }
1016 }
1017 {
1018 /* De-fragment the free page heap after cache reuse phase which can leave hole. */
1019 PassSimple::Sub &sub = pass.sub("Defrag");
1020 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_PAGE_DEFRAG));
1021 sub.bind_ssbo("pages_infos_buf", pages_infos_data_);
1022 sub.bind_ssbo("pages_free_buf", pages_free_data_);
1023 sub.bind_ssbo("pages_cached_buf", pages_cached_data_);
1024 sub.bind_ssbo("statistics_buf", statistics_buf_.current());
1025 sub.bind_ssbo("clear_dispatch_buf", clear_dispatch_buf_);
1026 sub.bind_ssbo("tile_draw_buf", tile_draw_buf_);
1027 sub.dispatch(int3(1, 1, 1));
1029 }
1030 {
1031 /* Assign pages to tiles that have been marked as used but possess no page. */
1032 PassSimple::Sub &sub = pass.sub("AllocatePages");
1033 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_PAGE_ALLOCATE));
1034 sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
1035 sub.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
1036 sub.bind_ssbo("statistics_buf", statistics_buf_.current());
1037 sub.bind_ssbo("pages_infos_buf", pages_infos_data_);
1038 sub.bind_ssbo("pages_free_buf", pages_free_data_);
1039 sub.bind_ssbo("pages_cached_buf", pages_cached_data_);
1040 sub.dispatch(int3(1, 1, tilemap_pool.tilemaps_data.size()));
1042 }
1043 {
1044 /* Convert the unordered tiles into a texture used during shading. Creates views. */
1045 PassSimple::Sub &sub = pass.sub("Finalize");
1046 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_FINALIZE));
1047 sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
1048 sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
1049 sub.bind_ssbo("pages_infos_buf", &pages_infos_data_);
1050 sub.bind_ssbo("statistics_buf", &statistics_buf_.current());
1051 sub.bind_ssbo("view_infos_buf", &shadow_multi_view_.matrices_ubo_get());
1052 sub.bind_ssbo("render_view_buf", &render_view_buf_);
1053 sub.bind_ssbo("tilemaps_clip_buf", &tilemap_pool.tilemaps_clip);
1054 sub.bind_image("tilemaps_img", &tilemap_pool.tilemap_tx);
1055 sub.dispatch(int3(1, 1, tilemap_pool.tilemaps_data.size()));
1058 }
1059 {
1060 /* Convert the unordered tiles into a texture used during shading. Creates views. */
1061 PassSimple::Sub &sub = pass.sub("RenderMap");
1062 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_RENDERMAP));
1063 sub.bind_ssbo("statistics_buf", &statistics_buf_.current());
1064 sub.bind_ssbo("render_view_buf", &render_view_buf_);
1065 sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
1066 sub.bind_ssbo("clear_dispatch_buf", &clear_dispatch_buf_);
1067 sub.bind_ssbo("tile_draw_buf", &tile_draw_buf_);
1068 sub.bind_ssbo("dst_coord_buf", &dst_coord_buf_);
1069 sub.bind_ssbo("src_coord_buf", &src_coord_buf_);
1070 sub.bind_ssbo("render_map_buf", &render_map_buf_);
1071 sub.dispatch(int3(1, 1, SHADOW_VIEW_MAX));
1073 }
1074 {
1075 /* Amend tilemap_tx content to support clipmap LODs. */
1076 PassSimple::Sub &sub = pass.sub("Amend");
1077 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_AMEND));
1078 sub.bind_image("tilemaps_img", tilemap_pool.tilemap_tx);
1079 sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
1080 sub.bind_resources(inst_.lights);
1081 sub.dispatch(int3(1));
1083 }
1084
1085 /* NOTE: We do not need to run the clear pass when using the TBDR update variant, as tiles
1086 * will be fully cleared as part of the shadow raster step. */
1089 PassSimple::Sub &sub = pass.sub("RenderClear");
1090 sub.framebuffer_set(&render_fb_);
1092 sub.shader_set(inst_.shaders.static_shader_get(SHADOW_PAGE_CLEAR));
1093 sub.bind_ssbo("pages_infos_buf", pages_infos_data_);
1094 sub.bind_ssbo("dst_coord_buf", dst_coord_buf_);
1095 sub.bind_image("shadow_atlas_img", atlas_tx_);
1096 sub.dispatch(clear_dispatch_buf_);
1098 }
1099 }
1100 }
1101
1103}
1104
1106{
1107 if (!ELEM(inst_.debug_mode,
1112 {
1113 return;
1114 }
1115
1116 /* Init but not filled if no active object. */
1117 debug_draw_ps_.init();
1118
1119 Object *object_active = inst_.draw_ctx->obact;
1120 if (object_active == nullptr) {
1121 return;
1122 }
1123
1124 ObjectKey object_key(ObjectRef(DEG_get_original(object_active)));
1125
1126 if (inst_.lights.light_map_.contains(object_key) == false) {
1127 return;
1128 }
1129
1130 Light &light = inst_.lights.light_map_.lookup(object_key);
1131
1132 if (light.tilemap_index >= SHADOW_MAX_TILEMAP) {
1133 return;
1134 }
1135
1136 DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | inst_.film.depth.test_state |
1138
1139 debug_draw_ps_.state_set(state);
1140 debug_draw_ps_.shader_set(inst_.shaders.static_shader_get(SHADOW_DEBUG));
1141 debug_draw_ps_.push_constant("debug_mode", int(inst_.debug_mode));
1142 debug_draw_ps_.push_constant("debug_tilemap_index", light.tilemap_index);
1143 debug_draw_ps_.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
1144 debug_draw_ps_.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
1145 debug_draw_ps_.bind_resources(inst_.uniform_data);
1146 debug_draw_ps_.bind_resources(inst_.hiz_buffer.front);
1147 debug_draw_ps_.bind_resources(inst_.lights);
1148 debug_draw_ps_.bind_resources(inst_.shadows);
1149 debug_draw_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
1150}
1151
1153 bool is_perspective,
1154 const int2 &extent)
1155{
1156 float min_dim = float(min_ii(extent.x, extent.y));
1157 float3 p0 = float3(-1.0f, -1.0f, 0.0f);
1158 float3 p1 = float3(float2(min_dim / extent) * 2.0f - 1.0f, 0.0f);
1159 p0 = math::project_point(wininv, p0);
1160 p1 = math::project_point(wininv, p1);
1161 /* Compute radius at unit plane from the camera. This is NOT the perspective division. */
1162 if (is_perspective) {
1163 p0 = p0 / p0.z;
1164 p1 = p1 / p1.z;
1165 }
1166 return math::distance(p0, p1) / min_dim;
1167}
1168
1169bool ShadowModule::shadow_update_finished(int loop_count)
1170{
1171 if (loop_count >= (SHADOW_MAX_TILEMAP * SHADOW_TILEMAP_LOD) / SHADOW_VIEW_MAX) {
1172 /* We have reach the maximum theoretical number of updates.
1173 * This can indicate a problem in the statistic buffer read-back or update tagging. */
1174 inst_.info_append_i18n("Error: Reached max shadow updates.");
1175 return true;
1176 }
1177
1178 if (!inst_.is_image_render && !inst_.is_light_bake) {
1179 /* For viewport, only run the shadow update once per redraw.
1180 * This avoids the stall from the read-back and freezes from long shadow update. */
1181 return true;
1182 }
1183
1184 int max_updated_view_count = tilemap_pool.tilemaps_data.size() * SHADOW_TILEMAP_LOD;
1185 if (max_updated_view_count <= SHADOW_VIEW_MAX) {
1186 /* There is enough shadow views to cover all tile-map updates.
1187 * No read-back needed as it is guaranteed that all of them will be updated. */
1188 return true;
1189 }
1190
1191 /* Read back and check if there is still tile-map to update. */
1192 statistics_buf_.current().async_flush_to_host();
1193 statistics_buf_.current().read();
1194 ShadowStatistics stats = statistics_buf_.current();
1195
1196 if (stats.page_used_count > shadow_page_len_) {
1197 inst_.info_append_i18n(
1198 "Error: Shadow buffer full, may result in missing shadows and lower "
1199 "performance. ({} / {})",
1200 stats.page_used_count,
1201 shadow_page_len_);
1202 }
1203
1204 /* Rendering is finished if we rendered all the remaining pages. */
1205 return stats.view_needed_count <= SHADOW_VIEW_MAX;
1206}
1207
1208int ShadowModule::max_view_per_tilemap()
1209{
1210 if (inst_.is_image_render) {
1211 /* No need to limit updates per lights as we ensure all lights levels will be rendered.
1212 * is_image_render. */
1213 return SHADOW_TILEMAP_LOD;
1214 }
1215 /* For now very simple heuristic. Can be improved later by taking into consideration how many
1216 * tile-maps are updating, but we cannot know the ones updated by casters. */
1217 int potential_view_count = 0;
1218 for (auto i : IndexRange(tilemap_pool.tilemaps_data.size())) {
1219 if (tilemap_pool.tilemaps_data[i].projection_type == SHADOW_PROJECTION_CUBEFACE) {
1220 potential_view_count += SHADOW_TILEMAP_LOD;
1221 }
1222 else {
1223 potential_view_count += 1;
1224 }
1225 }
1226 int max_view_count = divide_ceil_u(SHADOW_VIEW_MAX, math::max(potential_view_count, 1));
1227 /* For viewport interactivity, have a hard maximum. This allows smoother experience. */
1228 if (inst_.is_transforming || inst_.is_navigating) {
1229 max_view_count = math::min(2, max_view_count);
1230 }
1231 /* For animation playback, we always want the maximum performance. */
1232 if (inst_.is_playback) {
1233 max_view_count = math::min(1, max_view_count);
1234 }
1235
1236 return max_view_count;
1237}
1238
1239void ShadowModule::ShadowView::compute_visibility(ObjectBoundsBuf &bounds,
1240 ObjectInfosBuf &infos,
1241 uint resource_len,
1242 bool /*debug_freeze*/)
1243{
1244 GPU_debug_group_begin("View.compute_visibility");
1245
1246 uint word_per_draw = this->visibility_word_per_draw();
1247 /* Switch between tightly packed and set of whole word per instance. */
1248 uint words_len = (view_len_ == 1) ? divide_ceil_u(resource_len, 32) :
1249 resource_len * word_per_draw;
1250 words_len = ceil_to_multiple_u(max_ii(1, words_len), 4);
1251 /* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */
1252 visibility_buf_.resize(words_len);
1253
1254 const uint32_t data = 0xFFFFFFFFu;
1256
1257 if (do_visibility_) {
1258 gpu::Shader *shader = inst_.shaders.static_shader_get(SHADOW_VIEW_VISIBILITY);
1259 GPU_shader_bind(shader);
1260 GPU_shader_uniform_1i(shader, "resource_len", resource_len);
1261 GPU_shader_uniform_1i(shader, "view_len", view_len_);
1262 GPU_shader_uniform_1i(shader, "visibility_word_per_draw", word_per_draw);
1263 GPU_storagebuf_bind(bounds, GPU_shader_get_ssbo_binding(shader, "bounds_buf"));
1265 GPU_storagebuf_bind(render_view_buf_, GPU_shader_get_ssbo_binding(shader, "render_view_buf"));
1269 GPU_compute_dispatch(shader, divide_ceil_u(resource_len, DRW_VISIBILITY_GROUP_SIZE), 1, 1);
1271 }
1272
1274}
1275
1277{
1278 if (enabled_ == false) {
1279 /* All lights have been tagged to have no shadow. */
1280 return;
1281 }
1282
1283 input_depth_extent_ = extent;
1284
1286
1287 dispatch_depth_scan_size_ = int3(math::divide_ceil(extent, int2(SHADOW_DEPTH_SCAN_GROUP_SIZE)),
1288 1);
1289 max_view_per_tilemap_ = max_view_per_tilemap();
1290
1291 data_.film_pixel_radius = screen_pixel_radius(view.wininv(), view.is_persp(), extent);
1292 inst_.uniform_data.push_update();
1293
1294 usage_tag_fb_resolution_ = math::divide_ceil(extent, int2(std::exp2(usage_tag_fb_lod_)));
1295 usage_tag_fb.ensure(usage_tag_fb_resolution_);
1296
1298 int2 fb_size = int2(SHADOW_TILEMAP_RES * shadow_page_size_);
1299 int fb_layers = SHADOW_VIEW_MAX;
1300
1302 /* Create attachment-less framebuffer. */
1303 shadow_depth_fb_tx_.free();
1304 shadow_depth_accum_tx_.free();
1305 render_fb_.ensure(fb_size);
1306 }
1308 /* Create memoryless depth attachment for on-tile surface depth accumulation. */
1309 shadow_depth_fb_tx_.ensure_2d_array(
1310 gpu::TextureFormat::SFLOAT_32_DEPTH, fb_size, fb_layers, usage);
1311 shadow_depth_accum_tx_.ensure_2d_array(
1312 gpu::TextureFormat::SFLOAT_32, fb_size, fb_layers, usage);
1313 render_fb_.ensure(GPU_ATTACHMENT_TEXTURE(shadow_depth_fb_tx_),
1314 GPU_ATTACHMENT_TEXTURE(shadow_depth_accum_tx_));
1315 }
1316 else {
1318 }
1319
1320 inst_.hiz_buffer.update();
1321
1322 int loop_count = 0;
1323 do {
1324 GPU_debug_group_begin("Shadow");
1325 {
1326 GPU_uniformbuf_clear_to_zero(shadow_multi_view_.matrices_ubo_get());
1327
1328 inst_.manager->submit(tilemap_setup_ps_, view);
1329 if (assign_if_different(update_casters_, false)) {
1330 /* Run caster update only once. */
1331 /* TODO(fclem): There is an optimization opportunity here where we can
1332 * test casters only against the static tile-maps instead of all of them. */
1333 inst_.manager->submit(caster_update_ps_, view);
1334 }
1335 if (loop_count == 0) {
1336 inst_.manager->submit(jittered_transparent_caster_update_ps_, view);
1337 }
1338 inst_.manager->submit(tilemap_usage_ps_, view);
1339 inst_.manager->submit(tilemap_update_ps_, view);
1340
1341 shadow_multi_view_.compute_procedural_bounds();
1342
1343 statistics_buf_.current().async_flush_to_host();
1344
1345 /* Isolate shadow update into its own command buffer.
1346 * If parameter buffer exceeds limits, then other work will not be impacted. */
1347 bool use_flush = (shadow_technique == ShadowTechnique::TILE_COPY) &&
1349 /* Flush every loop as these passes are very heavy. */
1350 use_flush |= loop_count != 0;
1351
1352 if (use_flush) {
1353 GPU_flush();
1354 }
1355
1356 /* TODO(fclem): Move all of this to the draw::PassMain. */
1357 if (shadow_depth_fb_tx_.is_valid() && shadow_depth_accum_tx_.is_valid()) {
1359 render_fb_,
1360 {
1361 /* Depth is cleared to 0 for TBDR optimization. */
1362 {GPU_LOADACTION_CLEAR, GPU_STOREACTION_DONT_CARE, {0.0f, 0.0f, 0.0f, 0.0f}},
1366 });
1367 }
1368 else if (shadow_depth_fb_tx_.is_valid()) {
1369 GPU_framebuffer_bind_ex(render_fb_,
1370 {
1374 });
1375 }
1376 else {
1377 GPU_framebuffer_bind(render_fb_);
1378 }
1379
1381 reinterpret_cast<int (*)[4]>(multi_viewports_.data()));
1382
1383 inst_.pipelines.shadow.render(shadow_multi_view_);
1384
1385 if (use_flush) {
1386 GPU_flush();
1387 }
1388
1390 }
1392
1393 loop_count++;
1394
1395 } while (!shadow_update_finished(loop_count));
1396
1397 if (prev_fb) {
1398 GPU_framebuffer_bind(prev_fb);
1399 }
1400}
1401
1403{
1404 if (!ELEM(inst_.debug_mode,
1409 {
1410 return;
1411 }
1412
1413 switch (inst_.debug_mode) {
1415 inst_.info_append("Debug Mode: Shadow Tilemap");
1416 break;
1418 inst_.info_append("Debug Mode: Shadow Values");
1419 break;
1421 inst_.info_append("Debug Mode: Shadow Tile Random Color");
1422 break;
1424 inst_.info_append("Debug Mode: Shadow Tilemap Random Color");
1425 break;
1426 default:
1427 break;
1428 }
1429
1430 inst_.hiz_buffer.update();
1431
1432 GPU_framebuffer_bind(view_fb);
1433 inst_.manager->submit(debug_draw_ps_, view);
1434}
1435
1437
1438} // namespace blender::eevee
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE uint ceil_to_multiple_u(uint a, uint b)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE uint divide_ceil_u(uint a, uint b)
MINLINE int square_i(int a)
MINLINE int max_ii(int a, int b)
MINLINE uint64_t divide_ceil_ul(uint64_t a, uint64_t b)
MINLINE int clamp_i(int value, int min, int max)
MINLINE float int_as_float(int i)
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
unsigned int uint
#define UNUSED_VARS(...)
#define ELEM(...)
T * DEG_get_original(T *id)
@ OB_HIDE_SHADOW
@ SCE_EEVEE_SHADOW_ENABLED
@ SCE_EEVEE_SHADOW_JITTERED_VIEWPORT
static AppView * view
blender::gpu::Batch * GPU_batch_unit_cube() ATTR_WARN_UNUSED_RESULT
@ GPU_LOADACTION_CLEAR
@ GPU_STOREACTION_DONT_CARE
void GPU_compute_dispatch(blender::gpu::Shader *shader, uint groups_x_len, uint groups_y_len, uint groups_z_len, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
GPUBackendType GPU_backend_get_type()
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
#define GPU_ATTACHMENT_TEXTURE(_texture)
#define GPU_framebuffer_bind_ex(_fb,...)
void GPU_framebuffer_multi_viewports_set(blender::gpu::FrameBuffer *gpu_fb, const int viewport_rects[GPU_MAX_VIEWPORTS][4])
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
blender::gpu::FrameBuffer * GPU_framebuffer_active_get()
@ GPU_ARCHITECTURE_TBDR
GPUArchitectureType GPU_platform_architecture()
@ GPU_PRIM_TRIS
void GPU_shader_bind(blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
int GPU_shader_get_ssbo_binding(blender::gpu::Shader *shader, const char *name)
void GPU_shader_uniform_1i(blender::gpu::Shader *sh, const char *name, int value)
int32_t bool32_t
void GPU_flush()
Definition gpu_state.cc:305
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
@ GPU_BARRIER_TEXTURE_FETCH
Definition GPU_state.hh:37
@ GPU_BARRIER_UNIFORM
Definition GPU_state.hh:54
@ GPU_BARRIER_SHADER_IMAGE_ACCESS
Definition GPU_state.hh:35
void GPU_memory_barrier(GPUBarrier barrier)
Definition gpu_state.cc:326
void GPU_storagebuf_clear(blender::gpu::StorageBuf *ssbo, uint32_t clear_value)
void GPU_storagebuf_bind(blender::gpu::StorageBuf *ssbo, int slot)
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_SHADER_WRITE
@ GPU_TEXTURE_USAGE_MEMORYLESS
@ GPU_TEXTURE_USAGE_ATTACHMENT
@ GPU_TEXTURE_USAGE_ATOMIC
void GPU_uniformbuf_bind(blender::gpu::UniformBuf *ubo, int slot)
void GPU_uniformbuf_clear_to_zero(blender::gpu::UniformBuf *ubo)
BMesh const char void * data
long long int int64_t
constexpr int64_t one_after_last() const
constexpr IndexRange shift(int64_t n) const
constexpr IndexRange intersect(IndexRange other) const
constexpr int64_t start() const
SwapChain< ObjectBoundsBuf, 2 > bounds_buf
UniformArrayBuffer< ViewCullingData, DRW_VIEW_MAX > culling_
Definition draw_view.hh:50
VisibilityBuf visibility_buf_
Definition draw_view.hh:55
UniformArrayBuffer< ViewMatrices, DRW_VIEW_MAX > data_
Definition draw_view.hh:49
int visibility_word_per_draw() const
Definition draw_view.hh:167
void bind_resources(U &resources)
Definition draw_pass.hh:449
void framebuffer_set(gpu::FrameBuffer **framebuffer)
void shader_set(gpu::Shader *shader)
void bind_texture(const char *name, gpu::Texture *texture, GPUSamplerState state=sampler_auto)
void bind_image(const char *name, gpu::Texture *image)
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:690
void dispatch(int group_len)
void state_set(DRWState state, int clip_plane_count=0)
void barrier(GPUBarrier type)
void state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask)
void push_constant(const char *name, const float &data)
void bind_ssbo(const char *name, gpu::StorageBuf *buffer)
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:499
bool is_perspective() const
A running instance of the engine.
void info_append_i18n(const char *msg, Args &&...args)
static float coverage_get(int lvl)
static float tile_size_get(int lvl)
void end_sync(Light &light, const Camera &camera)
void release_excess_tilemaps(const Light &light, const Camera &camera)
ShadowModule(Instance &inst, ShadowSceneData &data)
ShadowTileMapPool tilemap_pool
void sync_object(const Object *ob, const ObjectHandle &handle, const ResourceHandleRange &resource_handle, bool is_alpha_blend, bool has_transparent_shadows)
static float screen_pixel_radius(const float4x4 &wininv, bool is_perspective, const int2 &extent)
void set_view(View &view, int2 extent)
void debug_draw(View &view, gpu::FrameBuffer *view_fb)
static ShadowTechnique shadow_technique
void release_excess_tilemaps(const Light &light)
nullptr float
Simple API to draw debug shapes and log in the viewport.
#define DRW_VISIBILITY_GROUP_SIZE
#define DRW_VIEW_CULLING_UBO_SLOT
#define DRW_OBJ_INFOS_SLOT
#define DRW_VIEW_UBO_SLOT
DRWState
Definition draw_state.hh:25
@ DRW_STATE_CULL_FRONT
Definition draw_state.hh:44
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_ALWAYS
Definition draw_state.hh:36
@ DRW_STATE_BLEND_CUSTOM
Definition draw_state.hh:63
@ DRW_STATE_WRITE_STENCIL
Definition draw_state.hh:32
#define SHADOW_TILEMAP_RES
#define SHADOW_PAGE_RES
#define SHADOW_MAX_TILEMAP
#define SHADOW_PAGE_PER_ROW
#define SHADOW_CLIPMAP_GROUP_SIZE
#define SHADOW_VIEW_MAX
#define SHADOW_DEPTH_SCAN_GROUP_SIZE
#define VOLUME_GROUP_SIZE
#define SHADOW_MAX_RAY
#define SHADOW_TILEDATA_PER_TILEMAP
#define SHADOW_MAX_STEP
#define SHADOW_BOUNDS_GROUP_SIZE
#define SHADOW_PAGE_PER_COL
#define SHADOW_PAGE_PER_LAYER
#define SHADOW_MAX_PAGE
#define SHADOW_TILEMAP_LOD
#define LIGHT_NO_SHADOW
#define round
VecBase< float, D > normalize(VecOp< float, D >) RET
#define log2
#define abs
#define floor
#define ceil
static ulong state[N]
detail::Pass< command::DrawCommandBuf > PassSimple
detail::Pass< command::DrawMultiBuf > PassMain
void drw_debug_matrix_as_bbox(const float4x4 &mat, const float4 color, const uint lifetime)
StorageArrayBuffer< ObjectBounds, 128 > ObjectBoundsBuf
Definition draw_view.hh:33
StorageArrayBuffer< ObjectInfos, 128 > ObjectInfosBuf
Definition draw_view.hh:34
@ SHADOW_TILEMAP_TAG_USAGE_SURFELS
@ SHADOW_TILEMAP_TAG_USAGE_OPAQUE
@ SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT
@ SHADOW_TILEMAP_TAG_USAGE_VOLUME
static constexpr const float shadow_face_mat[6][3][3]
static int2 shadow_cascade_grid_offset(int2 base_offset, int level_relative)
static int light_local_tilemap_count(LightData light)
static float3 transform_direction_transposed(Transform t, float3 direction)
draw::StorageArrayBuffer< Surfel, 64 > SurfelBuf
draw::StorageBuffer< CaptureInfoData > CaptureInfoBuf
static uint shadow_page_pack(uint3 page)
MatBase< T, 4, 4 > orthographic(T left, T right, T bottom, T top, T near_clip, T far_clip)
Create an orthographic projection matrix using OpenGL coordinate convention: Maps each axis range to ...
MatBase< T, 4, 4 > perspective(T left, T right, T bottom, T top, T near_clip, T far_clip)
Create a perspective projection matrix using OpenGL coordinate convention: Maps each axis range to [-...
MatBase< T, NumCol, NumRow > transpose(const MatBase< T, NumRow, NumCol > &mat)
T distance(const T &a, const T &b)
VecBase< T, Size > divide_ceil(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T min(const T &a, const T &b)
CartesianBasis invert(const CartesianBasis &basis)
VectorT project_point(const MatT &mat, const VectorT &point)
T max(const T &a, const T &b)
T abs(const T &a)
T round(const T &a)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
VecBase< uint32_t, 2 > uint2
VecBase< uint32_t, 4 > uint4
MatBase< float, 2, 3 > float2x3
VecBase< uint32_t, 3 > uint3
bool assign_if_different(T &old_value, T new_value)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
static struct PyModuleDef module
Definition python.cpp:796
#define FLT_MAX
Definition stdcycles.h:14
short type
short visibility_flag
float shadow_resolution_scale
struct SceneEEVEE eevee
const c_style_mat & ptr() const
const MatView< T, ViewNumCol, ViewNumRow, NumCol, NumRow, SrcStartCol, SrcStartRow, Alignment > view() const
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
void sync_cubeface(eLightType light_type_, const float4x4 &object_mat, float near, float far, eCubeFace face, uint2 shadow_set_membership_=~uint2(0))
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251