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