Browse Source

Move clustered renderer functionality

Bastiaan Olij 4 years ago
parent
commit
dad40fa2df

+ 1 - 0
servers/rendering/renderer_rd/SCsub

@@ -4,4 +4,5 @@ Import("env")
 
 
 env.add_source_files(env.servers_sources, "*.cpp")
 env.add_source_files(env.servers_sources, "*.cpp")
 
 
+SConscript("forward_clustered/SCsub")
 SConscript("shaders/SCsub")
 SConscript("shaders/SCsub")

+ 5 - 0
servers/rendering/renderer_rd/forward_clustered/SCsub

@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")

File diff suppressed because it is too large
+ 75 - 565
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp


+ 19 - 172
servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h → servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h

@@ -1,5 +1,5 @@
 /*************************************************************************/
 /*************************************************************************/
-/*  renderer_scene_render_forward_clustered.h                            */
+/*  render_forward_clustered.h                                           */
 /*************************************************************************/
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
 /*                           GODOT ENGINE                                */
@@ -32,12 +32,17 @@
 #define RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
 #define RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
 
 
 #include "core/templates/paged_allocator.h"
 #include "core/templates/paged_allocator.h"
+#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
 #include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
 #include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
 #include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
 #include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
 #include "servers/rendering/renderer_rd/renderer_storage_rd.h"
 #include "servers/rendering/renderer_rd/renderer_storage_rd.h"
 #include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
 
 
-class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
+namespace RendererSceneRenderImplementation {
+
+class RenderForwardClustered : public RendererSceneRenderRD {
+	friend SceneShaderForwardClustered;
+
 	enum {
 	enum {
 		SCENE_UNIFORM_SET = 0,
 		SCENE_UNIFORM_SET = 0,
 		RENDER_PASS_UNIFORM_SET = 1,
 		RENDER_PASS_UNIFORM_SET = 1,
@@ -63,155 +68,11 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
 
 
 	/* Scene Shader */
 	/* Scene Shader */
 
 
-	enum ShaderVersion {
-		SHADER_VERSION_DEPTH_PASS,
-		SHADER_VERSION_DEPTH_PASS_DP,
-		SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
-		SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE,
-		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,
-		SHADER_VERSION_MAX
-	};
-
-	struct {
-		SceneForwardClusteredShaderRD scene_shader;
-		ShaderCompilerRD compiler;
-	} shader;
-
-	/* Material */
-
-	struct ShaderData : public RendererStorageRD::ShaderData {
-		enum BlendMode { //used internally
-			BLEND_MODE_MIX,
-			BLEND_MODE_ADD,
-			BLEND_MODE_SUB,
-			BLEND_MODE_MUL,
-			BLEND_MODE_ALPHA_TO_COVERAGE
-		};
-
-		enum DepthDraw {
-			DEPTH_DRAW_DISABLED,
-			DEPTH_DRAW_OPAQUE,
-			DEPTH_DRAW_ALWAYS
-		};
-
-		enum DepthTest {
-			DEPTH_TEST_DISABLED,
-			DEPTH_TEST_ENABLED
-		};
-
-		enum Cull {
-			CULL_DISABLED,
-			CULL_FRONT,
-			CULL_BACK
-		};
-
-		enum CullVariant {
-			CULL_VARIANT_NORMAL,
-			CULL_VARIANT_REVERSED,
-			CULL_VARIANT_DOUBLE_SIDED,
-			CULL_VARIANT_MAX
-
-		};
-
-		enum AlphaAntiAliasing {
-			ALPHA_ANTIALIASING_OFF,
-			ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
-			ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
-		};
-
-		bool valid;
-		RID version;
-		uint32_t vertex_input_mask;
-		PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
-
-		String path;
-
-		Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
-		Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
-
-		Vector<uint32_t> ubo_offsets;
-		uint32_t ubo_size;
-
-		String code;
-		Map<StringName, RID> default_texture_params;
-
-		DepthDraw depth_draw;
-		DepthTest depth_test;
-
-		bool uses_point_size;
-		bool uses_alpha;
-		bool uses_blend_alpha;
-		bool uses_alpha_clip;
-		bool uses_depth_pre_pass;
-		bool uses_discard;
-		bool uses_roughness;
-		bool uses_normal;
-
-		bool unshaded;
-		bool uses_vertex;
-		bool uses_sss;
-		bool uses_transmittance;
-		bool uses_screen_texture;
-		bool uses_depth_texture;
-		bool uses_normal_texture;
-		bool uses_time;
-		bool writes_modelview_or_projection;
-		bool uses_world_coordinates;
-
-		uint64_t last_pass = 0;
-		uint32_t index = 0;
-
-		virtual void set_code(const String &p_Code);
-		virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
-		virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
-		void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
-
-		virtual bool is_param_texture(const StringName &p_param) const;
-		virtual bool is_animated() const;
-		virtual bool casts_shadows() const;
-		virtual Variant get_default_parameter(const StringName &p_parameter) const;
-		virtual RS::ShaderNativeSourceCode get_native_source_code() const;
-
-		ShaderData();
-		virtual ~ShaderData();
-	};
-
-	RendererStorageRD::ShaderData *_create_shader_func();
-	static RendererStorageRD::ShaderData *_create_shader_funcs() {
-		return static_cast<RendererSceneRenderForwardClustered *>(singleton)->_create_shader_func();
-	}
-
-	struct MaterialData : public RendererStorageRD::MaterialData {
-		uint64_t last_frame;
-		ShaderData *shader_data;
-		RID uniform_buffer;
-		RID uniform_set;
-		Vector<RID> texture_cache;
-		Vector<uint8_t> ubo_data;
-		uint64_t last_pass = 0;
-		uint32_t index = 0;
-		RID next_pass;
-		uint8_t priority;
-		virtual void set_render_priority(int p_priority);
-		virtual void set_next_pass(RID p_pass);
-		virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
-		virtual ~MaterialData();
-	};
-
-	RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
-	static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
-		return static_cast<RendererSceneRenderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
-	}
+	SceneShaderForwardClustered scene_shader;
 
 
 	/* Framebuffer */
 	/* Framebuffer */
 
 
-	struct RenderBufferDataForward : public RenderBufferData {
+	struct RenderBufferDataForwardClustered : public RenderBufferData {
 		//for rendering, may be MSAAd
 		//for rendering, may be MSAAd
 
 
 		RID color;
 		RID color;
@@ -244,13 +105,12 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
 		void clear();
 		void clear();
 		virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa);
 		virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa);
 
 
-		~RenderBufferDataForward();
+		~RenderBufferDataForwardClustered();
 	};
 	};
 
 
 	virtual RenderBufferData *_create_render_buffer_data();
 	virtual RenderBufferData *_create_render_buffer_data();
-	void _allocate_normal_roughness_texture(RenderBufferDataForward *rb);
+	void _allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb);
 
 
-	RID shadow_sampler;
 	RID render_base_uniform_set;
 	RID render_base_uniform_set;
 	LocalVector<RID> render_pass_uniform_sets;
 	LocalVector<RID> render_pass_uniform_sets;
 	RID sdfgi_pass_uniform_set;
 	RID sdfgi_pass_uniform_set;
