summaryrefslogtreecommitdiff
path: root/servers/rendering/renderer_rd
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/renderer_rd')
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.h2
-rw-r--r--servers/rendering/renderer_rd/effects_rd.cpp500
-rw-r--r--servers/rendering/renderer_rd/effects_rd.h137
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp203
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h39
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp54
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h13
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp647
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h72
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp44
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h7
-rw-r--r--servers/rendering/renderer_rd/pipeline_cache_rd.cpp31
-rw-r--r--servers/rendering/renderer_rd/pipeline_cache_rd.h13
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp22
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp8
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h4
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp478
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h94
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp392
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.h10
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp123
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h30
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.cpp24
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp179
-rw-r--r--servers/rendering/renderer_rd/shader_rd.h6
-rw-r--r--servers/rendering/renderer_rd/shaders/blur_raster.glsl228
-rw-r--r--servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl36
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl48
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl48
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl163
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl256
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl95
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl94
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl63
-rw-r--r--servers/rendering/renderer_rd/shaders/light_data_inc.glsl20
-rw-r--r--servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl74
-rw-r--r--servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl11
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl360
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl33
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl200
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl65
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl46
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/tonemap.glsl32
47 files changed, 3822 insertions, 1202 deletions
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h
index ebb81abdad..c0c03eb26a 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.h
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.h
@@ -235,7 +235,7 @@ public:
Transform3D xform = view_xform * p_transform;
float radius = xform.basis.get_uniform_scale();
- if (radius > 0.98 || radius < 1.02) {
+ if (radius < 0.98 || radius > 1.02) {
xform.basis.orthonormalize();
}
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp
index 5cf8895c8e..c609f25e31 100644
--- a/servers/rendering/renderer_rd/effects_rd.cpp
+++ b/servers/rendering/renderer_rd/effects_rd.cpp
@@ -37,6 +37,10 @@
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "thirdparty/misc/cubemap_coeffs.h"
+bool EffectsRD::get_prefer_raster_effects() {
+ return prefer_raster_effects;
+}
+
static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
@@ -66,6 +70,28 @@ RID EffectsRD::_get_uniform_set_from_image(RID p_image) {
return uniform_set;
}
+RID EffectsRD::_get_uniform_set_for_input(RID p_texture) {
+ if (input_to_uniform_set_cache.has(p_texture)) {
+ RID uniform_set = input_to_uniform_set_cache[p_texture];
+ if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ return uniform_set;
+ }
+ }
+
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT;
+ u.binding = 0;
+ u.ids.push_back(p_texture);
+ uniforms.push_back(u);
+ // This is specific to our subpass shader
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, TONEMAP_MODE_SUBPASS), 0);
+
+ input_to_uniform_set_cache[p_texture] = uniform_set;
+
+ return uniform_set;
+}
+
RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) {
if (texture_to_uniform_set_cache.has(p_texture)) {
RID uniform_set = texture_to_uniform_set_cache[p_texture];
@@ -81,7 +107,7 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps)
u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
u.ids.push_back(p_texture);
uniforms.push_back(u);
- //anything with the same configuration (one texture in binding 0 for set 0), is good
+ // anything with the same configuration (one texture in binding 0 for set 0), is good
RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 0);
texture_to_uniform_set_cache[p_texture] = uniform_set;
@@ -383,6 +409,8 @@ void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i
}
void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the compute version of the gaussian blur with the mobile renderer.");
+
memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
uint32_t base_flags = 0;
@@ -416,6 +444,8 @@ void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back
}
void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the gaussian glow with the mobile renderer.");
+
memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW;
@@ -449,6 +479,57 @@ void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const
RD::get_singleton()->compute_list_end();
}
+void EffectsRD::gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer.");
+
+ memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
+
+ BlurRasterMode blur_mode = p_first_pass && p_auto_exposure.is_valid() ? BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : BLUR_MODE_GAUSSIAN_GLOW;
+ uint32_t base_flags = 0;
+
+ blur_raster.push_constant.pixel_size[0] = p_pixel_size.x;
+ blur_raster.push_constant.pixel_size[1] = p_pixel_size.y;
+
+ blur_raster.push_constant.glow_strength = p_strength;
+ blur_raster.push_constant.glow_bloom = p_bloom;
+ blur_raster.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold;
+ blur_raster.push_constant.glow_hdr_scale = p_hdr_bleed_scale;
+ blur_raster.push_constant.glow_exposure = p_exposure;
+ blur_raster.push_constant.glow_white = 0; //actually unused
+ blur_raster.push_constant.glow_luminance_cap = p_luminance_cap;
+
+ blur_raster.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also
+
+ //HORIZONTAL
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
+ if (p_auto_exposure.is_valid() && p_first_pass) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_auto_exposure), 1);
+ }
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ blur_raster.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL | (p_first_pass ? BLUR_FLAG_GLOW_FIRST_PASS : 0);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+
+ blur_mode = BLUR_MODE_GAUSSIAN_GLOW;
+
+ //VERTICAL
+ draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_rd_texture_half), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ blur_raster.push_constant.flags = base_flags;
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera) {
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
@@ -719,11 +800,11 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone
if (p_settings.view_count > 1) {
// Use MULTIVIEW versions
- mode += 4;
+ mode += 6;
}
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass()));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2);
@@ -735,7 +816,48 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone
RD::get_singleton()->draw_list_end();
}
+void EffectsRD::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) {
+ memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
+
+ tonemap.push_constant.use_bcs = p_settings.use_bcs;
+ tonemap.push_constant.bcs[0] = p_settings.brightness;
+ tonemap.push_constant.bcs[1] = p_settings.contrast;
+ tonemap.push_constant.bcs[2] = p_settings.saturation;
+
+ ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses.");
+ tonemap.push_constant.use_glow = p_settings.use_glow;
+
+ int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS;
+ if (p_settings.view_count > 1) {
+ // Use MULTIVIEW versions
+ mode += 6;
+ }
+
+ tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
+ tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
+ tonemap.push_constant.exposure = p_settings.exposure;
+ tonemap.push_constant.white = p_settings.white;
+ tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey;
+
+ tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
+
+ tonemap.push_constant.use_debanding = p_settings.use_debanding;
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass()));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_for_input(p_source_color), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); // should be set to a default texture, it's ignored
+ RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2); // should be set to a default texture, it's ignored
+ RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3);
+
+ RD::get_singleton()->draw_list_bind_index_array(p_subpass_draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
+ RD::get_singleton()->draw_list_draw(p_subpass_draw_list, true);
+}
+
void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer.");
+
luminance_reduce.push_constant.source_size[0] = p_source_size.x;
luminance_reduce.push_constant.source_size[1] = p_source_size.y;
luminance_reduce.push_constant.max_luminance = p_max_luminance;
@@ -774,7 +896,41 @@ void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_
RD::get_singleton()->compute_list_end();
}
+void EffectsRD::luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster version of luminance reduction with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_reduce.size() != p_fb.size(), "Incorrect frame buffer account for luminance reduction.");
+
+ luminance_reduce_raster.push_constant.max_luminance = p_max_luminance;
+ luminance_reduce_raster.push_constant.min_luminance = p_min_luminance;
+ luminance_reduce_raster.push_constant.exposure_adjust = p_adjust;
+
+ for (int i = 0; i < p_reduce.size(); i++) {
+ luminance_reduce_raster.push_constant.source_size[0] = i == 0 ? p_source_size.x : luminance_reduce_raster.push_constant.dest_size[0];
+ luminance_reduce_raster.push_constant.source_size[1] = i == 0 ? p_source_size.y : luminance_reduce_raster.push_constant.dest_size[1];
+ luminance_reduce_raster.push_constant.dest_size[0] = MAX(luminance_reduce_raster.push_constant.source_size[0] / 8, 1);
+ luminance_reduce_raster.push_constant.dest_size[1] = MAX(luminance_reduce_raster.push_constant.source_size[1] / 8, 1);
+
+ bool final = !p_set && (luminance_reduce_raster.push_constant.dest_size[0] == 1) && (luminance_reduce_raster.push_constant.dest_size[1] == 1);
+ LuminanceReduceRasterMode mode = final ? LUMINANCE_REDUCE_FRAGMENT_FINAL : (i == 0 ? LUMINANCE_REDUCE_FRAGMENT_FIRST : LUMINANCE_REDUCE_FRAGMENT);
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, luminance_reduce_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_fb[i])));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(i == 0 ? p_source_texture : p_reduce[i - 1]), 0);
+ if (final) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_prev_luminance), 1);
+ }
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &luminance_reduce_raster.push_constant, sizeof(LuminanceReduceRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ }
+}
+
void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of BOKEH DOF with the mobile renderer.");
+
bokeh.push_constant.blur_far_active = p_dof_far;
bokeh.push_constant.blur_far_begin = p_dof_far_begin;
bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size;
@@ -924,6 +1080,78 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
RD::get_singleton()->compute_list_end();
}
+void EffectsRD::blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use blur DOF with the clustered renderer.");
+
+ memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
+
+ BlurRasterMode blur_mode;
+ int qsteps[4] = { 4, 4, 10, 20 };
+ uint32_t base_flags = p_cam_orthogonal ? BLUR_FLAG_USE_ORTHOGONAL_PROJECTION : 0;
+
+ Vector2 pixel_size = Vector2(1.0 / p_base_texture_size.width, 1.0 / p_base_texture_size.height);
+
+ blur_raster.push_constant.dof_radius = (p_dof_blur_amount * p_dof_blur_amount) / qsteps[p_quality];
+ blur_raster.push_constant.pixel_size[0] = pixel_size.x;
+ blur_raster.push_constant.pixel_size[1] = pixel_size.y;
+ blur_raster.push_constant.camera_z_far = p_cam_zfar;
+ blur_raster.push_constant.camera_z_near = p_cam_znear;
+
+ if (p_dof_far || p_dof_near) {
+ if (p_quality == RS::DOF_BLUR_QUALITY_HIGH) {
+ blur_mode = BLUR_MODE_DOF_HIGH;
+ } else if (p_quality == RS::DOF_BLUR_QUALITY_MEDIUM) {
+ blur_mode = BLUR_MODE_DOF_MEDIUM;
+ } else { // for LOW or VERYLOW we use LOW
+ blur_mode = BLUR_MODE_DOF_LOW;
+ }
+
+ if (p_dof_far) {
+ base_flags |= BLUR_FLAG_DOF_FAR;
+ blur_raster.push_constant.dof_far_begin = p_dof_far_begin;
+ blur_raster.push_constant.dof_far_end = p_dof_far_begin + p_dof_far_size;
+ }
+
+ if (p_dof_near) {
+ base_flags |= BLUR_FLAG_DOF_NEAR;
+ blur_raster.push_constant.dof_near_begin = p_dof_near_begin;
+ blur_raster.push_constant.dof_near_end = p_dof_near_begin - p_dof_near_size;
+ }
+
+ //HORIZONTAL
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_secondary_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_secondary_fb)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_base_texture), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ blur_raster.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL;
+ blur_raster.push_constant.dof_dir[0] = 1.0;
+ blur_raster.push_constant.dof_dir[1] = 0.0;
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+
+ //VERTICAL
+ draw_list = RD::get_singleton()->draw_list_begin(p_base_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur_raster.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_base_fb)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_secondary_texture), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_depth_texture), 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ blur_raster.push_constant.flags = base_flags;
+ blur_raster.push_constant.dof_dir[0] = 0.0;
+ blur_raster.push_constant.dof_dir[1] = 1.0;
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur_raster.push_constant, sizeof(BlurRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+ }
+}
+
void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) {
RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0);
if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) {
@@ -1188,8 +1416,9 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
if (pass < blur_passes - 2) {
blur_pipeline = SSAO_BLUR_PASS_WIDE;
+ } else {
+ blur_pipeline = SSAO_BLUR_PASS_SMART;
}
- blur_pipeline = SSAO_BLUR_PASS_SMART;
}
for (int i = 0; i < 4; i++) {
@@ -1283,7 +1512,9 @@ void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
+void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap roughness with the mobile renderer.");
+
memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
@@ -1293,10 +1524,10 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffe
roughness.push_constant.face_size = p_size;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.pipeline);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_framebuffer), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
@@ -1308,11 +1539,37 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffe
RD::get_singleton()->compute_list_end();
}
+void EffectsRD::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap roughness with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap roughness must process one side at a time.");
+
+ memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
+
+ roughness.push_constant.face_id = p_face_id;
+ roughness.push_constant.roughness = p_roughness;
+ roughness.push_constant.sample_count = p_sample_count;
+ roughness.push_constant.use_direct_write = p_roughness == 0.0;
+ roughness.push_constant.face_size = p_size;
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap downsample with the mobile renderer.");
+
cubemap_downsampler.push_constant.face_size = p_size.x;
+ cubemap_downsampler.push_constant.face_id = 0; // we render all 6 sides to each layer in one call
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.pipeline);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap), 1);
@@ -1326,7 +1583,27 @@ void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, con
RD::get_singleton()->compute_list_end();
}
+void EffectsRD::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap downsample with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap downsample must process one side at a time.");
+
+ cubemap_downsampler.push_constant.face_size = p_size.x;
+ cubemap_downsampler.push_constant.face_id = p_face_id;
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap filter with the mobile renderer.");
+
Vector<RD::Uniform> uniforms;
for (int i = 0; i < p_dest_cubemap.size(); i++) {
RD::Uniform u;
@@ -1338,12 +1615,12 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap,
if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
RD::get_singleton()->free(filter.image_uniform_set);
}
- filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, 0), 2);
+ filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, 0), 2);
int pipeline = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY;
pipeline = filter.use_high_quality ? pipeline : pipeline + 1;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.pipelines[pipeline]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[pipeline]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap, true), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2);
@@ -1355,6 +1632,29 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap,
RD::get_singleton()->compute_list_end();
}
+void EffectsRD::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap filter with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap filter must process one side at a time.");
+
+ // TODO implement!
+ CubemapFilterRasterPushConstant push_constant;
+ push_constant.mip_level = p_mip_level;
+ push_constant.face_id = p_face_id;
+
+ CubemapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY;
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CubemapFilterRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
ResolvePushConstant push_constant;
push_constant.screen_size[0] = p_screen_size.x;
@@ -1464,7 +1764,35 @@ void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) {
RD::get_singleton()->compute_list_end();
}
-EffectsRD::EffectsRD() {
+EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
+ prefer_raster_effects = p_prefer_raster_effects;
+
+ if (prefer_raster_effects) {
+ // init blur shader (on compute use copy shader)
+
+ Vector<String> blur_modes;
+ blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); // BLUR_MODE_GAUSSIAN_BLUR
+ blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); // BLUR_MODE_GAUSSIAN_GLOW
+ blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); // BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE
+ blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_LOW\n"); // BLUR_MODE_DOF_LOW
+ blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_MEDIUM\n"); // BLUR_MODE_DOF_MEDIUM
+ blur_modes.push_back("\n#define MODE_DOF_BLUR\n#define DOF_QUALITY_HIGH\n"); // BLUR_MODE_DOF_HIGH
+
+ blur_raster.shader.initialize(blur_modes);
+ memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
+ blur_raster.shader_version = blur_raster.shader.version_create();
+
+ for (int i = 0; i < BLUR_MODE_MAX; i++) {
+ blur_raster.pipelines[i].setup(blur_raster.shader.version_get_shader(blur_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+
+ } else {
+ // not used in clustered
+ for (int i = 0; i < BLUR_MODE_MAX; i++) {
+ blur_raster.pipelines[i].clear();
+ }
+ }
+
{ // Initialize copy
Vector<String> copy_modes;
copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n");
@@ -1483,10 +1811,21 @@ EffectsRD::EffectsRD() {
copy.shader.initialize(copy_modes);
memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
+
+ if (prefer_raster_effects) {
+ // disable shaders we can't use
+ copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_COPY, false);
+ copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_COPY_8BIT, false);
+ copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_GLOW, false);
+ copy.shader.set_variant_enabled(COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, false);
+ }
+
copy.shader_version = copy.shader.version_create();
for (int i = 0; i < COPY_MODE_MAX; i++) {
- copy.pipelines[i] = RD::get_singleton()->compute_pipeline_create(copy.shader.version_get_shader(copy.shader_version, i));
+ if (copy.shader.is_variant_enabled(i)) {
+ copy.pipelines[i] = RD::get_singleton()->compute_pipeline_create(copy.shader.version_get_shader(copy.shader_version, i));
+ }
}
}
{
@@ -1510,11 +1849,22 @@ EffectsRD::EffectsRD() {
// Initialize roughness
Vector<String> cubemap_roughness_modes;
cubemap_roughness_modes.push_back("");
- roughness.shader.initialize(cubemap_roughness_modes);
- roughness.shader_version = roughness.shader.version_create();
+ if (prefer_raster_effects) {
+ roughness.raster_shader.initialize(cubemap_roughness_modes);
+
+ roughness.shader_version = roughness.raster_shader.version_create();
+
+ roughness.raster_pipeline.setup(roughness.raster_shader.version_get_shader(roughness.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+
+ } else {
+ roughness.compute_shader.initialize(cubemap_roughness_modes);
+
+ roughness.shader_version = roughness.compute_shader.version_create();
- roughness.pipeline = RD::get_singleton()->compute_pipeline_create(roughness.shader.version_get_shader(roughness.shader_version, 0));
+ roughness.compute_pipeline = RD::get_singleton()->compute_pipeline_create(roughness.compute_shader.version_get_shader(roughness.shader_version, 0));
+ roughness.raster_pipeline.clear();
+ }
}
{
@@ -1524,12 +1874,16 @@ EffectsRD::EffectsRD() {
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n");
tonemap_modes.push_back("\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
+ tonemap_modes.push_back("\n#define SUBPASS\n");
+ tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n");
// multiview versions of our shaders
tonemap_modes.push_back("\n#define MULTIVIEW\n");
tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n");
tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n");
tonemap.shader.initialize(tonemap_modes);
@@ -1538,6 +1892,8 @@ EffectsRD::EffectsRD() {
tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, false);
}
tonemap.shader_version = tonemap.shader.version_create();
@@ -1551,7 +1907,20 @@ EffectsRD::EffectsRD() {
}
}
- {
+ if (prefer_raster_effects) {
+ Vector<String> luminance_reduce_modes;
+ luminance_reduce_modes.push_back("\n#define FIRST_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FIRST
+ luminance_reduce_modes.push_back("\n"); // LUMINANCE_REDUCE_FRAGMENT
+ luminance_reduce_modes.push_back("\n#define FINAL_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FINAL
+
+ luminance_reduce_raster.shader.initialize(luminance_reduce_modes);
+ memset(&luminance_reduce_raster.push_constant, 0, sizeof(LuminanceReduceRasterPushConstant));
+ luminance_reduce_raster.shader_version = luminance_reduce_raster.shader.version_create();
+
+ for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) {
+ luminance_reduce_raster.pipelines[i].setup(luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ } else {
// Initialize luminance_reduce
Vector<String> luminance_reduce_modes;
luminance_reduce_modes.push_back("\n#define READ_TEXTURE\n");
@@ -1565,6 +1934,10 @@ EffectsRD::EffectsRD() {
for (int i = 0; i < LUMINANCE_REDUCE_MAX; i++) {
luminance_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, i));
}
+
+ for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) {
+ luminance_reduce_raster.pipelines[i].clear();
+ }
}
{
@@ -1583,7 +1956,9 @@ EffectsRD::EffectsRD() {
cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0);
}
- {
+ if (prefer_raster_effects) {
+ // not supported
+ } else {
// Initialize bokeh
Vector<String> bokeh_modes;
bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
@@ -1761,11 +2136,21 @@ EffectsRD::EffectsRD() {
//Initialize cubemap downsampler
Vector<String> cubemap_downsampler_modes;
cubemap_downsampler_modes.push_back("");
- cubemap_downsampler.shader.initialize(cubemap_downsampler_modes);
- cubemap_downsampler.shader_version = cubemap_downsampler.shader.version_create();
+ if (prefer_raster_effects) {
+ cubemap_downsampler.raster_shader.initialize(cubemap_downsampler_modes);
+
+ cubemap_downsampler.shader_version = cubemap_downsampler.raster_shader.version_create();
- cubemap_downsampler.pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.shader.version_get_shader(cubemap_downsampler.shader_version, 0));
+ cubemap_downsampler.raster_pipeline.setup(cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ } else {
+ cubemap_downsampler.compute_shader.initialize(cubemap_downsampler_modes);
+
+ cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create();
+
+ cubemap_downsampler.compute_pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0));
+ cubemap_downsampler.raster_pipeline.clear();
+ }
}
{
@@ -1777,12 +2162,6 @@ EffectsRD::EffectsRD() {
cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n");
cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n");
cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n");
- filter.shader.initialize(cubemap_filter_modes);
- filter.shader_version = filter.shader.version_create();
-
- for (int i = 0; i < FILTER_MODE_MAX; i++) {
- filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.shader.version_get_shader(filter.shader_version, i));
- }
if (filter.use_high_quality) {
filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs));
@@ -1792,15 +2171,50 @@ EffectsRD::EffectsRD() {
RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]);
}
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 0;
- u.ids.push_back(filter.coefficient_buffer);
- uniforms.push_back(u);
+ if (prefer_raster_effects) {
+ filter.raster_shader.initialize(cubemap_filter_modes);
+ filter.shader_version = filter.raster_shader.version_create();
+
+ // array variants are not supported in raster
+ filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false);
+ filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false);
+
+ for (int i = 0; i < FILTER_MODE_MAX; i++) {
+ if (filter.raster_shader.is_variant_enabled(i)) {
+ filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ } else {
+ filter.raster_pipelines[i].clear();
+ }
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(filter.coefficient_buffer);
+ uniforms.push_back(u);
+ }
+ filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.raster_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
+ } else {
+ filter.compute_shader.initialize(cubemap_filter_modes);
+ filter.shader_version = filter.compute_shader.version_create();
+
+ for (int i = 0; i < FILTER_MODE_MAX; i++) {
+ filter.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.compute_shader.version_get_shader(filter.shader_version, i));
+ filter.raster_pipelines[i].clear();
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(filter.coefficient_buffer);
+ uniforms.push_back(u);
+ }
+ filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
}
- filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
}
{
@@ -1974,15 +2388,23 @@ EffectsRD::~EffectsRD() {
RD::get_singleton()->free(ssao.gather_constants_buffer);
RD::get_singleton()->free(ssao.importance_map_load_counter);
- bokeh.shader.version_free(bokeh.shader_version);
+ if (prefer_raster_effects) {
+ blur_raster.shader.version_free(blur_raster.shader_version);
+ luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
+ roughness.raster_shader.version_free(roughness.shader_version);
+ cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version);
+ filter.raster_shader.version_free(filter.shader_version);
+ } else {
+ bokeh.shader.version_free(bokeh.shader_version);
+ luminance_reduce.shader.version_free(luminance_reduce.shader_version);
+ roughness.compute_shader.version_free(roughness.shader_version);
+ cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version);
+ filter.compute_shader.version_free(filter.shader_version);
+ }
copy.shader.version_free(copy.shader_version);
copy_to_fb.shader.version_free(copy_to_fb.shader_version);
cube_to_dp.shader.version_free(cube_to_dp.shader_version);
- cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version);
- filter.shader.version_free(filter.shader_version);
- luminance_reduce.shader.version_free(luminance_reduce.shader_version);
resolve.shader.version_free(resolve.shader_version);
- roughness.shader.version_free(roughness.shader_version);
roughness_limiter.shader.version_free(roughness_limiter.shader_version);
sort.shader.version_free(sort.shader_version);
specular_merge.shader.version_free(specular_merge.shader_version);
diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h
index 33d32f0c57..79d9a8b738 100644
--- a/servers/rendering/renderer_rd/effects_rd.h
+++ b/servers/rendering/renderer_rd/effects_rd.h
@@ -33,14 +33,19 @@
#include "core/math/camera_matrix.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/shaders/blur_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/bokeh_dof.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/roughness_limiter.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl.gen.h"
@@ -60,6 +65,66 @@
#include "servers/rendering_server.h"
class EffectsRD {
+private:
+ bool prefer_raster_effects;
+
+ enum BlurRasterMode {
+ BLUR_MODE_GAUSSIAN_BLUR,
+ BLUR_MODE_GAUSSIAN_GLOW,
+ BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
+
+ BLUR_MODE_DOF_LOW,
+ BLUR_MODE_DOF_MEDIUM,
+ BLUR_MODE_DOF_HIGH,
+
+ BLUR_MODE_MAX
+ };
+
+ enum {
+ BLUR_FLAG_HORIZONTAL = (1 << 0),
+ BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 1),
+ BLUR_FLAG_GLOW_FIRST_PASS = (1 << 2),
+ BLUR_FLAG_DOF_FAR = (1 << 3),
+ BLUR_FLAG_DOF_NEAR = (1 << 4),
+ };
+
+ struct BlurRasterPushConstant {
+ float pixel_size[2];
+ uint32_t flags;
+ uint32_t pad;
+
+ //glow
+ float glow_strength;
+ float glow_bloom;
+ float glow_hdr_threshold;
+ float glow_hdr_scale;
+
+ float glow_exposure;
+ float glow_white;
+ float glow_luminance_cap;
+ float glow_auto_exposure_grey;
+
+ //dof
+ float dof_far_begin;
+ float dof_far_end;
+ float dof_near_begin;
+ float dof_near_end;
+
+ float dof_radius;
+ float dof_pad[3];
+
+ float dof_dir[2];
+ float camera_z_far;
+ float camera_z_near;
+ };
+
+ struct BlurRaster {
+ BlurRasterPushConstant push_constant;
+ BlurRasterShaderRD shader;
+ RID shader_version;
+ PipelineCacheRD pipelines[BLUR_MODE_MAX];
+ } blur_raster;
+
enum CopyMode {
COPY_MODE_GAUSSIAN_COPY,
COPY_MODE_GAUSSIAN_COPY_8BIT,
@@ -161,9 +226,11 @@ class EffectsRD {
struct CubemapRoughness {
CubemapRoughnessPushConstant push_constant;
- CubemapRoughnessShaderRD shader;
+ CubemapRoughnessShaderRD compute_shader;
+ CubemapRoughnessRasterShaderRD raster_shader;
RID shader_version;
- RID pipeline;
+ RID compute_pipeline;
+ PipelineCacheRD raster_pipeline;
} roughness;
enum TonemapMode {
@@ -171,11 +238,15 @@ class EffectsRD {
TONEMAP_MODE_BICUBIC_GLOW_FILTER,
TONEMAP_MODE_1D_LUT,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT,
+ TONEMAP_MODE_SUBPASS,
+ TONEMAP_MODE_SUBPASS_1D_LUT,
TONEMAP_MODE_NORMAL_MULTIVIEW,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW,
TONEMAP_MODE_1D_LUT_MULTIVIEW,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW,
+ TONEMAP_MODE_SUBPASS_MULTIVIEW,
+ TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW,
TONEMAP_MODE_MAX
};
@@ -239,6 +310,29 @@ class EffectsRD {
RID pipelines[LUMINANCE_REDUCE_MAX];
} luminance_reduce;
+ enum LuminanceReduceRasterMode {
+ LUMINANCE_REDUCE_FRAGMENT_FIRST,
+ LUMINANCE_REDUCE_FRAGMENT,
+ LUMINANCE_REDUCE_FRAGMENT_FINAL,
+ LUMINANCE_REDUCE_FRAGMENT_MAX
+ };
+
+ struct LuminanceReduceRasterPushConstant {
+ int32_t source_size[2];
+ int32_t dest_size[2];
+ float exposure_adjust;
+ float min_luminance;
+ float max_luminance;
+ float pad[1];
+ };
+
+ struct LuminanceReduceFragment {
+ LuminanceReduceRasterPushConstant push_constant;
+ LuminanceReduceRasterShaderRD shader;
+ RID shader_version;
+ PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX];
+ } luminance_reduce_raster;
+
struct CopyToDPPushConstant {
float z_far;
float z_near;
@@ -426,15 +520,17 @@ class EffectsRD {
struct CubemapDownsamplerPushConstant {
uint32_t face_size;
- float pad[3];
+ uint32_t face_id;
+ float pad[2];
};
struct CubemapDownsampler {
CubemapDownsamplerPushConstant push_constant;
- CubemapDownsamplerShaderRD shader;
+ CubemapDownsamplerShaderRD compute_shader;
+ CubemapDownsamplerRasterShaderRD raster_shader;
RID shader_version;
- RID pipeline;
-
+ RID compute_pipeline;
+ PipelineCacheRD raster_pipeline;
} cubemap_downsampler;
enum CubemapFilterMode {
@@ -445,10 +541,19 @@ class EffectsRD {
FILTER_MODE_MAX,
};
+ struct CubemapFilterRasterPushConstant {
+ uint32_t mip_level;
+ uint32_t face_id;
+ float pad[2];
+ };
+
struct CubemapFilter {
- CubemapFilterShaderRD shader;
+ CubemapFilterShaderRD compute_shader;
+ CubemapFilterRasterShaderRD raster_shader;
RID shader_version;
- RID pipelines[FILTER_MODE_MAX];
+ RID compute_pipelines[FILTER_MODE_MAX];
+ PipelineCacheRD raster_pipelines[FILTER_MODE_MAX];
+
RID uniform_set;
RID image_uniform_set;
RID coefficient_buffer;
@@ -617,6 +722,7 @@ class EffectsRD {
RID index_array;
Map<RID, RID> texture_to_uniform_set_cache;
+ Map<RID, RID> input_to_uniform_set_cache;
Map<RID, RID> image_to_uniform_set_cache;
@@ -650,6 +756,7 @@ class EffectsRD {
Map<TextureSamplerPair, RID> texture_sampler_to_compute_uniform_set_cache;
RID _get_uniform_set_from_image(RID p_texture);
+ RID _get_uniform_set_for_input(RID p_texture);
RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler);
@@ -657,6 +764,8 @@ class EffectsRD {
RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2);
public:
+ bool get_prefer_raster_effects();
+
void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID());
void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false);
void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);
@@ -666,12 +775,17 @@ public:
void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false);
void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false);
void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
+ void gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
- void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
+ void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
+ void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip);
void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
+ void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
+
void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
+ void blur_dof_raster(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_base_fb, RID p_secondary_texture, RID p_secondary_fb, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_dof_blur_amount, RS::DOFBlurQuality p_quality, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
struct TonemapSettings {
bool use_glow = false;
@@ -734,13 +848,16 @@ public:
};
void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings);
+ void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings);
void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set);
void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set);
void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
+ void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size);
void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
+ void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level);
void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);
@@ -751,7 +868,7 @@ public:
void sort_buffer(RID p_uniform_set, int p_size);
- EffectsRD();
+ EffectsRD(bool p_prefer_raster_effects);
~EffectsRD();
};
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 22bfd03115..0d304556c2 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -183,7 +183,7 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
}
}
-void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
+void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
clear();
ERR_FAIL_COND_MSG(p_view_count != 1, "Multiple views is currently not supported in this renderer, please use the mobile renderer for VR support");
@@ -318,11 +318,11 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
RID prev_pipeline_rd;
RID prev_xforms_uniform_set;
- bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP);
+ bool shadow_pass = (p_pass_mode == PASS_MODE_SHADOW) || (p_pass_mode == PASS_MODE_SHADOW_DP);
SceneState::PushConstant push_constant;
- if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) {
+ if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) {
push_constant.uv_offset = Math::make_half_float(p_params->uv_offset.y) << 16;
push_constant.uv_offset |= Math::make_half_float(p_params->uv_offset.x);
} else {
@@ -339,7 +339,7 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
SceneShaderForwardClustered::ShaderData *shader;
void *mesh_surface;
- if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too
+ if (shadow_pass || p_pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too
material_uniform_set = surf->material_uniform_set_shadow;
shader = surf->shader_shadow;
mesh_surface = surf->surface_shadow;
@@ -369,7 +369,7 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
//find cull variant
SceneShaderForwardClustered::ShaderData::CullVariant cull_variant;
- if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
+ if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL || p_pass_mode == PASS_MODE_SDF || ((p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
cull_variant = SceneShaderForwardClustered::ShaderData::CULL_VARIANT_DOUBLE_SIDED;
} else {
bool mirror = surf->owner->mirror;
@@ -384,14 +384,30 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
SceneShaderForwardClustered::ShaderVersion shader_version = SceneShaderForwardClustered::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
- switch (p_params->pass_mode) {
+ uint32_t pipeline_specialization = 0;
+
+ if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT || p_pass_mode == PASS_MODE_COLOR_SPECULAR) {
+ if (element_info.uses_softshadow) {
+ pipeline_specialization |= SceneShaderForwardClustered::SHADER_SPECIALIZATION_SOFT_SHADOWS;
+ }
+ if (element_info.uses_projector) {
+ pipeline_specialization |= SceneShaderForwardClustered::SHADER_SPECIALIZATION_PROJECTOR;
+ }
+
+ if (p_params->use_directional_soft_shadow) {
+ pipeline_specialization |= SceneShaderForwardClustered::SHADER_SPECIALIZATION_DIRECTIONAL_SOFT_SHADOWS;
+ }
+ }
+
+ switch (p_pass_mode) {
case PASS_MODE_COLOR:
case PASS_MODE_COLOR_TRANSPARENT: {
if (element_info.uses_lightmap) {
shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
- } else if (element_info.uses_forward_gi) {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI;
} else {
+ if (element_info.uses_forward_gi) {
+ pipeline_specialization |= SceneShaderForwardClustered::SHADER_SPECIALIZATION_FORWARD_GI;
+ }
shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS;
}
} break;
@@ -452,7 +468,7 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
prev_index_array_rd = index_array_rd;
}
- RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe);
+ RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, 0, pipeline_specialization);
if (pipeline_rd != prev_pipeline_rd) {
// checking with prev shader does not make so much sense, as
@@ -467,8 +483,8 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
}
if (material_uniform_set != prev_material_uniform_set) {
- //update uniform set
- if (material_uniform_set.is_valid()) {
+ // Update uniform set.
+ if (RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
}
@@ -573,11 +589,6 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
RendererStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
- scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get();
- scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get();
- scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get();
- scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get();
-
Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
@@ -848,7 +859,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
bool cant_repeat = instance_data.flags & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid();
- if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2) {
+ if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2 && repeats < RenderElementInfo::MAX_REPEATS) {
//this element is the same as the previous one, count repeats to draw it using instancing
repeats++;
} else {
@@ -868,6 +879,8 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
element_info.lod_index = surface->sort.lod_index;
element_info.uses_forward_gi = surface->sort.uses_forward_gi;
element_info.uses_lightmap = surface->sort.uses_lightmap;
+ element_info.uses_softshadow = surface->sort.uses_softshadow;
+ element_info.uses_projector = surface->sort.uses_projector;
if (cant_repeat) {
prev_surface = nullptr;
@@ -1375,7 +1388,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID());
bool finish_depth = using_ssao || using_sdfgi || using_voxelgi;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
@@ -1432,7 +1445,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
_render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
if (will_continue_color && using_separate_specular) {
// close the specular framebuffer, as it's no longer used
@@ -1529,7 +1542,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
_render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
}
@@ -1542,6 +1555,14 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RD::get_singleton()->draw_command_end_label();
+
+ if (p_render_data->render_buffers.is_valid()) {
+ _debug_draw_cluster(p_render_data->render_buffers);
+
+ RENDER_TIMESTAMP("Tonemap");
+
+ _render_buffers_post_process_and_tonemap(p_render_data);
+ }
}
void RenderForwardClustered::_render_shadow_begin() {
@@ -1631,7 +1652,7 @@ void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) {
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
- RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, true, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
_render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
}
@@ -1672,7 +1693,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
{
//regular forward for now
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, true, rp_uniform_set);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, true, false, rp_uniform_set);
_render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
}
RD::get_singleton()->draw_command_end_label();
@@ -1707,7 +1728,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
RENDER_TIMESTAMP("Render Material");
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, false, rp_uniform_set);
//regular forward for now
Vector<Color> clear;
clear.push_back(Color(0, 0, 0, 0));
@@ -1750,7 +1771,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p
RENDER_TIMESTAMP("Render Material");
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, true);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, false, rp_uniform_set, true);
//regular forward for now
Vector<Color> clear;
clear.push_back(Color(0, 0, 0, 0));
@@ -1868,7 +1889,7 @@ void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i
E = sdfgi_framebuffer_size_cache.insert(fb_size, fb);
}
- RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, rp_uniform_set, false);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, true, false, rp_uniform_set, false);
_render_list_with_threads(&render_list_params, E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), sbs);
}
@@ -1924,13 +1945,67 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (decals_get_filter()) {
+ case RS::DECAL_FILTER_NEAREST: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.ids.push_back(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (light_projectors_get_filter()) {
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.ids.push_back(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_omni_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 4;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_spot_light_buffer());
uniforms.push_back(u);
@@ -1938,35 +2013,35 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
{
RD::Uniform u;
- u.binding = 5;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 6;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.ids.push_back(get_directional_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 7;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(scene_state.lightmap_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(scene_state.lightmap_capture_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 9;
+ u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = storage->decal_atlas_get_texture();
u.ids.push_back(decal_atlas);
@@ -1974,7 +2049,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
}
{
RD::Uniform u;
- u.binding = 10;
+ u.binding = 12;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = storage->decal_atlas_get_texture_srgb();
u.ids.push_back(decal_atlas);
@@ -1982,7 +2057,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
}
{
RD::Uniform u;
- u.binding = 11;
+ u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_decal_buffer());
uniforms.push_back(u);
@@ -1991,7 +2066,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 12;
+ u.binding = 14;
u.ids.push_back(storage->global_variables_get_storage_buffer());
uniforms.push_back(u);
}
@@ -1999,7 +2074,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 13;
+ u.binding = 15;
u.ids.push_back(sdfgi_get_ubo());
uniforms.push_back(u);
}
@@ -2511,12 +2586,14 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
sdcache->sort.sort_key2 = 0;
sdcache->sort.surface_index = p_surface;
- sdcache->sort.material_id_low = p_material_id & 0x3FFF;
- sdcache->sort.material_id_hi = p_material_id >> 14;
+ sdcache->sort.material_id_low = p_material_id & 0xFFFF;
+ sdcache->sort.material_id_hi = p_material_id >> 16;
sdcache->sort.shader_id = p_shader_id;
sdcache->sort.geometry_id = p_mesh.get_local_index(); //only meshes can repeat anyway
sdcache->sort.uses_forward_gi = ginstance->can_sdfgi;
sdcache->sort.priority = p_material->priority;
+ sdcache->sort.uses_projector = ginstance->using_projectors;
+ sdcache->sort.uses_softshadow = ginstance->using_softshadows;
}
void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
@@ -2911,6 +2988,56 @@ void RenderForwardClustered::geometry_instance_pair_voxel_gi_instances(GeometryI
}
}
+void RenderForwardClustered::geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->using_projectors = p_projector;
+ ginstance->using_softshadows = p_softshadow;
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardClustered::_update_shader_quality_settings() {
+ Vector<RD::PipelineSpecializationConstant> spec_constants;
+
+ RD::PipelineSpecializationConstant sc;
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
+
+ sc.constant_id = SPEC_CONSTANT_SOFT_SHADOW_SAMPLES;
+ sc.int_value = soft_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES;
+ sc.int_value = penumbra_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES;
+ sc.int_value = directional_soft_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES;
+ sc.int_value = directional_penumbra_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ sc.constant_id = SPEC_CONSTANT_DECAL_FILTER;
+ sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_PROJECTOR_FILTER;
+ sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+
+ spec_constants.push_back(sc);
+
+ scene_shader.set_default_specialization_constants(spec_constants);
+
+ _base_uniforms_changed(); //also need this
+}
+
RenderForwardClustered::RenderForwardClustered(RendererStorageRD *p_storage) :
RendererSceneRenderRD(p_storage) {
singleton = this;
@@ -2948,6 +3075,8 @@ RenderForwardClustered::RenderForwardClustered(RendererStorageRD *p_storage) :
}
render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
+
+ _update_shader_quality_settings();
}
RenderForwardClustered::~RenderForwardClustered() {
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 750c0167e7..676f633d33 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -51,6 +51,15 @@ class RenderForwardClustered : public RendererSceneRenderRD {
};
enum {
+ SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 6,
+ SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 7,
+ SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 8,
+ SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 9,
+ SPEC_CONSTANT_DECAL_FILTER = 10,
+ SPEC_CONSTANT_PROJECTOR_FILTER = 11,
+ };
+
+ enum {
SDFGI_MAX_CASCADES = 8,
MAX_VOXEL_GI_INSTANCESS = 8,
MAX_LIGHTMAPS = 8,
@@ -103,7 +112,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void ensure_specular();
void ensure_voxelgi();
void clear();
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
~RenderBufferDataForwardClustered();
};
@@ -156,8 +165,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
uint32_t barrier = RD::BARRIER_MASK_ALL;
+ bool use_directional_soft_shadow = false;
- RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
@@ -172,6 +182,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
screen_lod_threshold = p_screen_lod_threshold;
element_offset = p_element_offset;
barrier = p_barrier;
+ use_directional_soft_shadow = p_use_directional_soft_shadows;
}
};
@@ -220,11 +231,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
float penumbra_shadow_kernel[128];
float soft_shadow_kernel[128];
- uint32_t directional_penumbra_shadow_samples;
- uint32_t directional_soft_shadow_samples;
- uint32_t penumbra_shadow_samples;
- uint32_t soft_shadow_samples;
-
float ambient_light_color_energy[4];
float ambient_color_sky_mix;
@@ -353,7 +359,10 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
struct RenderElementInfo {
- uint32_t repeat : 22;
+ enum { MAX_REPEATS = (1 << 20) - 1 };
+ uint32_t repeat : 20;
+ uint32_t uses_projector : 1;
+ uint32_t uses_softshadow : 1;
uint32_t uses_lightmap : 1;
uint32_t uses_forward_gi : 1;
uint32_t lod_index : 8;
@@ -402,12 +411,14 @@ class RenderForwardClustered : public RendererSceneRenderRD {
union {
struct {
uint64_t lod_index : 8;
- uint64_t surface_index : 10;
+ uint64_t surface_index : 8;
uint64_t geometry_id : 32;
- uint64_t material_id_low : 14;
+ uint64_t material_id_low : 16;
- uint64_t material_id_hi : 18;
+ uint64_t material_id_hi : 16;
uint64_t shader_id : 32;
+ uint64_t uses_softshadow : 1;
+ uint64_t uses_projector : 1;
uint64_t uses_forward_gi : 1;
uint64_t uses_lightmap : 1;
uint64_t depth_layer : 4;
@@ -455,6 +466,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t trail_steps = 1;
RID mesh_instance;
bool can_sdfgi = false;
+ bool using_projectors = false;
+ bool using_softshadows = false;
//used during setup
uint32_t base_flags = 0;
Transform3D transform;
@@ -564,6 +577,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RenderList render_list[RENDER_LIST_MAX];
+ virtual void _update_shader_quality_settings() override;
+
protected:
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
@@ -604,6 +619,8 @@ public:
virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override;
virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override;
+ virtual void geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) override;
+
virtual bool free(RID p_rid) override;
RenderForwardClustered(RendererStorageRD *p_storage);
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index d39823a1a3..89d14e871a 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -131,8 +131,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
+ if (err != OK) {
+ return;
+ }
if (version.is_null()) {
version = shader_singleton->shader.version_create();
@@ -287,7 +288,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
multisample_state.enable_alpha_to_one = true;
}
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
blend_state = blend_state_blend;
if (depth_draw == DEPTH_DRAW_OPAQUE) {
depth_stencil.enable_depth_write = false; //alpha does not draw depth
@@ -305,7 +306,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
continue; // do not use this version (will error if using it is attempted)
}
} else {
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
blend_state = blend_state_opaque;
} else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
//none, leave empty
@@ -324,7 +325,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
}
RID shader_variant = shader_singleton->shader.version_get_shader(version, k);
- pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants);
}
}
}
@@ -408,7 +409,8 @@ RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_s
return shader_singleton->shader.version_get_native_source_code(version);
}
-SceneShaderForwardClustered::ShaderData::ShaderData() {
+SceneShaderForwardClustered::ShaderData::ShaderData() :
+ shader_list_element(this) {
valid = false;
uses_screen_texture = false;
}
@@ -424,6 +426,7 @@ SceneShaderForwardClustered::ShaderData::~ShaderData() {
RendererStorageRD::ShaderData *SceneShaderForwardClustered::_create_shader_func() {
ShaderData *shader_data = memnew(ShaderData);
+ singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
}
@@ -483,7 +486,6 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n"); // SHADER_VERSION_DEPTH_PASS_WITH_SDF
shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS
- shader_versions.push_back("\n#define USE_FORWARD_GI\n"); // SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI
shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); // SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR
shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS
shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR
@@ -682,7 +684,19 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
//default material and shader
default_shader = storage->shader_allocate();
storage->shader_initialize(default_shader);
- storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
+ storage->shader_set_code(default_shader, R"(
+shader_type spatial;
+
+void vertex() {
+ ROUGHNESS = 0.8;
+}
+
+void fragment() {
+ ALBEDO = vec3(0.6);
+ ROUGHNESS = 0.8;
+ METALLIC = 0.2;
+}
+)");
default_material = storage->material_allocate();
storage->material_initialize(default_material);
storage->material_set_shader(default_material, default_shader);
@@ -699,7 +713,16 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
overdraw_material_shader = storage->shader_allocate();
storage->shader_initialize(overdraw_material_shader);
// Use relatively low opacity so that more "layers" of overlapping objects can be distinguished.
- storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.1; }");
+ storage->shader_set_code(overdraw_material_shader, R"(
+shader_type spatial;
+
+render_mode blend_add, unshaded;
+
+void fragment() {
+ ALBEDO = vec3(0.4, 0.8, 0.8);
+ ALPHA = 0.1;
+}
+)");
overdraw_material = storage->material_allocate();
storage->material_initialize(overdraw_material);
storage->material_set_shader(overdraw_material, overdraw_material_shader);
@@ -729,3 +752,16 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
}
}
+
+void SceneShaderForwardClustered::set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants) {
+ default_specialization_constants = p_constants;
+ for (SelfList<ShaderData> *E = shader_list.first(); E; E = E->next()) {
+ for (int i = 0; i < ShaderData::CULL_VARIANT_MAX; i++) {
+ for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
+ for (int k = 0; k < SHADER_VERSION_MAX; k++) {
+ E->self()->pipelines[i][j][k].update_specialization_constants(default_specialization_constants);
+ }
+ }
+ }
+ }
+}
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index 810b1f3876..8d75f30a20 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -52,7 +52,6 @@ public:
SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
SHADER_VERSION_DEPTH_PASS_WITH_SDF,
SHADER_VERSION_COLOR_PASS,
- SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI,
SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
SHADER_VERSION_LIGHTMAP_COLOR_PASS,
SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
@@ -60,6 +59,13 @@ public:
SHADER_VERSION_MAX
};
+ enum ShaderSpecializations {
+ SHADER_SPECIALIZATION_FORWARD_GI = 1 << 0,
+ SHADER_SPECIALIZATION_PROJECTOR = 1 << 1,
+ SHADER_SPECIALIZATION_SOFT_SHADOWS = 1 << 2,
+ SHADER_SPECIALIZATION_DIRECTIONAL_SOFT_SHADOWS = 1 << 3,
+ };
+
struct ShaderData : public RendererStorageRD::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
@@ -154,10 +160,13 @@ public:
virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+ SelfList<ShaderData> shader_list_element;
ShaderData();
virtual ~ShaderData();
};
+ SelfList<ShaderData>::List shader_list;
+
RendererStorageRD::ShaderData *_create_shader_func();
static RendererStorageRD::ShaderData *_create_shader_funcs() {
return static_cast<SceneShaderForwardClustered *>(singleton)->_create_shader_func();
@@ -203,10 +212,12 @@ public:
RID overdraw_material_uniform_set;
ShaderData *overdraw_material_shader_ptr = nullptr;
+ Vector<RD::PipelineSpecializationConstant> default_specialization_constants;
SceneShaderForwardClustered();
~SceneShaderForwardClustered();
void init(RendererStorageRD *p_storage, const String p_defines);
+ void set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants);
};
} // namespace RendererSceneRenderImplementation
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 7fbd6e23b0..f810ae2454 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -35,6 +35,34 @@
using namespace RendererSceneRenderImplementation;
+RenderForwardMobile::ForwardID RenderForwardMobile::_allocate_forward_id(ForwardIDType p_type) {
+ int32_t index = -1;
+ for (uint32_t i = 0; i < forward_id_allocators[p_type].allocations.size(); i++) {
+ if (forward_id_allocators[p_type].allocations[i] == false) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == -1) {
+ index = forward_id_allocators[p_type].allocations.size();
+ forward_id_allocators[p_type].allocations.push_back(true);
+ forward_id_allocators[p_type].map.push_back(0xFF);
+ } else {
+ forward_id_allocators[p_type].allocations[index] = true;
+ }
+
+ return index;
+}
+void RenderForwardMobile::_free_forward_id(ForwardIDType p_type, ForwardID p_id) {
+ ERR_FAIL_INDEX(p_id, (ForwardID)forward_id_allocators[p_type].allocations.size());
+ forward_id_allocators[p_type].allocations[p_id] = false;
+}
+
+void RenderForwardMobile::_map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) {
+ forward_id_allocators[p_type].map[p_id] = p_index;
+}
+
/* Render buffer */
void RenderForwardMobile::RenderBufferDataForwardMobile::clear() {
@@ -50,12 +78,16 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::clear() {
color = RID();
depth = RID();
- color_fb = RID();
+ for (int i = 0; i < FB_CONFIG_MAX; i++) {
+ color_fbs[i] = RID();
+ }
}
-void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
+void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
clear();
+ bool is_half_resolution = false; // Set this once we support this feature.
+
msaa = p_msaa;
width = p_width;
@@ -65,22 +97,57 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
color = p_color_buffer;
depth = p_depth_buffer;
- // re-introduce setting up msaa? For now we ignore this...
+ // We are creating 4 configurations here for our framebuffers.
if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) {
Vector<RID> fb;
- fb.push_back(p_color_buffer);
- fb.push_back(depth);
+ fb.push_back(p_color_buffer); // 0 - color buffer
+ fb.push_back(depth); // 1 - depth buffer
+
+ // Now define our subpasses
+ Vector<RD::FramebufferPass> passes;
+ RD::FramebufferPass pass;
+
+ // re-using the same attachments
+ pass.color_attachments.push_back(0);
+ pass.depth_attachment = 1;
+
+ // - opaque pass
+ passes.push_back(pass);
+ color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+
+ // - add sky pass
+ passes.push_back(pass);
+ color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+
+ // - add alpha pass
+ passes.push_back(pass);
+ color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
- color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
+ if (!is_half_resolution) {
+ // - add blit to 2D pass
+ fb.push_back(p_target_buffer); // 2 - target buffer
+
+ RD::FramebufferPass blit_pass;
+ blit_pass.color_attachments.push_back(2);
+ blit_pass.input_attachments.push_back(0);
+ passes.push_back(blit_pass);
+
+ color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+ } else {
+ // can't do our blit pass if resolutions don't match
+ color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID();
+ }
} else {
+ RD::DataFormat color_format = RenderForwardMobile::singleton->_render_buffers_get_color_format();
+
RD::TextureFormat tf;
if (view_count > 1) {
tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
} else {
tf.texture_type = RD::TEXTURE_TYPE_2D;
}
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = color_format;
tf.width = p_width;
tf.height = p_height;
tf.array_layers = view_count; // create a layer for every view
@@ -106,14 +173,87 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
{
Vector<RID> fb;
- fb.push_back(color_msaa);
- fb.push_back(depth_msaa);
+ fb.push_back(color_msaa); // 0 - msaa color buffer
+ fb.push_back(depth_msaa); // 1 - msaa depth buffer
+
+ // Now define our subpasses
+ Vector<RD::FramebufferPass> passes;
+ RD::FramebufferPass pass;
+
+ // re-using the same attachments
+ pass.color_attachments.push_back(0);
+ pass.depth_attachment = 1;
+
+ // - opaque pass
+ passes.push_back(pass);
+
+ // - add sky pass
+ fb.push_back(color); // 2 - color buffer
+ passes.push_back(pass); // without resolve for our 3 + 4 subpass config
+ {
+ // but with resolve for our 2 subpass config
+ Vector<RD::FramebufferPass> two_passes;
+ two_passes.push_back(pass); // opaque subpass without resolve
+ pass.resolve_attachments.push_back(2);
+ two_passes.push_back(pass); // sky subpass with resolve
+
+ color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, two_passes, RenderingDevice::INVALID_ID, view_count);
+ }
- color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
+ // - add alpha pass (with resolve, we just added that above)
+ passes.push_back(pass);
+ color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+
+ {
+ // we also need our one pass with resolve
+ Vector<RD::FramebufferPass> one_pass_with_resolve;
+ one_pass_with_resolve.push_back(pass); // note our pass configuration already has resolve..
+ color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, one_pass_with_resolve, RenderingDevice::INVALID_ID, view_count);
+ }
+
+ if (!is_half_resolution) {
+ // - add blit to 2D pass
+ fb.push_back(p_target_buffer); // 3 - target buffer
+ RD::FramebufferPass blit_pass;
+ blit_pass.color_attachments.push_back(3);
+ blit_pass.input_attachments.push_back(2);
+ passes.push_back(blit_pass);
+
+ color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
+ } else {
+ // can't do our blit pass if resolutions don't match
+ color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID();
+ }
}
}
}
+RID RenderForwardMobile::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
+ // Our attachments
+ Vector<RID> fb;
+ fb.push_back(p_color); // 0
+ fb.push_back(p_depth); // 1
+
+ // Now define our subpasses
+ Vector<RD::FramebufferPass> passes;
+ RD::FramebufferPass pass;
+
+ // re-using the same attachments
+ pass.color_attachments.push_back(0);
+ pass.depth_attachment = 1;
+
+ // - opaque pass
+ passes.push_back(pass);
+
+ // - sky pass
+ passes.push_back(pass);
+
+ // - alpha pass
+ passes.push_back(pass);
+
+ return RD::get_singleton()->framebuffer_create_multipass(fb, passes);
+}
+
RenderForwardMobile::RenderBufferDataForwardMobile::~RenderBufferDataForwardMobile() {
clear();
}
@@ -131,6 +271,17 @@ bool RenderForwardMobile::free(RID p_rid) {
/* Render functions */
+RD::DataFormat RenderForwardMobile::_render_buffers_get_color_format() {
+ // Using 32bit buffers enables AFBC on mobile devices which should have a definite performance improvement (MALI G710 and newer support this on 64bit RTs)
+ return RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
+}
+
+bool RenderForwardMobile::_render_buffers_can_be_storage() {
+ // Using 32bit buffers enables AFBC on mobile devices which should have a definite performance improvement (MALI G710 and newer support this on 64bit RTs)
+ // Doesn't support storage
+ return false;
+}
+
RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) {
//there should always be enough uniform buffers for render passes, otherwise bugs
ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
@@ -326,14 +477,29 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
scene_state.ubo.viewport_size[1] = vp_he.y;
scene_state.ubo.directional_light_count = 0;
+ // We can only use our full subpass approach if we're:
+ // - not reading from SCREEN_TEXTURE/DEPTH_TEXTURE
+ // - not using ssr/sss (currently not supported)
+ // - not using glow or other post effects (can't do 4th subpass)
+ // - rendering to a half sized render buffer (can't do 4th subpass)
+ // We'll need to restrict how far we're going with subpasses based on this.
+
Size2i screen_size;
- RID opaque_framebuffer;
- RID alpha_framebuffer;
+ RID framebuffer;
bool reverse_cull = false;
+ bool using_subpass_transparent = true;
+ bool using_subpass_post_process = true;
+
+ bool is_half_resolution = false; // Set this once we support this feature.
+ bool using_ssr = false; // I don't think we support this in our mobile renderer so probably should phase it out
+ bool using_sss = false; // I don't think we support this in our mobile renderer so probably should phase it out
- // I don't think we support either of these in our mobile renderer so probably should phase them out
- bool using_ssr = false;
- bool using_sss = false;
+ // fill our render lists early so we can find out if we use various features
+ _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
+ render_list[RENDER_LIST_OPAQUE].sort_by_key();
+ render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
+ _fill_element_info(RENDER_LIST_OPAQUE);
+ _fill_element_info(RENDER_LIST_ALPHA);
if (p_render_data->render_info) {
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_render_data->instances->size();
@@ -345,15 +511,36 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
screen_size.x = render_buffer->width;
screen_size.y = render_buffer->height;
- opaque_framebuffer = render_buffer->color_fb;
- alpha_framebuffer = opaque_framebuffer;
+ if (is_half_resolution) {
+ // can't do blit subpass
+ using_subpass_post_process = false;
+ } else if (env && (env->glow_enabled || env->auto_exposure || camera_effects_uses_dof(p_render_data->camera_effects))) {
+ // can't do blit subpass
+ using_subpass_post_process = false;
+ }
+
+ if (using_ssr || using_sss || scene_state.used_screen_texture || scene_state.used_depth_texture) {
+ // can't use our last two subpasses
+ using_subpass_transparent = false;
+ using_subpass_post_process = false;
+ }
+
+ if (using_subpass_post_process) {
+ // all as subpasses
+ framebuffer = render_buffer->color_fbs[FB_CONFIG_FOUR_SUBPASSES];
+ } else if (using_subpass_transparent) {
+ // our tonemap pass is separate
+ framebuffer = render_buffer->color_fbs[FB_CONFIG_THREE_SUBPASSES];
+ } else {
+ // only opaque and sky as subpasses
+ framebuffer = render_buffer->color_fbs[FB_CONFIG_TWO_SUBPASSES];
+ }
} else if (p_render_data->reflection_probe.is_valid()) {
uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
screen_size.x = resolution;
screen_size.y = resolution;
- opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
- alpha_framebuffer = opaque_framebuffer;
+ framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
p_render_data->environment = RID(); //no environment on interiors
@@ -361,6 +548,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
reverse_cull = true;
+ using_subpass_transparent = true; // we ignore our screen/depth texture here
+ using_subpass_post_process = false; // not applicable at all for reflection probes.
} else {
ERR_FAIL(); //bug?
}
@@ -372,17 +561,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
- _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
- render_list[RENDER_LIST_OPAQUE].sort_by_key();
- render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
-
- // we no longer use this...
- _fill_instance_data(RENDER_LIST_OPAQUE);
- _fill_instance_data(RENDER_LIST_ALPHA);
-
- RD::get_singleton()->draw_command_end_label();
-
- // note, no depth prepass here!
+ RD::get_singleton()->draw_command_end_label(); // Render Setup
// setup environment
RID radiance_texture;
@@ -457,97 +636,201 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// do not try to draw sky if invalid
draw_sky = false;
}
- RD::get_singleton()->draw_command_end_label();
+ RD::get_singleton()->draw_command_end_label(); // Setup Sky
}
} else {
clear_color = p_default_bg_color;
}
- // opaque pass
+ // update sky buffers (if required)
+ if (draw_sky || draw_sky_fog_only) {
+ // !BAS! @TODO See if we can limit doing some things double and maybe even move this into _pre_opaque_render
+ // and change Forward Clustered in the same way as we have here (but without using subpasses)
+ RENDER_TIMESTAMP("Setup Sky resolution buffers");
+
+ RD::get_singleton()->draw_command_begin_label("Setup Sky resolution buffers");
+
+ if (p_render_data->reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ CameraMatrix projection = correction * p_render_data->cam_projection;
+ sky.update_res_buffers(env, 1, &projection, p_render_data->cam_transform, time);
+ } else {
+ sky.update_res_buffers(env, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
+ }
+
+ RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
+ }
- // !BAS! Look into this, seems most of the code in here related to clustered only, may want to move this code into ForwardClustered/RenderForwardMobile before calling it from here
- // does trigger shadow map rendering so kinda important
_pre_opaque_render(p_render_data, false, false, RID(), RID());
- RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
+ {
+ if (render_buffer) {
+ RD::get_singleton()->draw_command_begin_label("Render 3D Pass");
+ } else {
+ RD::get_singleton()->draw_command_begin_label("Render Reflection Probe Pass");
+ }
- scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
+ // opaque pass
- _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
+ RD::get_singleton()->draw_command_begin_label("Render Opaque Subpass");
- RENDER_TIMESTAMP("Render Opaque Pass");
+ scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
+ _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
- bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
- bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
+ if (using_subpass_transparent && using_subpass_post_process) {
+ RENDER_TIMESTAMP("Render Opaque + Transparent + Tonemap");
+ } else if (using_subpass_transparent) {
+ RENDER_TIMESTAMP("Render Opaque + Transparent");
+ } else {
+ RENDER_TIMESTAMP("Render Opaque");
+ }
- {
- bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
- bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
- // regular forward for now
- Vector<Color> c;
- c.push_back(clear_color.to_linear());
+ bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture && !using_ssr && !using_sss;
+ bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture && !using_ssr && !using_sss;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
- _render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
- }
+ {
+ // regular forward for now
+ Vector<Color> c;
+ c.push_back(clear_color.to_linear()); // our render buffer
+ if (render_buffer) {
+ if (render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ c.push_back(clear_color.to_linear()); // our resolve buffer
+ }
+ if (using_subpass_post_process) {
+ c.push_back(Color()); // our 2D buffer we're copying into
+ }
+ }
- RD::get_singleton()->draw_command_end_label();
+ RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ render_list_params.framebuffer_format = fb_format;
+ if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
+ // secondary command buffers need more testing at this time
+ //multi threaded
+ thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params);
+ } else {
+ //single threaded
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
+ _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
+ }
+ }
- if (draw_sky || draw_sky_fog_only) {
- RENDER_TIMESTAMP("Render Sky");
+ RD::get_singleton()->draw_command_end_label(); //Render Opaque Subpass
- RD::get_singleton()->draw_command_begin_label("Draw Sky");
+ if (draw_sky || draw_sky_fog_only) {
+ RD::get_singleton()->draw_command_begin_label("Draw Sky Subpass");
- if (p_render_data->reflection_probe.is_valid()) {
- CameraMatrix correction;
- correction.set_depth_correction(true);
- CameraMatrix projection = correction * p_render_data->cam_projection;
- sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, 1, &projection, p_render_data->cam_transform, time);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
+
+ if (p_render_data->reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ CameraMatrix projection = correction * p_render_data->cam_projection;
+ sky.draw(draw_list, env, framebuffer, 1, &projection, p_render_data->cam_transform, time);
+ } else {
+ sky.draw(draw_list, env, framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
+ }
+
+ RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass
+
+ // note, if MSAA is used in 2-subpass approach we should get an automatic resolve here
} else {
- sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
+ // switch to subpass but we do nothing here so basically we skip (though this should trigger resolve with 2-subpass MSAA).
+ RD::get_singleton()->draw_list_switch_to_next_pass();
}
- RD::get_singleton()->draw_command_end_label();
- }
- if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color);
- /*
- if (using_separate_specular) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular);
+ if (!using_subpass_transparent) {
+ // We're done with our subpasses so end our container pass
+ RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
+
+ RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
}
- */
- }
- if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth);
- }
+ // transparent pass
+
+ RD::get_singleton()->draw_command_begin_label("Render Transparent Subpass");
- // transparent pass
- RENDER_TIMESTAMP("Render Transparent Pass");
+ rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
- RD::get_singleton()->draw_command_begin_label("Render Transparent Pass");
+ if (using_subpass_transparent) {
+ RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ render_list_params.framebuffer_format = fb_format;
+ if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
+ // secondary command buffers need more testing at this time
+ //multi threaded
+ thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ RD::get_singleton()->draw_list_switch_to_next_pass_split(thread_draw_lists.size(), thread_draw_lists.ptr());
+ render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass();
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params);
+ } else {
+ //single threaded
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
+ render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass();
+ _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
+ }
- rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
+ RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass
- _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
+ // note if we are using MSAA we should get an automatic resolve through our subpass configuration.
- {
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
- _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ // blit to tonemap
+ if (render_buffer && using_subpass_post_process) {
+ _post_process_subpass(render_buffer->color, framebuffer, p_render_data);
+ }
+
+ RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
+
+ RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
+ } else {
+ RENDER_TIMESTAMP("Render Transparent");
+
+ framebuffer = render_buffer->color_fbs[FB_CONFIG_ONE_PASS];
+
+ // this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
+ // _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
+
+ RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ render_list_params.framebuffer_format = fb_format;
+ if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
+ // secondary command buffers need more testing at this time
+ //multi threaded
+ thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params);
+ RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
+ } else {
+ //single threaded
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
+ RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
+ }
+
+ RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass
+ }
}
- RD::get_singleton()->draw_command_end_label();
+ if (render_buffer && !using_subpass_post_process) {
+ RD::get_singleton()->draw_command_begin_label("Post process pass");
- RD::get_singleton()->draw_command_begin_label("Resolve");
+ // If we need extra effects we do this in its own pass
+ RENDER_TIMESTAMP("Tonemap");
- if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color);
+ _render_buffers_post_process_and_tonemap(p_render_data);
+
+ RD::get_singleton()->draw_command_end_label(); // Post process pass
}
- RD::get_singleton()->draw_command_end_label();
+ if (render_buffer) {
+ _disable_clear_request(p_render_data);
+ }
}
/* these are being called from RendererSceneRenderRD::_pre_opaque_render */
@@ -596,7 +879,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
- _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false);
+ _fill_element_info(RENDER_LIST_SECONDARY, render_list_from, render_list_size);
{
//regular forward for now
@@ -674,7 +957,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_instance_data(RENDER_LIST_SECONDARY);
+ _fill_element_info(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -715,7 +998,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_in
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_instance_data(RENDER_LIST_SECONDARY);
+ _fill_element_info(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -788,7 +1071,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
- _fill_instance_data(RENDER_LIST_SECONDARY);
+ _fill_element_info(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@@ -853,13 +1136,67 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (decals_get_filter()) {
+ case RS::DECAL_FILTER_NEAREST: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.ids.push_back(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ RID sampler;
+ switch (light_projectors_get_filter()) {
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
+ sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
+ }
+
+ u.ids.push_back(sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_omni_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 4;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_spot_light_buffer());
uniforms.push_back(u);
@@ -867,35 +1204,35 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
{
RD::Uniform u;
- u.binding = 5;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 6;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.ids.push_back(get_directional_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 7;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(scene_state.lightmap_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(scene_state.lightmap_capture_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
- u.binding = 9;
+ u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = storage->decal_atlas_get_texture();
u.ids.push_back(decal_atlas);
@@ -903,7 +1240,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
}
{
RD::Uniform u;
- u.binding = 10;
+ u.binding = 12;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID decal_atlas = storage->decal_atlas_get_texture_srgb();
u.ids.push_back(decal_atlas);
@@ -911,7 +1248,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
}
{
RD::Uniform u;
- u.binding = 11;
+ u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.ids.push_back(get_decal_buffer());
uniforms.push_back(u);
@@ -920,7 +1257,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 12;
+ u.binding = 14;
u.ids.push_back(storage->global_variables_get_storage_buffer());
uniforms.push_back(u);
}
@@ -1157,11 +1494,6 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
RendererStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
- scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get();
- scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get();
- scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get();
- scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get();
-
Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
@@ -1325,9 +1657,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
}
-void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
- // !BAS! Rename this to make clear this is not the same as with the forward renderer and remove p_update_buffer?
-
+void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) {
RenderList *rl = &render_list[p_render_list];
uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
@@ -1392,6 +1722,44 @@ void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_para
}
}
+void RenderForwardMobile::_fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, const GeometryInstanceForwardMobile *p_instance) {
+ // first zero out our indices
+
+ p_push_constant->omni_lights[0] = 0xFFFF;
+ p_push_constant->omni_lights[1] = 0xFFFF;
+
+ p_push_constant->spot_lights[0] = 0xFFFF;
+ p_push_constant->spot_lights[1] = 0xFFFF;
+
+ p_push_constant->decals[0] = 0xFFFF;
+ p_push_constant->decals[1] = 0xFFFF;
+
+ p_push_constant->reflection_probes[0] = 0xFFFF;
+ p_push_constant->reflection_probes[1] = 0xFFFF;
+
+ for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
+ uint32_t ofs = i < 4 ? 0 : 1;
+ uint32_t shift = (i & 0x3) << 3;
+ uint32_t mask = ~(0xFF << shift);
+ if (i < p_instance->omni_light_count) {
+ p_push_constant->omni_lights[ofs] &= mask;
+ p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
+ }
+ if (i < p_instance->spot_light_count) {
+ p_push_constant->spot_lights[ofs] &= mask;
+ p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
+ }
+ if (i < p_instance->decals_count) {
+ p_push_constant->decals[ofs] &= mask;
+ p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
+ }
+ if (i < p_instance->reflection_probe_count) {
+ p_push_constant->reflection_probes[ofs] &= mask;
+ p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
+ }
+ }
+}
+
template <RenderForwardMobile::PassMode p_pass_mode>
void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
RD::DrawListID draw_list = p_draw_list;
@@ -1441,8 +1809,6 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
push_constant.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
};
- _fill_instance_indices(inst->omni_lights, inst->omni_light_count, push_constant.omni_lights, inst->spot_lights, inst->spot_light_count, push_constant.spot_lights, inst->reflection_probes, inst->reflection_probe_count, push_constant.reflection_probes, inst->decals, inst->decals_count, push_constant.decals, push_constant.layer_mask);
-
RID material_uniform_set;
SceneShaderForwardMobile::ShaderData *shader;
void *mesh_surface;
@@ -1453,6 +1819,8 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
mesh_surface = surf->surface_shadow;
} else {
+ _fill_push_constant_instance_indices(&push_constant, inst);
+
#ifdef DEBUG_ENABLED
if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
material_uniform_set = scene_shader.default_material_uniform_set;
@@ -1543,7 +1911,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
prev_index_array_rd = index_array_rd;
}
- RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe);
+ RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass);
if (pipeline_rd != prev_pipeline_rd) {
// checking with prev shader does not make so much sense, as
@@ -1558,8 +1926,8 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
}
if (material_uniform_set != prev_material_uniform_set) {
- //update uniform set
- if (material_uniform_set.is_valid()) {
+ // Update uniform set.
+ if (RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
}
@@ -1761,13 +2129,13 @@ void RenderForwardMobile::geometry_instance_pair_light_instances(GeometryInstanc
switch (type) {
case RS::LIGHT_OMNI: {
if (ginstance->omni_light_count < (uint32_t)MAX_RDL_CULL) {
- ginstance->omni_lights[ginstance->omni_light_count] = p_light_instances[i];
+ ginstance->omni_lights[ginstance->omni_light_count] = light_instance_get_forward_id(p_light_instances[i]);
ginstance->omni_light_count++;
}
} break;
case RS::LIGHT_SPOT: {
if (ginstance->spot_light_count < (uint32_t)MAX_RDL_CULL) {
- ginstance->spot_lights[ginstance->spot_light_count] = p_light_instances[i];
+ ginstance->spot_lights[ginstance->spot_light_count] = light_instance_get_forward_id(p_light_instances[i]);
ginstance->spot_light_count++;
}
} break;
@@ -1783,7 +2151,7 @@ void RenderForwardMobile::geometry_instance_pair_reflection_probe_instances(Geom
ginstance->reflection_probe_count = p_reflection_probe_instance_count < (uint32_t)MAX_RDL_CULL ? p_reflection_probe_instance_count : (uint32_t)MAX_RDL_CULL;
for (uint32_t i = 0; i < ginstance->reflection_probe_count; i++) {
- ginstance->reflection_probes[i] = p_reflection_probe_instances[i];
+ ginstance->reflection_probes[i] = reflection_probe_instance_get_forward_id(p_reflection_probe_instances[i]);
}
}
@@ -1793,7 +2161,7 @@ void RenderForwardMobile::geometry_instance_pair_decal_instances(GeometryInstanc
ginstance->decals_count = p_decal_instance_count < (uint32_t)MAX_RDL_CULL ? p_decal_instance_count : (uint32_t)MAX_RDL_CULL;
for (uint32_t i = 0; i < ginstance->decals_count; i++) {
- ginstance->decals[i] = p_decal_instances[i];
+ ginstance->decals[i] = decal_instance_get_forward_id(p_decal_instances[i]);
}
}
@@ -1801,6 +2169,9 @@ void RenderForwardMobile::geometry_instance_pair_voxel_gi_instances(GeometryInst
// We do not have this here!
}
+void RenderForwardMobile::geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) {
+}
+
void RenderForwardMobile::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
if (ginstance->dirty_list_element.in_list()) {
@@ -2150,10 +2521,54 @@ uint32_t RenderForwardMobile::get_max_elements() const {
RenderForwardMobile *RenderForwardMobile::singleton = nullptr;
+void RenderForwardMobile::_update_shader_quality_settings() {
+ Vector<RD::PipelineSpecializationConstant> spec_constants;
+
+ RD::PipelineSpecializationConstant sc;
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
+
+ sc.constant_id = SPEC_CONSTANT_SOFT_SHADOW_SAMPLES;
+ sc.int_value = soft_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES;
+ sc.int_value = penumbra_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES;
+ sc.int_value = directional_soft_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES;
+ sc.int_value = directional_penumbra_shadow_samples_get();
+
+ spec_constants.push_back(sc);
+
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ sc.constant_id = SPEC_CONSTANT_DECAL_FILTER;
+ sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+
+ spec_constants.push_back(sc);
+
+ sc.constant_id = SPEC_CONSTANT_PROJECTOR_FILTER;
+ sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+
+ spec_constants.push_back(sc);
+
+ scene_shader.set_default_specialization_constants(spec_constants);
+
+ _base_uniforms_changed(); //also need this
+}
+
RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) :
RendererSceneRenderRD(p_storage) {
singleton = this;
+ sky.set_texture_format(_render_buffers_get_color_format());
+
String defines;
defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
@@ -2185,6 +2600,8 @@ RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) :
// !BAS! maybe we need a mobile version of this setting?
render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
+
+ _update_shader_quality_settings();
}
RenderForwardMobile::~RenderForwardMobile() {
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index f40f713c03..b981592840 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -42,6 +42,18 @@ namespace RendererSceneRenderImplementation {
class RenderForwardMobile : public RendererSceneRenderRD {
friend SceneShaderForwardMobile;
+ struct ForwardIDAllocator {
+ LocalVector<bool> allocations;
+ LocalVector<uint8_t> map;
+ };
+
+ ForwardIDAllocator forward_id_allocators[FORWARD_ID_MAX];
+
+ virtual ForwardID _allocate_forward_id(ForwardIDType p_type) override;
+ virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) override;
+ virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) override;
+ virtual bool _uses_forward_ids() const override { return true; }
+
protected:
/* Scene Shader */
@@ -53,6 +65,15 @@ protected:
};
enum {
+ SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 6,
+ SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 7,
+ SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 8,
+ SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 9,
+ SPEC_CONSTANT_DECAL_FILTER = 10,
+ SPEC_CONSTANT_PROJECTOR_FILTER = 11,
+ };
+
+ enum {
MAX_LIGHTMAPS = 8,
MAX_RDL_CULL = 8, // maximum number of reflection probes, decals or lights we can cull per geometry instance
INSTANCE_DATA_BUFFER_MIN_SIZE = 4096
@@ -71,6 +92,18 @@ protected:
/* Render Buffer */
+ // We can have:
+ // - 4 subpasses combining the full render cycle
+ // - 3 subpasses + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
+ // - 2 subpasses + 1 normal pass for transparent + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
+ enum RenderBufferMobileFramebufferConfigType {
+ FB_CONFIG_ONE_PASS, // Single pass frame buffer for alpha pass
+ FB_CONFIG_TWO_SUBPASSES, // Opaque + Sky sub pass
+ FB_CONFIG_THREE_SUBPASSES, // Opaque + Sky + Alpha sub pass
+ FB_CONFIG_FOUR_SUBPASSES, // Opaque + Sky + Alpha sub pass + Tonemap pass
+ FB_CONFIG_MAX
+ };
+
struct RenderBufferDataForwardMobile : public RenderBufferData {
RID color;
RID depth;
@@ -83,12 +116,12 @@ protected:
RID depth_msaa;
// RID normal_roughness_buffer_msaa;
- RID color_fb;
+ RID color_fbs[FB_CONFIG_MAX];
int width, height;
uint32_t view_count;
void clear();
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
~RenderBufferDataForwardMobile();
};
@@ -131,6 +164,7 @@ protected:
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
uint32_t barrier = RD::BARRIER_MASK_ALL;
+ uint32_t subpass = 0;
RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
elements = p_elements;
@@ -151,6 +185,9 @@ protected:
}
};
+ virtual RD::DataFormat _render_buffers_get_color_format() override;
+ virtual bool _render_buffers_can_be_storage() override;
+
RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
@@ -171,7 +208,7 @@ protected:
virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override;
void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
- void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
+ void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1);
// void _update_instance_data_buffer(RenderListType p_render_list);
static RenderForwardMobile *singleton;
@@ -213,11 +250,6 @@ protected:
float penumbra_shadow_kernel[128];
float soft_shadow_kernel[128];
- uint32_t directional_penumbra_shadow_samples;
- uint32_t directional_soft_shadow_samples;
- uint32_t penumbra_shadow_samples;
- uint32_t soft_shadow_samples;
-
float ambient_light_color_energy[4];
float ambient_color_sky_mix;
@@ -513,14 +545,14 @@ protected:
GeometryInstanceLightmapSH *lightmap_sh = nullptr;
// culled light info
- uint32_t reflection_probe_count;
- RID reflection_probes[MAX_RDL_CULL];
- uint32_t omni_light_count;
- RID omni_lights[MAX_RDL_CULL];
- uint32_t spot_light_count;
- RID spot_lights[MAX_RDL_CULL];
- uint32_t decals_count;
- RID decals[MAX_RDL_CULL];
+ uint32_t reflection_probe_count = 0;
+ ForwardID reflection_probes[MAX_RDL_CULL];
+ uint32_t omni_light_count = 0;
+ ForwardID omni_lights[MAX_RDL_CULL];
+ uint32_t spot_light_count = 0;
+ ForwardID spot_lights[MAX_RDL_CULL];
+ uint32_t decals_count = 0;
+ ForwardID decals[MAX_RDL_CULL];
GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
@@ -552,7 +584,13 @@ protected:
dirty_list_element(this) {}
};
+ _FORCE_INLINE_ void _fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, const GeometryInstanceForwardMobile *p_instance);
+
+ void _update_shader_quality_settings() override;
+
public:
+ virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth) override;
+
static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker);
static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker);
@@ -594,6 +632,8 @@ public:
virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override;
virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override;
+ virtual void geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) override;
+
virtual bool free(RID p_rid) override;
virtual bool is_dynamic_gi_supported() const override;
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 7709c8aadc..bcdcb05653 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -318,7 +318,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
}
RID shader_variant = shader_singleton->shader.version_get_shader(version, k);
- pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants);
}
}
}
@@ -402,7 +402,8 @@ RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_sour
return shader_singleton->shader.version_get_native_source_code(version);
}
-SceneShaderForwardMobile::ShaderData::ShaderData() {
+SceneShaderForwardMobile::ShaderData::ShaderData() :
+ shader_list_element(this) {
valid = false;
uses_screen_texture = false;
}
@@ -418,6 +419,7 @@ SceneShaderForwardMobile::ShaderData::~ShaderData() {
RendererStorageRD::ShaderData *SceneShaderForwardMobile::_create_shader_func() {
ShaderData *shader_data = memnew(ShaderData);
+ singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
}
@@ -671,7 +673,19 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
//default material and shader
default_shader = storage->shader_allocate();
storage->shader_initialize(default_shader);
- storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
+ storage->shader_set_code(default_shader, R"(
+shader_type spatial;
+
+void vertex() {
+ ROUGHNESS = 0.8;
+}
+
+void fragment() {
+ ALBEDO = vec3(0.6);
+ ROUGHNESS = 0.8;
+ METALLIC = 0.2;
+}
+)");
default_material = storage->material_allocate();
storage->material_initialize(default_material);
storage->material_set_shader(default_material, default_shader);
@@ -687,7 +701,16 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
overdraw_material_shader = storage->shader_allocate();
storage->shader_initialize(overdraw_material_shader);
// Use relatively low opacity so that more "layers" of overlapping objects can be distinguished.
- storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.1; }");
+ storage->shader_set_code(overdraw_material_shader, R"(
+shader_type spatial;
+
+render_mode blend_add, unshaded;
+
+void fragment() {
+ ALBEDO = vec3(0.4, 0.8, 0.8);
+ ALPHA = 0.1;
+}
+)");
overdraw_material = storage->material_allocate();
storage->material_initialize(overdraw_material);
storage->material_set_shader(overdraw_material, overdraw_material_shader);
@@ -718,6 +741,19 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p
}
}
+void SceneShaderForwardMobile::set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants) {
+ default_specialization_constants = p_constants;
+ for (SelfList<ShaderData> *E = shader_list.first(); E; E = E->next()) {
+ for (int i = 0; i < ShaderData::CULL_VARIANT_MAX; i++) {
+ for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
+ for (int k = 0; k < SHADER_VERSION_MAX; k++) {
+ E->self()->pipelines[i][j][k].update_specialization_constants(default_specialization_constants);
+ }
+ }
+ }
+ }
+}
+
SceneShaderForwardMobile::~SceneShaderForwardMobile() {
RD::get_singleton()->free(default_vec4_xform_buffer);
RD::get_singleton()->free(shadow_sampler);
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 5c9e35fd0d..e1c10f0206 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -151,6 +151,8 @@ public:
virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+ SelfList<ShaderData> shader_list_element;
+
ShaderData();
virtual ~ShaderData();
};
@@ -174,6 +176,8 @@ public:
virtual ~MaterialData();
};
+ SelfList<ShaderData>::List shader_list;
+
RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
return static_cast<SceneShaderForwardMobile *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
@@ -202,7 +206,10 @@ public:
SceneShaderForwardMobile();
~SceneShaderForwardMobile();
+ Vector<RD::PipelineSpecializationConstant> default_specialization_constants;
+
void init(RendererStorageRD *p_storage, const String p_defines);
+ void set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants);
};
} // namespace RendererSceneRenderImplementation
diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp
index 22888ddbe5..aefe926cb0 100644
--- a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp
+++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp
@@ -31,14 +31,30 @@
#include "pipeline_cache_rd.h"
#include "core/os/memory.h"
-RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass) {
+RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass, uint32_t p_bool_specializations) {
RD::PipelineMultisampleState multisample_state_version = multisample_state;
multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id, p_render_pass);
RD::PipelineRasterizationState raster_state_version = rasterization_state;
raster_state_version.wireframe = p_wireframe;
- RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, raster_state_version, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags, p_render_pass);
+ Vector<RD::PipelineSpecializationConstant> specialization_constants = base_specialization_constants;
+
+ uint32_t bool_index = 0;
+ uint32_t bool_specializations = p_bool_specializations;
+ while (bool_specializations) {
+ if (bool_specializations & (1 << bool_index)) {
+ RD::PipelineSpecializationConstant sc;
+ sc.bool_value = true;
+ sc.constant_id = bool_index;
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ specialization_constants.push_back(sc);
+ bool_specializations &= ~(1 << bool_index);
+ }
+ bool_index++;
+ }
+
+ RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, raster_state_version, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags, p_render_pass, specialization_constants);
ERR_FAIL_COND_V(pipeline.is_null(), RID());
versions = (Version *)memrealloc(versions, sizeof(Version) * (version_count + 1));
versions[version_count].framebuffer_id = p_framebuffer_format_id;
@@ -46,11 +62,15 @@ RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD
versions[version_count].wireframe = p_wireframe;
versions[version_count].pipeline = pipeline;
versions[version_count].render_pass = p_render_pass;
+ versions[version_count].bool_specializations = p_bool_specializations;
version_count++;
return pipeline;
}
void PipelineCacheRD::_clear() {
+#ifndef _MSC_VER
+#warning Clear should probably recompile all the variants already compiled instead to avoid stalls? needs discussion
+#endif
if (versions) {
for (uint32_t i = 0; i < version_count; i++) {
//shader may be gone, so this may not be valid
@@ -64,7 +84,7 @@ void PipelineCacheRD::_clear() {
}
}
-void PipelineCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) {
+void PipelineCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, const Vector<RD::PipelineSpecializationConstant> &p_base_specialization_constants) {
ERR_FAIL_COND(p_shader.is_null());
_clear();
shader = p_shader;
@@ -75,6 +95,11 @@ void PipelineCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const
depth_stencil_state = p_depth_stencil_state;
blend_state = p_blend_state;
dynamic_state_flags = p_dynamic_state_flags;
+ base_specialization_constants = p_base_specialization_constants;
+}
+void PipelineCacheRD::update_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_base_specialization_constants) {
+ base_specialization_constants = p_base_specialization_constants;
+ _clear();
}
void PipelineCacheRD::update_shader(RID p_shader) {
diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h
index 387a8a038f..e52f47fa47 100644
--- a/servers/rendering/renderer_rd/pipeline_cache_rd.h
+++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h
@@ -46,27 +46,30 @@ class PipelineCacheRD {
RD::PipelineDepthStencilState depth_stencil_state;
RD::PipelineColorBlendState blend_state;
int dynamic_state_flags;
+ Vector<RD::PipelineSpecializationConstant> base_specialization_constants;
struct Version {
RD::VertexFormatID vertex_id;
RD::FramebufferFormatID framebuffer_id;
uint32_t render_pass;
bool wireframe;
+ uint32_t bool_specializations;
RID pipeline;
};
Version *versions;
uint32_t version_count;
- RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass);
+ RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass, uint32_t p_bool_specializations = 0);
void _clear();
public:
- void setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0);
+ void setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, const Vector<RD::PipelineSpecializationConstant> &p_base_specialization_constants = Vector<RD::PipelineSpecializationConstant>());
+ void update_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_base_specialization_constants);
void update_shader(RID p_shader);
- _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe = false, uint32_t p_render_pass = 0) {
+ _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe = false, uint32_t p_render_pass = 0, uint32_t p_bool_specializations = 0) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_V_MSG(shader.is_null(), RID(),
"Attempted to use an unused shader variant (shader is null),");
@@ -75,13 +78,13 @@ public:
spin_lock.lock();
RID result;
for (uint32_t i = 0; i < version_count; i++) {
- if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id && versions[i].wireframe == p_wireframe && versions[i].render_pass == p_render_pass) {
+ if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id && versions[i].wireframe == p_wireframe && versions[i].render_pass == p_render_pass && versions[i].bool_specializations == p_bool_specializations) {
result = versions[i].pipeline;
spin_lock.unlock();
return result;
}
}
- result = _generate_version(p_vertex_format_id, p_framebuffer_format_id, p_wireframe, p_render_pass);
+ result = _generate_version(p_vertex_format_id, p_framebuffer_format_id, p_wireframe, p_render_pass, p_bool_specializations);
spin_lock.unlock();
return result;
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 1e3dbe69a3..14b2768c29 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -480,6 +480,10 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
case Item::Command::TYPE_RECT: {
const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
+ if (rect->flags & CANVAS_RECT_TILE) {
+ current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
+ }
+
//bind pipeline
{
RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
@@ -620,7 +624,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
RD::get_singleton()->draw_list_draw(p_draw_list, true);
- //restore if overrided
+ // Restore if overridden.
push_constant.color_texture_pixel_size[0] = texpixel_size.x;
push_constant.color_texture_pixel_size[1] = texpixel_size.y;
@@ -1089,7 +1093,8 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
if (material_data) {
if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
pipeline_variants = &material_data->shader_data->pipeline_variants;
- if (material_data->uniform_set.is_valid()) {
+ // Update uniform set.
+ if (RD::get_singleton()->uniform_set_is_valid(material_data->uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, MATERIAL_UNIFORM_SET);
}
} else {
@@ -2570,8 +2575,19 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) {
default_canvas_group_shader = storage->shader_allocate();
storage->shader_initialize(default_canvas_group_shader);
- storage->shader_set_code(default_canvas_group_shader, "shader_type canvas_item; \nvoid fragment() {\n\tvec4 c = textureLod(SCREEN_TEXTURE,SCREEN_UV,0.0); if (c.a > 0.0001) c.rgb/=c.a; COLOR *= c; \n}\n");
+ storage->shader_set_code(default_canvas_group_shader, R"(
+shader_type canvas_item;
+
+void fragment() {
+ vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ if (c.a > 0.0001) {
+ c.rgb /= c.a;
+ }
+
+ COLOR *= c;
+}
+)");
default_canvas_group_material = storage->material_allocate();
storage->material_initialize(default_canvas_group_material);
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index a8f086b0f9..02d548bf13 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -173,7 +173,6 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
}
Size2 window_size = DisplayServer::get_singleton()->window_get_size();
- print_line("window size: " + window_size);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
Rect2 screenrect;
@@ -216,8 +215,6 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
blit.push_constant.upscale = 1.0;
blit.push_constant.aspect_ratio = 1.0;
- print_line("rect: " + screenrect);
-
RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
@@ -225,7 +222,7 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
RD::get_singleton()->swap_buffers();
- RD::get_singleton()->free(texture);
+ storage->free(texture);
}
RendererCompositorRD *RendererCompositorRD::singleton = nullptr;
@@ -283,6 +280,9 @@ RendererCompositorRD::RendererCompositorRD() {
// default to our high end renderer
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
}
+
+ // now we're ready to create our effects,
+ storage->init_effects(!scene->_render_buffers_can_be_storage());
}
RendererCompositorRD::~RendererCompositorRD() {
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 15b3b77ed9..8639362da9 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -80,7 +80,7 @@ protected:
Map<RID, RID> render_target_descriptors;
double time;
- float delta;
+ double delta;
static uint64_t frame;
@@ -100,7 +100,7 @@ public:
void finalize();
_ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; }
- _ALWAYS_INLINE_ float get_frame_delta_time() const { return delta; }
+ _ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
_ALWAYS_INLINE_ double get_total_time() const { return time; }
static Error is_viable() {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 46057bddab..fd797b1cab 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -567,6 +567,8 @@ int RendererSceneRenderRD::reflection_atlas_get_size(RID p_ref_atlas) const {
RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) {
ReflectionProbeInstance rpi;
rpi.probe = p_probe;
+ rpi.forward_id = _allocate_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE);
+
return reflection_probe_instance_owner.make_rid(rpi);
}
@@ -627,6 +629,8 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
ERR_FAIL_COND_V(!rpi, false);
+ RD::get_singleton()->draw_command_begin_label("Reflection probe render");
+
if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) {
WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings.");
reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count);
@@ -654,12 +658,12 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
//reflection atlas was unused, create:
RD::TextureFormat tf;
tf.array_layers = 6 * atlas->count;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = _render_buffers_get_color_format();
tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
tf.mipmaps = mipmaps;
tf.width = atlas->size;
tf.height = atlas->size;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
@@ -673,12 +677,9 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
}
atlas->reflections.resize(atlas->count);
for (int i = 0; i < atlas->count; i++) {
- atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers);
+ atlas->reflections.write[i].data.update_reflection_data(storage, atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers, _render_buffers_get_color_format());
for (int j = 0; j < 6; j++) {
- Vector<RID> fb;
- fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
- fb.push_back(atlas->depth_buffer);
- atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb);
+ atlas->reflections.write[i].fbs[j] = reflection_probe_create_framebuffer(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j], atlas->depth_buffer);
}
}
@@ -709,15 +710,28 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
}
}
+ if (rpi->atlas_index != -1) { // should we fail if this is still -1 ?
+ atlas->reflections.write[rpi->atlas_index].owner = p_instance;
+ }
+
rpi->atlas = p_reflection_atlas;
rpi->rendering = true;
rpi->dirty = false;
rpi->processing_layer = 1;
rpi->processing_side = 0;
+ RD::get_singleton()->draw_command_end_label();
+
return true;
}
+RID RendererSceneRenderRD::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
+ Vector<RID> fb;
+ fb.push_back(p_color);
+ fb.push_back(p_depth);
+ return RD::get_singleton()->framebuffer_create(fb);
+}
+
bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
ERR_FAIL_COND_V(!rpi, false);
@@ -1229,6 +1243,9 @@ RID RendererSceneRenderRD::light_instance_create(RID p_light) {
light_instance->self = li;
light_instance->light = p_light;
light_instance->light_type = storage->light_get_type(p_light);
+ if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) {
+ light_instance->forward_id = _allocate_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT);
+ }
return li;
}
@@ -1302,6 +1319,7 @@ RendererSceneRenderRD::ShadowCubemap *RendererSceneRenderRD::_get_shadow_cubemap
RID RendererSceneRenderRD::decal_instance_create(RID p_decal) {
DecalInstance di;
di.decal = p_decal;
+ di.forward_id = _allocate_forward_id(FORWARD_ID_TYPE_DECAL);
return decal_instance_owner.make_rid(di);
}
@@ -1373,12 +1391,20 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
uint32_t mipmaps_required = Image::get_image_required_mipmaps(rb->width, rb->height, Image::FORMAT_RGBAH);
+ // TODO make sure texture_create_shared_from_slice works for multiview
+
RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = _render_buffers_get_color_format(); // RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
tf.width = rb->width;
tf.height = rb->height;
- tf.texture_type = RD::TEXTURE_TYPE_2D;
- tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D;
+ tf.array_layers = rb->view_count;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ if (_render_buffers_can_be_storage()) {
+ tf.usage_bits += RD::TEXTURE_USAGE_STORAGE_BIT;
+ } else {
+ tf.usage_bits += RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
tf.mipmaps = mipmaps_required;
rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
@@ -1398,11 +1424,40 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
mm.width = base_width;
mm.height = base_height;
+ if (!_render_buffers_can_be_storage()) {
+ Vector<RID> fb;
+ fb.push_back(mm.texture);
+
+ mm.fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+
+ if (!_render_buffers_can_be_storage()) {
+ // and half texture, this is an intermediate result so just allocate a texture, is this good enough?
+ tf.width = MAX(1, base_width >> 1);
+ tf.height = base_height;
+ tf.mipmaps = 1; // 1 or 0?
+
+ mm.half_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ Vector<RID> half_fb;
+ half_fb.push_back(mm.half_texture);
+ mm.half_fb = RD::get_singleton()->framebuffer_create(half_fb);
+ }
+
rb->blur[0].mipmaps.push_back(mm);
if (i > 0) {
mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[1].texture, 0, i - 1);
+ if (!_render_buffers_can_be_storage()) {
+ Vector<RID> fb;
+ fb.push_back(mm.texture);
+
+ mm.fb = RD::get_singleton()->framebuffer_create(fb);
+
+ // We can re-use the half texture here as it is an intermediate result
+ }
+
rb->blur[1].mipmaps.push_back(mm);
}
@@ -1425,26 +1480,48 @@ void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) {
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
tf.width = w;
tf.height = h;
- tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
bool final = w == 1 && h == 1;
- if (final) {
- tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
+ if (_render_buffers_can_be_storage()) {
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+ if (final) {
+ tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
+ }
+ } else {
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
}
RID texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
rb->luminance.reduce.push_back(texture);
+ if (!_render_buffers_can_be_storage()) {
+ Vector<RID> fb;
+ fb.push_back(texture);
+
+ rb->luminance.fb.push_back(RD::get_singleton()->framebuffer_create(fb));
+ }
if (final) {
rb->luminance.current = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ if (!_render_buffers_can_be_storage()) {
+ Vector<RID> fb;
+ fb.push_back(rb->luminance.current);
+
+ rb->luminance.current_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
break;
}
}
}
void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
+ if (rb->texture_fb.is_valid()) {
+ RD::get_singleton()->free(rb->texture_fb);
+ rb->texture_fb = RID();
+ }
+
if (rb->texture.is_valid()) {
RD::get_singleton()->free(rb->texture);
rb->texture = RID();
@@ -1456,19 +1533,43 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
}
for (int i = 0; i < 2; i++) {
+ for (int m = 0; m < rb->blur[i].mipmaps.size(); m++) {
+ // do we free the texture slice here? or is it enough to free the main texture?
+
+ // do free the mobile extra stuff
+ if (rb->blur[i].mipmaps[m].fb.is_valid()) {
+ RD::get_singleton()->free(rb->blur[i].mipmaps[m].fb);
+ }
+ if (rb->blur[i].mipmaps[m].half_fb.is_valid()) {
+ RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_fb);
+ }
+ if (rb->blur[i].mipmaps[m].half_texture.is_valid()) {
+ RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_texture);
+ }
+ }
+ rb->blur[i].mipmaps.clear();
+
if (rb->blur[i].texture.is_valid()) {
RD::get_singleton()->free(rb->blur[i].texture);
rb->blur[i].texture = RID();
- rb->blur[i].mipmaps.clear();
}
}
+ for (int i = 0; i < rb->luminance.fb.size(); i++) {
+ RD::get_singleton()->free(rb->luminance.fb[i]);
+ }
+ rb->luminance.fb.clear();
+
for (int i = 0; i < rb->luminance.reduce.size(); i++) {
RD::get_singleton()->free(rb->luminance.reduce[i]);
}
-
rb->luminance.reduce.clear();
+ if (rb->luminance.current_fb.is_valid()) {
+ RD::get_singleton()->free(rb->luminance.current_fb);
+ rb->luminance.current_fb = RID();
+ }
+
if (rb->luminance.current.is_valid()) {
RD::get_singleton()->free(rb->luminance.current);
rb->luminance.current = RID();
@@ -1740,17 +1841,27 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
CameraEffects *camfx = camera_effects_owner.getornull(p_render_data->camera_effects);
bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+ bool can_use_storage = _render_buffers_can_be_storage();
+
+ // @TODO IMPLEMENT MULTIVIEW, all effects need to support stereo buffers or effects are only applied to the left eye
if (can_use_effects && camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0) {
+ RD::get_singleton()->draw_command_begin_label("DOF");
if (rb->blur[0].texture.is_null()) {
_allocate_blur_textures(rb);
}
- float bokeh_size = camfx->dof_blur_amount * 64.0;
- storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
+ if (can_use_storage) {
+ float bokeh_size = camfx->dof_blur_amount * 64.0;
+ storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
+ } else {
+ storage->get_effects()->blur_dof_raster(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->texture_fb, rb->blur[0].mipmaps[0].texture, rb->blur[0].mipmaps[0].fb, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, camfx->dof_blur_amount, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
+ }
+ RD::get_singleton()->draw_command_end_label();
}
if (can_use_effects && env && env->auto_exposure) {
+ RD::get_singleton()->draw_command_begin_label("Auto exposure");
if (rb->luminance.current.is_null()) {
_allocate_luminance_textures(rb);
}
@@ -1759,16 +1870,26 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
rb->auto_exposure_version = env->auto_exposure_version;
double step = env->auto_exp_speed * time_step;
- storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
-
+ if (can_use_storage) {
+ storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
+ } else {
+ storage->get_effects()->luminance_reduction_raster(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
+ }
//swap final reduce with prev luminance
SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]);
+ if (!can_use_storage) {
+ SWAP(rb->luminance.current_fb, rb->luminance.fb.write[rb->luminance.fb.size() - 1]);
+ }
+
RenderingServerDefault::redraw_request(); //redraw all the time if auto exposure rendering is on
+ RD::get_singleton()->draw_command_end_label();
}
int max_glow_level = -1;
if (can_use_effects && env && env->glow_enabled) {
+ RD::get_singleton()->draw_command_begin_label("Gaussian Glow");
+
/* see that blur textures are allocated */
if (rb->blur[1].texture.is_null()) {
@@ -1794,14 +1915,26 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
if (env->auto_exposure && rb->luminance.current.is_valid()) {
luminance_texture = rb->luminance.current;
}
- storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
+ if (can_use_storage) {
+ storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
+ } else {
+ storage->get_effects()->gaussian_glow_raster(rb->texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
+ }
} else {
- storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality);
+ if (can_use_storage) {
+ storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality);
+ } else {
+ storage->get_effects()->gaussian_glow_raster(rb->blur[1].mipmaps[i - 1].texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Vector2(1.0 / vp_w, 1.0 / vp_h), env->glow_strength, glow_high_quality);
+ }
}
}
+
+ RD::get_singleton()->draw_command_end_label();
}
{
+ RD::get_singleton()->draw_command_begin_label("Tonemap");
+
//tonemap
EffectsRD::TonemapSettings tonemap;
@@ -1860,11 +1993,81 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.view_count = p_render_data->view_count;
storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap);
+
+ RD::get_singleton()->draw_command_end_label();
}
storage->render_target_disable_clear_request(rb->render_target);
}
+void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data) {
+ RD::get_singleton()->draw_command_begin_label("Post Process Subpass");
+
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment);
+
+ bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
+
+ EffectsRD::TonemapSettings tonemap;
+
+ if (env) {
+ tonemap.tonemap_mode = env->tone_mapper;
+ tonemap.exposure = env->exposure;
+ tonemap.white = env->white;
+ }
+
+ // We don't support glow or auto exposure here, if they are needed, don't use subpasses!
+ // The problem is that we need to use the result so far and process them before we can
+ // apply this to our results.
+ if (can_use_effects && env && env->glow_enabled) {
+ ERR_FAIL_MSG("Glow is not supported when using subpasses.");
+ }
+ if (can_use_effects && env && env->auto_exposure) {
+ ERR_FAIL_MSG("Glow is not supported when using subpasses.");
+ }
+
+ tonemap.use_glow = false;
+ tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ tonemap.use_auto_exposure = false;
+ tonemap.exposure_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+
+ tonemap.use_color_correction = false;
+ tonemap.use_1d_color_correction = false;
+ tonemap.color_correction_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+
+ if (can_use_effects && env) {
+ tonemap.use_bcs = env->adjustments_enabled;
+ tonemap.brightness = env->adjustments_brightness;
+ tonemap.contrast = env->adjustments_contrast;
+ tonemap.saturation = env->adjustments_saturation;
+ if (env->adjustments_enabled && env->color_correction.is_valid()) {
+ tonemap.use_color_correction = true;
+ tonemap.use_1d_color_correction = env->use_1d_color_correction;
+ tonemap.color_correction_texture = storage->texture_get_rd_texture(env->color_correction);
+ }
+ }
+
+ tonemap.use_debanding = rb->use_debanding;
+ tonemap.texture_size = Vector2i(rb->width, rb->height);
+
+ tonemap.view_count = p_render_data->view_count;
+
+ storage->get_effects()->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap);
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_data) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ storage->render_target_disable_clear_request(rb->render_target);
+}
+
void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
EffectsRD *effects = storage->get_effects();
@@ -2114,8 +2317,16 @@ float RendererSceneRenderRD::render_buffers_get_volumetric_fog_detail_spread(RID
return rb->volumetric_fog->spread;
}
+RD::DataFormat RendererSceneRenderRD::_render_buffers_get_color_format() {
+ return RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+}
+
+bool RendererSceneRenderRD::_render_buffers_can_be_storage() {
+ return true;
+}
+
void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) {
- ERR_FAIL_COND_MSG(p_view_count == 0, "Must have atleast 1 view");
+ ERR_FAIL_COND_MSG(p_view_count == 0, "Must have at least 1 view");
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
rb->width = p_width;
@@ -2140,16 +2351,15 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
if (rb->view_count > 1) {
tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
}
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = _render_buffers_get_color_format();
tf.width = rb->width;
tf.height = rb->height;
tf.array_layers = rb->view_count; // create a layer for every view
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
- tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- } else {
- tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
}
+ tf.usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer
rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
@@ -2179,7 +2389,16 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
- rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa, p_view_count);
+ if (!_render_buffers_can_be_storage()) {
+ // ONLY USED ON MOBILE RENDERER, ONLY USED FOR POST EFFECTS!
+ Vector<RID> fb;
+ fb.push_back(rb->texture);
+
+ rb->texture_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, rb->view_count);
+ }
+
+ RID target_texture = storage->render_target_get_rd_texture(rb->render_target);
+ rb->data->configure(rb->texture, rb->depth_texture, target_texture, p_width, p_height, p_msaa, p_view_count);
if (is_clustered_enabled()) {
rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
@@ -2241,6 +2460,8 @@ void RendererSceneRenderRD::shadows_quality_set(RS::ShadowQuality p_quality) {
get_vogel_disk(penumbra_shadow_kernel, penumbra_shadow_samples);
get_vogel_disk(soft_shadow_kernel, soft_shadow_samples);
}
+
+ _update_shader_quality_settings();
}
void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) {
@@ -2281,6 +2502,23 @@ void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_q
get_vogel_disk(directional_penumbra_shadow_kernel, directional_penumbra_shadow_samples);
get_vogel_disk(directional_soft_shadow_kernel, directional_soft_shadow_samples);
}
+
+ _update_shader_quality_settings();
+}
+
+void RendererSceneRenderRD::decals_set_filter(RenderingServer::DecalFilter p_filter) {
+ if (decals_filter == p_filter) {
+ return;
+ }
+ decals_filter = p_filter;
+ _update_shader_quality_settings();
+}
+void RendererSceneRenderRD::light_projectors_set_filter(RenderingServer::LightProjectorFilter p_filter) {
+ if (light_projectors_filter == p_filter) {
+ return;
+ }
+ light_projectors_filter = p_filter;
+ _update_shader_quality_settings();
}
int RendererSceneRenderRD::get_roughness_layers() const {
@@ -2320,10 +2558,13 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
sort_array.sort(cluster.reflection_sort, cluster.reflection_count);
}
+ bool using_forward_ids = _uses_forward_ids();
for (uint32_t i = 0; i < cluster.reflection_count; i++) {
ReflectionProbeInstance *rpi = cluster.reflection_sort[i].instance;
- rpi->render_index = i;
+ if (using_forward_ids) {
+ _map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i);
+ }
RID base_probe = rpi->probe;
@@ -2373,7 +2614,7 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
}
}
-void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) {
+void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows) {
Transform3D inverse_transform = p_camera_transform.affine_inverse();
r_directional_light_count = 0;
@@ -2385,6 +2626,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
cluster.omni_light_count = 0;
cluster.spot_light_count = 0;
+ r_directional_light_soft_shadows = false;
+
for (int i = 0; i < (int)p_lights.size(); i++) {
LightInstance *li = light_instance_owner.getornull(p_lights[i]);
if (!li) {
@@ -2423,6 +2666,9 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
// technically this will keep expanding until reaching the sun, but all we care
// is expand until we reach the radius of the near plane (there can't be more occluders than that)
angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ if (storage->light_has_shadow(base)) {
+ r_directional_light_soft_shadows = true;
+ }
} else {
angular_diameter = 0.0;
}
@@ -2615,6 +2861,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
}
+ bool using_forward_ids = _uses_forward_ids();
+
for (uint32_t i = 0; i < (cluster.omni_light_count + cluster.spot_light_count); i++) {
uint32_t index = (i < cluster.omni_light_count) ? i : i - (cluster.omni_light_count);
Cluster::LightData &light_data = (i < cluster.omni_light_count) ? cluster.omni_lights[index] : cluster.spot_lights[index];
@@ -2622,6 +2870,10 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
LightInstance *li = (i < cluster.omni_light_count) ? cluster.omni_light_sort[index].instance : cluster.spot_light_sort[index].instance;
RID base = li->light;
+ if (using_forward_ids) {
+ _map_forward_id(type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, li->forward_id, index);
+ }
+
Transform3D light_transform = li->transform;
float sign = storage->light_is_negative(base) ? -1 : 1;
@@ -2754,7 +3006,6 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.shadow_enabled = false;
}
- li->light_index = index;
li->cull_mask = storage->light_get_cull_mask(base);
if (current_cluster_builder != nullptr) {
@@ -2823,11 +3074,15 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
sort_array.sort(cluster.decal_sort, cluster.decal_count);
}
+ bool using_forward_ids = _uses_forward_ids();
for (uint32_t i = 0; i < cluster.decal_count; i++) {
DecalInstance *di = cluster.decal_sort[i].instance;
RID decal = di->decal;
- di->render_index = i;
+ if (using_forward_ids) {
+ _map_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id, i);
+ }
+
di->cull_mask = storage->decal_get_cull_mask(decal);
Transform3D xform = di->transform;
@@ -2944,116 +3199,6 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
}
}
-void RendererSceneRenderRD::_fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words) {
- // first zero out our indices
- for (uint32_t i = 0; i < p_max_dst_words; i++) {
- p_omni_light_indices[i] = 0;
- p_spot_light_indices[i] = 0;
- p_reflection_probe_indices[i] = 0;
- p_decal_instance_indices[i] = 0;
- }
-
- {
- // process omni lights
- uint32_t dword = 0;
- uint32_t shift = 0;
-
- for (uint32_t i = 0; i < p_omni_light_instance_count && dword < p_max_dst_words; i++) {
- LightInstance *li = light_instance_owner.getornull(p_omni_light_instances[i]);
-
- if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) {
- p_omni_light_indices[dword] += li->light_index << shift;
- if (shift == 24) {
- dword++;
- shift = 0;
- } else {
- shift += 8;
- }
- }
- }
-
- if (dword < 2) {
- // put in ending mark
- p_omni_light_indices[dword] += 0xFF << shift;
- }
- }
-
- {
- // process spot lights
- uint32_t dword = 0;
- uint32_t shift = 0;
-
- for (uint32_t i = 0; i < p_spot_light_instance_count && dword < p_max_dst_words; i++) {
- LightInstance *li = light_instance_owner.getornull(p_spot_light_instances[i]);
-
- if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) {
- p_spot_light_indices[dword] += li->light_index << shift;
- if (shift == 24) {
- dword++;
- shift = 0;
- } else {
- shift += 8;
- }
- }
- }
-
- if (dword < 2) {
- // put in ending mark
- p_spot_light_indices[dword] += 0xFF << shift;
- }
- }
-
- {
- // process reflection probes
- uint32_t dword = 0;
- uint32_t shift = 0;
-
- for (uint32_t i = 0; i < p_reflection_probe_instance_count && dword < p_max_dst_words; i++) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_instances[i]);
-
- if ((rpi->cull_mask & p_layer_mask) && (rpi->render_index < 255)) {
- p_reflection_probe_indices[dword] += rpi->render_index << shift;
- if (shift == 24) {
- dword++;
- shift = 0;
- } else {
- shift += 8;
- }
- }
- }
-
- if (dword < 2) {
- // put in ending mark
- p_reflection_probe_indices[dword] += 0xFF << shift;
- }
- }
-
- {
- // process decals
- uint32_t dword = 0;
- uint32_t shift = 0;
-
- for (uint32_t i = 0; i < p_decal_instance_count && dword < p_max_dst_words; i++) {
- DecalInstance *decal = decal_instance_owner.getornull(p_decal_instances[i]);
-
- if ((decal->cull_mask & p_layer_mask) && (decal->render_index < 255)) {
- p_decal_instance_indices[dword] += decal->render_index << shift;
- if (shift == 24) {
- dword++;
- shift = 0;
- } else {
- shift += 8;
- }
- }
- }
-
- if (dword < 2) {
- // put in ending mark
- p_decal_instance_indices[dword] += 0xFF << shift;
- }
- }
-}
-
void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
ERR_FAIL_COND(!rb->volumetric_fog);
@@ -3617,7 +3762,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
uint32_t directional_light_count = 0;
uint32_t positional_light_count = 0;
- _setup_lights(*p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count);
+ _setup_lights(*p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
_setup_decals(*p_render_data->decals, p_render_data->cam_transform.affine_inverse());
p_render_data->directional_light_count = directional_light_count;
@@ -3773,9 +3918,28 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
_render_scene(&render_data, clear_color);
if (p_render_buffers.is_valid()) {
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
+ /*
+ _debug_draw_cluster(p_render_buffers);
+
+ RENDER_TIMESTAMP("Tonemap");
+
+ _render_buffers_post_process_and_tonemap(&render_data);
+ */
+
+ _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) {
+ rb->sdfgi->debug_draw(render_data.cam_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture);
+ }
+ }
+}
+
+void RendererSceneRenderRD::_debug_draw_cluster(RID p_render_buffers) {
+ if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) {
+ RS::ViewportDebugDraw dd = get_debug_draw_mode();
+
+ if (dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX;
- switch (debug_draw) {
+ switch (dd) {
case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS:
elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT;
break;
@@ -3791,17 +3955,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
default: {
}
}
- if (current_cluster_builder != nullptr) {
- current_cluster_builder->debug(elem_type);
- }
- }
-
- RENDER_TIMESTAMP("Tonemap");
-
- _render_buffers_post_process_and_tonemap(&render_data);
- _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) {
- rb->sdfgi->debug_draw(render_data.cam_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture);
+ current_cluster_builder->debug(elem_type);
}
}
}
@@ -4029,11 +4183,13 @@ bool RendererSceneRenderRD::free(RID p_rid) {
}
reflection_atlas_owner.free(p_rid);
} else if (reflection_probe_instance_owner.owns(p_rid)) {
- //not much to delete, just free it
- //ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid);
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid);
+ _free_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id);
reflection_probe_release_atlas_index(p_rid);
reflection_probe_instance_owner.free(p_rid);
} else if (decal_instance_owner.owns(p_rid)) {
+ DecalInstance *di = decal_instance_owner.getornull(p_rid);
+ _free_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id);
decal_instance_owner.free(p_rid);
} else if (lightmap_instance_owner.owns(p_rid)) {
lightmap_instance_owner.free(p_rid);
@@ -4068,6 +4224,9 @@ bool RendererSceneRenderRD::free(RID p_rid) {
shadow_atlas->shadow_owners.erase(p_rid);
}
+ if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) {
+ _free_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id);
+ }
light_instance_owner.free(p_rid);
} else if (shadow_atlas_owner.owns(p_rid)) {
@@ -4357,6 +4516,9 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth"));
environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter"));
+ decals_set_filter(RS::DecalFilter(int(GLOBAL_GET("rendering/textures/decals/filter"))));
+ light_projectors_set_filter(RS::LightProjectorFilter(int(GLOBAL_GET("rendering/textures/light_projectors/filter"))));
+
cull_argument.set_page_pool(&cull_argument_pool);
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index be3d3551c7..336dd6e1a7 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -80,6 +80,7 @@ struct RenderDataRD {
uint32_t cluster_max_elements = 0;
uint32_t directional_light_count = 0;
+ bool directional_light_soft_shadows = false;
RendererScene::RenderInfo *render_info = nullptr;
};
@@ -94,12 +95,12 @@ protected:
double time_step = 0;
struct RenderBufferData {
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) = 0;
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) = 0;
virtual ~RenderBufferData() {}
};
virtual RenderBufferData *_create_render_buffer_data() = 0;
- void _setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count);
+ void _setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows);
void _setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform);
void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
@@ -116,6 +117,7 @@ protected:
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0;
void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);
+ void _debug_draw_cluster(RID p_render_buffers);
RenderBufferData *render_buffers_get_data(RID p_render_buffers);
@@ -132,6 +134,10 @@ protected:
void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer);
+ void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
+ void _post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data);
+ void _disable_clear_request(const RenderDataRD *p_render_data);
+
// needed for a single argument calls (material and uv2)
PagedArrayPool<GeometryInstance *> cull_argument_pool;
PagedArray<GeometryInstance *> cull_argument; //need this to exist
@@ -145,7 +151,26 @@ protected:
} else {
return nullptr;
}
- }
+ };
+
+ //used for mobile renderer mostly
+
+ typedef int32_t ForwardID;
+
+ enum ForwardIDType {
+ FORWARD_ID_TYPE_OMNI_LIGHT,
+ FORWARD_ID_TYPE_SPOT_LIGHT,
+ FORWARD_ID_TYPE_REFLECTION_PROBE,
+ FORWARD_ID_TYPE_DECAL,
+ FORWARD_ID_MAX,
+ };
+
+ virtual ForwardID _allocate_forward_id(ForwardIDType p_type) { return -1; }
+ virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) {}
+ virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) {}
+ virtual bool _uses_forward_ids() const { return false; }
+
+ virtual void _update_shader_quality_settings() {}
private:
RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
@@ -188,9 +213,10 @@ private:
uint32_t render_step = 0;
uint64_t last_pass = 0;
- uint32_t render_index = 0;
uint32_t cull_mask = 0;
+ ForwardID forward_id = -1;
+
Transform3D transform;
};
@@ -201,8 +227,8 @@ private:
struct DecalInstance {
RID decal;
Transform3D transform;
- uint32_t render_index;
uint32_t cull_mask;
+ ForwardID forward_id = -1;
};
mutable RID_Owner<DecalInstance> decal_instance_owner;
@@ -286,6 +312,8 @@ private:
int directional_soft_shadow_samples = 0;
int penumbra_shadow_samples = 0;
int soft_shadow_samples = 0;
+ RS::DecalFilter decals_filter = RS::DECAL_FILTER_LINEAR_MIPMAPS;
+ RS::LightProjectorFilter light_projectors_filter = RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS;
/* DIRECTIONAL SHADOW */
@@ -346,7 +374,6 @@ private:
uint64_t last_scene_pass = 0;
uint64_t last_scene_shadow_pass = 0;
uint64_t last_pass = 0;
- uint32_t light_index = 0;
uint32_t cull_mask = 0;
uint32_t light_directional_index = 0;
@@ -358,6 +385,8 @@ private:
Set<RID> shadow_atlases; //shadow atlases where this light is registered
+ ForwardID forward_id = -1;
+
LightInstance() {}
};
@@ -426,6 +455,7 @@ private:
RID texture; //main texture for rendering to, must be filled after done rendering
RID depth_texture; //main depth texture
+ RID texture_fb; // framebuffer for the main texture, ONLY USED FOR MOBILE RENDERER POST EFFECTS, DO NOT USE FOR RENDERING 3D!!!
RendererSceneGIRD::SDFGI *sdfgi = nullptr;
VolumetricFog *volumetric_fog = nullptr;
@@ -441,6 +471,11 @@ private:
RID texture;
int width;
int height;
+
+ // only used on mobile renderer
+ RID fb;
+ RID half_texture;
+ RID half_fb;
};
Vector<Mipmap> mipmaps;
@@ -451,6 +486,10 @@ private:
struct Luminance {
Vector<RID> reduce;
RID current;
+
+ // used only on mobile renderer
+ Vector<RID> fb;
+ RID current_fb;
} luminance;
struct SSAO {
@@ -490,7 +529,6 @@ private:
void _allocate_luminance_textures(RenderBuffers *rb);
void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
- void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
/* Cluster */
@@ -889,6 +927,12 @@ public:
virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override;
virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override;
+ bool camera_effects_uses_dof(RID p_camera_effects) {
+ CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
+
+ return camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0;
+ }
+
virtual RID light_instance_create(RID p_light) override;
virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
@@ -1005,14 +1049,9 @@ public:
return li->last_pass;
}
- _FORCE_INLINE_ void light_instance_set_index(RID p_light_instance, uint32_t p_index) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- li->light_index = p_index;
- }
-
- _FORCE_INLINE_ uint32_t light_instance_get_index(RID p_light_instance) {
+ _FORCE_INLINE_ ForwardID light_instance_get_forward_id(RID p_light_instance) {
LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->light_index;
+ return li->forward_id;
}
_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
@@ -1036,6 +1075,7 @@ public:
virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
+ virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth);
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
uint32_t reflection_probe_instance_get_resolution(RID p_instance);
@@ -1049,17 +1089,11 @@ public:
return rpi->probe;
}
- _FORCE_INLINE_ void reflection_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!rpi);
- rpi->render_index = p_render_index;
- }
-
- _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_index(RID p_instance) {
+ _FORCE_INLINE_ ForwardID reflection_probe_instance_get_forward_id(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
ERR_FAIL_COND_V(!rpi, 0);
- return rpi->render_index;
+ return rpi->forward_id;
}
_FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
@@ -1097,6 +1131,11 @@ public:
return decal->decal;
}
+ _FORCE_INLINE_ ForwardID decal_instance_get_forward_id(RID p_decal) const {
+ DecalInstance *decal = decal_instance_owner.getornull(p_decal);
+ return decal->forward_id;
+ }
+
_FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal) const {
DecalInstance *decal = decal_instance_owner.getornull(p_decal);
return decal->transform;
@@ -1117,8 +1156,6 @@ public:
return li->transform;
}
- void _fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words = 2);
-
/* gi light probes */
virtual RID voxel_gi_instance_create(RID p_base) override;
@@ -1129,6 +1166,8 @@ public:
/* render buffers */
+ virtual RD::DataFormat _render_buffers_get_color_format();
+ virtual bool _render_buffers_can_be_storage();
virtual RID render_buffers_create() override;
virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override;
virtual void gi_set_use_half_resolution(bool p_enable) override;
@@ -1183,6 +1222,10 @@ public:
virtual void shadows_quality_set(RS::ShadowQuality p_quality) override;
virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) override;
+
+ virtual void decals_set_filter(RS::DecalFilter p_filter) override;
+ virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override;
+
_FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const { return shadows_quality; }
_FORCE_INLINE_ RS::ShadowQuality directional_shadow_quality_get() const { return directional_shadow_quality; }
_FORCE_INLINE_ float shadows_quality_radius_get() const { return shadows_quality_radius; }
@@ -1198,6 +1241,9 @@ public:
_FORCE_INLINE_ int penumbra_shadow_samples_get() const { return penumbra_shadow_samples; }
_FORCE_INLINE_ int soft_shadow_samples_get() const { return soft_shadow_samples; }
+ _FORCE_INLINE_ RS::LightProjectorFilter light_projectors_get_filter() const { return light_projectors_filter; }
+ _FORCE_INLINE_ RS::DecalFilter decals_get_filter() const { return decals_filter; }
+
int get_roughness_layers() const;
bool is_using_radiance_cubemap_array() const;
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
index e701219617..9331cab090 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -283,14 +283,17 @@ void RendererSceneSkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_
RD::DrawListID draw_list = p_list;
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format));
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format, false, RD::get_singleton()->draw_list_get_current_pass()));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0);
- if (p_uniform_set.is_valid()) { //material may not have uniform set
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
+ // Update uniform sets.
+ {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0);
+ if (RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) { // Material may not have a uniform set.
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
+ }
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3);
}
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3);
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@@ -313,12 +316,16 @@ void RendererSceneSkyRD::ReflectionData::clear_reflection_data() {
coefficient_buffer = RID();
}
-void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers) {
+void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageRD *p_storage, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format) {
//recreate radiance and all data
int mipmaps = p_mipmaps;
uint32_t w = p_size, h = p_size;
+ EffectsRD *effects = p_storage->get_effects();
+ ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
if (p_use_array) {
int num_layers = p_low_quality ? 8 : p_roughness_layers;
@@ -377,9 +384,9 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
}
radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP);
-
+ RD::get_singleton()->set_resource_name(radiance_base_cubemap, "radiance base cubemap");
RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = p_texture_format;
tf.width = 64; // Always 64x64
tf.height = 64;
tf.texture_type = RD::TEXTURE_TYPE_CUBE;
@@ -388,6 +395,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(downsampled_radiance_cubemap, "downsampled radiance cubemap");
{
uint32_t mmw = 64;
uint32_t mmh = 64;
@@ -397,6 +405,18 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
mm.size.width = mmw;
mm.size.height = mmh;
mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP);
+ RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip " + itos(j) + " ");
+ if (prefer_raster_effects) {
+ // we need a framebuffer for each side of our cubemap
+
+ for (int k = 0; k < 6; k++) {
+ mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, k, j);
+ RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip: " + itos(j) + " Face: " + itos(k) + " ");
+ Vector<RID> fbtex;
+ fbtex.push_back(mm.views[k]);
+ mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
+ }
+ }
mmw = MAX(1, mmw >> 1);
mmh = MAX(1, mmh >> 1);
@@ -405,50 +425,128 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
}
void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) {
- p_storage->get_effects()->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+ EffectsRD *effects = p_storage->get_effects();
+ ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
+ if (prefer_raster_effects) {
+ RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size);
+ }
- for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
- p_storage->get_effects()->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
- }
+ for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size);
+ }
+ }
+ RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
- Vector<RID> views;
- if (p_use_arrays) {
- for (int i = 1; i < layers.size(); i++) {
- views.push_back(layers[i].views[0]);
+ if (p_use_arrays) {
+ RD::get_singleton()->draw_command_begin_label("filter radiance map into array heads");
+ for (int i = 0; i < layers.size(); i++) {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i);
+ }
+ }
+ } else {
+ RD::get_singleton()->draw_command_begin_label("filter radiance map into mipmaps directly");
+ for (int j = 0; j < layers[0].mipmaps.size(); j++) {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j);
+ }
+ }
}
+ RD::get_singleton()->draw_command_end_label(); // Filter radiance
} else {
- for (int i = 1; i < layers[0].views.size(); i++) {
- views.push_back(layers[0].views[i]);
+ effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+
+ for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
+ effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
+ }
+
+ Vector<RID> views;
+ if (p_use_arrays) {
+ for (int i = 1; i < layers.size(); i++) {
+ views.push_back(layers[i].views[0]);
+ }
+ } else {
+ for (int i = 1; i < layers[0].views.size(); i++) {
+ views.push_back(layers[0].views[i]);
+ }
}
- }
- p_storage->get_effects()->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
+ effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
+ }
}
void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) {
- if (p_use_arrays) {
- //render directly to the layers
- p_storage->get_effects()->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
+ EffectsRD *effects = p_storage->get_effects();
+ ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
+ if (prefer_raster_effects) {
+ // Need to ask clayjohn but p_cube_side is set to 10, looks like in the compute shader we're doing all 6 sides in one call
+ // here we need to do them one by one so ignoring p_cube_side
+ if (p_use_arrays) {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_roughness_raster(
+ radiance_base_cubemap,
+ layers[p_base_layer].mipmaps[0].framebuffers[k],
+ k,
+ p_sky_ggx_samples_quality,
+ float(p_base_layer) / (layers.size() - 1.0),
+ layers[p_base_layer].mipmaps[0].size.x);
+ }
+ } else {
+ for (int k = 0; k < 6; k++) {
+ effects->cubemap_roughness_raster(
+ layers[0].views[p_base_layer - 1],
+ layers[0].mipmaps[p_base_layer].framebuffers[k],
+ k,
+ p_sky_ggx_samples_quality,
+ float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
+ layers[0].mipmaps[p_base_layer].size.x);
+ }
+ }
} else {
- p_storage->get_effects()->cubemap_roughness(
- layers[0].views[p_base_layer - 1],
- layers[0].views[p_base_layer],
- p_cube_side,
- p_sky_ggx_samples_quality,
- float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
- layers[0].mipmaps[p_base_layer].size.x);
+ if (p_use_arrays) {
+ //render directly to the layers
+ effects->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
+ } else {
+ effects->cubemap_roughness(
+ layers[0].views[p_base_layer - 1],
+ layers[0].views[p_base_layer],
+ p_cube_side,
+ p_sky_ggx_samples_quality,
+ float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
+ layers[0].mipmaps[p_base_layer].size.x);
+ }
}
}
void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) {
+ EffectsRD *effects = p_storage->get_effects();
+ ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
+ RD::get_singleton()->draw_command_begin_label("Update Radiance Cubemap Array Mipmaps");
for (int i = p_start; i < p_end; i++) {
for (int j = 0; j < layers[i].views.size() - 1; j++) {
RID view = layers[i].views[j];
- RID texture = layers[i].views[j + 1];
Size2i size = layers[i].mipmaps[j + 1].size;
- p_storage->get_effects()->cubemap_downsample(view, texture, size);
+ if (prefer_raster_effects) {
+ for (int k = 0; k < 6; k++) {
+ RID framebuffer = layers[i].mipmaps[j + 1].framebuffers[k];
+ effects->cubemap_downsample_raster(view, framebuffer, k, size);
+ }
+ } else {
+ RID texture = layers[i].views[j + 1];
+ effects->cubemap_downsample(view, texture, size);
+ }
}
}
+ RD::get_singleton()->draw_command_end_label();
}
////////////////////////////////////////////////////////////////////////////////
@@ -757,7 +855,13 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
sky_shader.default_shader = storage->shader_allocate();
storage->shader_initialize(sky_shader.default_shader);
- storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void sky() { COLOR = vec3(0.0); } \n");
+ storage->shader_set_code(sky_shader.default_shader, R"(
+shader_type sky;
+
+void sky() {
+ COLOR = vec3(0.0);
+}
+)");
sky_shader.default_material = storage->material_allocate();
storage->material_initialize(sky_shader.default_material);
@@ -838,7 +942,15 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
sky_scene_state.fog_shader = storage->shader_allocate();
storage->shader_initialize(sky_scene_state.fog_shader);
- storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void sky() { COLOR = clear_color.rgb; } \n");
+ storage->shader_set_code(sky_scene_state.fog_shader, R"(
+shader_type sky;
+
+uniform vec4 clear_color;
+
+void sky() {
+ COLOR = clear_color.rgb;
+}
+)");
sky_scene_state.fog_material = storage->material_allocate();
storage->material_initialize(sky_scene_state.fog_material);
@@ -888,6 +1000,10 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
}
}
+void RendererSceneSkyRD::set_texture_format(RD::DataFormat p_texture_format) {
+ texture_format = p_texture_format;
+}
+
RendererSceneSkyRD::~RendererSceneSkyRD() {
// TODO cleanup anything created in init...
@@ -1156,6 +1272,7 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
cm = correction * cm;
if (shader_data->uses_quarter_res) {
+ RD::get_singleton()->draw_command_begin_label("Render Sky to Quarter Res Cubemap");
PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES];
Vector<Color> clear_colors;
@@ -1163,17 +1280,18 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
RD::DrawListID cubemap_draw_list;
for (int i = 0; i < 6; i++) {
- Transform3D local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin);
+ _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
+ RD::get_singleton()->draw_command_end_label();
}
if (shader_data->uses_half_res) {
+ RD::get_singleton()->draw_command_begin_label("Render Sky to Half Res Cubemap");
PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES];
Vector<Color> clear_colors;
@@ -1181,28 +1299,29 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
RD::DrawListID cubemap_draw_list;
for (int i = 0; i < 6; i++) {
- Transform3D local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin);
+ _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
+ RD::get_singleton()->draw_command_end_label();
}
RD::DrawListID cubemap_draw_list;
PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP];
+ RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap");
for (int i = 0; i < 6; i++) {
- Transform3D local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin);
+ _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
+ RD::get_singleton()->draw_command_end_label();
if (sky_mode == RS::SKY_MODE_REALTIME) {
sky->reflection.create_reflection_fast_filter(storage, sky_use_cubemap_array);
@@ -1348,6 +1467,179 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
RD::get_singleton()->draw_list_end();
}
+void RendererSceneSkyRD::update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time) {
+ ERR_FAIL_COND(!p_env);
+
+ ERR_FAIL_COND(p_view_count == 0);
+ ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
+
+ Sky *sky = get_sky(p_env->sky);
+ ERR_FAIL_COND(!sky);
+
+ SkyMaterialData *material = nullptr;
+ RID sky_material;
+
+ RS::EnvironmentBG background = p_env->background;
+
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(p_env->sky);
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+ }
+
+ if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_scene_state.fog_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ SkyShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ Basis sky_transform = p_env->sky_orientation;
+ sky_transform.invert();
+
+ float multiplier = p_env->bg_energy;
+ float custom_fov = p_env->sky_custom_fov;
+
+ // Camera
+ CameraMatrix camera;
+ uint32_t view_count = p_view_count;
+ const CameraMatrix *projections = p_projections;
+
+ if (custom_fov) {
+ // With custom fov we don't support stereo...
+ float near_plane = p_projections[0].get_z_near();
+ float far_plane = p_projections[0].get_z_far();
+ float aspect = p_projections[0].get_aspect();
+
+ camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
+
+ view_count = 1;
+ projections = &camera;
+ }
+
+ sky_transform = p_transform.basis * sky_transform;
+
+ if (shader_data->uses_quarter_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
+
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ if (shader_data->uses_half_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
+
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+}
+
+void RendererSceneSkyRD::draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time) {
+ ERR_FAIL_COND(!p_env);
+
+ ERR_FAIL_COND(p_view_count == 0);
+ ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
+
+ Sky *sky = get_sky(p_env->sky);
+ ERR_FAIL_COND(!sky);
+
+ SkyMaterialData *material = nullptr;
+ RID sky_material;
+
+ RS::EnvironmentBG background = p_env->background;
+
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(p_env->sky);
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+ }
+
+ if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_scene_state.fog_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ SkyShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ Basis sky_transform = p_env->sky_orientation;
+ sky_transform.invert();
+
+ float multiplier = p_env->bg_energy;
+ float custom_fov = p_env->sky_custom_fov;
+
+ // Camera
+ CameraMatrix camera;
+ uint32_t view_count = p_view_count;
+ const CameraMatrix *projections = p_projections;
+
+ if (custom_fov) {
+ // With custom fov we don't support stereo...
+ float near_plane = p_projections[0].get_z_near();
+ float far_plane = p_projections[0].get_z_far();
+ float aspect = p_projections[0].get_aspect();
+
+ camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
+
+ view_count = 1;
+ projections = &camera;
+ }
+
+ sky_transform = p_transform.basis * sky_transform;
+
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
+
+ RID texture_uniform_set;
+ if (sky) {
+ texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd);
+ } else {
+ texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
+ }
+
+ _render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin);
+}
+
void RendererSceneSkyRD::invalidate_sky(Sky *p_sky) {
if (!p_sky->dirty) {
p_sky->dirty = true;
@@ -1379,7 +1671,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
//array (higher quality, 6 times more memory)
RD::TextureFormat tf;
tf.array_layers = layers * 6;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = texture_format;
tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
tf.mipmaps = mipmaps;
tf.width = w;
@@ -1388,13 +1680,13 @@ void RendererSceneSkyRD::update_dirty_skys() {
sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
- sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+ sky->reflection.update_reflection_data(storage, sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format);
} else {
//regular cubemap, lower quality (aliasing, less memory)
RD::TextureFormat tf;
tf.array_layers = 6;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.format = texture_format;
tf.texture_type = RD::TEXTURE_TYPE_CUBE;
tf.mipmaps = MIN(mipmaps, layers);
tf.width = w;
@@ -1403,7 +1695,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
- sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+ sky->reflection.update_reflection_data(storage, sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format);
}
texture_set_dirty = true;
}
@@ -1411,7 +1703,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
// Create subpass buffers if they haven't been created already
if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tformat.format = texture_format;
tformat.width = sky->screen_size.x / 2;
tformat.height = sky->screen_size.y / 2;
tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
@@ -1426,7 +1718,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tformat.format = texture_format;
tformat.width = sky->screen_size.x / 4;
tformat.height = sky->screen_size.y / 4;
tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
index 4f852e55a7..7b670bddd5 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
@@ -64,6 +64,7 @@ public:
private:
RendererStorageRD *storage;
+ RD::DataFormat texture_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
RID index_buffer;
RID index_array;
@@ -190,6 +191,10 @@ public:
struct Mipmap {
RID view;
Size2i size;
+
+ // for mobile only
+ RID views[6];
+ RID framebuffers[6];
};
Vector<Mipmap> mipmaps;
};
@@ -204,7 +209,7 @@ public:
Vector<Layer> layers;
void clear_reflection_data();
- void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers);
+ void update_reflection_data(RendererStorageRD *p_storage, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format);
void create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays);
void create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality);
void update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end);
@@ -284,11 +289,14 @@ public:
RendererSceneSkyRD();
void init(RendererStorageRD *p_storage);
+ void set_texture_format(RD::DataFormat p_texture_format);
~RendererSceneSkyRD();
void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time);
void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time);
+ void update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time);
+ void draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time);
void invalidate_sky(Sky *p_sky);
void update_dirty_skys();
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 6738f499bd..4feaf08808 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -2531,6 +2531,8 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
Mesh *mesh = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND(!mesh);
+ ERR_FAIL_COND(mesh->surface_count == RS::MAX_MESH_SURFACES);
+
#ifdef DEBUG_ENABLED
//do a validation, to catch errors first
{
@@ -2714,9 +2716,7 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su
mesh->surfaces[mesh->surface_count] = s;
mesh->surface_count++;
- for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) {
- //update instances
- MeshInstance *mi = E->get();
+ for (MeshInstance *mi : mesh->instances) {
_mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1);
}
@@ -3027,8 +3027,7 @@ void RendererStorageRD::mesh_clear(RID p_mesh) {
mesh->surface_count = 0;
mesh->material_cache.clear();
//clear instance data
- for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) {
- MeshInstance *mi = E->get();
+ for (MeshInstance *mi : mesh->instances) {
_mesh_instance_clear(mi);
}
mesh->has_bone_weights = false;
@@ -3454,6 +3453,7 @@ void RendererStorageRD::multimesh_allocate_data(RID p_multimesh, int p_instances
if (multimesh->buffer.is_valid()) {
RD::get_singleton()->free(multimesh->buffer);
multimesh->buffer = RID();
+ multimesh->uniform_set_2d = RID(); //cleared by dependency
multimesh->uniform_set_3d = RID(); //cleared by dependency
}
@@ -4092,7 +4092,7 @@ void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) {
particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
}
-void RendererStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) {
+void RendererStorageRD::particles_set_lifetime(RID p_particles, double p_lifetime) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
particles->lifetime = p_lifetime;
@@ -4104,7 +4104,7 @@ void RendererStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot)
particles->one_shot = p_one_shot;
}
-void RendererStorageRD::particles_set_pre_process_time(RID p_particles, float p_time) {
+void RendererStorageRD::particles_set_pre_process_time(RID p_particles, double p_time) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
particles->pre_process_time = p_time;
@@ -4127,7 +4127,7 @@ void RendererStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p
particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
-void RendererStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) {
+void RendererStorageRD::particles_set_speed_scale(RID p_particles, double p_scale) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
@@ -4443,7 +4443,7 @@ void RendererStorageRD::particles_set_canvas_sdf_collision(RID p_particles, bool
particles->sdf_collision_texture = p_texture;
}
-void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta) {
+void RendererStorageRD::_particles_process(Particles *p_particles, double p_delta) {
if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) {
Vector<RD::Uniform> uniforms;
@@ -4492,7 +4492,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
p_particles->particles_material_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 1);
}
- float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0);
+ double new_phase = Math::fmod((double)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, 1.0);
//move back history (if there is any)
for (uint32_t i = p_particles->frame_history.size() - 1; i > 0; i--) {
@@ -4960,7 +4960,7 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &
RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
RD::get_singleton()->compute_list_end();
- effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount);
+ effects->sort_buffer(particles->particles_sort_uniform_set, particles->amount);
}
copy_push_constant.total_particles *= copy_push_constant.total_particles;
@@ -5132,14 +5132,14 @@ void RendererStorageRD::update_particles() {
bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
if (particles->clear && particles->pre_process_time > 0.0) {
- float frame_time;
+ double frame_time;
if (fixed_fps > 0) {
frame_time = 1.0 / fixed_fps;
} else {
frame_time = 1.0 / 30.0;
}
- float todo = particles->pre_process_time;
+ double todo = particles->pre_process_time;
while (todo >= 0) {
_particles_process(particles, frame_time);
@@ -5148,8 +5148,8 @@ void RendererStorageRD::update_particles() {
}
if (fixed_fps > 0) {
- float frame_time;
- float decr;
+ double frame_time;
+ double decr;
if (zero_time_scale) {
frame_time = 0.0;
decr = 1.0 / fixed_fps;
@@ -5157,13 +5157,13 @@ void RendererStorageRD::update_particles() {
frame_time = 1.0 / fixed_fps;
decr = frame_time;
}
- float delta = RendererCompositorRD::singleton->get_frame_delta_time();
+ double delta = RendererCompositorRD::singleton->get_frame_delta_time();
if (delta > 0.1) { //avoid recursive stalls if fps goes below 10
delta = 0.1;
} else if (delta <= 0.0) { //unlikely but..
delta = 0.001;
}
- float todo = particles->frame_remainder + delta;
+ double todo = particles->frame_remainder + delta;
while (todo >= frame_time) {
_particles_process(particles, frame_time);
@@ -5886,6 +5886,10 @@ void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, flo
ERR_FAIL_COND(!light);
ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX);
+ if (light->param[p_param] == p_value) {
+ return;
+ }
+
switch (p_param) {
case RS::LIGHT_PARAM_RANGE:
case RS::LIGHT_PARAM_SPOT_ANGLE:
@@ -5899,6 +5903,12 @@ void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, flo
light->version++;
light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT);
} break;
+ case RS::LIGHT_PARAM_SIZE: {
+ if ((light->param[p_param] > CMP_EPSILON) != (p_value > CMP_EPSILON)) {
+ //changing from no size to size and the opposite
+ light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR);
+ }
+ } break;
default: {
}
}
@@ -5935,8 +5945,11 @@ void RendererStorageRD::light_set_projector(RID p_light, RID p_texture) {
light->projector = p_texture;
- if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) {
- texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ if (light->type != RS::LIGHT_DIRECTIONAL) {
+ if (light->projector.is_valid()) {
+ texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ }
+ light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR);
}
}
@@ -7523,7 +7536,7 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c
//single texture copy for backbuffer
//RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true);
- effects.copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true);
+ effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, true, true);
if (!p_gen_mipmaps) {
return;
@@ -7539,7 +7552,7 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c
region.size.y = MAX(1, region.size.y >> 1);
const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i];
- effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true);
+ effects->gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true);
prev_texture = mm.mipmap;
}
}
@@ -7562,7 +7575,7 @@ void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, con
}
//single texture copy for backbuffer
- effects.set_color(rt->backbuffer_mipmap0, p_color, region, true);
+ effects->set_color(rt->backbuffer_mipmap0, p_color, region, true);
}
void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) {
@@ -7592,7 +7605,7 @@ void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_targe
region.size.y = MAX(1, region.size.y >> 1);
const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i];
- effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true);
+ effects->gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true);
prev_texture = mm.mipmap;
}
}
@@ -7913,14 +7926,14 @@ void RendererStorageRD::_update_decal_atlas() {
while ((K = decal_atlas.textures.next(K))) {
DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K);
Texture *src_tex = texture_owner.getornull(*K);
- effects.copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0);
+ effects->copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0);
}
RD::get_singleton()->draw_list_end();
prev_texture = mm.texture;
} else {
- effects.copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size));
+ effects->copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size));
prev_texture = mm.texture;
}
} else {
@@ -8398,10 +8411,10 @@ void RendererStorageRD::global_variables_load_settings(bool p_load_textures) {
List<PropertyInfo> settings;
ProjectSettings::get_singleton()->get_property_list(&settings);
- for (List<PropertyInfo>::Element *E = settings.front(); E; E = E->next()) {
- if (E->get().name.begins_with("shader_globals/")) {
- StringName name = E->get().name.get_slice("/", 1);
- Dictionary d = ProjectSettings::get_singleton()->get(E->get().name);
+ for (const PropertyInfo &E : settings) {
+ if (E.name.begins_with("shader_globals/")) {
+ StringName name = E.name.get_slice("/", 1);
+ Dictionary d = ProjectSettings::get_singleton()->get(E.name);
ERR_CONTINUE(!d.has("type"));
ERR_CONTINUE(!d.has("value"));
@@ -8569,8 +8582,8 @@ void RendererStorageRD::_update_global_variables() {
if (global_variables.must_update_buffer_materials) {
// only happens in the case of a buffer variable added or removed,
// so not often.
- for (List<RID>::Element *E = global_variables.materials_using_buffer.front(); E; E = E->next()) {
- Material *material = material_owner.getornull(E->get());
+ for (const RID &E : global_variables.materials_using_buffer) {
+ Material *material = material_owner.getornull(E);
ERR_CONTINUE(!material); //wtf
_material_queue_update(material, true, false);
@@ -8582,8 +8595,8 @@ void RendererStorageRD::_update_global_variables() {
if (global_variables.must_update_texture_materials) {
// only happens in the case of a buffer variable added or removed,
// so not often.
- for (List<RID>::Element *E = global_variables.materials_using_texture.front(); E; E = E->next()) {
- Material *material = material_owner.getornull(E->get());
+ for (const RID &E : global_variables.materials_using_texture) {
+ Material *material = material_owner.getornull(E);
ERR_CONTINUE(!material); //wtf
_material_queue_update(material, false, true);
@@ -8792,8 +8805,13 @@ bool RendererStorageRD::free(RID p_rid) {
return true;
}
+void RendererStorageRD::init_effects(bool p_prefer_raster_effects) {
+ effects = memnew(EffectsRD(p_prefer_raster_effects));
+}
+
EffectsRD *RendererStorageRD::get_effects() {
- return &effects;
+ ERR_FAIL_NULL_V_MSG(effects, nullptr, "Effects haven't been initialised yet.");
+ return effects;
}
void RendererStorageRD::capture_timestamps_begin() {
@@ -9112,25 +9130,41 @@ RendererStorageRD::RendererStorageRD() {
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
sampler_state.use_anisotropy = true;
sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
sampler_state.use_anisotropy = true;
sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
@@ -9373,7 +9407,13 @@ RendererStorageRD::RendererStorageRD() {
// default material and shader for particles shader
particles_shader.default_shader = shader_allocate();
shader_initialize(particles_shader.default_shader);
- shader_set_code(particles_shader.default_shader, "shader_type particles; void process() { COLOR = vec4(1.0); } \n");
+ shader_set_code(particles_shader.default_shader, R"(
+shader_type particles;
+
+void process() {
+ COLOR = vec4(1.0);
+}
+)");
particles_shader.default_material = material_allocate();
material_initialize(particles_shader.default_material);
material_set_shader(particles_shader.default_material, particles_shader.default_shader);
@@ -9517,4 +9557,9 @@ RendererStorageRD::~RendererStorageRD() {
if (decal_atlas.texture.is_valid()) {
RD::get_singleton()->free(decal_atlas.texture);
}
+
+ if (effects) {
+ memdelete(effects);
+ effects = NULL;
+ }
}
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 1a33569c33..71c3d8b09a 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -715,12 +715,12 @@ private:
struct Particles {
RS::ParticlesMode mode = RS::PARTICLES_MODE_3D;
bool inactive = true;
- float inactive_time = 0.0;
+ double inactive_time = 0.0;
bool emitting = false;
bool one_shot = false;
int amount = 0;
- float lifetime = 1.0;
- float pre_process_time = 0.0;
+ double lifetime = 1.0;
+ double pre_process_time = 0.0;
float explosiveness = 0.0;
float randomness = 0.0;
bool restart_request = false;
@@ -773,12 +773,12 @@ private:
uint32_t cycle_number = 0;
- float speed_scale = 1.0;
+ double speed_scale = 1.0;
int fixed_fps = 30;
bool interpolate = true;
bool fractional_delta = false;
- float frame_remainder = 0;
+ double frame_remainder = 0;
float collision_base_size = 0.01;
bool clear = true;
@@ -805,14 +805,14 @@ private:
}
};
- void _particles_process(Particles *p_particles, float p_delta);
+ void _particles_process(Particles *p_particles, double p_delta);
void _particles_allocate_emission_buffer(Particles *particles);
void _particles_free_data(Particles *particles);
void _particles_update_buffers(Particles *particles);
struct ParticlesShader {
struct PushConstant {
- float lifetime;
+ double lifetime;
uint32_t clear;
uint32_t total_particles;
uint32_t trail_size;
@@ -1290,7 +1290,7 @@ private:
void _update_global_variables();
/* EFFECTS */
- EffectsRD effects;
+ EffectsRD *effects = NULL;
public:
virtual bool can_create_resources_async() const;
@@ -1888,6 +1888,13 @@ public:
return light->shadow;
}
+ _FORCE_INLINE_ bool light_has_projector(RID p_light) const {
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+
+ return texture_owner.owns(light->projector);
+ }
+
_FORCE_INLINE_ bool light_is_negative(RID p_light) const {
const Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
@@ -2137,13 +2144,13 @@ public:
void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode);
void particles_set_emitting(RID p_particles, bool p_emitting);
void particles_set_amount(RID p_particles, int p_amount);
- void particles_set_lifetime(RID p_particles, float p_lifetime);
+ void particles_set_lifetime(RID p_particles, double p_lifetime);
void particles_set_one_shot(RID p_particles, bool p_one_shot);
- void particles_set_pre_process_time(RID p_particles, float p_time);
+ void particles_set_pre_process_time(RID p_particles, double p_time);
void particles_set_explosiveness_ratio(RID p_particles, float p_ratio);
void particles_set_randomness_ratio(RID p_particles, float p_ratio);
void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb);
- void particles_set_speed_scale(RID p_particles, float p_scale);
+ void particles_set_speed_scale(RID p_particles, double p_scale);
void particles_set_use_local_coordinates(RID p_particles, bool p_enable);
void particles_set_process_material(RID p_particles, RID p_material);
void particles_set_fixed_fps(RID p_particles, int p_fps);
@@ -2367,6 +2374,7 @@ public:
static RendererStorageRD *base_singleton;
+ void init_effects(bool p_prefer_raster_effects);
EffectsRD *get_effects();
RendererStorageRD();
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
index b347197289..9c1068ea2e 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
@@ -571,7 +571,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
max_texture_uniforms++;
} else {
if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue; //instances are indexed directly, dont need index uniforms
+ continue; // Instances are indexed directly, don't need index uniforms.
}
max_uniforms++;
@@ -605,7 +605,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
if (uniform.scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
//insert, but don't generate any code.
p_actions.uniforms->insert(uniform_name, uniform);
- continue; //instances are indexed directly, dont need index uniforms
+ continue; // Instances are indexed directly, don't need index uniforms.
}
if (SL::is_sampler_type(uniform.type)) {
ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_order) + ") uniform ";
@@ -760,11 +760,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
if (var_frag_to_light.size() > 0) {
String gcode = "\n\nstruct {\n";
- for (List<Pair<StringName, SL::ShaderNode::Varying>>::Element *E = var_frag_to_light.front(); E; E = E->next()) {
- gcode += "\t" + _prestr(E->get().second.precision) + _typestr(E->get().second.type) + " " + _mkid(E->get().first);
- if (E->get().second.array_size > 0) {
+ for (const Pair<StringName, SL::ShaderNode::Varying> &E : var_frag_to_light) {
+ gcode += "\t" + _prestr(E.second.precision) + _typestr(E.second.type) + " " + _mkid(E.first);
+ if (E.second.array_size > 0) {
gcode += "[";
- gcode += itos(E->get().second.array_size);
+ gcode += itos(E.second.array_size);
gcode += "]";
}
gcode += ";\n";
@@ -1351,7 +1351,13 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
if (err != OK) {
Vector<String> shader = p_code.split("\n");
for (int i = 0; i < shader.size(); i++) {
- print_line(itos(i + 1) + " " + shader[i]);
+ if (i + 1 == parser.get_error_line()) {
+ // Mark the error line to be visible without having to look at
+ // the trace at the end.
+ print_line(vformat("E%4d-> %s", i + 1, shader[i]));
+ } else {
+ print_line(vformat("%5d | %s", i + 1, shader[i]));
+ }
}
_err_print_error(nullptr, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER);
@@ -1388,8 +1394,8 @@ void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
ShaderLanguage::get_builtin_funcs(&func_list);
- for (List<String>::Element *E = func_list.front(); E; E = E->next()) {
- internal_functions.insert(E->get());
+ for (const String &E : func_list) {
+ internal_functions.insert(E);
}
texture_functions.insert("texture");
texture_functions.insert("textureProj");
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index 27305cc938..5bb12fc168 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -116,8 +116,10 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con
}
StringBuilder tohash;
- tohash.append("[VersionKey]");
- tohash.append(RenderingDevice::get_singleton()->shader_get_cache_key());
+ tohash.append("[SpirvCacheKey]");
+ tohash.append(RenderingDevice::get_singleton()->shader_get_spirv_cache_key());
+ tohash.append("[BinaryCacheKey]");
+ tohash.append(RenderingDevice::get_singleton()->shader_get_binary_cache_key());
tohash.append("[Vertex]");
tohash.append(p_vertex_code ? p_vertex_code : "");
tohash.append("[Fragment]");
@@ -144,12 +146,14 @@ void ShaderRD::_clear_version(Version *p_version) {
//clear versions if they exist
if (p_version->variants) {
for (int i = 0; i < variant_defines.size(); i++) {
- RD::get_singleton()->free(p_version->variants[i]);
+ if (variants_enabled[i]) {
+ RD::get_singleton()->free(p_version->variants[i]);
+ }
}
memdelete_arr(p_version->variants);
- if (p_version->variant_stages) {
- memdelete_arr(p_version->variant_stages);
+ if (p_version->variant_data) {
+ memdelete_arr(p_version->variant_data);
}
p_version->variants = nullptr;
}
@@ -203,7 +207,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
return; //variant is disabled, return
}
- Vector<RD::ShaderStageData> &stages = p_version->variant_stages[p_variant];
+ Vector<RD::ShaderStageSPIRVData> stages;
String error;
String current_source;
@@ -217,8 +221,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
_build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX]);
current_source = builder.as_string();
- RD::ShaderStageData stage;
- stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+ RD::ShaderStageSPIRVData stage;
+ stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spir_v.size() == 0) {
build_ok = false;
} else {
@@ -235,8 +239,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
_build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT]);
current_source = builder.as_string();
- RD::ShaderStageData stage;
- stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+ RD::ShaderStageSPIRVData stage;
+ stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spir_v.size() == 0) {
build_ok = false;
} else {
@@ -254,8 +258,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
current_source = builder.as_string();
- RD::ShaderStageData stage;
- stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+ RD::ShaderStageSPIRVData stage;
+ stage.spir_v = RD::get_singleton()->shader_compile_spirv_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spir_v.size() == 0) {
build_ok = false;
} else {
@@ -275,10 +279,15 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
return;
}
- RID shader = RD::get_singleton()->shader_create(stages);
+ Vector<uint8_t> shader_data = RD::get_singleton()->shader_compile_binary_from_spirv(stages);
+
+ ERR_FAIL_COND(shader_data.size() == 0);
+
+ RID shader = RD::get_singleton()->shader_create_from_bytecode(shader_data);
{
MutexLock lock(variant_set_mutex);
p_version->variants[p_variant] = shader;
+ p_version->variant_data[p_variant] = shader_data;
}
}
@@ -364,14 +373,12 @@ String ShaderRD::_version_get_sha1(Version *p_version) const {
}
static const char *shader_file_header = "GDSC";
-static const uint32_t cache_file_version = 1;
+static const uint32_t cache_file_version = 2;
bool ShaderRD::_load_from_cache(Version *p_version) {
String sha1 = _version_get_sha1(p_version);
String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
- uint64_t time_from = OS::get_singleton()->get_ticks_usec();
-
FileAccessRef f = FileAccess::open(path, FileAccess::READ);
if (!f) {
return false;
@@ -390,76 +397,43 @@ bool ShaderRD::_load_from_cache(Version *p_version) {
ERR_FAIL_COND_V(variant_count != (uint32_t)variant_defines.size(), false); //should not happen but check
- bool success = true;
for (uint32_t i = 0; i < variant_count; i++) {
- uint32_t stage_count = f->get_32();
- p_version->variant_stages[i].resize(stage_count);
- for (uint32_t j = 0; j < stage_count; j++) {
- p_version->variant_stages[i].write[j].shader_stage = RD::ShaderStage(f->get_32());
-
- int compression = f->get_32();
- uint32_t length = f->get_32();
-
- if (compression == 0) {
- Vector<uint8_t> data;
- data.resize(length);
-
- f->get_buffer(data.ptrw(), length);
-
- p_version->variant_stages[i].write[j].spir_v = data;
- } else {
- Vector<uint8_t> data;
-
- if (compression == 2) {
- //zstd
- int smol_length = f->get_32();
- Vector<uint8_t> zstd_data;
-
- zstd_data.resize(smol_length);
- f->get_buffer(zstd_data.ptrw(), smol_length);
-
- data.resize(length);
- Compression::decompress(data.ptrw(), data.size(), zstd_data.ptr(), zstd_data.size(), Compression::MODE_ZSTD);
-
- } else {
- data.resize(length);
- f->get_buffer(data.ptrw(), length);
- }
-
- Vector<uint8_t> spirv;
- uint32_t spirv_size = smolv::GetDecodedBufferSize(data.ptr(), data.size());
- spirv.resize(spirv_size);
- if (!smolv::Decode(data.ptr(), data.size(), spirv.ptrw(), spirv_size)) {
- ERR_PRINT("Malformed smolv input uncompressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(j));
- success = false;
- break;
- }
- p_version->variant_stages[i].write[j].spir_v = spirv;
- }
+ uint32_t variant_size = f->get_32();
+ ERR_FAIL_COND_V(variant_size == 0 && variants_enabled[i], false);
+ if (!variants_enabled[i]) {
+ continue;
}
- }
+ Vector<uint8_t> variant_bytes;
+ variant_bytes.resize(variant_size);
- if (!success) {
- for (uint32_t i = 0; i < variant_count; i++) {
- p_version->variant_stages[i].resize(0);
- }
- return false;
- }
+ uint32_t br = f->get_buffer(variant_bytes.ptrw(), variant_size);
- float time_ms = double(OS::get_singleton()->get_ticks_usec() - time_from) / 1000.0;
+ ERR_FAIL_COND_V(br != variant_size, false);
- print_verbose("Shader cache load success '" + path + "' " + rtos(time_ms) + "ms.");
+ p_version->variant_data[i] = variant_bytes;
+ }
for (uint32_t i = 0; i < variant_count; i++) {
- RID shader = RD::get_singleton()->shader_create(p_version->variant_stages[i]);
+ if (!variants_enabled[i]) {
+ MutexLock lock(variant_set_mutex);
+ p_version->variants[i] = RID();
+ continue;
+ }
+ RID shader = RD::get_singleton()->shader_create_from_bytecode(p_version->variant_data[i]);
+ if (shader.is_null()) {
+ for (uint32_t j = 0; j < i; j++) {
+ RD::get_singleton()->free(p_version->variants[i]);
+ }
+ ERR_FAIL_COND_V(shader.is_null(), false);
+ }
{
MutexLock lock(variant_set_mutex);
p_version->variants[i] = shader;
}
}
- memdelete_arr(p_version->variant_stages); //clear stages
- p_version->variant_stages = nullptr;
+ memdelete_arr(p_version->variant_data); //clear stages
+ p_version->variant_data = nullptr;
p_version->valid = true;
return true;
}
@@ -476,49 +450,8 @@ void ShaderRD::_save_to_cache(Version *p_version) {
f->store_32(variant_count); //variant count
for (uint32_t i = 0; i < variant_count; i++) {
- f->store_32(p_version->variant_stages[i].size()); //stage count
- for (int j = 0; j < p_version->variant_stages[i].size(); j++) {
- f->store_32(p_version->variant_stages[i][j].shader_stage); //stage count
- Vector<uint8_t> spirv = p_version->variant_stages[i][j].spir_v;
-
- bool save_uncompressed = true;
- if (shader_cache_save_compressed) {
- smolv::ByteArray smolv;
- bool strip_debug = !shader_cache_save_debug;
- if (!smolv::Encode(spirv.ptr(), spirv.size(), smolv, strip_debug ? smolv::kEncodeFlagStripDebugInfo : 0)) {
- ERR_PRINT("Error compressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(i));
- } else {
- bool compress_zstd = shader_cache_save_compressed_zstd;
-
- if (compress_zstd) {
- Vector<uint8_t> zstd;
- zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD));
- int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD);
- if (dst_size >= 0 && (uint32_t)dst_size < smolv.size()) {
- f->store_32(2); //compressed zstd
- f->store_32(smolv.size()); //size of smolv buffer
- f->store_32(dst_size); //size of smolv buffer
- f->store_buffer(zstd.ptr(), dst_size); //smolv buffer
- } else {
- compress_zstd = false;
- }
- }
-
- if (!compress_zstd) {
- f->store_32(1); //compressed
- f->store_32(smolv.size()); //size of smolv buffer
- f->store_buffer(&smolv[0], smolv.size()); //smolv buffer
- }
- save_uncompressed = false;
- }
- }
-
- if (save_uncompressed) {
- f->store_32(0); //uncompressed
- f->store_32(spirv.size()); //stage count
- f->store_buffer(spirv.ptr(), spirv.size()); //stage count
- }
- }
+ f->store_32(p_version->variant_data[i].size()); //stage count
+ f->store_buffer(p_version->variant_data[i].ptr(), p_version->variant_data[i].size());
}
f->close();
@@ -531,8 +464,8 @@ void ShaderRD::_compile_version(Version *p_version) {
p_version->dirty = false;
p_version->variants = memnew_arr(RID, variant_defines.size());
- typedef Vector<RD::ShaderStageData> ShaderStageArray;
- p_version->variant_stages = memnew_arr(ShaderStageArray, variant_defines.size());
+ typedef Vector<uint8_t> ShaderStageData;
+ p_version->variant_data = memnew_arr(ShaderStageData, variant_defines.size());
if (shader_cache_dir_valid) {
if (_load_from_cache(p_version)) {
@@ -571,19 +504,19 @@ void ShaderRD::_compile_version(Version *p_version) {
}
}
memdelete_arr(p_version->variants);
- if (p_version->variant_stages) {
- memdelete_arr(p_version->variant_stages);
+ if (p_version->variant_data) {
+ memdelete_arr(p_version->variant_data);
}
p_version->variants = nullptr;
- p_version->variant_stages = nullptr;
+ p_version->variant_data = nullptr;
return;
} else if (shader_cache_dir_valid) {
//save shader cache
_save_to_cache(p_version);
}
- memdelete_arr(p_version->variant_stages); //clear stages
- p_version->variant_stages = nullptr;
+ memdelete_arr(p_version->variant_data); //clear stages
+ p_version->variant_data = nullptr;
p_version->valid = true;
}
diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h
index 9a68e02007..44705b2bd6 100644
--- a/servers/rendering/renderer_rd/shader_rd.h
+++ b/servers/rendering/renderer_rd/shader_rd.h
@@ -59,7 +59,7 @@ class ShaderRD {
Map<StringName, CharString> code_sections;
Vector<CharString> custom_defines;
- Vector<RD::ShaderStageData> *variant_stages = nullptr;
+ Vector<uint8_t> *variant_data = nullptr;
RID *variants = nullptr; //same size as version defines
bool valid;
@@ -142,7 +142,9 @@ public:
ERR_FAIL_COND_V(!variants_enabled[p_variant], RID());
Version *version = version_owner.getornull(p_version);
- ERR_FAIL_COND_V(!version, RID());
+ if (!version) {
+ return RID();
+ }
if (version->dirty) {
_compile_version(version);
diff --git a/servers/rendering/renderer_rd/shaders/blur_raster.glsl b/servers/rendering/renderer_rd/shaders/blur_raster.glsl
new file mode 100644
index 0000000000..b1d1c2365e
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/blur_raster.glsl
@@ -0,0 +1,228 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "blur_raster_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "blur_raster_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D source_color;
+
+#ifdef GLOW_USE_AUTO_EXPOSURE
+layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
+#endif
+
+layout(location = 0) out vec4 frag_color;
+
+//DOF
+#ifdef MODE_DOF_BLUR
+
+layout(set = 1, binding = 0) uniform sampler2D dof_source_depth;
+
+#ifdef DOF_QUALITY_LOW
+const int dof_kernel_size = 5;
+const int dof_kernel_from = 2;
+const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388);
+#endif
+
+#ifdef DOF_QUALITY_MEDIUM
+const int dof_kernel_size = 11;
+const int dof_kernel_from = 5;
+const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037);
+
+#endif
+
+#ifdef DOF_QUALITY_HIGH
+const int dof_kernel_size = 21;
+const int dof_kernel_from = 10;
+const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174);
+#endif
+
+#endif
+
+void main() {
+#ifdef MODE_MIPMAP
+
+ vec2 pix_size = blur.pixel_size;
+ vec4 color = texture(source_color, uv_interp + vec2(-0.5, -0.5) * pix_size);
+ color += texture(source_color, uv_interp + vec2(0.5, -0.5) * pix_size);
+ color += texture(source_color, uv_interp + vec2(0.5, 0.5) * pix_size);
+ color += texture(source_color, uv_interp + vec2(-0.5, 0.5) * pix_size);
+ frag_color = color / 4.0;
+
+#endif
+
+#ifdef MODE_GAUSSIAN_BLUR
+
+ //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect
+
+ if (bool(blur.flags & FLAG_HORIZONTAL)) {
+ vec2 pix_size = blur.pixel_size;
+ pix_size *= 0.5; //reading from larger buffer, so use more samples
+ vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.214607;
+ color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.189879;
+ color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.131514;
+ color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.071303;
+ color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.189879;
+ color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.131514;
+ color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.071303;
+ frag_color = color;
+ } else {
+ vec2 pix_size = blur.pixel_size;
+ vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.38774;
+ color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.24477;
+ color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.06136;
+ color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.24477;
+ color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.06136;
+ frag_color = color;
+ }
+#endif
+
+#ifdef MODE_GAUSSIAN_GLOW
+
+ //Glow uses larger sigma 1 for a more rounded blur effect
+
+#define GLOW_ADD(m_ofs, m_mult) \
+ { \
+ vec2 ofs = uv_interp + m_ofs * pix_size; \
+ vec4 c = texture(source_color, ofs) * m_mult; \
+ if (any(lessThan(ofs, vec2(0.0))) || any(greaterThan(ofs, vec2(1.0)))) { \
+ c *= 0.0; \
+ } \
+ color += c; \
+ }
+
+ if (bool(blur.flags & FLAG_HORIZONTAL)) {
+ vec2 pix_size = blur.pixel_size;
+ pix_size *= 0.5; //reading from larger buffer, so use more samples
+ vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.174938;
+ GLOW_ADD(vec2(1.0, 0.0), 0.165569);
+ GLOW_ADD(vec2(2.0, 0.0), 0.140367);
+ GLOW_ADD(vec2(3.0, 0.0), 0.106595);
+ GLOW_ADD(vec2(-1.0, 0.0), 0.165569);
+ GLOW_ADD(vec2(-2.0, 0.0), 0.140367);
+ GLOW_ADD(vec2(-3.0, 0.0), 0.106595);
+ color *= blur.glow_strength;
+ frag_color = color;
+ } else {
+ vec2 pix_size = blur.pixel_size;
+ vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.288713;
+ GLOW_ADD(vec2(0.0, 1.0), 0.233062);
+ GLOW_ADD(vec2(0.0, 2.0), 0.122581);
+ GLOW_ADD(vec2(0.0, -1.0), 0.233062);
+ GLOW_ADD(vec2(0.0, -2.0), 0.122581);
+ color *= blur.glow_strength;
+ frag_color = color;
+ }
+
+#undef GLOW_ADD
+
+ if (bool(blur.flags & FLAG_GLOW_FIRST_PASS)) {
+#ifdef GLOW_USE_AUTO_EXPOSURE
+
+ frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_grey;
+#endif
+ frag_color *= blur.glow_exposure;
+
+ float luminance = max(frag_color.r, max(frag_color.g, frag_color.b));
+ float feedback = max(smoothstep(blur.glow_hdr_threshold, blur.glow_hdr_threshold + blur.glow_hdr_scale, luminance), blur.glow_bloom);
+
+ frag_color = min(frag_color * feedback, vec4(blur.glow_luminance_cap));
+ }
+
+#endif
+
+#ifdef MODE_DOF_BLUR
+
+ vec4 color_accum = vec4(0.0);
+
+ float depth = texture(dof_source_depth, uv_interp, 0.0).r;
+ depth = depth * 2.0 - 1.0;
+
+ if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) {
+ depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0;
+ } else {
+ depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near));
+ }
+
+ // mix near and far blur amount
+ float amount = 1.0;
+ if (bool(blur.flags & FLAG_DOF_FAR)) {
+ amount *= 1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, depth);
+ }
+ if (bool(blur.flags & FLAG_DOF_NEAR)) {
+ amount *= smoothstep(blur.dof_near_end, blur.dof_near_begin, depth);
+ }
+ amount = 1.0 - amount;
+
+ if (amount > 0.0) {
+ float k_accum = 0.0;
+
+ for (int i = 0; i < dof_kernel_size; i++) {
+ int int_ofs = i - dof_kernel_from;
+ vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius;
+
+ float tap_k = dof_kernel[i];
+
+ float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
+ tap_depth = tap_depth * 2.0 - 1.0;
+
+ if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) {
+ tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0;
+ } else {
+ tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near));
+ }
+
+ // mix near and far blur amount
+ float tap_amount = 1.0;
+ if (bool(blur.flags & FLAG_DOF_FAR)) {
+ tap_amount *= mix(1.0 - smoothstep(blur.dof_far_begin, blur.dof_far_end, tap_depth), 0.0, int_ofs == 0);
+ }
+ if (bool(blur.flags & FLAG_DOF_NEAR)) {
+ tap_amount *= mix(smoothstep(blur.dof_near_end, blur.dof_near_begin, tap_depth), 0.0, int_ofs == 0);
+ }
+ tap_amount = 1.0 - tap_amount;
+
+ tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
+
+ vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k;
+
+ k_accum += tap_k * tap_amount;
+ color_accum += tap_color * tap_amount;
+ }
+
+ if (k_accum > 0.0) {
+ color_accum /= k_accum;
+ }
+
+ frag_color = color_accum; ///k_accum;
+ } else {
+ // we are in focus, don't waste time
+ frag_color = texture(source_color, uv_interp, 0.0);
+ }
+
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl
new file mode 100644
index 0000000000..6ea968e595
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/blur_raster_inc.glsl
@@ -0,0 +1,36 @@
+#define FLAG_HORIZONTAL (1 << 0)
+#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 1)
+#define FLAG_GLOW_FIRST_PASS (1 << 2)
+#define FLAG_DOF_FAR (1 << 3)
+#define FLAG_DOF_NEAR (1 << 4)
+
+layout(push_constant, binding = 1, std430) uniform Blur {
+ vec2 pixel_size;
+ uint flags;
+ uint pad;
+
+ // Glow.
+ float glow_strength;
+ float glow_bloom;
+ float glow_hdr_threshold;
+ float glow_hdr_scale;
+
+ float glow_exposure;
+ float glow_white;
+ float glow_luminance_cap;
+ float glow_auto_exposure_grey;
+
+ // DOF.
+ float dof_far_begin;
+ float dof_far_end;
+ float dof_near_begin;
+ float dof_near_end;
+
+ float dof_radius;
+ float dof_pad[3];
+
+ vec2 dof_dir;
+ float camera_z_far;
+ float camera_z_near;
+}
+blur;
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
index 9fa84657d1..63f0ce690e 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
@@ -32,53 +32,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
-layout(push_constant, binding = 1, std430) uniform Params {
- uint face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-void get_dir_0(out vec3 dir, in float u, in float v) {
- dir[0] = 1.0;
- dir[1] = v;
- dir[2] = -u;
-}
-
-void get_dir_1(out vec3 dir, in float u, in float v) {
- dir[0] = -1.0;
- dir[1] = v;
- dir[2] = u;
-}
-
-void get_dir_2(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = 1.0;
- dir[2] = -v;
-}
-
-void get_dir_3(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = -1.0;
- dir[2] = v;
-}
-
-void get_dir_4(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = v;
- dir[2] = 1.0;
-}
-
-void get_dir_5(out vec3 dir, in float u, in float v) {
- dir[0] = -u;
- dir[1] = v;
- dir[2] = -1.0;
-}
-
-float calcWeight(float u, float v) {
- float val = u * u + v * v + 1.0;
- return val * sqrt(val);
-}
+#include "cubemap_downsampler_inc.glsl"
void main() {
uvec3 id = gl_GlobalInvocationID;
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl
new file mode 100644
index 0000000000..b329e67293
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl
@@ -0,0 +1,48 @@
+layout(push_constant, binding = 1, std430) uniform Params {
+ uint face_size;
+ uint face_id; // only used in raster shader
+}
+params;
+
+#define M_PI 3.14159265359
+
+void get_dir_0(out vec3 dir, in float u, in float v) {
+ dir[0] = 1.0;
+ dir[1] = v;
+ dir[2] = -u;
+}
+
+void get_dir_1(out vec3 dir, in float u, in float v) {
+ dir[0] = -1.0;
+ dir[1] = v;
+ dir[2] = u;
+}
+
+void get_dir_2(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = 1.0;
+ dir[2] = -v;
+}
+
+void get_dir_3(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = -1.0;
+ dir[2] = v;
+}
+
+void get_dir_4(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = v;
+ dir[2] = 1.0;
+}
+
+void get_dir_5(out vec3 dir, in float u, in float v) {
+ dir[0] = -u;
+ dir[1] = v;
+ dir[2] = -1.0;
+}
+
+float calcWeight(float u, float v) {
+ float val = u * u + v * v + 1.0;
+ return val * sqrt(val);
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl
new file mode 100644
index 0000000000..0828ffd921
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl
@@ -0,0 +1,163 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_downsampler_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex] * float(params.face_size);
+ gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_downsampler_inc.glsl"
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+
+layout(location = 0) in vec2 uv_interp;
+layout(location = 0) out vec4 frag_color;
+/* clang-format on */
+
+void main() {
+ // Converted from compute shader which uses absolute coordinates.
+ // Could possibly simplify this
+ float face_size = float(params.face_size);
+
+ if (uv_interp.x < face_size && uv_interp.y < face_size) {
+ float inv_face_size = 1.0 / face_size;
+
+ float u0 = (uv_interp.x * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
+ float u1 = (uv_interp.x * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
+
+ float v0 = (uv_interp.y * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
+ float v1 = (uv_interp.y * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
+
+ float weights[4];
+ weights[0] = calcWeight(u0, v0);
+ weights[1] = calcWeight(u1, v0);
+ weights[2] = calcWeight(u0, v1);
+ weights[3] = calcWeight(u1, v1);
+
+ const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
+ for (int i = 0; i < 4; i++) {
+ weights[i] = weights[i] * wsum + .125;
+ }
+
+ vec3 dir;
+ vec4 color;
+ switch (params.face_id) {
+ case 0:
+ get_dir_0(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_0(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_0(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_0(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 1:
+ get_dir_1(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_1(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_1(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_1(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 2:
+ get_dir_2(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_2(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_2(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_2(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 3:
+ get_dir_3(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_3(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_3(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_3(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 4:
+ get_dir_4(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_4(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_4(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_4(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ default:
+ get_dir_5(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_5(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_5(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_5(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ }
+ frag_color = color;
+ }
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl
new file mode 100644
index 0000000000..324d306218
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl
@@ -0,0 +1,256 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ int mip_level;
+ uint face_id;
+}
+params;
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+ gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ int mip_level;
+ uint face_id;
+}
+params;
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+
+layout(location = 0) in vec2 uv_interp;
+layout(location = 0) out vec4 frag_color;
+
+/* clang-format on */
+
+#ifdef USE_HIGH_QUALITY
+#define NUM_TAPS 32
+#else
+#define NUM_TAPS 8
+#endif
+
+#define BASE_RESOLUTION 128
+
+#ifdef USE_HIGH_QUALITY
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+ vec4[7][5][3][24] coeffs;
+}
+data;
+#else
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+ vec4[7][5][6] coeffs;
+}
+data;
+#endif
+
+void get_dir(out vec3 dir, in vec2 uv, in uint face) {
+ switch (face) {
+ case 0:
+ dir = vec3(1.0, uv[1], -uv[0]);
+ break;
+ case 1:
+ dir = vec3(-1.0, uv[1], uv[0]);
+ break;
+ case 2:
+ dir = vec3(uv[0], 1.0, -uv[1]);
+ break;
+ case 3:
+ dir = vec3(uv[0], -1.0, uv[1]);
+ break;
+ case 4:
+ dir = vec3(uv[0], uv[1], 1.0);
+ break;
+ default:
+ dir = vec3(-uv[0], uv[1], -1.0);
+ break;
+ }
+}
+
+void main() {
+ // determine dir / pos for the texel
+ vec3 dir, adir, frameZ;
+ {
+ vec2 uv;
+ uv.x = uv_interp.x;
+ uv.y = 1.0 - uv_interp.y;
+ uv = uv * 2.0 - 1.0;
+
+ get_dir(dir, uv, params.face_id);
+ frameZ = normalize(dir);
+
+ adir = abs(dir);
+ }
+
+ // determine which texel this is
+ // NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name.
+ int mip_level = 0;
+
+ if (params.mip_level < 0) {
+ // return as is
+ frag_color.rgb = textureLod(source_cubemap, frameZ, 0.0).rgb;
+ frag_color.a = 1.0;
+ return;
+ } else if (params.mip_level > 6) {
+ // maximum level
+ mip_level = 6;
+ } else {
+ mip_level = params.mip_level;
+ }
+
+ // GGX gather colors
+ vec4 color = vec4(0.0);
+ for (int axis = 0; axis < 3; axis++) {
+ const int otherAxis0 = 1 - (axis & 1) - (axis >> 1);
+ const int otherAxis1 = 2 - (axis >> 1);
+
+ float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25;
+ if (frameweight > 0.0) {
+ // determine frame
+ vec3 UpVector;
+ switch (axis) {
+ case 0:
+ UpVector = vec3(1, 0, 0);
+ break;
+ case 1:
+ UpVector = vec3(0, 1, 0);
+ break;
+ default:
+ UpVector = vec3(0, 0, 1);
+ break;
+ }
+
+ vec3 frameX = normalize(cross(UpVector, frameZ));
+ vec3 frameY = cross(frameZ, frameX);
+
+ // calculate parametrization for polynomial
+ float Nx = dir[otherAxis0];
+ float Ny = dir[otherAxis1];
+ float Nz = adir[axis];
+
+ float NmaxXY = max(abs(Ny), abs(Nx));
+ Nx /= NmaxXY;
+ Ny /= NmaxXY;
+
+ float theta;
+ if (Ny < Nx) {
+ if (Ny <= -0.999)
+ theta = Nx;
+ else
+ theta = Ny;
+ } else {
+ if (Ny >= 0.999)
+ theta = -Nx;
+ else
+ theta = -Ny;
+ }
+
+ float phi;
+ if (Nz <= -0.999)
+ phi = -NmaxXY;
+ else if (Nz >= 0.999)
+ phi = NmaxXY;
+ else
+ phi = Nz;
+
+ float theta2 = theta * theta;
+ float phi2 = phi * phi;
+
+ // sample
+ for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) {
+ const int index = (NUM_TAPS / 4) * axis + iSuperTap;
+
+#ifdef USE_HIGH_QUALITY
+ vec4 coeffsDir0[3];
+ vec4 coeffsDir1[3];
+ vec4 coeffsDir2[3];
+ vec4 coeffsLevel[3];
+ vec4 coeffsWeight[3];
+
+ for (int iCoeff = 0; iCoeff < 3; iCoeff++) {
+ coeffsDir0[iCoeff] = data.coeffs[mip_level][0][iCoeff][index];
+ coeffsDir1[iCoeff] = data.coeffs[mip_level][1][iCoeff][index];
+ coeffsDir2[iCoeff] = data.coeffs[mip_level][2][iCoeff][index];
+ coeffsLevel[iCoeff] = data.coeffs[mip_level][3][iCoeff][index];
+ coeffsWeight[iCoeff] = data.coeffs[mip_level][4][iCoeff][index];
+ }
+
+ for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+ // determine sample attributes (dir, weight, mip_level)
+ vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2);
+
+ float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2;
+
+ float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2;
+#else
+ vec4 coeffsDir0 = data.coeffs[mip_level][0][index];
+ vec4 coeffsDir1 = data.coeffs[mip_level][1][index];
+ vec4 coeffsDir2 = data.coeffs[mip_level][2][index];
+ vec4 coeffsLevel = data.coeffs[mip_level][3][index];
+ vec4 coeffsWeight = data.coeffs[mip_level][4][index];
+
+ for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+ // determine sample attributes (dir, weight, mip_level)
+ vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap];
+
+ float sample_level = coeffsLevel[iSubTap];
+
+ float sample_weight = coeffsWeight[iSubTap];
+#endif
+
+ sample_weight *= frameweight;
+
+ // adjust for jacobian
+ sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2])));
+ sample_level += 0.75 * log2(dot(sample_dir, sample_dir));
+ // sample cubemap
+ color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight;
+ color.w += sample_weight;
+ }
+ }
+ }
+ }
+ color /= color.w;
+
+ // write color
+ color.xyz = max(vec3(0.0), color.xyz);
+ color.w = 1.0;
+
+ frag_color = color;
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
index ce7c03c1d4..28f4dc59ec 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
@@ -12,100 +12,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube;
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
-layout(push_constant, binding = 1, std430) uniform Params {
- uint face_id;
- uint sample_count;
- float roughness;
- bool use_direct_write;
- float face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-vec3 texelCoordToVec(vec2 uv, uint faceID) {
- mat3 faceUvVectors[6];
-
- // -x
- faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
- faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
-
- // +x
- faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
- faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
-
- // -y
- faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
- faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
-
- // +y
- faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
- faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
-
- // -z
- faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
- faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
-
- // +z
- faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
-
- // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
- vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
- return normalize(result);
-}
-
-vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
- float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
-
- // Compute distribution direction
- float Phi = 2.0 * M_PI * Xi.x;
- float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
- float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
-
- // Convert to spherical direction
- vec3 H;
- H.x = SinTheta * cos(Phi);
- H.y = SinTheta * sin(Phi);
- H.z = CosTheta;
-
- vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
- vec3 TangentX = normalize(cross(UpVector, N));
- vec3 TangentY = cross(N, TangentX);
-
- // Tangent to world space
- return TangentX * H.x + TangentY * H.y + N * H.z;
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float GGX(float NdotV, float a) {
- float k = a / 2.0;
- return NdotV / (NdotV * (1.0 - k) + k);
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float G_Smith(float a, float nDotV, float nDotL) {
- return GGX(nDotL, a * a) * GGX(nDotV, a * a);
-}
-
-float radicalInverse_VdC(uint bits) {
- bits = (bits << 16u) | (bits >> 16u);
- bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
- bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
- bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
- bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
- return float(bits) * 2.3283064365386963e-10; // / 0x100000000
-}
-
-vec2 Hammersley(uint i, uint N) {
- return vec2(float(i) / float(N), radicalInverse_VdC(i));
-}
+#include "cubemap_roughness_inc.glsl"
void main() {
uvec3 id = gl_GlobalInvocationID;
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
new file mode 100644
index 0000000000..80c0ac4fb4
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
@@ -0,0 +1,94 @@
+#define M_PI 3.14159265359
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ uint face_id;
+ uint sample_count;
+ float roughness;
+ bool use_direct_write;
+ float face_size;
+}
+params;
+
+vec3 texelCoordToVec(vec2 uv, uint faceID) {
+ mat3 faceUvVectors[6];
+
+ // -x
+ faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+ // +x
+ faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+ // -y
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+ // +y
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+ // -z
+ faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+ // +z
+ faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
+
+ // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
+ vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
+ return normalize(result);
+}
+
+vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
+ float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
+
+ // Compute distribution direction
+ float Phi = 2.0 * M_PI * Xi.x;
+ float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
+ float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
+
+ // Convert to spherical direction
+ vec3 H;
+ H.x = SinTheta * cos(Phi);
+ H.y = SinTheta * sin(Phi);
+ H.z = CosTheta;
+
+ vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+ vec3 TangentX = normalize(cross(UpVector, N));
+ vec3 TangentY = cross(N, TangentX);
+
+ // Tangent to world space
+ return TangentX * H.x + TangentY * H.y + N * H.z;
+}
+
+// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float GGX(float NdotV, float a) {
+ float k = a / 2.0;
+ return NdotV / (NdotV * (1.0 - k) + k);
+}
+
+// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float G_Smith(float a, float nDotV, float nDotL) {
+ return GGX(nDotL, a * a) * GGX(nDotV, a * a);
+}
+
+float radicalInverse_VdC(uint bits) {
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ return float(bits) * 2.3283064365386963e-10; // / 0x100000000
+}
+
+vec2 Hammersley(uint i, uint N) {
+ return vec2(float(i) / float(N), radicalInverse_VdC(i));
+}
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl
new file mode 100644
index 0000000000..2570308816
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl
@@ -0,0 +1,63 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_roughness_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_roughness_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+
+layout(set = 0, binding = 0) uniform samplerCube source_cube;
+
+layout(location = 0) out vec4 frag_color;
+/* clang-format on */
+
+void main() {
+ vec3 N = texelCoordToVec(uv_interp * 2.0 - 1.0, params.face_id);
+
+ //vec4 color = color_interp;
+
+ if (params.use_direct_write) {
+ frag_color = vec4(texture(source_cube, N).rgb, 1.0);
+ } else {
+ vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
+
+ for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
+ vec2 xi = Hammersley(sampleNum, params.sample_count);
+
+ vec3 H = ImportanceSampleGGX(xi, params.roughness, N);
+ vec3 V = N;
+ vec3 L = (2.0 * dot(V, H) * H - V);
+
+ float ndotl = clamp(dot(N, L), 0.0, 1.0);
+
+ if (ndotl > 0.0) {
+ sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
+ sum.a += ndotl;
+ }
+ }
+ sum /= sum.a;
+
+ frag_color = vec4(sum.rgb, 1.0);
+ }
+}
diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
index 2fce258cff..9155216d7e 100644
--- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
@@ -3,7 +3,7 @@
#define LIGHT_BAKE_STATIC 2
struct LightData { //this structure needs to be as packed as possible
- vec3 position;
+ highp vec3 position;
float inv_radius;
vec3 direction;
@@ -17,8 +17,8 @@ struct LightData { //this structure needs to be as packed as possible
float specular_amount;
bool shadow_enabled;
- vec4 atlas_rect; // rect in the shadow atlas
- mat4 shadow_matrix;
+ highp vec4 atlas_rect; // rect in the shadow atlas
+ highp mat4 shadow_matrix;
float shadow_bias;
float shadow_normal_bias;
float transmittance_bias;
@@ -27,7 +27,7 @@ struct LightData { //this structure needs to be as packed as possible
uint mask;
float shadow_volumetric_fog_fade;
uint bake_mode;
- vec4 projector_rect; //projector rect in srgb decal atlas
+ highp vec4 projector_rect; //projector rect in srgb decal atlas
};
#define REFLECTION_AMBIENT_DISABLED 0
@@ -69,13 +69,13 @@ struct DirectionalLightData {
vec4 shadow_bias;
vec4 shadow_normal_bias;
vec4 shadow_transmittance_bias;
- vec4 shadow_z_range;
- vec4 shadow_range_begin;
+ highp vec4 shadow_z_range;
+ highp vec4 shadow_range_begin;
vec4 shadow_split_offsets;
- mat4 shadow_matrix1;
- mat4 shadow_matrix2;
- mat4 shadow_matrix3;
- mat4 shadow_matrix4;
+ highp mat4 shadow_matrix1;
+ highp mat4 shadow_matrix2;
+ highp mat4 shadow_matrix3;
+ highp mat4 shadow_matrix4;
vec4 shadow_color1;
vec4 shadow_color2;
vec4 shadow_color3;
diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl
new file mode 100644
index 0000000000..29ebd74a90
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl
@@ -0,0 +1,74 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "luminance_reduce_raster_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "luminance_reduce_raster_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D source_exposure;
+
+#ifdef FINAL_PASS
+layout(set = 1, binding = 0) uniform sampler2D prev_luminance;
+#endif
+
+layout(location = 0) out highp float luminance;
+
+void main() {
+ ivec2 dest_pos = ivec2(uv_interp * settings.dest_size);
+ ivec2 src_pos = ivec2(uv_interp * settings.source_size);
+
+ ivec2 next_pos = (dest_pos + ivec2(1)) * settings.source_size / settings.dest_size;
+ next_pos = max(next_pos, src_pos + ivec2(1)); //so it at least reads one pixel
+
+ highp vec3 source_color = vec3(0.0);
+ for (int i = src_pos.x; i < next_pos.x; i++) {
+ for (int j = src_pos.y; j < next_pos.y; j++) {
+ source_color += texelFetch(source_exposure, ivec2(i, j), 0).rgb;
+ }
+ }
+
+ source_color /= float((next_pos.x - src_pos.x) * (next_pos.y - src_pos.y));
+
+#ifdef FIRST_PASS
+ luminance = max(source_color.r, max(source_color.g, source_color.b));
+
+ // This formula should be more "accurate" but gave an overexposed result when testing.
+ // Leaving it here so we can revisit it if we want.
+ // luminance = source_color.r * 0.21 + source_color.g * 0.71 + source_color.b * 0.07;
+#else
+ luminance = source_color.r;
+#endif
+
+#ifdef FINAL_PASS
+ // Obtain our target luminance
+ luminance = clamp(luminance, settings.min_luminance, settings.max_luminance);
+
+ // Now smooth to our transition
+ highp float prev_lum = texelFetch(prev_luminance, ivec2(0, 0), 0).r; //1 pixel previous luminance
+ luminance = prev_lum + (luminance - prev_lum) * clamp(settings.exposure_adjust, 0.0, 1.0);
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl
new file mode 100644
index 0000000000..ed389ffe56
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl
@@ -0,0 +1,11 @@
+
+layout(push_constant, binding = 1, std430) uniform PushConstant {
+ ivec2 source_size;
+ ivec2 dest_size;
+
+ float exposure_adjust;
+ float min_luminance;
+ float max_luminance;
+ float pad;
+}
+settings;
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index 4dceeea995..e88e68b511 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -138,7 +138,7 @@ void main() {
if (bool(particles.data[particle].flags & PARTICLE_FLAG_ACTIVE) || bool(particles.data[particle].flags & PARTICLE_FLAG_TRAILED)) {
txform = particles.data[particle].xform;
if (params.trail_size > 1) {
- // since the steps dont fit precisely in the history frames, must do a tiny bit of
+ // Since the steps don't fit precisely in the history frames, must do a tiny bit of
// interpolation to get them close to their intended location.
uint part_ofs = particle % params.trail_size;
float natural_ofs = fract((float(part_ofs) / float(params.trail_size)) * float(params.trail_total)) * params.frame_delta;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index 74d5af5cb6..4f140dd10d 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -356,6 +356,24 @@ void main() {
#VERSION_DEFINES
+/* Specialization Constants (Toggles) */
+
+layout(constant_id = 0) const bool sc_use_forward_gi = false;
+layout(constant_id = 1) const bool sc_use_light_projector = false;
+layout(constant_id = 2) const bool sc_use_light_soft_shadows = false;
+layout(constant_id = 3) const bool sc_use_directional_soft_shadows = false;
+
+/* Specialization Constants (Values) */
+
+layout(constant_id = 6) const uint sc_soft_shadow_samples = 4;
+layout(constant_id = 7) const uint sc_penumbra_shadow_samples = 4;
+
+layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4;
+layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4;
+
+layout(constant_id = 10) const bool sc_decal_use_mipmaps = true;
+layout(constant_id = 11) const bool sc_projector_use_mipmaps = true;
+
#include "scene_forward_clustered_inc.glsl"
/* Varyings */
@@ -448,14 +466,15 @@ layout(location = 0) out vec4 frag_color;
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-#include "scene_forward_lights_inc.glsl"
+/* Make a default specular mode SPECULAR_SCHLICK_GGX. */
+#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON)
+#define SPECULAR_SCHLICK_GGX
+#endif
-#ifdef USE_FORWARD_GI
+#include "scene_forward_lights_inc.glsl"
#include "scene_forward_gi_inc.glsl"
-#endif //USE_FORWARD_GI
-
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
#ifndef MODE_RENDER_DEPTH
@@ -793,25 +812,35 @@ void main() {
continue; //out of decal
}
- //we need ddx/ddy for mipmaps, so simulate them
- vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
- vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
-
float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade);
if (decals.data[decal_index].normal_fade > 0.0) {
fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5);
}
+ //we need ddx/ddy for mipmaps, so simulate them
+ vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
+ vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
+
if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
//has albedo
- vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ vec4 decal_albedo;
+ if (sc_decal_use_mipmaps) {
+ decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ } else {
+ decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
+ }
decal_albedo *= decals.data[decal_index].modulate;
decal_albedo.a *= fade;
albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix);
if (decals.data[decal_index].normal_rect != vec4(0.0)) {
- vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ vec3 decal_normal;
+ if (sc_decal_use_mipmaps) {
+ decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ } else {
+ decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz;
+ }
decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software
decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
//convert to view space, use xzy because y is up
@@ -821,7 +850,12 @@ void main() {
}
if (decals.data[decal_index].orm_rect != vec4(0.0)) {
- vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ vec3 decal_orm;
+ if (sc_decal_use_mipmaps) {
+ decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ } else {
+ decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz;
+ }
ao = mix(ao, decal_orm.r, decal_albedo.a);
roughness = mix(roughness, decal_orm.g, decal_albedo.a);
metallic = mix(metallic, decal_orm.b, decal_albedo.a);
@@ -830,7 +864,11 @@ void main() {
if (decals.data[decal_index].emission_rect != vec4(0.0)) {
//emission is additive, so its independent from albedo
- emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ if (sc_decal_use_mipmaps) {
+ emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ } else {
+ emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade;
+ }
}
}
}
@@ -874,6 +912,8 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
+ specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
@@ -963,9 +1003,9 @@ void main() {
ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb;
}
}
-#elif defined(USE_FORWARD_GI)
+#else
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture
+ if (sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture
//make vertex orientation the world one, but still align to camera
vec3 cam_pos = mat3(scene_data.camera_matrix) * vertex;
@@ -1037,7 +1077,7 @@ void main() {
}
}
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
+ if (sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
vec3 ref_vec = normalize(reflect(normalize(vertex), normal));
@@ -1068,9 +1108,8 @@ void main() {
specular_light = spec_accum.rgb;
ambient_light = amb_accum.rgb;
}
-#else
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
+ if (!sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
vec2 coord;
@@ -1101,7 +1140,7 @@ void main() {
ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a);
specular_light = mix(specular_light, buffer_reflection.rgb, buffer_reflection.a);
}
-#endif
+#endif // !USE_LIGHTMAP
if (scene_data.ssao_enabled) {
float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
@@ -1182,7 +1221,7 @@ void main() {
specular_light *= specular * metallic * albedo * 2.0;
#else
- // scales the specular reflections, needs to be be computed before lighting happens,
+ // scales the specular reflections, needs to be computed before lighting happens,
// but after environment, GI, and reflection probes are added
// Environment brdf approximation (Lazarov 2013)
// see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
@@ -1228,14 +1267,13 @@ void main() {
float shadow = 1.0;
-#ifdef USE_SOFT_SHADOWS
//version with soft shadows, more expensive
if (directional_lights.data[i].shadow_enabled) {
- float depth_z = -vertex.z;
+ if (sc_use_directional_soft_shadows && directional_lights.data[i].softshadow_angle > 0) {
+ float depth_z = -vertex.z;
- vec4 pssm_coord;
- vec3 shadow_color = vec3(0.0);
- vec3 light_dir = directional_lights.data[i].direction;
+ vec3 shadow_color = vec3(0.0);
+ vec3 light_dir = directional_lights.data[i].direction;
#define BIAS_FUNC(m_var, m_idx) \
m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
@@ -1243,168 +1281,105 @@ void main() {
normal_bias -= light_dir * dot(light_dir, normal_bias); \
m_var.xyz += normal_bias;
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- vec4 v = vec4(vertex, 1.0);
+ uint blend_index = 0;
- BIAS_FUNC(v, 0)
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
- pssm_coord /= pssm_coord.w;
+ BIAS_FUNC(v, 0)
+
+ vec4 pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
float range_begin = directional_lights.data[i].shadow_range_begin.x;
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius;
shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ blend_index++;
}
- shadow_color = directional_lights.data[i].shadow_color1.rgb;
-
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
+ if (blend_index < 2 && depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 1)
+ BIAS_FUNC(v, 1)
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
+ vec4 pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
float range_begin = directional_lights.data[i].shadow_range_begin.y;
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+
+ if (blend_index == 0) {
+ shadow = s;
+ } else {
+ //blend
+ float blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ shadow = mix(shadow, s, blend);
+ }
+
+ blend_index++;
}
- shadow_color = directional_lights.data[i].shadow_color2.rgb;
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
+ if (blend_index < 2 && depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 2)
+ BIAS_FUNC(v, 2)
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_coord /= pssm_coord.w;
+ vec4 pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
float range_pos = dot(directional_lights.data[i].direction, v.xyz);
float range_begin = directional_lights.data[i].shadow_range_begin.z;
float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- }
-
- shadow_color = directional_lights.data[i].shadow_color3.rgb;
-
- } else {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 3)
+ float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
+ if (blend_index == 0) {
+ shadow = s;
+ } else {
+ //blend
+ float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ shadow = mix(shadow, s, blend);
+ }
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.w;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
- shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ blend_index++;
}
- shadow_color = directional_lights.data[i].shadow_color4.rgb;
- }
-
- if (directional_lights.data[i].blend_splits) {
- vec3 shadow_color_blend = vec3(0.0);
- float pssm_blend;
- float shadow2;
-
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ if (blend_index < 2) {
vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 1)
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.y;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
- shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- }
+ BIAS_FUNC(v, 3)
- pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
- shadow_color_blend = directional_lights.data[i].shadow_color2.rgb;
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 2)
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ vec4 pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.z;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
- shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- } else {
- shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- }
-
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.w;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
+ float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
- shadow_color_blend = directional_lights.data[i].shadow_color3.rgb;
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
- BIAS_FUNC(v, 3)
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_coord /= pssm_coord.w;
- if (directional_lights.data[i].softshadow_angle > 0) {
- float range_pos = dot(directional_lights.data[i].direction, v.xyz);
- float range_begin = directional_lights.data[i].shadow_range_begin.w;
- float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
- vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
- shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ if (blend_index == 0) {
+ shadow = s;
} else {
- shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ //blend
+ float blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ shadow = mix(shadow, s, blend);
}
-
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
- shadow_color_blend = directional_lights.data[i].shadow_color4.rgb;
- } else {
- pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
}
- pssm_blend = sqrt(pssm_blend);
-
- shadow = mix(shadow, shadow2, pssm_blend);
- shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend);
- }
-
- shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
-
#undef BIAS_FUNC
- }
-#else
- // Soft shadow disabled version
+ } else { //no soft shadows
- if (directional_lights.data[i].shadow_enabled) {
- float depth_z = -vertex.z;
+ float depth_z = -vertex.z;
- vec4 pssm_coord;
- vec3 light_dir = directional_lights.data[i].direction;
- vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
+ vec4 pssm_coord;
+ vec3 light_dir = directional_lights.data[i].direction;
+ vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
#define BIAS_FUNC(m_var, m_idx) \
m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
@@ -1412,70 +1387,70 @@ void main() {
normal_bias -= light_dir * dot(light_dir, normal_bias); \
m_var.xyz += normal_bias;
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 0)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 1)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 2)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
-
- } else {
- vec4 v = vec4(vertex, 1.0);
-
- BIAS_FUNC(v, 3)
-
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- }
-
- pssm_coord /= pssm_coord.w;
-
- shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
- if (directional_lights.data[i].blend_splits) {
- float pssm_blend;
+ BIAS_FUNC(v, 0)
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
vec4 v = vec4(vertex, 1.0);
+
BIAS_FUNC(v, 1)
+
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
- pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
vec4 v = vec4(vertex, 1.0);
+
BIAS_FUNC(v, 2)
+
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+
+ } else {
vec4 v = vec4(vertex, 1.0);
+
BIAS_FUNC(v, 3)
+
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
- pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
- } else {
- pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
}
pssm_coord /= pssm_coord.w;
- float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
- shadow = mix(shadow, shadow2, pssm_blend);
- }
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+
+ if (directional_lights.data[i].blend_splits) {
+ float pssm_blend;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 1)
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 2)
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 3)
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ } else {
+ pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ }
- shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
+ pssm_coord /= pssm_coord.w;
+
+ float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ shadow = mix(shadow, shadow2, pssm_blend);
+ }
+
+ shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
#undef BIAS_FUNC
- }
-#endif
+ }
+ } // shadows
if (i < 4) {
shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8);
@@ -1554,7 +1529,9 @@ void main() {
blur_shadow(shadow);
- light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
+ float size_A = sc_use_light_soft_shadows ? directional_lights.data[i].size : 0.0;
+
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), size_A, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1573,9 +1550,6 @@ void main() {
#ifdef LIGHT_ANISOTROPY_USED
binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOW
- directional_lights.data[i].size,
-#endif
#ifdef USE_SHADOW_TO_OPACITY
alpha,
#endif
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
index 6599a42bab..b53bf6a6d4 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
@@ -52,6 +52,10 @@ layout(set = 0, binding = 1) uniform sampler material_samplers[12];
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+layout(set = 0, binding = 3) uniform sampler decal_sampler;
+
+layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
+
#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 7)
@@ -67,22 +71,22 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler;
//3 bits of stride
#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
-layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights {
LightData data[];
}
omni_lights;
-layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+layout(set = 0, binding = 6, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
-layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
+layout(set = 0, binding = 7, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
-layout(set = 0, binding = 6, std140) uniform DirectionalLights {
+layout(set = 0, binding = 8, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
@@ -94,7 +98,7 @@ struct Lightmap {
mat3 normal_xform;
};
-layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
+layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
Lightmap data[];
}
lightmaps;
@@ -103,20 +107,20 @@ struct LightmapCapture {
vec4 sh[9];
};
-layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
+layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures {
LightmapCapture data[];
}
lightmap_captures;
-layout(set = 0, binding = 9) uniform texture2D decal_atlas;
-layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb;
+layout(set = 0, binding = 11) uniform texture2D decal_atlas;
+layout(set = 0, binding = 12) uniform texture2D decal_atlas_srgb;
-layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
+layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
DecalData data[];
}
decals;
-layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData {
+layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
global_variables;
@@ -128,7 +132,7 @@ struct SDFVoxelGICascadeData {
float to_cell; // 1/bounds * grid_size
};
-layout(set = 0, binding = 13, std140) uniform SDFGI {
+layout(set = 0, binding = 15, std140) uniform SDFGI {
vec3 grid_size;
uint max_cascades;
@@ -173,17 +177,12 @@ layout(set = 1, binding = 0, std140) uniform SceneData {
uint cluster_type_size;
uint max_cluster_element_count_div_32;
- //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted
+ // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
vec4 directional_penumbra_shadow_kernel[32];
vec4 directional_soft_shadow_kernel[32];
vec4 penumbra_shadow_kernel[32];
vec4 soft_shadow_kernel[32];
- uint directional_penumbra_shadow_samples;
- uint directional_soft_shadow_samples;
- uint penumbra_shadow_samples;
- uint soft_shadow_samples;
-
vec4 ambient_light_color_energy;
float ambient_color_sky_mix;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index b6e89acb46..5920444f7a 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -73,7 +73,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
return mix(vec3(dielectric), albedo, vec3(metallic));
}
-void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount,
+void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -92,9 +92,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#ifdef LIGHT_ANISOTROPY_USED
vec3 B, vec3 T, float anisotropy,
#endif
-#ifdef USE_SOFT_SHADOWS
- float A,
-#endif
#ifdef USE_SHADOW_TO_OPACITY
inout float alpha,
#endif
@@ -111,11 +108,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#else
-#ifdef USE_SOFT_SHADOWS
float NdotL = min(A + dot(N, L), 1.0);
-#else
- float NdotL = dot(N, L);
-#endif
float cNdotL = max(NdotL, 0.0); // clamped NdotL
float NdotV = dot(N, V);
float cNdotV = max(NdotV, 0.0);
@@ -125,19 +118,11 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#endif
#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
-#else
- float cNdotH = clamp(dot(N, H), 0.0, 1.0);
-#endif
#endif
#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
-#else
- float cLdotH = clamp(dot(L, H), 0.0, 1.0);
-#endif
#endif
float metallic = unpackUnorm4x8(orms).z;
@@ -223,26 +208,20 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
//normalized blinn
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
- float blinn = pow(cNdotH, shininess) * cNdotL;
- blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float intensity = blinn;
+ float blinn = pow(cNdotH, shininess);
+ blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI));
- specular_light += light_color * intensity * attenuation * specular_amount;
+ specular_light += light_color * attenuation * specular_amount * blinn * f0 * unpackUnorm4x8(orms).w;
#elif defined(SPECULAR_PHONG)
vec3 R = normalize(-reflect(L, N));
-#ifdef USE_SOFT_SHADOWS
float cRdotV = clamp(A + dot(R, V), 0.0, 1.0);
-#else
- float cRdotV = clamp(dot(R, V), 0.0, 1.0);
-#endif
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
float phong = pow(cRdotV, shininess);
- phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75);
+ phong *= (shininess + 1.0) * (1.0 / (8.0 * M_PI));
- specular_light += light_color * intensity * attenuation * specular_amount;
+ specular_light += light_color * attenuation * specular_amount * phong * f0 * unpackUnorm4x8(orms).w;
#elif defined(SPECULAR_TOON)
@@ -320,7 +299,7 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
float depth = coord.z;
//if only one sample is taken, take it from the center
- if (scene_data.directional_soft_shadow_samples == 1) {
+ if (sc_directional_soft_shadow_samples == 1) {
return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
}
@@ -334,11 +313,11 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
float avg = 0.0;
- for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) {
+ for (uint i = 0; i < sc_directional_soft_shadow_samples; i++) {
avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0));
}
- return avg * (1.0 / float(scene_data.directional_soft_shadow_samples));
+ return avg * (1.0 / float(sc_directional_soft_shadow_samples));
}
float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
@@ -346,7 +325,7 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
float depth = coord.z;
//if only one sample is taken, take it from the center
- if (scene_data.soft_shadow_samples == 1) {
+ if (sc_soft_shadow_samples == 1) {
return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
}
@@ -360,11 +339,11 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
float avg = 0.0;
- for (uint i = 0; i < scene_data.soft_shadow_samples; i++) {
+ for (uint i = 0; i < sc_soft_shadow_samples; i++) {
avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0));
}
- return avg * (1.0 / float(scene_data.soft_shadow_samples));
+ return avg * (1.0 / float(sc_soft_shadow_samples));
}
float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) {
@@ -380,7 +359,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
}
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_directional_penumbra_shadow_samples; i++) {
vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
if (d < pssm_coord.z) {
@@ -396,12 +375,12 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
tex_scale *= penumbra;
float s = 0.0;
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_directional_penumbra_shadow_samples; i++) {
vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0));
}
- return s / float(scene_data.directional_penumbra_shadow_samples);
+ return s / float(sc_directional_penumbra_shadow_samples);
} else {
//no blockers found, so no shadow
@@ -442,8 +421,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
float shadow;
-#ifdef USE_SOFT_SHADOWS
- if (omni_lights.data[idx].soft_shadow_size > 0.0) {
+ if (sc_use_light_soft_shadows && omni_lights.data[idx].soft_shadow_size > 0.0) {
//soft shadow
//find blocker
@@ -468,7 +446,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
@@ -505,7 +483,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
@@ -526,14 +504,13 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0));
}
- shadow /= float(scene_data.penumbra_shadow_samples);
+ shadow /= float(sc_penumbra_shadow_samples);
} else {
//no blockers found, so no shadow
shadow = 1.0;
}
} else {
-#endif
splane.xyz = normalize(splane.xyz);
vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
@@ -553,9 +530,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
splane.w = 1.0; //needed? i think it should be 1 already
shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
-#ifdef USE_SOFT_SHADOWS
}
-#endif
return shadow;
}
@@ -592,14 +567,12 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
float light_attenuation = omni_attenuation;
vec3 color = omni_lights.data[idx].color;
-#ifdef USE_SOFT_SHADOWS
float size_A = 0.0;
- if (omni_lights.data[idx].size > 0.0) {
+ if (sc_use_light_soft_shadows && omni_lights.data[idx].size > 0.0) {
float t = omni_lights.data[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
-#endif
#ifdef LIGHT_TRANSMITTANCE_USED
float transmittance_z = transmittance_depth; //no transmittance by default
@@ -633,9 +606,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
}
#endif
-#if 0
-
- if (omni_lights.data[idx].projector_rect != vec4(0.0)) {
+ if (sc_use_light_projector && omni_lights.data[idx].projector_rect != vec4(0.0)) {
vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
local_v = normalize(local_v);
@@ -653,46 +624,50 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
local_v.xy = local_v.xy * 0.5 + 0.5;
vec2 proj_uv = local_v.xy * atlas_rect.zw;
- vec2 proj_uv_ddx;
- vec2 proj_uv_ddy;
- {
- vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
- local_v_ddx = normalize(local_v_ddx);
+ if (sc_projector_use_mipmaps) {
+ vec2 proj_uv_ddx;
+ vec2 proj_uv_ddy;
+ {
+ vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
+ local_v_ddx = normalize(local_v_ddx);
- if (local_v_ddx.z >= 0.0) {
- local_v_ddx.z += 1.0;
- } else {
- local_v_ddx.z = 1.0 - local_v_ddx.z;
- }
+ if (local_v_ddx.z >= 0.0) {
+ local_v_ddx.z += 1.0;
+ } else {
+ local_v_ddx.z = 1.0 - local_v_ddx.z;
+ }
- local_v_ddx.xy /= local_v_ddx.z;
- local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
+ local_v_ddx.xy /= local_v_ddx.z;
+ local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
- proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
+ proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
- vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
- local_v_ddy = normalize(local_v_ddy);
+ vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
+ local_v_ddy = normalize(local_v_ddy);
- if (local_v_ddy.z >= 0.0) {
- local_v_ddy.z += 1.0;
- } else {
- local_v_ddy.z = 1.0 - local_v_ddy.z;
- }
+ if (local_v_ddy.z >= 0.0) {
+ local_v_ddy.z += 1.0;
+ } else {
+ local_v_ddy.z = 1.0 - local_v_ddy.z;
+ }
- local_v_ddy.xy /= local_v_ddy.z;
- local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
+ local_v_ddy.xy /= local_v_ddy.z;
+ local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
- proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
- }
+ proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
+ }
- vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
- no_shadow = mix(no_shadow, proj.rgb, proj.a);
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ color *= proj.rgb * proj.a;
+ } else {
+ vec4 proj = textureLod(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + atlas_rect.xy, 0.0);
+ color *= proj.rgb * proj.a;
+ }
}
-#endif
light_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -711,9 +686,6 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOWS
- size_A,
-#endif
#ifdef USE_SHADOW_TO_OPACITY
alpha,
#endif
@@ -747,8 +719,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
splane /= splane.w;
-#ifdef USE_SOFT_SHADOWS
- if (spot_lights.data[idx].soft_shadow_size > 0.0) {
+ if (sc_use_light_soft_shadows && spot_lights.data[idx].soft_shadow_size > 0.0) {
//soft shadow
//find blocker
@@ -768,11 +739,11 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale;
vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
- if (d < z_norm) {
+ if (d < splane.z) {
blocker_average += d;
blocker_count += 1.0;
}
@@ -785,13 +756,13 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
uv_size *= penumbra;
shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
- shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
+ shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, splane.z, 1.0));
}
- shadow /= float(scene_data.penumbra_shadow_samples);
+ shadow /= float(sc_penumbra_shadow_samples);
} else {
//no blockers found, so no shadow
@@ -799,14 +770,11 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
}
} else {
-#endif
//hard shadow
vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0);
shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
-#ifdef USE_SOFT_SHADOWS
}
-#endif
return shadow;
}
@@ -816,6 +784,18 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
return 1.0;
}
+vec2 normal_to_panorama(vec3 n) {
+ n = normalize(n);
+ vec2 panorama_coords = vec2(atan(n.x, n.z), acos(-n.y));
+
+ if (panorama_coords.x < 0.0) {
+ panorama_coords.x += M_PI * 2.0;
+ }
+
+ panorama_coords /= vec2(M_PI * 2.0, M_PI);
+ return panorama_coords;
+}
+
void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
@@ -850,20 +830,12 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
vec3 color = spot_lights.data[idx].color;
float specular_amount = spot_lights.data[idx].specular_amount;
-#ifdef USE_SOFT_SHADOWS
float size_A = 0.0;
- if (spot_lights.data[idx].size > 0.0) {
+ if (sc_use_light_soft_shadows && spot_lights.data[idx].size > 0.0) {
float t = spot_lights.data[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
-#endif
-
- /*
- if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) {
- //use projector texture
- }
- */
#ifdef LIGHT_TRANSMITTANCE_USED
float transmittance_z = transmittance_depth;
@@ -886,9 +858,32 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
}
#endif //LIGHT_TRANSMITTANCE_USED
+ if (sc_use_light_projector && spot_lights.data[idx].projector_rect != vec4(0.0)) {
+ vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
+ splane /= splane.w;
+
+ vec2 proj_uv = normal_to_panorama(splane.xyz) * spot_lights.data[idx].projector_rect.zw;
+
+ if (sc_projector_use_mipmaps) {
+ //ensure we have proper mipmaps
+ vec4 splane_ddx = (spot_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0));
+ splane_ddx /= splane_ddx.w;
+ vec2 proj_uv_ddx = normal_to_panorama(splane_ddx.xyz) * spot_lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 splane_ddy = (spot_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0));
+ splane_ddy /= splane_ddy.w;
+ vec2 proj_uv_ddy = normal_to_panorama(splane_ddy.xyz) * spot_lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + spot_lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ color *= proj.rgb * proj.a;
+ } else {
+ vec4 proj = textureLod(sampler2D(decal_atlas_srgb, light_projector_sampler), proj_uv + spot_lights.data[idx].projector_rect.xy, 0.0);
+ color *= proj.rgb * proj.a;
+ }
+ }
light_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -907,9 +902,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#ifdef LIGHT_ANISOTROPY_USED
binormal, tangent, anisotropy,
#endif
-#ifdef USE_SOFT_SHADOW
- size_A,
-#endif
#ifdef USE_SHADOW_TO_OPACITY
alpha,
#endif
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
index 1bc17e140f..2babe92c1c 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -59,27 +59,27 @@ layout(location = 11) in vec4 weight_attrib;
/* Varyings */
-layout(location = 0) out vec3 vertex_interp;
+layout(location = 0) highp out vec3 vertex_interp;
#ifdef NORMAL_USED
-layout(location = 1) out vec3 normal_interp;
+layout(location = 1) mediump out vec3 normal_interp;
#endif
#if defined(COLOR_USED)
-layout(location = 2) out vec4 color_interp;
+layout(location = 2) mediump out vec4 color_interp;
#endif
#ifdef UV_USED
-layout(location = 3) out vec2 uv_interp;
+layout(location = 3) mediump out vec2 uv_interp;
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
-layout(location = 4) out vec2 uv2_interp;
+layout(location = 4) mediump out vec2 uv2_interp;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 5) out vec3 tangent_interp;
-layout(location = 6) out vec3 binormal_interp;
+layout(location = 5) mediump out vec3 tangent_interp;
+layout(location = 6) mediump out vec3 binormal_interp;
#endif
#ifdef MATERIAL_UNIFORMS_USED
@@ -370,37 +370,61 @@ void main() {
#VERSION_DEFINES
+//use medium precision for floats on mobile.
+
+precision mediump float;
+
+/* Specialization Constants */
+
+/* Specialization Constants (Toggles) */
+
+layout(constant_id = 0) const bool sc_use_forward_gi = false;
+layout(constant_id = 1) const bool sc_use_light_projector = false;
+layout(constant_id = 2) const bool sc_use_light_soft_shadows = false;
+layout(constant_id = 3) const bool sc_use_directional_soft_shadows = false;
+
+/* Specialization Constants (Values) */
+
+layout(constant_id = 6) const uint sc_soft_shadow_samples = 4;
+layout(constant_id = 7) const uint sc_penumbra_shadow_samples = 4;
+
+layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4;
+layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4;
+
+layout(constant_id = 10) const bool sc_decal_use_mipmaps = true;
+layout(constant_id = 11) const bool sc_projector_use_mipmaps = true;
+
/* Include our forward mobile UBOs definitions etc. */
#include "scene_forward_mobile_inc.glsl"
/* Varyings */
-layout(location = 0) in vec3 vertex_interp;
+layout(location = 0) highp in vec3 vertex_interp;
#ifdef NORMAL_USED
-layout(location = 1) in vec3 normal_interp;
+layout(location = 1) mediump in vec3 normal_interp;
#endif
#if defined(COLOR_USED)
-layout(location = 2) in vec4 color_interp;
+layout(location = 2) mediump in vec4 color_interp;
#endif
#ifdef UV_USED
-layout(location = 3) in vec2 uv_interp;
+layout(location = 3) mediump in vec2 uv_interp;
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
-layout(location = 4) in vec2 uv2_interp;
+layout(location = 4) mediump in vec2 uv2_interp;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 5) in vec3 tangent_interp;
-layout(location = 6) in vec3 binormal_interp;
+layout(location = 5) mediump in vec3 tangent_interp;
+layout(location = 6) mediump in vec3 binormal_interp;
#endif
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) in float dp_clip;
+layout(location = 8) highp in float dp_clip;
#endif
@@ -471,6 +495,11 @@ layout(location = 0) out vec4 frag_color;
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+/* Make a default specular mode SPECULAR_SCHLICK_GGX. */
+#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON)
+#define SPECULAR_SCHLICK_GGX
+#endif
+
#include "scene_forward_lights_inc.glsl"
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -823,6 +852,8 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
+ specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
}
@@ -961,7 +992,7 @@ void main() {
specular_light *= specular * metallic * albedo * 2.0;
#else
- // scales the specular reflections, needs to be be computed before lighting happens,
+ // scales the specular reflections, needs to be computed before lighting happens,
// but after environment, GI, and reflection probes are added
// Environment brdf approximation (Lazarov 2013)
// see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
@@ -1284,7 +1315,7 @@ void main() {
blur_shadow(shadow);
- light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), 0.0, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
index d4ebcbeec4..f1e554d01c 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
@@ -16,12 +16,12 @@
/* don't exceed 128 bytes!! */
/* put instance data into our push content, not a array */
layout(push_constant, binding = 0, std430) uniform DrawCall {
- mat4 transform; // 64 - 64
+ highp mat4 transform; // 64 - 64
uint flags; // 04 - 68
uint instance_uniforms_ofs; //base offset in global buffer for instance variables // 04 - 72
uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) // 04 - 76
uint layer_mask; // 04 - 80
- vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
+ highp vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
uvec2 reflection_probes; // 08 - 104
uvec2 omni_lights; // 08 - 112
@@ -51,6 +51,9 @@ layout(set = 0, binding = 1) uniform sampler material_samplers[12];
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+layout(set = 0, binding = 3) uniform sampler decal_sampler;
+layout(set = 0, binding = 4) uniform sampler light_projector_sampler;
+
#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 7)
@@ -66,22 +69,22 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler;
//3 bits of stride
#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
-layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights {
LightData data[];
}
omni_lights;
-layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+layout(set = 0, binding = 6, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
-layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
+layout(set = 0, binding = 7, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
-layout(set = 0, binding = 6, std140) uniform DirectionalLights {
+layout(set = 0, binding = 8, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
@@ -93,7 +96,7 @@ struct Lightmap {
mat3 normal_xform;
};
-layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
+layout(set = 0, binding = 9, std140) restrict readonly buffer Lightmaps {
Lightmap data[];
}
lightmaps;
@@ -102,20 +105,20 @@ struct LightmapCapture {
vec4 sh[9];
};
-layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
+layout(set = 0, binding = 10, std140) restrict readonly buffer LightmapCaptures {
LightmapCapture data[];
}
lightmap_captures;
-layout(set = 0, binding = 9) uniform texture2D decal_atlas;
-layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb;
+layout(set = 0, binding = 11) uniform texture2D decal_atlas;
+layout(set = 0, binding = 12) uniform texture2D decal_atlas_srgb;
-layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
+layout(set = 0, binding = 13, std430) restrict readonly buffer Decals {
DecalData data[];
}
decals;
-layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData {
+layout(set = 0, binding = 14, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
global_variables;
@@ -123,29 +126,24 @@ global_variables;
/* Set 1: Render Pass (changes per render pass) */
layout(set = 1, binding = 0, std140) uniform SceneData {
- mat4 projection_matrix;
- mat4 inv_projection_matrix;
- mat4 camera_matrix;
- mat4 inv_camera_matrix;
+ highp mat4 projection_matrix;
+ highp mat4 inv_projection_matrix;
+ highp mat4 camera_matrix;
+ highp mat4 inv_camera_matrix;
// only used for multiview
- mat4 projection_matrix_view[MAX_VIEWS];
- mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
vec2 viewport_size;
vec2 screen_pixel_size;
- //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted
+ // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
vec4 directional_penumbra_shadow_kernel[32];
vec4 directional_soft_shadow_kernel[32];
vec4 penumbra_shadow_kernel[32];
vec4 soft_shadow_kernel[32];
- uint directional_penumbra_shadow_samples;
- uint directional_soft_shadow_samples;
- uint penumbra_shadow_samples;
- uint soft_shadow_samples;
-
vec4 ambient_light_color_energy;
float ambient_color_sky_mix;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
index 99db35bb34..d6e5c6a92e 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
@@ -20,10 +20,10 @@ layout(set = 0, binding = 3, std430) restrict readonly buffer DispatchData {
dispatch_data;
struct ProcessVoxel {
- uint position; //xyz 7 bit packed, extra 11 bits for neigbours
- uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours
- uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
- uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
+ uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
+ uint albedo; // rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors.
+ uint light; // rgbe8985 encoded total saved light, extra 2 bits for neighbors.
+ uint light_aniso; // 55555 light anisotropy, extra 2 bits for neighbors.
//total neighbours: 26
};
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
index bc376e9522..eedd28959c 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
@@ -266,9 +266,9 @@ void main() {
} else if (params.sky_mode == SKY_MODE_SKY) {
#ifdef USE_CUBEMAP_ARRAY
- light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates
+ light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates.
#else
- light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates
+ light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates.
#endif
light.rgb *= params.sky_energy;
light.a = 0.0;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
index aa4ded146f..4d9fa85a74 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
@@ -101,7 +101,7 @@ layout(set = 0, binding = 10, std430) restrict buffer DispatchData {
dispatch_data;
struct ProcessVoxel {
- uint position; //xyz 7 bit packed, extra 11 bits for neigbours
+ uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours
uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
@@ -134,7 +134,7 @@ layout(set = 0, binding = 5, std430) restrict buffer readonly DispatchData {
dispatch_data;
struct ProcessVoxel {
- uint position; //xyz 7 bit packed, extra 11 bits for neigbours
+ uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neibhbours
uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
@@ -183,7 +183,7 @@ void main() {
ivec3 write_pos = read_pos + params.scroll;
if (any(lessThan(write_pos, ivec3(0))) || any(greaterThanEqual(write_pos, ivec3(params.grid_size)))) {
- return; //fits outside the 3D texture, dont do anything
+ return; // Fits outside the 3D texture, don't do anything.
}
uint albedo = ((src_process_voxels.data[index].albedo & 0x7FFF) << 1) | 1; //add solid bit
diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl
index 23f83b3b9c..3c685c25b9 100644
--- a/servers/rendering/renderer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl
@@ -35,11 +35,15 @@ void main() {
layout(location = 0) in vec2 uv_interp;
-#ifdef MULTIVIEW
+#ifdef SUBPASS
+layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color;
+#else
+#if MULTIVIEW
layout(set = 0, binding = 0) uniform sampler2DArray source_color;
#else
layout(set = 0, binding = 0) uniform sampler2D source_color;
#endif
+#endif
layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
layout(set = 2, binding = 0) uniform sampler2D source_glow;
#ifdef USE_1D_LUT
@@ -180,10 +184,6 @@ vec3 tonemap_aces(vec3 color, float white) {
}
vec3 tonemap_reinhard(vec3 color, float white) {
- // Ensure color values are positive.
- // They can be negative in the case of negative lights, which leads to undesired behavior.
- color = max(vec3(0.0), color);
-
return (white * color + color) / (color * white + white);
}
@@ -207,7 +207,7 @@ vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always o
return tonemap_reinhard(color, white);
} else if (params.tonemapper == TONEMAPPER_FILMIC) {
return tonemap_filmic(color, white);
- } else { //aces
+ } else { // TONEMAPPER_ACES
return tonemap_aces(color, white);
}
}
@@ -291,6 +291,7 @@ vec3 apply_color_correction(vec3 color) {
}
#endif
+#ifndef SUBPASS
vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
const float FXAA_REDUCE_MIN = (1.0 / 128.0);
const float FXAA_REDUCE_MUL = (1.0 / 8.0);
@@ -346,6 +347,7 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
return rgbB;
}
}
+#endif // !SUBPASS
// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
@@ -360,7 +362,10 @@ vec3 screen_space_dither(vec2 frag_coord) {
}
void main() {
-#ifdef MULTIVIEW
+#ifdef SUBPASS
+ // SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer
+ vec3 color = subpassLoad(input_color).rgb;
+#elif MULTIVIEW
vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb;
#else
vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb;
@@ -370,14 +375,16 @@ void main() {
float exposure = params.exposure;
+#ifndef SUBPASS
if (params.use_auto_exposure) {
exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey);
}
+#endif
color *= exposure;
// Early Tonemap & SRGB Conversion
-
+#ifndef SUBPASS
if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) {
vec3 glow = gather_glow(source_glow, uv_interp);
color.rgb = mix(color.rgb, glow, params.glow_intensity);
@@ -386,15 +393,21 @@ void main() {
if (params.use_fxaa) {
color = do_fxaa(color, exposure, uv_interp);
}
+#endif
+
if (params.use_debanding) {
// For best results, debanding should be done before tonemapping.
// Otherwise, we're adding noise to an already-quantized image.
color += screen_space_dither(gl_FragCoord.xy);
}
- color = apply_tonemapping(color, params.white);
+
+ // Ensure color values passed to tonemappers are positive.
+ // They can be negative in the case of negative lights, which leads to undesired behavior.
+ color = apply_tonemapping(max(vec3(0.0), color), params.white);
color = linear_to_srgb(color); // regular linear -> SRGB conversion
+#ifndef SUBPASS
// Glow
if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) {
@@ -406,6 +419,7 @@ void main() {
color = apply_glow(color, glow);
}
+#endif
// Additional effects