EEVEE-Next: Shadow: Add LOD system to directional clipmap shadows #120031

Merged
Clément Foucault merged 16 commits from fclem/blender:eevee-next-shadow-directional-lod into main 2024-03-29 16:23:06 +01:00
4 changed files with 100 additions and 5 deletions
Showing only changes of commit 5c957a34fb - Show all commits

View File

@ -1335,7 +1335,7 @@ static inline uint shadow_lod_offset_pack(uint2 ofs)
}
static inline uint2 shadow_lod_offset_unpack(uint data)
{
return (uint2(data) >> uint2(0u, 7u)) & uint2(7u);
return (uint2(data) >> uint2(0u, 7u)) & uint2(127u);
}
static inline ShadowSamplingTile shadow_sampling_tile_unpack(ShadowSamplingTilePacked data)
@ -1345,7 +1345,7 @@ static inline ShadowSamplingTile shadow_sampling_tile_unpack(ShadowSamplingTileP
/* -- 12 bits -- */
tile.lod = (data >> 12u) & 7u;
/* -- 15 bits -- */
tile.lod_offset = shadow_lod_offset_unpack((data >> 15u) & 14u);
tile.lod_offset = shadow_lod_offset_unpack(data >> 15u);
/* -- 29 bits -- */
/* Only 3 padding bits left. */
tile.is_valid = (data & SHADOW_TILE_IS_VALID) != 0;

View File

@ -61,10 +61,10 @@ void main()
tile_prev.lod += 1;
/* Previous level is now twice as big as this level.
* Double the offset to the valid page. */
tile_prev.lod_offset *= 2;
tile_prev.lod_offset *= 2u;
/* Add the offset of this tile relative to the previous level to the tile data.
* There is only an offset if offset is odd since previous level is twice as big. */
tile_prev.lod_offset += uvec2(not(equal(offset_binary, ivec2(0))));
tile_prev.lod_offset += uint2(offset_centered) & 1u;
tile_prev_packed = shadow_sampling_tile_pack(tile_prev);
/* Replace the missing page with the one from the lower LOD. */

View File

@ -31,7 +31,9 @@ float shadow_read_depth_at_tilemap_uv(int tilemap_index, vec2 tilemap_uv)
if (!tile.is_valid) {
return -1.0;
}
/* Shift LOD0 pixels so that they get wrapped at the right position for the given LOD. */
/* TODO convert everything to uint to avoid signed int operations. */
texel_coord += ivec2(tile.lod_offset << SHADOW_PAGE_LOD);
/* Scale to LOD pixels (merge LOD0 pixels together) then mask to get pixel in page. */
ivec2 texel_page = (texel_coord >> int(tile.lod)) & page_mask;
ivec3 texel = ivec3((ivec2(tile.page.xy) << page_shift) | texel_page, tile.page.z);

View File

@ -1164,6 +1164,41 @@ static void test_eevee_shadow_finalize()
}
DRAW_TEST(eevee_shadow_finalize)
static void test_eevee_shadow_tile_packing()
{
Vector<uint> test_values{0x00000000u, 0x00000001u, 0x0000000Fu, 0x000000FFu, 0xABCDEF01u,
0xAAAAAAAAu, 0xBBBBBBBBu, 0xCCCCCCCCu, 0xDDDDDDDDu, 0xEEEEEEEEu,
0xFFFFFFFFu, 0xDEADBEEFu, 0x8BADF00Du, 0xABADCAFEu, 0x0D15EA5Eu,
0xFEE1DEADu, 0xDEADC0DEu, 0xC00010FFu, 0xBBADBEEFu, 0xBAAAAAADu};
for (auto value : test_values) {
EXPECT_EQ(shadow_page_unpack(value),
shadow_page_unpack(shadow_page_pack(shadow_page_unpack(value))));
EXPECT_EQ(shadow_lod_offset_unpack(value),
shadow_lod_offset_unpack(shadow_lod_offset_pack(shadow_lod_offset_unpack(value))));
ShadowTileData expected_tile = shadow_tile_unpack(value);
ShadowTileData result_tile = shadow_tile_unpack(shadow_tile_pack(expected_tile));
EXPECT_EQ(expected_tile.page, result_tile.page);
EXPECT_EQ(expected_tile.cache_index, result_tile.cache_index);
EXPECT_EQ(expected_tile.is_used, result_tile.is_used);
EXPECT_EQ(expected_tile.do_update, result_tile.do_update);
EXPECT_EQ(expected_tile.is_allocated, result_tile.is_allocated);
EXPECT_EQ(expected_tile.is_rendered, result_tile.is_rendered);
EXPECT_EQ(expected_tile.is_cached, result_tile.is_cached);
ShadowSamplingTile expected_sampling_tile = shadow_sampling_tile_unpack(value);
ShadowSamplingTile result_sampling_tile = shadow_sampling_tile_unpack(
shadow_sampling_tile_pack(expected_sampling_tile));
EXPECT_EQ(expected_sampling_tile.page, result_sampling_tile.page);
EXPECT_EQ(expected_sampling_tile.lod, result_sampling_tile.lod);
EXPECT_EQ(expected_sampling_tile.lod_offset, result_sampling_tile.lod_offset);
EXPECT_EQ(expected_sampling_tile.is_valid, result_sampling_tile.is_valid);
}
}
DRAW_TEST(eevee_shadow_tile_packing)
static void test_eevee_shadow_tilemap_amend()
{
GPU_render_begin();
@ -1283,6 +1318,27 @@ static void test_eevee_shadow_tilemap_amend()
return result;
};
auto stringify_offset = [&](int tilemap_index) -> std::string {
std::string result = "";
for (auto y : IndexRange(SHADOW_TILEMAP_RES)) {
for (auto x : IndexRange(SHADOW_TILEMAP_RES)) {
/* Note: assumes that tilemap_index is < SHADOW_TILEMAP_PER_ROW. */
int tile_ofs = y * SHADOW_TILEMAP_RES * SHADOW_TILEMAP_PER_ROW + x +
tilemap_index * SHADOW_TILEMAP_RES;
ShadowSamplingTile tile = shadow_sampling_tile_unpack(pixels[tile_ofs]);
result += std::to_string(tile.lod_offset.x + tile.lod_offset.y);
if (x + 1 == SHADOW_TILEMAP_RES / 2) {
result += " ";
}
}
result += "\n";
if (y + 1 == SHADOW_TILEMAP_RES / 2) {
result += "\n";
}
}
return result;
};
/** The layout of these expected strings is Y down. */
StringRefNull expected_pages_lod2 =
@ -1431,6 +1487,43 @@ static void test_eevee_shadow_tilemap_amend()
EXPECT_EQ(expected_lod_lod0, stringify_lod(0));
/* Offset for each axis are added together in this test. */
StringRefNull expected_offset_lod0 =
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"\n"
"0000000000000000 0000000000000000\n"
"0000000000000033 3333330000000000\n"
"0000000000000033 3333330000000000\n"
"0000000000000033 3333330000000000\n"
"0000000000000033 3333330000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000011000000\n"
"0000000000000000 0000000011000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n"
"0000000000000000 0000000000000000\n";
EXPECT_EQ(expected_offset_lod0, stringify_offset(0));
MEM_SAFE_FREE(pixels);
}