@@ -258,7 +118,7 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
 	uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
 	uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
 
 
 	virtual void _base_uniforms_changed();
 	virtual void _base_uniforms_changed();
-	void _render_buffers_clear_uniform_set(RenderBufferDataForward *rb);
+	void _render_buffers_clear_uniform_set(RenderBufferDataForwardClustered *rb);
 	virtual void _render_buffers_uniform_set_changed(RID p_render_buffers);
 	virtual void _render_buffers_uniform_set_changed(RID p_render_buffers);
 	virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
 	virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
 
 
@@ -488,19 +348,7 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
 
 
 	} scene_state;
 	} scene_state;
 
 
-	static RendererSceneRenderForwardClustered *singleton;
-
-	RID default_shader;
-	RID default_material;
-	RID overdraw_material_shader;
-	RID overdraw_material;
-	RID wireframe_material_shader;
-	RID wireframe_material;
-	RID default_shader_rd;
-	RID default_shader_sdfgi_rd;
-
-	RID default_vec4_xform_buffer;
-	RID default_vec4_xform_uniform_set;
+	static RenderForwardClustered *singleton;
 
 
 	void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
 	void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
 	void _setup_giprobes(const PagedArray<RID> &p_giprobes);
 	void _setup_giprobes(const PagedArray<RID> &p_giprobes);
@@ -578,11 +426,11 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
 
 
 		void *surface = nullptr;
 		void *surface = nullptr;
 		RID material_uniform_set;
 		RID material_uniform_set;
-		ShaderData *shader = nullptr;
+		SceneShaderForwardClustered::ShaderData *shader = nullptr;
 
 
 		void *surface_shadow = nullptr;
 		void *surface_shadow = nullptr;
 		RID material_uniform_set_shadow;
 		RID material_uniform_set_shadow;
-		ShaderData *shader_shadow = nullptr;
+		SceneShaderForwardClustered::ShaderData *shader_shadow = nullptr;
 
 
 		GeometryInstanceSurfaceDataCache *next = nullptr;
 		GeometryInstanceSurfaceDataCache *next = nullptr;
 		GeometryInstanceForwardClustered *owner = nullptr;
 		GeometryInstanceForwardClustered *owner = nullptr;
@@ -650,14 +498,12 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
 	PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
 	PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
 	PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
 	PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
 
 
-	void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
+	void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
 	void _geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
 	void _geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
 	void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance);
 	void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance);
 	void _geometry_instance_update(GeometryInstance *p_geometry_instance);
 	void _geometry_instance_update(GeometryInstance *p_geometry_instance);
 	void _update_dirty_geometry_instances();
 	void _update_dirty_geometry_instances();
 
 
-	bool low_end = false;
-
 	/* Render List */
 	/* Render List */
 
 
 	struct RenderList {
 	struct RenderList {
@@ -760,7 +606,8 @@ public:
 
 
 	virtual bool free(RID p_rid);
 	virtual bool free(RID p_rid);
 
 
-	RendererSceneRenderForwardClustered(RendererStorageRD *p_storage);
-	~RendererSceneRenderForwardClustered();
+	RenderForwardClustered(RendererStorageRD *p_storage);
+	~RenderForwardClustered();
 };
 };
+} // namespace RendererSceneRenderImplementation
 #endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
 #endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H

+ 807 - 0
servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp

