Blender V4.5
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 "GPU_batch.hh"
8#include "GPU_context.hh"
9#include "draw_shader.hh"
10#include "draw_testing.hh"
14
15namespace blender::draw {
16
17using namespace blender::eevee;
18
19/* Replace with template version that is not GPU only. */
22
24{
26 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
27 ShadowTileDataBuf tiles_data = {"tiles_data"};
28 ShadowTileMapClipBuf tilemaps_clip = {"tilemaps_clip"};
29 ShadowPageCacheBuf pages_cached_data_ = {"pages_cached_data_"};
30
31 int tiles_index = 1;
32 int tile_lod0 = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 5;
33 int tile_lod1 = tile_lod0 + square_i(SHADOW_TILEMAP_RES);
34
35 {
36 ShadowTileMapData tilemap = {};
37 tilemap.tiles_index = tiles_index * SHADOW_TILEDATA_PER_TILEMAP;
40
41 tilemaps_data.append(tilemap);
42
43 tilemaps_data.push_update();
44 }
45 {
47
48 tile.page = uint3(1, 2, 0);
49 tile.is_used = true;
50 tile.do_update = true;
51 tiles_data[tile_lod0] = shadow_tile_pack(tile);
52
53 tile.page = uint3(3, 2, 4);
54 tile.is_used = false;
55 tile.do_update = false;
56 tiles_data[tile_lod1] = shadow_tile_pack(tile);
57
58 tiles_data.push_update();
59 }
60
61 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tilemap_init");
62
63 PassSimple pass("Test");
64 pass.shader_set(sh);
65 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
66 pass.bind_ssbo("tilemaps_clip_buf", tilemaps_clip);
67 pass.bind_ssbo("tiles_buf", tiles_data);
68 pass.bind_ssbo("pages_cached_buf", pages_cached_data_);
69 pass.dispatch(int3(1, 1, tilemaps_data.size()));
71
72 Manager manager;
73 manager.submit(pass);
74
75 tilemaps_data.read();
76 tiles_data.read();
77
78 EXPECT_EQ(tilemaps_data[0].grid_offset, int2(0));
79 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod0]).page, uint3(1, 2, 0));
80 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod0]).is_used, false);
81 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod0]).do_update, true);
82 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod1]).page, uint3(3, 2, 4));
83 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod1]).is_used, false);
84 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_lod1]).do_update, true);
85
87
91}
92DRAW_TEST(eevee_shadow_shift_clear)
93
95{
97 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
98 ShadowTileDataBuf tiles_data = {"tiles_data"};
99 StorageArrayBuffer<ShadowTileMapClip, SHADOW_MAX_TILEMAP> tilemaps_clip = {"tilemaps_clip"};
100 ShadowPageCacheBuf pages_cached_data = {"pages_cached_data"};
101
102 auto tile_co_to_page = [](int2 co) {
103 int page = co.x + co.y * SHADOW_TILEMAP_RES;
104 return uint3((page % SHADOW_PAGE_PER_ROW),
106 (page / SHADOW_PAGE_PER_LAYER));
107 };
108
109 {
110 ShadowTileMapClip clip = {};
111 clip.clip_near_stored = 0.0;
112 clip.clip_far_stored = 1.0;
113 clip.clip_near = 0x00000000; /* floatBitsToOrderedInt(0.0) */
114 clip.clip_far = 0x3F800000; /* floatBitsToOrderedInt(1.0) */
115
116 tilemaps_clip[0] = clip;
117
118 tilemaps_clip.push_update();
119 }
120 {
121 ShadowTileMapData tilemap = {};
122 tilemap.tiles_index = 0;
123 tilemap.clip_data_index = 0;
124 tilemap.grid_shift = int2(-1, 2);
126
127 tilemaps_data.append(tilemap);
128
129 tilemaps_data.push_update();
130 }
131 {
132 ShadowTileData tile = {};
133
134 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
135 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
136 tile.is_allocated = true;
137 tile.is_rendered = true;
138 tile.do_update = true;
139 tile.page = tile_co_to_page(int2(x, y));
140 tiles_data[x + y * SHADOW_TILEMAP_RES] = shadow_tile_pack(tile);
141 }
142 }
143
144 tiles_data.push_update();
145 }
146
147 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tilemap_init");
148
149 PassSimple pass("Test");
150 pass.shader_set(sh);
151 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
152 pass.bind_ssbo("tilemaps_clip_buf", tilemaps_clip);
153 pass.bind_ssbo("tiles_buf", tiles_data);
154 pass.bind_ssbo("pages_cached_buf", pages_cached_data);
155 pass.dispatch(int3(1, 1, tilemaps_data.size()));
157
158 Manager manager;
159 manager.submit(pass);
160
161 tilemaps_data.read();
162 tiles_data.read();
163
164 EXPECT_EQ(tilemaps_data[0].grid_offset, int2(0));
165 EXPECT_EQ(shadow_tile_unpack(tiles_data[0]).page,
166 tile_co_to_page(int2(SHADOW_TILEMAP_RES - 1, 2)));
167 EXPECT_EQ(shadow_tile_unpack(tiles_data[0]).do_update, true);
168 EXPECT_EQ(shadow_tile_unpack(tiles_data[0]).is_rendered, false);
169 EXPECT_EQ(shadow_tile_unpack(tiles_data[0]).is_allocated, true);
170 EXPECT_EQ(shadow_tile_unpack(tiles_data[1]).page, tile_co_to_page(int2(0, 2)));
171 EXPECT_EQ(shadow_tile_unpack(tiles_data[1]).do_update, false);
172 EXPECT_EQ(shadow_tile_unpack(tiles_data[1]).is_rendered, false);
173 EXPECT_EQ(shadow_tile_unpack(tiles_data[1]).is_allocated, true);
174 EXPECT_EQ(shadow_tile_unpack(tiles_data[0 + SHADOW_TILEMAP_RES * 2]).page,
175 tile_co_to_page(int2(SHADOW_TILEMAP_RES - 1, 4)));
176 EXPECT_EQ(shadow_tile_unpack(tiles_data[0 + SHADOW_TILEMAP_RES * 2]).do_update, true);
177 EXPECT_EQ(shadow_tile_unpack(tiles_data[0 + SHADOW_TILEMAP_RES * 2]).is_rendered, false);
178 EXPECT_EQ(shadow_tile_unpack(tiles_data[0 + SHADOW_TILEMAP_RES * 2]).is_allocated, true);
179 EXPECT_EQ(shadow_tile_unpack(tiles_data[1 + SHADOW_TILEMAP_RES * 2]).page,
180 tile_co_to_page(int2(0, 4)));
181 EXPECT_EQ(shadow_tile_unpack(tiles_data[1 + SHADOW_TILEMAP_RES * 2]).do_update, false);
182 EXPECT_EQ(shadow_tile_unpack(tiles_data[1 + SHADOW_TILEMAP_RES * 2]).is_rendered, false);
183 EXPECT_EQ(shadow_tile_unpack(tiles_data[1 + SHADOW_TILEMAP_RES * 2]).is_allocated, true);
184
186
187 GPU_shader_free(sh);
190}
191DRAW_TEST(eevee_shadow_shift)
192
194{
196 using namespace blender::math;
197 StorageVectorBuffer<uint, 128> past_casters_updated = {"PastCastersUpdated"};
198 StorageVectorBuffer<uint, 128> curr_casters_updated = {"CurrCastersUpdated"};
199
200 Manager manager;
201 {
202 /* Simulate 1 object moving and 1 object static with changing resource index. */
205 float3(1.0f), Quaternion::identity(), float3(0.5f));
206 float3 half_extent = float3(0.24f, 0.249f, 0.001f);
207
208 {
209 manager.begin_sync();
210 ResourceHandle hdl = manager.resource_handle(obmat, float3(0.5f, 0.5f, -1.0f), half_extent);
211 manager.resource_handle(obmat2);
212 manager.end_sync();
213 past_casters_updated.append(hdl.resource_index());
214 past_casters_updated.push_update();
215 }
216 {
217 manager.begin_sync();
218 manager.resource_handle(obmat2);
219 ResourceHandle hdl = manager.resource_handle(obmat, float3(-1.0f, 0.5f, -1.0f), half_extent);
220 manager.end_sync();
221 curr_casters_updated.append(hdl.resource_index());
222 curr_casters_updated.push_update();
223 }
224 }
225
226 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
227 ShadowTileDataBuf tiles_data = {"tiles_data"};
228 tiles_data.clear_to_zero();
229
230 {
233 tilemaps_data.append(tilemap);
234 }
235 {
238 tilemaps_data.append(tilemap);
239 }
240
241 tilemaps_data.push_update();
242
243 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tag_update");
244
245 PassSimple pass("Test");
246 pass.shader_set(sh);
247 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
248 pass.bind_ssbo("tiles_buf", tiles_data);
249 pass.bind_ssbo("bounds_buf", &manager.bounds_buf.previous());
250 pass.bind_ssbo("resource_ids_buf", past_casters_updated);
251 pass.dispatch(int3(past_casters_updated.size(), 1, tilemaps_data.size()));
252 pass.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
253 pass.bind_ssbo("resource_ids_buf", curr_casters_updated);
254 pass.dispatch(int3(curr_casters_updated.size(), 1, tilemaps_data.size()));
256
257 draw::View view("Test");
259 math::projection::orthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f));
260
261 manager.submit(pass, view);
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
358
359 GPU_shader_free(sh);
362}
363DRAW_TEST(eevee_shadow_tag_update)
364
366{
368 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
369 ShadowTileDataBuf tiles_data = {"tiles_data"};
370 ShadowPageHeapBuf pages_free_data = {"PagesFreeBuf"};
371 ShadowPageCacheBuf pages_cached_data = {"PagesCachedBuf"};
372 ShadowPagesInfoDataBuf pages_infos_data = {"PagesInfosBuf"};
373
374 int tiles_index = 1;
375 int tile_orphaned_cached = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 5;
376 int tile_orphaned_allocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 6;
377 int tile_used_cached = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 260;
378 int tile_used_allocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 32;
379 int tile_used_unallocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 64;
380 int tile_unused_cached = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 9;
381 int tile_unused_allocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 8;
382 int page_free_count = SHADOW_MAX_PAGE - 6;
383
384 for (uint i : IndexRange(2, page_free_count)) {
385 uint3 page = uint3((i % SHADOW_PAGE_PER_ROW),
388 pages_free_data[i] = shadow_page_pack(page);
389 }
390 pages_free_data.push_update();
391
392 pages_infos_data.page_free_count = page_free_count;
393 pages_infos_data.page_alloc_count = 0;
394 pages_infos_data.page_cached_next = 2u;
395 pages_infos_data.page_cached_start = 0u;
396 pages_infos_data.page_cached_end = 2u;
397 pages_infos_data.push_update();
398
399 for (uint i : IndexRange(pages_cached_data.size())) {
400 pages_cached_data[i] = uint2(-1, -1);
401 }
402 pages_cached_data[0] = uint2(0, tile_orphaned_cached);
403 pages_cached_data[1] = uint2(1, tile_used_cached);
404 pages_cached_data.push_update();
405
406 {
407 ShadowTileData tile = {};
408
409 tiles_data.clear_to_zero();
410 tiles_data.read();
411
412 /* is_orphaned = true */
413 tile.is_used = false;
414 tile.do_update = true;
415
416 tile.is_cached = true;
417 tile.is_allocated = false;
418 tiles_data[tile_orphaned_cached] = shadow_tile_pack(tile);
419
420 tile.is_cached = false;
421 tile.is_allocated = true;
422 tiles_data[tile_orphaned_allocated] = shadow_tile_pack(tile);
423
424 /* is_orphaned = false */
425 tile.do_update = false;
426 tile.is_used = true;
427
428 tile.is_cached = true;
429 tile.is_allocated = false;
430 tiles_data[tile_used_cached] = shadow_tile_pack(tile);
431
432 tile.is_cached = false;
433 tile.is_allocated = true;
434 tiles_data[tile_used_allocated] = shadow_tile_pack(tile);
435
436 tile.is_cached = false;
437 tile.is_allocated = false;
438 tiles_data[tile_used_unallocated] = shadow_tile_pack(tile);
439
440 tile.is_used = false;
441 tile.is_cached = true;
442 tile.is_allocated = false;
443 tiles_data[tile_unused_cached] = shadow_tile_pack(tile);
444
445 tile.is_cached = false;
446 tile.is_allocated = true;
447 tiles_data[tile_unused_allocated] = shadow_tile_pack(tile);
448
449 tiles_data.push_update();
450 }
451 {
452 ShadowTileMapData tilemap = {};
453 tilemap.tiles_index = tiles_index * SHADOW_TILEDATA_PER_TILEMAP;
454 tilemaps_data.append(tilemap);
455 tilemaps_data.push_update();
456 }
457
458 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_page_free");
459
460 PassSimple pass("Test");
461 pass.shader_set(sh);
462 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
463 pass.bind_ssbo("tiles_buf", tiles_data);
464 pass.bind_ssbo("pages_infos_buf", pages_infos_data);
465 pass.bind_ssbo("pages_free_buf", pages_free_data);
466 pass.bind_ssbo("pages_cached_buf", pages_cached_data);
467 pass.dispatch(int3(1, 1, tilemaps_data.size()));
469
470 Manager manager;
471 manager.submit(pass);
472
473 tiles_data.read();
474 pages_infos_data.read();
475
476 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_orphaned_cached]).is_cached, false);
477 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_orphaned_cached]).is_allocated, false);
478 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_orphaned_allocated]).is_cached, false);
479 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_orphaned_allocated]).is_allocated, false);
480 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_cached]).is_cached, false);
481 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_cached]).is_allocated, true);
482 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_allocated]).is_cached, false);
483 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_allocated]).is_allocated, true);
484 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_unallocated]).is_cached, false);
485 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_used_unallocated]).is_allocated, false);
486 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_unused_cached]).is_cached, true);
487 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_unused_cached]).is_allocated, false);
488 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_unused_allocated]).is_cached, true);
489 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_unused_allocated]).is_allocated, false);
490 EXPECT_EQ(pages_infos_data.page_alloc_count, 1);
491 EXPECT_EQ(pages_infos_data.page_free_count, page_free_count + 2);
492 EXPECT_EQ(pages_infos_data.page_cached_next, 3);
493 EXPECT_EQ(pages_infos_data.page_cached_end, 2);
494
496
497 GPU_shader_free(sh);
500}
501DRAW_TEST(eevee_shadow_free)
502
504 private:
505 ShadowTileDataBuf tiles_data = {"tiles_data"};
506 ShadowPageHeapBuf pages_free_data = {"PagesFreeBuf"};
507 ShadowPageCacheBuf pages_cached_data = {"PagesCachedBuf"};
508 ShadowPagesInfoDataBuf pages_infos_data = {"PagesInfosBuf"};
509 StorageBuffer<DispatchCommand> clear_dispatch_buf;
510 StorageBuffer<DrawCommand> tile_draw_buf;
511 ShadowStatisticsBuf statistics_buf = {"statistics_buf"};
512
513 public:
514 TestDefrag(int allocation_count,
515 int descriptor_offset,
517 StringRefNull expect)
518 {
521 pages_free_data[i] = page.x | (page.y << 16u);
522 }
523
524 for (uint i : IndexRange(tiles_data.size())) {
525 tiles_data[i] = 0;
526 }
527
528 int free_count = SHADOW_MAX_PAGE;
529 int tile_index = 0;
530
531 for (uint i : IndexRange(pages_cached_data.size())) {
532 pages_cached_data[i] = uint2(-1, -1);
533 }
534
535 int cached_index = descriptor_offset;
536 int hole_count = 0;
537 int inserted_count = 0;
538 ShadowTileData tile = {};
539 tile.is_cached = true;
540 for (char c : descriptor) {
541 switch (c) {
542 case 'c':
543 tile.cache_index = cached_index++ % SHADOW_MAX_PAGE;
544 pages_cached_data[tile.cache_index] = uint2(pages_free_data[--free_count], tile_index);
545 tiles_data[tile_index++] = shadow_tile_pack(tile);
546 break;
547 case 'f':
548 pages_cached_data[cached_index++ % SHADOW_MAX_PAGE] = uint2(-1, -1);
549 hole_count++;
550 break;
551 case 'i':
552 tile.cache_index = (cached_index + inserted_count++) % SHADOW_MAX_PAGE;
553 pages_cached_data[tile.cache_index] = uint2(pages_free_data[--free_count], tile_index);
554 tiles_data[tile_index++] = shadow_tile_pack(tile);
555 break;
556 default:
557 break;
558 }
559 }
560
561 pages_infos_data.page_alloc_count = allocation_count;
562 pages_infos_data.page_cached_next = cached_index + inserted_count;
563 pages_infos_data.page_free_count = free_count;
564 pages_infos_data.page_cached_start = descriptor_offset;
565 pages_infos_data.page_cached_end = cached_index;
566
567 tiles_data.push_update();
568 pages_infos_data.push_update();
569 pages_free_data.push_update();
570 pages_cached_data.push_update();
571
572 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_page_defrag");
573
574 PassSimple pass("Test");
575 pass.shader_set(sh);
576 pass.bind_ssbo("tiles_buf", tiles_data);
577 pass.bind_ssbo("pages_infos_buf", pages_infos_data);
578 pass.bind_ssbo("pages_free_buf", pages_free_data);
579 pass.bind_ssbo("pages_cached_buf", pages_cached_data);
580 pass.bind_ssbo("clear_dispatch_buf", clear_dispatch_buf);
581 pass.bind_ssbo("tile_draw_buf", tile_draw_buf);
582 pass.bind_ssbo("statistics_buf", statistics_buf);
583 pass.dispatch(int3(1, 1, 1));
585
586 Manager manager;
587 manager.submit(pass);
588
589 tiles_data.read();
590 pages_cached_data.read();
591 pages_infos_data.read();
592
593 std::string result;
594 int expect_cached_len = 0;
595 for (auto i : IndexRange(descriptor_offset, descriptor.size())) {
596 if (pages_cached_data[i % SHADOW_MAX_PAGE].y != -1) {
597 result += 'c';
598 expect_cached_len++;
599 }
600 else {
601 result += 'f';
602 }
603 }
604 EXPECT_EQ(expect, result);
605
606 allocation_count = min_ii(allocation_count, SHADOW_MAX_PAGE);
607
608 int additional_pages = max_ii(0, allocation_count - free_count);
609 int expected_free_count = max_ii(free_count, allocation_count);
610 int expected_start = descriptor_offset + hole_count + additional_pages;
611 int result_cached_len = pages_infos_data.page_cached_end - pages_infos_data.page_cached_start;
612
613 if (expected_start > SHADOW_MAX_PAGE) {
614 expected_start -= SHADOW_MAX_PAGE;
615 }
616
617 EXPECT_EQ(expected_free_count, pages_infos_data.page_free_count);
618 EXPECT_EQ(expected_start, pages_infos_data.page_cached_start);
619 EXPECT_EQ(expect_cached_len, result_cached_len);
620 EXPECT_EQ(pages_infos_data.page_cached_end, pages_infos_data.page_cached_next);
621
623
624 GPU_shader_free(sh);
626 }
627};
628
630{
631 TestDefrag(0, 0, "cfi", "fcc");
632 TestDefrag(0, 0, "fci", "fcc");
633 TestDefrag(0, 47, "ccfcffccfcfciiiii", "fffffcccccccccccc");
634 TestDefrag(10, SHADOW_MAX_PAGE - 5, "ccfcffccfcfciiiii", "fffffcccccccccccc");
635 TestDefrag(SHADOW_MAX_PAGE - 8, 30, "ccfcffccfcfciiiii", "fffffffffcccccccc");
636 TestDefrag(SHADOW_MAX_PAGE - 4, 30, "ccfcffccfcfciiiii", "fffffffffffffcccc");
637 /* Over allocation but should not crash. */
638 TestDefrag(SHADOW_MAX_PAGE + 4, 30, "ccfcffccfcfciiiii", "fffffffffffffffff");
639}
640DRAW_TEST(eevee_shadow_defrag)
641
643 private:
644 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
645 ShadowTileDataBuf tiles_data = {"tiles_data"};
646 ShadowPageHeapBuf pages_free_data = {"PagesFreeBuf"};
647 ShadowPageCacheBuf pages_cached_data = {"PagesCachedBuf"};
648 ShadowPagesInfoDataBuf pages_infos_data = {"PagesInfosBuf"};
649 ShadowStatisticsBuf statistics_buf = {"statistics_buf"};
650
651 public:
652 TestAlloc(int page_free_count)
653 {
655 int tiles_index = 1;
656
657 for (int i : IndexRange(SHADOW_MAX_TILE)) {
658 tiles_data[i] = 0;
659 }
660
661 for (uint i : IndexRange(0, page_free_count)) {
663 pages_free_data[i] = page.x | (page.y << 16u);
664 }
665 pages_free_data.push_update();
666 pages_cached_data.push_update();
667
668 pages_infos_data.page_free_count = page_free_count;
669 pages_infos_data.page_alloc_count = 1;
670 pages_infos_data.page_cached_next = 0u;
671 pages_infos_data.page_cached_start = 0u;
672 pages_infos_data.page_cached_end = 0u;
673 pages_infos_data.push_update();
674
675 statistics_buf.view_needed_count = 0;
676 statistics_buf.push_update();
677
678 int tile_allocated = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 5;
679 int tile_free = tiles_index * SHADOW_TILEDATA_PER_TILEMAP + 6;
680
681 {
682 ShadowTileData tile = {};
683
684 tile.is_used = true;
685 tile.do_update = false;
686
687 tile.is_cached = false;
688 tile.is_allocated = false;
689 tiles_data[tile_free] = shadow_tile_pack(tile);
690
691 tile.is_cached = false;
692 tile.is_allocated = true;
693 tiles_data[tile_allocated] = shadow_tile_pack(tile);
694
695 tiles_data.push_update();
696 }
697 {
698 ShadowTileMapData tilemap = {};
699 tilemap.tiles_index = tiles_index * SHADOW_TILEDATA_PER_TILEMAP;
700 tilemaps_data.append(tilemap);
701 tilemaps_data.push_update();
702 }
703
704 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_page_allocate");
705
706 PassSimple pass("Test");
707 pass.shader_set(sh);
708 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
709 pass.bind_ssbo("tiles_buf", tiles_data);
710 pass.bind_ssbo("pages_infos_buf", pages_infos_data);
711 pass.bind_ssbo("pages_free_buf", pages_free_data);
712 pass.bind_ssbo("pages_cached_buf", pages_cached_data);
713 pass.bind_ssbo("statistics_buf", statistics_buf);
714 pass.dispatch(int3(1, 1, tilemaps_data.size()));
716
717 Manager manager;
718 manager.submit(pass);
719
720 tiles_data.read();
721 pages_infos_data.read();
722
723 bool alloc_success = page_free_count >= 1;
724
725 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_free]).do_update, alloc_success);
726 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_free]).is_allocated, alloc_success);
727 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_allocated]).do_update, false);
728 EXPECT_EQ(shadow_tile_unpack(tiles_data[tile_allocated]).is_allocated, true);
729 EXPECT_EQ(pages_infos_data.page_free_count, page_free_count - 1);
730
732
733 GPU_shader_free(sh);
736 }
737};
738
740{
742 TestAlloc(1);
743 TestAlloc(0);
744}
745DRAW_TEST(eevee_shadow_alloc)
746
748{
750 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
751 ShadowTileDataBuf tiles_data = {"tiles_data"};
752 ShadowPageHeapBuf pages_free_data = {"PagesFreeBuf"};
753 ShadowPageCacheBuf pages_cached_data = {"PagesCachedBuf"};
754 ShadowPagesInfoDataBuf pages_infos_data = {"PagesInfosBuf"};
755 ShadowStatisticsBuf statistics_buf = {"statistics_buf"};
756 ShadowRenderViewBuf render_views_buf = {"render_views_buf"};
758 "tilemaps_clip"};
759
760 const uint lod0_len = SHADOW_TILEMAP_LOD0_LEN;
761 const uint lod1_len = SHADOW_TILEMAP_LOD1_LEN;
762 const uint lod2_len = SHADOW_TILEMAP_LOD2_LEN;
763 const uint lod3_len = SHADOW_TILEMAP_LOD3_LEN;
764 const uint lod4_len = SHADOW_TILEMAP_LOD4_LEN;
765
766 const uint lod0_ofs = 0;
767 const uint lod1_ofs = lod0_len;
768 const uint lod2_ofs = lod1_ofs + lod1_len;
769 const uint lod3_ofs = lod2_ofs + lod2_len;
770 const uint lod4_ofs = lod3_ofs + lod3_len;
771 const uint lod5_ofs = lod4_ofs + lod4_len;
772
774 tiles_data[i] = SHADOW_NO_DATA;
775 }
776
777 {
778 ShadowTileData tile = {};
779 tile.is_used = true;
780 tile.is_allocated = true;
781
782 tile.page = uint3(1, 0, 0);
783 tile.do_update = false;
784 tiles_data[lod0_ofs] = shadow_tile_pack(tile);
785
786 tile.page = uint3(2, 0, 0);
787 tile.do_update = false;
788 tiles_data[lod1_ofs] = shadow_tile_pack(tile);
789
790 tile.page = uint3(3, 0, 0);
791 tile.do_update = true;
792 tiles_data[lod2_ofs] = shadow_tile_pack(tile);
793
794 tile.page = uint3(0, 1, 0);
795 tile.do_update = true;
796 tiles_data[lod3_ofs] = shadow_tile_pack(tile);
797
798 tile.page = uint3(1, 1, 0);
799 tile.do_update = true;
800 tiles_data[lod4_ofs] = shadow_tile_pack(tile);
801
802 tile.page = uint3(2, 1, 0);
803 tile.do_update = true;
804 tiles_data[lod5_ofs] = shadow_tile_pack(tile);
805
806 tile.page = uint3(3, 1, 0);
807 tile.do_update = true;
808 tiles_data[lod0_ofs + 31] = shadow_tile_pack(tile);
809
810 tile.page = uint3(0, 2, 0);
811 tile.do_update = true;
812 tiles_data[lod3_ofs + 8] = shadow_tile_pack(tile);
813
814 tile.page = uint3(1, 2, 0);
815 tile.do_update = true;
816 tiles_data[lod0_ofs + 32 * 16 - 8] = shadow_tile_pack(tile);
817
818 tiles_data.push_update();
819 }
820 {
821 ShadowTileMapData tilemap = {};
822 tilemap.viewmat = float4x4::identity();
823 tilemap.tiles_index = 0;
824 tilemap.clip_data_index = 0;
825 tilemap.clip_far = 10.0f;
826 tilemap.clip_near = 1.0f;
827 tilemap.half_size = 1.0f;
829 tilemaps_data.append(tilemap);
830
831 tilemaps_data.push_update();
832 }
833 {
834 ShadowTileMapClip clip = {};
835 clip.clip_far_stored = 10.0f;
836 clip.clip_near_stored = 1.0f;
837 tilemaps_clip[0] = clip;
838 tilemaps_clip.push_update();
839 }
840 {
841 statistics_buf.view_needed_count = 0;
842 statistics_buf.push_update();
843 }
844 {
845 pages_infos_data.page_free_count = -5;
846 pages_infos_data.page_alloc_count = 0;
847 pages_infos_data.page_cached_next = 0u;
848 pages_infos_data.page_cached_start = 0u;
849 pages_infos_data.page_cached_end = 0u;
850 pages_infos_data.push_update();
851 }
852
853 Texture tilemap_tx = {"tilemap_tx"};
854 tilemap_tx.ensure_2d(GPU_R32UI,
858 tilemap_tx.clear(uint4(0));
859
860 StorageArrayBuffer<ViewMatrices, DRW_VIEW_MAX> shadow_multi_view_buf = {"ShadowMultiView"};
861 StorageBuffer<DispatchCommand> clear_dispatch_buf;
862 StorageBuffer<DrawCommand> tile_draw_buf;
863 StorageArrayBuffer<uint, SHADOW_MAX_PAGE> dst_coord_buf = {"dst_coord_buf"};
864 StorageArrayBuffer<uint, SHADOW_MAX_PAGE> src_coord_buf = {"src_coord_buf"};
865 StorageArrayBuffer<uint, SHADOW_RENDER_MAP_SIZE> render_map_buf = {"render_map_buf"};
866 StorageArrayBuffer<uint, SHADOW_VIEW_MAX> viewport_index_buf = {"viewport_index_buf"};
867
868 render_map_buf.clear_to_zero();
869
870 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tilemap_finalize");
871 PassSimple pass("Test");
872 pass.shader_set(sh);
873 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
874 pass.bind_ssbo("tiles_buf", tiles_data);
875 pass.bind_ssbo("pages_infos_buf", pages_infos_data);
876 pass.bind_ssbo("statistics_buf", statistics_buf);
877 pass.bind_ssbo("view_infos_buf", shadow_multi_view_buf);
878 pass.bind_ssbo("render_view_buf", render_views_buf);
879 pass.bind_ssbo("tilemaps_clip_buf", tilemaps_clip);
880 pass.bind_image("tilemaps_img", tilemap_tx);
881 pass.dispatch(int3(1, 1, tilemaps_data.size()));
883
884 GPUShader *sh2 = GPU_shader_create_from_info_name("eevee_shadow_tilemap_rendermap");
885 pass.shader_set(sh2);
886 pass.bind_ssbo("statistics_buf", statistics_buf);
887 pass.bind_ssbo("render_view_buf", render_views_buf);
888 pass.bind_ssbo("tiles_buf", tiles_data);
889 pass.bind_ssbo("clear_dispatch_buf", clear_dispatch_buf);
890 pass.bind_ssbo("tile_draw_buf", tile_draw_buf);
891 pass.bind_ssbo("dst_coord_buf", &dst_coord_buf);
892 pass.bind_ssbo("src_coord_buf", &src_coord_buf);
893 pass.bind_ssbo("render_map_buf", &render_map_buf);
894 pass.dispatch(int3(1, 1, SHADOW_VIEW_MAX));
896
897 Manager manager;
898 manager.submit(pass);
899
900 {
901 /* Check output views. */
902 shadow_multi_view_buf.read();
903
904 for (auto i : IndexRange(5)) {
905 EXPECT_EQ(shadow_multi_view_buf[i].viewmat, float4x4::identity());
906 EXPECT_EQ(shadow_multi_view_buf[i].viewinv, float4x4::identity());
907 }
908
909 EXPECT_EQ(shadow_multi_view_buf[0].winmat,
910 math::projection::perspective(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 10.0f));
911 EXPECT_EQ(shadow_multi_view_buf[1].winmat,
912 math::projection::perspective(-1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 10.0f));
913 EXPECT_EQ(shadow_multi_view_buf[2].winmat,
914 math::projection::perspective(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 10.0f));
915 EXPECT_EQ(shadow_multi_view_buf[3].winmat,
916 math::projection::perspective(-1.0f, -0.75f, -1.0f, -0.75f, 1.0f, 10.0f));
917 EXPECT_EQ(shadow_multi_view_buf[4].winmat,
918 math::projection::perspective(0.5f, 1.5f, -1.0f, 0.0f, 1.0f, 10.0f));
919 }
920
921 {
922 uint *pixels = tilemap_tx.read<uint32_t>(GPU_DATA_UINT);
923
924 std::string result;
925 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
926 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
928 result += std::to_string(tile.page.x + tile.page.y * SHADOW_PAGE_PER_ROW);
929 }
930 }
931
932 MEM_SAFE_FREE(pixels);
933
935 StringRefNull expected_pages =
936 "12334444555555556666666666666667"
937 "22334444555555556666666666666666"
938 "33334444555555556666666666666666"
939 "33334444555555556666666666666666"
940 "44444444555555556666666666666666"
941 "44444444555555556666666666666666"
942 "44444444555555556666666666666666"
943 "44444444555555556666666666666666"
944 "55555555555555556666666666666666"
945 "55555555555555556666666666666666"
946 "55555555555555556666666666666666"
947 "55555555555555556666666666666666"
948 "55555555555555556666666666666666"
949 "55555555555555556666666666666666"
950 "55555555555555556666666666666666"
951 "55555555555555556666666696666666"
952 "88888888666666666666666666666666"
953 "88888888666666666666666666666666"
954 "88888888666666666666666666666666"
955 "88888888666666666666666666666666"
956 "88888888666666666666666666666666"
957 "88888888666666666666666666666666"
958 "88888888666666666666666666666666"
959 "88888888666666666666666666666666"
960 "66666666666666666666666666666666"
961 "66666666666666666666666666666666"
962 "66666666666666666666666666666666"
963 "66666666666666666666666666666666"
964 "66666666666666666666666666666666"
965 "66666666666666666666666666666666"
966 "66666666666666666666666666666666"
967 "66666666666666666666666666666666";
968
969 EXPECT_EQ(expected_pages, result);
970 }
971
972 {
973 auto stringify_view = [](Span<uint> data) -> std::string {
974 std::string result;
975 for (auto x : data) {
976 result += (x == 0u) ? '-' : ((x == 0xFFFFFFFFu) ? 'x' : '0' + (x % 10));
977 }
978 return result;
979 };
980
982 StringRefNull expected_view0 =
983 "6-------------------------------"
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 "--------------------------------"
1009 "--------------------------------"
1010 "--------------------------------"
1011 "--------------------------------"
1012 "--------------------------------"
1013 "--------------------------------"
1014 "--------------------------------";
1015
1016 StringRefNull expected_view1 =
1017 "5-------------------------------"
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 "--------------------------------"
1043 "--------------------------------"
1044 "--------------------------------"
1045 "--------------------------------"
1046 "--------------------------------"
1047 "--------------------------------"
1048 "--------------------------------";
1049
1050 StringRefNull expected_view2 =
1051 "4xxx----------------------------"
1052 "xxxx----------------------------"
1053 "8xxx----------------------------"
1054 "xxxx----------------------------"
1055 "--------------------------------"
1056 "--------------------------------"
1057 "--------------------------------"
1058 "--------------------------------"
1059 "--------------------------------"
1060 "--------------------------------"
1061 "--------------------------------"
1062 "--------------------------------"
1063 "--------------------------------"
1064 "--------------------------------"
1065 "--------------------------------"
1066 "--------------------------------"
1067 "--------------------------------"
1068 "--------------------------------"
1069 "--------------------------------"
1070 "--------------------------------"
1071 "--------------------------------"
1072 "--------------------------------"
1073 "--------------------------------"
1074 "--------------------------------"
1075 "--------------------------------"
1076 "--------------------------------"
1077 "--------------------------------"
1078 "--------------------------------"
1079 "--------------------------------"
1080 "--------------------------------"
1081 "--------------------------------"
1082 "--------------------------------";
1083
1084 StringRefNull expected_view3 =
1085 "3-------------------------------"
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 "--------------------------------"
1111 "--------------------------------"
1112 "--------------------------------"
1113 "--------------------------------"
1114 "--------------------------------"
1115 "--------------------------------"
1116 "--------------------------------";
1117
1118 StringRefNull expected_view4 =
1119 "xxxxxxx7xxxxxxxx----------------"
1120 "xxxxxxxxxxxxxxxx----------------"
1121 "xxxxxxxxxxxxxxxx----------------"
1122 "xxxxxxxxxxxxxxxx----------------"
1123 "xxxxxxxxxxxxxxxx----------------"
1124 "xxxxxxxxxxxxxxxx----------------"
1125 "xxxxxxxxxxxxxxxx----------------"
1126 "xxxxxxxxxxxxxxxx----------------"
1127 "xxxxxxxxxxxxxxxx----------------"
1128 "xxxxxxxxxxxxxxxx----------------"
1129 "xxxxxxxxxxxxxxxx----------------"
1130 "xxxxxxxxxxxxxxxx----------------"
1131 "xxxxxxxxxxxxxxxx----------------"
1132 "xxxxxxxxxxxxxxxx----------------"
1133 "xxxxxxxxxxxxxxxx----------------"
1134 "9xxxxxxxxxxxxxxx----------------"
1135 "--------------------------------"
1136 "--------------------------------"
1137 "--------------------------------"
1138 "--------------------------------"
1139 "--------------------------------"
1140 "--------------------------------"
1141 "--------------------------------"
1142 "--------------------------------"
1143 "--------------------------------"
1144 "--------------------------------"
1145 "--------------------------------"
1146 "--------------------------------"
1147 "--------------------------------"
1148 "--------------------------------"
1149 "--------------------------------"
1150 "--------------------------------";
1151
1152 render_map_buf.read();
1153
1154 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 0],
1156 expected_view0);
1157 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 1],
1159 expected_view1);
1160 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 2],
1162 expected_view2);
1163 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 3],
1165 expected_view3);
1166 EXPECT_EQ(stringify_view(Span<uint>(&render_map_buf[SHADOW_TILEMAP_LOD0_LEN * 4],
1168 expected_view4);
1169 }
1170
1171 pages_infos_data.read();
1172 EXPECT_EQ(pages_infos_data.page_free_count, 0);
1173
1174 statistics_buf.read();
1175 EXPECT_EQ(statistics_buf.view_needed_count, 5);
1176
1178
1179 GPU_shader_free(sh);
1180 GPU_shader_free(sh2);
1183}
1184DRAW_TEST(eevee_shadow_finalize)
1185
1187{
1188 Vector<uint> test_values{0x00000000u, 0x00000001u, 0x0000000Fu, 0x000000FFu, 0xABCDEF01u,
1189 0xAAAAAAAAu, 0xBBBBBBBBu, 0xCCCCCCCCu, 0xDDDDDDDDu, 0xEEEEEEEEu,
1190 0xFFFFFFFFu, 0xDEADBEEFu, 0x8BADF00Du, 0xABADCAFEu, 0x0D15EA5Eu,
1191 0xFEE1DEADu, 0xDEADC0DEu, 0xC00010FFu, 0xBBADBEEFu, 0xBAAAAAADu};
1192
1193 for (auto value : test_values) {
1196
1199
1200 ShadowTileData expected_tile = shadow_tile_unpack(value);
1201 ShadowTileData result_tile = shadow_tile_unpack(shadow_tile_pack(expected_tile));
1202 EXPECT_EQ(expected_tile.page, result_tile.page);
1203 EXPECT_EQ(expected_tile.cache_index, result_tile.cache_index);
1204 EXPECT_EQ(expected_tile.is_used, result_tile.is_used);
1205 EXPECT_EQ(expected_tile.do_update, result_tile.do_update);
1206 EXPECT_EQ(expected_tile.is_allocated, result_tile.is_allocated);
1207 EXPECT_EQ(expected_tile.is_rendered, result_tile.is_rendered);
1208 EXPECT_EQ(expected_tile.is_cached, result_tile.is_cached);
1209
1210 ShadowSamplingTile expected_sampling_tile = shadow_sampling_tile_unpack(value);
1211 ShadowSamplingTile result_sampling_tile = shadow_sampling_tile_unpack(
1212 shadow_sampling_tile_pack(expected_sampling_tile));
1213 EXPECT_EQ(expected_sampling_tile.page, result_sampling_tile.page);
1214 EXPECT_EQ(expected_sampling_tile.lod, result_sampling_tile.lod);
1215 EXPECT_EQ(expected_sampling_tile.lod_offset, result_sampling_tile.lod_offset);
1216 EXPECT_EQ(expected_sampling_tile.is_valid, result_sampling_tile.is_valid);
1217 }
1218}
1219DRAW_TEST(eevee_shadow_tile_packing)
1220
1222{
1224
1227 tilemap_data.fill(0);
1228
1229 auto pixel_get = [&](int x, int y, int tilemap_index) -> uint32_t & {
1230 /* NOTE: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
1231 return tilemap_data[y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
1232 tilemap_index * SHADOW_TILEMAP_RES];
1233 };
1235 tile.lod = 0;
1236 tile.lod_offset = uint2(0);
1237 tile.is_valid = true;
1238 tile.page = uint3(1, 0, 0);
1239 pixel_get(16, 16, 2) = shadow_sampling_tile_pack(tile);
1240 tile.page = uint3(2, 0, 0);
1241 pixel_get(17, 16, 2) = shadow_sampling_tile_pack(tile);
1242 tile.page = uint3(3, 0, 0);
1243 pixel_get(20, 20, 1) = shadow_sampling_tile_pack(tile);
1244 tile.page = uint3(4, 0, 0);
1245 pixel_get(17, 16, 0) = shadow_sampling_tile_pack(tile);
1246
1247 Texture tilemap_tx = {"tilemap_tx"};
1251 tilemap_tx.ensure_2d(GPU_R32UI, tilemap_res, usage);
1253 tilemap_tx, GPU_DATA_UINT, tilemap_data.data(), 0, 0, 0, tilemap_res.x, tilemap_res.y, 0);
1254
1255 /* Setup one directional light with 3 tilemaps. Fill only the needed data. */
1256 LightData light;
1257 light.type = LIGHT_SUN;
1258 light.sun.clipmap_lod_min = 0;
1259 light.sun.clipmap_lod_max = 2;
1260 /* Shift LOD0 by 1 tile towards bottom. */
1261 light.sun.clipmap_base_offset_neg = int2(0, 1 << 0);
1262 /* Shift LOD1 by 1 tile towards right. */
1263 light.sun.clipmap_base_offset_pos = int2(1 << 1, 0);
1264 light.tilemap_index = 0;
1265
1266 LightDataBuf culling_light_buf = {"Lights_culled"};
1267 culling_light_buf[0] = light;
1268 culling_light_buf.push_update();
1269
1270 LightCullingDataBuf culling_data_buf = {"LightCull_data"};
1271 culling_data_buf.local_lights_len = 0;
1272 culling_data_buf.sun_lights_len = 1;
1273 culling_data_buf.items_count = 1;
1274 culling_data_buf.push_update();
1275
1276 /* Needed for validation. But not used since we use directionals. */
1277 LightCullingZbinBuf culling_zbin_buf = {"LightCull_zbin"};
1278 LightCullingTileBuf culling_tile_buf = {"LightCull_tile"};
1279 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
1280
1281 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_tilemap_amend");
1282
1283 PassSimple pass("Test");
1284 pass.shader_set(sh);
1285 pass.bind_image("tilemaps_img", tilemap_tx);
1286 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
1287 pass.bind_ssbo(LIGHT_CULL_BUF_SLOT, culling_data_buf);
1288 pass.bind_ssbo(LIGHT_BUF_SLOT, culling_light_buf);
1289 pass.bind_ssbo(LIGHT_ZBIN_BUF_SLOT, culling_zbin_buf);
1290 pass.bind_ssbo(LIGHT_TILE_BUF_SLOT, culling_tile_buf);
1291 pass.dispatch(int3(1));
1293
1294 draw::View view("Test");
1295 view.sync(float4x4::identity(),
1296 math::projection::orthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f));
1297
1298 Manager manager;
1299 manager.submit(pass, view);
1300
1301 {
1302 uint *pixels = tilemap_tx.read<uint32_t>(GPU_DATA_UINT);
1303
1304 auto stringify_tilemap = [&](int tilemap_index) -> std::string {
1305 std::string result;
1306 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
1307 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
1308 /* NOTE: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
1309 int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
1310 tilemap_index * SHADOW_TILEMAP_RES;
1312 result += std::to_string(tile.page.x + tile.page.y * SHADOW_PAGE_PER_ROW);
1313 if (x + 1 == SHADOW_TILEMAP_RES / 2) {
1314 result += " ";
1315 }
1316 }
1317 result += "\n";
1318 if (y + 1 == SHADOW_TILEMAP_RES / 2) {
1319 result += "\n";
1320 }
1321 }
1322 return result;
1323 };
1324
1325 auto stringify_lod = [&](int tilemap_index) -> std::string {
1326 std::string result;
1327 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
1328 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
1329 /* NOTE: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
1330 int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
1331 tilemap_index * SHADOW_TILEMAP_RES;
1333 result += std::to_string(tile.lod);
1334 if (x + 1 == SHADOW_TILEMAP_RES / 2) {
1335 result += " ";
1336 }
1337 }
1338 result += "\n";
1339 if (y + 1 == SHADOW_TILEMAP_RES / 2) {
1340 result += "\n";
1341 }
1342 }
1343 return result;
1344 };
1345
1346 auto stringify_offset = [&](int tilemap_index) -> std::string {
1347 std::string result;
1348 for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
1349 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
1350 /* NOTE: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
1351 int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
1352 tilemap_index * SHADOW_TILEMAP_RES;
1354 result += std::to_string(tile.lod_offset.x + tile.lod_offset.y);
1355 if (x + 1 == SHADOW_TILEMAP_RES / 2) {
1356 result += " ";
1357 }
1358 }
1359 result += "\n";
1360 if (y + 1 == SHADOW_TILEMAP_RES / 2) {
1361 result += "\n";
1362 }
1363 }
1364 return result;
1365 };
1366
1368
1369 StringRefNull expected_pages_lod2 =
1370 "0000000000000000 0000000000000000\n"
1371 "0000000000000000 0000000000000000\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 "\n"
1387 "0000000000000000 1200000000000000\n"
1388 "0000000000000000 0000000000000000\n"
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
1404 StringRefNull expected_pages_lod1 =
1405 "0000000000000000 0000000000000000\n"
1406 "0000000000000000 0000000000000000\n"
1407 "0000000000000000 0000000000000000\n"
1408 "0000000000000000 0000000000000000\n"
1409 "0000000000000000 0000000000000000\n"
1410 "0000000000000000 0000000000000000\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 "\n"
1422 "0000000000000001 1220000000000000\n"
1423 "0000000000000001 1220000000000000\n"
1424 "0000000000000000 0000000000000000\n"
1425 "0000000000000000 0000000000000000\n"
1426 "0000000000000000 0000300000000000\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
1439 StringRefNull expected_pages_lod0 =
1440 "0000000000000000 0000000000000000\n"
1441 "0000000000000000 0000000000000000\n"
1442 "0000000000000000 0000000000000000\n"
1443 "0000000000000000 0000000000000000\n"
1444 "0000000000000000 0000000000000000\n"
1445 "0000000000000000 0000000000000000\n"
1446 "0000000000000000 0000000000000000\n"
1447 "0000000000000000 0000000000000000\n"
1448 "0000000000000000 0000000000000000\n"
1449 "0000000000000000 0000000000000000\n"
1450 "0000000000000000 0000000000000000\n"
1451 "0000000000000000 0000000000000000\n"
1452 "0000000000000000 0000000000000000\n"
1453 "0000000000000000 0000000000000000\n"
1454 "0000000000000000 0000000000000000\n"
1455 "0000000000000000 0000000000000000\n"
1456 "\n"
1457 "0000000000000000 0400000000000000\n"
1458 "0000000000000011 1122220000000000\n"
1459 "0000000000000011 1122220000000000\n"
1460 "0000000000000011 1122220000000000\n"
1461 "0000000000000011 1122220000000000\n"
1462 "0000000000000000 0000000000000000\n"
1463 "0000000000000000 0000000000000000\n"
1464 "0000000000000000 0000000000000000\n"
1465 "0000000000000000 0000000000000000\n"
1466 "0000000000000000 0000000033000000\n"
1467 "0000000000000000 0000000033000000\n"
1468 "0000000000000000 0000000000000000\n"
1469 "0000000000000000 0000000000000000\n"
1470 "0000000000000000 0000000000000000\n"
1471 "0000000000000000 0000000000000000\n"
1472 "0000000000000000 0000000000000000\n";
1473
1474 EXPECT_EQ(expected_pages_lod2, stringify_tilemap(2));
1475 EXPECT_EQ(expected_pages_lod1, stringify_tilemap(1));
1476 EXPECT_EQ(expected_pages_lod0, stringify_tilemap(0));
1477
1478 StringRefNull expected_lod_lod0 =
1479 "0000000000000000 0000000000000000\n"
1480 "0000000000000000 0000000000000000\n"
1481 "0000000000000000 0000000000000000\n"
1482 "0000000000000000 0000000000000000\n"
1483 "0000000000000000 0000000000000000\n"
1484 "0000000000000000 0000000000000000\n"
1485 "0000000000000000 0000000000000000\n"
1486 "0000000000000000 0000000000000000\n"
1487 "0000000000000000 0000000000000000\n"
1488 "0000000000000000 0000000000000000\n"
1489 "0000000000000000 0000000000000000\n"
1490 "0000000000000000 0000000000000000\n"
1491 "0000000000000000 0000000000000000\n"
1492 "0000000000000000 0000000000000000\n"
1493 "0000000000000000 0000000000000000\n"
1494 "0000000000000000 0000000000000000\n"
1495 "\n"
1496 "0000000000000000 0000000000000000\n"
1497 "0000000000000022 2222220000000000\n"
1498 "0000000000000022 2222220000000000\n"
1499 "0000000000000022 2222220000000000\n"
1500 "0000000000000022 2222220000000000\n"
1501 "0000000000000000 0000000000000000\n"
1502 "0000000000000000 0000000000000000\n"
1503 "0000000000000000 0000000000000000\n"
1504 "0000000000000000 0000000000000000\n"
1505 "0000000000000000 0000000011000000\n"
1506 "0000000000000000 0000000011000000\n"
1507 "0000000000000000 0000000000000000\n"
1508 "0000000000000000 0000000000000000\n"
1509 "0000000000000000 0000000000000000\n"
1510 "0000000000000000 0000000000000000\n"
1511 "0000000000000000 0000000000000000\n";
1512
1513 EXPECT_EQ(expected_lod_lod0, stringify_lod(0));
1514
1515 /* Offset for each axis are added together in this test. */
1516 StringRefNull expected_offset_lod0 =
1517 "0000000000000000 0000000000000000\n"
1518 "0000000000000000 0000000000000000\n"
1519 "0000000000000000 0000000000000000\n"
1520 "0000000000000000 0000000000000000\n"
1521 "0000000000000000 0000000000000000\n"
1522 "0000000000000000 0000000000000000\n"
1523 "0000000000000000 0000000000000000\n"
1524 "0000000000000000 0000000000000000\n"
1525 "0000000000000000 0000000000000000\n"
1526 "0000000000000000 0000000000000000\n"
1527 "0000000000000000 0000000000000000\n"
1528 "0000000000000000 0000000000000000\n"
1529 "0000000000000000 0000000000000000\n"
1530 "0000000000000000 0000000000000000\n"
1531 "0000000000000000 0000000000000000\n"
1532 "0000000000000000 0000000000000000\n"
1533 "\n"
1534 "0000000000000000 0000000000000000\n"
1535 "0000000000000055 5555550000000000\n"
1536 "0000000000000055 5555550000000000\n"
1537 "0000000000000055 5555550000000000\n"
1538 "0000000000000055 5555550000000000\n"
1539 "0000000000000000 0000000000000000\n"
1540 "0000000000000000 0000000000000000\n"
1541 "0000000000000000 0000000000000000\n"
1542 "0000000000000000 0000000000000000\n"
1543 "0000000000000000 0000000011000000\n"
1544 "0000000000000000 0000000011000000\n"
1545 "0000000000000000 0000000000000000\n"
1546 "0000000000000000 0000000000000000\n"
1547 "0000000000000000 0000000000000000\n"
1548 "0000000000000000 0000000000000000\n"
1549 "0000000000000000 0000000000000000\n";
1550
1551 EXPECT_EQ(expected_offset_lod0, stringify_offset(0));
1552 MEM_SAFE_FREE(pixels);
1553 }
1554
1556
1557 GPU_shader_free(sh);
1560}
1561DRAW_TEST(eevee_shadow_tilemap_amend)
1562
1563static void test_eevee_shadow_page_mask_ex(int max_view_per_tilemap)
1564{
1566 ShadowTileMapDataBuf tilemaps_data = {"tilemaps_data"};
1567 ShadowTileDataBuf tiles_data = {"tiles_data"};
1568
1569 {
1570 ShadowTileMap tilemap(0);
1571 tilemap.sync_cubeface(LIGHT_OMNI_SPHERE, float4x4::identity(), 0.01f, 1.0f, Z_NEG);
1572 tilemaps_data.append(tilemap);
1573 }
1574
1575 const uint lod0_len = SHADOW_TILEMAP_LOD0_LEN;
1576 const uint lod1_len = SHADOW_TILEMAP_LOD1_LEN;
1577 const uint lod2_len = SHADOW_TILEMAP_LOD2_LEN;
1578 const uint lod3_len = SHADOW_TILEMAP_LOD3_LEN;
1579 const uint lod4_len = SHADOW_TILEMAP_LOD4_LEN;
1580 const uint lod5_len = SHADOW_TILEMAP_LOD5_LEN;
1581
1582 const uint lod0_ofs = 0;
1583 const uint lod1_ofs = lod0_ofs + lod0_len;
1584 const uint lod2_ofs = lod1_ofs + lod1_len;
1585 const uint lod3_ofs = lod2_ofs + lod2_len;
1586 const uint lod4_ofs = lod3_ofs + lod3_len;
1587 const uint lod5_ofs = lod4_ofs + lod4_len;
1588
1589 {
1590 ShadowTileData tile = {};
1591 /* Init all LOD to true. */
1593 tile.is_used = true;
1594 tile.do_update = true;
1595 tiles_data[i] = shadow_tile_pack(tile);
1596 }
1597
1598 /* Init all of LOD0 to false. */
1599 for (auto i : IndexRange(square_i(SHADOW_TILEMAP_RES))) {
1600 tile.is_used = false;
1601 tile.do_update = false;
1602 tiles_data[i] = shadow_tile_pack(tile);
1603 }
1604
1605 /* Bottom Left of the LOD0 to true. */
1606 for (auto y : IndexRange((SHADOW_TILEMAP_RES / 2))) {
1607 for (auto x : IndexRange((SHADOW_TILEMAP_RES / 2) + 1)) {
1608 tile.is_used = true;
1609 tile.do_update = true;
1610 tiles_data[x + y * SHADOW_TILEMAP_RES] = shadow_tile_pack(tile);
1611 }
1612 }
1613
1614 /* All Bottom of the LOD0 to true. */
1615 for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
1616 tile.is_used = true;
1617 tile.do_update = true;
1618 tiles_data[x] = shadow_tile_pack(tile);
1619 }
1620
1621 /* Bottom Left of the LOD1 to false. */
1622 /* Should still cover bottom LODs since it is itself fully masked */
1623 for (auto y : IndexRange((SHADOW_TILEMAP_RES / 8))) {
1624 for (auto x : IndexRange((SHADOW_TILEMAP_RES / 8))) {
1625 tile.is_used = false;
1626 tile.do_update = false;
1627 tiles_data[x + y * (SHADOW_TILEMAP_RES / 2) + lod0_len] = shadow_tile_pack(tile);
1628 }
1629 }
1630
1631 /* Top right Center of the LOD1 to false. */
1632 /* Should un-cover 1 LOD2 tile. */
1633 {
1634 int x = SHADOW_TILEMAP_RES / 4;
1635 int y = SHADOW_TILEMAP_RES / 4;
1636 tile.is_used = false;
1637 tile.do_update = false;
1638 tiles_data[x + y * (SHADOW_TILEMAP_RES / 2) + lod0_len] = shadow_tile_pack(tile);
1639 }
1640
1641 tiles_data.push_update();
1642 }
1643
1644 tilemaps_data.push_update();
1645
1646 GPUShader *sh = GPU_shader_create_from_info_name("eevee_shadow_page_mask");
1647
1648 PassSimple pass("Test");
1649 pass.shader_set(sh);
1650 pass.push_constant("max_view_per_tilemap", max_view_per_tilemap);
1651 pass.bind_ssbo("tilemaps_buf", tilemaps_data);
1652 pass.bind_ssbo("tiles_buf", tiles_data);
1653 pass.dispatch(int3(1, 1, tilemaps_data.size()));
1654
1655 Manager manager;
1656 manager.submit(pass);
1658
1659 tiles_data.read();
1660
1662 StringRefNull expected_lod0 =
1663 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
1664 "xxxxxxxxxxxxxxxxx---------------"
1665 "xxxxxxxxxxxxxxxxx---------------"
1666 "xxxxxxxxxxxxxxxxx---------------"
1667 "xxxxxxxxxxxxxxxxx---------------"
1668 "xxxxxxxxxxxxxxxxx---------------"
1669 "xxxxxxxxxxxxxxxxx---------------"
1670 "xxxxxxxxxxxxxxxxx---------------"
1671 "xxxxxxxxxxxxxxxxx---------------"
1672 "xxxxxxxxxxxxxxxxx---------------"
1673 "xxxxxxxxxxxxxxxxx---------------"
1674 "xxxxxxxxxxxxxxxxx---------------"
1675 "xxxxxxxxxxxxxxxxx---------------"
1676 "xxxxxxxxxxxxxxxxx---------------"
1677 "xxxxxxxxxxxxxxxxx---------------"
1678 "xxxxxxxxxxxxxxxxx---------------"
1679 "--------------------------------"
1680 "--------------------------------"
1681 "--------------------------------"
1682 "--------------------------------"
1683 "--------------------------------"
1684 "--------------------------------"
1685 "--------------------------------"
1686 "--------------------------------"
1687 "--------------------------------"
1688 "--------------------------------"
1689 "--------------------------------"
1690 "--------------------------------"
1691 "--------------------------------"
1692 "--------------------------------"
1693 "--------------------------------"
1694 "--------------------------------";
1695 StringRefNull expected_lod1 =
1696 "--------xxxxxxxx"
1697 "--------xxxxxxxx"
1698 "--------xxxxxxxx"
1699 "--------xxxxxxxx"
1700 "--------xxxxxxxx"
1701 "--------xxxxxxxx"
1702 "--------xxxxxxxx"
1703 "--------xxxxxxxx"
1704 "xxxxxxxx-xxxxxxx"
1705 "xxxxxxxxxxxxxxxx"
1706 "xxxxxxxxxxxxxxxx"
1707 "xxxxxxxxxxxxxxxx"
1708 "xxxxxxxxxxxxxxxx"
1709 "xxxxxxxxxxxxxxxx"
1710 "xxxxxxxxxxxxxxxx"
1711 "xxxxxxxxxxxxxxxx";
1712 StringRefNull expected_lod1_collapsed =
1713 "xxxxxxxxxxxxxxxx"
1714 "xxxxxxxxxxxxxxxx"
1715 "xxxxxxxxxxxxxxxx"
1716 "xxxxxxxxxxxxxxxx"
1717 "xxxxxxxxxxxxxxxx"
1718 "xxxxxxxxxxxxxxxx"
1719 "xxxxxxxxxxxxxxxx"
1720 "xxxxxxxxxxxxxxxx"
1721 "xxxxxxxx-xxxxxxx"
1722 "xxxxxxxxxxxxxxxx"
1723 "xxxxxxxxxxxxxxxx"
1724 "xxxxxxxxxxxxxxxx"
1725 "xxxxxxxxxxxxxxxx"
1726 "xxxxxxxxxxxxxxxx"
1727 "xxxxxxxxxxxxxxxx"
1728 "xxxxxxxxxxxxxxxx";
1729 StringRefNull expected_lod2 =
1730 "--------"
1731 "--------"
1732 "--------"
1733 "--------"
1734 "----x---"
1735 "--------"
1736 "--------"
1737 "--------";
1738 StringRefNull expected_lod2_collapsed =
1739 "xxxxxxxx"
1740 "xxxxxxxx"
1741 "xxxxxxxx"
1742 "xxxxxxxx"
1743 "xxxxxxxx"
1744 "xxxxxxxx"
1745 "xxxxxxxx"
1746 "xxxxxxxx";
1747 StringRefNull expected_lod3 =
1748 "----"
1749 "----"
1750 "----"
1751 "----";
1752 StringRefNull expected_lod4 =
1753 "--"
1754 "--";
1755 StringRefNull expected_lod5 = "-";
1756
1757 auto stringify_result = [&](uint start, uint len) -> std::string {
1758 std::string result;
1759 for (auto i : IndexRange(start, len)) {
1760 result += (shadow_tile_unpack(tiles_data[i]).is_used) ? "x" : "-";
1761 }
1762 return result;
1763 };
1764
1765 auto empty_result = [&](uint len) -> std::string {
1766 std::string result;
1767 for ([[maybe_unused]] const int i : IndexRange(len)) {
1768 result += "-";
1769 }
1770 return result;
1771 };
1772
1773 if (max_view_per_tilemap >= 3) {
1774 EXPECT_EQ(stringify_result(lod0_ofs, lod0_len), expected_lod0);
1775 }
1776 else {
1777 EXPECT_EQ(stringify_result(lod0_ofs, lod0_len), empty_result(lod0_len));
1778 }
1779
1780 if (max_view_per_tilemap > 2) {
1781 EXPECT_EQ(stringify_result(lod1_ofs, lod1_len), expected_lod1);
1782 }
1783 else if (max_view_per_tilemap == 2) {
1784 EXPECT_EQ(stringify_result(lod1_ofs, lod1_len), expected_lod1_collapsed);
1785 }
1786 else {
1787 EXPECT_EQ(stringify_result(lod1_ofs, lod1_len), empty_result(lod1_len));
1788 }
1789
1790 if (max_view_per_tilemap > 1) {
1791 EXPECT_EQ(stringify_result(lod2_ofs, lod2_len), expected_lod2);
1792 }
1793 else if (max_view_per_tilemap == 1) {
1794 EXPECT_EQ(stringify_result(lod2_ofs, lod2_len), expected_lod2_collapsed);
1795 }
1796 else {
1797 EXPECT_EQ(stringify_result(lod2_ofs, lod2_len), empty_result(lod2_len));
1798 }
1799 EXPECT_EQ(stringify_result(lod3_ofs, lod3_len), expected_lod3);
1800 EXPECT_EQ(stringify_result(lod4_ofs, lod4_len), expected_lod4);
1801 EXPECT_EQ(stringify_result(lod5_ofs, lod5_len), expected_lod5);
1802
1804
1805 GPU_shader_free(sh);
1808}
1809
1811{
1812 /* Expect default behavior. */
1814 /* Expect default behavior. */
1816 /* Expect LOD0 merged into LOD1. */
1818 /* Expect LOD0 and LOD1 merged into LOD2. */
1820}
1821DRAW_TEST(eevee_shadow_page_mask)
1822
1824{
1825 GTEST_SKIP() << "Result is non-deterministic. To be revisited.";
1826
1828 StorageArrayBuffer<int> list_start_buf = {"list_start_buf"};
1829 StorageVectorBuffer<Surfel> surfel_buf = {"surfel_buf"};
1830 CaptureInfoBuf capture_info_buf = {"capture_info_buf"};
1831 SurfelListInfoBuf list_info_buf = {"list_info_buf"};
1832
1836 {
1837 Surfel surfel;
1838 /* NOTE: Expected link assumes linear increasing processing order [0->5]. But this is
1839 * multithreaded and we can't know the execution order in advance. */
1840 /* 0: Project to (1, 0) = list 1. Unsorted Next = -1; Next = -1; Previous = 3. */
1841 surfel.position = {1.1f, 0.1f, 0.1f};
1842 surfel_buf.append(surfel);
1843 /* 1: Project to (1, 0) = list 1. Unsorted Next = 0; Next = 2; Previous = -1. */
1844 surfel.position = {1.1f, 0.2f, 0.5f};
1845 surfel_buf.append(surfel);
1846 /* 2: Project to (1, 0) = list 1. Unsorted Next = 1; Next = 3; Previous = 1. */
1847 surfel.position = {1.1f, 0.3f, 0.3f};
1848 surfel_buf.append(surfel);
1849 /* 3: Project to (1, 0) = list 1. Unsorted Next = 2; Next = 0; Previous = 2. */
1850 surfel.position = {1.2f, 0.4f, 0.2f};
1851 surfel_buf.append(surfel);
1852 /* 4: Project to (1, 1) = list 3. Unsorted Next = -1; Next = -1; Previous = -1. */
1853 surfel.position = {1.0f, 1.0f, 0.5f};
1854 surfel_buf.append(surfel);
1855 /* 5: Project to (0, 1) = list 2. Unsorted Next = -1; Next = -1; Previous = -1. */
1856 surfel.position = {0.1f, 1.1f, 0.5f};
1857 surfel_buf.append(surfel);
1858
1859 surfel_buf.push_update();
1860 }
1861 {
1862 capture_info_buf.surfel_len = surfel_buf.size();
1863 capture_info_buf.push_update();
1864 }
1865 {
1866 list_info_buf.ray_grid_size = int2(2);
1867 list_info_buf.list_max = list_info_buf.ray_grid_size.x * list_info_buf.ray_grid_size.y;
1868 list_info_buf.push_update();
1869 }
1870 {
1871 list_start_buf.resize(ceil_to_multiple_u(list_info_buf.list_max, 4u));
1872 list_start_buf.push_update();
1873 GPU_storagebuf_clear(list_start_buf, -1);
1874 }
1875
1876 /* Top-down view. */
1877 View view = {"RayProjectionView"};
1879
1880 GPUShader *sh_build = GPU_shader_create_from_info_name("eevee_surfel_list_build");
1881 GPUShader *sh_sort = GPU_shader_create_from_info_name("eevee_surfel_list_sort");
1882
1883 PassSimple pass("Build_and_Sort");
1884 pass.shader_set(sh_build);
1885 pass.bind_ssbo("list_start_buf", list_start_buf);
1886 pass.bind_ssbo("surfel_buf", surfel_buf);
1887 pass.bind_ssbo("capture_info_buf", capture_info_buf);
1888 pass.bind_ssbo("list_info_buf", list_info_buf);
1889 pass.dispatch(int3(1, 1, 1));
1891
1892 pass.shader_set(sh_sort);
1893 pass.bind_ssbo("list_start_buf", list_start_buf);
1894 pass.bind_ssbo("surfel_buf", surfel_buf);
1895 pass.bind_ssbo("list_info_buf", list_info_buf);
1896 pass.dispatch(int3(1, 1, 1));
1898
1899 Manager manager;
1900 manager.submit(pass, view);
1901
1902 list_start_buf.read();
1903 surfel_buf.read();
1904
1905 /* Expect surfel list. */
1906 Vector<int> expect_link_next = {-1, +2, +3, +0, -1, -1};
1907 Vector<int> expect_link_prev = {+3, -1, +1, +2, -1, -1};
1908
1909 Vector<int> link_next, link_prev;
1910 for (const auto &surfel : Span<Surfel>(surfel_buf.data(), surfel_buf.size())) {
1911 link_next.append(surfel.next);
1912 link_prev.append(surfel.prev);
1913 }
1914
1915#if 0 /* Useful for debugging */
1916 /* NOTE: All of these are unstable by definition (atomic + multi-thread).
1917 * But should be consistent since we only dispatch one thread-group. */
1918 /* Expect last added surfel index. It is the list start index before sorting. */
1919 Vector<int> expect_list_start = {-1, 1, 5, 4};
1920 // Span<int>(list_start_buf.data(), expect_list_start.size()).print_as_lines("list_start");
1921 // link_next.as_span().print_as_lines("link_next");
1922 // link_prev.as_span().print_as_lines("link_prev");
1923 EXPECT_EQ_ARRAY(expect_list_start.data(), list_start_buf.data(), expect_list_start.size());
1924#endif
1925 EXPECT_EQ_ARRAY(expect_link_next.data(), link_next.data(), expect_link_next.size());
1926 EXPECT_EQ_ARRAY(expect_link_prev.data(), link_prev.data(), expect_link_prev.size());
1927
1929
1930 GPU_shader_free(sh_build);
1931 GPU_shader_free(sh_sort);
1934}
1935DRAW_TEST(eevee_surfel_list)
1936
1938{
1940
1941 Manager manager;
1942
1943 /* Check if LUT generation matches the header version. */
1944 auto brdf_ggx_gen = Precompute(manager, LUT_GGX_BRDF_SPLIT_SUM, {64, 64, 1}).data<float3>();
1945 auto btdf_ggx_gen = Precompute(manager, LUT_GGX_BTDF_IOR_GT_ONE, {64, 64, 16}).data<float1>();
1946 auto bsdf_ggx_gen = Precompute(manager, LUT_GGX_BSDF_SPLIT_SUM, {64, 64, 16}).data<float3>();
1947 auto burley_gen = Precompute(manager, LUT_BURLEY_SSS_PROFILE, {64, 1, 1}).data<float1>();
1948 auto rand_walk_gen = Precompute(manager, LUT_RANDOM_WALK_SSS_PROFILE, {64, 1, 1}).data<float1>();
1949
1950 Span<float3> brdf_ggx_lut((const float3 *)&eevee::lut::brdf_ggx, 64 * 64);
1951 Span<float1> btdf_ggx_lut((const float1 *)&eevee::lut::btdf_ggx, 64 * 64 * 16);
1952 Span<float3> bsdf_ggx_lut((const float3 *)&eevee::lut::bsdf_ggx, 64 * 64 * 16);
1953 Span<float1> burley_sss_lut((const float1 *)&eevee::lut::burley_sss_profile, 64);
1954 Span<float1> rand_walk_lut((const float1 *)&eevee::lut::random_walk_sss_profile, 64);
1955
1956 const float eps = 3e-3f;
1957 EXPECT_NEAR_ARRAY_ND(brdf_ggx_lut.data(), brdf_ggx_gen.data(), brdf_ggx_gen.size(), 3, eps);
1958 EXPECT_NEAR_ARRAY_ND(btdf_ggx_lut.data(), btdf_ggx_gen.data(), btdf_ggx_gen.size(), 1, eps);
1959 EXPECT_NEAR_ARRAY_ND(bsdf_ggx_lut.data(), bsdf_ggx_gen.data(), bsdf_ggx_gen.size(), 3, eps);
1960 EXPECT_NEAR_ARRAY_ND(burley_gen.data(), burley_sss_lut.data(), burley_sss_lut.size(), 1, eps);
1961 EXPECT_NEAR_ARRAY_ND(rand_walk_gen.data(), rand_walk_lut.data(), rand_walk_lut.size(), 1, eps);
1962
1964}
1965DRAW_TEST(eevee_lut_gen)
1966
1967} // namespace blender::draw
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
static AppView * view
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_shader_unbind()
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:385
@ 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)
@ GPU_R32UI
bool do_update
Definition WM_types.hh:1008
BMesh const char void * data
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
int64_t size() const
void append(const T &value)
void fill(const T &value) const
void begin_sync(Object *object_active=nullptr)
SwapChain< ObjectBoundsBuf, 2 > bounds_buf
void submit(PassSimple &pass, View &view)
ResourceHandleRange 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 bind_image(const char *name, GPUTexture *image)
void dispatch(int group_len)
Definition draw_pass.hh:994
void barrier(eGPUBarrier type)
void push_constant(const char *name, const float &data)
void bind_ssbo(const char *name, GPUStorageBuf *buffer)
void shader_set(GPUShader *shader)
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
#define class
#define MEM_SAFE_FREE(v)
const ccl_global KernelWorkTile * tile
const int tile_index
descriptor
detail::Pass< command::DrawCommandBuf > PassSimple
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()
Definition eevee_test.cc:94
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:23
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]
draw::StorageArrayBuffer< LightData, LIGHT_CHUNK > LightDataBuf
draw::StorageBuffer< ShadowPagesInfoData > ShadowPagesInfoDataBuf
draw::StorageArrayBuffer< ShadowTileDataPacked, SHADOW_MAX_TILE, true > ShadowTileDataBuf
draw::StorageArrayBuffer< ShadowTileMapClip, SHADOW_MAX_TILEMAP, true > ShadowTileMapClipBuf
draw::StorageArrayBuffer< uint, CULLING_ZBIN_COUNT, true > LightCullingZbinBuf
draw::StorageArrayBuffer< uint2, SHADOW_MAX_PAGE, true > ShadowPageCacheBuf
draw::StorageArrayBuffer< uint, LIGHT_CHUNK, true > LightCullingTileBuf
draw::StorageArrayBuffer< ShadowRenderView, SHADOW_VIEW_MAX, true > ShadowRenderViewBuf
draw::StorageBuffer< LightCullingData > LightCullingDataBuf
static ShadowTileDataPacked shadow_tile_pack(ShadowTileData tile)
static ShadowSamplingTilePacked shadow_sampling_tile_pack(ShadowSamplingTile tile)
draw::StorageBuffer< SurfelListInfoData > SurfelListInfoBuf
static ShadowTileData shadow_tile_unpack(ShadowTileDataPacked data)
static uint2 shadow_lod_offset_unpack(uint data)
static uint3 shadow_page_unpack(uint data)
draw::StorageBuffer< CaptureInfoData > CaptureInfoBuf
static uint shadow_page_pack(uint3 page)
static uint shadow_lod_offset_pack(uint2 ofs)
draw::StorageBuffer< ShadowStatistics > ShadowStatisticsBuf
draw::StorageVectorBuffer< ShadowTileMapData, SHADOW_MAX_TILEMAP > ShadowTileMapDataBuf
static ShadowSamplingTile shadow_sampling_tile_unpack(ShadowSamplingTilePacked data)
draw::StorageVectorBuffer< uint, SHADOW_MAX_PAGE > ShadowPageHeapBuf
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< float, 1 > float1
VecBase< uint32_t, 4 > uint4
VecBase< uint32_t, 3 > uint3
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
const btScalar eps
Definition poly34.cpp:11
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))
i
Definition text_draw.cc:230
uint len