diff options
19 files changed, 386 insertions, 203 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index cb25a459534..8d27a492156 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -334,6 +334,8 @@ data_to_c_simple(engines/eevee/shaders/eevee_shadow_debug_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_shadow_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_alloc_comp.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_copy_comp.glsl SRC) +data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_debug_comp.glsl SRC) +data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_defrag_comp.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_free_comp.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_init_comp.glsl SRC) data_to_c_simple(engines/eevee/shaders/eevee_shadow_page_lib.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_shader.cc b/source/blender/draw/engines/eevee/eevee_shader.cc index 6585b3c48b3..e04e3d0bd21 100644 --- a/source/blender/draw/engines/eevee/eevee_shader.cc +++ b/source/blender/draw/engines/eevee/eevee_shader.cc @@ -117,6 +117,8 @@ extern char datatoc_eevee_shadow_debug_frag_glsl[]; extern char datatoc_eevee_shadow_lib_glsl[]; extern char datatoc_eevee_shadow_page_alloc_comp_glsl[]; extern char datatoc_eevee_shadow_page_copy_comp_glsl[]; +extern char datatoc_eevee_shadow_page_debug_comp_glsl[]; +extern char datatoc_eevee_shadow_page_defrag_comp_glsl[]; extern char datatoc_eevee_shadow_page_free_comp_glsl[]; extern char datatoc_eevee_shadow_page_init_comp_glsl[]; extern char datatoc_eevee_shadow_page_lib_glsl[]; @@ -398,6 +400,8 @@ ShaderModule::ShaderModule() SHADER_FULLSCREEN(SHADOW_DEBUG, eevee_shadow_debug_frag); SHADER_COMPUTE(SHADOW_PAGE_ALLOC, eevee_shadow_page_alloc_comp, nullptr); SHADER_COMPUTE(SHADOW_PAGE_COPY, eevee_shadow_page_copy_comp, nullptr); + SHADER_COMPUTE(SHADOW_PAGE_DEBUG, eevee_shadow_page_debug_comp, nullptr); + SHADER_COMPUTE(SHADOW_PAGE_DEFRAG, eevee_shadow_page_defrag_comp, nullptr); SHADER_COMPUTE(SHADOW_PAGE_FREE, eevee_shadow_page_free_comp, nullptr); SHADER_COMPUTE(SHADOW_PAGE_INIT, eevee_shadow_page_init_comp, nullptr); SHADER(SHADOW_PAGE_MARK, eevee_shadow_page_mark_vert, nullptr, eevee_depth_clear_frag, nullptr); diff --git a/source/blender/draw/engines/eevee/eevee_shader.hh b/source/blender/draw/engines/eevee/eevee_shader.hh index 49193a63322..ec7601b97c9 100644 --- a/source/blender/draw/engines/eevee/eevee_shader.hh +++ b/source/blender/draw/engines/eevee/eevee_shader.hh @@ -112,6 +112,8 @@ enum eShaderType { SHADOW_DEBUG, SHADOW_PAGE_ALLOC, SHADOW_PAGE_COPY, + SHADOW_PAGE_DEBUG, + SHADOW_PAGE_DEFRAG, SHADOW_PAGE_FREE, SHADOW_PAGE_INIT, SHADOW_PAGE_MARK, diff --git a/source/blender/draw/engines/eevee/eevee_shader_shared.hh b/source/blender/draw/engines/eevee/eevee_shader_shared.hh index cc5a52ea545..746087ad232 100644 --- a/source/blender/draw/engines/eevee/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee/eevee_shader_shared.hh @@ -483,10 +483,10 @@ BLI_STATIC_ASSERT_ALIGN(ShadowData, 16) * IMPORTANT: Some data packing are tweaked for these values. * Be sure to update them accordingly. * SHADOW_TILEMAP_RES max is 32 because of the shared bitmaps used for LOD tagging. - * It is also limited by the maximum thread group size (1024) + * It is also limited by the maximum thread group size (1024). */ -#define SHADOW_TILEMAP_RES 32 -#define SHADOW_TILEMAP_LOD 5 /* LOG2(SHADOW_TILEMAP_RES) */ +#define SHADOW_TILEMAP_RES 16 +#define SHADOW_TILEMAP_LOD 4 /* LOG2(SHADOW_TILEMAP_RES) */ #define SHADOW_TILEMAP_PER_ROW 64 #define SHADOW_PAGE_COPY_GROUP_SIZE 32 #define SHADOW_DEPTH_SCAN_GROUP_SIZE 32 @@ -515,9 +515,6 @@ static inline vec2 shadow_tile_coord_to_ndc(ivec2 tile) return co * 2.0f - 1.0f; } -/** Expands to ShadowPageData. */ -#define ShadowPagePacked int - /** * Small descriptor used for the tile update phase. */ @@ -932,7 +929,7 @@ using RaytraceDataBuf = StructBuffer<RaytraceData>; using ShadowDataBuf = StorageArrayBuffer<ShadowData, CULLING_BATCH_SIZE>; using ShadowDebugDataBuf = StructBuffer<ShadowDebugData>; using ShadowPagesInfoDataBuf = StorageBuffer<ShadowPagesInfoData, true>; -using ShadowPageHeapBuf = StorageArrayBuffer<ShadowPagePacked, SHADOW_MAX_PAGE, true>; +using ShadowPageHeapBuf = StorageArrayBuffer<uint, SHADOW_MAX_PAGE, true>; using ShadowTileMapDataBuf = StorageArrayBuffer<ShadowTileMapData, SHADOW_MAX_TILEMAP>; using SubsurfaceDataBuf = StructBuffer<SubsurfaceData>; using VelocityObjectBuf = StructBuffer<VelocityObjectData>; diff --git a/source/blender/draw/engines/eevee/eevee_shadow.cc b/source/blender/draw/engines/eevee/eevee_shadow.cc index 0b2b0e991e5..ae026db0efb 100644 --- a/source/blender/draw/engines/eevee/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee/eevee_shadow.cc @@ -610,6 +610,7 @@ void ShadowModule::sync_object(Object *ob, } if (is_alpha_blend) { + printf("receivers_non_opaque_\n"); DRW_buffer_add_entry_struct(receivers_non_opaque_, &shadow_ob.aabb); } } @@ -707,15 +708,19 @@ void ShadowModule::end_sync(void) GPUShader *sh = inst_.shaders.static_shader_get(SHADOW_TILE_SETUP); DRWShadingGroup *grp = DRW_shgroup_create(sh, tilemap_setup_ps_); DRW_shgroup_vertex_buffer(grp, "pages_infos_buf", pages_infos_data_); - DRW_shgroup_vertex_buffer(grp, "pages_buf", pages_data_); + DRW_shgroup_vertex_buffer(grp, "pages_free_buf", pages_free_data_); DRW_shgroup_vertex_buffer(grp, "tilemaps_buf", tilemap_allocator.tilemaps_data); DRW_shgroup_uniform_image(grp, "tilemaps_img", tilemap_allocator.tilemap_tx); int64_t tilemaps_updated_len = tilemaps_len + tilemap_allocator.deleted_maps_len; if (tilemaps_updated_len > 0) { DRW_shgroup_call_compute(grp, 1, 1, tilemaps_updated_len); - DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_SHADER_STORAGE); } do_tilemap_setup_ = true; + + if (G.debug & G_DEBUG_GPU) { + debug_page_map_call(tilemap_setup_ps_); + } } { tilemap_visibility_ps_ = DRW_pass_create("ShadowVisibilityTag", (DRWState)0); @@ -809,9 +814,13 @@ void ShadowModule::end_sync(void) DRWShadingGroup *grp = DRW_shgroup_create(sh, page_init_ps_); DRW_shgroup_vertex_buffer(grp, "pages_infos_buf", pages_infos_data_); DRW_shgroup_vertex_buffer(grp, "pages_free_buf", pages_free_data_); - DRW_shgroup_vertex_buffer(grp, "pages_buf", pages_data_); + DRW_shgroup_uniform_image(grp, "tilemaps_img", tilemap_allocator.tilemap_tx); DRW_shgroup_call_compute(grp, SHADOW_MAX_PAGE / SHADOW_PAGE_PER_ROW, 1, 1); - DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_STORAGE); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_SHADER_STORAGE); + + if (G.debug & G_DEBUG_GPU) { + debug_page_map_call(page_init_ps_); + } } { page_free_ps_ = DRW_pass_create("ShadowPageFree", (DRWState)0); @@ -820,7 +829,6 @@ void ShadowModule::end_sync(void) DRWShadingGroup *grp = DRW_shgroup_create(sh, page_free_ps_); DRW_shgroup_vertex_buffer(grp, "pages_infos_buf", pages_infos_data_); DRW_shgroup_vertex_buffer(grp, "pages_free_buf", pages_free_data_); - DRW_shgroup_vertex_buffer(grp, "pages_buf", pages_data_); DRW_shgroup_vertex_buffer(grp, "tilemaps_buf", tilemap_allocator.tilemaps_data); DRW_shgroup_uniform_image(grp, "tilemaps_img", tilemap_allocator.tilemap_tx); int64_t tilemaps_updated_len = tilemaps_len + tilemap_allocator.deleted_maps_len; @@ -828,6 +836,21 @@ void ShadowModule::end_sync(void) DRW_shgroup_call_compute(grp, 1, 1, tilemaps_updated_len); DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_SHADER_STORAGE); } + + if (G.debug & G_DEBUG_GPU) { + debug_page_map_call(page_free_ps_); + } + } + { + page_defrag_ps_ = DRW_pass_create("ShadowPageDefrag", (DRWState)0); + + GPUShader *sh = inst_.shaders.static_shader_get(SHADOW_PAGE_DEFRAG); + DRWShadingGroup *grp = DRW_shgroup_create(sh, page_defrag_ps_); + DRW_shgroup_vertex_buffer(grp, "pages_free_buf", pages_free_data_); + DRW_shgroup_vertex_buffer(grp, "pages_infos_buf", pages_infos_data_); + DRW_shgroup_uniform_image(grp, "tilemaps_img", tilemap_allocator.tilemap_tx); + DRW_shgroup_call_compute(grp, 1, 1, 1); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_SHADER_STORAGE); } { page_alloc_ps_ = DRW_pass_create("ShadowPageAllocate", (DRWState)0); @@ -836,7 +859,6 @@ void ShadowModule::end_sync(void) DRWShadingGroup *grp = DRW_shgroup_create(sh, page_alloc_ps_); DRW_shgroup_vertex_buffer(grp, "pages_infos_buf", pages_infos_data_); DRW_shgroup_vertex_buffer(grp, "pages_free_buf", pages_free_data_); - DRW_shgroup_vertex_buffer(grp, "pages_buf", pages_data_); DRW_shgroup_vertex_buffer(grp, "tilemaps_buf", tilemap_allocator.tilemaps_data); DRW_shgroup_uniform_image(grp, "tilemaps_img", tilemap_allocator.tilemap_tx); DRW_shgroup_uniform_image(grp, "tilemap_rects_img", tilemap_allocator.tilemap_rects_tx); @@ -847,6 +869,10 @@ void ShadowModule::end_sync(void) barrier |= GPU_BARRIER_TEXTURE_UPDATE; /* Needed for readback. */ DRW_shgroup_barrier(grp, barrier); } + + if (G.debug & G_DEBUG_GPU) { + debug_page_map_call(page_alloc_ps_); + } } { DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS; @@ -877,6 +903,22 @@ void ShadowModule::end_sync(void) debug_end_sync(); } +void ShadowModule::debug_page_map_call(DRWPass *pass) +{ + if (debug_data_.type == SHADOW_DEBUG_NONE) { + return; + } + debug_page_tx_.ensure(SHADOW_PAGE_PER_ROW, SHADOW_PAGE_PER_ROW, 0, GPU_R32UI); + + GPUShader *sh = inst_.shaders.static_shader_get(SHADOW_PAGE_DEBUG); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_vertex_buffer(grp, "pages_free_buf", pages_free_data_); + DRW_shgroup_uniform_image(grp, "tilemaps_img", tilemap_allocator.tilemap_tx); + DRW_shgroup_uniform_image(grp, "debug_img", debug_page_tx_); + DRW_shgroup_call_compute(grp, 1, 1, 1); + DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS | GPU_BARRIER_TEXTURE_FETCH); +} + void ShadowModule::debug_end_sync(void) { debug_draw_ps_ = nullptr; @@ -931,14 +973,23 @@ void ShadowModule::debug_end_sync(void) DRW_STATE_BLEND_CUSTOM; debug_draw_ps_ = DRW_pass_create("ShadowDebugDraw", state); + if (debug_data_.type == SHADOW_DEBUG_PAGE_ALLOCATION) { + debug_page_map_call(debug_draw_ps_); + } + GPUShader *sh = inst_.shaders.static_shader_get(SHADOW_DEBUG); DRWShadingGroup *grp = DRW_shgroup_create(sh, debug_draw_ps_); DRW_shgroup_vertex_buffer(grp, "tilemaps_buf", tilemap_allocator.tilemaps_data); - DRW_shgroup_vertex_buffer(grp, "pages_buf", pages_data_); DRW_shgroup_uniform_texture(grp, "tilemaps_tx", tilemap_allocator.tilemap_tx); DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &input_depth_tx_); DRW_shgroup_uniform_texture(grp, "atlas_tx", atlas_tx_); DRW_shgroup_uniform_block(grp, "debug_block", debug_data_.ubo_get()); + if (debug_data_.type == SHADOW_DEBUG_PAGE_ALLOCATION) { + DRW_shgroup_uniform_texture(grp, "debug_page_tx", debug_page_tx_); + } + else { + DRW_shgroup_uniform_texture(grp, "debug_page_tx", tilemap_allocator.tilemap_tx); + } DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); } } @@ -1020,6 +1071,7 @@ void ShadowModule::set_view(const DRWView *view, GPUTexture *depth_tx) #ifndef SHADOW_DEBUG_NO_CACHING do_page_init_ = false; #endif + tilemap_allocator.tilemap_tx.clear((uint)0); DRW_draw_pass(page_init_ps_); } do_tilemap_setup_ = false; @@ -1037,6 +1089,7 @@ void ShadowModule::set_view(const DRWView *view, GPUTexture *depth_tx) #endif DRW_draw_pass(tilemap_lod_mask_ps_); DRW_draw_pass(page_free_ps_); + DRW_draw_pass(page_defrag_ps_); DRW_draw_pass(page_alloc_ps_); } DRW_stats_group_end(); diff --git a/source/blender/draw/engines/eevee/eevee_shadow.hh b/source/blender/draw/engines/eevee/eevee_shadow.hh index acd6fb61fd3..2bc252d4f8e 100644 --- a/source/blender/draw/engines/eevee/eevee_shadow.hh +++ b/source/blender/draw/engines/eevee/eevee_shadow.hh @@ -241,7 +241,7 @@ struct ShadowTileMap : public ShadowTileMapData { void set_dirty() { - grid_shift = int2(16); + grid_shift = int2(SHADOW_TILEMAP_RES); } void set_updated() @@ -487,8 +487,6 @@ class ShadowModule { eevee::Texture atlas_tx_ = Texture("shadow_atlas_tx_"); - /** Contains mapping from pages to pixel inside the tilemap. */ - ShadowPageHeapBuf pages_data_; /** Pool of unallocated pages waiting to be assigned to specific tiles in the tilemap atlas. */ ShadowPageHeapBuf pages_free_data_; /** Infos for book keeping and debug. */ @@ -496,6 +494,8 @@ class ShadowModule { /** Page buffer clear. This is only done if shadow atlas is reallocated. */ DRWPass *page_init_ps_; + /** Defragment the page free array. */ + DRWPass *page_defrag_ps_; /** Free pages of deleted tiles. You can think of a garbage collection. */ DRWPass *page_free_ps_; /** Allocate pages for new tiles. */ @@ -527,6 +527,8 @@ class ShadowModule { DRWView *debug_view_; /** Debug data sent to GPU. */ ShadowDebugDataBuf debug_data_; + /** Debug texture to check page status. */ + Texture debug_page_tx_ = Texture("debug_page_tx_"); /** \} */ @@ -577,6 +579,7 @@ class ShadowModule { private: void remove_unused(void); + void debug_page_map_call(DRWPass *pass); }; /** \} */ diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_debug_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_debug_frag.glsl index 986f13e6643..99dc6d5ee56 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_shadow_debug_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_debug_frag.glsl @@ -25,11 +25,7 @@ layout(std430, binding = 0) readonly buffer tilemaps_buf ShadowTileMapData tilemaps[]; }; -layout(std430, binding = 1) readonly buffer pages_buf -{ - ShadowPagePacked pages[]; -}; - +uniform usampler2D debug_page_tx; uniform usampler2D tilemaps_tx; uniform sampler2D depth_tx; uniform sampler2D atlas_tx; @@ -52,9 +48,6 @@ vec3 debug_random_color(int v) vec3 debug_tile_state_color(ShadowTileData tile) { - if (tile.is_error) { - return vec3(1, 0, 1); - } if (tile.lod > 0) { return vec3(1, 0.5, 0) * float(tile.lod) / float(SHADOW_TILEMAP_LOD); } @@ -185,24 +178,21 @@ void debug_tile_state(vec3 P) void debug_page_allocation(void) { - ivec2 page = ivec2(gl_FragCoord.xy / pixel_scale); - - if (in_range_inclusive(page, ivec2(0), ivec2(SHADOW_PAGE_PER_ROW - 1))) { - uint page_index = shadow_page_to_index(page); - if (pages[page_index] != SHADOW_PAGE_NO_DATA) { - ShadowPageData page = shadow_page_data_unpack(pages[page_index]); - ShadowTileData tile = shadow_tile_data_unpack(texelFetch(tilemaps_tx, page.tile, 0).x); - if (tile.is_allocated) { - out_color_add = vec4(1, 1, 1, 0); - } - else { - /* There is an error. Page points to a tile that isn't its owner. */ - out_color_add = vec4(1, 0, 0, 0); - } - } - else { - out_color_add = vec4(0, 0, 0, 0); - } + ivec2 page = ivec2(gl_FragCoord.xy / pixel_scale) - 1; + + if (in_range_inclusive(page, ivec2(0), textureSize(debug_page_tx, 0).xy - 1)) { + uint page = texelFetch(debug_page_tx, page, 0).x; + + bool error = (page & 0xFFFFu) != 1u; + bool is_cached = (page & SHADOW_PAGE_IS_CACHED) != 0u; + bool is_needed = (page & SHADOW_PAGE_IS_NEEDED) != 0u; + bool in_heap = (page & SHADOW_PAGE_IN_FREE_HEAP) != 0u; + error = error || (is_cached && !in_heap); + error = error || (is_needed && is_cached); + + vec3 col = vec3(error, is_cached, is_needed); + + out_color_add = vec4(col, 0); out_color_mul = vec4(0); /* Write depth to overlap overlays. */ gl_FragDepth = 0.0; diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_lib.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_lib.glsl index e02ab0817fa..a1657a830ff 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_shadow_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_lib.glsl @@ -54,6 +54,13 @@ float shadow_punctual_depth_get( int tilemap_index = shadow.tilemap_index + face_id; ShadowTileData tile = shadow_tile_load(tilemaps_tx, tile_co, 0, tilemap_index); + /* TODO(fclem): Remove this indirection. But this means having to store another indirection + * table for the pages. */ + if (tile.lod > 0u) { + tile_co >>= int(tile.lod); + tile.page = shadow_tile_load(tilemaps_tx, tile_co, int(tile.lod), tilemap_index).page; + } + float depth = 1.0; if ((tilemap_index <= shadow.tilemap_last) && (tile.is_allocated || tile.lod > 0)) { vec2 shadow_uv = shadow_page_uv_transform(tile.page, tile.lod, uv); diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_alloc_comp.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_alloc_comp.glsl index a50dd495c05..3d217cdfc95 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_alloc_comp.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_alloc_comp.glsl @@ -29,12 +29,7 @@ layout(std430, binding = 0) restrict readonly buffer tilemaps_buf layout(std430, binding = 1) restrict buffer pages_free_buf { - int pages_free[]; -}; - -layout(std430, binding = 2) restrict buffer pages_buf -{ - ShadowPagePacked pages[]; + uint free_page_owners[]; }; layout(std430, binding = 3) restrict buffer pages_infos_buf @@ -51,11 +46,7 @@ void main() int tilemap_idx = tilemap_data.index; int lod_max = tilemap_data.is_cubeface ? SHADOW_TILEMAP_LOD : 0; - /* Used to broadcast the first valid page to all LOD 0 tiles covered by a LOD > 0 page. */ - shared uint page_map[(SHADOW_TILEMAP_RES / 2) * (SHADOW_TILEMAP_RES / 2)]; - - int lod_valid = -1; - uvec2 page_valid; + int lod_valid = 0; for (int lod = lod_max; lod >= 0; lod--) { ivec2 tile_co = ivec2(gl_GlobalInvocationID.xy) >> lod; int tile_index = (SHADOW_TILEMAP_RES / 2) * tile_co.y + tile_co.x; @@ -73,56 +64,38 @@ void main() /** Tile allocation. */ int free_index = atomicAdd(infos.page_free_next, -1); if (free_index >= 0) { - ShadowPageData page; - page.tile = texel; + ivec2 owner_texel = ivec2(unpackUvec2x16(free_page_owners[free_index])); + free_page_owners[free_index] = uint(-1); - int page_index = pages_free[free_index]; - pages[page_index] = shadow_page_data_pack(page); - - pages_free[free_index] = -1; - - tile.page = shadow_page_from_index(page_index); + tile.page = shadow_tile_data_unpack(imageLoad(tilemaps_img, owner_texel).x).page; tile.do_update = true; tile.is_allocated = true; - - if (page_index == -1) { - tile.is_error = true; - tile.is_allocated = false; - } - + tile.is_cached = false; imageStore(tilemaps_img, texel, uvec4(shadow_tile_data_pack(tile))); - } - else { - /* Well, hum ... you blew up your budget! */ - } - } - if (lod > 0) { - /* Use shared variable to broadcast the page. */ - if (tile.is_allocated) { - page_map[tile_index] = shadow_page_to_index(tile.page); + const uint flag = SHADOW_TILE_IS_ALLOCATED | SHADOW_TILE_IS_CACHED; + imageAtomicAnd(tilemaps_img, owner_texel, ~flag); } else { - page_map[tile_index] = uint(-1); + /* Well, hum ... you blew up your budget! */ } } } barrier(); - if (lod > 0) { - /* Save highest quality valid lod for this thread. */ - if (page_map[tile_index] != uint(-1)) { - lod_valid = lod; - page_valid = shadow_page_from_index(int(page_map[tile_index])); - } + /* Save highest quality valid lod for this thread. */ + if (tile.is_visible && tile.is_used) { + lod_valid = lod; } - else if (tile.is_allocated == false && lod_valid != -1) { - /* If the LOD 0 tile is not allocated and one of the lower level is, - * we save a reference to it to avoid 2 load at shading time. */ - tile.lod = uint(lod_valid); - tile.page = page_valid; - imageStore(tilemaps_img, texel, uvec4(shadow_tile_data_pack(tile))); + else if (lod == 0) { + /* If the tile is not used, store the valid LOD level. */ + /* This is tricky because the tile might be processed by another thread doing an allocation. + * So we need to set the LOD using atomics. */ + uint lod_mask = 7u << 12u; + uint lod_store = uint(lod_valid) << 12u; + imageAtomicAnd(tilemaps_img, texel, ~lod_mask); + imageAtomicOr(tilemaps_img, texel, lod_store); } /** Compute area to render and write to buffer for CPU to read. */ diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_debug_comp.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_debug_comp.glsl new file mode 100644 index 00000000000..a2ef545248a --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_debug_comp.glsl @@ -0,0 +1,113 @@ + +/** + * Virtual shadowmapping: Debug pages. + * + * Since pages are only existing if they are attached to a tilemap or the free list, + * this shader will scan every possible position and create a debug map out of it. + * This is nice to inspect the state of the page allocation during the pipeline. + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_shadow_page_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl) + +layout(local_size_x = 8, local_size_y = 8) in; + +layout(std430, binding = 1) readonly restrict buffer pages_free_buf +{ + uint free_page_owners[]; +}; + +layout(r32ui) restrict uniform uimage2D tilemaps_img; + +layout(r32ui) restrict uniform uimage2D debug_img; + +/* Use this as custom channel viewer in renderdoc to inspect debug_img. */ +#if 0 + +layout(binding = 2) uniform usampler2D texUInt2D; +in vec2 uv; +out vec4 color_out; + +void main() +{ + uint page = texture(texUInt2D, uv).x; + + bool error = (page & 0xFFFFu) != 1u; + bool is_cached = (page & SHADOW_PAGE_IS_CACHED) != 0u; + bool is_needed = (page & SHADOW_PAGE_IS_NEEDED) != 0u; + bool in_heap = (page & SHADOW_PAGE_IN_FREE_HEAP) != 0u; + error = error || (is_cached && !in_heap); + error = error || (is_needed && is_cached); + + color_out = vec4(error, is_cached, is_needed, in_heap); +} + +#endif + +void main() +{ + for (int y = 0; y < imageSize(debug_img).y / int(gl_WorkGroupSize.y); y++) { + for (int x = 0; x < imageSize(debug_img).x / int(gl_WorkGroupSize.x); x++) { + ivec2 co = ivec2(x, y) * ivec2(gl_WorkGroupSize.xy) + ivec2(gl_LocalInvocationID.xy); + imageStore(debug_img, co, uvec4(0)); + } + } + + barrier(); + + /* TODO(fclem): We only scan the first line of tilemap, otherwise it is too slow. + * Finish and do it properly one day... */ + for (int y = 0; y < imageSize(tilemaps_img).y / int(gl_WorkGroupSize.y); y++) { + for (int x = 0; x < imageSize(tilemaps_img).x / int(gl_WorkGroupSize.x); x++) { + ivec2 co = ivec2(x, y) * ivec2(gl_WorkGroupSize.xy) + ivec2(gl_LocalInvocationID.xy); + ShadowTileData tile = shadow_tile_data_unpack(imageLoad(tilemaps_img, co).x); + + if (tile.is_allocated) { + /* User count. */ + imageAtomicAdd(debug_img, ivec2(tile.page), 1u); + } + } + } + + barrier(); + + for (int y = 0; y < imageSize(tilemaps_img).y / int(gl_WorkGroupSize.y); y++) { + for (int x = 0; x < imageSize(tilemaps_img).x / int(gl_WorkGroupSize.x); x++) { + ivec2 co = ivec2(x, y) * ivec2(gl_WorkGroupSize.xy) + ivec2(gl_LocalInvocationID.xy); + ShadowTileData tile = shadow_tile_data_unpack(imageLoad(tilemaps_img, co).x); + + if (tile.is_allocated) { + imageAtomicOr(debug_img, ivec2(tile.page), SHADOW_PAGE_ALLOCATED); + if (tile.is_cached) { + imageAtomicOr(debug_img, ivec2(tile.page), SHADOW_PAGE_IS_CACHED); + /* Verify reference. */ + ivec2 ref = ivec2(unpackUvec2x16(free_page_owners[tile.free_page_owner_index])); + if (ref == co) { + imageAtomicOr(debug_img, ivec2(tile.page), SHADOW_PAGE_IN_FREE_HEAP); + } + } + if (tile.is_used && tile.is_visible) { + imageAtomicOr(debug_img, ivec2(tile.page), SHADOW_PAGE_IS_NEEDED); + } + if (tile.do_update) { + imageAtomicOr(debug_img, ivec2(tile.page), SHADOW_PAGE_DO_UPDATE); + } + } + } + } + +#if 0 + for (int x = 0; x < SHADOW_MAX_PAGE; x++) { + if (free_page_owners[x] != uint(-1)) { + uvec2 owner = unpackUvec2x16(free_page_owners[x]); + uvec2 page = shadow_tile_data_unpack(imageLoad(tilemaps_img, ivec2(owner)).x).page; + /* User count. */ + imageAtomicAdd(debug_img, ivec2(page), 1u); + + imageAtomicOr(debug_img, ivec2(page), SHADOW_PAGE_IN_FREE_HEAP); + } + } +#endif +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_defrag_comp.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_defrag_comp.glsl new file mode 100644 index 00000000000..30f0f1e8925 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_defrag_comp.glsl @@ -0,0 +1,59 @@ + +/** + * Virtual shadowmapping: Defrag. + * + * Defragment the free page owner heap making one continuous array. + */ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_shadow_page_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl) + +layout(local_size_x = 1) in; + +layout(std430, binding = 1) restrict buffer pages_free_buf +{ + uint free_page_owners[]; +}; + +layout(std430, binding = 3) restrict buffer pages_infos_buf +{ + ShadowPagesInfoData infos; +}; + +layout(r32ui) restrict uniform uimage2D tilemaps_img; + +void find_last_valid(inout uint last_valid) +{ + for (uint i = last_valid; i > 0u; i--) { + if (free_page_owners[i] != uint(-1)) { + last_valid = i; + break; + } + } +} + +void main() +{ + uint last_valid = uint(infos.page_free_next); + + find_last_valid(last_valid); + + for (uint i = 0u; i < last_valid; i++) { + if (free_page_owners[i] == uint(-1)) { + free_page_owners[i] = free_page_owners[last_valid]; + + /* Update corresponding reference in tile. */ + ivec2 texel = ivec2(unpackUvec2x16(free_page_owners[last_valid])); + ShadowTileData tile = shadow_tile_data_unpack(imageLoad(tilemaps_img, texel).x); + tile.free_page_owner_index = i; + imageStore(tilemaps_img, texel, uvec4(shadow_tile_data_pack(tile))); + + free_page_owners[last_valid] = uint(-1); + find_last_valid(last_valid); + } + } + + infos.page_free_next = int(last_valid); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_free_comp.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_free_comp.glsl index 03e56fe2f5d..4c013ab526c 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_free_comp.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_free_comp.glsl @@ -19,12 +19,7 @@ layout(std430, binding = 0) restrict readonly buffer tilemaps_buf layout(std430, binding = 1) restrict buffer pages_free_buf { - int pages_free[]; -}; - -layout(std430, binding = 2) restrict writeonly buffer pages_buf -{ - ShadowPagePacked pages[]; + uint free_page_owners[]; }; layout(std430, binding = 3) restrict buffer pages_infos_buf @@ -51,31 +46,28 @@ void main() ivec2 texel = shadow_tile_coord_in_atlas(tile_co, tilemap_idx, lod); ShadowTileData tile = shadow_tile_data_unpack(imageLoad(tilemaps_img, texel).x); - if (tile.is_allocated && (!tile.is_visible || !tile.is_used)) { - /* Push page to the free page heap. */ - uint page_index = shadow_page_to_index(tile.page); -#ifdef SHADOW_DEBUG_PAGE_ALLOCATION_ENABLED - pages[page_index] = SHADOW_PAGE_NO_DATA; -#endif - - int free_index = atomicAdd(infos.page_free_next, 1) + 1; - if (free_index < SHADOW_MAX_PAGE) { - pages_free[free_index] = int(page_index); + if (tile.is_allocated) { + if (tile.is_visible && tile.is_used && tile.is_cached) { + /* Try to recover cached tiles. Update flag is kept untouched as content might be valid. */ + free_page_owners[tile.free_page_owner_index] = uint(-1); + tile.is_cached = false; + tile.free_page_owner_index = uint(-1); + imageStore(tilemaps_img, texel, uvec4(shadow_tile_data_pack(tile))); } - else { - /* Well, this should never happen. This would mean some pages were marked - * for deletion multiple times. */ - infos.page_free_next = SHADOW_MAX_PAGE - 1; + else if ((!tile.is_visible || !tile.is_used) && !tile.is_cached) { + /* Push page to the free page heap. */ + int free_index = atomicAdd(infos.page_free_next, 1) + 1; + if (free_index < SHADOW_MAX_PAGE) { + free_page_owners[free_index] = packUvec2x16(uvec2(texel)); + tile.is_cached = true; + tile.free_page_owner_index = uint(free_index); + imageStore(tilemaps_img, texel, uvec4(shadow_tile_data_pack(tile))); + } + else { + /* Well, this should never happen. This would mean some pages were marked + * for deletion multiple times. */ + } } - - tile.is_allocated = false; -#ifdef SHADOW_DEBUG_TILE_ALLOCATION_ENABLED - tile.page = uvec2(0); - tile.is_visible = false; - tile.do_update = false; - tile.is_used = false; -#endif - imageStore(tilemaps_img, texel, uvec4(shadow_tile_data_pack(tile))); } } }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_init_comp.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_init_comp.glsl index 0075bd2be92..adc00a18948 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_init_comp.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_init_comp.glsl @@ -2,21 +2,18 @@ /** * Virtual shadowmapping: Init page buffer. * + * All pages are always owned by tiles. This step init all owners. * This avoid mapping the buffer to host memory. */ #pragma BLENDER_REQUIRE(eevee_shadow_page_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl) layout(local_size_x = SHADOW_PAGE_PER_ROW) in; layout(std430, binding = 1) restrict writeonly buffer pages_free_buf { - int pages_free[]; -}; - -layout(std430, binding = 2) restrict writeonly buffer pages_buf -{ - ShadowPagePacked pages[]; + uint free_page_owners[]; }; layout(std430, binding = 3) restrict writeonly buffer pages_infos_buf @@ -24,15 +21,29 @@ layout(std430, binding = 3) restrict writeonly buffer pages_infos_buf ShadowPagesInfoData infos; }; +layout(r32ui) restrict uniform uimage2D tilemaps_img; + void main() { - infos.page_free_next = SHADOW_MAX_PAGE - 1; - infos.page_free_next_prev = 0; - infos.page_updated_count = 0; - - pages_free[gl_GlobalInvocationID.x] = ShadowPagePacked(gl_GlobalInvocationID.x); - -#ifdef SHADOW_DEBUG_PAGE_ALLOCATION_ENABLED - pages[gl_GlobalInvocationID.x] = SHADOW_PAGE_NO_DATA; -#endif + if (gl_GlobalInvocationID == uvec3(0)) { + infos.page_free_next = SHADOW_MAX_PAGE - 1; + infos.page_free_next_prev = 0; + infos.page_updated_count = 0; + } + + uint page_index = gl_GlobalInvocationID.x; + + ivec2 texel = ivec2(page_index % (SHADOW_TILEMAP_PER_ROW * SHADOW_TILEMAP_RES), + page_index / (SHADOW_TILEMAP_PER_ROW * SHADOW_TILEMAP_RES)); + free_page_owners[page_index] = packUvec2x16(uvec2(texel)); + + /* Start with a blank tile. */ + ShadowTileData tile = shadow_tile_data_unpack(0u); + tile.page = uvec2(page_index % uint(SHADOW_PAGE_PER_ROW), + page_index / uint(SHADOW_PAGE_PER_ROW)); + tile.free_page_owner_index = page_index; + tile.is_allocated = true; + tile.is_cached = true; + tile.do_update = true; + imageStore(tilemaps_img, texel, uvec4(shadow_tile_data_pack(tile))); }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_lib.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_lib.glsl index a4c3d5fd981..4dc95dfd011 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_page_lib.glsl @@ -2,39 +2,11 @@ #pragma BLENDER_REQUIRE(common_math_lib.glsl) #pragma BLENDER_REQUIRE(eevee_shader_shared.hh) -/** Decoded page data structure. */ -struct ShadowPageData { - /** Tile inside the tilemap atlas. */ - ivec2 tile; -}; - -#define SHADOW_PAGE_NO_DATA 0xFFFFFFFF - -uvec2 shadow_page_from_index(ShadowPagePacked index) -{ - return uvec2(index % SHADOW_PAGE_PER_ROW, index / SHADOW_PAGE_PER_ROW); -} - -uint shadow_page_to_index(uvec2 page) -{ - return page.y * uint(SHADOW_PAGE_PER_ROW) + page.x; -} - -ShadowPageData shadow_page_data_unpack(ShadowPagePacked data) -{ - ShadowPageData page; - page.tile.x = data & 0xFFF; - page.tile.y = (data >> 12) & 0xFFF; - return page; -} - -ShadowPagePacked shadow_page_data_pack(ShadowPageData page) -{ - ShadowPagePacked data; - data = page.tile.x; - data |= page.tile.y << 12; - return data; -} +#define SHADOW_PAGE_ALLOCATED (1u << 16u) +#define SHADOW_PAGE_IS_CACHED (1u << 17u) +#define SHADOW_PAGE_IS_NEEDED (1u << 18u) +#define SHADOW_PAGE_IN_FREE_HEAP (1u << 19u) +#define SHADOW_PAGE_DO_UPDATE (1u << 20u) /** \a unormalized_uv is the uv coordinates for the whole tilemap [0..SHADOW_TILEMAP_RES]. */ vec2 shadow_page_uv_transform(uvec2 page, uint lod, vec2 unormalized_uv) diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_depth_scan_comp.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_depth_scan_comp.glsl index 4f4abc6579a..cdb9a1a4bad 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_depth_scan_comp.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_depth_scan_comp.glsl @@ -97,7 +97,7 @@ void tag_tilemap(uint l_idx, vec3 P, float dist_to_cam, const bool is_directiona tilemap_index += face_id; } - const uint flag = SHADOW_TILE_IS_VISIBLE | SHADOW_TILE_IS_USED; + const uint flag = SHADOW_TILE_IS_USED; shadow_tile_set_flag(tilemaps_img, tile_co, lod, tilemap_index, flag); } diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_lib.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_lib.glsl index 7c8e58f1c78..39553d5eb92 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_lib.glsl @@ -11,6 +11,8 @@ struct ShadowTileData { /** Page inside the virtual shadow map atlas. */ uvec2 page; + /** Page owner index inside free_page_owners heap. Only valid if is_cached is true. */ + uint free_page_owner_index; /** Lod pointed to by LOD 0 tile page. (cubemap only) */ uint lod; /** Set to true during the setup phase if the tile is inside the view frustum. */ @@ -21,11 +23,12 @@ struct ShadowTileData { bool is_allocated; /** True if an update is needed. */ bool do_update; - bool is_error; + /** True if the tile is indexed inside the free_page_owners heap. */ + bool is_cached; }; #define SHADOW_TILE_NO_DATA 0u -#define SHADOW_TILE_IS_ERROR (1u << 27u) +#define SHADOW_TILE_IS_CACHED (1u << 27u) #define SHADOW_TILE_IS_ALLOCATED (1u << 28u) #define SHADOW_TILE_DO_UPDATE (1u << 29u) #define SHADOW_TILE_IS_VISIBLE (1u << 30u) @@ -34,13 +37,17 @@ struct ShadowTileData { ShadowTileData shadow_tile_data_unpack(uint data) { ShadowTileData tile; - tile.page.x = data & 0xFFu; - tile.page.y = (data >> 8u) & 0xFFu; - tile.lod = (data >> 16u) & 0xFu; + /* Tweaked for SHADOW_PAGE_PER_ROW = 64. */ + tile.page.x = data & 63u; + tile.page.y = (data >> 6u) & 63u; + /* Tweaked for SHADOW_TILEMAP_LOD < 8. */ + tile.lod = (data >> 12u) & 7u; + /* Tweaked for SHADOW_MAX_TILEMAP = 4096. */ + tile.free_page_owner_index = (data >> 15u) & 4095u; tile.is_visible = flag_test(data, SHADOW_TILE_IS_VISIBLE); tile.is_used = flag_test(data, SHADOW_TILE_IS_USED); + tile.is_cached = flag_test(data, SHADOW_TILE_IS_CACHED); tile.is_allocated = flag_test(data, SHADOW_TILE_IS_ALLOCATED); - tile.is_error = flag_test(data, SHADOW_TILE_IS_ERROR); tile.do_update = flag_test(data, SHADOW_TILE_DO_UPDATE); return tile; } @@ -49,12 +56,13 @@ uint shadow_tile_data_pack(ShadowTileData tile) { uint data; data = tile.page.x; - data |= tile.page.y << 8u; - data |= tile.lod << 16u; + data |= tile.page.y << 6u; + data |= tile.lod << 12u; + data |= tile.free_page_owner_index << 15u; set_flag_from_test(data, tile.is_visible, SHADOW_TILE_IS_VISIBLE); set_flag_from_test(data, tile.is_used, SHADOW_TILE_IS_USED); set_flag_from_test(data, tile.is_allocated, SHADOW_TILE_IS_ALLOCATED); - set_flag_from_test(data, tile.is_error, SHADOW_TILE_IS_ERROR); + set_flag_from_test(data, tile.is_cached, SHADOW_TILE_IS_CACHED); set_flag_from_test(data, tile.do_update, SHADOW_TILE_DO_UPDATE); return data; } diff --git a/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_setup_comp.glsl b/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_setup_comp.glsl index f4a17662dee..92a0c3d6d14 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_setup_comp.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_shadow_tilemap_setup_comp.glsl @@ -17,9 +17,9 @@ layout(std430, binding = 0) readonly buffer tilemaps_buf ShadowTileMapData tilemaps[]; }; -layout(std430, binding = 2) restrict writeonly buffer pages_buf +layout(std430, binding = 1) restrict buffer pages_free_buf { - ShadowPagePacked pages[]; + uint free_page_owners[]; }; layout(std430, binding = 3) restrict buffer pages_infos_buf @@ -39,56 +39,42 @@ void main() * This way the tile can even be reused if it is needed. Also avoid negative modulo. */ ivec2 tile_wrapped = (tile_shifted + SHADOW_TILEMAP_RES) % SHADOW_TILEMAP_RES; - ivec2 texel = shadow_tile_coord_in_atlas(tile_wrapped, tilemap.index, 0); - ShadowTileData tile_data = shadow_tile_data_unpack(imageLoad(tilemaps_img, texel).x); - /* Reset all flags but keep the allocated page. */ + ivec2 texel_out = shadow_tile_coord_in_atlas(tile_co, tilemap.index, 0); + ivec2 texel_in = shadow_tile_coord_in_atlas(tile_wrapped, tilemap.index, 0); + + ShadowTileData tile_data = shadow_tile_data_unpack(imageLoad(tilemaps_img, texel_in).x); tile_data.is_visible = false; tile_data.is_used = false; - tile_data.do_update = false; tile_data.lod = 0; -#ifdef SHADOW_DEBUG_NO_CACHING - tile_data.page = uvec2(0); - tile_data.is_allocated = false; -#endif if (!in_range_inclusive(tile_shifted, ivec2(0), ivec2(SHADOW_TILEMAP_RES - 1))) { /* This tile was shifted in. */ tile_data.do_update = true; } - if (tilemap.grid_shift.x != 0) { + if (tilemap.grid_shift != ivec2(0) && tile_data.is_cached) { /* Update page location after shift. */ - ShadowPageData page; - page.tile = texel; - pages[shadow_page_to_index(tile_data.page)] = shadow_page_data_pack(page); + free_page_owners[tile_data.free_page_owner_index] = packUvec2x16(uvec2(texel_out)); } - shadow_tile_store(tilemaps_img, tile_co, tilemap.index, tile_data); + imageStore(tilemaps_img, texel_out, uvec4(shadow_tile_data_pack(tile_data))); if (tilemap.is_cubeface) { /* Cubemap shift update is always all or nothing. */ bool do_update = (tilemap.grid_shift.x != 0); /* Number of lod0 tiles covered by the current lod level (in one dimension). */ - uint lod_stride = 1u; - uint lod_size = uint(SHADOW_TILEMAP_RES); - for (int lod = 1; lod <= SHADOW_TILEMAP_LOD; lod++) { - lod_size >>= 1; - lod_stride <<= 1; - + uint lod_stride = 1u << 1u; + uint lod_size = uint(SHADOW_TILEMAP_RES) >> 1u; + for (int lod = 1; lod <= SHADOW_TILEMAP_LOD; lod++, lod_size >>= 1u, lod_stride <<= 1u) { if (all(lessThan(tile_co, ivec2(lod_size)))) { ivec2 texel = shadow_tile_coord_in_atlas(tile_co, tilemap.index, lod); ShadowTileData tile_data = shadow_tile_data_unpack(imageLoad(tilemaps_img, texel).x); - /* Reset all flags but keep the allocated page. */ tile_data.is_visible = false; tile_data.is_used = false; tile_data.do_update = do_update; tile_data.lod = 0; -#ifdef SHADOW_DEBUG_NO_CACHING - tile_data.page = uvec2(0); - tile_data.is_allocated = false; -#endif imageStore(tilemaps_img, texel, uvec4(shadow_tile_data_pack(tile_data))); } } diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 9982a84fabe..58271eba509 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -1208,6 +1208,7 @@ DRWCallBuffer *DRW_call_buffer_create(struct GPUVertFormat *format) GPUVertBuf *DRW_call_buffer_as_vertbuf(DRWCallBuffer *callbuf) { + GPU_vertbuf_data_len_set(callbuf->buf, callbuf->count); return callbuf->buf; } diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index 28943b99929..e2941f1b049 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -139,6 +139,16 @@ uint bit_field_mask(uint bit_width, uint bit_min) return ~mask << bit_min; } +uvec2 unpackUvec2x16(uint data) +{ + return uvec2(data >> 16u, data & 0xFFFFu); +} + +uint packUvec2x16(uvec2 data) +{ + return (data.x << 16u) | (data.y & 0xFFFFu); +} + float distance_squared(vec2 a, vec2 b) { a -= b; |