Blender V4.3
eevee_lightprobe_volume.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "BKE_global.hh"
8#include "BKE_lightprobe.h"
9
10#include "GPU_capabilities.hh"
11#include "GPU_debug.hh"
12
13#include "BLI_math_rotation.hh"
14
15#include "eevee_instance.hh"
16
18
19#include <cstdio>
20
21namespace blender::eevee {
22
23/* -------------------------------------------------------------------- */
28{
29 display_grids_enabled_ = DRW_state_draw_support();
30
31 /* This might become an option in the future. */
32 bool use_l2_band = false;
33 int sh_coef_len = use_l2_band ? 9 : 4;
35 int texel_byte_size = 8; /* Assumes GPU_RGBA16F. */
36 uint atlas_col_count = 0;
37 uint atlas_row_count = 0;
38
39 if (assign_if_different(irradiance_pool_size_,
41 !irradiance_atlas_tx_.is_valid())
42 {
43 irradiance_atlas_tx_.free();
44 /* Find highest pool size within device limits. */
45 for (uint irradiance_pool_size = irradiance_pool_size_;
46 irradiance_pool_size >= 16 && !irradiance_atlas_tx_.is_valid();
47 irradiance_pool_size >>= 1)
48 {
49 int atlas_byte_size = 1024 * 1024 * irradiance_pool_size;
50 /* Reshape texture to improve grid occupancy within device limits. */
51 constexpr uint atlas_col_count_min = 16;
52 constexpr uint atlas_col_count_max = 16384;
53 for (uint atlas_col_count_try = atlas_col_count_min;
54 atlas_col_count_try <= atlas_col_count_max && !irradiance_atlas_tx_.is_valid();
55 atlas_col_count_try <<= 1)
56 {
57 int3 atlas_extent(IRRADIANCE_GRID_BRICK_SIZE);
58 atlas_extent.z *= sh_coef_len;
59 /* Add space for validity bits. */
60 atlas_extent.z += IRRADIANCE_GRID_BRICK_SIZE / 4;
61 atlas_extent.x *= atlas_col_count_try;
62
63 /* Determine the row count depending on the scene settings. */
64 int row_byte_size = math::reduce_mul(atlas_extent) * texel_byte_size;
65 atlas_row_count = divide_ceil_u(atlas_byte_size, row_byte_size);
66 atlas_extent.y *= atlas_row_count;
67
71 irradiance_atlas_tx_.ensure_3d(VOLUME_PROBE_FORMAT, atlas_extent, usage);
72 if (irradiance_atlas_tx_.is_valid()) {
73 do_full_update_ = true;
74 irradiance_pool_size_alloc_ = irradiance_pool_size;
75 atlas_col_count = atlas_col_count_try;
76 }
77 }
78 }
79 }
80 if (irradiance_pool_size_alloc_ != irradiance_pool_size_) {
81 inst_.info_append_i18n(
82 "Warning: Could not allocate light probes volume pool of {} MB, using {} MB instead.",
83 irradiance_pool_size_,
84 irradiance_pool_size_alloc_);
85 }
86
87 if (do_full_update_) {
88 do_update_world_ = true;
89
90 /* Delete all references to existing bricks. */
91 for (VolumeProbe &grid : inst_.light_probes.volume_map_.values()) {
92 grid.bricks.clear();
93 }
94 brick_pool_.clear();
95 /* Fill with all the available bricks. */
96 for (auto i : IndexRange(atlas_row_count * atlas_col_count)) {
97 if (i == 0) {
98 /* Reserve one brick for the world. */
99 world_brick_index_ = 0;
100 }
101 else {
102 IrradianceBrick brick;
103 brick.atlas_coord = uint2(i % atlas_col_count, i / atlas_col_count) *
105 brick_pool_.append(irradiance_brick_pack(brick));
106 }
107 }
108
109 if (irradiance_atlas_tx_.is_valid()) {
110 /* Clear the pool to avoid any interpolation to undefined values. */
111 irradiance_atlas_tx_.clear(float4(0.0f));
112 }
113 }
114
115 if (irradiance_atlas_tx_.is_valid() == false) {
116 inst_.info_append_i18n("Irradiance Atlas texture could not be created");
117 }
118}
119
121{
122 if (inst_.is_baking()) {
123 bake.sync();
124 }
125}
126
128{
129 if (brick_pool_.size() < brick_len) {
130 /* Fail allocation. Not enough brick in the atlas. */
131 return {};
132 }
133 Vector<IrradianceBrickPacked> allocated(brick_len);
134 /* Copy bricks to return vector. */
135 allocated.as_mutable_span().copy_from(brick_pool_.as_span().take_back(brick_len));
136 /* Remove bricks from the pool. */
137 brick_pool_.resize(brick_pool_.size() - brick_len);
138
139 return allocated;
140}
141
143{
144 brick_pool_.extend(bricks.as_span());
145 bricks.clear();
146}
147
149{
150 Vector<VolumeProbe *> grid_loaded;
151
152 bool any_update = false;
153 /* First allocate the needed bricks and populate the brick buffer. */
154 bricks_infos_buf_.clear();
155 for (VolumeProbe &grid : inst_.light_probes.volume_map_.values()) {
156 LightProbeGridCacheFrame *cache = grid.cache ? grid.cache->grid_static_cache : nullptr;
157 if (cache == nullptr) {
158 continue;
159 }
160
161 if (cache->baking.L0 == nullptr && cache->irradiance.L0 == nullptr) {
162 /* No data. */
163 continue;
164 }
165
166 int3 grid_size = int3(cache->size);
167 if (grid_size.x <= 0 || grid_size.y <= 0 || grid_size.z <= 0) {
168 inst_.info_append_i18n("Error: Malformed irradiance grid data");
169 continue;
170 }
171
172 /* TODO frustum cull and only load visible grids. */
173
174 /* Note that we reserve 1 slot for the world irradiance. */
175 if (grid_loaded.size() >= IRRADIANCE_GRID_MAX - 1) {
176 inst_.info_append_i18n("Error: Too many irradiance grids in the scene");
177 /* TODO frustum cull and only load visible grids. */
178 // inst_.info_append_i18n("Error: Too many grid visible");
179 continue;
180 }
181
182 int3 grid_size_with_padding = grid_size + 2;
183 if (grid.bricks.is_empty()) {
184 int3 grid_size_in_bricks = math::divide_ceil(grid_size_with_padding,
186 int brick_len = grid_size_in_bricks.x * grid_size_in_bricks.y * grid_size_in_bricks.z;
187 grid.bricks = bricks_alloc(brick_len);
188
189 if (grid.bricks.is_empty()) {
190 inst_.info_append_i18n("Error: Irradiance grid allocation failed");
191 continue;
192 }
193 grid.do_update = true;
194 }
195
196 if (do_update_world_) {
197 /* Update grid composition if world changed. */
198 grid.do_update = true;
199 }
200
201 any_update = any_update || grid.do_update;
202
203 grid.brick_offset = bricks_infos_buf_.size();
204 bricks_infos_buf_.extend(grid.bricks);
205
206 float4x4 grid_to_world = grid.object_to_world * math::from_location<float4x4>(float3(-1.0f)) *
208 float3(2.0f / float3(grid_size_with_padding - 1))) *
210
211 grid.world_to_grid_transposed = float3x4(math::transpose(math::invert(grid_to_world)));
212 grid.grid_size_padded = grid_size_with_padding;
213 grid_loaded.append(&grid);
214 }
215
216 /* TODO: This is greedy update detection. We should check if a change can influence each grid
217 * before tagging update. But this is a bit too complex and update is quite cheap. So we update
218 * everything if there is any update on any grid. */
219 if (any_update) {
220 for (VolumeProbe *grid : grid_loaded) {
221 grid->do_update = true;
222 }
223 }
224
225 /* Then create brick & grid infos UBOs content. */
226 int world_grid_index = 0;
227 {
228 /* Stable sorting of grids. */
229 std::sort(
230 grid_loaded.begin(), grid_loaded.end(), [](const VolumeProbe *a, const VolumeProbe *b) {
231 float volume_a = math::determinant(float3x3(a->object_to_world));
232 float volume_b = math::determinant(float3x3(b->object_to_world));
233 if (volume_a != volume_b) {
234 /* Smallest first. */
235 return volume_a < volume_b;
236 }
237 /* Volumes are identical. Any arbitrary criteria can be used to sort them.
238 * Use position to avoid unstable result caused by depsgraph non deterministic eval
239 * order. This could also become a priority parameter. */
240 float3 _a = a->object_to_world.location();
241 float3 _b = b->object_to_world.location();
242 if (_a.x != _b.x) {
243 return _a.x < _b.x;
244 }
245 else if (_a.y != _b.y) {
246 return _a.y < _b.y;
247 }
248 else if (_a.z != _b.z) {
249 return _a.z < _b.z;
250 }
251 else {
252 /* Fallback to memory address, since there's no good alternative. */
253 return a < b;
254 }
255 });
256
257 /* Insert grids in UBO in sorted order. */
258 int grids_len = 0;
259 for (VolumeProbe *grid : grid_loaded) {
260 grid->grid_index = grids_len;
261 grids_infos_buf_[grids_len++] = *grid;
262 }
263
264 /* Insert world grid last. */
265 world_grid_index = grids_len++;
266
267 VolumeProbeData grid;
269 grid.grid_size_padded = int3(1);
270 grid.brick_offset = bricks_infos_buf_.size();
271 grid.normal_bias = 0.0f;
272 grid.view_bias = 0.0f;
273 grid.facing_bias = 0.0f;
274 grids_infos_buf_[world_grid_index] = grid;
275
276 bricks_infos_buf_.append(world_brick_index_);
277
278 if (grids_len < IRRADIANCE_GRID_MAX) {
279 /* Tag last grid as invalid to stop the iteration. */
280 grids_infos_buf_[grids_len].grid_size_padded = int3(-1);
281 }
282
283 bricks_infos_buf_.push_update();
284 grids_infos_buf_.push_update();
285 }
286
287 /* Upload data for world. */
288 if (do_update_world_) {
289 grid_upload_ps_.init();
290 grid_upload_ps_.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_WORLD));
291 grid_upload_ps_.bind_resources(inst_.uniform_data);
292 grid_upload_ps_.bind_ssbo("harmonic_buf", &inst_.sphere_probes.spherical_harmonics_buf());
293 grid_upload_ps_.bind_ubo("grids_infos_buf", &grids_infos_buf_);
294 grid_upload_ps_.bind_ssbo("bricks_infos_buf", &bricks_infos_buf_);
295 grid_upload_ps_.push_constant("grid_index", world_grid_index);
296 grid_upload_ps_.bind_image("irradiance_atlas_img", &irradiance_atlas_tx_);
297 /* Sync with extraction. */
298 grid_upload_ps_.barrier(GPU_BARRIER_SHADER_STORAGE);
299 /* Only upload one brick. */
300 grid_upload_ps_.dispatch(int3(1));
301 /* Sync with next load. */
302 grid_upload_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH);
303
304 inst_.manager->submit(grid_upload_ps_);
305 }
306
307 /* Upload data for each grid that need to be inserted in the atlas.
308 * Upload by order of dependency. */
309 /* Start at world index to not load any other grid (+1 because we decrement at loop start). */
310 int grid_start_index = grid_loaded.size() + 1;
311 for (auto it = grid_loaded.rbegin(); it != grid_loaded.rend(); ++it) {
312 grid_start_index--;
313
314 VolumeProbe *grid = *it;
315 if (!grid->do_update) {
316 continue;
317 }
318
319 grid->do_update = false;
320
321 LightProbeGridCacheFrame *cache = grid->cache->grid_static_cache;
322
323 /* Staging textures are recreated for each light grid to avoid increasing VRAM usage. */
324 draw::Texture irradiance_a_tx = {"irradiance_a_tx"};
325 draw::Texture irradiance_b_tx = {"irradiance_b_tx"};
326 draw::Texture irradiance_c_tx = {"irradiance_c_tx"};
327 draw::Texture irradiance_d_tx = {"irradiance_d_tx"};
328 draw::Texture validity_tx = {"validity_tx"};
329
331 int3 grid_size = int3(cache->size);
332 if (cache->baking.L0) {
333 irradiance_a_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, (const float *)cache->baking.L0);
334 irradiance_b_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, (const float *)cache->baking.L1_a);
335 irradiance_c_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, (const float *)cache->baking.L1_b);
336 irradiance_d_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, (const float *)cache->baking.L1_c);
337 validity_tx.ensure_3d(GPU_R16F, grid_size, usage, cache->baking.validity);
338 if (cache->baking.validity == nullptr) {
339 /* Avoid displaying garbage data. */
340 validity_tx.clear(float4(0.0));
341 }
342 }
343 else if (cache->irradiance.L0) {
344 irradiance_a_tx.ensure_3d(GPU_RGB16F, grid_size, usage, (const float *)cache->irradiance.L0);
345 irradiance_b_tx.ensure_3d(
346 GPU_RGB16F, grid_size, usage, (const float *)cache->irradiance.L1_a);
347 irradiance_c_tx.ensure_3d(
348 GPU_RGB16F, grid_size, usage, (const float *)cache->irradiance.L1_b);
349 irradiance_d_tx.ensure_3d(
350 GPU_RGB16F, grid_size, usage, (const float *)cache->irradiance.L1_c);
351 validity_tx.ensure_3d(GPU_R8, grid_size, usage);
352 if (cache->connectivity.validity) {
353 /* TODO(fclem): Make texture creation API work with different data types. */
354 GPU_texture_update_sub(validity_tx,
356 cache->connectivity.validity,
357 0,
358 0,
359 0,
360 UNPACK3(grid_size));
361 }
362 else {
363 /* Avoid displaying garbage data. */
364 validity_tx.clear(float4(0.0));
365 }
366 }
367 else {
368 continue;
369 }
370
371 if (irradiance_a_tx.is_valid() == false) {
372 inst_.info_append_i18n("Error: Could not allocate irradiance staging texture");
373 /* Avoid undefined behavior with uninitialized values. Still load a clear texture. */
374 const float4 zero(0.0f);
375 irradiance_a_tx.ensure_3d(GPU_RGB16F, int3(1), usage, zero);
376 irradiance_b_tx.ensure_3d(GPU_RGB16F, int3(1), usage, zero);
377 irradiance_c_tx.ensure_3d(GPU_RGB16F, int3(1), usage, zero);
378 irradiance_d_tx.ensure_3d(GPU_RGB16F, int3(1), usage, zero);
379 validity_tx.ensure_3d(GPU_R16F, int3(1), usage, zero);
380 }
381
382 bool visibility_available = cache->visibility.L0 != nullptr;
383 bool is_baking = cache->irradiance.L0 == nullptr;
384
385 draw::Texture visibility_a_tx = {"visibility_a_tx"};
386 draw::Texture visibility_b_tx = {"visibility_b_tx"};
387 draw::Texture visibility_c_tx = {"visibility_c_tx"};
388 draw::Texture visibility_d_tx = {"visibility_d_tx"};
389 if (visibility_available) {
390 visibility_a_tx.ensure_3d(GPU_R16F, grid_size, usage, (const float *)cache->visibility.L0);
391 visibility_b_tx.ensure_3d(GPU_R16F, grid_size, usage, (const float *)cache->visibility.L1_a);
392 visibility_c_tx.ensure_3d(GPU_R16F, grid_size, usage, (const float *)cache->visibility.L1_b);
393 visibility_d_tx.ensure_3d(GPU_R16F, grid_size, usage, (const float *)cache->visibility.L1_c);
394
395 GPU_texture_swizzle_set(visibility_a_tx, "111r");
396 GPU_texture_swizzle_set(visibility_b_tx, "111r");
397 GPU_texture_swizzle_set(visibility_c_tx, "111r");
398 GPU_texture_swizzle_set(visibility_d_tx, "111r");
399 }
400 else if (!is_baking) {
401 /* Missing visibility. Load default visibility L0 = 1, L1 = (0, 0, 0). */
402 GPU_texture_swizzle_set(irradiance_a_tx, "rgb1");
403 GPU_texture_swizzle_set(irradiance_b_tx, "rgb0");
404 GPU_texture_swizzle_set(irradiance_c_tx, "rgb0");
405 GPU_texture_swizzle_set(irradiance_d_tx, "rgb0");
406 }
407
408 grid_upload_ps_.init();
409 grid_upload_ps_.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_LOAD));
410
411 grid_upload_ps_.bind_resources(inst_.uniform_data);
412 grid_upload_ps_.push_constant("validity_threshold", grid->validity_threshold);
413 grid_upload_ps_.push_constant("dilation_threshold", grid->dilation_threshold);
414 grid_upload_ps_.push_constant("dilation_radius", grid->dilation_radius);
415 grid_upload_ps_.push_constant("grid_index", grid->grid_index);
416 grid_upload_ps_.push_constant("grid_start_index", grid_start_index);
417 grid_upload_ps_.push_constant("grid_local_to_world", grid->object_to_world);
418 grid_upload_ps_.push_constant("grid_intensity_factor", grid->intensity);
419 grid_upload_ps_.bind_ubo("grids_infos_buf", &grids_infos_buf_);
420 grid_upload_ps_.bind_ssbo("bricks_infos_buf", &bricks_infos_buf_);
421 grid_upload_ps_.bind_texture("irradiance_a_tx", &irradiance_a_tx);
422 grid_upload_ps_.bind_texture("irradiance_b_tx", &irradiance_b_tx);
423 grid_upload_ps_.bind_texture("irradiance_c_tx", &irradiance_c_tx);
424 grid_upload_ps_.bind_texture("irradiance_d_tx", &irradiance_d_tx);
425 grid_upload_ps_.bind_texture("validity_tx", &validity_tx);
426 grid_upload_ps_.bind_image("irradiance_atlas_img", &irradiance_atlas_tx_);
427 /* NOTE: We are read and writing the same texture that we are sampling from. If that causes an
428 * issue, we should revert to manual trilinear interpolation. */
429 grid_upload_ps_.bind_texture("irradiance_atlas_tx", &irradiance_atlas_tx_);
430 /* If visibility is invalid, either it is still baking and visibility is stored with
431 * irradiance, or it is missing and we sample a completely uniform visibility. */
432 bool use_vis = visibility_available;
433 grid_upload_ps_.bind_texture("visibility_a_tx", use_vis ? &visibility_a_tx : &irradiance_a_tx);
434 grid_upload_ps_.bind_texture("visibility_b_tx", use_vis ? &visibility_b_tx : &irradiance_b_tx);
435 grid_upload_ps_.bind_texture("visibility_c_tx", use_vis ? &visibility_c_tx : &irradiance_c_tx);
436 grid_upload_ps_.bind_texture("visibility_d_tx", use_vis ? &visibility_d_tx : &irradiance_d_tx);
437
438 /* Runtime grid is padded for blending with surrounding probes. */
439 int3 grid_size_with_padding = grid_size + 2;
440 /* Note that we take into account the padding border of each brick. */
441 int3 grid_size_in_bricks = math::divide_ceil(grid_size_with_padding,
443 grid_upload_ps_.dispatch(grid_size_in_bricks);
444 /* Sync with next load. */
445 grid_upload_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH);
446
447 inst_.manager->submit(grid_upload_ps_);
448
449 irradiance_a_tx.free();
450 irradiance_b_tx.free();
451 irradiance_c_tx.free();
452 irradiance_d_tx.free();
453 }
454
455 do_full_update_ = false;
456 do_update_world_ = false;
457}
458
459void VolumeProbeModule::viewport_draw(View &view, GPUFrameBuffer *view_fb)
460{
461 if (!inst_.is_baking()) {
462 debug_pass_draw(view, view_fb);
463 display_pass_draw(view, view_fb);
464 }
465}
466
467void VolumeProbeModule::debug_pass_draw(View &view, GPUFrameBuffer *view_fb)
468{
469 switch (inst_.debug_mode) {
470 case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL:
471 inst_.info_append("Debug Mode: Surfels Normal");
472 break;
473 case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_CLUSTER:
474 inst_.info_append("Debug Mode: Surfels Cluster");
475 break;
476 case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE:
477 inst_.info_append("Debug Mode: Surfels Irradiance");
478 break;
479 case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_VISIBILITY:
480 inst_.info_append("Debug Mode: Surfels Visibility");
481 break;
482 case eDebugMode::DEBUG_IRRADIANCE_CACHE_VALIDITY:
483 inst_.info_append("Debug Mode: Irradiance Validity");
484 break;
485 case eDebugMode::DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET:
486 inst_.info_append("Debug Mode: Virtual Offset");
487 break;
488 default:
489 /* Nothing to display. */
490 return;
491 }
492
493 for (const VolumeProbe &grid : inst_.light_probes.volume_map_.values()) {
494 if (grid.cache == nullptr) {
495 continue;
496 }
497
498 LightProbeGridCacheFrame *cache = grid.cache->grid_static_cache;
499
500 if (cache == nullptr) {
501 continue;
502 }
503
504 switch (inst_.debug_mode) {
505 case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL:
506 case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_CLUSTER:
507 case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_VISIBILITY:
508 case eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE: {
509 if (cache->surfels == nullptr || cache->surfels_len == 0) {
510 continue;
511 }
512 float max_axis_len = math::reduce_max(math::to_scale(grid.object_to_world));
513 debug_ps_.init();
514 debug_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
516 debug_ps_.framebuffer_set(&view_fb);
517 debug_ps_.shader_set(inst_.shaders.static_shader_get(DEBUG_SURFELS));
518 debug_ps_.push_constant("debug_surfel_radius", 0.5f * max_axis_len / grid.surfel_density);
519 debug_ps_.push_constant("debug_mode", int(inst_.debug_mode));
520
521 debug_surfels_buf_.resize(cache->surfels_len);
522 /* TODO(fclem): Cleanup: Could have a function in draw::StorageArrayBuffer that takes an
523 * input data. */
524 Span<Surfel> grid_surfels(static_cast<Surfel *>(cache->surfels), cache->surfels_len);
525 MutableSpan<Surfel>(debug_surfels_buf_.data(), cache->surfels_len).copy_from(grid_surfels);
526 debug_surfels_buf_.push_update();
527
528 debug_ps_.bind_ssbo("surfels_buf", debug_surfels_buf_);
529 debug_ps_.draw_procedural(GPU_PRIM_TRI_STRIP, cache->surfels_len, 4);
530
531 inst_.manager->submit(debug_ps_, view);
532 break;
533 }
534
535 case eDebugMode::DEBUG_IRRADIANCE_CACHE_VALIDITY:
536 case eDebugMode::DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET: {
537 int3 grid_size = int3(cache->size);
538 debug_ps_.init();
539 debug_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
541 debug_ps_.framebuffer_set(&view_fb);
542 debug_ps_.shader_set(inst_.shaders.static_shader_get(DEBUG_IRRADIANCE_GRID));
543 debug_ps_.push_constant("debug_mode", int(inst_.debug_mode));
544 debug_ps_.push_constant("grid_mat", grid.object_to_world);
545
547 Texture debug_data_tx = {"debug_data_tx"};
548
549 if (inst_.debug_mode == eDebugMode::DEBUG_IRRADIANCE_CACHE_VALIDITY) {
550 const float *data;
551 if (cache->baking.validity) {
552 data = cache->baking.validity;
553 debug_data_tx.ensure_3d(GPU_R16F, grid_size, usage, data);
554 }
555 else if (cache->connectivity.validity) {
556 debug_data_tx.ensure_3d(GPU_R8, grid_size, usage);
557 /* TODO(fclem): Make texture creation API work with different data types. */
558 GPU_texture_update_sub(debug_data_tx,
560 cache->connectivity.validity,
561 0,
562 0,
563 0,
564 UNPACK3(grid_size));
565 }
566 else {
567 continue;
568 }
569 debug_ps_.push_constant("debug_value", grid.validity_threshold);
570 debug_ps_.bind_texture("debug_data_tx", debug_data_tx);
571 debug_ps_.draw_procedural(GPU_PRIM_POINTS, 1, grid_size.x * grid_size.y * grid_size.z);
572 }
573 else {
574 if (cache->baking.virtual_offset) {
575 const float *data = (const float *)cache->baking.virtual_offset;
576 debug_data_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, data);
577 }
578 else {
579 continue;
580 }
581 debug_ps_.bind_texture("debug_data_tx", debug_data_tx);
582 debug_ps_.draw_procedural(
583 GPU_PRIM_LINES, 1, grid_size.x * grid_size.y * grid_size.z * 2);
584 }
585
586 inst_.manager->submit(debug_ps_, view);
587 break;
588 }
589
590 default:
591 break;
592 }
593 }
594}
595
596void VolumeProbeModule::display_pass_draw(View &view, GPUFrameBuffer *view_fb)
597{
598 if (!display_grids_enabled_) {
599 return;
600 }
601
602 for (const VolumeProbe &grid : inst_.light_probes.volume_map_.values()) {
603 if (!grid.viewport_display || grid.viewport_display_size == 0.0f || !grid.cache ||
604 !grid.cache->grid_static_cache)
605 {
606 continue;
607 }
608
609 LightProbeGridCacheFrame *cache = grid.cache->grid_static_cache;
610
611 /* Display texture. Updated for each individual light grid to avoid increasing VRAM usage. */
612 draw::Texture irradiance_a_tx = {"irradiance_a_tx"};
613 draw::Texture irradiance_b_tx = {"irradiance_b_tx"};
614 draw::Texture irradiance_c_tx = {"irradiance_c_tx"};
615 draw::Texture irradiance_d_tx = {"irradiance_d_tx"};
616 draw::Texture validity_tx = {"validity_tx"};
617
619 int3 grid_size = int3(cache->size);
620 if (cache->baking.L0) {
621 irradiance_a_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, (const float *)cache->baking.L0);
622 irradiance_b_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, (const float *)cache->baking.L1_a);
623 irradiance_c_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, (const float *)cache->baking.L1_b);
624 irradiance_d_tx.ensure_3d(GPU_RGBA16F, grid_size, usage, (const float *)cache->baking.L1_c);
625 validity_tx.ensure_3d(GPU_R16F, grid_size, usage, (const float *)cache->baking.validity);
626 if (cache->baking.validity == nullptr) {
627 /* Avoid displaying garbage data. */
628 validity_tx.clear(float4(0.0));
629 }
630 }
631 else if (cache->irradiance.L0) {
632 irradiance_a_tx.ensure_3d(GPU_RGB16F, grid_size, usage, (const float *)cache->irradiance.L0);
633 irradiance_b_tx.ensure_3d(
634 GPU_RGB16F, grid_size, usage, (const float *)cache->irradiance.L1_a);
635 irradiance_c_tx.ensure_3d(
636 GPU_RGB16F, grid_size, usage, (const float *)cache->irradiance.L1_b);
637 irradiance_d_tx.ensure_3d(
638 GPU_RGB16F, grid_size, usage, (const float *)cache->irradiance.L1_c);
639 validity_tx.ensure_3d(GPU_R8, grid_size, usage);
640 if (cache->connectivity.validity) {
641 /* TODO(fclem): Make texture creation API work with different data types. */
642 GPU_texture_update_sub(validity_tx,
644 cache->connectivity.validity,
645 0,
646 0,
647 0,
648 UNPACK3(grid_size));
649 }
650 else {
651 /* Avoid displaying garbage data. */
652 validity_tx.clear(float4(0.0));
653 }
654 }
655 else {
656 continue;
657 }
658
659 display_grids_ps_.init();
660 display_grids_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
662 display_grids_ps_.framebuffer_set(&view_fb);
663 display_grids_ps_.shader_set(inst_.shaders.static_shader_get(DISPLAY_PROBE_VOLUME));
664
665 display_grids_ps_.push_constant("sphere_radius", grid.viewport_display_size);
666 display_grids_ps_.push_constant("grid_resolution", grid_size);
667 display_grids_ps_.push_constant("grid_to_world", grid.object_to_world);
668 display_grids_ps_.push_constant("world_to_grid", grid.world_to_object);
669 /* TODO(fclem): Make it an option when display options are moved to probe DNA. */
670 display_grids_ps_.push_constant("display_validity", false);
671
672 display_grids_ps_.bind_texture("irradiance_a_tx", &irradiance_a_tx);
673 display_grids_ps_.bind_texture("irradiance_b_tx", &irradiance_b_tx);
674 display_grids_ps_.bind_texture("irradiance_c_tx", &irradiance_c_tx);
675 display_grids_ps_.bind_texture("irradiance_d_tx", &irradiance_d_tx);
676 display_grids_ps_.bind_texture("validity_tx", &validity_tx);
677
678 int sample_count = int(BKE_lightprobe_grid_cache_frame_sample_count(cache));
679 int triangle_count = sample_count * 2;
680 display_grids_ps_.draw_procedural(GPU_PRIM_TRIS, 1, triangle_count * 3);
681
682 inst_.manager->submit(display_grids_ps_, view);
683
684 irradiance_a_tx.free();
685 irradiance_b_tx.free();
686 irradiance_c_tx.free();
687 irradiance_d_tx.free();
688 }
689}
690
693/* -------------------------------------------------------------------- */
697void IrradianceBake::init(const Object &probe_object)
698{
699 float max_axis_len = math::reduce_max(math::to_scale(probe_object.object_to_world()));
700
701 const ::LightProbe *lightprobe = static_cast<::LightProbe *>(probe_object.data);
702 surfel_density_ = lightprobe->grid_surfel_density / max_axis_len;
703 min_distance_to_surface_ = lightprobe->grid_surface_bias;
704 max_virtual_offset_ = lightprobe->grid_escape_bias;
705 clip_distance_ = lightprobe->clipend;
706 capture_world_ = (lightprobe->grid_flag & LIGHTPROBE_GRID_CAPTURE_WORLD);
707 capture_indirect_ = (lightprobe->grid_flag & LIGHTPROBE_GRID_CAPTURE_INDIRECT);
708 capture_emission_ = (lightprobe->grid_flag & LIGHTPROBE_GRID_CAPTURE_EMISSION);
709
710 /* Initialize views data, since they're used by other modules. */
711 surfel_raster_views_sync(float3(0.0f), float3(1.0f), float4x4::identity());
712}
713
714void IrradianceBake::sync()
715{
716 {
717 PassSimple &pass = surfel_light_eval_ps_;
718 pass.init();
719 /* Apply lights contribution to scene surfel representation. */
720 pass.shader_set(inst_.shaders.static_shader_get(SURFEL_LIGHT));
721 pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
722 pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
723 pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
724 pass.bind_resources(inst_.uniform_data);
725 pass.bind_resources(inst_.lights);
726 pass.bind_resources(inst_.shadows);
727 /* Sync with the surfel creation stage. */
728 pass.barrier(GPU_BARRIER_SHADER_STORAGE);
730 pass.barrier(GPU_BARRIER_TEXTURE_FETCH);
731 pass.dispatch(&dispatch_per_surfel_);
732 }
733 {
734 PassSimple &pass = surfel_cluster_build_ps_;
735 pass.init();
736 pass.shader_set(inst_.shaders.static_shader_get(SURFEL_CLUSTER_BUILD));
737 pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
738 pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
739 pass.bind_image("cluster_list_img", &cluster_list_tx_);
740 pass.barrier(GPU_BARRIER_SHADER_STORAGE);
741 pass.dispatch(&dispatch_per_surfel_);
743 }
744 {
745 PassSimple &pass = surfel_ray_build_ps_;
746 pass.init();
747 {
748 PassSimple::Sub &sub = pass.sub("ListBuild");
749 sub.shader_set(inst_.shaders.static_shader_get(SURFEL_LIST_BUILD));
750 sub.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
751 sub.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
752 sub.bind_ssbo("list_start_buf", &list_start_buf_);
753 sub.bind_ssbo("list_info_buf", &list_info_buf_);
755 sub.dispatch(&dispatch_per_surfel_);
756 }
757 {
758 PassSimple::Sub &sub = pass.sub("ListSort");
759 sub.shader_set(inst_.shaders.static_shader_get(SURFEL_LIST_SORT));
760 sub.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
761 sub.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
762 sub.bind_ssbo("list_start_buf", &list_start_buf_);
763 sub.bind_ssbo("list_info_buf", &list_info_buf_);
765 sub.dispatch(&dispatch_per_list_);
766 }
767 }
768 {
769 PassSimple &pass = surfel_light_propagate_ps_;
770 pass.init();
771 {
772 PassSimple::Sub &sub = pass.sub("RayEval");
773 sub.shader_set(inst_.shaders.static_shader_get(SURFEL_RAY));
774 sub.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
775 sub.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
776 sub.bind_resources(inst_.sphere_probes);
777 sub.push_constant("radiance_src", &radiance_src_);
778 sub.push_constant("radiance_dst", &radiance_dst_);
780 sub.dispatch(&dispatch_per_surfel_);
781 }
782 }
783 {
784 PassSimple &pass = irradiance_capture_ps_;
785 pass.init();
786 pass.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_RAY));
787 pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
788 pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
789 pass.bind_resources(inst_.sphere_probes);
790 pass.bind_ssbo("list_start_buf", &list_start_buf_);
791 pass.bind_ssbo("list_info_buf", &list_info_buf_);
792 pass.push_constant("radiance_src", &radiance_src_);
793 pass.bind_image("irradiance_L0_img", &irradiance_L0_tx_);
794 pass.bind_image("irradiance_L1_a_img", &irradiance_L1_a_tx_);
795 pass.bind_image("irradiance_L1_b_img", &irradiance_L1_b_tx_);
796 pass.bind_image("irradiance_L1_c_img", &irradiance_L1_c_tx_);
797 pass.bind_image("validity_img", &validity_tx_);
798 pass.bind_image("virtual_offset_img", &virtual_offset_tx_);
800 pass.dispatch(&dispatch_per_grid_sample_);
801 }
802 {
803 PassSimple &pass = irradiance_offset_ps_;
804 pass.init();
805 pass.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_OFFSET));
806 pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
807 pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
808 pass.bind_ssbo("list_start_buf", &list_start_buf_);
809 pass.bind_ssbo("list_info_buf", &list_info_buf_);
810 pass.bind_image("cluster_list_img", &cluster_list_tx_);
811 pass.bind_image("virtual_offset_img", &virtual_offset_tx_);
813 pass.dispatch(&dispatch_per_grid_sample_);
814 }
815}
816
817void IrradianceBake::surfel_raster_views_sync(const float3 &scene_min,
818 const float3 &scene_max,
819 const float4x4 &probe_to_world)
820{
821 using namespace blender::math;
822
823 float3 location, scale;
824 Quaternion rotation;
825 to_loc_rot_scale(probe_to_world, location, rotation, scale);
826 /* Remove scale from view matrix. */
827 float4x4 viewinv = from_loc_rot_scale<float4x4>(location, rotation, float3(1.0f));
828 float4x4 viewmat = invert(viewinv);
829
830 /* Compute the intersection between the grid and the scene extents. */
831 float3 extent_min = float3(FLT_MAX);
832 float3 extent_max = float3(-FLT_MAX);
833 for (int x : {0, 1}) {
834 for (int y : {0, 1}) {
835 for (int z : {0, 1}) {
836 float3 ws_corner = scene_min + ((scene_max - scene_min) * float3(x, y, z));
837 float3 ls_corner = transform_point(viewmat, ws_corner);
838 extent_min = min(extent_min, ls_corner);
839 extent_max = max(extent_max, ls_corner);
840 }
841 }
842 }
843 /* Clip distance is added to every axis in both directions, not just Z. */
844 float3 target_extent = scale + clip_distance_;
845 extent_min = max(extent_min, -target_extent);
846 extent_max = min(extent_max, target_extent);
847
848 grid_pixel_extent_ = max(int3(1), int3(surfel_density_ * (extent_max - extent_min)));
849 grid_pixel_extent_ = min(grid_pixel_extent_, int3(16384));
850
851 float3 ls_midpoint = midpoint(extent_min, extent_max);
852 scene_bound_sphere_ = float4(transform_point(viewinv, ls_midpoint),
853 distance(extent_min, extent_max) / 2.0f);
854
855 /* We could use multi-view rendering here to avoid multiple submissions but it is unlikely to
856 * make any difference. The bottleneck is still the light propagation loop. */
857 auto sync_view = [&](View &view, CartesianBasis basis) {
858 float4x4 capture_viewinv = viewinv * from_rotation<float4x4>(basis);
859
860 float3 capture_extent_min = transform_point(invert(basis), extent_min);
861 float3 capture_extent_max = transform_point(invert(basis), extent_max);
862
863 float4x4 capture_winmat = projection::orthographic(capture_extent_min.x,
864 capture_extent_max.x,
865 capture_extent_min.y,
866 capture_extent_max.y,
867 -capture_extent_min.z,
868 -capture_extent_max.z);
869
870 view.visibility_test(false);
871 view.sync(invert(capture_viewinv), capture_winmat);
872 };
873
874 sync_view(view_x_, basis_x_);
875 sync_view(view_y_, basis_y_);
876 sync_view(view_z_, basis_z_);
877}
878
879void IrradianceBake::surfels_create(const Object &probe_object)
880{
886 using namespace blender::math;
887
888 const ::LightProbe *lightprobe = static_cast<::LightProbe *>(probe_object.data);
889
890 int3 grid_resolution = int3(&lightprobe->grid_resolution_x);
891 float4x4 grid_local_to_world = invert(probe_object.world_to_object());
892 float3 grid_scale = math::to_scale(probe_object.object_to_world());
893
894 /* TODO(fclem): Options. */
895 capture_info_buf_.capture_world_direct = capture_world_;
896 capture_info_buf_.capture_world_indirect = capture_world_ && capture_indirect_;
897 capture_info_buf_.capture_visibility_direct = !capture_world_;
898 capture_info_buf_.capture_visibility_indirect = !(capture_world_ && capture_indirect_);
899 capture_info_buf_.capture_indirect = capture_indirect_;
900 capture_info_buf_.capture_emission = capture_emission_;
901
902 LightProbeModule &light_probes = inst_.light_probes;
903 SphereProbeData &world_data = *static_cast<SphereProbeData *>(&light_probes.world_sphere_);
904 capture_info_buf_.world_atlas_coord = world_data.atlas_coord;
905
906 dispatch_per_grid_sample_ = math::divide_ceil(grid_resolution, int3(IRRADIANCE_GRID_GROUP_SIZE));
907 capture_info_buf_.irradiance_grid_size = grid_resolution;
908 capture_info_buf_.irradiance_grid_local_to_world = grid_local_to_world;
909 capture_info_buf_.irradiance_grid_world_to_local = probe_object.world_to_object();
910 capture_info_buf_.irradiance_grid_world_to_local_rotation = float4x4(
911 invert(normalize(float3x3(grid_local_to_world))));
912
913 capture_info_buf_.min_distance_to_surface = min_distance_to_surface_;
914 capture_info_buf_.max_virtual_offset = max_virtual_offset_;
915 capture_info_buf_.surfel_radius = 0.5f / surfel_density_;
916 /* Make virtual offset distances scale relative. */
917 float min_distance_between_grid_samples = math::reduce_min(grid_scale / float3(grid_resolution));
918 capture_info_buf_.min_distance_to_surface *= min_distance_between_grid_samples;
919 capture_info_buf_.max_virtual_offset *= min_distance_between_grid_samples;
920 capture_info_buf_.clamp_direct = (lightprobe->grid_clamp_direct > 0.0) ?
921 lightprobe->grid_clamp_direct :
922 1e20f;
923 capture_info_buf_.clamp_indirect = (lightprobe->grid_clamp_indirect > 0.0) ?
924 lightprobe->grid_clamp_indirect :
925 1e20f;
926
929
930 /* 32bit float is needed here otherwise we loose too much energy from rounding error during the
931 * accumulation when the sample count is above 500. */
932 irradiance_L0_tx_.ensure_3d(GPU_RGBA32F, grid_resolution, texture_usage);
933 irradiance_L1_a_tx_.ensure_3d(GPU_RGBA32F, grid_resolution, texture_usage);
934 irradiance_L1_b_tx_.ensure_3d(GPU_RGBA32F, grid_resolution, texture_usage);
935 irradiance_L1_c_tx_.ensure_3d(GPU_RGBA32F, grid_resolution, texture_usage);
936 validity_tx_.ensure_3d(GPU_R32F, grid_resolution, texture_usage);
937 virtual_offset_tx_.ensure_3d(GPU_RGBA16F, grid_resolution, texture_usage);
938
939 if (!irradiance_L0_tx_.is_valid() || !irradiance_L1_a_tx_.is_valid() ||
940 !irradiance_L1_b_tx_.is_valid() || !irradiance_L1_c_tx_.is_valid() ||
941 !validity_tx_.is_valid() || !virtual_offset_tx_.is_valid())
942 {
943 inst_.info_append_i18n("Error: Not enough memory to bake {}.", probe_object.id.name);
944 do_break_ = true;
945 return;
946 }
947
948 irradiance_L0_tx_.clear(float4(0.0f));
949 irradiance_L1_a_tx_.clear(float4(0.0f));
950 irradiance_L1_b_tx_.clear(float4(0.0f));
951 irradiance_L1_c_tx_.clear(float4(0.0f));
952 validity_tx_.clear(float4(0.0f));
953 virtual_offset_tx_.clear(float4(0.0f));
954
955 DRW_stats_group_start("IrradianceBake.SceneBounds");
956
957 {
958 draw::Manager &manager = *inst_.manager;
959 PassSimple &pass = irradiance_bounds_ps_;
960 pass.init();
961 pass.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_BOUNDS));
962 pass.bind_ssbo("capture_info_buf", &capture_info_buf_);
963 pass.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
964 pass.push_constant("resource_len", int(manager.resource_handle_count()));
965 pass.dispatch(
967 }
968
969 /* Raster the scene to query the number of surfel needed. */
970 capture_info_buf_.do_surfel_count = false;
971 capture_info_buf_.do_surfel_output = false;
972
973 const int neg_flt_max = int(0xFF7FFFFFu ^ 0x7FFFFFFFu); /* floatBitsToOrderedInt(-FLT_MAX) */
974 const int pos_flt_max = 0x7F7FFFFF; /* floatBitsToOrderedInt(FLT_MAX) */
975 capture_info_buf_.scene_bound_x_min = pos_flt_max;
976 capture_info_buf_.scene_bound_y_min = pos_flt_max;
977 capture_info_buf_.scene_bound_z_min = pos_flt_max;
978 capture_info_buf_.scene_bound_x_max = neg_flt_max;
979 capture_info_buf_.scene_bound_y_max = neg_flt_max;
980 capture_info_buf_.scene_bound_z_max = neg_flt_max;
981
982 capture_info_buf_.push_update();
983
984 inst_.manager->submit(irradiance_bounds_ps_);
985
987 capture_info_buf_.read();
988
989 if (capture_info_buf_.scene_bound_x_min == pos_flt_max) {
990 /* No valid object has been found. */
991 do_break_ = true;
992 return;
993 }
994
995 auto ordered_int_bits_to_float = [](int32_t int_value) -> float {
996 int32_t float_bits = (int_value < 0) ? (int_value ^ 0x7FFFFFFF) : int_value;
997 return *reinterpret_cast<float *>(&float_bits);
998 };
999
1000 float3 scene_min = float3(ordered_int_bits_to_float(capture_info_buf_.scene_bound_x_min),
1001 ordered_int_bits_to_float(capture_info_buf_.scene_bound_y_min),
1002 ordered_int_bits_to_float(capture_info_buf_.scene_bound_z_min));
1003 float3 scene_max = float3(ordered_int_bits_to_float(capture_info_buf_.scene_bound_x_max),
1004 ordered_int_bits_to_float(capture_info_buf_.scene_bound_y_max),
1005 ordered_int_bits_to_float(capture_info_buf_.scene_bound_z_max));
1006 /* To avoid loosing any surface to the clipping planes, add some padding. */
1007 float epsilon = 1.0f / surfel_density_;
1008 scene_min -= epsilon;
1009 scene_max += epsilon;
1010 surfel_raster_views_sync(scene_min, scene_max, probe_object.object_to_world());
1011
1013
1014 /* WORKAROUND: Sync camera with correct bounds for light culling. */
1015 inst_.camera.sync();
1016 /* WORKAROUND: Sync shadows tile-maps count again with new camera bounds. Fixes issues with sun
1017 * lights. */
1018 inst_.shadows.end_sync();
1019 inst_.lights.end_sync();
1020
1021 DRW_stats_group_start("IrradianceBake.SurfelsCount");
1022
1023 /* Raster the scene to query the number of surfel needed. */
1024 capture_info_buf_.do_surfel_count = true;
1025 capture_info_buf_.do_surfel_output = false;
1026 capture_info_buf_.surfel_len = 0u;
1027 capture_info_buf_.push_update();
1028
1029 empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_x_), grid_pixel_extent_).xy()));
1030 inst_.pipelines.capture.render(view_x_);
1031 empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_y_), grid_pixel_extent_).xy()));
1032 inst_.pipelines.capture.render(view_y_);
1033 empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_z_), grid_pixel_extent_).xy()));
1034 inst_.pipelines.capture.render(view_z_);
1035
1037
1038 /* Allocate surfel pool. */
1040 capture_info_buf_.read();
1041 if (capture_info_buf_.surfel_len == 0) {
1042 /* No surfel to allocate. */
1043 return;
1044 }
1045
1046 if (capture_info_buf_.surfel_len > surfels_buf_.size()) {
1047 printf("IrradianceBake: Allocating %u surfels.\n", capture_info_buf_.surfel_len);
1048
1049 size_t max_size = GPU_max_storage_buffer_size();
1051 int total_mem_kb, free_mem_kb;
1052 GPU_mem_stats_get(&total_mem_kb, &free_mem_kb);
1053 /* Leave at least 128MByte for OS and stuffs.
1054 * Try to avoid crashes because of OUT_OF_MEMORY errors. */
1055 size_t max_alloc = (size_t(total_mem_kb) - 128 * 1024) * 1024;
1056 /* Cap to 95% of available memory. */
1057 size_t max_free = size_t((size_t(free_mem_kb) * 1024) * 0.95f);
1058
1059 max_size = min(max_size, min(max_alloc, max_free));
1060 }
1061
1062 size_t required_mem = sizeof(Surfel) * (capture_info_buf_.surfel_len - surfels_buf_.size());
1063 if (required_mem > max_size) {
1064 const bool is_ssbo_bound = (max_size == GPU_max_storage_buffer_size());
1065 const uint req_mb = required_mem / (1024 * 1024);
1066 const uint max_mb = max_size / (1024 * 1024);
1067
1068 if (is_ssbo_bound) {
1069 inst_.info_append_i18n(
1070 "Cannot allocate enough video memory to bake \"{}\" ({} / {} MBytes).\n"
1071 "Try reducing surfel resolution or capture distance to lower the size of the "
1072 "allocation.",
1073 probe_object.id.name,
1074 req_mb,
1075 max_mb);
1076 }
1077 else {
1078 inst_.info_append_i18n(
1079 "Not enough available video memory to bake \"{}\" ({} / {} MBytes).\n"
1080 "Try reducing surfel resolution or capture distance to lower the size of the "
1081 "allocation.",
1082 probe_object.id.name,
1083 req_mb,
1084 max_mb);
1085 }
1086
1087 if (G.background) {
1088 /* Print something in background mode instead of failing silently. */
1089 fprintf(stderr, "%s", inst_.info_get());
1090 }
1091
1092 do_break_ = true;
1093 return;
1094 }
1095 }
1096
1097 surfels_buf_.resize(capture_info_buf_.surfel_len);
1098 surfels_buf_.clear_to_zero();
1099
1100 dispatch_per_surfel_.x = divide_ceil_u(surfels_buf_.size(), SURFEL_GROUP_SIZE);
1101
1102 DRW_stats_group_start("IrradianceBake.SurfelsCreate");
1103
1104 /* Raster the scene to generate the surfels. */
1105 capture_info_buf_.do_surfel_count = true;
1106 capture_info_buf_.do_surfel_output = true;
1107 capture_info_buf_.surfel_len = 0u;
1108 capture_info_buf_.push_update();
1109
1110 empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_x_), grid_pixel_extent_).xy()));
1111 inst_.pipelines.capture.render(view_x_);
1112 empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_y_), grid_pixel_extent_).xy()));
1113 inst_.pipelines.capture.render(view_y_);
1114 empty_raster_fb_.ensure(math::abs(transform_point(invert(basis_z_), grid_pixel_extent_).xy()));
1115 inst_.pipelines.capture.render(view_z_);
1116
1117 /* Sync with any other following pass using the surfel buffer. */
1119 /* Read back so that following push_update will contain correct surfel count. */
1120 capture_info_buf_.read();
1121
1123}
1124
1125void IrradianceBake::surfels_lights_eval()
1126{
1127 /* Use the last setup view. This should work since the view is orthographic. */
1128 /* TODO(fclem): Remove this. It is only present to avoid crash inside `shadows.set_view` */
1129 inst_.render_buffers.acquire(int2(1));
1130 inst_.hiz_buffer.set_source(&inst_.render_buffers.depth_tx);
1131 inst_.lights.set_view(view_z_, grid_pixel_extent_.xy());
1132 inst_.shadows.set_view(view_z_, grid_pixel_extent_.xy());
1133 inst_.render_buffers.release();
1134
1135 inst_.manager->submit(surfel_light_eval_ps_, view_z_);
1136}
1137
1138void IrradianceBake::clusters_build()
1139{
1140 if (max_virtual_offset_ == 0.0f) {
1141 return;
1142 }
1145
1146 cluster_list_tx_.ensure_3d(GPU_R32I, capture_info_buf_.irradiance_grid_size, texture_usage);
1147 cluster_list_tx_.clear(int4(-1));
1148 /* View is not important here. It is only for validation. */
1149 inst_.manager->submit(surfel_cluster_build_ps_, view_z_);
1150}
1151
1152void IrradianceBake::irradiance_offset()
1153{
1154 if (max_virtual_offset_ == 0.0f) {
1155 /* NOTE: Virtual offset texture should already have been cleared to 0. */
1156 return;
1157 }
1158
1159 inst_.manager->submit(irradiance_offset_ps_, view_z_);
1160
1161 /* Not needed after this point. */
1162 cluster_list_tx_.free();
1163}
1164
1165void IrradianceBake::raylists_build()
1166{
1167 using namespace blender::math;
1168
1169 float2 rand_uv = inst_.sampling.rng_2d_get(eSamplingDimension::SAMPLING_LENS_U);
1170 const float3 ray_direction = inst_.sampling.sample_sphere(rand_uv);
1171 const float3 up = ray_direction;
1172 const float3 forward = cross(up, normalize(orthogonal(up)));
1173 const float4x4 viewinv = from_orthonormal_axes<float4x4>(float3(0.0f), forward, up);
1174 const float4x4 viewmat = invert(viewinv);
1175
1176 /* Compute projection bounds. */
1177 float2 min, max;
1178 min = max = transform_point(viewmat, scene_bound_sphere_.xyz()).xy();
1179 min -= scene_bound_sphere_.w;
1180 max += scene_bound_sphere_.w;
1181
1182 /* This avoid light leaking by making sure that for one surface there will always be at least 1
1183 * surfel capture inside a ray list. Since the surface with the maximum distance (after
1184 * projection) between adjacent surfels is a slope that goes through 3 corners of a cube,
1185 * the distance the grid needs to cover is the diagonal of a cube face.
1186 *
1187 * The lower the number the more surfels it clumps together in the same surfel-list.
1188 * Biasing the grid_density like that will create many invalid link between coplanar surfels.
1189 * These are dealt with during the list sorting pass.
1190 *
1191 * This has a side effect of inflating shadows and emissive surfaces.
1192 *
1193 * We add an extra epsilon just in case. We really need this step to be leak free. */
1194 const float max_distance_between_neighbor_surfels_inv = M_SQRT1_2 - 1e-4;
1195 /* Surfel list per unit distance. */
1196 const float ray_grid_density = surfel_density_ * max_distance_between_neighbor_surfels_inv;
1197 /* Surfel list size in unit distance. */
1198 const float pixel_size = 1.0f / ray_grid_density;
1199 list_info_buf_.ray_grid_size = math::max(int2(1), int2(ray_grid_density * (max - min)));
1200
1201 /* Add a 2 pixels margin to have empty lists for irradiance grid samples to fall into (as they
1202 * are not considered by the scene bounds). The first pixel margin is because we are jittering
1203 * the grid position. */
1204 list_info_buf_.ray_grid_size += int2(4);
1205 min -= pixel_size * 2.0f;
1206 max += pixel_size * 2.0f;
1207
1208 /* Randomize grid center to avoid uneven inflating of corners in some directions. */
1209 const float2 aa_rand = inst_.sampling.rng_2d_get(eSamplingDimension::SAMPLING_FILTER_U);
1210 /* Offset in surfel list "pixel". */
1211 const float2 aa_offset = (aa_rand - 0.5f) * 0.499f;
1212 min += pixel_size * aa_offset;
1213
1214 list_info_buf_.list_max = list_info_buf_.ray_grid_size.x * list_info_buf_.ray_grid_size.y;
1215 list_info_buf_.push_update();
1216
1217 /* NOTE: Z values do not really matter since we are not doing any rasterization. */
1218 const float4x4 winmat = projection::orthographic<float>(min.x, max.x, min.y, max.y, 0, 1);
1219
1220 ray_view_.sync(viewmat, winmat);
1221
1222 dispatch_per_list_.x = divide_ceil_u(list_info_buf_.list_max, SURFEL_LIST_GROUP_SIZE);
1223
1224 list_start_buf_.resize(ceil_to_multiple_u(list_info_buf_.list_max, 4));
1225
1226 GPU_storagebuf_clear(list_start_buf_, -1);
1227 inst_.manager->submit(surfel_ray_build_ps_, ray_view_);
1228}
1229
1230void IrradianceBake::propagate_light()
1231{
1232 /* NOTE: Subtract 1 because after `sampling.step()`. */
1233 capture_info_buf_.sample_index = inst_.sampling.sample_index() - 1;
1234 capture_info_buf_.sample_count = inst_.sampling.sample_count();
1235 capture_info_buf_.push_update();
1236
1237 inst_.manager->submit(surfel_light_propagate_ps_, ray_view_);
1238
1239 std::swap(radiance_src_, radiance_dst_);
1240}
1241
1242void IrradianceBake::irradiance_capture()
1243{
1244 inst_.manager->submit(irradiance_capture_ps_, ray_view_);
1245}
1246
1247void IrradianceBake::read_surfels(LightProbeGridCacheFrame *cache_frame)
1248{
1249 if (!ELEM(inst_.debug_mode,
1250 eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_CLUSTER,
1251 eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_NORMAL,
1252 eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE,
1253 eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS_VISIBILITY))
1254 {
1255 return;
1256 }
1257
1259 capture_info_buf_.read();
1260 surfels_buf_.read();
1261
1262 cache_frame->surfels_len = capture_info_buf_.surfel_len;
1263 cache_frame->surfels = MEM_malloc_arrayN(cache_frame->surfels_len, sizeof(Surfel), __func__);
1264
1265 MutableSpan<Surfel> surfels_dst((Surfel *)cache_frame->surfels, cache_frame->surfels_len);
1266 Span<Surfel> surfels_src(surfels_buf_.data(), cache_frame->surfels_len);
1267 surfels_dst.copy_from(surfels_src);
1268}
1269
1270void IrradianceBake::read_virtual_offset(LightProbeGridCacheFrame *cache_frame)
1271{
1272 if (!ELEM(inst_.debug_mode, eDebugMode::DEBUG_IRRADIANCE_CACHE_VIRTUAL_OFFSET)) {
1273 return;
1274 }
1275
1277
1278 cache_frame->baking.virtual_offset = (float(*)[4])virtual_offset_tx_.read<float4>(
1280}
1281
1282LightProbeGridCacheFrame *IrradianceBake::read_result_unpacked()
1283{
1285
1286 read_surfels(cache_frame);
1287 read_virtual_offset(cache_frame);
1288
1289 cache_frame->size[0] = irradiance_L0_tx_.width();
1290 cache_frame->size[1] = irradiance_L0_tx_.height();
1291 cache_frame->size[2] = irradiance_L0_tx_.depth();
1292
1294
1295 cache_frame->baking.L0 = (float(*)[4])irradiance_L0_tx_.read<float4>(GPU_DATA_FLOAT);
1296 cache_frame->baking.L1_a = (float(*)[4])irradiance_L1_a_tx_.read<float4>(GPU_DATA_FLOAT);
1297 cache_frame->baking.L1_b = (float(*)[4])irradiance_L1_b_tx_.read<float4>(GPU_DATA_FLOAT);
1298 cache_frame->baking.L1_c = (float(*)[4])irradiance_L1_c_tx_.read<float4>(GPU_DATA_FLOAT);
1299 cache_frame->baking.validity = (float *)validity_tx_.read<float>(GPU_DATA_FLOAT);
1300
1301 return cache_frame;
1302}
1303
1304LightProbeGridCacheFrame *IrradianceBake::read_result_packed()
1305{
1307
1308 read_surfels(cache_frame);
1309 read_virtual_offset(cache_frame);
1310
1311 cache_frame->size[0] = irradiance_L0_tx_.width();
1312 cache_frame->size[1] = irradiance_L0_tx_.height();
1313 cache_frame->size[2] = irradiance_L0_tx_.depth();
1314
1316
1317 cache_frame->baking.L0 = (float(*)[4])irradiance_L0_tx_.read<float4>(GPU_DATA_FLOAT);
1318 cache_frame->baking.L1_a = (float(*)[4])irradiance_L1_a_tx_.read<float4>(GPU_DATA_FLOAT);
1319 cache_frame->baking.L1_b = (float(*)[4])irradiance_L1_b_tx_.read<float4>(GPU_DATA_FLOAT);
1320 cache_frame->baking.L1_c = (float(*)[4])irradiance_L1_c_tx_.read<float4>(GPU_DATA_FLOAT);
1321 cache_frame->baking.validity = (float *)validity_tx_.read<float>(GPU_DATA_FLOAT);
1322
1323 int64_t sample_count = int64_t(irradiance_L0_tx_.width()) * irradiance_L0_tx_.height() *
1324 irradiance_L0_tx_.depth();
1325 size_t coefficient_texture_size = sizeof(*cache_frame->irradiance.L0) * sample_count;
1326 size_t validity_texture_size = sizeof(*cache_frame->connectivity.validity) * sample_count;
1327 cache_frame->irradiance.L0 = (float(*)[3])MEM_mallocN(coefficient_texture_size, __func__);
1328 cache_frame->irradiance.L1_a = (float(*)[3])MEM_mallocN(coefficient_texture_size, __func__);
1329 cache_frame->irradiance.L1_b = (float(*)[3])MEM_mallocN(coefficient_texture_size, __func__);
1330 cache_frame->irradiance.L1_c = (float(*)[3])MEM_mallocN(coefficient_texture_size, __func__);
1331 cache_frame->connectivity.validity = (uint8_t *)MEM_mallocN(validity_texture_size, __func__);
1332
1333 size_t visibility_texture_size = sizeof(*cache_frame->irradiance.L0) * sample_count;
1334 cache_frame->visibility.L0 = (float *)MEM_mallocN(visibility_texture_size, __func__);
1335 cache_frame->visibility.L1_a = (float *)MEM_mallocN(visibility_texture_size, __func__);
1336 cache_frame->visibility.L1_b = (float *)MEM_mallocN(visibility_texture_size, __func__);
1337 cache_frame->visibility.L1_c = (float *)MEM_mallocN(visibility_texture_size, __func__);
1338
1339 /* TODO(fclem): This could be done on GPU if that's faster. */
1340 for (auto i : IndexRange(sample_count)) {
1341 copy_v3_v3(cache_frame->irradiance.L0[i], cache_frame->baking.L0[i]);
1342 copy_v3_v3(cache_frame->irradiance.L1_a[i], cache_frame->baking.L1_a[i]);
1343 copy_v3_v3(cache_frame->irradiance.L1_b[i], cache_frame->baking.L1_b[i]);
1344 copy_v3_v3(cache_frame->irradiance.L1_c[i], cache_frame->baking.L1_c[i]);
1345
1346 cache_frame->visibility.L0[i] = cache_frame->baking.L0[i][3];
1347 cache_frame->visibility.L1_a[i] = cache_frame->baking.L1_a[i][3];
1348 cache_frame->visibility.L1_b[i] = cache_frame->baking.L1_b[i][3];
1349 cache_frame->visibility.L1_c[i] = cache_frame->baking.L1_c[i][3];
1351 cache_frame->baking.validity[i]);
1352 }
1353
1354 MEM_SAFE_FREE(cache_frame->baking.L0);
1355 MEM_SAFE_FREE(cache_frame->baking.L1_a);
1356 MEM_SAFE_FREE(cache_frame->baking.L1_b);
1357 MEM_SAFE_FREE(cache_frame->baking.L1_c);
1358 MEM_SAFE_FREE(cache_frame->baking.validity);
1359
1360 return cache_frame;
1361}
1362
1365} // namespace blender::eevee
General operations for probes.
struct LightProbeGridCacheFrame * BKE_lightprobe_grid_cache_frame_create(void)
int64_t BKE_lightprobe_grid_cache_frame_sample_count(const struct LightProbeGridCacheFrame *cache)
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE uint ceil_to_multiple_u(uint a, uint b)
MINLINE uint divide_ceil_u(uint a, uint b)
#define M_SQRT1_2
MINLINE void copy_v3_v3(float r[3], const float a[3])
unsigned int uint
#define UNPACK3(a)
#define ELEM(...)
@ LIGHTPROBE_GRID_CAPTURE_EMISSION
@ LIGHTPROBE_GRID_CAPTURE_WORLD
@ LIGHTPROBE_GRID_CAPTURE_INDIRECT
static AppView * view
void GPU_mem_stats_get(int *r_totalmem, int *r_freemem)
bool GPU_mem_stats_supported()
size_t GPU_max_storage_buffer_size()
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_PRIM_TRI_STRIP
@ GPU_PRIM_TRIS
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:374
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
@ GPU_BARRIER_TEXTURE_FETCH
Definition GPU_state.hh:37
@ GPU_BARRIER_BUFFER_UPDATE
Definition GPU_state.hh:56
@ GPU_BARRIER_SHADER_IMAGE_ACCESS
Definition GPU_state.hh:35
@ GPU_BARRIER_TEXTURE_UPDATE
Definition GPU_state.hh:39
void GPU_storagebuf_clear(GPUStorageBuf *ssbo, uint32_t clear_value)
@ GPU_DATA_UBYTE
@ GPU_DATA_FLOAT
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_SHADER_WRITE
@ GPU_TEXTURE_USAGE_HOST_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
@ GPU_TEXTURE_USAGE_ATOMIC
void GPU_texture_update_sub(GPUTexture *texture, eGPUDataFormat data_format, const void *pixels, int offset_x, int offset_y, int offset_z, int width, int height, int depth)
@ GPU_R32I
@ GPU_R8
@ GPU_RGB16F
void GPU_texture_swizzle_set(GPUTexture *texture, const char swizzle[4])
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
int64_t size() const
void append(const T &value)
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
void extend(Span< T > array)
Span< T > as_span() const
SwapChain< ObjectBoundsBuf, 2 > bounds_buf
uint resource_handle_count() const
void extend(const Span< T > values)
void clear(float4 values)
bool ensure_3d(eGPUTextureFormat format, int3 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
void bind_resources(U &resources)
Definition draw_pass.hh:426
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 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
void info_append_i18n(const char *msg, Args &&...args)
LightProbeModule light_probes
Vector< IrradianceBrickPacked > bricks_alloc(int brick_len)
void bricks_free(Vector< IrradianceBrickPacked > &bricks)
local_group_size(16, 16) .push_constant(Type b
additional_info("compositor_sum_float_shared") .push_constant(Type additional_info("compositor_sum_float_shared") .push_constant(Type GPU_RGBA32F
#define printf
bool DRW_state_draw_support()
void DRW_stats_group_start(const char *name)
void DRW_stats_group_end()
@ 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_CULL_BACK
Definition draw_state.hh:43
#define SURFEL_GROUP_SIZE
#define IRRADIANCE_BOUNDS_GROUP_SIZE
#define RBUFS_UTILITY_TEX_SLOT
#define CAPTURE_BUF_SLOT
#define SURFEL_LIST_GROUP_SIZE
#define IRRADIANCE_GRID_MAX
#define IRRADIANCE_GRID_BRICK_SIZE
#define IRRADIANCE_GRID_GROUP_SIZE
#define VOLUME_PROBE_FORMAT
#define SURFEL_BUF_SLOT
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
BLI_INLINE void grid_to_world(HairGrid *grid, float vecw[3], const float vec[3])
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition invert.h:9
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
#define unit_float_to_uchar_clamp(val)
ccl_device_inline float cross(const float2 a, const float2 b)
#define G(x, y, z)
static IrradianceBrickPacked irradiance_brick_pack(IrradianceBrick brick)
MatBase< T, NumCol, NumRow > transpose(const MatBase< T, NumRow, NumCol > &mat)
T reduce_max(const VecBase< T, Size > &a)
VecBase< T, Size > divide_ceil(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T reduce_min(const VecBase< T, Size > &a)
CartesianBasis invert(const CartesianBasis &basis)
T midpoint(const T &a, const T &b)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
T reduce_mul(const VecBase< T, Size > &a)
VecBase< T, 3 > to_scale(const MatBase< T, NumCol, NumRow > &mat)
T max(const T &a, const T &b)
T abs(const T &a)
MatT from_location(const typename MatT::loc_type &location)
void to_loc_rot_scale(const MatBase< T, 3, 3 > &mat, VecBase< T, 2 > &r_location, AngleRadianBase< T > &r_rotation, VecBase< T, 2 > &r_scale)
VecBase< uint32_t, 2 > uint2
VecBase< int32_t, 4 > int4
bool assign_if_different(T &old_value, T new_value)
MatBase< float, 4, 4 > float4x4
MatBase< float, 3, 4 > float3x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
float distance(float a, float b)
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
__int64 int64_t
Definition stdint.h:89
signed int int32_t
Definition stdint.h:77
unsigned char uint8_t
Definition stdint.h:78
char name[66]
Definition DNA_ID.h:425
LightProbeVisibilityData visibility
LightProbeConnectivityData connectivity
LightProbeIrradianceData irradiance
int gi_irradiance_pool_size
struct SceneEEVEE eevee
VecBase< T, 2 > xy() const
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
Definition transform.h:63
float max
int xy[2]
Definition wm_draw.cc:170