Blender V4.3
eevee_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
7#include "BKE_context.hh"
8#include "BKE_idtype.hh"
9#include "BKE_main.hh"
10#include "BKE_node.hh"
11#include "BKE_object.hh"
12
13#include "BLI_vector.hh"
14
15#include "RNA_define.hh"
16
17#include "GPU_batch.hh"
18#include "draw_shader.hh"
19#include "draw_testing.hh"
22
23namespace blender::draw {
24
25using namespace blender::eevee;
26
27/* Replace with template version that is not GPU only. */
30
32{
34 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
35 ShadowTileDataBuf tiles_data = {"tiles_data"};
36 ShadowTileMapClipBuf tilemaps_clip = {"tilemaps_clip"};
37 ShadowPageCacheBuf pages_cached_data_ = {"pages_cached_data_"};
38
39 int tiles_index = 1;
40 int tile_lod0 = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 5;
41 int tile_lod1 = tile_lod0 + square_i(SHADOW_TILEMAP_RES);
42
43 {
44 ShadowTileMapData tilemap = {};
45 tilemap.tiles_index = tiles_index * SHADOW_TILEDATA_PER_TILEMAP;
48
49 tilemaps_data.append(tilemap);
50
51 tilemaps_data.push_update();
52 }
53 {
55
56 tile.page = uint3(1, 2, 0);
57 tile.is_used = true;
58 tile.do_update = true;
59 tiles_data[tile_lod0] = shadow_tile_pack(tile);
60
61 tile.page = uint3(3, 2, 4);
62 tile.is_used = false;
63 tile.do_update = false;
64 tiles_data[tile_lod1] = shadow_tile_pack(tile);
65
66 tiles_data.push_update();
67 }
68
69 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tilemap_init");
70
71 PassSimple pass("Test");
72 pass.shader_set(sh);
73 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
74 pass.bind_ssbo("tilemaps_clip_buf", tilemaps_clip);
75 pass.bind_ssbo("tiles_buf", tiles_data);
76 pass.bind_ssbo("pages_cached_buf", pages_cached_data_);
77 pass.dispatch(int3(1, 1, tilemaps_data.size()));
78 pass.barrier(GPU_BARRIER_BUFFER_UPDATE);
79
80 Manager manager;
81 manager.submit(pass);
82
83 tilemaps_data.read();
84 tiles_data.read();
85
86 EXPECT_EQ(tilemaps_data[0].grid_offset, int2(0));
87 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod0]).page, uint3(1, 2, 0));
88 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod0]).is_used, false);
89 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod0]).do_update, true);
90 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod1]).page, uint3(3, 2, 4));
91 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod1]).is_used, false);
92 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod1]).do_update, true);
93
97}
98DRAW_TEST(eevee_shadow_shift_clear)
99
101{
103 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
104 ShadowTileDataBuf tiles_data = {"tiles_data"};
105 StorageArrayBuffer<ShadowTileMapClip, SHADOW_MAX_TILEMAP> tilemaps_clip = {"tilemaps_clip"};
106 ShadowPageCacheBuf pages_cached_data = {"pages_cached_data"};
107
108 auto tile_co_to_page = [](int2 co) {
109 int page = co.x + co.y * SHADOW_TILEMAP_RES;
110 return uint3((page % SHADOW_PAGE_PER_ROW),
112 (page / SHADOW_PAGE_PER_LAYER));
113 };
114
115 {
116 ShadowTileMapClip clip = {};
117 clip.clip_near_stored = 0.0;
118 clip.clip_far_stored = 1.0;
119 clip.clip_near = 0x00000000; /* floatBitsToOrderedInt(0.0) */
120 clip.clip_far = 0x3F800000; /* floatBitsToOrderedInt(1.0) */
121
122 tilemaps_clip[0] = clip;
123
124 tilemaps_clip.push_update();
125 }
126 {
127 ShadowTileMapData tilemap = {};
128 tilemap.tiles_index = 0;
129 tilemap.clip_data_index = 0;
130 tilemap.grid_shift = int2(-1, 2);
132
133 tilemaps_data.append(tilemap);
134
135 tilemaps_data.push_update();
136 }
137 {
138 ShadowTileData tile = {};
139
140 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
141 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
142 tile.is_allocated = true;
143 tile.is_rendered = true;
144 tile.do_update = true;
145 tile.page = tile_co_to_page(int2(x, y));
146 tiles_data[x + y * SHADOW_TILEMAP_RES] = shadow_tile_pack(tile);
147 }
148 }
149
150 tiles_data.push_update();
151 }
152
153 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tilemap_init");
154
155 PassSimple pass("Test");
156 pass.shader_set(sh);
157 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
158 pass.bind_ssbo("tilemaps_clip_buf", tilemaps_clip);
159 pass.bind_ssbo("tiles_buf", tiles_data);
160 pass.bind_ssbo("pages_cached_buf", pages_cached_data);
161 pass.dispatch(int3(1, 1, tilemaps_data.size()));
162 pass.barrier(GPU_BARRIER_BUFFER_UPDATE);
163
164 Manager manager;
165 manager.submit(pass);
166
167 tilemaps_data.read();
168 tiles_data.read();
169
170 EXPECT_EQ(tilemaps_data[0].grid_offset, int2(0));
171 EXPECT_EQ(shadow_tile_unpack(tiles_data[0]).page,
172 tile_co_to_page(int2(SHADOW_TILEMAP_RES - 1, 2)));
173 EXPECT_EQ(shadow_tile_unpack(tiles_data[0]).do_update, true);
174 EXPECT_EQ(shadow_tile_unpack(tiles_data[0]).is_rendered, false);
175 EXPECT_EQ(shadow_tile_unpack(tiles_data[0]).is_allocated, true);
176 EXPECT_EQ(shadow_tile_unpack(tiles_data[1]).page, tile_co_to_page(int2(0, 2)));
177 EXPECT_EQ(shadow_tile_unpack(tiles_data[1]).do_update, false);
178 EXPECT_EQ(shadow_tile_unpack(tiles_data[1]).is_rendered, false);
179 EXPECT_EQ(shadow_tile_unpack(tiles_data[1]).is_allocated, true);
180 EXPECT_EQ(shadow_tile_unpack(tiles_data[0 + SHADOW_TILEMAP_RES * 2]).page,
181 tile_co_to_page(int2(SHADOW_TILEMAP_RES - 1, 4)));
182 EXPECT_EQ(shadow_tile_unpack(tiles_data[0 + SHADOW_TILEMAP_RES * 2]).do_update, true);
183 EXPECT_EQ(shadow_tile_unpack(tiles_data[0 + SHADOW_TILEMAP_RES * 2]).is_rendered, false);
184 EXPECT_EQ(shadow_tile_unpack(tiles_data[0 + SHADOW_TILEMAP_RES * 2]).is_allocated, true);
185 EXPECT_EQ(shadow_tile_unpack(tiles_data[1 + SHADOW_TILEMAP_RES * 2]).page,
186 tile_co_to_page(int2(0, 4)));
187 EXPECT_EQ(shadow_tile_unpack(tiles_data[1 + SHADOW_TILEMAP_RES * 2]).do_update, false);
188 EXPECT_EQ(shadow_tile_unpack(tiles_data[1 + SHADOW_TILEMAP_RES * 2]).is_rendered, false);
189 EXPECT_EQ(shadow_tile_unpack(tiles_data[1 + SHADOW_TILEMAP_RES * 2]).is_allocated, true);
190
191 GPU_shader_free(sh);
194}
195DRAW_TEST(eevee_shadow_shift)
196
198{
200 using namespace blender::math;
201 StorageVectorBuffer<uint, 128> past_casters_updated = {"PastCastersUpdated"};
202 StorageVectorBuffer<uint, 128> curr_casters_updated = {"CurrCastersUpdated"};
203
204 Manager manager;
205 {
206 /* Simulate 1 object moving and 1 object static with changing resource index. */
209 float3(1.0f), Quaternion::identity(), float3(0.5f));
210 float3 half_extent = float3(0.24f, 0.249f, 0.001f);
211
212 {
213 manager.begin_sync();
214 ResourceHandle hdl = manager.resource_handle(obmat, float3(0.5f, 0.5f, -1.0f), half_extent);
215 manager.resource_handle(obmat2);
216 manager.end_sync();
217 past_casters_updated.append(hdl.resource_index());
218 past_casters_updated.push_update();
219 }
220 {
221 manager.begin_sync();
222 manager.resource_handle(obmat2);
223 ResourceHandle hdl = manager.resource_handle(obmat, float3(-1.0f, 0.5f, -1.0f), half_extent);
224 manager.end_sync();
225 curr_casters_updated.append(hdl.resource_index());
226 curr_casters_updated.push_update();
227 }
228 }
229
230 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
231 ShadowTileDataBuf tiles_data = {"tiles_data"};
232 tiles_data.clear_to_zero();
233
234 {
237 tilemaps_data.append(tilemap);
238 }
239 {
242 tilemaps_data.append(tilemap);
243 }
244
245 tilemaps_data.push_update();
246
247 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tag_update");
248
249 PassSimple pass("Test");
250 pass.shader_set(sh);
251 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
252 pass.bind_ssbo("tiles_buf", tiles_data);
253 pass.bind_ssbo("bounds_buf", &manager.bounds_buf.previous());
254 pass.bind_ssbo("resource_ids_buf", past_casters_updated);
255 pass.dispatch(int3(past_casters_updated.size(), 1, tilemaps_data.size()));
256 pass.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
257 pass.bind_ssbo("resource_ids_buf", curr_casters_updated);
258 pass.dispatch(int3(curr_casters_updated.size(), 1, tilemaps_data.size()));
259 pass.barrier(GPU_BARRIER_BUFFER_UPDATE);
260
261 manager.submit(pass);
262
263 tiles_data.read();
264
266 StringRefNull expected_lod0 =
267 "--------------------------------"
268 "--------------------------------"
269 "--------------------------------"
270 "--------------------------------"
271 "--------------------------------"
272 "--------------------------------"
273 "--------------------------------"
274 "--------------------------------"
275 "--------------------------------"
276 "--------------------------------"
277 "--------------------------------"
278 "--------------------------------"
279 "--------------------------------"
280 "--------------------------------"
281 "--------------------------------"
282 "--------------------------------"
283 "--------------------------------"
284 "--------------------------------"
285 "--------------------------------"
286 "--------------------------------"
287 "xxxx----------------xxxxxxxx----"
288 "xxxx----------------xxxxxxxx----"
289 "xxxx----------------xxxxxxxx----"
290 "xxxx----------------xxxxxxxx----"
291 "xxxx----------------xxxxxxxx----"
292 "xxxx----------------xxxxxxxx----"
293 "xxxx----------------xxxxxxxx----"
294 "xxxx----------------xxxxxxxx----"
295 "--------------------------------"
296 "--------------------------------"
297 "--------------------------------"
298 "--------------------------------";
299 StringRefNull expected_lod1 =
300 "----------------"
301 "----------------"
302 "----------------"
303 "----------------"
304 "----------------"
305 "----------------"
306 "----------------"
307 "----------------"
308 "----------------"
309 "----------------"
310 "xx--------xxxx--"
311 "xx--------xxxx--"
312 "xx--------xxxx--"
313 "xx--------xxxx--"
314 "----------------"
315 "----------------";
316 StringRefNull expected_lod2 =
317 "--------"
318 "--------"
319 "--------"
320 "--------"
321 "--------"
322 "x----xx-"
323 "x----xx-"
324 "--------";
325 StringRefNull expected_lod3 =
326 "----"
327 "----"
328 "x-xx"
329 "x-xx";
330 StringRefNull expected_lod4 =
331 "--"
332 "xx";
333 StringRefNull expected_lod5 = "x";
334 const uint lod0_len = SHADOW_TILEMAP_LOD0_LEN;
335 const uint lod1_len = SHADOW_TILEMAP_LOD1_LEN;
336 const uint lod2_len = SHADOW_TILEMAP_LOD2_LEN;
337 const uint lod3_len = SHADOW_TILEMAP_LOD3_LEN;
338 const uint lod4_len = SHADOW_TILEMAP_LOD4_LEN;
339 const uint lod5_len = SHADOW_TILEMAP_LOD5_LEN;
340
341 auto stringify_result = [&](uint start, uint len) -> std::string {
342 std::string result = "";
343 for (auto i : IndexRange(start, len)) {
344 result += (shadow_tile_unpack(tiles_data[i]).do_update) ? "x" : "-";
345 }
346 return result;
347 };
348
349 EXPECT_EQ(stringify_result(0, lod0_len), expected_lod0);
350 EXPECT_EQ(stringify_result(lod0_len, lod1_len), expected_lod1);
351 EXPECT_EQ(stringify_result(lod0_len + lod1_len, lod2_len), expected_lod2);
352 EXPECT_EQ(stringify_result(lod0_len + lod1_len + lod2_len, lod3_len), expected_lod3);
353 EXPECT_EQ(stringify_result(lod0_len + lod1_len + lod2_len + lod3_len, lod4_len), expected_lod4);
354 EXPECT_EQ(stringify_result(lod0_len + lod1_len + lod2_len + lod3_len + lod4_len, lod5_len),
355 expected_lod5);
356
357 GPU_shader_free(sh);
360}
361DRAW_TEST(eevee_shadow_tag_update)
362
364{
366 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
367 ShadowTileDataBuf tiles_data = {"tiles_data"};
368 ShadowPageHeapBuf pages_free_data = {"PagesFreeBuf"};
369 ShadowPageCacheBuf pages_cached_data = {"PagesCachedBuf"};
370 ShadowPagesInfoDataBuf pages_infos_data = {"PagesInfosBuf"};
371
372 int tiles_index = 1;
373 int tile_orphaned_cached = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 5;
374 int tile_orphaned_allocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 6;
375 int tile_used_cached = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 260;
376 int tile_used_allocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 32;
377 int tile_used_unallocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 64;
378 int tile_unused_cached = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 9;
379 int tile_unused_allocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 8;
380 int page_free_count = SHADOW_MAX_PAGE - 6;
381
382 for (uint i : IndexRange(2, page_free_count)) {
383 uint3 page = uint3((i % SHADOW_PAGE_PER_ROW),
386 pages_free_data[i] = shadow_page_pack(page);
387 }
388 pages_free_data.push_update();
389
390 pages_infos_data.page_free_count = page_free_count;
391 pages_infos_data.page_alloc_count = 0;
392 pages_infos_data.page_cached_next = 2u;
393 pages_infos_data.page_cached_start = 0u;
394 pages_infos_data.page_cached_end = 2u;
395 pages_infos_data.push_update();
396
397 for (uint i : IndexRange(pages_cached_data.size())) {
398 pages_cached_data[i] = uint2(-1, -1);
399 }
400 pages_cached_data[0] = uint2(0, tile_orphaned_cached);
401 pages_cached_data[1] = uint2(1, tile_used_cached);
402 pages_cached_data.push_update();
403
404 {
405 ShadowTileData tile = {};
406
407 tiles_data.clear_to_zero();
408 tiles_data.read();
409
410 /* is_orphaned = true */
411 tile.is_used = false;
412 tile.do_update = true;
413
414 tile.is_cached = true;
415 tile.is_allocated = false;
416 tiles_data[tile_orphaned_cached] = shadow_tile_pack(tile);
417
418 tile.is_cached = false;
419 tile.is_allocated = true;
420 tiles_data[tile_orphaned_allocated] = shadow_tile_pack(tile);
421
422 /* is_orphaned = false */
423 tile.do_update = false;
424 tile.is_used = true;
425
426 tile.is_cached = true;
427 tile.is_allocated = false;
428 tiles_data[tile_used_cached] = shadow_tile_pack(tile);
429
430 tile.is_cached = false;
431 tile.is_allocated = true;
432 tiles_data[tile_used_allocated] = shadow_tile_pack(tile);
433
434 tile.is_cached = false;
435 tile.is_allocated = false;
436 tiles_data[tile_used_unallocated] = shadow_tile_pack(tile);
437
438 tile.is_used = false;
439 tile.is_cached = true;
440 tile.is_allocated = false;
441 tiles_data[tile_unused_cached] = shadow_tile_pack(tile);
442
443 tile.is_cached = false;
444 tile.is_allocated = true;
445 tiles_data[tile_unused_allocated] = shadow_tile_pack(tile);
446
447 tiles_data.push_update();
448 }
449 {
450 ShadowTileMapData tilemap = {};
451 tilemap.tiles_index = tiles_index * SHADOW_TILEDATA_PER_TILEMAP;
452 tilemaps_data.append(tilemap);
453 tilemaps_data.push_update();
454 }
455
456 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_page_free");
457
458 PassSimple pass("Test");
459 pass.shader_set(sh);
460 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
461 pass.bind_ssbo("tiles_buf", tiles_data);
462 pass.bind_ssbo("pages_infos_buf", pages_infos_data);
463 pass.bind_ssbo("pages_free_buf", pages_free_data);
464 pass.bind_ssbo("pages_cached_buf", pages_cached_data);
465 pass.dispatch(int3(1, 1, tilemaps_data.size()));
466 pass.barrier(GPU_BARRIER_BUFFER_UPDATE);
467
468 Manager manager;
469 manager.submit(pass);
470
471 tiles_data.read();
472 pages_infos_data.read();
473
474 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_orphaned_cached]).is_cached, false);
475 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_orphaned_cached]).is_allocated, false);
476 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_orphaned_allocated]).is_cached, false);
477 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_orphaned_allocated]).is_allocated, false);
478 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_cached]).is_cached, false);
479 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_cached]).is_allocated, true);
480 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_allocated]).is_cached, false);
481 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_allocated]).is_allocated, true);
482 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_unallocated]).is_cached, false);
483 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_unallocated]).is_allocated, false);
484 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_unused_cached]).is_cached, true);
485 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_unused_cached]).is_allocated, false);
486 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_unused_allocated]).is_cached, true);
487 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_unused_allocated]).is_allocated, false);
488 EXPECT_EQ(pages_infos_data.page_alloc_count, 1);
489 EXPECT_EQ(pages_infos_data.page_free_count, page_free_count + 2);
490 EXPECT_EQ(pages_infos_data.page_cached_next, 3);
491 EXPECT_EQ(pages_infos_data.page_cached_end, 2);
492
493 GPU_shader_free(sh);
496}
497DRAW_TEST(eevee_shadow_free)
498
500 private:
501 ShadowTileDataBuf tiles_data = {"tiles_data"};
502 ShadowPageHeapBuf pages_free_data = {"PagesFreeBuf"};
503 ShadowPageCacheBuf pages_cached_data = {"PagesCachedBuf"};
504 ShadowPagesInfoDataBuf pages_infos_data = {"PagesInfosBuf"};
505 StorageBuffer<DispatchCommand> clear_dispatch_buf;
506 StorageBuffer<DrawCommand> tile_draw_buf;
507 ShadowStatisticsBuf statistics_buf = {"statistics_buf"};
508
509 public:
510 TestDefrag(int allocation_count,
511 int descriptor_offset,
513 StringRefNull expect)
514 {
515 for (uint i : IndexRange(SHADOW_MAX_PAGE)) {
517 pages_free_data[i] = page.x | (page.y << 16u);
518 }
519
520 for (uint i : IndexRange(tiles_data.size())) {
521 tiles_data[i] = 0;
522 }
523
524 int free_count = SHADOW_MAX_PAGE;
525 int tile_index = 0;
526
527 for (uint i : IndexRange(pages_cached_data.size())) {
528 pages_cached_data[i] = uint2(-1, -1);
529 }
530
531 int cached_index = descriptor_offset;
532 int hole_count = 0;
533 int inserted_count = 0;
534 ShadowTileData tile = {};
535 tile.is_cached = true;
536 for (char c : descriptor) {
537 switch (c) {
538 case 'c':
539 tile.cache_index = cached_index++ % SHADOW_MAX_PAGE;
540 pages_cached_data[tile.cache_index] = uint2(pages_free_data[--free_count], tile_index);
541 tiles_data[tile_index++] = shadow_tile_pack(tile);
542 break;
543 case 'f':
544 pages_cached_data[cached_index++ % SHADOW_MAX_PAGE] = uint2(-1, -1);
545 hole_count++;
546 break;
547 case 'i':
548 tile.cache_index = (cached_index + inserted_count++) % SHADOW_MAX_PAGE;
549 pages_cached_data[tile.cache_index] = uint2(pages_free_data[--free_count], tile_index);
550 tiles_data[tile_index++] = shadow_tile_pack(tile);
551 break;
552 default:
553 break;
554 }
555 }
556
557 pages_infos_data.page_alloc_count = allocation_count;
558 pages_infos_data.page_cached_next = cached_index + inserted_count;
559 pages_infos_data.page_free_count = free_count;
560 pages_infos_data.page_cached_start = descriptor_offset;
561 pages_infos_data.page_cached_end = cached_index;
562
563 tiles_data.push_update();
564 pages_infos_data.push_update();
565 pages_free_data.push_update();
566 pages_cached_data.push_update();
567
568 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_page_defrag");
569
570 PassSimple pass("Test");
571 pass.shader_set(sh);
572 pass.bind_ssbo("tiles_buf", tiles_data);
573 pass.bind_ssbo("pages_infos_buf", pages_infos_data);
574 pass.bind_ssbo("pages_free_buf", pages_free_data);
575 pass.bind_ssbo("pages_cached_buf", pages_cached_data);
576 pass.bind_ssbo("clear_dispatch_buf", clear_dispatch_buf);
577 pass.bind_ssbo("tile_draw_buf", tile_draw_buf);
578 pass.bind_ssbo("statistics_buf", statistics_buf);
579 pass.dispatch(int3(1, 1, 1));
580 pass.barrier(GPU_BARRIER_BUFFER_UPDATE);
581
582 Manager manager;
583 manager.submit(pass);
584
585 tiles_data.read();
586 pages_cached_data.read();
587 pages_infos_data.read();
588
589 std::string result = "";
590 int expect_cached_len = 0;
591 for (auto i : IndexRange(descriptor_offset, descriptor.size())) {
592 if (pages_cached_data[i % SHADOW_MAX_PAGE].y != -1) {
593 result += 'c';
594 expect_cached_len++;
595 }
596 else {
597 result += 'f';
598 }
599 }
600 EXPECT_EQ(expect, result);
601
602 allocation_count = min_ii(allocation_count, SHADOW_MAX_PAGE);
603
604 int additional_pages = max_ii(0, allocation_count - free_count);
605 int expected_free_count = max_ii(free_count, allocation_count);
606 int expected_start = descriptor_offset + hole_count + additional_pages;
607 int result_cached_len = pages_infos_data.page_cached_end - pages_infos_data.page_cached_start;
608
609 if (expected_start > SHADOW_MAX_PAGE) {
610 expected_start -= SHADOW_MAX_PAGE;
611 }
612
613 EXPECT_EQ(expected_free_count, pages_infos_data.page_free_count);
614 EXPECT_EQ(expected_start, pages_infos_data.page_cached_start);
615 EXPECT_EQ(expect_cached_len, result_cached_len);
616 EXPECT_EQ(pages_infos_data.page_cached_end, pages_infos_data.page_cached_next);
617
618 GPU_shader_free(sh);
620 }
621};
622
624{
625 TestDefrag(0, 0, "cfi", "fcc");
626 TestDefrag(0, 0, "fci", "fcc");
627 TestDefrag(0, 47, "ccfcffccfcfciiiii", "fffffcccccccccccc");
628 TestDefrag(10, SHADOW_MAX_PAGE - 5, "ccfcffccfcfciiiii", "fffffcccccccccccc");
629 TestDefrag(SHADOW_MAX_PAGE - 8, 30, "ccfcffccfcfciiiii", "fffffffffcccccccc");
630 TestDefrag(SHADOW_MAX_PAGE - 4, 30, "ccfcffccfcfciiiii", "fffffffffffffcccc");
631 /* Over allocation but should not crash. */
632 TestDefrag(SHADOW_MAX_PAGE + 4, 30, "ccfcffccfcfciiiii", "fffffffffffffffff");
633}
634DRAW_TEST(eevee_shadow_defrag)
635
637 private:
638 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
639 ShadowTileDataBuf tiles_data = {"tiles_data"};
640 ShadowPageHeapBuf pages_free_data = {"PagesFreeBuf"};
641 ShadowPageCacheBuf pages_cached_data = {"PagesCachedBuf"};
642 ShadowPagesInfoDataBuf pages_infos_data = {"PagesInfosBuf"};
643 ShadowStatisticsBuf statistics_buf = {"statistics_buf"};
644
645 public:
646 TestAlloc(int page_free_count)
647 {
649 int tiles_index = 1;
650
651 for (int i : IndexRange(SHADOW_MAX_TILE)) {
652 tiles_data[i] = 0;
653 }
654
655 for (uint i : IndexRange(0, page_free_count)) {
657 pages_free_data[i] = page.x | (page.y << 16u);
658 }
659 pages_free_data.push_update();
660 pages_cached_data.push_update();
661
662 pages_infos_data.page_free_count = page_free_count;
663 pages_infos_data.page_alloc_count = 1;
664 pages_infos_data.page_cached_next = 0u;
665 pages_infos_data.page_cached_start = 0u;
666 pages_infos_data.page_cached_end = 0u;
667 pages_infos_data.push_update();
668
669 statistics_buf.view_needed_count = 0;
670 statistics_buf.push_update();
671
672 int tile_allocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 5;
673 int tile_free = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 6;
674
675 {
676 ShadowTileData tile = {};
677
678 tile.is_used = true;
679 tile.do_update = false;
680
681 tile.is_cached = false;
682 tile.is_allocated = false;
683 tiles_data[tile_free] = shadow_tile_pack(tile);
684
685 tile.is_cached = false;
686 tile.is_allocated = true;
687 tiles_data[tile_allocated] = shadow_tile_pack(tile);
688
689 tiles_data.push_update();
690 }
691 {
692 ShadowTileMapData tilemap = {};
693 tilemap.tiles_index = tiles_index * SHADOW_TILEDATA_PER_TILEMAP;
694 tilemaps_data.append(tilemap);
695 tilemaps_data.push_update();
696 }
697
698 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_page_allocate");
699
700 PassSimple pass("Test");
701 pass.shader_set(sh);
702 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
703 pass.bind_ssbo("tiles_buf", tiles_data);
704 pass.bind_ssbo("pages_infos_buf", pages_infos_data);
705 pass.bind_ssbo("pages_free_buf", pages_free_data);
706 pass.bind_ssbo("pages_cached_buf", pages_cached_data);
707 pass.bind_ssbo("statistics_buf", statistics_buf);
708 pass.dispatch(int3(1, 1, tilemaps_data.size()));
709 pass.barrier(GPU_BARRIER_BUFFER_UPDATE);
710
711 Manager manager;
712 manager.submit(pass);
713
714 tiles_data.read();
715 pages_infos_data.read();
716
717 bool alloc_success = page_free_count >= 1;
718
719 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_free]).do_update, alloc_success);
720 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_free]).is_allocated, alloc_success);
721 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_allocated]).do_update, false);
722 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_allocated]).is_allocated, true);
723 EXPECT_EQ(pages_infos_data.page_free_count, page_free_count - 1);
724
725 GPU_shader_free(sh);
728 }
729};
730
732{
734 TestAlloc(1);
735 TestAlloc(0);
736}
737DRAW_TEST(eevee_shadow_alloc)
738
740{
742 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
743 ShadowTileDataBuf tiles_data = {"tiles_data"};
744 ShadowPageHeapBuf pages_free_data = {"PagesFreeBuf"};
745 ShadowPageCacheBuf pages_cached_data = {"PagesCachedBuf"};
746 ShadowPagesInfoDataBuf pages_infos_data = {"PagesInfosBuf"};
747 ShadowStatisticsBuf statistics_buf = {"statistics_buf"};
748 ShadowRenderViewBuf render_views_buf = {"render_views_buf"};
750 "tilemaps_clip"};
751
752 const uint lod0_len = SHADOW_TILEMAP_LOD0_LEN;
753 const uint lod1_len = SHADOW_TILEMAP_LOD1_LEN;
754 const uint lod2_len = SHADOW_TILEMAP_LOD2_LEN;
755 const uint lod3_len = SHADOW_TILEMAP_LOD3_LEN;
756 const uint lod4_len = SHADOW_TILEMAP_LOD4_LEN;
757
758 const uint lod0_ofs = 0;
759 const uint lod1_ofs = lod0_len;
760 const uint lod2_ofs = lod1_ofs + lod1_len;
761 const uint lod3_ofs = lod2_ofs + lod2_len;
762 const uint lod4_ofs = lod3_ofs + lod3_len;
763 const uint lod5_ofs = lod4_ofs + lod4_len;
764
766 tiles_data[i] = SHADOW_NO_DATA;
767 }
768
769 {
770 ShadowTileData tile = {};
771 tile.is_used = true;
772 tile.is_allocated = true;
773
774 tile.page = uint3(1, 0, 0);
775 tile.do_update = false;
776 tiles_data[lod0_ofs] = shadow_tile_pack(tile);
777
778 tile.page = uint3(2, 0, 0);
779 tile.do_update = false;
780 tiles_data[lod1_ofs] = shadow_tile_pack(tile);
781
782 tile.page = uint3(3, 0, 0);
783 tile.do_update = true;
784 tiles_data[lod2_ofs] = shadow_tile_pack(tile);
785
786 tile.page = uint3(0, 1, 0);
787 tile.do_update = true;
788 tiles_data[lod3_ofs] = shadow_tile_pack(tile);
789
790 tile.page = uint3(1, 1, 0);
791 tile.do_update = true;
792 tiles_data[lod4_ofs] = shadow_tile_pack(tile);
793
794 tile.page = uint3(2, 1, 0);
795 tile.do_update = true;
796 tiles_data[lod5_ofs] = shadow_tile_pack(tile);
797
798 tile.page = uint3(3, 1, 0);
799 tile.do_update = true;
800 tiles_data[lod0_ofs + 31] = shadow_tile_pack(tile);
801
802 tile.page = uint3(0, 2, 0);
803 tile.do_update = true;
804 tiles_data[lod3_ofs + 8] = shadow_tile_pack(tile);
805
806 tile.page = uint3(1, 2, 0);
807 tile.do_update = true;
808 tiles_data[lod0_ofs + 32 * 16 - 8] = shadow_tile_pack(tile);
809
810 tiles_data.push_update();
811 }
812 {
813 ShadowTileMapData tilemap = {};
814 tilemap.viewmat = float4x4::identity();
815 tilemap.tiles_index = 0;
816 tilemap.clip_data_index = 0;
817 tilemap.clip_far = 10.0f;
818 tilemap.clip_near = 1.0f;
819 tilemap.half_size = 1.0f;
821 tilemaps_data.append(tilemap);
822
823 tilemaps_data.push_update();
824 }
825 {
826 ShadowTileMapClip clip = {};
827 clip.clip_far_stored = 10.0f;
828 clip.clip_near_stored = 1.0f;
829 tilemaps_clip[0] = clip;
830 tilemaps_clip.push_update();
831 }
832 {
833 statistics_buf.view_needed_count = 0;
834 statistics_buf.push_update();
835 }
836 {
837 pages_infos_data.page_free_count = -5;
838 pages_infos_data.page_alloc_count = 0;
839 pages_infos_data.page_cached_next = 0u;
840 pages_infos_data.page_cached_start = 0u;
841 pages_infos_data.page_cached_end = 0u;
842 pages_infos_data.push_update();
843 }
844
845 Texture tilemap_tx = {"tilemap_tx"};
846 tilemap_tx.ensure_2d(GPU_R32UI,
850 tilemap_tx.clear(uint4(0));
851
852 StorageArrayBuffer<ViewMatrices, DRW_VIEW_MAX> shadow_multi_view_buf = {"ShadowMultiView"};
853 StorageBuffer<DispatchCommand> clear_dispatch_buf;
854 StorageBuffer<DrawCommand> tile_draw_buf;
855 StorageArrayBuffer<uint, SHADOW_MAX_PAGE> dst_coord_buf = {"dst_coord_buf"};
856 StorageArrayBuffer<uint, SHADOW_MAX_PAGE> src_coord_buf = {"src_coord_buf"};
857 StorageArrayBuffer<uint, SHADOW_RENDER_MAP_SIZE> render_map_buf = {"render_map_buf"};
858 StorageArrayBuffer<uint, SHADOW_VIEW_MAX> viewport_index_buf = {"viewport_index_buf"};
859
860 render_map_buf.clear_to_zero();
861
862 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tilemap_finalize");
863 PassSimple pass("Test");
864 pass.shader_set(sh);
865 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
866 pass.bind_ssbo("tiles_buf", tiles_data);
867 pass.bind_ssbo("pages_infos_buf", pages_infos_data);
868 pass.bind_ssbo("statistics_buf", statistics_buf);
869 pass.bind_ssbo("view_infos_buf", shadow_multi_view_buf);
870 pass.bind_ssbo("render_view_buf", render_views_buf);
871 pass.bind_ssbo("tilemaps_clip_buf", tilemaps_clip);
872 pass.bind_image("tilemaps_img", tilemap_tx);
873 pass.dispatch(int3(1, 1, tilemaps_data.size()));
874 pass.barrier(GPU_BARRIER_SHADER_STORAGE);
875
876 GPUShader *sh2 = GPU_shader_create_from_info_name("eevee_shadow_tilemap_rendermap");
877 pass.shader_set(sh2);
878 pass.bind_ssbo("statistics_buf", statistics_buf);
879 pass.bind_ssbo("render_view_buf", render_views_buf);
880 pass.bind_ssbo("tiles_buf", tiles_data);
881 pass.bind_ssbo("clear_dispatch_buf", clear_dispatch_buf);
882 pass.bind_ssbo("tile_draw_buf", tile_draw_buf);
883 pass.bind_ssbo("dst_coord_buf", &dst_coord_buf);
884 pass.bind_ssbo("src_coord_buf", &src_coord_buf);
885 pass.bind_ssbo("render_map_buf", &render_map_buf);
886 pass.dispatch(int3(1, 1, SHADOW_VIEW_MAX));
888
889 Manager manager;
890 manager.submit(pass);
891
892 {
893 /* Check output views. */
894 shadow_multi_view_buf.read();
895
896 for (auto i : IndexRange(5)) {
897 EXPECT_EQ(shadow_multi_view_buf[i].viewmat, float4x4::identity());
898 EXPECT_EQ(shadow_multi_view_buf[i].viewinv, float4x4::identity());
899 }
900
901 EXPECT_EQ(shadow_multi_view_buf[0].winmat,
902 math::projection::perspective(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 10.0f));
903 EXPECT_EQ(shadow_multi_view_buf[1].winmat,
904 math::projection::perspective(-1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 10.0f));
905 EXPECT_EQ(shadow_multi_view_buf[2].winmat,
906 math::projection::perspective(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 10.0f));
907 EXPECT_EQ(shadow_multi_view_buf[3].winmat,
908 math::projection::perspective(-1.0f, -0.75f, -1.0f, -0.75f, 1.0f, 10.0f));
909 EXPECT_EQ(shadow_multi_view_buf[4].winmat,
910 math::projection::perspective(0.5f, 1.5f, -1.0f, 0.0f, 1.0f, 10.0f));
911 }
912
913 {
914 uint *pixels = tilemap_tx.read<uint32_t>(GPU_DATA_UINT);
915
916 std::string result = "";
917 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
918 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
920 result += std::to_string(tile.page.x + tile.page.y * SHADOW_PAGE_PER_ROW);
921 }
922 }
923
924 MEM_SAFE_FREE(pixels);
925
927 StringRefNull expected_pages =
928 "12334444555555556666666666666667"
929 "22334444555555556666666666666666"
930 "33334444555555556666666666666666"
931 "33334444555555556666666666666666"
932 "44444444555555556666666666666666"
933 "44444444555555556666666666666666"
934 "44444444555555556666666666666666"
935 "44444444555555556666666666666666"
936 "55555555555555556666666666666666"
937 "55555555555555556666666666666666"
938 "55555555555555556666666666666666"
939 "55555555555555556666666666666666"
940 "55555555555555556666666666666666"
941 "55555555555555556666666666666666"
942 "55555555555555556666666666666666"
943 "55555555555555556666666696666666"
944 "88888888666666666666666666666666"
945 "88888888666666666666666666666666"
946 "88888888666666666666666666666666"
947 "88888888666666666666666666666666"
948 "88888888666666666666666666666666"
949 "88888888666666666666666666666666"
950 "88888888666666666666666666666666"
951 "88888888666666666666666666666666"
952 "66666666666666666666666666666666"
953 "66666666666666666666666666666666"
954 "66666666666666666666666666666666"
955 "66666666666666666666666666666666"
956 "66666666666666666666666666666666"
957 "66666666666666666666666666666666"
958 "66666666666666666666666666666666"
959 "66666666666666666666666666666666";
960
961 EXPECT_EQ(expected_pages, result);
962 }
963
964 {
965 auto stringify_view = [](Span<uint> data) -> std::string {
966 std::string result = "";
967 for (auto x : data) {
968 result += (x == 0u) ? '-' : ((x == 0xFFFFFFFFu) ? 'x' : '0' + (x % 10));
969 }
970 return result;
971 };
972
974 StringRefNull expected_view0 =
975 "6-------------------------------"
976 "--------------------------------"
977 "--------------------------------"
978 "--------------------------------"
979 "--------------------------------"
980 "--------------------------------"
981 "--------------------------------"
982 "--------------------------------"
983 "--------------------------------"
984 "--------------------------------"
985 "--------------------------------"
986 "--------------------------------"
987 "--------------------------------"
988 "--------------------------------"
989 "--------------------------------"
990 "--------------------------------"
991 "--------------------------------"
992 "--------------------------------"
993 "--------------------------------"
994 "--------------------------------"
995 "--------------------------------"
996 "--------------------------------"
997 "--------------------------------"
998 "--------------------------------"
999 "--------------------------------"
1000 "--------------------------------"
1001 "--------------------------------"
1002 "--------------------------------"
1003 "--------------------------------"
1004 "--------------------------------"
1005 "--------------------------------"
1006 "--------------------------------";
1007
1008 StringRefNull expected_view1 =
1009 "5-------------------------------"
1010 "--------------------------------"
1011 "--------------------------------"
1012 "--------------------------------"
1013 "--------------------------------"
1014 "--------------------------------"
1015 "--------------------------------"
1016 "--------------------------------"
1017 "--------------------------------"
1018 "--------------------------------"
1019 "--------------------------------"
1020 "--------------------------------"
1021 "--------------------------------"
1022 "--------------------------------"
1023 "--------------------------------"
1024 "--------------------------------"
1025 "--------------------------------"
1026 "--------------------------------"
1027 "--------------------------------"
1028 "--------------------------------"
1029 "--------------------------------"
1030 "--------------------------------"
1031 "--------------------------------"
1032 "--------------------------------"
1033 "--------------------------------"
1034 "--------------------------------"
1035 "--------------------------------"
1036 "--------------------------------"
1037 "--------------------------------"
1038 "--------------------------------"
1039 "--------------------------------"
1040 "--------------------------------";
1041
1042 StringRefNull expected_view2 =
1043 "4xxx----------------------------"
1044 "xxxx----------------------------"
1045 "8xxx----------------------------"
1046 "xxxx----------------------------"
1047 "--------------------------------"
1048 "--------------------------------"
1049 "--------------------------------"
1050 "--------------------------------"
1051 "--------------------------------"
1052 "--------------------------------"
1053 "--------------------------------"
1054 "--------------------------------"
1055 "--------------------------------"
1056 "--------------------------------"
1057 "--------------------------------"
1058 "--------------------------------"
1059 "--------------------------------"
1060 "--------------------------------"
1061 "--------------------------------"
1062 "--------------------------------"
1063 "--------------------------------"
1064 "--------------------------------"
1065 "--------------------------------"
1066 "--------------------------------"
1067 "--------------------------------"
1068 "--------------------------------"
1069 "--------------------------------"
1070 "--------------------------------"
1071 "--------------------------------"
1072 "--------------------------------"
1073 "--------------------------------"
1074 "--------------------------------";
1075
1076 StringRefNull expected_view3 =
1077 "3-------------------------------"
1078 "--------------------------------"
1079 "--------------------------------"
1080 "--------------------------------"
1081 "--------------------------------"
1082 "--------------------------------"
1083 "--------------------------------"
1084 "--------------------------------"
1085 "--------------------------------"
1086 "--------------------------------"
1087 "--------------------------------"
1088 "--------------------------------"
1089 "--------------------------------"
1090 "--------------------------------"
1091 "--------------------------------"
1092 "--------------------------------"
1093 "--------------------------------"
1094 "--------------------------------"
1095 "--------------------------------"
1096 "--------------------------------"
1097 "--------------------------------"
1098 "--------------------------------"
1099 "--------------------------------"
1100 "--------------------------------"
1101 "--------------------------------"
1102 "--------------------------------"
1103 "--------------------------------"
1104 "--------------------------------"
1105 "--------------------------------"
1106 "--------------------------------"
1107 "--------------------------------"
1108 "--------------------------------";
1109
1110 StringRefNull expected_view4 =
1111 "xxxxxxx7xxxxxxxx----------------"
1112 "xxxxxxxxxxxxxxxx----------------"
1113 "xxxxxxxxxxxxxxxx----------------"
1114 "xxxxxxxxxxxxxxxx----------------"
1115 "xxxxxxxxxxxxxxxx----------------"
1116 "xxxxxxxxxxxxxxxx----------------"
1117 "xxxxxxxxxxxxxxxx----------------"
1118 "xxxxxxxxxxxxxxxx----------------"
1119 "xxxxxxxxxxxxxxxx----------------"
1120 "xxxxxxxxxxxxxxxx----------------"
1121 "xxxxxxxxxxxxxxxx----------------"
1122 "xxxxxxxxxxxxxxxx----------------"
1123 "xxxxxxxxxxxxxxxx----------------"
1124 "xxxxxxxxxxxxxxxx----------------"
1125 "xxxxxxxxxxxxxxxx----------------"
1126 "9xxxxxxxxxxxxxxx----------------"
1127 "--------------------------------"
1128 "--------------------------------"
1129 "--------------------------------"
1130 "--------------------------------"
1131 "--------------------------------"
1132 "--------------------------------"
1133 "--------------------------------"
1134 "--------------------------------"
1135 "--------------------------------"
1136 "--------------------------------"
1137 "--------------------------------"
1138 "--------------------------------"
1139 "--------------------------------"
1140 "--------------------------------"
1141 "--------------------------------"
1142 "--------------------------------";
1143
1144 render_map_buf.read();
1145
1146 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 0],
1148 expected_view0);
1149 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 1],
1151 expected_view1);
1152 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 2],
1154 expected_view2);
1155 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 3],
1157 expected_view3);
1158 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 4],
1160 expected_view4);
1161 }
1162
1163 pages_infos_data.read();
1164 EXPECT_EQ(pages_infos_data.page_free_count, 0);
1165
1166 statistics_buf.read();
1167 EXPECT_EQ(statistics_buf.view_needed_count, 5);
1168
1169 GPU_shader_free(sh);
1170 GPU_shader_free(sh2);
1173}
1174DRAW_TEST(eevee_shadow_finalize)
1175
1177{
1178 Vector<uint> test_values{0x00000000u, 0x00000001u, 0x0000000Fu, 0x000000FFu, 0xABCDEF01u,
1179 0xAAAAAAAAu, 0xBBBBBBBBu, 0xCCCCCCCCu, 0xDDDDDDDDu, 0xEEEEEEEEu,
1180 0xFFFFFFFFu, 0xDEADBEEFu, 0x8BADF00Du, 0xABADCAFEu, 0x0D15EA5Eu,
1181 0xFEE1DEADu, 0xDEADC0DEu, 0xC00010FFu, 0xBBADBEEFu, 0xBAAAAAADu};
1182
1183 for (auto value : test_values) {
1186
1189
1190 ShadowTileData expected_tile = shadow_tile_unpack(value);
1191 ShadowTileData result_tile = shadow_tile_unpack(shadow_tile_pack(expected_tile));
1192 EXPECT_EQ(expected_tile.page, result_tile.page);
1193 EXPECT_EQ(expected_tile.cache_index, result_tile.cache_index);
1194 EXPECT_EQ(expected_tile.is_used, result_tile.is_used);
1195 EXPECT_EQ(expected_tile.do_update, result_tile.do_update);
1196 EXPECT_EQ(expected_tile.is_allocated, result_tile.is_allocated);
1197 EXPECT_EQ(expected_tile.is_rendered, result_tile.is_rendered);
1198 EXPECT_EQ(expected_tile.is_cached, result_tile.is_cached);
1199
1200 ShadowSamplingTile expected_sampling_tile = shadow_sampling_tile_unpack(value);
1201 ShadowSamplingTile result_sampling_tile = shadow_sampling_tile_unpack(
1202 shadow_sampling_tile_pack(expected_sampling_tile));
1203 EXPECT_EQ(expected_sampling_tile.page, result_sampling_tile.page);
1204 EXPECT_EQ(expected_sampling_tile.lod, result_sampling_tile.lod);
1205 EXPECT_EQ(expected_sampling_tile.lod_offset, result_sampling_tile.lod_offset);
1206 EXPECT_EQ(expected_sampling_tile.is_valid, result_sampling_tile.is_valid);
1207 }
1208}
1209DRAW_TEST(eevee_shadow_tile_packing)
1210
1212{
1214
1217 tilemap_data.fill(0);
1218
1219 auto pixel_get = [&](int x, int y, int tilemap_index) -> uint32_t & {
1220 /* NOTE: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
1221 return tilemap_data[y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
1222 tilemap_index * SHADOW_TILEMAP_RES];
1223 };
1225 tile.lod = 0;
1226 tile.lod_offset = uint2(0);
1227 tile.is_valid = true;
1228 tile.page = uint3(1, 0, 0);
1229 pixel_get(16, 16, 2) = shadow_sampling_tile_pack(tile);
1230 tile.page = uint3(2, 0, 0);
1231 pixel_get(17, 16, 2) = shadow_sampling_tile_pack(tile);
1232 tile.page = uint3(3, 0, 0);
1233 pixel_get(20, 20, 1) = shadow_sampling_tile_pack(tile);
1234 tile.page = uint3(4, 0, 0);
1235 pixel_get(17, 16, 0) = shadow_sampling_tile_pack(tile);
1236
1237 Texture tilemap_tx = {"tilemap_tx"};
1241 tilemap_tx.ensure_2d(GPU_R32UI, tilemap_res, usage);
1243 tilemap_tx, GPU_DATA_UINT, tilemap_data.data(), 0, 0, 0, tilemap_res.x, tilemap_res.y, 0);
1244
1245 /* Setup one directional light with 3 tilemaps. Fill only the needed data. */
1246 LightData light;
1247 light.type = LIGHT_SUN;
1248 light.sun.clipmap_lod_min = 0;
1249 light.sun.clipmap_lod_max = 2;
1250 /* Shift LOD0 by 1 tile towards bottom. */
1251 light.sun.clipmap_base_offset_neg = int2(0, 1 << 0);
1252 /* Shift LOD1 by 1 tile towards right. */
1253 light.sun.clipmap_base_offset_pos = int2(1 << 1, 0);
1254 light.tilemap_index = 0;
1255
1256 LightDataBuf culling_light_buf = {"Lights_culled"};
1257 culling_light_buf[0] = light;
1258 culling_light_buf.push_update();
1259
1260 LightCullingDataBuf culling_data_buf = {"LightCull_data"};
1261 culling_data_buf.local_lights_len = 0;
1262 culling_data_buf.sun_lights_len = 1;
1263 culling_data_buf.items_count = 1;
1264 culling_data_buf.push_update();
1265
1266 /* Needed for validation. But not used since we use directionals. */
1267 LightCullingZbinBuf culling_zbin_buf = {"LightCull_zbin"};
1268 LightCullingTileBuf culling_tile_buf = {"LightCull_tile"};
1269
1270 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tilemap_amend");
1271
1272 PassSimple pass("Test");
1273 pass.shader_set(sh);
1274 pass.bind_image("tilemaps_img", tilemap_tx);
1275 pass.bind_ssbo(LIGHT_CULL_BUF_SLOT, culling_data_buf);
1276 pass.bind_ssbo(LIGHT_BUF_SLOT, culling_light_buf);
1277 pass.bind_ssbo(LIGHT_ZBIN_BUF_SLOT, culling_zbin_buf);
1278 pass.bind_ssbo(LIGHT_TILE_BUF_SLOT, culling_tile_buf);
1279 pass.dispatch(int3(1));
1280 pass.barrier(GPU_BARRIER_TEXTURE_UPDATE);
1281
1282 Manager manager;
1283 manager.submit(pass);
1284
1285 {
1286 uint *pixels = tilemap_tx.read<uint32_t>(GPU_DATA_UINT);
1287
1288 auto stringify_tilemap = [&](int tilemap_index) -> std::string {
1289 std::string result = "";
1290 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
1291 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
1292 /* NOTE: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
1293 int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
1294 tilemap_index * SHADOW_TILEMAP_RES;
1296 result += std::to_string(tile.page.x + tile.page.y * SHADOW_PAGE_PER_ROW);
1297 if (x + 1 == SHADOW_TILEMAP_RES / 2) {
1298 result += " ";
1299 }
1300 }
1301 result += "\n";
1302 if (y + 1 == SHADOW_TILEMAP_RES / 2) {
1303 result += "\n";
1304 }
1305 }
1306 return result;
1307 };
1308
1309 auto stringify_lod = [&](int tilemap_index) -> std::string {
1310 std::string result = "";
1311 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
1312 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
1313 /* NOTE: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
1314 int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
1315 tilemap_index * SHADOW_TILEMAP_RES;
1317 result += std::to_string(tile.lod);
1318 if (x + 1 == SHADOW_TILEMAP_RES / 2) {
1319 result += " ";
1320 }
1321 }
1322 result += "\n";
1323 if (y + 1 == SHADOW_TILEMAP_RES / 2) {
1324 result += "\n";
1325 }
1326 }
1327 return result;
1328 };
1329
1330 auto stringify_offset = [&](int tilemap_index) -> std::string {
1331 std::string result = "";
1332 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
1333 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
1334 /* NOTE: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
1335 int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
1336 tilemap_index * SHADOW_TILEMAP_RES;
1338 result += std::to_string(tile.lod_offset.x + tile.lod_offset.y);
1339 if (x + 1 == SHADOW_TILEMAP_RES / 2) {
1340 result += " ";
1341 }
1342 }
1343 result += "\n";
1344 if (y + 1 == SHADOW_TILEMAP_RES / 2) {
1345 result += "\n";
1346 }
1347 }
1348 return result;
1349 };
1350
1353 StringRefNull expected_pages_lod2 =
1354 "0000000000000000 0000000000000000\n"
1355 "0000000000000000 0000000000000000\n"
1356 "0000000000000000 0000000000000000\n"
1357 "0000000000000000 0000000000000000\n"
1358 "0000000000000000 0000000000000000\n"
1359 "0000000000000000 0000000000000000\n"
1360 "0000000000000000 0000000000000000\n"
1361 "0000000000000000 0000000000000000\n"
1362 "0000000000000000 0000000000000000\n"
1363 "0000000000000000 0000000000000000\n"
1364 "0000000000000000 0000000000000000\n"
1365 "0000000000000000 0000000000000000\n"
1366 "0000000000000000 0000000000000000\n"
1367 "0000000000000000 0000000000000000\n"
1368 "0000000000000000 0000000000000000\n"
1369 "0000000000000000 0000000000000000\n"
1370 "\n"
1371 "0000000000000000 1200000000000000\n"
1372 "0000000000000000 0000000000000000\n"
1373 "0000000000000000 0000000000000000\n"
1374 "0000000000000000 0000000000000000\n"
1375 "0000000000000000 0000000000000000\n"
1376 "0000000000000000 0000000000000000\n"
1377 "0000000000000000 0000000000000000\n"
1378 "0000000000000000 0000000000000000\n"
1379 "0000000000000000 0000000000000000\n"
1380 "0000000000000000 0000000000000000\n"
1381 "0000000000000000 0000000000000000\n"
1382 "0000000000000000 0000000000000000\n"
1383 "0000000000000000 0000000000000000\n"
1384 "0000000000000000 0000000000000000\n"
1385 "0000000000000000 0000000000000000\n"
1386 "0000000000000000 0000000000000000\n";
1387
1388 StringRefNull expected_pages_lod1 =
1389 "0000000000000000 0000000000000000\n"
1390 "0000000000000000 0000000000000000\n"
1391 "0000000000000000 0000000000000000\n"
1392 "0000000000000000 0000000000000000\n"
1393 "0000000000000000 0000000000000000\n"
1394 "0000000000000000 0000000000000000\n"
1395 "0000000000000000 0000000000000000\n"
1396 "0000000000000000 0000000000000000\n"
1397 "0000000000000000 0000000000000000\n"
1398 "0000000000000000 0000000000000000\n"
1399 "0000000000000000 0000000000000000\n"
1400 "0000000000000000 0000000000000000\n"
1401 "0000000000000000 0000000000000000\n"
1402 "0000000000000000 0000000000000000\n"
1403 "0000000000000000 0000000000000000\n"
1404 "0000000000000000 0000000000000000\n"
1405 "\n"
1406 "0000000000000001 1220000000000000\n"
1407 "0000000000000001 1220000000000000\n"
1408 "0000000000000000 0000000000000000\n"
1409 "0000000000000000 0000000000000000\n"
1410 "0000000000000000 0000300000000000\n"
1411 "0000000000000000 0000000000000000\n"
1412 "0000000000000000 0000000000000000\n"
1413 "0000000000000000 0000000000000000\n"
1414 "0000000000000000 0000000000000000\n"
1415 "0000000000000000 0000000000000000\n"
1416 "0000000000000000 0000000000000000\n"
1417 "0000000000000000 0000000000000000\n"
1418 "0000000000000000 0000000000000000\n"
1419 "0000000000000000 0000000000000000\n"
1420 "0000000000000000 0000000000000000\n"
1421 "0000000000000000 0000000000000000\n";
1422
1423 StringRefNull expected_pages_lod0 =
1424 "0000000000000000 0000000000000000\n"
1425 "0000000000000000 0000000000000000\n"
1426 "0000000000000000 0000000000000000\n"
1427 "0000000000000000 0000000000000000\n"
1428 "0000000000000000 0000000000000000\n"
1429 "0000000000000000 0000000000000000\n"
1430 "0000000000000000 0000000000000000\n"
1431 "0000000000000000 0000000000000000\n"
1432 "0000000000000000 0000000000000000\n"
1433 "0000000000000000 0000000000000000\n"
1434 "0000000000000000 0000000000000000\n"
1435 "0000000000000000 0000000000000000\n"
1436 "0000000000000000 0000000000000000\n"
1437 "0000000000000000 0000000000000000\n"
1438 "0000000000000000 0000000000000000\n"
1439 "0000000000000000 0000000000000000\n"
1440 "\n"
1441 "0000000000000000 0400000000000000\n"
1442 "0000000000000011 1122220000000000\n"
1443 "0000000000000011 1122220000000000\n"
1444 "0000000000000011 1122220000000000\n"
1445 "0000000000000011 1122220000000000\n"
1446 "0000000000000000 0000000000000000\n"
1447 "0000000000000000 0000000000000000\n"
1448 "0000000000000000 0000000000000000\n"
1449 "0000000000000000 0000000000000000\n"
1450 "0000000000000000 0000000033000000\n"
1451 "0000000000000000 0000000033000000\n"
1452 "0000000000000000 0000000000000000\n"
1453 "0000000000000000 0000000000000000\n"
1454 "0000000000000000 0000000000000000\n"
1455 "0000000000000000 0000000000000000\n"
1456 "0000000000000000 0000000000000000\n";
1457
1458 EXPECT_EQ(expected_pages_lod2, stringify_tilemap(2));
1459 EXPECT_EQ(expected_pages_lod1, stringify_tilemap(1));
1460 EXPECT_EQ(expected_pages_lod0, stringify_tilemap(0));
1461
1462 StringRefNull expected_lod_lod0 =
1463 "0000000000000000 0000000000000000\n"
1464 "0000000000000000 0000000000000000\n"
1465 "0000000000000000 0000000000000000\n"
1466 "0000000000000000 0000000000000000\n"
1467 "0000000000000000 0000000000000000\n"
1468 "0000000000000000 0000000000000000\n"
1469 "0000000000000000 0000000000000000\n"
1470 "0000000000000000 0000000000000000\n"
1471 "0000000000000000 0000000000000000\n"
1472 "0000000000000000 0000000000000000\n"
1473 "0000000000000000 0000000000000000\n"
1474 "0000000000000000 0000000000000000\n"
1475 "0000000000000000 0000000000000000\n"
1476 "0000000000000000 0000000000000000\n"
1477 "0000000000000000 0000000000000000\n"
1478 "0000000000000000 0000000000000000\n"
1479 "\n"
1480 "0000000000000000 0000000000000000\n"
1481 "0000000000000022 2222220000000000\n"
1482 "0000000000000022 2222220000000000\n"
1483 "0000000000000022 2222220000000000\n"
1484 "0000000000000022 2222220000000000\n"
1485 "0000000000000000 0000000000000000\n"
1486 "0000000000000000 0000000000000000\n"
1487 "0000000000000000 0000000000000000\n"
1488 "0000000000000000 0000000000000000\n"
1489 "0000000000000000 0000000011000000\n"
1490 "0000000000000000 0000000011000000\n"
1491 "0000000000000000 0000000000000000\n"
1492 "0000000000000000 0000000000000000\n"
1493 "0000000000000000 0000000000000000\n"
1494 "0000000000000000 0000000000000000\n"
1495 "0000000000000000 0000000000000000\n";
1496
1497 EXPECT_EQ(expected_lod_lod0, stringify_lod(0));
1498
1499 /* Offset for each axis are added together in this test. */
1500 StringRefNull expected_offset_lod0 =
1501 "0000000000000000 0000000000000000\n"
1502 "0000000000000000 0000000000000000\n"
1503 "0000000000000000 0000000000000000\n"
1504 "0000000000000000 0000000000000000\n"
1505 "0000000000000000 0000000000000000\n"
1506 "0000000000000000 0000000000000000\n"
1507 "0000000000000000 0000000000000000\n"
1508 "0000000000000000 0000000000000000\n"
1509 "0000000000000000 0000000000000000\n"
1510 "0000000000000000 0000000000000000\n"
1511 "0000000000000000 0000000000000000\n"
1512 "0000000000000000 0000000000000000\n"
1513 "0000000000000000 0000000000000000\n"
1514 "0000000000000000 0000000000000000\n"
1515 "0000000000000000 0000000000000000\n"
1516 "0000000000000000 0000000000000000\n"
1517 "\n"
1518 "0000000000000000 0000000000000000\n"
1519 "0000000000000055 5555550000000000\n"
1520 "0000000000000055 5555550000000000\n"
1521 "0000000000000055 5555550000000000\n"
1522 "0000000000000055 5555550000000000\n"
1523 "0000000000000000 0000000000000000\n"
1524 "0000000000000000 0000000000000000\n"
1525 "0000000000000000 0000000000000000\n"
1526 "0000000000000000 0000000000000000\n"
1527 "0000000000000000 0000000011000000\n"
1528 "0000000000000000 0000000011000000\n"
1529 "0000000000000000 0000000000000000\n"
1530 "0000000000000000 0000000000000000\n"
1531 "0000000000000000 0000000000000000\n"
1532 "0000000000000000 0000000000000000\n"
1533 "0000000000000000 0000000000000000\n";
1534
1535 EXPECT_EQ(expected_offset_lod0, stringify_offset(0));
1536 MEM_SAFE_FREE(pixels);
1537 }
1538
1539 GPU_shader_free(sh);
1542}
1543DRAW_TEST(eevee_shadow_tilemap_amend)
1544
1545static void test_eevee_shadow_page_mask_ex(int max_view_per_tilemap)
1546{
1548 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
1549 ShadowTileDataBuf tiles_data = {"tiles_data"};
1550
1551 {
1552 ShadowTileMap tilemap(0);
1553 tilemap.sync_cubeface(LIGHT_OMNI_SPHERE, float4x4::identity(), 0.01f, 1.0f, Z_NEG);
1554 tilemaps_data.append(tilemap);
1555 }
1556
1557 const uint lod0_len = SHADOW_TILEMAP_LOD0_LEN;
1558 const uint lod1_len = SHADOW_TILEMAP_LOD1_LEN;
1559 const uint lod2_len = SHADOW_TILEMAP_LOD2_LEN;
1560 const uint lod3_len = SHADOW_TILEMAP_LOD3_LEN;
1561 const uint lod4_len = SHADOW_TILEMAP_LOD4_LEN;
1562 const uint lod5_len = SHADOW_TILEMAP_LOD5_LEN;
1563
1564 const uint lod0_ofs = 0;
1565 const uint lod1_ofs = lod0_ofs + lod0_len;
1566 const uint lod2_ofs = lod1_ofs + lod1_len;
1567 const uint lod3_ofs = lod2_ofs + lod2_len;
1568 const uint lod4_ofs = lod3_ofs + lod3_len;
1569 const uint lod5_ofs = lod4_ofs + lod4_len;
1570
1571 {
1572 ShadowTileData tile = {};
1573 /* Init all LOD to true. */
1574 for (auto i : IndexRange(SHADOW_TILEDATA_PER_TILEMAP)) {
1575 tile.is_used = true;
1576 tile.do_update = true;
1577 tiles_data[i] = shadow_tile_pack(tile);
1578 }
1579
1580 /* Init all of LOD0 to false. */
1581 for (auto i : IndexRange(square_i(SHADOW_TILEMAP_RES))) {
1582 tile.is_used = false;
1583 tile.do_update = false;
1584 tiles_data[i] = shadow_tile_pack(tile);
1585 }
1586
1587 /* Bottom Left of the LOD0 to true. */
1588 for (auto y : IndexRange((SHADOW_TILEMAP_RES / 2))) {
1589 for (auto x : IndexRange((SHADOW_TILEMAP_RES / 2) + 1)) {
1590 tile.is_used = true;
1591 tile.do_update = true;
1592 tiles_data[x + y * SHADOW_TILEMAP_RES] = shadow_tile_pack(tile);
1593 }
1594 }
1595
1596 /* All Bottom of the LOD0 to true. */
1597 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
1598 tile.is_used = true;
1599 tile.do_update = true;
1600 tiles_data[x] = shadow_tile_pack(tile);
1601 }
1602
1603 /* Bottom Left of the LOD1 to false. */
1604 /* Should still cover bottom LODs since it is itself fully masked */
1605 for (auto y : IndexRange((SHADOW_TILEMAP_RES / 8))) {
1606 for (auto x : IndexRange((SHADOW_TILEMAP_RES / 8))) {
1607 tile.is_used = false;
1608 tile.do_update = false;
1609 tiles_data[x + y * (SHADOW_TILEMAP_RES / 2) + lod0_len] = shadow_tile_pack(tile);
1610 }
1611 }
1612
1613 /* Top right Center of the LOD1 to false. */
1614 /* Should un-cover 1 LOD2 tile. */
1615 {
1616 int x = SHADOW_TILEMAP_RES / 4;
1617 int y = SHADOW_TILEMAP_RES / 4;
1618 tile.is_used = false;
1619 tile.do_update = false;
1620 tiles_data[x + y * (SHADOW_TILEMAP_RES / 2) + lod0_len] = shadow_tile_pack(tile);
1621 }
1622
1623 tiles_data.push_update();
1624 }
1625
1626 tilemaps_data.push_update();
1627
1628 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_page_mask");
1629
1630 PassSimple pass("Test");
1631 pass.shader_set(sh);
1632 pass.push_constant("max_view_per_tilemap", max_view_per_tilemap);
1633 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
1634 pass.bind_ssbo("tiles_buf", tiles_data);
1635 pass.dispatch(int3(1, 1, tilemaps_data.size()));
1636
1637 Manager manager;
1638 manager.submit(pass);
1640
1641 tiles_data.read();
1642
1644 StringRefNull expected_lod0 =
1645 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
1646 "xxxxxxxxxxxxxxxxx---------------"
1647 "xxxxxxxxxxxxxxxxx---------------"
1648 "xxxxxxxxxxxxxxxxx---------------"
1649 "xxxxxxxxxxxxxxxxx---------------"
1650 "xxxxxxxxxxxxxxxxx---------------"
1651 "xxxxxxxxxxxxxxxxx---------------"
1652 "xxxxxxxxxxxxxxxxx---------------"
1653 "xxxxxxxxxxxxxxxxx---------------"
1654 "xxxxxxxxxxxxxxxxx---------------"
1655 "xxxxxxxxxxxxxxxxx---------------"
1656 "xxxxxxxxxxxxxxxxx---------------"
1657 "xxxxxxxxxxxxxxxxx---------------"
1658 "xxxxxxxxxxxxxxxxx---------------"
1659 "xxxxxxxxxxxxxxxxx---------------"
1660 "xxxxxxxxxxxxxxxxx---------------"
1661 "--------------------------------"
1662 "--------------------------------"
1663 "--------------------------------"
1664 "--------------------------------"
1665 "--------------------------------"
1666 "--------------------------------"
1667 "--------------------------------"
1668 "--------------------------------"
1669 "--------------------------------"
1670 "--------------------------------"
1671 "--------------------------------"
1672 "--------------------------------"
1673 "--------------------------------"
1674 "--------------------------------"
1675 "--------------------------------"
1676 "--------------------------------";
1677 StringRefNull expected_lod1 =
1678 "--------xxxxxxxx"
1679 "--------xxxxxxxx"
1680 "--------xxxxxxxx"
1681 "--------xxxxxxxx"
1682 "--------xxxxxxxx"
1683 "--------xxxxxxxx"
1684 "--------xxxxxxxx"
1685 "--------xxxxxxxx"
1686 "xxxxxxxx-xxxxxxx"
1687 "xxxxxxxxxxxxxxxx"
1688 "xxxxxxxxxxxxxxxx"
1689 "xxxxxxxxxxxxxxxx"
1690 "xxxxxxxxxxxxxxxx"
1691 "xxxxxxxxxxxxxxxx"
1692 "xxxxxxxxxxxxxxxx"
1693 "xxxxxxxxxxxxxxxx";
1694 StringRefNull expected_lod1_collapsed =
1695 "xxxxxxxxxxxxxxxx"
1696 "xxxxxxxxxxxxxxxx"
1697 "xxxxxxxxxxxxxxxx"
1698 "xxxxxxxxxxxxxxxx"
1699 "xxxxxxxxxxxxxxxx"
1700 "xxxxxxxxxxxxxxxx"
1701 "xxxxxxxxxxxxxxxx"
1702 "xxxxxxxxxxxxxxxx"
1703 "xxxxxxxx-xxxxxxx"
1704 "xxxxxxxxxxxxxxxx"
1705 "xxxxxxxxxxxxxxxx"
1706 "xxxxxxxxxxxxxxxx"
1707 "xxxxxxxxxxxxxxxx"
1708 "xxxxxxxxxxxxxxxx"
1709 "xxxxxxxxxxxxxxxx"
1710 "xxxxxxxxxxxxxxxx";
1711 StringRefNull expected_lod2 =
1712 "--------"
1713 "--------"
1714 "--------"
1715 "--------"
1716 "----x---"
1717 "--------"
1718 "--------"
1719 "--------";
1720 StringRefNull expected_lod2_collapsed =
1721 "xxxxxxxx"
1722 "xxxxxxxx"
1723 "xxxxxxxx"
1724 "xxxxxxxx"
1725 "xxxxxxxx"
1726 "xxxxxxxx"
1727 "xxxxxxxx"
1728 "xxxxxxxx";
1729 StringRefNull expected_lod3 =
1730 "----"
1731 "----"
1732 "----"
1733 "----";
1734 StringRefNull expected_lod4 =
1735 "--"
1736 "--";
1737 StringRefNull expected_lod5 = "-";
1738
1739 auto stringify_result = [&](uint start, uint len) -> std::string {
1740 std::string result = "";
1741 for (auto i : IndexRange(start, len)) {
1742 result += (shadow_tile_unpack(tiles_data[i]).is_used) ? "x" : "-";
1743 }
1744 return result;
1745 };
1746
1747 auto empty_result = [&](uint len) -> std::string {
1748 std::string result = "";
1749 for ([[maybe_unused]] const int i : IndexRange(len)) {
1750 result += "-";
1751 }
1752 return result;
1753 };
1754
1755 if (max_view_per_tilemap >= 3) {
1756 EXPECT_EQ(stringify_result(lod0_ofs, lod0_len), expected_lod0);
1757 }
1758 else {
1759 EXPECT_EQ(stringify_result(lod0_ofs, lod0_len), empty_result(lod0_len));
1760 }
1761
1762 if (max_view_per_tilemap > 2) {
1763 EXPECT_EQ(stringify_result(lod1_ofs, lod1_len), expected_lod1);
1764 }
1765 else if (max_view_per_tilemap == 2) {
1766 EXPECT_EQ(stringify_result(lod1_ofs, lod1_len), expected_lod1_collapsed);
1767 }
1768 else {
1769 EXPECT_EQ(stringify_result(lod1_ofs, lod1_len), empty_result(lod1_len));
1770 }
1771
1772 if (max_view_per_tilemap > 1) {
1773 EXPECT_EQ(stringify_result(lod2_ofs, lod2_len), expected_lod2);
1774 }
1775 else if (max_view_per_tilemap == 1) {
1776 EXPECT_EQ(stringify_result(lod2_ofs, lod2_len), expected_lod2_collapsed);
1777 }
1778 else {
1779 EXPECT_EQ(stringify_result(lod2_ofs, lod2_len), empty_result(lod2_len));
1780 }
1781 EXPECT_EQ(stringify_result(lod3_ofs, lod3_len), expected_lod3);
1782 EXPECT_EQ(stringify_result(lod4_ofs, lod4_len), expected_lod4);
1783 EXPECT_EQ(stringify_result(lod5_ofs, lod5_len), expected_lod5);
1784
1785 GPU_shader_free(sh);
1788}
1789
1791{
1792 /* Expect default behavior. */
1794 /* Expect default behavior. */
1796 /* Expect LOD0 merged into LOD1. */
1798 /* Expect LOD0 and LOD1 merged into LOD2. */
1800}
1801DRAW_TEST(eevee_shadow_page_mask)
1802
1804{
1806 StorageArrayBuffer<int> list_start_buf = {"list_start_buf"};
1807 StorageVectorBuffer<Surfel> surfel_buf = {"surfel_buf"};
1808 CaptureInfoBuf capture_info_buf = {"capture_info_buf"};
1809 SurfelListInfoBuf list_info_buf = {"list_info_buf"};
1810
1814 {
1815 Surfel surfel;
1816 /* NOTE: Expected link assumes linear increasing processing order [0->5]. But this is
1817 * multithreaded and we can't know the execution order in advance. */
1818 /* 0: Project to (1, 0) = list 1. Unsorted Next = -1; Next = -1; Previous = 3. */
1819 surfel.position = {1.1f, 0.1f, 0.1f};
1820 surfel_buf.append(surfel);
1821 /* 1: Project to (1, 0) = list 1. Unsorted Next = 0; Next = 2; Previous = -1. */
1822 surfel.position = {1.1f, 0.2f, 0.5f};
1823 surfel_buf.append(surfel);
1824 /* 2: Project to (1, 0) = list 1. Unsorted Next = 1; Next = 3; Previous = 1. */
1825 surfel.position = {1.1f, 0.3f, 0.3f};
1826 surfel_buf.append(surfel);
1827 /* 3: Project to (1, 0) = list 1. Unsorted Next = 2; Next = 0; Previous = 2. */
1828 surfel.position = {1.2f, 0.4f, 0.2f};
1829 surfel_buf.append(surfel);
1830 /* 4: Project to (1, 1) = list 3. Unsorted Next = -1; Next = -1; Previous = -1. */
1831 surfel.position = {1.0f, 1.0f, 0.5f};
1832 surfel_buf.append(surfel);
1833 /* 5: Project to (0, 1) = list 2. Unsorted Next = -1; Next = -1; Previous = -1. */
1834 surfel.position = {0.1f, 1.1f, 0.5f};
1835 surfel_buf.append(surfel);
1836
1837 surfel_buf.push_update();
1838 }
1839 {
1840 capture_info_buf.surfel_len = surfel_buf.size();
1841 capture_info_buf.push_update();
1842 }
1843 {
1844 list_info_buf.ray_grid_size = int2(2);
1845 list_info_buf.list_max = list_info_buf.ray_grid_size.x * list_info_buf.ray_grid_size.y;
1846 list_info_buf.push_update();
1847 }
1848 {
1849 list_start_buf.resize(ceil_to_multiple_u(list_info_buf.list_max, 4u));
1850 list_start_buf.push_update();
1851 GPU_storagebuf_clear(list_start_buf, -1);
1852 }
1853
1854 /* Top-down view. */
1855 View view = {"RayProjectionView"};
1857
1858 GPUShader *sh_build = GPU_shader_create_from_info_name("eevee_surfel_list_build");
1859 GPUShader *sh_sort = GPU_shader_create_from_info_name("eevee_surfel_list_sort");
1860
1861 PassSimple pass("Build_and_Sort");
1862 pass.shader_set(sh_build);
1863 pass.bind_ssbo("list_start_buf", list_start_buf);
1864 pass.bind_ssbo("surfel_buf", surfel_buf);
1865 pass.bind_ssbo("capture_info_buf", capture_info_buf);
1866 pass.bind_ssbo("list_info_buf", list_info_buf);
1867 pass.dispatch(int3(1, 1, 1));
1868 pass.barrier(GPU_BARRIER_SHADER_STORAGE);
1869
1870 pass.shader_set(sh_sort);
1871 pass.bind_ssbo("list_start_buf", list_start_buf);
1872 pass.bind_ssbo("surfel_buf", surfel_buf);
1873 pass.bind_ssbo("list_info_buf", list_info_buf);
1874 pass.dispatch(int3(1, 1, 1));
1875 pass.barrier(GPU_BARRIER_BUFFER_UPDATE);
1876
1877 Manager manager;
1878 manager.submit(pass, view);
1879
1880 list_start_buf.read();
1881 surfel_buf.read();
1882
1883 /* Expect surfel list. */
1884 Vector<int> expect_link_next = {-1, +2, +3, +0, -1, -1};
1885 Vector<int> expect_link_prev = {+3, -1, +1, +2, -1, -1};
1886
1887 Vector<int> link_next, link_prev;
1888 for (auto &surfel : Span<Surfel>(surfel_buf.data(), surfel_buf.size())) {
1889 link_next.append(surfel.next);
1890 link_prev.append(surfel.prev);
1891 }
1892
1893#if 0 /* Useful for debugging */
1894 /* NOTE: All of these are unstable by definition (atomic + multi-thread).
1895 * But should be consistent since we only dispatch one thread-group. */
1896 /* Expect last added surfel index. It is the list start index before sorting. */
1897 Vector<int> expect_list_start = {-1, 1, 5, 4};
1898 // Span<int>(list_start_buf.data(), expect_list_start.size()).print_as_lines("list_start");
1899 // link_next.as_span().print_as_lines("link_next");
1900 // link_prev.as_span().print_as_lines("link_prev");
1901 EXPECT_EQ_ARRAY(expect_list_start.data(), list_start_buf.data(), expect_list_start.size());
1902#endif
1903 EXPECT_EQ_ARRAY(expect_link_next.data(), link_next.data(), expect_link_next.size());
1904 EXPECT_EQ_ARRAY(expect_link_prev.data(), link_prev.data(), expect_link_prev.size());
1905
1906 GPU_shader_free(sh_build);
1907 GPU_shader_free(sh_sort);
1910}
1911DRAW_TEST(eevee_surfel_list)
1912
1914{
1916
1917 Manager manager;
1918
1919 /* Check if LUT generation matches the header version. */
1920 auto brdf_ggx_gen = Precompute(manager, LUT_GGX_BRDF_SPLIT_SUM, {64, 64, 1}).data<float3>();
1921 auto btdf_ggx_gen = Precompute(manager, LUT_GGX_BTDF_IOR_GT_ONE, {64, 64, 16}).data<float1>();
1922 auto bsdf_ggx_gen = Precompute(manager, LUT_GGX_BSDF_SPLIT_SUM, {64, 64, 16}).data<float3>();
1923 auto burley_gen = Precompute(manager, LUT_BURLEY_SSS_PROFILE, {64, 1, 1}).data<float1>();
1924 auto rand_walk_gen = Precompute(manager, LUT_RANDOM_WALK_SSS_PROFILE, {64, 1, 1}).data<float1>();
1925
1926 Span<float3> brdf_ggx_lut((const float3 *)&eevee::lut::brdf_ggx, 64 * 64);
1927 Span<float1> btdf_ggx_lut((const float1 *)&eevee::lut::btdf_ggx, 64 * 64 * 16);
1928 Span<float3> bsdf_ggx_lut((const float3 *)&eevee::lut::bsdf_ggx, 64 * 64 * 16);
1929 Span<float1> burley_sss_lut((const float1 *)&eevee::lut::burley_sss_profile, 64);
1930 Span<float1> rand_walk_lut((const float1 *)&eevee::lut::random_walk_sss_profile, 64);
1931
1932 const float eps = 3e-3f;
1933 EXPECT_NEAR_ARRAY_ND(brdf_ggx_lut.data(), brdf_ggx_gen.data(), brdf_ggx_gen.size(), 3, eps);
1934 EXPECT_NEAR_ARRAY_ND(btdf_ggx_lut.data(), btdf_ggx_gen.data(), btdf_ggx_gen.size(), 1, eps);
1935 EXPECT_NEAR_ARRAY_ND(bsdf_ggx_lut.data(), bsdf_ggx_gen.data(), bsdf_ggx_gen.size(), 3, eps);
1936 EXPECT_NEAR_ARRAY_ND(burley_gen.data(), burley_sss_lut.data(), burley_sss_lut.size(), 1, eps);
1937 EXPECT_NEAR_ARRAY_ND(rand_walk_gen.data(), rand_walk_lut.data(), rand_walk_lut.size(), 1, eps);
1938
1940}
1941DRAW_TEST(eevee_lut_gen)
1942
1943} // namespace blender::draw
General operations, lookup, etc. for blender objects.
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
MINLINE uint ceil_to_multiple_u(uint a, uint b)
MINLINE int min_ii(int a, int b)
MINLINE int square_i(int a)
MINLINE int max_ii(int a, int b)
unsigned int uint
void GPU_render_end()
void GPU_render_begin()
GPUShader * GPU_shader_create_from_info_name(const char *info_name)
void GPU_shader_free(GPUShader *shader)
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:374
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
@ GPU_BARRIER_BUFFER_UPDATE
Definition GPU_state.hh:56
@ GPU_BARRIER_TEXTURE_UPDATE
Definition GPU_state.hh:39
void GPU_storagebuf_clear(GPUStorageBuf *ssbo, uint32_t clear_value)
@ GPU_DATA_UINT
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_SHADER_WRITE
@ GPU_TEXTURE_USAGE_HOST_READ
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)
#define MEM_SAFE_FREE(v)
struct GPUShader GPUShader
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
int64_t size() const
void append(const T &value)
void fill(const T &value) const
SwapChain< ObjectBoundsBuf, 2 > bounds_buf
void submit(PassSimple &pass, View &view)
ResourceHandle resource_handle(const ObjectRef &ref, float inflate_bounds=0.0f)
TestAlloc(int page_free_count)
TestDefrag(int allocation_count, int descriptor_offset, StringRefNull descriptor, StringRefNull expect)
void clear(float4 values)
T * read(eGPUDataFormat format, int miplvl=0)
bool ensure_2d(eGPUTextureFormat format, int2 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
void sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id=0)
Definition draw_view.cc:20
int len
void DRW_shaders_free()
#define DRAW_TEST(test_name)
#define SHADOW_TILEMAP_LOD2_LEN
#define SHADOW_TILEMAP_RES
#define SHADOW_TILEMAP_LOD4_LEN
#define LIGHT_BUF_SLOT
#define SHADOW_TILEMAP_PER_ROW
#define SHADOW_TILEMAP_LOD1_LEN
#define SHADOW_PAGE_PER_ROW
#define SHADOW_TILEMAP_LOD0_LEN
#define SHADOW_VIEW_MAX
#define LIGHT_ZBIN_BUF_SLOT
#define SHADOW_MAX_TILE
#define SHADOW_TILEDATA_PER_TILEMAP
#define SHADOW_PAGE_PER_COL
#define SHADOW_PAGE_PER_LAYER
#define SHADOW_MAX_PAGE
#define LIGHT_TILE_BUF_SLOT
#define SHADOW_TILEMAP_LOD5_LEN
#define LIGHT_CULL_BUF_SLOT
#define SHADOW_TILEMAP_LOD3_LEN
SHADOW_TILEMAP_RES tiles_buf[] statistics_buf render_view_buf[SHADOW_VIEW_MAX] GPU_R32UI
const int tile_index
ccl_global const KernelWorkTile * tile
descriptor
static void test_eevee_shadow_free()
static void test_eevee_surfel_list()
static void test_eevee_shadow_tilemap_amend()
static void test_eevee_lut_gen()
static void test_eevee_shadow_defrag()
static void test_eevee_shadow_finalize()
static void test_eevee_shadow_tag_update()
static void test_eevee_shadow_shift()
static void test_eevee_shadow_alloc()
static void test_eevee_shadow_page_mask()
static void test_eevee_shadow_page_mask_ex(int max_view_per_tilemap)
static void test_eevee_shadow_shift_clear()
Definition eevee_test.cc:31
static void test_eevee_shadow_tile_packing()
const float burley_sss_profile[64][1]
const float brdf_ggx[64][64][3]
const float random_walk_sss_profile[64][1]
const float btdf_ggx[16][64][64][1]
const float bsdf_ggx[16][64][64][3]
static ShadowTileDataPacked shadow_tile_pack(ShadowTileData tile)
static ShadowSamplingTilePacked shadow_sampling_tile_pack(ShadowSamplingTile tile)
static ShadowTileData shadow_tile_unpack(ShadowTileDataPacked data)
static uint2 shadow_lod_offset_unpack(uint data)
static uint3 shadow_page_unpack(uint data)
static uint shadow_page_pack(uint3 page)
static uint shadow_lod_offset_pack(uint2 ofs)
static ShadowSamplingTile shadow_sampling_tile_unpack(ShadowSamplingTilePacked data)
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 [-...
MatT from_loc_rot_scale(const typename MatT::loc_type &location, const RotationT &rotation, const VecBase< typename MatT::base_type, ScaleDim > &scale)
VecBase< uint32_t, 2 > uint2
VecBase< uint32_t, 4 > uint4
VecBase< uint32_t, 3 > uint3
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
const btScalar eps
Definition poly34.cpp:11
unsigned int uint32_t
Definition stdint.h:80
void sync_orthographic(const float4x4 &object_mat_, int2 origin_offset, int clipmap_level, eShadowProjectionType projection_type_, uint2 shadow_set_membership_=~uint2(0))
void sync_cubeface(eLightType light_type_, const float4x4 &object_mat, float near, float far, eCubeFace face, uint2 shadow_set_membership_=~uint2(0))