diff options
Diffstat (limited to 'servers/rendering/renderer_rd')
36 files changed, 1970 insertions, 765 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..47bb756d55 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -383,6 +383,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(©.push_constant, 0, sizeof(CopyPushConstant));  	uint32_t base_flags = 0; @@ -416,6 +418,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(©.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 +453,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 fragment 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(); @@ -736,6 +791,8 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone  }  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 +831,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 fragment 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 +1015,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 +1351,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++) { @@ -1464,7 +1628,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 +1675,21 @@ EffectsRD::EffectsRD() {  		copy.shader.initialize(copy_modes);  		memset(©.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)); +			}  		}  	}  	{ @@ -1551,7 +1754,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 +1781,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 +1803,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"); @@ -1974,13 +2196,18 @@ 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); +	} else { +		bokeh.shader.version_free(bokeh.shader_version); +		luminance_reduce.shader.version_free(luminance_reduce.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); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index 33d32f0c57..d072564c23 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -33,6 +33,7 @@  #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" @@ -41,6 +42,7 @@  #include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h"  #include "servers/rendering/renderer_rd/shaders/cubemap_roughness.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 +62,63 @@  #include "servers/rendering_server.h"  class EffectsRD { +	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, @@ -239,6 +298,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; @@ -656,6 +738,8 @@ class EffectsRD {  	RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false);  	RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2); +	bool prefer_raster_effects; +  public:  	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); @@ -666,12 +750,16 @@ 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 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; @@ -751,7 +839,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..ac20515c28 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -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 @@ -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);  	} @@ -1631,7 +1644,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 +1685,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 +1720,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 +1763,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 +1881,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 +1937,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 +2005,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 +2041,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 +2049,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 +2058,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 +2066,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 +2578,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 +2980,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 +3067,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..6682c5e9b0 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, @@ -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..333e87bdbd 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 @@ -287,7 +287,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 +305,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 +324,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 +408,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 +425,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 +485,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 +683,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 +712,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 +751,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..5f6d9465c7 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() { @@ -65,7 +93,7 @@ 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... +	RD::DataFormat color_format = RenderForwardMobile::singleton->_render_buffers_get_color_format();  	if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) {  		Vector<RID> fb; @@ -80,7 +108,7 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b  		} 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 @@ -131,6 +159,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()); @@ -853,13 +892,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 +960,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 +996,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 +1004,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 +1013,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 +1250,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; @@ -1392,6 +1480,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 +1567,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 +1577,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; @@ -1761,13 +1887,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 +1909,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 +1919,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 +1927,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,6 +2279,48 @@ 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; @@ -2185,6 +2356,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..973925d562 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 @@ -151,6 +172,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; @@ -213,11 +237,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 +532,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,6 +571,10 @@ 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:  	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 +617,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..18c1fe02a0 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -620,7 +620,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; @@ -2570,8 +2570,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..a7ee0dd141 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); @@ -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_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 46057bddab..2e0e7c3c43 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);  } @@ -654,12 +656,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());  		} @@ -709,6 +711,10 @@ 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; @@ -1229,6 +1235,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 +1311,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 +1383,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 +1416,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 +1472,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 +1525,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 +1833,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 +1862,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 +1907,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,6 +1985,8 @@ 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); @@ -2114,8 +2241,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,13 +2275,13 @@ 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);  		if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { -			tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; +			tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);  		} else {  			tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;  		} @@ -2179,6 +2314,14 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p  		rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());  	} +	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); +	} +  	rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa, p_view_count);  	if (is_clustered_enabled()) { @@ -2241,6 +2384,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 +2426,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 +2482,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 +2538,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 +2550,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 +2590,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 +2785,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 +2794,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 +2930,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 +2998,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 +3123,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 +3686,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; @@ -4029,11 +4098,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 +4139,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 +4431,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..bb06eb608f 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;  }; @@ -99,7 +100,7 @@ protected:  	};  	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); @@ -147,6 +148,25 @@ protected:  		}  	} +	//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;  	static RendererSceneRenderRD *singleton; @@ -188,9 +208,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 +222,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 +307,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 +369,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 +380,8 @@ private:  		Set<RID> shadow_atlases; //shadow atlases where this light is registered +		ForwardID forward_id = -1; +  		LightInstance() {}  	}; @@ -426,6 +450,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 +466,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 +481,10 @@ private:  		struct Luminance {  			Vector<RID> reduce;  			RID current; + +			// used only on mobile renderer +			Vector<RID> fb; +			RID current_fb;  		} luminance;  		struct SSAO { @@ -1005,14 +1039,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) { @@ -1049,17 +1078,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 +1120,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 +1145,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 +1155,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 +1211,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 +1230,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..bc1603a219 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -757,7 +757,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 +844,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); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 6738f499bd..d5c7db6fd2 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; @@ -4960,7 +4959,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; @@ -5886,6 +5885,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 +5902,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 +5944,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 +7535,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 +7551,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 +7574,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 +7604,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 +7925,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 +8410,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 +8581,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 +8594,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 +8804,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() { @@ -9373,7 +9390,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 +9540,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..b290c07705 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -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); @@ -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..1b9f54d1c8 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]"); @@ -148,8 +150,8 @@ void ShaderRD::_clear_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;  	} @@ -203,7 +205,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 +219,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 +237,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 +256,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 +277,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 +371,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 +395,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 +448,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 +462,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 +502,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..529328f0ed 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; 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/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..b3a349c948 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 */ @@ -450,12 +468,8 @@ layout(location = 0) out vec4 frag_color;  #include "scene_forward_lights_inc.glsl" -#ifdef USE_FORWARD_GI -  #include "scene_forward_gi_inc.glsl" -#endif //USE_FORWARD_GI -  #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)  #ifndef MODE_RENDER_DEPTH @@ -793,25 +807,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 +845,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 +859,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; +					}  				}  			}  		} @@ -963,9 +996,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 +1070,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 +1101,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 +1133,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 +1214,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 +1260,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 +1274,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; +						float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); -				} 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; +						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 +1380,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 +1522,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 +1543,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..7039ea2942 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; @@ -232,11 +217,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,  #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)); @@ -320,7 +301,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 +315,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 +327,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 +341,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 +361,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 +377,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 +423,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 +448,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 +485,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 +506,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 +532,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 +569,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 +608,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 +626,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 +688,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 +721,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 +741,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 +758,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 +772,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 +786,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 +832,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 +860,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 +904,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..70900a847c 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -370,6 +370,26 @@ void main() {  #VERSION_DEFINES +/* 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" @@ -961,7 +981,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 +1304,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..d9682d7b23 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl @@ -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; @@ -135,17 +138,12 @@ layout(set = 1, binding = 0, std140) uniform SceneData {  	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  |