EEVEE: Shadow: Split Tilemap finalize
This fixes a kernel crash on NVidia GP100. This splits the tilemap finalize shader into another shader and split the valid tile gather into its own loop. Simplifying the shader seems to avoid the issue. But the cause of the issue remains unknown. Pull Request: https://projects.blender.org/blender/blender/pulls/123850
This commit is contained in:
committed by
Clément Foucault
parent
3d17217025
commit
6673302840
@@ -465,6 +465,7 @@ set(GLSL_SRC
|
||||
engines/eevee_next/shaders/eevee_shadow_tilemap_finalize_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_shadow_tilemap_init_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_shadow_tilemap_rendermap_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_spherical_harmonics_lib.glsl
|
||||
engines/eevee_next/shaders/eevee_subsurface_convolve_comp.glsl
|
||||
engines/eevee_next/shaders/eevee_subsurface_lib.glsl
|
||||
|
||||
@@ -310,6 +310,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
|
||||
return "eevee_shadow_tilemap_bounds";
|
||||
case SHADOW_TILEMAP_FINALIZE:
|
||||
return "eevee_shadow_tilemap_finalize";
|
||||
case SHADOW_TILEMAP_RENDERMAP:
|
||||
return "eevee_shadow_tilemap_rendermap";
|
||||
case SHADOW_TILEMAP_INIT:
|
||||
return "eevee_shadow_tilemap_init";
|
||||
case SHADOW_TILEMAP_TAG_UPDATE:
|
||||
|
||||
@@ -125,6 +125,7 @@ enum eShaderType {
|
||||
SHADOW_TILEMAP_AMEND,
|
||||
SHADOW_TILEMAP_BOUNDS,
|
||||
SHADOW_TILEMAP_FINALIZE,
|
||||
SHADOW_TILEMAP_RENDERMAP,
|
||||
SHADOW_TILEMAP_INIT,
|
||||
SHADOW_TILEMAP_TAG_UPDATE,
|
||||
SHADOW_TILEMAP_TAG_USAGE_OPAQUE,
|
||||
|
||||
@@ -1352,6 +1352,12 @@ struct ShadowRenderView {
|
||||
bool32_t is_directional;
|
||||
/** If directional, distance along the negative Z axis of the near clip in view space. */
|
||||
float clip_near;
|
||||
/** Copy of `ShadowTileMapData.tiles_index`. */
|
||||
int tilemap_tiles_index;
|
||||
/** The level of detail of the tilemap this view is rendering. */
|
||||
int tilemap_lod;
|
||||
/** Updated region of the tilemap. */
|
||||
int2 rect_min;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ShadowRenderView, 16)
|
||||
|
||||
|
||||
@@ -1022,23 +1022,33 @@ void ShadowModule::end_sync()
|
||||
/* Convert the unordered tiles into a texture used during shading. Creates views. */
|
||||
PassSimple::Sub &sub = pass.sub("Finalize");
|
||||
sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_FINALIZE));
|
||||
sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
|
||||
sub.bind_ssbo("tilemaps_clip_buf", tilemap_pool.tilemaps_clip);
|
||||
sub.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
|
||||
sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
|
||||
sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
|
||||
sub.bind_ssbo("pages_infos_buf", &pages_infos_data_);
|
||||
sub.bind_ssbo("statistics_buf", &statistics_buf_.current());
|
||||
sub.bind_ssbo("view_infos_buf", &shadow_multi_view_.matrices_ubo_get());
|
||||
sub.bind_ssbo("statistics_buf", statistics_buf_.current());
|
||||
sub.bind_ssbo("clear_dispatch_buf", clear_dispatch_buf_);
|
||||
sub.bind_ssbo("tile_draw_buf", tile_draw_buf_);
|
||||
sub.bind_ssbo("dst_coord_buf", dst_coord_buf_);
|
||||
sub.bind_ssbo("src_coord_buf", src_coord_buf_);
|
||||
sub.bind_ssbo("render_map_buf", render_map_buf_);
|
||||
sub.bind_ssbo("render_view_buf", render_view_buf_);
|
||||
sub.bind_ssbo("pages_infos_buf", pages_infos_data_);
|
||||
sub.bind_image("tilemaps_img", tilemap_pool.tilemap_tx);
|
||||
sub.bind_ssbo("render_view_buf", &render_view_buf_);
|
||||
sub.bind_ssbo("tilemaps_clip_buf", &tilemap_pool.tilemaps_clip);
|
||||
sub.bind_image("tilemaps_img", &tilemap_pool.tilemap_tx);
|
||||
sub.dispatch(int3(1, 1, tilemap_pool.tilemaps_data.size()));
|
||||
sub.barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_UNIFORM | GPU_BARRIER_TEXTURE_FETCH |
|
||||
GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
}
|
||||
{
|
||||
/* Convert the unordered tiles into a texture used during shading. Creates views. */
|
||||
PassSimple::Sub &sub = pass.sub("RenderMap");
|
||||
sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_RENDERMAP));
|
||||
sub.bind_ssbo("statistics_buf", &statistics_buf_.current());
|
||||
sub.bind_ssbo("render_view_buf", &render_view_buf_);
|
||||
sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
|
||||
sub.bind_ssbo("clear_dispatch_buf", &clear_dispatch_buf_);
|
||||
sub.bind_ssbo("tile_draw_buf", &tile_draw_buf_);
|
||||
sub.bind_ssbo("dst_coord_buf", &dst_coord_buf_);
|
||||
sub.bind_ssbo("src_coord_buf", &src_coord_buf_);
|
||||
sub.bind_ssbo("render_map_buf", &render_map_buf_);
|
||||
sub.dispatch(int3(1, 1, SHADOW_VIEW_MAX));
|
||||
sub.barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||
}
|
||||
{
|
||||
/* Amend tilemap_tx content to support clipmap LODs. */
|
||||
PassSimple::Sub &sub = pass.sub("Amend");
|
||||
|
||||
@@ -18,7 +18,7 @@ shared int rect_min_x;
|
||||
shared int rect_min_y;
|
||||
shared int rect_max_x;
|
||||
shared int rect_max_y;
|
||||
shared int view_index;
|
||||
shared uint lod_rendered;
|
||||
|
||||
/**
|
||||
* Select the smallest viewport that can contain the given rect of tiles to render.
|
||||
@@ -36,49 +36,32 @@ int viewport_select(ivec2 rect_size)
|
||||
return power_of_two;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the smallest viewport that can contain the given rect of tiles to render.
|
||||
* Returns the viewport size in tile.
|
||||
*/
|
||||
ivec2 viewport_size_get(int viewport_index)
|
||||
{
|
||||
/* TODO(fclem): Experiment with non squared viewports. */
|
||||
return ivec2(1 << viewport_index);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int tilemap_index = int(gl_GlobalInvocationID.z);
|
||||
ivec2 tile_co = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
uvec2 atlas_texel = shadow_tile_coord_in_atlas(uvec2(tile_co), tilemap_index);
|
||||
|
||||
ShadowTileMapData tilemap_data = tilemaps_buf[tilemap_index];
|
||||
bool is_cubemap = (tilemap_data.projection_type == SHADOW_PROJECTION_CUBEFACE);
|
||||
int lod_max = is_cubemap ? SHADOW_TILEMAP_LOD : 0;
|
||||
int valid_tile_index = -1;
|
||||
uint valid_lod = 0u;
|
||||
/* With all threads (LOD0 size dispatch) load each lod tile from the highest lod
|
||||
* to the lowest, keeping track of the lowest one allocated which will be use for shadowing.
|
||||
* This guarantee a O(1) lookup time.
|
||||
* Add one render view per LOD that has tiles to be rendered. */
|
||||
|
||||
lod_rendered = 0u;
|
||||
|
||||
for (int lod = lod_max; lod >= 0; lod--) {
|
||||
ivec2 tile_co_lod = tile_co >> lod;
|
||||
int tile_index = shadow_tile_offset(uvec2(tile_co_lod), tilemap_data.tiles_index, lod);
|
||||
|
||||
ShadowTileData tile = shadow_tile_unpack(tiles_buf[tile_index]);
|
||||
|
||||
/* Compute update area. */
|
||||
if (gl_LocalInvocationIndex == 0u) {
|
||||
rect_min_x = SHADOW_TILEMAP_RES;
|
||||
rect_min_y = SHADOW_TILEMAP_RES;
|
||||
rect_max_x = 0;
|
||||
rect_max_y = 0;
|
||||
view_index = -1;
|
||||
}
|
||||
|
||||
barrier();
|
||||
|
||||
ShadowTileData tile = shadow_tile_unpack(tiles_buf[tile_index]);
|
||||
bool lod_valid_thread = all(equal(tile_co, tile_co_lod << lod));
|
||||
bool do_page_render = tile.is_used && tile.do_update && lod_valid_thread;
|
||||
if (do_page_render) {
|
||||
@@ -94,14 +77,16 @@ void main()
|
||||
ivec2 rect_max = ivec2(rect_max_x, rect_max_y);
|
||||
|
||||
int viewport_index = viewport_select(rect_max - rect_min);
|
||||
ivec2 viewport_size = viewport_size_get(viewport_index);
|
||||
ivec2 viewport_size = shadow_viewport_size_get(uint(viewport_index));
|
||||
|
||||
/* Issue one view if there is an update in the LOD. */
|
||||
if (gl_LocalInvocationIndex == 0u) {
|
||||
bool lod_has_update = rect_min.x < rect_max.x;
|
||||
if (lod_has_update) {
|
||||
view_index = atomicAdd(statistics_buf.view_needed_count, 1);
|
||||
int view_index = atomicAdd(statistics_buf.view_needed_count, 1);
|
||||
if (view_index < SHADOW_VIEW_MAX) {
|
||||
lod_rendered |= 1u << lod;
|
||||
|
||||
/* Setup the view. */
|
||||
view_infos_buf[view_index].viewmat = tilemap_data.viewmat;
|
||||
view_infos_buf[view_index].viewinv = inverse(tilemap_data.viewmat);
|
||||
@@ -146,45 +131,30 @@ void main()
|
||||
/* Disable local clipping. */
|
||||
render_view_buf[view_index].clip_distance_inv = 0.0;
|
||||
}
|
||||
/* For building the render map. */
|
||||
render_view_buf[view_index].tilemap_tiles_index = tilemap_data.tiles_index;
|
||||
render_view_buf[view_index].tilemap_lod = lod;
|
||||
render_view_buf[view_index].rect_min = rect_min;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
barrier();
|
||||
/* Broadcast result of `lod_rendered`. */
|
||||
barrier();
|
||||
|
||||
bool lod_is_rendered = (view_index >= 0) && (view_index < SHADOW_VIEW_MAX);
|
||||
if (lod_is_rendered && lod_valid_thread) {
|
||||
/* Tile coordinate relative to chosen viewport origin. */
|
||||
ivec2 viewport_tile_co = tile_co_lod - rect_min;
|
||||
/* We need to add page indirection to the render map for the whole viewport even if this one
|
||||
* might extend outside of the shadow-map range. To this end, we need to wrap the threads to
|
||||
* always cover the whole mip. This is because the viewport cannot be bigger than the mip
|
||||
* level itself. */
|
||||
int lod_res = SHADOW_TILEMAP_RES >> lod;
|
||||
ivec2 relative_tile_co = (viewport_tile_co + lod_res) % lod_res;
|
||||
if (all(lessThan(relative_tile_co, viewport_size))) {
|
||||
uint page_packed = shadow_page_pack(tile.page);
|
||||
/* Add page to render map. */
|
||||
int render_page_index = shadow_render_page_index_get(view_index, relative_tile_co);
|
||||
render_map_buf[render_page_index] = do_page_render ? page_packed : 0xFFFFFFFFu;
|
||||
|
||||
if (do_page_render) {
|
||||
/* Tag tile as rendered. There is a barrier after the read. So it is safe. */
|
||||
tiles_buf[tile_index] |= SHADOW_IS_RENDERED;
|
||||
/* Add page to clear dispatch. */
|
||||
uint page_index = atomicAdd(clear_dispatch_buf.num_groups_z, 1u);
|
||||
/* Add page to tile processing. */
|
||||
atomicAdd(tile_draw_buf.vertex_len, 6u);
|
||||
/* Add page mapping for indexing the page position in atlas and in the frame-buffer. */
|
||||
dst_coord_buf[page_index] = page_packed;
|
||||
src_coord_buf[page_index] = packUvec4x8(
|
||||
uvec4(relative_tile_co.x, relative_tile_co.y, view_index, 0));
|
||||
/* Statistics. */
|
||||
atomicAdd(statistics_buf.page_rendered_count, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* With all threads (LOD0 size dispatch) load each lod tile from the highest lod
|
||||
* to the lowest, keeping track of the lowest one allocated which will be use for shadowing.
|
||||
* This guarantee a O(1) lookup time.
|
||||
* Add one render view per LOD that has tiles to be rendered. */
|
||||
int valid_tile_index = -1;
|
||||
uint valid_lod = 0u;
|
||||
for (int lod = lod_max; lod >= 0; lod--) {
|
||||
ivec2 tile_co_lod = tile_co >> lod;
|
||||
int tile_index = shadow_tile_offset(uvec2(tile_co_lod), tilemap_data.tiles_index, lod);
|
||||
ShadowTileData tile = shadow_tile_unpack(tiles_buf[tile_index]);
|
||||
|
||||
bool lod_is_rendered = ((lod_rendered >> lod) & 1u) == 1u;
|
||||
if (tile.is_used && tile.is_allocated && (!tile.do_update || lod_is_rendered)) {
|
||||
/* Save highest lod for this thread. */
|
||||
valid_tile_index = tile_index;
|
||||
@@ -198,6 +168,8 @@ void main()
|
||||
ShadowTileData tile_data = shadow_tile_unpack(tile_packed);
|
||||
ShadowSamplingTile tile_sampling = shadow_sampling_tile_create(tile_data, valid_lod);
|
||||
ShadowSamplingTilePacked tile_sampling_packed = shadow_sampling_tile_pack(tile_sampling);
|
||||
|
||||
uvec2 atlas_texel = shadow_tile_coord_in_atlas(uvec2(tile_co), tilemap_index);
|
||||
imageStore(tilemaps_img, ivec2(atlas_texel), uvec4(tile_sampling_packed));
|
||||
|
||||
if (all(equal(gl_GlobalInvocationID, uvec3(0)))) {
|
||||
|
||||
@@ -6,6 +6,16 @@
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
|
||||
|
||||
/**
|
||||
* Select the smallest viewport that can contain the given rect of tiles to render.
|
||||
* Returns the viewport size in tile.
|
||||
*/
|
||||
ivec2 shadow_viewport_size_get(uint viewport_index)
|
||||
{
|
||||
/* TODO(fclem): Experiment with non squared viewports. */
|
||||
return ivec2(1u << viewport_index);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Tile-map data
|
||||
* \{ */
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/**
|
||||
* Virtual shadow-mapping: Tile-map to render-map conversion.
|
||||
*
|
||||
* For each shadow view, copy page atlas location to the indirection table before render.
|
||||
*/
|
||||
|
||||
#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
int view_index = int(gl_GlobalInvocationID.z);
|
||||
/* Dispatch size if already bounded by SHADOW_VIEW_MAX. */
|
||||
if (view_index >= statistics_buf.view_needed_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
int2 rect_min = render_view_buf[view_index].rect_min;
|
||||
int tilemap_tiles_index = render_view_buf[view_index].tilemap_tiles_index;
|
||||
int lod = render_view_buf[view_index].tilemap_lod;
|
||||
ivec2 viewport_size = shadow_viewport_size_get(render_view_buf[view_index].viewport_index);
|
||||
|
||||
ivec2 tile_co = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 tile_co_lod = tile_co >> lod;
|
||||
bool lod_valid_thread = all(equal(tile_co, tile_co_lod << lod));
|
||||
|
||||
int tile_index = shadow_tile_offset(uvec2(tile_co_lod), tilemap_tiles_index, lod);
|
||||
|
||||
if (lod_valid_thread) {
|
||||
ShadowTileData tile = shadow_tile_unpack(tiles_buf[tile_index]);
|
||||
/* Tile coordinate relative to chosen viewport origin. */
|
||||
ivec2 viewport_tile_co = tile_co_lod - rect_min;
|
||||
/* We need to add page indirection to the render map for the whole viewport even if this one
|
||||
* might extend outside of the shadow-map range. To this end, we need to wrap the threads to
|
||||
* always cover the whole mip. This is because the viewport cannot be bigger than the mip
|
||||
* level itself. */
|
||||
int lod_res = SHADOW_TILEMAP_RES >> lod;
|
||||
ivec2 relative_tile_co = (viewport_tile_co + lod_res) % lod_res;
|
||||
if (all(lessThan(relative_tile_co, viewport_size))) {
|
||||
bool do_page_render = tile.is_used && tile.do_update;
|
||||
uint page_packed = shadow_page_pack(tile.page);
|
||||
/* Add page to render map. */
|
||||
int render_page_index = shadow_render_page_index_get(view_index, relative_tile_co);
|
||||
render_map_buf[render_page_index] = do_page_render ? page_packed : 0xFFFFFFFFu;
|
||||
|
||||
if (do_page_render) {
|
||||
/* Add page to clear dispatch. */
|
||||
uint page_index = atomicAdd(clear_dispatch_buf.num_groups_z, 1u);
|
||||
/* Add page to tile processing. */
|
||||
atomicAdd(tile_draw_buf.vertex_len, 6u);
|
||||
/* Add page mapping for indexing the page position in atlas and in the frame-buffer. */
|
||||
dst_coord_buf[page_index] = page_packed;
|
||||
src_coord_buf[page_index] = packUvec4x8(
|
||||
uvec4(relative_tile_co.x, relative_tile_co.y, view_index, 0));
|
||||
/* Tag tile as rendered. Should be safe since only one thread is reading and writting. */
|
||||
tiles_buf[tile_index] |= SHADOW_IS_RENDERED;
|
||||
/* Statistics. */
|
||||
atomicAdd(statistics_buf.page_rendered_count, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,8 +72,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_surfels)
|
||||
.do_static_compilation(true)
|
||||
.local_group_size(SURFEL_GROUP_SIZE)
|
||||
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
/* ShadowTileDataPacked is uint. But MSL translation need the real type. */
|
||||
.storage_buf(7, Qualifier::READ_WRITE, "uint", "tiles_buf[]")
|
||||
.storage_buf(7, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.push_constant(Type::INT, "directional_level")
|
||||
.additional_info("eevee_shared",
|
||||
"draw_view",
|
||||
@@ -176,22 +175,31 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_finalize)
|
||||
.typedef_source("draw_shader_shared.hh")
|
||||
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
|
||||
.storage_buf(0, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
|
||||
.storage_buf(3, Qualifier::WRITE, "ViewMatrices", "view_infos_buf[SHADOW_VIEW_MAX]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "ShadowStatistics", "statistics_buf")
|
||||
.storage_buf(5, Qualifier::READ_WRITE, "DispatchCommand", "clear_dispatch_buf")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, "DrawCommand", "tile_draw_buf")
|
||||
.storage_buf(7, Qualifier::WRITE, SHADOW_PAGE_PACKED, "dst_coord_buf[SHADOW_RENDER_MAP_SIZE]")
|
||||
.storage_buf(8, Qualifier::WRITE, SHADOW_PAGE_PACKED, "src_coord_buf[SHADOW_RENDER_MAP_SIZE]")
|
||||
.storage_buf(9, Qualifier::WRITE, SHADOW_PAGE_PACKED, "render_map_buf[SHADOW_RENDER_MAP_SIZE]")
|
||||
.storage_buf(10, Qualifier::WRITE, "ShadowRenderView", "render_view_buf[SHADOW_VIEW_MAX]")
|
||||
.storage_buf(11, Qualifier::READ, "ShadowTileMapClip", "tilemaps_clip_buf[]")
|
||||
/* 12 is the minimum number of storage buf we require. Do not go above this limit. */
|
||||
.storage_buf(3, Qualifier::READ_WRITE, "ShadowStatistics", "statistics_buf")
|
||||
.storage_buf(4, Qualifier::WRITE, "ViewMatrices", "view_infos_buf[SHADOW_VIEW_MAX]")
|
||||
.storage_buf(5, Qualifier::WRITE, "ShadowRenderView", "render_view_buf[SHADOW_VIEW_MAX]")
|
||||
.storage_buf(6, Qualifier::READ, "ShadowTileMapClip", "tilemaps_clip_buf[]")
|
||||
.image(0, GPU_R32UI, Qualifier::WRITE, ImageType::UINT_2D, "tilemaps_img")
|
||||
.additional_info("eevee_shared")
|
||||
.compute_source("eevee_shadow_tilemap_finalize_comp.glsl");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_rendermap)
|
||||
.do_static_compilation(true)
|
||||
.typedef_source("draw_shader_shared.hh")
|
||||
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowStatistics", "statistics_buf")
|
||||
.storage_buf(1, Qualifier::READ, "ShadowRenderView", "render_view_buf[SHADOW_VIEW_MAX]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(3, Qualifier::READ_WRITE, "DispatchCommand", "clear_dispatch_buf")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "DrawCommand", "tile_draw_buf")
|
||||
.storage_buf(5, Qualifier::WRITE, SHADOW_PAGE_PACKED, "dst_coord_buf[SHADOW_RENDER_MAP_SIZE]")
|
||||
.storage_buf(6, Qualifier::WRITE, SHADOW_PAGE_PACKED, "src_coord_buf[SHADOW_RENDER_MAP_SIZE]")
|
||||
.storage_buf(7, Qualifier::WRITE, SHADOW_PAGE_PACKED, "render_map_buf[SHADOW_RENDER_MAP_SIZE]")
|
||||
.additional_info("eevee_shared")
|
||||
.compute_source("eevee_shadow_tilemap_rendermap_comp.glsl");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_amend)
|
||||
.do_static_compilation(true)
|
||||
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
|
||||
|
||||
Reference in New Issue
Block a user