@@ -0,0 +1,807 @@
+/*************************************************************************/
+/*  scene_shader_forward_clustered.cpp                                   */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "scene_shader_forward_clustered.h"
+#include "core/config/project_settings.h"
+#include "render_forward_clustered.h"
+
+using namespace RendererSceneRenderImplementation;
+
+void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
+	//compile
+
+	code = p_code;
+	valid = false;
+	ubo_size = 0;
+	uniforms.clear();
+	uses_screen_texture = false;
+
+	if (code == String()) {
+		return; //just invalid, but no error
+	}
+
+	ShaderCompilerRD::GeneratedCode gen_code;
+
+	int blend_mode = BLEND_MODE_MIX;
+	int depth_testi = DEPTH_TEST_ENABLED;
+	int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
+	int cull = CULL_BACK;
+
+	uses_point_size = false;
+	uses_alpha = false;
+	uses_blend_alpha = false;
+	uses_depth_pre_pass = false;
+	uses_discard = false;
+	uses_roughness = false;
+	uses_normal = false;
+	bool wireframe = false;
+
+	unshaded = false;
+	uses_vertex = false;
+	uses_sss = false;
+	uses_transmittance = false;
+	uses_screen_texture = false;
+	uses_depth_texture = false;
+	uses_normal_texture = false;
+	uses_time = false;
+	writes_modelview_or_projection = false;
+	uses_world_coordinates = false;
+
+	int depth_drawi = DEPTH_DRAW_OPAQUE;
+
+	ShaderCompilerRD::IdentifierActions actions;
+
+	actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
+	actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
+	actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
+	actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
+
+	actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
+	actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
+
+	actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
+	actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
+	actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
+
+	actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+
+	actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED);
+	actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT);
+	actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK);
+
+	actions.render_mode_flags["unshaded"] = &unshaded;
+	actions.render_mode_flags["wireframe"] = &wireframe;
+
+	actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
+	actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
+
+	actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
+	actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
+
+	actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+	actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
+	actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
+	actions.usage_flag_pointers["DISCARD"] = &uses_discard;
+	actions.usage_flag_pointers["TIME"] = &uses_time;
+	actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
+	actions.usage_flag_pointers["NORMAL"] = &uses_normal;
+	actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal;
+
+	actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
+	actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
+
+	actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
+	actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
+	actions.write_flag_pointers["VERTEX"] = &uses_vertex;
+
+	actions.uniforms = &uniforms;
+
+	SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+	Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
+
+	ERR_FAIL_COND(err != OK);
+
+	if (version.is_null()) {
+		version = shader_singleton->shader.version_create();
+	}
+
+	depth_draw = DepthDraw(depth_drawi);
+	depth_test = DepthTest(depth_testi);
+
+#if 0
+	print_line("**compiling shader:");
+	print_line("**defines:\n");
+	for (int i = 0; i < gen_code.defines.size(); i++) {
+		print_line(gen_code.defines[i]);
+	}
+	print_line("\n**uniforms:\n" + gen_code.uniforms);
+	print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
+	print_line("\n**vertex_code:\n" + gen_code.vertex);
+	print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
+	print_line("\n**fragment_code:\n" + gen_code.fragment);
+	print_line("\n**light_code:\n" + gen_code.light);
+#endif
+	shader_singleton->shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines);
+	ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
+
+	ubo_size = gen_code.uniform_total_size;
+	ubo_offsets = gen_code.uniform_offsets;
+	texture_uniforms = gen_code.texture_uniforms;
+
+	//blend modes
+
+	// if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
+	if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
+		blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
+	}
+
+	RD::PipelineColorBlendState::Attachment blend_attachment;
+
+	switch (blend_mode) {
+		case BLEND_MODE_MIX: {
+			blend_attachment.enable_blend = true;
+			blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+			blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+			blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+			blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+			blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+		} break;
+		case BLEND_MODE_ADD: {
+			blend_attachment.enable_blend = true;
+			blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+			blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+			blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+			blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+			uses_blend_alpha = true; //force alpha used because of blend
+
+		} break;
+		case BLEND_MODE_SUB: {
+			blend_attachment.enable_blend = true;
+			blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
+			blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
+			blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+			blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+			uses_blend_alpha = true; //force alpha used because of blend
+
+		} break;
+		case BLEND_MODE_MUL: {
+			blend_attachment.enable_blend = true;
+			blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+			blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+			blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
+			blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
+			blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
+			blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+			uses_blend_alpha = true; //force alpha used because of blend
+		} break;
+		case BLEND_MODE_ALPHA_TO_COVERAGE: {
+			blend_attachment.enable_blend = true;
+			blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+			blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+			blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+			blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+			blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+			blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+		}
+	}
+
+	RD::PipelineColorBlendState blend_state_blend;
+	blend_state_blend.attachments.push_back(blend_attachment);
+	RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1);
+	RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2);
+	RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
+	RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
+
+	//update pipelines
+
+	RD::PipelineDepthStencilState depth_stencil_state;
+
+	if (depth_test != DEPTH_TEST_DISABLED) {
+		depth_stencil_state.enable_depth_test = true;
+		depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+		depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
+	}
+
+	for (int i = 0; i < CULL_VARIANT_MAX; i++) {
+		RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
+			{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
+			{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
+			{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
+		};
+
+		RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
+
+		for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
+			RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
+				RD::RENDER_PRIMITIVE_POINTS,
+				RD::RENDER_PRIMITIVE_LINES,
+				RD::RENDER_PRIMITIVE_LINESTRIPS,
+				RD::RENDER_PRIMITIVE_TRIANGLES,
+				RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
+			};
+
+			RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
+
+			for (int k = 0; k < SHADER_VERSION_MAX; k++) {
+				if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(k)) {
+					continue;
+				}
+				RD::PipelineRasterizationState raster_state;
+				raster_state.cull_mode = cull_mode_rd;
+				raster_state.wireframe = wireframe;
+
+				RD::PipelineColorBlendState blend_state;
+				RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
+				RD::PipelineMultisampleState multisample_state;
+
+				if (uses_alpha || uses_blend_alpha) {
+					// only allow these flags to go through if we have some form of msaa
+					if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
+						multisample_state.enable_alpha_to_coverage = true;
+					} else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
+						multisample_state.enable_alpha_to_coverage = true;
+						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) {
+						blend_state = blend_state_blend;
+						if (depth_draw == DEPTH_DRAW_OPAQUE) {
+							depth_stencil.enable_depth_write = false; //alpha does not draw depth
+						}
+					} else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
+						if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+							//none, blend state contains nothing
+						} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+							blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+						} else {
+							blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
+						}
+					} else {
+						pipelines[i][j][k].clear();
+						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) {
+						blend_state = blend_state_opaque;
+					} else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+						//none, leave empty
+					} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
+						blend_state = blend_state_depth_normal_roughness;
+					} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) {
+						blend_state = blend_state_depth_normal_roughness_giprobe;
+					} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+						blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+					} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) {
+						blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
+					} else {
+						//specular write
+						blend_state = blend_state_opaque_specular;
+						depth_stencil.enable_depth_test = false;
+						depth_stencil.enable_depth_write = false;
+					}
+				}
+
+				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);
+			}
+		}
+	}
+
+	valid = true;
+}
+
+void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+	if (!p_texture.is_valid()) {
+		default_texture_params.erase(p_name);
+	} else {
+		default_texture_params[p_name] = p_texture;
+	}
+}
+
+void SceneShaderForwardClustered::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+	Map<int, StringName> order;
+
+	for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+		if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+			continue;
+		}
+
+		if (E->get().texture_order >= 0) {
+			order[E->get().texture_order + 100000] = E->key();
+		} else {
+			order[E->get().order] = E->key();
+		}
+	}
+
+	for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+		PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+		pi.name = E->get();
+		p_param_list->push_back(pi);
+	}
+}
+
+void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
+	for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+		if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+			continue;
+		}
+
+		RendererStorage::InstanceShaderParam p;
+		p.info = ShaderLanguage::uniform_to_property_info(E->get());
+		p.info.name = E->key(); //supply name
+		p.index = E->get().instance_index;
+		p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+		p_param_list->push_back(p);
+	}
+}
+
+bool SceneShaderForwardClustered::ShaderData::is_param_texture(const StringName &p_param) const {
+	if (!uniforms.has(p_param)) {
+		return false;
+	}
+
+	return uniforms[p_param].texture_order >= 0;
+}
+
+bool SceneShaderForwardClustered::ShaderData::is_animated() const {
+	return false;
+}
+
+bool SceneShaderForwardClustered::ShaderData::casts_shadows() const {
+	return false;
+}
+
+Variant SceneShaderForwardClustered::ShaderData::get_default_parameter(const StringName &p_parameter) const {
+	if (uniforms.has(p_parameter)) {
+		ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+		Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+		return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+	}
+	return Variant();
+}
+
+RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const {
+	SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+
+	return shader_singleton->shader.version_get_native_source_code(version);
+}
+
+SceneShaderForwardClustered::ShaderData::ShaderData() {
+	valid = false;
+	uses_screen_texture = false;
+}
+
+SceneShaderForwardClustered::ShaderData::~ShaderData() {
+	SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+	ERR_FAIL_COND(!shader_singleton);
+	//pipeline variants will clear themselves if shader is gone
+	if (version.is_valid()) {
+		shader_singleton->shader.version_free(version);
+	}
+}
+
+RendererStorageRD::ShaderData *SceneShaderForwardClustered::_create_shader_func() {
+	ShaderData *shader_data = memnew(ShaderData);
+	return shader_data;
+}
+
+void SceneShaderForwardClustered::MaterialData::set_render_priority(int p_priority) {
+	priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
+}
+
+void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
+	next_pass = p_pass;
+}
+
+void SceneShaderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+	SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+
+	if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
+		p_uniform_dirty = true;
+		if (uniform_buffer.is_valid()) {
+			RD::get_singleton()->free(uniform_buffer);
+			uniform_buffer = RID();
+		}
+
+		ubo_data.resize(shader_data->ubo_size);
+		if (ubo_data.size()) {
+			uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+			memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
+		}
+
+		//clear previous uniform set
+		if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+			RD::get_singleton()->free(uniform_set);
+			uniform_set = RID();
+		}
+	}
+
+	//check whether buffer changed
+	if (p_uniform_dirty && ubo_data.size()) {
+		update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
+		RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER);
+	}
+
+	uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+
+	if ((uint32_t)texture_cache.size() != tex_uniform_count) {
+		texture_cache.resize(tex_uniform_count);
+		p_textures_dirty = true;
+
+		//clear previous uniform set
+		if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+			RD::get_singleton()->free(uniform_set);
+			uniform_set = RID();
+		}
+	}
+
+	if (p_textures_dirty && tex_uniform_count) {
+		update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
+	}
+
+	if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
+		// This material does not require an uniform set, so don't create it.
+		return;
+	}
+
+	if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+		//no reason to update uniform set, only UBO (or nothing) was needed to update
+		return;
+	}
+
+	Vector<RD::Uniform> uniforms;
+
+	{
+		if (shader_data->ubo_size) {
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+			u.binding = 0;
+			u.ids.push_back(uniform_buffer);
+			uniforms.push_back(u);
+		}
+
+		const RID *textures = texture_cache.ptrw();
+		for (uint32_t i = 0; i < tex_uniform_count; i++) {
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+			u.binding = 1 + i;
+			u.ids.push_back(textures[i]);
+			uniforms.push_back(u);
+		}
+	}
+
+	uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET);
+}
+
+SceneShaderForwardClustered::MaterialData::~MaterialData() {
+	if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+		RD::get_singleton()->free(uniform_set);
+	}
+
+	if (uniform_buffer.is_valid()) {
+		RD::get_singleton()->free(uniform_buffer);
+	}
+}
+
+RendererStorageRD::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) {
+	MaterialData *material_data = memnew(MaterialData);
+	material_data->shader_data = p_shader;
+	material_data->last_frame = false;
+	//update will happen later anyway so do nothing.
+	return material_data;
+}
+
+SceneShaderForwardClustered *SceneShaderForwardClustered::singleton = nullptr;
+
+SceneShaderForwardClustered::SceneShaderForwardClustered() {
+	// there should be only one of these, contained within our RenderFM singleton.
+	singleton = this;
+}
+
+SceneShaderForwardClustered::~SceneShaderForwardClustered() {
+	RD::get_singleton()->free(default_vec4_xform_buffer);
+	RD::get_singleton()->free(shadow_sampler);
+
+	storage->free(wireframe_material_shader);
+	storage->free(overdraw_material_shader);
+	storage->free(default_shader);
+
+	storage->free(wireframe_material);
+	storage->free(overdraw_material);
+	storage->free(default_material);
+}
+
+void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const String p_defines, bool p_is_low_end) {
+	storage = p_storage;
+
+	{
+		Vector<String> shader_versions;
+		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
+		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
+		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n");
+		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n");
+		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
+		shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n");
+		shader_versions.push_back("");
+		shader_versions.push_back("\n#define USE_FORWARD_GI\n");
+		shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
+		shader_versions.push_back("\n#define USE_LIGHTMAP\n");
+		shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n");
+		shader.initialize(shader_versions, p_defines);
+
+		if (p_is_low_end) {
+			//disable the high end versions
+			shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false);
+			shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false);
+			shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false);
+			shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false);
+			shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
+			shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
+		}
+	}
+
+	storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
+	storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs);
+
+	{
+		//shader compiler
+		ShaderCompilerRD::DefaultIdentifierActions actions;
+
+		actions.renames["WORLD_MATRIX"] = "world_matrix";
+		actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix";
+		actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix";
+		actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix";
+		actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
+		actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix";
+		actions.renames["MODELVIEW_MATRIX"] = "modelview";
+		actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
+
+		actions.renames["VERTEX"] = "vertex";
+		actions.renames["NORMAL"] = "normal";
+		actions.renames["TANGENT"] = "tangent";
+		actions.renames["BINORMAL"] = "binormal";
+		actions.renames["POSITION"] = "position";
+		actions.renames["UV"] = "uv_interp";
+		actions.renames["UV2"] = "uv2_interp";
+		actions.renames["COLOR"] = "color_interp";
+		actions.renames["POINT_SIZE"] = "gl_PointSize";
+		actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
+
+		actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
+		actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
+		actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
+		actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
+
+		//builtins
+
+		actions.renames["TIME"] = "scene_data.time";
+		actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
+
+		actions.renames["FRAGCOORD"] = "gl_FragCoord";
+		actions.renames["FRONT_FACING"] = "gl_FrontFacing";
+		actions.renames["NORMAL_MAP"] = "normal_map";
+		actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
+		actions.renames["ALBEDO"] = "albedo";
+		actions.renames["ALPHA"] = "alpha";
+		actions.renames["METALLIC"] = "metallic";
+		actions.renames["SPECULAR"] = "specular";
+		actions.renames["ROUGHNESS"] = "roughness";
+		actions.renames["RIM"] = "rim";
+		actions.renames["RIM_TINT"] = "rim_tint";
+		actions.renames["CLEARCOAT"] = "clearcoat";
+		actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
+		actions.renames["ANISOTROPY"] = "anisotropy";
+		actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+		actions.renames["SSS_STRENGTH"] = "sss_strength";
+		actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
+		actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
+		actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve";
+		actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
+		actions.renames["BACKLIGHT"] = "backlight";
+		actions.renames["AO"] = "ao";
+		actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+		actions.renames["EMISSION"] = "emission";
+		actions.renames["POINT_COORD"] = "gl_PointCoord";
+		actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+		actions.renames["SCREEN_UV"] = "screen_uv";
+		actions.renames["SCREEN_TEXTURE"] = "color_buffer";
+		actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
+		actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
+		actions.renames["DEPTH"] = "gl_FragDepth";
+		actions.renames["OUTPUT_IS_SRGB"] = "true";
+		actions.renames["FOG"] = "custom_fog";
+		actions.renames["RADIANCE"] = "custom_radiance";
+		actions.renames["IRRADIANCE"] = "custom_irradiance";
+		actions.renames["BONE_INDICES"] = "bone_attrib";
+		actions.renames["BONE_WEIGHTS"] = "weight_attrib";
+		actions.renames["CUSTOM0"] = "custom0_attrib";
+		actions.renames["CUSTOM1"] = "custom1_attrib";
+		actions.renames["CUSTOM2"] = "custom2_attrib";
+		actions.renames["CUSTOM3"] = "custom3_attrib";
+
+		//for light
+		actions.renames["VIEW"] = "view";
+		actions.renames["LIGHT_COLOR"] = "light_color";
+		actions.renames["LIGHT"] = "light";
+		actions.renames["ATTENUATION"] = "attenuation";
+		actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation";
+		actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
+		actions.renames["SPECULAR_LIGHT"] = "specular_light";
+
+		actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+		actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
+		actions.usage_defines["BINORMAL"] = "@TANGENT";
+		actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
+		actions.usage_defines["RIM_TINT"] = "@RIM";
+		actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
+		actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
+		actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
+		actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+		actions.usage_defines["AO"] = "#define AO_USED\n";
+		actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
+		actions.usage_defines["UV"] = "#define UV_USED\n";
+		actions.usage_defines["UV2"] = "#define UV2_USED\n";
+		actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
+		actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
+		actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
+		actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
+		actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
+		actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
+		actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
+		actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
+		actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+		actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+		actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+		actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
+		actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
+		actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
+		actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
+
+		actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+		actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
+		actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
+		actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+		actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+		actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+		actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+
+		actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
+		actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
+		actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
+
+		actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+		actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+		actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+		actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
+		actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+
+		bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
+
+		if (!force_lambert) {
+			actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+		}
+
+		actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
+		actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
+		actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
+
+		actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
+
+		bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx");
+
+		if (!force_blinn) {
+			actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+		} else {
+			actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
+		}
+
+		actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
+		actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
+		actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+		actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+		actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+		actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+		actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+		actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+
+		actions.sampler_array_name = "material_samplers";
+		actions.base_texture_binding_index = 1;
+		actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
+		actions.base_uniform_string = "material.";
+		actions.base_varying_index = 10;
+
+		actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+		actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+		actions.global_buffer_array_variable = "global_variables.data";
+		actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+
+		compiler.initialize(actions);
+	}
+
+	{
+		//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");
+		default_material = storage->material_allocate();
+		storage->material_initialize(default_material);
+		storage->material_set_shader(default_material, default_shader);
+
+		MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
+		default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
+		if (!p_is_low_end) {
+			default_shader_sdfgi_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF);
+		}
+	}
+
+	{
+		overdraw_material_shader = storage->shader_allocate();
+		storage->shader_initialize(overdraw_material_shader);
+		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.2; }");
+		overdraw_material = storage->material_allocate();
+		storage->material_initialize(overdraw_material);
+		storage->material_set_shader(overdraw_material, overdraw_material_shader);
+
+		wireframe_material_shader = storage->shader_allocate();
+		storage->shader_initialize(wireframe_material_shader);
+		storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }");
+		wireframe_material = storage->material_allocate();
+		storage->material_initialize(wireframe_material);
+		storage->material_set_shader(wireframe_material, wireframe_material_shader);
+	}
+
+	{
+		default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
+		Vector<RD::Uniform> uniforms;
+		RD::Uniform u;
+		u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+		u.ids.push_back(default_vec4_xform_buffer);
+		u.binding = 0;
+		uniforms.push_back(u);
+
+		default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RenderForwardClustered::TRANSFORMS_UNIFORM_SET);
+	}
+	{
+		RD::SamplerState sampler;
+		sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+		sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
+		sampler.enable_compare = true;
+		sampler.compare_op = RD::COMPARE_OP_LESS;
+		shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+	}
+}

+ 210 - 0
servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h

@@ -0,0 +1,210 @@
+/*************************************************************************/
+/*  scene_shader_forward_clustered.h                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef RSSR_SCENE_SHADER_FC_H
+#define RSSR_SCENE_SHADER_FC_H
+
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
+
+namespace RendererSceneRenderImplementation {
+
+class SceneShaderForwardClustered {
+private:
+	static SceneShaderForwardClustered *singleton;
+
+public:
+	RendererStorageRD *storage;
+
+	enum ShaderVersion {
+		SHADER_VERSION_DEPTH_PASS,
+		SHADER_VERSION_DEPTH_PASS_DP,
+		SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
+		SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE,
+		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,
+		SHADER_VERSION_MAX
+	};
+
+	struct ShaderData : public RendererStorageRD::ShaderData {
+		enum BlendMode { //used internally
+			BLEND_MODE_MIX,
+			BLEND_MODE_ADD,
+			BLEND_MODE_SUB,
+			BLEND_MODE_MUL,
+			BLEND_MODE_ALPHA_TO_COVERAGE
+		};
+
+		enum DepthDraw {
+			DEPTH_DRAW_DISABLED,
+			DEPTH_DRAW_OPAQUE,
+			DEPTH_DRAW_ALWAYS
+		};
+
+		enum DepthTest {
+			DEPTH_TEST_DISABLED,
+			DEPTH_TEST_ENABLED
+		};
+
+		enum Cull {
+			CULL_DISABLED,
+			CULL_FRONT,
+			CULL_BACK
+		};
+
+		enum CullVariant {
+			CULL_VARIANT_NORMAL,
+			CULL_VARIANT_REVERSED,
+			CULL_VARIANT_DOUBLE_SIDED,
+			CULL_VARIANT_MAX
+
+		};
+
+		enum AlphaAntiAliasing {
+			ALPHA_ANTIALIASING_OFF,
+			ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
+			ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
+		};
+
+		bool valid;
+		RID version;
+		uint32_t vertex_input_mask;
+		PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
+
+		String path;
+
+		Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+		Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+		Vector<uint32_t> ubo_offsets;
+		uint32_t ubo_size;
+
+		String code;
+		Map<StringName, RID> default_texture_params;
+
+		DepthDraw depth_draw;
+		DepthTest depth_test;
+
+		bool uses_point_size;
+		bool uses_alpha;
+		bool uses_blend_alpha;
+		bool uses_alpha_clip;
+		bool uses_depth_pre_pass;
+		bool uses_discard;
+		bool uses_roughness;
+		bool uses_normal;
+
+		bool unshaded;
+		bool uses_vertex;
+		bool uses_sss;
+		bool uses_transmittance;
+		bool uses_screen_texture;
+		bool uses_depth_texture;
+		bool uses_normal_texture;
+		bool uses_time;
+		bool writes_modelview_or_projection;
+		bool uses_world_coordinates;
+
+		uint64_t last_pass = 0;
+		uint32_t index = 0;
+
+		virtual void set_code(const String &p_Code);
+		virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+		virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+		void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
+
+		virtual bool is_param_texture(const StringName &p_param) const;
+		virtual bool is_animated() const;
+		virtual bool casts_shadows() const;
+		virtual Variant get_default_parameter(const StringName &p_parameter) const;
+		virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+
+		ShaderData();
+		virtual ~ShaderData();
+	};
+
+	RendererStorageRD::ShaderData *_create_shader_func();
+	static RendererStorageRD::ShaderData *_create_shader_funcs() {
+		return static_cast<SceneShaderForwardClustered *>(singleton)->_create_shader_func();
+	}
+
+	struct MaterialData : public RendererStorageRD::MaterialData {
+		uint64_t last_frame;
+		ShaderData *shader_data;
+		RID uniform_buffer;
+		RID uniform_set;
+		Vector<RID> texture_cache;
+		Vector<uint8_t> ubo_data;
+		uint64_t last_pass = 0;
+		uint32_t index = 0;
+		RID next_pass;
+		uint8_t priority;
+		virtual void set_render_priority(int p_priority);
+		virtual void set_next_pass(RID p_pass);
+		virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+		virtual ~MaterialData();
+	};
+
+	RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
+	static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
+		return static_cast<SceneShaderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+	}
+
+	SceneForwardClusteredShaderRD shader;
+	ShaderCompilerRD compiler;
+
+	RID default_shader;
+	RID default_material;
+	RID overdraw_material_shader;
+	RID overdraw_material;
+	RID wireframe_material_shader;
+	RID wireframe_material;
+	RID default_shader_rd;
+	RID default_shader_sdfgi_rd;
+
+	RID default_vec4_xform_buffer;
+	RID default_vec4_xform_uniform_set;
+
+	RID shadow_sampler;
+
+	SceneShaderForwardClustered();
+	~SceneShaderForwardClustered();
+
+	void init(RendererStorageRD *p_storage, const String p_defines, bool p_is_low_end);
+};
+
+} // namespace RendererSceneRenderImplementation
+#endif // !RSSR_SCENE_SHADER_FM_H

+ 1 - 1
servers/rendering/renderer_rd/renderer_compositor_rd.cpp

@@ -175,5 +175,5 @@ RendererCompositorRD::RendererCompositorRD() {
 
 
 	storage = memnew(RendererStorageRD);
 	storage = memnew(RendererStorageRD);
 	canvas = memnew(RendererCanvasRenderRD(storage));
 	canvas = memnew(RendererCanvasRenderRD(storage));
-	scene = memnew(RendererSceneRenderForwardClustered(storage));
+	scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
 }
 }

+ 1 - 1
servers/rendering/renderer_rd/renderer_compositor_rd.h

@@ -34,8 +34,8 @@
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/templates/thread_work_pool.h"
 #include "core/templates/thread_work_pool.h"
 #include "servers/rendering/renderer_compositor.h"
 #include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h"
 #include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h"
 #include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h"
-#include "servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h"
 #include "servers/rendering/renderer_rd/renderer_storage_rd.h"
 #include "servers/rendering/renderer_rd/renderer_storage_rd.h"
 
 
 class RendererCompositorRD : public RendererCompositor {
 class RendererCompositorRD : public RendererCompositor {

+ 11 - 10
servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp

@@ -2992,6 +2992,7 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
 		}
 		}
 	}
 	}
 	default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES);
 	default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES);
+	half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution");
 }
 }
 
 
 void RendererSceneGIRD::free() {
 void RendererSceneGIRD::free() {
@@ -3097,10 +3098,10 @@ void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_
 	}
 	}
 
 
 	if (giprobes_changed) {
 	if (giprobes_changed) {
-		if (RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) {
-			RD::get_singleton()->free(rb->gi_uniform_set);
+		if (RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) {
+			RD::get_singleton()->free(rb->gi.uniform_set);
 		}
 		}
-		rb->gi_uniform_set = RID();
+		rb->gi.uniform_set = RID();
 		if (rb->volumetric_fog) {
 		if (rb->volumetric_fog) {
 			if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
 			if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
 				RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
 				RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
@@ -3125,7 +3126,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
 	ERR_FAIL_COND(rb == nullptr);
 	ERR_FAIL_COND(rb == nullptr);
 	RendererSceneEnvironmentRD *env = p_scene_render->environment_owner.getornull(p_environment);
 	RendererSceneEnvironmentRD *env = p_scene_render->environment_owner.getornull(p_environment);
 
 
-	if (rb->ambient_buffer.is_null() || rb->using_half_size_gi != half_resolution) {
+	if (rb->ambient_buffer.is_null() || rb->gi.using_half_size_gi != half_resolution) {
 		if (rb->ambient_buffer.is_valid()) {
 		if (rb->ambient_buffer.is_valid()) {
 			RD::get_singleton()->free(rb->ambient_buffer);
 			RD::get_singleton()->free(rb->ambient_buffer);
 			RD::get_singleton()->free(rb->reflection_buffer);
 			RD::get_singleton()->free(rb->reflection_buffer);
@@ -3142,7 +3143,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
 		tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
 		tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
 		rb->reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
 		rb->reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
 		rb->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
 		rb->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
-		rb->using_half_size_gi = half_resolution;
+		rb->gi.using_half_size_gi = half_resolution;
 
 
 		p_scene_render->_render_buffers_uniform_set_changed(p_render_buffers);
 		p_scene_render->_render_buffers_uniform_set_changed(p_render_buffers);
 	}
 	}
@@ -3187,7 +3188,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
 	push_constant.cam_rotation[10] = p_transform.basis[2][2];
 	push_constant.cam_rotation[10] = p_transform.basis[2][2];
 	push_constant.cam_rotation[11] = 0;
 	push_constant.cam_rotation[11] = 0;
 
 
-	if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) {
+	if (rb->gi.uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) {
 		Vector<RD::Uniform> uniforms;
 		Vector<RD::Uniform> uniforms;
 		{
 		{
 			RD::Uniform u;
 			RD::Uniform u;
@@ -3340,22 +3341,22 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
 			uniforms.push_back(u);
 			uniforms.push_back(u);
 		}
 		}
 
 
-		rb->gi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0);
+		rb->gi.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0);
 	}
 	}
 
 
 	Mode mode;
 	Mode mode;
 
 
-	if (rb->using_half_size_gi) {
+	if (rb->gi.using_half_size_gi) {
 		mode = (use_sdfgi && use_giprobes) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_GIPROBE);
 		mode = (use_sdfgi && use_giprobes) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_GIPROBE);
 	} else {
 	} else {
 		mode = (use_sdfgi && use_giprobes) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_GIPROBE);
 		mode = (use_sdfgi && use_giprobes) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_GIPROBE);
 	}
 	}
 	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
 	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
 	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]);
 	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]);
-	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi_uniform_set, 0);
+	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi.uniform_set, 0);
 	RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
 	RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
 
 
-	if (rb->using_half_size_gi) {
+	if (rb->gi.using_half_size_gi) {
 		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1);
 		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1);
 	} else {
 	} else {
 		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1);
 		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1);

+ 3 - 0
servers/rendering/renderer_rd/renderer_scene_gi_rd.h

@@ -561,6 +561,9 @@ public:
 		RID full_buffer;
 		RID full_buffer;
 		RID full_dispatch;
 		RID full_dispatch;
 		RID full_mask;
 		RID full_mask;
+
+		RID uniform_set;
+		bool using_half_size_gi = false;
 	};
 	};
 
 
 	struct SDFGIData {
 	struct SDFGIData {

+ 47 - 18
servers/rendering/renderer_rd/renderer_scene_render_rd.cpp

@@ -522,9 +522,13 @@ RID RendererSceneRenderRD::reflection_atlas_create() {
 	ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count");
 	ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count");
 	ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size");
 	ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size");
 
 
-	ra.cluster_builder = memnew(ClusterBuilderRD);
-	ra.cluster_builder->set_shared(&cluster_builder_shared);
-	ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID());
+	if (is_clustered_enabled()) {
+		ra.cluster_builder = memnew(ClusterBuilderRD);
+		ra.cluster_builder->set_shared(&cluster_builder_shared);
+		ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID());
+	} else {
+		ra.cluster_builder = nullptr;
+	}
 
 
 	return reflection_atlas_owner.make_rid(ra);
 	return reflection_atlas_owner.make_rid(ra);
 }
 }
@@ -537,7 +541,10 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref
 		return; //no changes
 		return; //no changes
 	}
 	}
 
 
-	ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID());
+	if (ra->cluster_builder) {
+		// only if we're using our cluster
+		ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID());
+	}
 
 
 	ra->size = p_reflection_size;
 	ra->size = p_reflection_size;
 	ra->count = p_reflection_count;
 	ra->count = p_reflection_count;
@@ -2124,10 +2131,13 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
 	rb->msaa = p_msaa;
 	rb->msaa = p_msaa;
 	rb->screen_space_aa = p_screen_space_aa;
 	rb->screen_space_aa = p_screen_space_aa;
 	rb->use_debanding = p_use_debanding;
 	rb->use_debanding = p_use_debanding;
-	if (rb->cluster_builder == nullptr) {
-		rb->cluster_builder = memnew(ClusterBuilderRD);
+
+	if (is_clustered_enabled()) {
+		if (rb->cluster_builder == nullptr) {
+			rb->cluster_builder = memnew(ClusterBuilderRD);
+		}
+		rb->cluster_builder->set_shared(&cluster_builder_shared);
 	}
 	}
-	rb->cluster_builder->set_shared(&cluster_builder_shared);
 
 
 	_free_render_buffer_data(rb);
 	_free_render_buffer_data(rb);
 
 
@@ -2170,7 +2180,9 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
 	rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa);
 	rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa);
 	_render_buffers_uniform_set_changed(p_render_buffers);
 	_render_buffers_uniform_set_changed(p_render_buffers);
 
 
-	rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
+	if (is_clustered_enabled()) {
+		rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
+	}
 }
 }
 
 
 void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) {
 void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) {
@@ -2943,6 +2955,7 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
 }
 }
 
 
 void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) {
 void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) {
+	ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered
 	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
 	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
 	ERR_FAIL_COND(!rb);
 	ERR_FAIL_COND(!rb);
 	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
 	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
@@ -3505,7 +3518,9 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
 				break;
 				break;
 			}
 			}
 		}
 		}
-		_update_volumetric_fog(render_state.render_buffers, render_state.environment, render_state.cam_projection, render_state.cam_transform, render_state.shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count);
+		if (is_volumetric_supported()) {
+			_update_volumetric_fog(render_state.render_buffers, render_state.environment, render_state.cam_projection, render_state.cam_transform, render_state.shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count);
+		}
 	}
 	}
 }
 }
 
 
@@ -3578,8 +3593,8 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
 	}
 	}
 
 
 	if (render_buffers_owner.owns(render_state.render_buffers)) {
 	if (render_buffers_owner.owns(render_state.render_buffers)) {
-		RenderBuffers *rs_rb = render_buffers_owner.getornull(render_state.render_buffers);
-		current_cluster_builder = rs_rb->cluster_builder;
+		// render_state.render_buffers == p_render_buffers so we can use our already retrieved rb
+		current_cluster_builder = rb->cluster_builder;
 	} else if (reflection_probe_instance_owner.owns(render_state.reflection_probe)) {
 	} else if (reflection_probe_instance_owner.owns(render_state.reflection_probe)) {
 		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_state.reflection_probe);
 		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_state.reflection_probe);
 		ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas);
 		ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas);
@@ -3590,7 +3605,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
 			current_cluster_builder = ra->cluster_builder;
 			current_cluster_builder = ra->cluster_builder;
 		}
 		}
 	} else {
 	} else {
-		ERR_PRINT("No cluster builder, bug"); //should never happen, will crash
+		ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash
 		current_cluster_builder = nullptr;
 		current_cluster_builder = nullptr;
 	}
 	}
 
 
@@ -4077,7 +4092,23 @@ int RendererSceneRenderRD::get_max_directional_lights() const {
 }
 }
 
 
 bool RendererSceneRenderRD::is_low_end() const {
 bool RendererSceneRenderRD::is_low_end() const {
-	return low_end;
+	// by default we switch this on this (may be ignored in some implementations)
+	return GLOBAL_GET("rendering/driver/rd_renderer/use_low_end_renderer");
+}
+
+bool RendererSceneRenderRD::is_dynamic_gi_supported() const {
+	// usable by default (unless low end = true)
+	return true;
+}
+
+bool RendererSceneRenderRD::is_clustered_enabled() const {
+	// used by default.
+	return true;
+}
+
+bool RendererSceneRenderRD::is_volumetric_supported() const {
+	// usable by default (unless low end = true)
+	return true;
 }
 }
 
 
 RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
 RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
@@ -4091,7 +4122,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
 
 
 	uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
 	uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
 
 
-	low_end = GLOBAL_GET("rendering/driver/rd_renderer/use_low_end_renderer");
+	low_end = is_low_end();
 
 
 	if (textures_per_stage < 48) {
 	if (textures_per_stage < 48) {
 		low_end = true;
 		low_end = true;
@@ -4103,7 +4134,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
 
 
 	/* GI */
 	/* GI */
 
 
-	if (!low_end) {
+	if (!low_end && is_dynamic_gi_supported()) {
 		gi.init(storage, &sky);
 		gi.init(storage, &sky);
 	}
 	}
 
 
@@ -4141,7 +4172,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
 		cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
 		cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
 	}
 	}
 
 
-	if (!low_end) {
+	if (!low_end && is_volumetric_supported()) {
 		String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
 		String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
 		Vector<String> volumetric_fog_modes;
 		Vector<String> volumetric_fog_modes;
 		volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
 		volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
@@ -4188,8 +4219,6 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
 	environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter"));
 	environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter"));
 
 
 	cull_argument.set_page_pool(&cull_argument_pool);
 	cull_argument.set_page_pool(&cull_argument_pool);
-
-	gi.half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution");
 }
 }
 
 
 RendererSceneRenderRD::~RendererSceneRenderRD() {
 RendererSceneRenderRD::~RendererSceneRenderRD() {

+ 7 - 6
servers/rendering/renderer_rd/renderer_scene_render_rd.h

@@ -51,6 +51,7 @@ protected:
 	RendererStorageRD *storage;
 	RendererStorageRD *storage;
 	double time;
 	double time;
 	double time_step = 0;
 	double time_step = 0;
+	bool low_end = false; // If true GI and Volumetric fog are disabled
 
 
 	struct RenderBufferData {
 	struct RenderBufferData {
 		virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0;
 		virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0;
@@ -383,9 +384,9 @@ private:
 		RID texture; //main texture for rendering to, must be filled after done rendering
 		RID texture; //main texture for rendering to, must be filled after done rendering
 		RID depth_texture; //main depth texture
 		RID depth_texture; //main depth texture
 
 
-		RID gi_uniform_set;
 		RendererSceneGIRD::SDFGI *sdfgi = nullptr;
 		RendererSceneGIRD::SDFGI *sdfgi = nullptr;
 		VolumetricFog *volumetric_fog = nullptr;
 		VolumetricFog *volumetric_fog = nullptr;
+		RendererSceneGIRD::RenderBuffersGI gi;
 
 
 		ClusterBuilderRD *cluster_builder = nullptr;
 		ClusterBuilderRD *cluster_builder = nullptr;
 
 
@@ -428,9 +429,6 @@ private:
 
 
 		RID ambient_buffer;
 		RID ambient_buffer;
 		RID reflection_buffer;
 		RID reflection_buffer;
-		bool using_half_size_gi = false;
-
-		RendererSceneGIRD::RenderBuffersGI gi;
 	};
 	};
 
 
 	/* GI */
 	/* GI */
@@ -719,7 +717,6 @@ private:
 	*/
 	*/
 
 
 	uint32_t max_cluster_elements = 512;
 	uint32_t max_cluster_elements = 512;
-	bool low_end = false;
 
 
 	void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true);
 	void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true);
 
 
@@ -1193,7 +1190,11 @@ public:
 
 
 	void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir);
 	void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir);
 
 
-	bool is_low_end() const;
+	virtual bool is_low_end() const;
+
+	virtual bool is_dynamic_gi_supported() const;
+	virtual bool is_clustered_enabled() const;
+	virtual bool is_volumetric_supported() const;
 
 
 	RendererSceneRenderRD(RendererStorageRD *p_storage);
 	RendererSceneRenderRD(RendererStorageRD *p_storage);
 	~RendererSceneRenderRD();
 	~RendererSceneRenderRD();

Some files were not shown because too many files changed in this diff