Shadow map rendering optimization
-All shadow rendering is done with raster now (no compute) -All shadow rendering is done by rendering directly to the shadow atlas -Improved how buffer clearing is done to optimize the above. -Ability to set shadows as 16 bits.
This commit is contained in:
parent
6fe342478b
commit
a9beb7aa8c
29 changed files with 330 additions and 292 deletions
|
|
@ -3564,13 +3564,28 @@ RID RendererSceneRenderRD::shadow_atlas_create() {
|
|||
return shadow_atlas_owner.make_rid(ShadowAtlas());
|
||||
}
|
||||
|
||||
void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size) {
|
||||
void RendererSceneRenderRD::_update_shadow_atlas(ShadowAtlas *shadow_atlas) {
|
||||
if (shadow_atlas->size > 0 && shadow_atlas->depth.is_null()) {
|
||||
RD::TextureFormat tf;
|
||||
tf.format = shadow_atlas->use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT;
|
||||
tf.width = shadow_atlas->size;
|
||||
tf.height = shadow_atlas->size;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
Vector<RID> fb_tex;
|
||||
fb_tex.push_back(shadow_atlas->depth);
|
||||
shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb_tex);
|
||||
}
|
||||
}
|
||||
|
||||
void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
|
||||
ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
|
||||
ERR_FAIL_COND(!shadow_atlas);
|
||||
ERR_FAIL_COND(p_size < 0);
|
||||
p_size = next_power_of_2(p_size);
|
||||
|
||||
if (p_size == shadow_atlas->size) {
|
||||
if (p_size == shadow_atlas->size && p_16_bits == shadow_atlas->use_16_bits) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3597,16 +3612,7 @@ void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size) {
|
|||
shadow_atlas->shadow_owners.clear();
|
||||
|
||||
shadow_atlas->size = p_size;
|
||||
|
||||
if (shadow_atlas->size) {
|
||||
RD::TextureFormat tf;
|
||||
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
|
||||
tf.width = shadow_atlas->size;
|
||||
tf.height = shadow_atlas->size;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
|
||||
shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
}
|
||||
shadow_atlas->use_16_bits = p_size;
|
||||
}
|
||||
|
||||
void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
|
||||
|
|
@ -3861,10 +3867,24 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i
|
|||
return false;
|
||||
}
|
||||
|
||||
void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size) {
|
||||
void RendererSceneRenderRD::_update_directional_shadow_atlas() {
|
||||
if (directional_shadow.depth.is_null() && directional_shadow.size > 0) {
|
||||
RD::TextureFormat tf;
|
||||
tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT;
|
||||
tf.width = directional_shadow.size;
|
||||
tf.height = directional_shadow.size;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
Vector<RID> fb_tex;
|
||||
fb_tex.push_back(directional_shadow.depth);
|
||||
directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb_tex);
|
||||
}
|
||||
}
|
||||
void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
|
||||
p_size = nearest_power_of_2_templated(p_size);
|
||||
|
||||
if (directional_shadow.size == p_size) {
|
||||
if (directional_shadow.size == p_size && directional_shadow.use_16_bits == p_16_bits) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3874,19 +3894,8 @@ void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size) {
|
|||
RD::get_singleton()->free(directional_shadow.depth);
|
||||
_clear_shadow_shrink_stages(directional_shadow.shrink_stages);
|
||||
directional_shadow.depth = RID();
|
||||
_base_uniforms_changed();
|
||||
}
|
||||
|
||||
if (p_size > 0) {
|
||||
RD::TextureFormat tf;
|
||||
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
|
||||
tf.width = p_size;
|
||||
tf.height = p_size;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
|
||||
|
||||
directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
}
|
||||
|
||||
_base_uniforms_changed();
|
||||
}
|
||||
|
||||
void RendererSceneRenderRD::set_directional_shadow_count(int p_count) {
|
||||
|
|
@ -4056,29 +4065,6 @@ RendererSceneRenderRD::ShadowCubemap *RendererSceneRenderRD::_get_shadow_cubemap
|
|||
return &shadow_cubemaps[p_size];
|
||||
}
|
||||
|
||||
RendererSceneRenderRD::ShadowMap *RendererSceneRenderRD::_get_shadow_map(const Size2i &p_size) {
|
||||
if (!shadow_maps.has(p_size)) {
|
||||
ShadowMap sm;
|
||||
{
|
||||
RD::TextureFormat tf;
|
||||
tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
|
||||
tf.width = p_size.width;
|
||||
tf.height = p_size.height;
|
||||
tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
|
||||
|
||||
sm.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
}
|
||||
|
||||
Vector<RID> fbtex;
|
||||
fbtex.push_back(sm.depth);
|
||||
sm.fb = RD::get_singleton()->framebuffer_create(fbtex);
|
||||
|
||||
shadow_maps[p_size] = sm;
|
||||
}
|
||||
|
||||
return &shadow_maps[p_size];
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
|
||||
RID RendererSceneRenderRD::decal_instance_create(RID p_decal) {
|
||||
|
|
@ -7456,26 +7442,31 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
ERR_FAIL_COND(!light_instance);
|
||||
|
||||
Rect2i atlas_rect;
|
||||
RID atlas_texture;
|
||||
uint32_t atlas_size;
|
||||
RID atlas_fb;
|
||||
|
||||
bool using_dual_paraboloid = false;
|
||||
bool using_dual_paraboloid_flip = false;
|
||||
float znear = 0;
|
||||
float zfar = 0;
|
||||
RID render_fb;
|
||||
RID render_texture;
|
||||
float bias = 0;
|
||||
float normal_bias = 0;
|
||||
float zfar;
|
||||
|
||||
bool use_pancake = false;
|
||||
bool use_linear_depth = false;
|
||||
bool render_cubemap = false;
|
||||
bool finalize_cubemap = false;
|
||||
|
||||
bool flip_y = false;
|
||||
|
||||
CameraMatrix light_projection;
|
||||
Transform light_transform;
|
||||
|
||||
bool clear_region = true;
|
||||
bool begin_texture = true;
|
||||
bool end_texture = true;
|
||||
|
||||
if (storage->light_get_type(light_instance->light) == RS::LIGHT_DIRECTIONAL) {
|
||||
_update_directional_shadow_atlas();
|
||||
|
||||
//set pssm stuff
|
||||
if (light_instance->last_scene_shadow_pass != scene_pass) {
|
||||
light_instance->directional_rect = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light);
|
||||
|
|
@ -7492,6 +7483,7 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
atlas_rect.size.width = light_instance->directional_rect.size.x;
|
||||
atlas_rect.size.height = light_instance->directional_rect.size.y;
|
||||
|
||||
int pass_count = 1;
|
||||
if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
|
||||
atlas_rect.size.width /= 2;
|
||||
atlas_rect.size.height /= 2;
|
||||
|
|
@ -7504,7 +7496,7 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
atlas_rect.position.x += atlas_rect.size.width;
|
||||
atlas_rect.position.y += atlas_rect.size.height;
|
||||
}
|
||||
|
||||
pass_count = 4;
|
||||
} else if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
|
||||
atlas_rect.size.height /= 2;
|
||||
|
||||
|
|
@ -7512,6 +7504,7 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
} else {
|
||||
atlas_rect.position.y += atlas_rect.size.height;
|
||||
}
|
||||
pass_count = 2;
|
||||
}
|
||||
|
||||
light_instance->shadow_transform[p_pass].atlas_rect = atlas_rect;
|
||||
|
|
@ -7519,15 +7512,15 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
light_instance->shadow_transform[p_pass].atlas_rect.position /= directional_shadow.size;
|
||||
light_instance->shadow_transform[p_pass].atlas_rect.size /= directional_shadow.size;
|
||||
|
||||
float bias_mult = light_instance->shadow_transform[p_pass].bias_scale;
|
||||
zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE);
|
||||
bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_mult;
|
||||
normal_bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * bias_mult;
|
||||
|
||||
ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size);
|
||||
render_fb = shadow_map->fb;
|
||||
render_texture = shadow_map->depth;
|
||||
atlas_texture = directional_shadow.depth;
|
||||
render_fb = directional_shadow.fb;
|
||||
render_texture = RID();
|
||||
flip_y = true;
|
||||
|
||||
clear_region = false;
|
||||
begin_texture = (directional_shadow.current_light == 1) && (p_pass == 0); //light is 1-index because it was incremented above
|
||||
end_texture = (directional_shadow.current_light == directional_shadow.light_count) && (p_pass == pass_count - 1);
|
||||
|
||||
} else {
|
||||
//set from shadow atlas
|
||||
|
|
@ -7536,6 +7529,8 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
ERR_FAIL_COND(!shadow_atlas);
|
||||
ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light));
|
||||
|
||||
_update_shadow_atlas(shadow_atlas);
|
||||
|
||||
uint32_t key = shadow_atlas->shadow_owners[p_light];
|
||||
|
||||
uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
|
||||
|
|
@ -7554,11 +7549,8 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
|
||||
atlas_rect.size.width = shadow_size;
|
||||
atlas_rect.size.height = shadow_size;
|
||||
atlas_texture = shadow_atlas->depth;
|
||||
|
||||
zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE);
|
||||
bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS);
|
||||
normal_bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS);
|
||||
|
||||
if (storage->light_get_type(light_instance->light) == RS::LIGHT_OMNI) {
|
||||
if (storage->light_omni_get_shadow_mode(light_instance->light) == RS::LIGHT_OMNI_SHADOW_CUBE) {
|
||||
|
|
@ -7571,6 +7563,10 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
light_transform = light_instance->shadow_transform[0].transform;
|
||||
render_cubemap = true;
|
||||
finalize_cubemap = p_pass == 5;
|
||||
atlas_fb = shadow_atlas->fb;
|
||||
|
||||
atlas_size = shadow_atlas->size;
|
||||
clear_region = false;
|
||||
|
||||
} else {
|
||||
light_projection = light_instance->shadow_transform[0].camera;
|
||||
|
|
@ -7581,22 +7577,17 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
|
||||
using_dual_paraboloid = true;
|
||||
using_dual_paraboloid_flip = p_pass == 1;
|
||||
|
||||
ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size);
|
||||
render_fb = shadow_map->fb;
|
||||
render_texture = shadow_map->depth;
|
||||
render_fb = shadow_atlas->fb;
|
||||
flip_y = true;
|
||||
}
|
||||
|
||||
} else if (storage->light_get_type(light_instance->light) == RS::LIGHT_SPOT) {
|
||||
light_projection = light_instance->shadow_transform[0].camera;
|
||||
light_transform = light_instance->shadow_transform[0].transform;
|
||||
|
||||
ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size);
|
||||
render_fb = shadow_map->fb;
|
||||
render_texture = shadow_map->depth;
|
||||
render_fb = shadow_atlas->fb;
|
||||
|
||||
znear = light_instance->shadow_transform[0].camera.get_z_near();
|
||||
use_linear_depth = true;
|
||||
flip_y = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7605,25 +7596,19 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p
|
|||
_render_shadow(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold);
|
||||
if (finalize_cubemap) {
|
||||
//reblit
|
||||
atlas_rect.size.height /= 2;
|
||||
storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, false);
|
||||
atlas_rect.position.y += atlas_rect.size.height;
|
||||
storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, true);
|
||||
Rect2 atlas_rect_norm = atlas_rect;
|
||||
atlas_rect_norm.position.x /= float(atlas_size);
|
||||
atlas_rect_norm.position.y /= float(atlas_size);
|
||||
atlas_rect_norm.size.x /= float(atlas_size);
|
||||
atlas_rect_norm.size.y /= float(atlas_size);
|
||||
atlas_rect_norm.size.height /= 2;
|
||||
storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), false);
|
||||
atlas_rect_norm.position.y += atlas_rect_norm.size.height;
|
||||
storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), true);
|
||||
}
|
||||
} else {
|
||||
//render shadow
|
||||
|
||||
_render_shadow(render_fb, p_instances, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold);
|
||||
|
||||
//copy to atlas
|
||||
if (use_linear_depth) {
|
||||
storage->get_effects()->copy_depth_to_rect_and_linearize(render_texture, atlas_texture, atlas_rect, true, znear, zfar);
|
||||
} else {
|
||||
storage->get_effects()->copy_depth_to_rect(render_texture, atlas_texture, atlas_rect, true);
|
||||
}
|
||||
|
||||
//does not work from depth to color
|
||||
//RD::get_singleton()->texture_copy(render_texture, atlas_texture, Vector3(0, 0, 0), Vector3(atlas_rect.position.x, atlas_rect.position.y, 0), Vector3(atlas_rect.size.x, atlas_rect.size.y, 1), 0, 0, 0, 0, true);
|
||||
_render_shadow(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, atlas_rect, flip_y, clear_region, begin_texture, end_texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8404,6 +8389,9 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
|
|||
sdfgi_frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(CLAMP(int32_t(GLOBAL_GET("rendering/sdfgi/frames_to_converge")), 0, int32_t(RS::ENV_SDFGI_CONVERGE_MAX - 1)));
|
||||
sdfgi_frames_to_update_light = RS::EnvironmentSDFGIFramesToUpdateLight(CLAMP(int32_t(GLOBAL_GET("rendering/sdfgi/frames_to_update_lights")), 0, int32_t(RS::ENV_SDFGI_UPDATE_LIGHT_MAX - 1)));
|
||||
|
||||
directional_shadow.size = GLOBAL_GET("rendering/quality/directional_shadow/size");
|
||||
directional_shadow.use_16_bits = GLOBAL_GET("rendering/quality/directional_shadow/16_bits");
|
||||
|
||||
uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
|
||||
|
||||
low_end = GLOBAL_GET("rendering/quality/rd_renderer/use_low_end_renderer");
|
||||
|
|
@ -8877,9 +8865,6 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
|
|||
}
|
||||
|
||||
RendererSceneRenderRD::~RendererSceneRenderRD() {
|
||||
for (Map<Vector2i, ShadowMap>::Element *E = shadow_maps.front(); E; E = E->next()) {
|
||||
RD::get_singleton()->free(E->get().depth);
|
||||
}
|
||||
for (Map<int, ShadowCubemap>::Element *E = shadow_cubemaps.front(); E; E = E->next()) {
|
||||
RD::get_singleton()->free(E->get().cubemap);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue