diff options
63 files changed, 6810 insertions, 6235 deletions
diff --git a/core/io/json.cpp b/core/io/json.cpp index bc4527869b..0d9117fdda 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -234,6 +234,52 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to  								}  								index += 4; //will add at the end anyway +								if ((res & 0xfffffc00) == 0xd800) { +									if (p_str[index + 1] != '\\' || p_str[index + 2] != 'u') { +										r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate"; +										return ERR_PARSE_ERROR; +									} +									index += 2; +									char32_t trail = 0; +									for (int j = 0; j < 4; j++) { +										char32_t c = p_str[index + j + 1]; +										if (c == 0) { +											r_err_str = "Unterminated String"; +											return ERR_PARSE_ERROR; +										} +										if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) { +											r_err_str = "Malformed hex constant in string"; +											return ERR_PARSE_ERROR; +										} +										char32_t v; +										if (c >= '0' && c <= '9') { +											v = c - '0'; +										} else if (c >= 'a' && c <= 'f') { +											v = c - 'a'; +											v += 10; +										} else if (c >= 'A' && c <= 'F') { +											v = c - 'A'; +											v += 10; +										} else { +											ERR_PRINT("Bug parsing hex constant."); +											v = 0; +										} + +										trail <<= 4; +										trail |= v; +									} +									if ((trail & 0xfffffc00) == 0xdc00) { +										res = (res << 10UL) + trail - ((0xd800 << 10UL) + 0xdc00 - 0x10000); +										index += 4; //will add at the end anyway +									} else { +										r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate"; +										return ERR_PARSE_ERROR; +									} +								} else if ((res & 0xfffffc00) == 0xdc00) { +									r_err_str = "Invalid UTF-16 sequence in string, unpaired trail surrogate"; +									return ERR_PARSE_ERROR; +								} +  							} break;  							default: {  								res = next; diff --git a/core/io/logger.cpp b/core/io/logger.cpp index bd0285a7a9..8a07459a1d 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -43,6 +43,12 @@ bool Logger::should_log(bool p_err) {  	return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled);  } +bool Logger::_flush_stdout_on_print = true; + +void Logger::set_flush_stdout_on_print(bool value) { +	_flush_stdout_on_print = value; +} +  void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) {  	if (!should_log(true)) {  		return; @@ -207,7 +213,7 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {  			Memory::free_static(buf);  		} -		if (p_err || !ProjectSettings::get_singleton() || GLOBAL_GET("application/run/flush_stdout_on_print")) { +		if (p_err || _flush_stdout_on_print) {  			// Don't always flush when printing stdout to avoid performance  			// issues when `print()` is spammed in release builds.  			file->flush(); @@ -228,7 +234,7 @@ void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) {  		vfprintf(stderr, p_format, p_list);  	} else {  		vprintf(p_format, p_list); -		if (!ProjectSettings::get_singleton() || GLOBAL_GET("application/run/flush_stdout_on_print")) { +		if (_flush_stdout_on_print) {  			// Don't always flush when printing stdout to avoid performance  			// issues when `print()` is spammed in release builds.  			fflush(stdout); diff --git a/core/io/logger.h b/core/io/logger.h index b8e615b436..a12945911c 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -41,6 +41,8 @@ class Logger {  protected:  	bool should_log(bool p_err); +	static bool _flush_stdout_on_print; +  public:  	enum ErrorType {  		ERR_ERROR, @@ -49,6 +51,8 @@ public:  		ERR_SHADER  	}; +	static void set_flush_stdout_on_print(bool value); +  	virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0;  	virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); diff --git a/core/math/color.cpp b/core/math/color.cpp index e1b45cac9c..8affb07e8c 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -452,56 +452,9 @@ String Color::to_html(bool p_alpha) const {  }  Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const { -	p_h = Math::fmod(p_h * 360.0f, 360.0f); -	if (p_h < 0.0) { -		p_h += 360.0f; -	} - -	const float h_ = p_h / 60.0f; -	const float c = p_v * p_s; -	const float x = c * (1.0f - Math::abs(Math::fmod(h_, 2.0f) - 1.0f)); -	float r, g, b; - -	switch ((int)h_) { -		case 0: { -			r = c; -			g = x; -			b = 0; -		} break; -		case 1: { -			r = x; -			g = c; -			b = 0; -		} break; -		case 2: { -			r = 0; -			g = c; -			b = x; -		} break; -		case 3: { -			r = 0; -			g = x; -			b = c; -		} break; -		case 4: { -			r = x; -			g = 0; -			b = c; -		} break; -		case 5: { -			r = c; -			g = 0; -			b = x; -		} break; -		default: { -			r = 0; -			g = 0; -			b = 0; -		} break; -	} - -	const float m = p_v - c; -	return Color(m + r, m + g, m + b, p_a); +	Color c; +	c.set_hsv(p_h, p_s, p_v, p_a); +	return c;  }  Color::operator String() const { diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml index f137ede90f..b69768d33f 100644 --- a/doc/classes/Callable.xml +++ b/doc/classes/Callable.xml @@ -8,26 +8,26 @@  		[b]Example:[/b]  		[codeblocks]  		[gdscript] -		var callable = Callable(self, "print_args")  		func print_args(arg1, arg2, arg3 = ""):  		    prints(arg1, arg2, arg3)  		func test(): -		    callable.call("hello", "world")  # Prints "hello world". +		    var callable = Callable(self, "print_args") +		    callable.call("hello", "world")  # Prints "hello world ".  		    callable.call(Vector2.UP, 42, callable)  # Prints "(0, -1) 42 Node(Node.gd)::print_args".  		    callable.call("invalid")  # Invalid call, should have at least 2 arguments.  		[/gdscript]  		[csharp] -		Callable callable = new Callable(this, "print_args"); -		public void PrintArgs(object arg1, object arg2, object arg3 = "") +		public void PrintArgs(object arg1, object arg2, object arg3 = null)  		{  		    GD.PrintS(arg1, arg2, arg3);  		}  		public void Test()  		{ -		    callable.Call("hello", "world"); // Prints "hello world". -		    callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.gd)::print_args". +		    Callable callable = new Callable(this, nameof(PrintArgs)); +		    callable.Call("hello", "world"); // Prints "hello world null". +		    callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs".  		    callable.Call("invalid"); // Invalid call, should have at least 2 arguments.  		}  		[/csharp] @@ -67,6 +67,7 @@  			<return type="Callable">  			</return>  			<description> +				Returns a copy of this [Callable] with the arguments bound. Bound arguments are passed after the arguments supplied by [method call].  			</description>  		</method>  		<method name="call" qualifiers="vararg"> @@ -108,24 +109,28 @@  			<return type="int">  			</return>  			<description> +				Returns the hash value of this [Callable]'s object.  			</description>  		</method>  		<method name="is_custom">  			<return type="bool">  			</return>  			<description> +				Returns [code]true[/code] if this [Callable] is a custom callable whose behavior differs based on implementation details. Custom callables are used in the engine for various reasons. If [code]true[/code], you can't use [method get_method].  			</description>  		</method>  		<method name="is_null">  			<return type="bool">  			</return>  			<description> +				Returns [code]true[/code] if this [Callable] has no target to call the method on.  			</description>  		</method>  		<method name="is_standard">  			<return type="bool">  			</return>  			<description> +				Returns [code]true[/code] if this [Callable] is a standard callable, referencing an object and a method using a [StringName].  			</description>  		</method>  		<method name="operator !=" qualifiers="operator"> @@ -134,6 +139,7 @@  			<argument index="0" name="right" type="Callable">  			</argument>  			<description> +				Returns [code]true[/code] if both [Callable]s invoke different targets.  			</description>  		</method>  		<method name="operator ==" qualifiers="operator"> @@ -142,6 +148,7 @@  			<argument index="0" name="right" type="Callable">  			</argument>  			<description> +				Returns [code]true[/code] if both [Callable]s invoke the same custom target.  			</description>  		</method>  		<method name="unbind"> @@ -150,6 +157,7 @@  			<argument index="0" name="argcount" type="int">  			</argument>  			<description> +				Returns a copy of this [Callable] with the arguments unbound. Calling the returned [Callable] will call the method without the extra arguments that are supplied in the [Callable] on which you are calling this method.  			</description>  		</method>  	</methods> diff --git a/doc/classes/Curve2D.xml b/doc/classes/Curve2D.xml index 2d50d98a74..b33f3b4ffc 100644 --- a/doc/classes/Curve2D.xml +++ b/doc/classes/Curve2D.xml @@ -63,7 +63,7 @@  			<argument index="0" name="to_point" type="Vector2">  			</argument>  			<description> -				Returns the closest point (in curve's local space) to [code]to_point[/code]. +				Returns the closest baked point (in curve's local space) to [code]to_point[/code].  				[code]to_point[/code] must be in this curve's local space.  			</description>  		</method> diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml index bda04f010b..fcd150ad57 100644 --- a/doc/classes/Curve3D.xml +++ b/doc/classes/Curve3D.xml @@ -78,7 +78,7 @@  			<argument index="0" name="to_point" type="Vector3">  			</argument>  			<description> -				Returns the closest point (in curve's local space) to [code]to_point[/code]. +				Returns the closest baked point (in curve's local space) to [code]to_point[/code].  				[code]to_point[/code] must be in this curve's local space.  			</description>  		</method> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index b68ca2ac67..a1e5e60b4a 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -273,9 +273,11 @@  			If [code]true[/code], flushes the standard output stream every time a line is printed. This affects both terminal logging and file logging.  			When running a project, this setting must be enabled if you want logs to be collected by service managers such as systemd/journalctl. This setting is disabled by default on release builds, since flushing on every printed line will negatively affect performance if lots of lines are printed in a rapid succession. Also, if this setting is enabled, logged files will still be written successfully if the application crashes or is otherwise killed by the user (without being closed "normally").  			[b]Note:[/b] Regardless of this setting, the standard error stream ([code]stderr[/code]) is always flushed when a line is printed to it. +			Changes to this setting will only be applied upon restarting the application.  		</member>  		<member name="application/run/flush_stdout_on_print.debug" type="bool" setter="" getter="" default="true">  			Debug build override for [member application/run/flush_stdout_on_print], as performance is less important during debugging. +			Changes to this setting will only be applied upon restarting the application.  		</member>  		<member name="application/run/frame_delay_msec" type="int" setter="" getter="" default="0">  			Forces a delay between frames in the main loop (in milliseconds). This may be useful if you plan to disable vertical synchronization. diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml index c56596423d..83235f0991 100644 --- a/doc/classes/Sprite2D.xml +++ b/doc/classes/Sprite2D.xml @@ -60,7 +60,7 @@  			If [code]true[/code], texture is cut from a larger atlas texture. See [member region_rect].  		</member>  		<member name="region_filter_clip" type="bool" setter="set_region_filter_clip" getter="is_region_filter_clip_enabled" default="false"> -			If [code]true[/code], the outermost pixels get blurred out. +			If [code]true[/code], the outermost pixels get blurred out. [member region_enabled] must be [code]true[/code].  		</member>  		<member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2( 0, 0, 0, 0 )">  			The region of the atlas texture to display. [member region_enabled] must be [code]true[/code]. diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml index 13ea7df294..d66ae210ec 100644 --- a/doc/classes/StyleBoxFlat.xml +++ b/doc/classes/StyleBoxFlat.xml @@ -4,12 +4,12 @@  		Customizable [StyleBox] with a given set of parameters (no texture required).  	</brief_description>  	<description> -		This [StyleBox] can be used to achieve all kinds of looks without the need of a texture. Those properties are customizable: +		This [StyleBox] can be used to achieve all kinds of looks without the need of a texture. The following properties are customizable:  		- Color  		- Border width (individual width for each border)  		- Rounded corners (individual radius for each corner)  		- Shadow (with blur and offset) -		Setting corner radius to high values is allowed. As soon as corners would overlap, the stylebox will switch to a relative system. Example: +		Setting corner radius to high values is allowed. As soon as corners overlap, the stylebox will switch to a relative system. Example:  		[codeblock]  		height = 30  		corner_radius_top_left = 50 @@ -178,8 +178,8 @@  			Border width for the top border.  		</member>  		<member name="corner_detail" type="int" setter="set_corner_detail" getter="get_corner_detail" default="8"> -			This sets the amount of vertices used for each corner. Higher values result in rounder corners but take more processing power to compute. When choosing a value, you should take the corner radius ([method set_corner_radius_all]) into account. -			For corner radii smaller than 10, [code]4[/code] or [code]5[/code] should be enough. For corner radii smaller than 30, values between [code]8[/code] and [code]12[/code] should be enough. +			This sets the number of vertices used for each corner. Higher values result in rounder corners but take more processing power to compute. When choosing a value, you should take the corner radius ([method set_corner_radius_all]) into account. +			For corner radii less than 10, [code]4[/code] or [code]5[/code] should be enough. For corner radii less than 30, values between [code]8[/code] and [code]12[/code] should be enough.  			A corner detail of [code]1[/code] will result in chamfered corners instead of rounded corners, which is useful for some artistic effects.  		</member>  		<member name="corner_radius_bottom_left" type="int" setter="set_corner_radius" getter="get_corner_radius" default="0"> diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index a9ed1bc2b9..711072f4b2 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -170,6 +170,7 @@ void CreateDialog::_update_search() {  	root->set_text(0, base_type);  	root->set_icon(0, search_options->get_theme_icon(icon_fallback, "EditorIcons"));  	search_options_types[base_type] = root; +	_configure_search_option_item(root, base_type, ClassDB::class_exists(base_type));  	const String search_text = search_box->get_text();  	bool empty_search = search_text == ""; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 28926d18c2..82ebf48242 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1021,6 +1021,32 @@ void CanvasItemEditor::_selection_menu_hide() {  	selection_menu->set_size(Vector2(0, 0));  } +void CanvasItemEditor::_add_node_pressed(int p_result) { +	if (p_result == AddNodeOption::ADD_NODE) { +		editor->get_scene_tree_dock()->open_add_child_dialog(); +	} else if (p_result == AddNodeOption::ADD_INSTANCE) { +		editor->get_scene_tree_dock()->open_instance_child_dialog(); +	} +} + +void CanvasItemEditor::_node_created(Node *p_node) { +	if (node_create_position == Point2()) { +		return; +	} + +	CanvasItem *c = Object::cast_to<CanvasItem>(p_node); +	if (c) { +		Transform2D xform = c->get_global_transform_with_canvas().affine_inverse() * c->get_transform(); +		c->_edit_set_position(xform.xform(node_create_position)); +	} + +	call_deferred("_reset_create_position"); // Defer the call in case more than one node is added. +} + +void CanvasItemEditor::_reset_create_position() { +	node_create_position = Point2(); +} +  bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) {  	Ref<InputEventMouseButton> b = p_event;  	Ref<InputEventMouseMotion> m = p_event; @@ -2463,6 +2489,14 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {  			}  		} +		if (b.is_valid() && b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && b->get_control()) { +			add_node_menu->set_position(get_global_transform().xform(get_local_mouse_position())); +			add_node_menu->set_size(Vector2(1, 1)); +			add_node_menu->popup(); +			node_create_position = transform.affine_inverse().xform((get_local_mouse_position())); +			return true; +		} +  		if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {  			// Single item selection  			Point2 click = transform.affine_inverse().xform(b->get_position()); @@ -5364,6 +5398,7 @@ void CanvasItemEditor::_bind_methods() {  	ClassDB::bind_method("_unhandled_key_input", &CanvasItemEditor::_unhandled_key_input);  	ClassDB::bind_method("_queue_update_bone_list", &CanvasItemEditor::_update_bone_list);  	ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list); +	ClassDB::bind_method("_reset_create_position", &CanvasItemEditor::_reset_create_position);  	ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);  	ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport); @@ -5685,6 +5720,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {  	editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::update));  	editor_selection->connect("selection_changed", callable_mp(this, &CanvasItemEditor::_selection_changed)); +	editor->get_scene_tree_dock()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created)); +	editor->get_scene_tree_dock()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position)); +  	editor->call_deferred("connect", "play_pressed", Callable(this, "_update_override_camera_button"), make_binds(true));  	editor->call_deferred("connect", "stop_pressed", Callable(this, "_update_override_camera_button"), make_binds(false)); @@ -6106,6 +6144,12 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {  	selection_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_selection_result_pressed));  	selection_menu->connect("popup_hide", callable_mp(this, &CanvasItemEditor::_selection_menu_hide)); +	add_node_menu = memnew(PopupMenu); +	add_child(add_node_menu); +	add_node_menu->add_icon_item(editor->get_scene_tree_dock()->get_theme_icon("Add", "EditorIcons"), TTR("Add Node Here")); +	add_node_menu->add_icon_item(editor->get_scene_tree_dock()->get_theme_icon("Instance", "EditorIcons"), TTR("Instance Scene Here")); +	add_node_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_add_node_pressed)); +  	multiply_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/multiply_grid_step", TTR("Multiply grid step by 2"), KEY_KP_MULTIPLY);  	divide_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/divide_grid_step", TTR("Divide grid step by 2"), KEY_KP_DIVIDE);  	pan_view_shortcut = ED_SHORTCUT("canvas_item_editor/pan_view", TTR("Pan View"), KEY_SPACE); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 24149a57b0..62a9b1e162 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -79,6 +79,11 @@ public:  		TOOL_MAX  	}; +	enum AddNodeOption { +		ADD_NODE, +		ADD_INSTANCE, +	}; +  private:  	EditorNode *editor; @@ -284,6 +289,7 @@ private:  	bool ruler_tool_active;  	Point2 ruler_tool_origin; +	Point2 node_create_position;  	MenuOption last_option; @@ -376,6 +382,7 @@ private:  	Button *key_auto_insert_button;  	PopupMenu *selection_menu; +	PopupMenu *add_node_menu;  	Control *top_ruler;  	Control *left_ruler; @@ -436,6 +443,9 @@ private:  	void _snap_changed();  	void _selection_result_pressed(int);  	void _selection_menu_hide(); +	void _add_node_pressed(int p_result); +	void _node_created(Node *p_node); +	void _reset_create_position();  	UndoRedo *undo_redo;  	bool _build_bones_list(Node *p_node); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index bb6cc50a31..9643881f96 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -4713,7 +4713,7 @@ Dictionary Node3DEditor::get_state() const {  			continue;  		}  		int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i)); -		String name = gizmo_plugins_by_name[i]->get_name(); +		String name = gizmo_plugins_by_name[i]->get_gizmo_name();  		gizmos_status[name] = state;  	} @@ -4839,7 +4839,7 @@ void Node3DEditor::set_state(const Dictionary &p_state) {  			}  			int state = EditorNode3DGizmoPlugin::VISIBLE;  			for (int i = 0; i < keys.size(); i++) { -				if (gizmo_plugins_by_name.write[j]->get_name() == String(keys[i])) { +				if (gizmo_plugins_by_name.write[j]->get_gizmo_name() == String(keys[i])) {  					state = gizmos_status[keys[i]];  					break;  				} @@ -5750,7 +5750,7 @@ void Node3DEditor::_update_gizmos_menu() {  		if (!gizmo_plugins_by_name[i]->can_be_hidden()) {  			continue;  		} -		String plugin_name = gizmo_plugins_by_name[i]->get_name(); +		String plugin_name = gizmo_plugins_by_name[i]->get_gizmo_name();  		const int plugin_state = gizmo_plugins_by_name[i]->get_state();  		gizmos_menu->add_multistate_item(plugin_name, 3, plugin_state, i);  		const int idx = gizmos_menu->get_item_index(i); @@ -7252,7 +7252,7 @@ void Node3DEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) {  struct _GizmoPluginPriorityComparator {  	bool operator()(const Ref<EditorNode3DGizmoPlugin> &p_a, const Ref<EditorNode3DGizmoPlugin> &p_b) const {  		if (p_a->get_priority() == p_b->get_priority()) { -			return p_a->get_name() < p_b->get_name(); +			return p_a->get_gizmo_name() < p_b->get_gizmo_name();  		}  		return p_a->get_priority() > p_b->get_priority();  	} @@ -7260,7 +7260,7 @@ struct _GizmoPluginPriorityComparator {  struct _GizmoPluginNameComparator {  	bool operator()(const Ref<EditorNode3DGizmoPlugin> &p_a, const Ref<EditorNode3DGizmoPlugin> &p_b) const { -		return p_a->get_name() < p_b->get_name(); +		return p_a->get_gizmo_name() < p_b->get_gizmo_name();  	}  }; @@ -7471,7 +7471,7 @@ void EditorNode3DGizmoPlugin::_bind_methods() {  	ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorNode3DGizmoPlugin::get_material, DEFVAL(Ref<EditorNode3DGizmo>())); -	BIND_VMETHOD(MethodInfo(Variant::STRING, "get_name")); +	BIND_VMETHOD(MethodInfo(Variant::STRING, "get_gizmo_name"));  	BIND_VMETHOD(MethodInfo(Variant::INT, "get_priority"));  	BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_be_hidden"));  	BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_selectable_when_hidden")); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 6a16aa28a9..74b01b3c36 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -40,9 +40,12 @@  void TileMapEditor::_node_removed(Node *p_node) {  	if (p_node == node && node) { -		// Fixes #44824, which describes a situation where you can reselect a TileMap node without first de-selecting it when switching scenes. -		node->disconnect("settings_changed", callable_mp(this, &TileMapEditor::_tileset_settings_changed)); +		Callable callable_tileset_settings_changed = callable_mp(this, &TileMapEditor::_tileset_settings_changed); +		if (node->is_connected("settings_changed", callable_tileset_settings_changed)) { +			// Fixes #44824, which describes a situation where you can reselect a TileMap node without first de-selecting it when switching scenes. +			node->disconnect("settings_changed", callable_tileset_settings_changed); +		}  		node = nullptr;  	}  } @@ -1870,7 +1873,11 @@ void TileMapEditor::edit(Node *p_tile_map) {  	}  	if (node) { -		node->disconnect("settings_changed", callable_mp(this, &TileMapEditor::_tileset_settings_changed)); +		Callable callable_tileset_settings_changed = callable_mp(this, &TileMapEditor::_tileset_settings_changed); + +		if (node->is_connected("settings_changed", callable_tileset_settings_changed)) { +			node->disconnect("settings_changed", callable_tileset_settings_changed); +		}  	}  	if (p_tile_map) {  		node = Object::cast_to<TileMap>(p_tile_map); @@ -1897,7 +1904,11 @@ void TileMapEditor::edit(Node *p_tile_map) {  	}  	if (node) { -		node->connect("settings_changed", callable_mp(this, &TileMapEditor::_tileset_settings_changed)); +		Callable callable_tileset_settings_changed = callable_mp(this, &TileMapEditor::_tileset_settings_changed); + +		if (!node->is_connected("settings_changed", callable_tileset_settings_changed)) { +			node->connect("settings_changed", callable_tileset_settings_changed); +		}  	}  	_clear_bucket_cache(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 58589467a8..16a0576af4 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -219,6 +219,9 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node  	editor_data->get_undo_redo().commit_action();  	editor->push_item(instances[instances.size() - 1]); +	for (int i = 0; i < instances.size(); i++) { +		emit_signal("node_created", instances[i]); +	}  }  void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) { @@ -347,6 +350,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {  				break;  			} +			if (reset_create_dialog) { +				create_dialog->set_base_type("Node"); +				reset_create_dialog = false; +			} +  			// Prefer nodes that inherit from the current scene root.  			Node *current_edited_scene_root = EditorNode::get_singleton()->get_edited_scene();  			if (current_edited_scene_root) { @@ -367,6 +375,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {  			}  			create_dialog->popup_create(true); +			if (!p_confirm_override) { +				emit_signal("add_node_used"); +			}  		} break;  		case TOOL_INSTANCE: {  			if (!profile_allow_editing) { @@ -381,7 +392,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {  			quick_open->popup_dialog("PackedScene", true);  			quick_open->set_title(TTR("Instance Child Scene")); - +			if (!p_confirm_override) { +				emit_signal("add_node_used"); +			}  		} break;  		case TOOL_EXPAND_COLLAPSE: {  			if (!scene_tree->get_selected()) { @@ -2101,6 +2114,8 @@ void SceneTreeDock::_do_create(Node *p_parent) {  		}  		ct->set_size(ms);  	} + +	emit_signal("node_created", c);  }  void SceneTreeDock::_create() { @@ -2321,10 +2336,14 @@ void SceneTreeDock::_new_scene_from(String p_file) {  	Node *base = selection.front()->get(); -	Map<Node *, Node *> reown; -	reown[editor_data->get_edited_scene_root()] = base; -	Node *copy = base->duplicate_and_reown(reown); +	Map<const Node *, Node *> duplimap; +	Node *copy = base->duplicate_from_editor(duplimap); +  	if (copy) { +		for (int i = 0; i < copy->get_child_count(); i++) { +			_set_node_owner_recursive(copy->get_child(i), copy); +		} +  		Ref<PackedScene> sdata = memnew(PackedScene);  		Error err = sdata->pack(copy);  		memdelete(copy); @@ -2354,6 +2373,16 @@ void SceneTreeDock::_new_scene_from(String p_file) {  	}  } +void SceneTreeDock::_set_node_owner_recursive(Node *p_node, Node *p_owner) { +	if (!p_node->get_owner()) { +		p_node->set_owner(p_owner); +	} + +	for (int i = 0; i < p_node->get_child_count(); i++) { +		_set_node_owner_recursive(p_node->get_child(i), p_owner); +	} +} +  static bool _is_node_visible(Node *p_node) {  	if (!p_node->get_owner()) {  		return false; @@ -2776,6 +2805,16 @@ void SceneTreeDock::open_script_dialog(Node *p_for_node, bool p_extend) {  	}  } +void SceneTreeDock::open_add_child_dialog() { +	create_dialog->set_base_type("CanvasItem"); +	_tool_selected(TOOL_NEW, true); +	reset_create_dialog = true; +} + +void SceneTreeDock::open_instance_child_dialog() { +	_tool_selected(TOOL_INSTANCE, true); +} +  void SceneTreeDock::add_remote_tree_editor(Control *p_remote) {  	ERR_FAIL_COND(remote_tree != nullptr);  	add_child(p_remote); @@ -2975,6 +3014,8 @@ void SceneTreeDock::_bind_methods() {  	ClassDB::bind_method(D_METHOD("replace_node"), &SceneTreeDock::replace_node);  	ADD_SIGNAL(MethodInfo("remote_tree_selected")); +	ADD_SIGNAL(MethodInfo("add_node_used")); +	ADD_SIGNAL(MethodInfo("node_created", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));  }  SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data) { diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 3779b61c60..aa62c93cb5 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -100,6 +100,7 @@ class SceneTreeDock : public VBoxContainer {  	Vector<ObjectID> subresources;  	bool restore_script_editor_on_drag; +	bool reset_create_dialog = false;  	int current_option;  	CreateDialog *create_dialog; @@ -203,6 +204,7 @@ class SceneTreeDock : public VBoxContainer {  	void _import_subscene();  	void _new_scene_from(String p_file); +	void _set_node_owner_recursive(Node *p_node, Node *p_owner);  	bool _validate_no_foreign();  	bool _validate_no_instance(); @@ -273,6 +275,9 @@ public:  	void attach_script_to_selected(bool p_extend);  	void open_script_dialog(Node *p_for_node, bool p_extend); +	void open_add_child_dialog(); +	void open_instance_child_dialog(); +  	ScriptCreateDialog *get_script_create_dialog() { return script_create_dialog; }  	SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data); diff --git a/main/main.cpp b/main/main.cpp index e9b06f6b07..884caab1e9 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -538,8 +538,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph  	// Only flush stdout in debug builds by default, as spamming `print()` will  	// decrease performance if this is enabled. -	GLOBAL_DEF("application/run/flush_stdout_on_print", false); -	GLOBAL_DEF("application/run/flush_stdout_on_print.debug", true); +	GLOBAL_DEF_RST("application/run/flush_stdout_on_print", false); +	GLOBAL_DEF_RST("application/run/flush_stdout_on_print.debug", true);  	GLOBAL_DEF("debug/settings/crash_handler/message",  			String("Please include this when reporting the bug on https://github.com/godotengine/godot/issues")); @@ -1174,6 +1174,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph  		_print_line_enabled = false;  	} +	Logger::set_flush_stdout_on_print(ProjectSettings::get_singleton()->get("application/run/flush_stdout_on_print")); +  	OS::get_singleton()->set_cmdline(execpath, main_args);  	GLOBAL_DEF("rendering/driver/driver_name", "Vulkan"); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index b17971cf93..a9975c8602 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2261,10 +2261,9 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c  					}  					r_arghint = _make_arguments_hint(info, p_argidx); -					return;  				} -				if (ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node") && p_argidx == 0) { +				if (p_argidx == 0 && ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node")) {  					// Get autoloads  					List<PropertyInfo> props;  					ProjectSettings::get_singleton()->get_property_list(&props); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index a77fb14064..08645d371c 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -2080,6 +2080,17 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_unary_operator(ExpressionN  	return operation;  } +GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_not_in_operator(ExpressionNode *p_previous_operand, bool p_can_assign) { +	// check that NOT is followed by IN by consuming it before calling parse_binary_operator which will only receive a plain IN +	consume(GDScriptTokenizer::Token::IN, R"(Expected "in" after "not" in content-test operator.)"); +	ExpressionNode *in_operation = parse_binary_operator(p_previous_operand, p_can_assign); +	UnaryOpNode *operation = alloc_node<UnaryOpNode>(); +	operation->operation = UnaryOpNode::OP_LOGIC_NOT; +	operation->variant_op = Variant::OP_NOT; +	operation->operand = in_operation; +	return operation; +} +  GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(ExpressionNode *p_previous_operand, bool p_can_assign) {  	GDScriptTokenizer::Token op = previous;  	BinaryOpNode *operation = alloc_node<BinaryOpNode>(); @@ -2906,7 +2917,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty  		// Logical  		{ nullptr,                                          &GDScriptParser::parse_binary_operator,      	PREC_LOGIC_AND }, // AND,  		{ nullptr,                                          &GDScriptParser::parse_binary_operator,      	PREC_LOGIC_OR }, // OR, -		{ &GDScriptParser::parse_unary_operator,         	nullptr,                                        PREC_NONE }, // NOT, +		{ &GDScriptParser::parse_unary_operator,         	&GDScriptParser::parse_binary_not_in_operator,	PREC_CONTENT_TEST }, // NOT,  		{ nullptr,                                          &GDScriptParser::parse_binary_operator,			PREC_LOGIC_AND }, // AMPERSAND_AMPERSAND,  		{ nullptr,                                          &GDScriptParser::parse_binary_operator,			PREC_LOGIC_OR }, // PIPE_PIPE,  		{ &GDScriptParser::parse_unary_operator,			nullptr,                                        PREC_NONE }, // BANG, @@ -3157,11 +3168,16 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node  				push_error(R"(Cannot use "@export" annotation with variable without type or initializer, since type can't be inferred.)", p_annotation);  				return false;  			} -			if (variable->initializer->type != Node::LITERAL) { +			if (variable->initializer->type == Node::LITERAL) { +				variable->export_info.type = static_cast<LiteralNode *>(variable->initializer)->value.get_type(); +			} else if (variable->initializer->type == Node::ARRAY) { +				variable->export_info.type = Variant::ARRAY; +			} else if (variable->initializer->type == Node::DICTIONARY) { +				variable->export_info.type = Variant::DICTIONARY; +			} else {  				push_error(R"(To use "@export" annotation with type-less variable, the default value must be a literal.)", p_annotation);  				return false;  			} -			variable->export_info.type = static_cast<LiteralNode *>(variable->initializer)->value.get_type();  		} // else: Actual type will be set by the analyzer, which can infer the proper type.  	} diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index d59b68b602..a4b1d4c866 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1285,6 +1285,7 @@ private:  	ExpressionNode *parse_builtin_constant(ExpressionNode *p_previous_operand, bool p_can_assign);  	ExpressionNode *parse_unary_operator(ExpressionNode *p_previous_operand, bool p_can_assign);  	ExpressionNode *parse_binary_operator(ExpressionNode *p_previous_operand, bool p_can_assign); +	ExpressionNode *parse_binary_not_in_operator(ExpressionNode *p_previous_operand, bool p_can_assign);  	ExpressionNode *parse_ternary_operator(ExpressionNode *p_previous_operand, bool p_can_assign);  	ExpressionNode *parse_assignment(ExpressionNode *p_previous_operand, bool p_can_assign);  	ExpressionNode *parse_array(ExpressionNode *p_previous_operand, bool p_can_assign); diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index fceeb82325..d7f7054acb 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -727,9 +727,9 @@ Point2i DisplayServerX11::screen_get_position(int p_screen) const {  	int count;  	XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count); -	if (p_screen >= count) { -		return Point2i(0, 0); -	} + +	// Check if screen is valid +	ERR_FAIL_INDEX_V(p_screen, count, Point2i(0, 0));  	Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org); @@ -758,9 +758,9 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {  	int count;  	XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count); -	if (p_screen >= count) { -		return Rect2i(0, 0, 0, 0); -	} + +	// Check if screen is valid +	ERR_FAIL_INDEX_V(p_screen, count, Rect2i(0, 0, 0, 0));  	Rect2i rect = Rect2i(xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height);  	XFree(xsi); @@ -1041,11 +1041,13 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window  	ERR_FAIL_COND(!windows.has(p_window));  	WindowData &wd = windows[p_window]; -	int count = get_screen_count(); -	if (p_screen >= count) { -		return; +	if (p_screen == SCREEN_OF_MAIN_WINDOW) { +		p_screen = window_get_current_screen();  	} +	// Check if screen is valid +	ERR_FAIL_INDEX(p_screen, get_screen_count()); +  	if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN) {  		Point2i position = screen_get_position(p_screen);  		Size2i size = screen_get_size(p_screen); diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index b4de12b113..c5ac4e1a05 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -263,6 +263,7 @@ void Camera2D::_notification(int p_what) {  			viewport = nullptr;  		} break; +#ifdef TOOLS_ENABLED  		case NOTIFICATION_DRAW: {  			if (!is_inside_tree() || !Engine::get_singleton()->is_editor_hint()) {  				break; @@ -339,8 +340,8 @@ void Camera2D::_notification(int p_what) {  					draw_line(inv_transform.xform(margin_endpoints[i]), inv_transform.xform(margin_endpoints[(i + 1) % 4]), margin_drawing_color, margin_drawing_width);  				}  			} -  		} break; +#endif  	}  } @@ -610,7 +611,9 @@ Node *Camera2D::get_custom_viewport() const {  void Camera2D::set_screen_drawing_enabled(bool enable) {  	screen_drawing_enabled = enable; +#ifdef TOOLS_ENABLED  	update(); +#endif  }  bool Camera2D::is_screen_drawing_enabled() const { @@ -619,7 +622,9 @@ bool Camera2D::is_screen_drawing_enabled() const {  void Camera2D::set_limit_drawing_enabled(bool enable) {  	limit_drawing_enabled = enable; +#ifdef TOOLS_ENABLED  	update(); +#endif  }  bool Camera2D::is_limit_drawing_enabled() const { @@ -628,7 +633,9 @@ bool Camera2D::is_limit_drawing_enabled() const {  void Camera2D::set_margin_drawing_enabled(bool enable) {  	margin_drawing_enabled = enable; +#ifdef TOOLS_ENABLED  	update(); +#endif  }  bool Camera2D::is_margin_drawing_enabled() const { diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 0e51264171..48acee1bc4 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -1032,66 +1032,64 @@ void CPUParticles2D::_update_render_thread() {  }  void CPUParticles2D::_notification(int p_what) { -	if (p_what == NOTIFICATION_ENTER_TREE) { -		set_process_internal(emitting); -	} - -	if (p_what == NOTIFICATION_EXIT_TREE) { -		_set_redraw(false); -	} - -	if (p_what == NOTIFICATION_DRAW) { -		// first update before rendering to avoid one frame delay after emitting starts -		if (emitting && (time == 0)) { -			_update_internal(); -		} - -		if (!redraw) { -			return; // don't add to render list -		} - -		RID texrid; -		if (texture.is_valid()) { -			texrid = texture->get_rid(); -		} - -		RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid); -	} - -	if (p_what == NOTIFICATION_INTERNAL_PROCESS) { -		_update_internal(); -	} - -	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { -		inv_emission_transform = get_global_transform().affine_inverse(); +	switch (p_what) { +		case NOTIFICATION_ENTER_TREE: { +			set_process_internal(emitting); +		} break; +		case NOTIFICATION_EXIT_TREE: { +			_set_redraw(false); +		} break; +		case NOTIFICATION_DRAW: { +			// first update before rendering to avoid one frame delay after emitting starts +			if (emitting && (time == 0)) { +				_update_internal(); +			} -		if (!local_coords) { -			int pc = particles.size(); +			if (!redraw) { +				return; // don't add to render list +			} -			float *w = particle_data.ptrw(); -			const Particle *r = particles.ptr(); -			float *ptr = w; +			RID texrid; +			if (texture.is_valid()) { +				texrid = texture->get_rid(); +			} -			for (int i = 0; i < pc; i++) { -				Transform2D t = inv_emission_transform * r[i].transform; +			RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid); +		} break; +		case NOTIFICATION_INTERNAL_PROCESS: { +			_update_internal(); +		} break; +		case NOTIFICATION_TRANSFORM_CHANGED: { +			inv_emission_transform = get_global_transform().affine_inverse(); -				if (r[i].active) { -					ptr[0] = t.elements[0][0]; -					ptr[1] = t.elements[1][0]; -					ptr[2] = 0; -					ptr[3] = t.elements[2][0]; -					ptr[4] = t.elements[0][1]; -					ptr[5] = t.elements[1][1]; -					ptr[6] = 0; -					ptr[7] = t.elements[2][1]; +			if (!local_coords) { +				int pc = particles.size(); + +				float *w = particle_data.ptrw(); +				const Particle *r = particles.ptr(); +				float *ptr = w; + +				for (int i = 0; i < pc; i++) { +					Transform2D t = inv_emission_transform * r[i].transform; + +					if (r[i].active) { +						ptr[0] = t.elements[0][0]; +						ptr[1] = t.elements[1][0]; +						ptr[2] = 0; +						ptr[3] = t.elements[2][0]; +						ptr[4] = t.elements[0][1]; +						ptr[5] = t.elements[1][1]; +						ptr[6] = 0; +						ptr[7] = t.elements[2][1]; + +					} else { +						zeromem(ptr, sizeof(float) * 8); +					} -				} else { -					zeromem(ptr, sizeof(float) * 8); +					ptr += 16;  				} - -				ptr += 16;  			} -		} +		} break;  	}  } diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index ecc05fb931..a60a32f1d2 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -88,6 +88,12 @@ bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toler  	}  	return Geometry2D::is_point_in_polygon(p_point - get_offset(), polygon2d);  } + +void Polygon2D::_validate_property(PropertyInfo &property) const { +	if (!invert && property.name == "invert_border") { +		property.usage = PROPERTY_USAGE_NOEDITOR; +	} +}  #endif  void Polygon2D::_skeleton_bone_setup_changed() { @@ -455,6 +461,7 @@ Size2 Polygon2D::get_texture_scale() const {  void Polygon2D::set_invert(bool p_invert) {  	invert = p_invert;  	update(); +	notify_property_list_changed();  }  bool Polygon2D::get_invert() const { diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index ab01a4ffd0..43a66aad13 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -72,6 +72,10 @@ class Polygon2D : public Node2D {  	void _skeleton_bone_setup_changed(); +#ifdef TOOLS_ENABLED +	void _validate_property(PropertyInfo &property) const override; +#endif +  protected:  	void _notification(int p_what);  	static void _bind_methods(); diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index dde9790b44..31040020dd 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -206,6 +206,7 @@ void Sprite2D::set_region(bool p_region) {  	region = p_region;  	update(); +	notify_property_list_changed();  }  bool Sprite2D::is_region() const { @@ -383,6 +384,10 @@ void Sprite2D::_validate_property(PropertyInfo &property) const {  	if (property.name == "frame_coords") {  		property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;  	} + +	if (!region && (property.name == "region_rect" || property.name == "region_filter_clip")) { +		property.usage = PROPERTY_USAGE_NOEDITOR; +	}  }  void Sprite2D::_texture_changed() { diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index 0f10f2b85f..b5eab35605 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -109,6 +109,7 @@ Color Decal::get_modulate() const {  void Decal::set_enable_distance_fade(bool p_enable) {  	distance_fade_enabled = p_enable;  	RS::get_singleton()->decal_set_distance_fade(decal, distance_fade_enabled, distance_fade_begin, distance_fade_length); +	notify_property_list_changed();  }  bool Decal::is_distance_fade_enabled() const { @@ -153,6 +154,14 @@ Vector<Face3> Decal::get_faces(uint32_t p_usage_flags) const {  	return Vector<Face3>();  } +#ifdef TOOLS_ENABLED +void Decal::_validate_property(PropertyInfo &property) const { +	if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_length")) { +		property.usage = PROPERTY_USAGE_NOEDITOR; +	} +} +#endif +  void Decal::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_extents", "extents"), &Decal::set_extents);  	ClassDB::bind_method(D_METHOD("get_extents"), &Decal::get_extents); diff --git a/scene/3d/decal.h b/scene/3d/decal.h index 095579d775..20d86ee16c 100644 --- a/scene/3d/decal.h +++ b/scene/3d/decal.h @@ -62,6 +62,10 @@ private:  	float distance_fade_begin = 10.0;  	float distance_fade_length = 1.0; +#ifdef TOOLS_ENABLED +	void _validate_property(PropertyInfo &property) const override; +#endif +  protected:  	static void _bind_methods(); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 8a8bfe50b9..43f820e5d4 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -415,13 +415,16 @@ Vector3i GIProbe::get_estimated_cell_size() const {  void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {  	static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 }; +	p_from_node = p_from_node ? p_from_node : get_parent(); +	ERR_FAIL_NULL(p_from_node); +  	Voxelizer baker;  	baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0));  	List<PlotMesh> mesh_list; -	_find_meshes(p_from_node ? p_from_node : get_parent(), mesh_list); +	_find_meshes(p_from_node, mesh_list);  	if (bake_begin_function) {  		bake_begin_function(mesh_list.size() + 1); diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index b0a10b5547..87f54022b3 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -65,6 +65,8 @@ void Light3D::set_shadow(bool p_enable) {  	if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) {  		update_configuration_warning();  	} + +	notify_property_list_changed();  }  bool Light3D::has_shadow() const { @@ -202,6 +204,10 @@ bool Light3D::is_editor_only() const {  }  void Light3D::_validate_property(PropertyInfo &property) const { +	if (!shadow && (property.name == "shadow_color" || property.name == "shadow_color" || property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_blur")) { +		property.usage = PROPERTY_USAGE_NOEDITOR; +	} +  	if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_size") {  		property.usage = 0;  	} diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp index 0463bed9d6..ebc57ed477 100644 --- a/scene/3d/physics_joint_3d.cpp +++ b/scene/3d/physics_joint_3d.cpp @@ -64,6 +64,7 @@ void Joint3D::_body_exit_tree(const ObjectID &p_body_id) {  void Joint3D::_update_joint(bool p_only_free) {  	if (ba.is_valid() && bb.is_valid()) {  		PhysicsServer3D::get_singleton()->body_remove_collision_exception(ba, bb); +		PhysicsServer3D::get_singleton()->body_remove_collision_exception(bb, ba);  	}  	ba = RID(); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index cb2df9130f..f881181ccd 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -518,6 +518,7 @@ void Sprite3D::set_region(bool p_region) {  	region = p_region;  	_queue_update(); +	notify_property_list_changed();  }  bool Sprite3D::is_region() const { @@ -623,6 +624,12 @@ void Sprite3D::_validate_property(PropertyInfo &property) const {  	if (property.name == "frame_coords") {  		property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;  	} + +#ifdef TOOLS_ENABLED +	if (!region && property.name == "region_rect") { +		property.usage = PROPERTY_USAGE_NOEDITOR; +	} +#endif  }  void Sprite3D::_bind_methods() { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 0c104bf318..bff3024e38 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -93,7 +93,7 @@ void Control::_edit_set_state(const Dictionary &p_state) {  void Control::_edit_set_position(const Point2 &p_position) {  #ifdef TOOLS_ENABLED -	set_position(p_position, CanvasItemEditor::get_singleton()->is_anchors_mode_enabled()); +	set_position(p_position, CanvasItemEditor::get_singleton()->is_anchors_mode_enabled() && Object::cast_to<Control>(data.parent));  #else  	// Unlikely to happen. TODO: enclose all _edit_ functions into TOOLS_ENABLED  	set_position(p_position); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 9c8669fff0..331f0380c5 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1558,7 +1558,12 @@ bool GraphEdit::is_minimap_enabled() const {  }  void GraphEdit::_minimap_toggled() { -	minimap->update(); +	if (is_minimap_enabled()) { +		minimap->set_visible(true); +		minimap->update(); +	} else { +		minimap->set_visible(false); +	}  }  void GraphEdit::set_connection_lines_thickness(float p_thickness) { diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 91daa08ff8..d9b29daf26 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -231,6 +231,7 @@ void CanvasLayer::set_follow_viewport(bool p_enable) {  	follow_viewport = p_enable;  	_update_follow_viewport(); +	notify_property_list_changed();  }  bool CanvasLayer::is_following_viewport() const { @@ -257,6 +258,14 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) {  	}  } +#ifdef TOOLS_ENABLED +void CanvasLayer::_validate_property(PropertyInfo &property) const { +	if (!follow_viewport && property.name == "follow_viewport_scale") { +		property.usage = PROPERTY_USAGE_NOEDITOR; +	} +} +#endif +  void CanvasLayer::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer);  	ClassDB::bind_method(D_METHOD("get_layer"), &CanvasLayer::get_layer); diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 181d1dd659..b20b291367 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -61,6 +61,10 @@ class CanvasLayer : public Node {  	void _update_locrotscale();  	void _update_follow_viewport(bool p_force_exit = false); +#ifdef TOOLS_ENABLED +	void _validate_property(PropertyInfo &property) const override; +#endif +  protected:  	void _notification(int p_what);  	static void _bind_methods(); diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 77bdf09426..71c372aec2 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -387,6 +387,9 @@ bool HTTPRequest::_update_connection() {  			}  			client->poll(); +			if (client->get_status() != HTTPClient::STATUS_BODY) { +				return false; +			}  			PackedByteArray chunk = client->read_response_body_chunk();  			downloaded.add(chunk.size()); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index df00af8f5b..9d8c7981e6 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2052,6 +2052,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const  	if (get_filename() != "") { //an instance  		node->set_filename(get_filename()); +		node->data.editable_instance = data.editable_instance;  	}  	StringName script_property_name = CoreStringNames::get_singleton()->_script; @@ -2267,74 +2268,6 @@ void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resourc  }  #endif -void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const { -	if (get_owner() != get_parent()->get_owner()) { -		return; -	} - -	Node *node = nullptr; - -	if (get_filename() != "") { -		Ref<PackedScene> res = ResourceLoader::load(get_filename()); -		ERR_FAIL_COND_MSG(res.is_null(), "Cannot load scene: " + get_filename()); -		node = res->instance(); -		ERR_FAIL_COND(!node); -	} else { -		Object *obj = ClassDB::instance(get_class()); -		ERR_FAIL_COND_MSG(!obj, "Node: Could not duplicate: " + String(get_class()) + "."); -		node = Object::cast_to<Node>(obj); -		if (!node) { -			memdelete(obj); -			ERR_FAIL_MSG("Node: Could not duplicate: " + String(get_class()) + "."); -		} -	} - -	List<PropertyInfo> plist; - -	get_property_list(&plist); - -	for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { -		if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { -			continue; -		} -		String name = E->get().name; - -		Variant value = get(name).duplicate(true); - -		node->set(name, value); -	} - -	List<GroupInfo> groups; -	get_groups(&groups); - -	for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next()) { -		node->add_to_group(E->get().name, E->get().persistent); -	} - -	node->set_name(get_name()); -	p_new_parent->add_child(node); - -	Node *owner = get_owner(); - -	if (p_reown_map.has(owner)) { -		owner = p_reown_map[owner]; -	} - -	if (owner) { -		NodePath p = get_path_to(owner); -		if (owner != this) { -			Node *new_owner = node->get_node(p); -			if (new_owner) { -				node->set_owner(new_owner); -			} -		} -	} - -	for (int i = 0; i < get_child_count(); i++) { -		get_child(i)->_duplicate_and_reown(node, p_reown_map); -	} -} -  // Duplication of signals must happen after all the node descendants have been copied,  // because re-targeting of connections from some descendant to another is not possible  // if the emitter node comes later in tree order than the receiver @@ -2389,49 +2322,6 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {  	}  } -Node *Node::duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const { -	ERR_FAIL_COND_V(get_filename() != "", nullptr); - -	Object *obj = ClassDB::instance(get_class()); -	ERR_FAIL_COND_V_MSG(!obj, nullptr, "Node: Could not duplicate: " + String(get_class()) + "."); - -	Node *node = Object::cast_to<Node>(obj); -	if (!node) { -		memdelete(obj); -		ERR_FAIL_V_MSG(nullptr, "Node: Could not duplicate: " + String(get_class()) + "."); -	} -	node->set_name(get_name()); - -	List<PropertyInfo> plist; - -	get_property_list(&plist); - -	for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { -		if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { -			continue; -		} -		String name = E->get().name; -		node->set(name, get(name)); -	} - -	List<GroupInfo> groups; -	get_groups(&groups); - -	for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next()) { -		node->add_to_group(E->get().name, E->get().persistent); -	} - -	for (int i = 0; i < get_child_count(); i++) { -		get_child(i)->_duplicate_and_reown(node, p_reown_map); -	} - -	// Duplication of signals must happen after all the node descendants have been copied, -	// because re-targeting of connections from some descendant to another is not possible -	// if the emitter node comes later in tree order than the receiver -	_duplicate_signals(this, node); -	return node; -} -  static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) {  	if (p_node->get_owner() == p_by) {  		p_owned->push_back(p_node); diff --git a/scene/main/node.h b/scene/main/node.h index 249a0ff86e..d47d271a10 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -173,7 +173,6 @@ private:  	Array _get_node_and_resource(const NodePath &p_path);  	void _duplicate_signals(const Node *p_original, Node *p_copy) const; -	void _duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const;  	Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = nullptr) const;  	TypedArray<Node> _get_children() const; @@ -366,7 +365,6 @@ public:  	bool is_processing_unhandled_key_input() const;  	Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const; -	Node *duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const;  #ifdef TOOLS_ENABLED  	Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const;  	Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap, const Map<RES, RES> &p_resource_remap) const; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 8198fa41c5..e40e990cf7 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1035,6 +1035,9 @@ void Window::popup_centered_ratio(float p_ratio) {  void Window::popup(const Rect2i &p_screen_rect) {  	emit_signal("about_to_popup"); +	// Update window size to calculate the actual window size based on contents minimum size and minimum size. +	_update_window_size(); +  	if (p_screen_rect != Rect2i()) {  		set_position(p_screen_rect.position);  		set_size(p_screen_rect.size); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index fd22cc445c..66bc71c834 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -70,7 +70,7 @@ private:  		bool loop_wrap = true;  		NodePath path; // path to something  		bool imported = false; -		bool enabled = false; +		bool enabled = true;  		Track() {}  		virtual ~Track() {}  	}; diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp index 4038338e1e..00312fc7b2 100644 --- a/scene/resources/camera_effects.cpp +++ b/scene/resources/camera_effects.cpp @@ -120,6 +120,7 @@ void CameraEffects::_update_dof_blur() {  void CameraEffects::set_override_exposure_enabled(bool p_enabled) {  	override_exposure_enabled = p_enabled;  	_update_override_exposure(); +	notify_property_list_changed();  }  bool CameraEffects::is_override_exposure_enabled() const { @@ -144,6 +145,16 @@ void CameraEffects::_update_override_exposure() {  // Private methods, constructor and destructor +#ifdef TOOLS_ENABLED +void CameraEffects::_validate_property(PropertyInfo &property) const { +	if ((!dof_blur_far_enabled && (property.name == "dof_blur_far_distance" || property.name == "dof_blur_far_transition")) || +			(!dof_blur_near_enabled && (property.name == "dof_blur_near_distance" || property.name == "dof_blur_near_transition")) || +			(!override_exposure_enabled && property.name == "override_exposure")) { +		property.usage = PROPERTY_USAGE_NOEDITOR; +	} +} +#endif +  void CameraEffects::_bind_methods() {  	// DOF blur diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_effects.h index 28aa6b8660..51fb2b6cf7 100644 --- a/scene/resources/camera_effects.h +++ b/scene/resources/camera_effects.h @@ -57,6 +57,10 @@ private:  	float override_exposure = 1.0;  	void _update_override_exposure(); +#ifdef TOOLS_ENABLED +	void _validate_property(PropertyInfo &property) const override; +#endif +  protected:  	static void _bind_methods(); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 6f6af93848..c04b271d81 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -441,6 +441,7 @@ void Environment::_update_ssao() {  void Environment::set_sdfgi_enabled(bool p_enabled) {  	sdfgi_enabled = p_enabled;  	_update_sdfgi(); +	notify_property_list_changed();  }  bool Environment::is_sdfgi_enabled() const { @@ -983,6 +984,7 @@ void Environment::_validate_property(PropertyInfo &property) const {  		"auto_exposure_",  		"ss_reflections_",  		"ssao_", +		"sdfgi_",  		"glow_",  		"adjustment_",  		nullptr diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 062d921855..9931757cc4 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1584,7 +1584,7 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {  	}  	flags[p_flag] = p_enabled; -	if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN) { +	if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN || p_flag == FLAG_USE_POINT_SIZE) {  		notify_property_list_changed();  	}  	_queue_shader_change(); @@ -1650,7 +1650,7 @@ BaseMaterial3D::TextureFilter BaseMaterial3D::get_texture_filter() const {  void BaseMaterial3D::_validate_feature(const String &text, Feature feature, PropertyInfo &property) const {  	if (property.name.begins_with(text) && property.name != text + "_enabled" && !features[feature]) { -		property.usage = 0; +		property.usage = PROPERTY_USAGE_NOEDITOR;  	}  } @@ -1683,16 +1683,24 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {  		property.usage = 0;  	} -	if (property.name == "params_grow_amount" && !grow_enabled) { -		property.usage = 0; +	if (property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) { +		property.usage = PROPERTY_USAGE_NOEDITOR; +	} + +	if (property.name == "grow_amount" && !grow_enabled) { +		property.usage = PROPERTY_USAGE_NOEDITOR; +	} + +	if (property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) { +		property.usage = PROPERTY_USAGE_NOEDITOR;  	}  	if (property.name == "proximity_fade_distance" && !proximity_fade_enabled) { -		property.usage = 0; +		property.usage = PROPERTY_USAGE_NOEDITOR;  	}  	if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) { -		property.usage = 0; +		property.usage = PROPERTY_USAGE_NOEDITOR;  	}  	// you can only enable anti-aliasing (in mataerials) on alpha scissor and alpha hash diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index d6200059f6..a99c09e89c 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -2742,8 +2742,6 @@ int VisualShaderNodeClamp::get_input_port_count() const {  VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_input_port_type(int p_port) const {  	switch (op_type) { -		case OP_TYPE_FLOAT: -			return PORT_TYPE_SCALAR;  		case OP_TYPE_INT:  			return PORT_TYPE_SCALAR_INT;  		case OP_TYPE_VECTOR: @@ -2771,8 +2769,6 @@ int VisualShaderNodeClamp::get_output_port_count() const {  VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_output_port_type(int p_port) const {  	switch (op_type) { -		case OP_TYPE_FLOAT: -			return PORT_TYPE_SCALAR;  		case OP_TYPE_INT:  			return PORT_TYPE_SCALAR_INT;  		case OP_TYPE_VECTOR: @@ -2954,18 +2950,11 @@ int VisualShaderNodeStep::get_input_port_count() const {  VisualShaderNodeStep::PortType VisualShaderNodeStep::get_input_port_type(int p_port) const {  	switch (op_type) { -		case OP_TYPE_SCALAR: -			return PORT_TYPE_SCALAR;  		case OP_TYPE_VECTOR:  			return PORT_TYPE_VECTOR;  		case OP_TYPE_VECTOR_SCALAR: -			switch (p_port) { -				case 0: -					return PORT_TYPE_SCALAR; -				case 1: -					return PORT_TYPE_VECTOR; -				default: -					break; +			if (p_port == 1) { +				return PORT_TYPE_VECTOR;  			}  			break;  		default: @@ -2989,8 +2978,6 @@ int VisualShaderNodeStep::get_output_port_count() const {  VisualShaderNodeStep::PortType VisualShaderNodeStep::get_output_port_type(int p_port) const {  	switch (op_type) { -		case OP_TYPE_SCALAR: -			return PORT_TYPE_SCALAR;  		case OP_TYPE_VECTOR:  			return PORT_TYPE_VECTOR;  		case OP_TYPE_VECTOR_SCALAR: @@ -3032,7 +3019,7 @@ void VisualShaderNodeStep::set_op_type(OpType p_op_type) {  				set_input_port_default_value(0, 0.0); // edge  			}  			if (op_type == OP_TYPE_SCALAR) { -				set_input_port_default_value(1, 0.0); // x +				set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // x  			}  			break;  		default: @@ -3085,20 +3072,11 @@ int VisualShaderNodeSmoothStep::get_input_port_count() const {  VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_input_port_type(int p_port) const {  	switch (op_type) { -		case OP_TYPE_SCALAR: -			return PORT_TYPE_SCALAR;  		case OP_TYPE_VECTOR:  			return PORT_TYPE_VECTOR;  		case OP_TYPE_VECTOR_SCALAR: -			switch (p_port) { -				case 0: -					return PORT_TYPE_SCALAR; // edge0 -				case 1: -					return PORT_TYPE_SCALAR; // edge1 -				case 2: -					return PORT_TYPE_VECTOR; // x -				default: -					break; +			if (p_port == 2) { +				return PORT_TYPE_VECTOR; // x  			}  			break;  		default: @@ -3124,8 +3102,6 @@ int VisualShaderNodeSmoothStep::get_output_port_count() const {  VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_output_port_type(int p_port) const {  	switch (op_type) { -		case OP_TYPE_SCALAR: -			return PORT_TYPE_SCALAR;  		case OP_TYPE_VECTOR:  			return PORT_TYPE_VECTOR;  		case OP_TYPE_VECTOR_SCALAR: @@ -3319,16 +3295,11 @@ int VisualShaderNodeMix::get_input_port_count() const {  VisualShaderNodeMix::PortType VisualShaderNodeMix::get_input_port_type(int p_port) const {  	switch (op_type) { -		case OP_TYPE_SCALAR: -			return PORT_TYPE_SCALAR;  		case OP_TYPE_VECTOR: -			if (p_port == 2) { -				return PORT_TYPE_VECTOR; -			}  			return PORT_TYPE_VECTOR;  		case OP_TYPE_VECTOR_SCALAR:  			if (p_port == 2) { -				return PORT_TYPE_SCALAR; +				break;  			}  			return PORT_TYPE_VECTOR;  		default: @@ -3353,8 +3324,6 @@ int VisualShaderNodeMix::get_output_port_count() const {  VisualShaderNodeMix::PortType VisualShaderNodeMix::get_output_port_type(int p_port) const {  	switch (op_type) { -		case OP_TYPE_SCALAR: -			return PORT_TYPE_SCALAR;  		case OP_TYPE_VECTOR:  			return PORT_TYPE_VECTOR;  		case OP_TYPE_VECTOR_SCALAR: @@ -4540,9 +4509,7 @@ int VisualShaderNodeTextureUniformTriplanar::get_input_port_count() const {  }  VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const { -	if (p_port == 0) { -		return PORT_TYPE_VECTOR; -	} else if (p_port == 1) { +	if (p_port == 0 || p_port == 1) {  		return PORT_TYPE_VECTOR;  	}  	return PORT_TYPE_SCALAR; @@ -4923,8 +4890,6 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int  	}  	if (p_port == 1 || p_port == 2) {  		switch (op_type) { -			case OP_TYPE_FLOAT: -				return PORT_TYPE_SCALAR;  			case OP_TYPE_INT:  				return PORT_TYPE_SCALAR_INT;  			case OP_TYPE_VECTOR: @@ -4959,8 +4924,6 @@ int VisualShaderNodeSwitch::get_output_port_count() const {  VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(int p_port) const {  	switch (op_type) { -		case OP_TYPE_FLOAT: -			return PORT_TYPE_SCALAR;  		case OP_TYPE_INT:  			return PORT_TYPE_SCALAR_INT;  		case OP_TYPE_VECTOR: @@ -5238,9 +5201,6 @@ int VisualShaderNodeCompare::get_input_port_count() const {  }  VisualShaderNodeCompare::PortType VisualShaderNodeCompare::get_input_port_type(int p_port) const { -	if (p_port == 2) { -		return PORT_TYPE_SCALAR; -	}  	switch (ctype) {  		case CTYPE_SCALAR:  			return PORT_TYPE_SCALAR; @@ -5252,8 +5212,9 @@ VisualShaderNodeCompare::PortType VisualShaderNodeCompare::get_input_port_type(i  			return PORT_TYPE_BOOLEAN;  		case CTYPE_TRANSFORM:  			return PORT_TYPE_TRANSFORM; +		default: +			return PORT_TYPE_SCALAR;  	} -	return PORT_TYPE_VECTOR;  }  String VisualShaderNodeCompare::get_input_port_name(int p_port) const { @@ -5472,10 +5433,10 @@ int VisualShaderNodeMultiplyAdd::get_input_port_count() const {  }  VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_input_port_type(int p_port) const { -	if (op_type == OP_TYPE_SCALAR) { -		return PORT_TYPE_SCALAR; +	if (op_type == OP_TYPE_VECTOR) { +		return PORT_TYPE_VECTOR;  	} -	return PORT_TYPE_VECTOR; +	return PORT_TYPE_SCALAR;  }  String VisualShaderNodeMultiplyAdd::get_input_port_name(int p_port) const { diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp index f503868ba5..c7b556deba 100644 --- a/servers/physics_2d/joints_2d_sw.cpp +++ b/servers/physics_2d/joints_2d_sw.cpp @@ -205,15 +205,6 @@ PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p  	}  } -PinJoint2DSW::~PinJoint2DSW() { -	if (A) { -		A->remove_constraint(this, 0); -	} -	if (B) { -		B->remove_constraint(this, 1); -	} -} -  //////////////////////////////////////////////  //////////////////////////////////////////////  ////////////////////////////////////////////// @@ -346,11 +337,6 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_  	B->add_constraint(this, 1);  } -GrooveJoint2DSW::~GrooveJoint2DSW() { -	A->remove_constraint(this, 0); -	B->remove_constraint(this, 1); -} -  //////////////////////////////////////////////  //////////////////////////////////////////////  ////////////////////////////////////////////// @@ -442,8 +428,3 @@ DampedSpringJoint2DSW::DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Ve  	A->add_constraint(this, 0);  	B->add_constraint(this, 1);  } - -DampedSpringJoint2DSW::~DampedSpringJoint2DSW() { -	A->remove_constraint(this, 0); -	B->remove_constraint(this, 1); -} diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h index 6050dc2775..628de972ae 100644 --- a/servers/physics_2d/joints_2d_sw.h +++ b/servers/physics_2d/joints_2d_sw.h @@ -60,6 +60,15 @@ public:  		bias = 0;  		max_force = max_bias = 3.40282e+38;  	}; + +	virtual ~Joint2DSW() { +		for (int i = 0; i < get_body_count(); i++) { +			Body2DSW *body = get_body_ptr()[i]; +			if (body) { +				body->remove_constraint(this, i); +			} +		} +	};  };  class PinJoint2DSW : public Joint2DSW { @@ -90,7 +99,6 @@ public:  	real_t get_param(PhysicsServer2D::PinJointParam p_param) const;  	PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p_body_b = nullptr); -	~PinJoint2DSW();  };  class GrooveJoint2DSW : public Joint2DSW { @@ -124,7 +132,6 @@ public:  	virtual void solve(real_t p_step);  	GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b); -	~GrooveJoint2DSW();  };  class DampedSpringJoint2DSW : public Joint2DSW { @@ -160,7 +167,6 @@ public:  	real_t get_param(PhysicsServer2D::DampedSpringParam p_param) const;  	DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, Body2DSW *p_body_a, Body2DSW *p_body_b); -	~DampedSpringJoint2DSW();  };  #endif // JOINTS_2D_SW_H diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp index f507cacdc3..651961433c 100644 --- a/servers/physics_3d/collision_solver_3d_sat.cpp +++ b/servers/physics_3d/collision_solver_3d_sat.cpp @@ -845,7 +845,7 @@ static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform &p_t  	//capsule sphere 1, sphere -	Vector3 capsule_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5); +	Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);  	Vector3 capsule_ball_1 = p_transform_b.origin + capsule_axis; @@ -1148,7 +1148,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran  		}  	} -	Vector3 cyl_axis = p_transform_b.basis.get_axis(2).normalized(); +	Vector3 cyl_axis = p_transform_b.basis.get_axis(1).normalized();  	// edges of A, capsule cylinder @@ -1193,7 +1193,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran  	// capsule balls, edges of A  	for (int i = 0; i < 2; i++) { -		Vector3 capsule_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5); +		Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);  		Vector3 sphere_pos = p_transform_b.origin + ((i == 0) ? capsule_axis : -capsule_axis); @@ -1569,8 +1569,8 @@ static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform &p_  	// some values -	Vector3 capsule_A_axis = p_transform_a.basis.get_axis(2) * (capsule_A->get_height() * 0.5); -	Vector3 capsule_B_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5); +	Vector3 capsule_A_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5); +	Vector3 capsule_B_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);  	Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis;  	Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis; @@ -1670,7 +1670,7 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf  	for (int i = 0; i < edge_count; i++) {  		// cylinder  		Vector3 edge_axis = p_transform_b.basis.xform(vertices[edges[i].a]) - p_transform_b.basis.xform(vertices[edges[i].b]); -		Vector3 axis = edge_axis.cross(p_transform_a.basis.get_axis(2)).normalized(); +		Vector3 axis = edge_axis.cross(p_transform_a.basis.get_axis(1)).normalized();  		if (!separator.test_axis(axis)) {  			return; @@ -1682,7 +1682,7 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf  	for (int i = 0; i < 2; i++) {  		// edges of B, capsule cylinder -		Vector3 capsule_axis = p_transform_a.basis.get_axis(2) * (capsule_A->get_height() * 0.5); +		Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);  		Vector3 sphere_pos = p_transform_a.origin + ((i == 0) ? capsule_axis : -capsule_axis); @@ -1720,7 +1720,7 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra  	// edges of B, capsule cylinder -	Vector3 capsule_axis = p_transform_a.basis.get_axis(2) * (capsule_A->get_height() * 0.5); +	Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);  	for (int i = 0; i < 3; i++) {  		// edge-cylinder diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/joints_3d_sw.h index 1fe573c69e..225a71aca9 100644 --- a/servers/physics_3d/joints_3d_sw.h +++ b/servers/physics_3d/joints_3d_sw.h @@ -49,6 +49,15 @@ public:  	_FORCE_INLINE_ Joint3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) :  			Constraint3DSW(p_body_ptr, p_body_count) {  	} + +	virtual ~Joint3DSW() { +		for (int i = 0; i < get_body_count(); i++) { +			Body3DSW *body = get_body_ptr()[i]; +			if (body) { +				body->remove_constraint(this); +			} +		} +	}  };  #endif // JOINTS_SW_H diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp index 735e9094d2..6bbef09907 100644 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ b/servers/physics_3d/physics_server_3d_sw.cpp @@ -1312,9 +1312,6 @@ void PhysicsServer3DSW::free(RID p_rid) {  	} else if (joint_owner.owns(p_rid)) {  		Joint3DSW *joint = joint_owner.getornull(p_rid); -		for (int i = 0; i < joint->get_body_count(); i++) { -			joint->get_body_ptr()[i]->remove_constraint(joint); -		}  		joint_owner.free(p_rid);  		memdelete(joint); diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp index 5bac4f19b9..02d0c66215 100644 --- a/servers/physics_3d/shape_3d_sw.cpp +++ b/servers/physics_3d/shape_3d_sw.cpp @@ -491,10 +491,10 @@ BoxShape3DSW::BoxShape3DSW() {  void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {  	Vector3 n = p_transform.basis.xform_inv(p_normal).normalized(); -	real_t h = (n.z > 0) ? height : -height; +	real_t h = (n.y > 0) ? height : -height;  	n *= radius; -	n.z += h * 0.5; +	n.y += h * 0.5;  	r_max = p_normal.dot(p_transform.xform(n));  	r_min = p_normal.dot(p_transform.xform(-n)); @@ -503,36 +503,36 @@ void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform &p  Vector3 CapsuleShape3DSW::get_support(const Vector3 &p_normal) const {  	Vector3 n = p_normal; -	real_t h = (n.z > 0) ? height : -height; +	real_t h = (n.y > 0) ? height : -height;  	n *= radius; -	n.z += h * 0.5; +	n.y += h * 0.5;  	return n;  }  void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {  	Vector3 n = p_normal; -	real_t d = n.z; +	real_t d = n.y;  	if (Math::abs(d) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {  		// make it flat -		n.z = 0.0; +		n.y = 0.0;  		n.normalize();  		n *= radius;  		r_amount = 2;  		r_type = FEATURE_EDGE;  		r_supports[0] = n; -		r_supports[0].z += height * 0.5; +		r_supports[0].y += height * 0.5;  		r_supports[1] = n; -		r_supports[1].z -= height * 0.5; +		r_supports[1].y -= height * 0.5;  	} else {  		real_t h = (d > 0) ? height : -height;  		n *= radius; -		n.z += h * 0.5; +		n.y += h * 0.5;  		r_amount = 1;  		r_type = FEATURE_POINT;  		*r_supports = n; @@ -551,7 +551,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &  	// test against cylinder and spheres :-| -	collided = Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &auxres, &auxn); +	collided = Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &auxres, &auxn, 1);  	if (collided) {  		real_t d = norm.dot(auxres); @@ -563,7 +563,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &  		}  	} -	collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * 0.5), radius, &auxres, &auxn); +	collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * 0.5, 0), radius, &auxres, &auxn);  	if (collided) {  		real_t d = norm.dot(auxres); @@ -575,7 +575,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &  		}  	} -	collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * -0.5), radius, &auxres, &auxn); +	collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * -0.5, 0), radius, &auxres, &auxn);  	if (collided) {  		real_t d = norm.dot(auxres); @@ -596,19 +596,19 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &  }  bool CapsuleShape3DSW::intersect_point(const Vector3 &p_point) const { -	if (Math::abs(p_point.z) < height * 0.5) { -		return Vector3(p_point.x, p_point.y, 0).length() < radius; +	if (Math::abs(p_point.y) < height * 0.5) { +		return Vector3(p_point.x, 0, p_point.z).length() < radius;  	} else {  		Vector3 p = p_point; -		p.z = Math::abs(p.z) - height * 0.5; +		p.y = Math::abs(p.y) - height * 0.5;  		return p.length() < radius;  	}  }  Vector3 CapsuleShape3DSW::get_closest_point_to(const Vector3 &p_point) const {  	Vector3 s[2] = { -		Vector3(0, 0, -height * 0.5), -		Vector3(0, 0, height * 0.5), +		Vector3(0, -height * 0.5, 0), +		Vector3(0, height * 0.5, 0),  	};  	Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, s); @@ -633,7 +633,7 @@ Vector3 CapsuleShape3DSW::get_moment_of_inertia(real_t p_mass) const {  void CapsuleShape3DSW::_setup(real_t p_height, real_t p_radius) {  	height = p_height;  	radius = p_radius; -	configure(AABB(Vector3(-radius, -radius, -height * 0.5 - radius), Vector3(radius * 2, radius * 2, height + radius * 2.0))); +	configure(AABB(Vector3(-radius, -height * 0.5 - radius, -radius), Vector3(radius * 2, height + radius * 2.0, radius * 2)));  }  void CapsuleShape3DSW::set_data(const Variant &p_data) { diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp new file mode 100644 index 0000000000..d631cb4bac --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp @@ -0,0 +1,126 @@ +/*************************************************************************/ +/*  renderer_scene_environment_rd.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 "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" + +uint64_t RendererSceneEnvironmentRD::auto_exposure_counter = 2; + +void RendererSceneEnvironmentRD::set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) { +	ambient_light = p_color; +	ambient_source = p_ambient; +	ambient_light_energy = p_energy; +	ambient_sky_contribution = p_sky_contribution; +	reflection_source = p_reflection_source; +	ao_color = p_ao_color; +} + +void RendererSceneEnvironmentRD::set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { +	exposure = p_exposure; +	tone_mapper = p_tone_mapper; +	if (!auto_exposure && p_auto_exposure) { +		auto_exposure_version = ++auto_exposure_counter; +	} +	auto_exposure = p_auto_exposure; +	white = p_white; +	min_luminance = p_min_luminance; +	max_luminance = p_max_luminance; +	auto_exp_speed = p_auto_exp_speed; +	auto_exp_scale = p_auto_exp_scale; +} + +void RendererSceneEnvironmentRD::set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +	ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7"); +	glow_enabled = p_enable; +	glow_levels = p_levels; +	glow_intensity = p_intensity; +	glow_strength = p_strength; +	glow_mix = p_mix; +	glow_bloom = p_bloom_threshold; +	glow_blend_mode = p_blend_mode; +	glow_hdr_bleed_threshold = p_hdr_bleed_threshold; +	glow_hdr_bleed_scale = p_hdr_bleed_scale; +	glow_hdr_luminance_cap = p_hdr_luminance_cap; +} + +void RendererSceneEnvironmentRD::set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { +	sdfgi_enabled = p_enable; +	sdfgi_cascades = p_cascades; +	sdfgi_min_cell_size = p_min_cell_size; +	sdfgi_use_occlusion = p_use_occlusion; +	sdfgi_bounce_feedback = p_bounce_feedback; +	sdfgi_read_sky_light = p_read_sky; +	sdfgi_energy = p_energy; +	sdfgi_normal_bias = p_normal_bias; +	sdfgi_probe_bias = p_probe_bias; +	sdfgi_y_scale = p_y_scale; +} + +void RendererSceneEnvironmentRD::set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) { +	fog_enabled = p_enable; +	fog_light_color = p_light_color; +	fog_light_energy = p_light_energy; +	fog_sun_scatter = p_sun_scatter; +	fog_density = p_density; +	fog_height = p_height; +	fog_height_density = p_height_density; +	fog_aerial_perspective = p_fog_aerial_perspective; +} + +void RendererSceneEnvironmentRD::set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) { +	volumetric_fog_enabled = p_enable; +	volumetric_fog_density = p_density; +	volumetric_fog_light = p_light; +	volumetric_fog_light_energy = p_light_energy; +	volumetric_fog_length = p_length; +	volumetric_fog_detail_spread = p_detail_spread; +	volumetric_fog_gi_inject = p_gi_inject; +	volumetric_fog_temporal_reprojection = p_temporal_reprojection; +	volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount; +} + +void RendererSceneEnvironmentRD::set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) { +	ssr_enabled = p_enable; +	ssr_max_steps = p_max_steps; +	ssr_fade_in = p_fade_int; +	ssr_fade_out = p_fade_out; +	ssr_depth_tolerance = p_depth_tolerance; +} + +void RendererSceneEnvironmentRD::set_ssao(bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) { +	ssao_enabled = p_enable; +	ssao_radius = p_radius; +	ssao_intensity = p_intensity; +	ssao_power = p_power; +	ssao_detail = p_detail; +	ssao_horizon = p_horizon; +	ssao_sharpness = p_sharpness; +	ssao_direct_light_affect = p_light_affect; +	ssao_ao_channel_affect = p_ao_channel_affect; +} diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h new file mode 100644 index 0000000000..992c4bf471 --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h @@ -0,0 +1,155 @@ +/*************************************************************************/ +/*  renderer_scene_environment_rd.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 RENDERING_SERVER_SCENE_ENVIRONMENT_RD_H +#define RENDERING_SERVER_SCENE_ENVIRONMENT_RD_H + +#include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering/rendering_device.h" + +class RendererSceneEnvironmentRD { +private: +	static uint64_t auto_exposure_counter; + +public: +	// BG +	RS::EnvironmentBG background = RS::ENV_BG_CLEAR_COLOR; +	RID sky; +	float sky_custom_fov = 0.0; +	Basis sky_orientation; +	Color bg_color; +	float bg_energy = 1.0; +	int canvas_max_layer = 0; +	RS::EnvironmentAmbientSource ambient_source = RS::ENV_AMBIENT_SOURCE_BG; +	Color ambient_light; +	float ambient_light_energy = 1.0; +	float ambient_sky_contribution = 1.0; +	RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG; +	Color ao_color; + +	/// Tonemap + +	RS::EnvironmentToneMapper tone_mapper; +	float exposure = 1.0; +	float white = 1.0; +	bool auto_exposure = false; +	float min_luminance = 0.2; +	float max_luminance = 8.0; +	float auto_exp_speed = 0.2; +	float auto_exp_scale = 0.5; +	uint64_t auto_exposure_version = 0; + +	// Fog +	bool fog_enabled = false; +	Color fog_light_color = Color(0.5, 0.6, 0.7); +	float fog_light_energy = 1.0; +	float fog_sun_scatter = 0.0; +	float fog_density = 0.001; +	float fog_height = 0.0; +	float fog_height_density = 0.0; //can be negative to invert effect +	float fog_aerial_perspective = 0.0; + +	/// Volumetric Fog +	/// +	bool volumetric_fog_enabled = false; +	float volumetric_fog_density = 0.01; +	Color volumetric_fog_light = Color(0, 0, 0); +	float volumetric_fog_light_energy = 0.0; +	float volumetric_fog_length = 64.0; +	float volumetric_fog_detail_spread = 2.0; +	float volumetric_fog_gi_inject = 0.0; +	bool volumetric_fog_temporal_reprojection = true; +	float volumetric_fog_temporal_reprojection_amount = 0.9; + +	/// Glow + +	bool glow_enabled = false; +	Vector<float> glow_levels; +	float glow_intensity = 0.8; +	float glow_strength = 1.0; +	float glow_bloom = 0.0; +	float glow_mix = 0.01; +	RS::EnvironmentGlowBlendMode glow_blend_mode = RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT; +	float glow_hdr_bleed_threshold = 1.0; +	float glow_hdr_luminance_cap = 12.0; +	float glow_hdr_bleed_scale = 2.0; + +	/// SSAO + +	bool ssao_enabled = false; +	float ssao_radius = 1.0; +	float ssao_intensity = 2.0; +	float ssao_power = 1.5; +	float ssao_detail = 0.5; +	float ssao_horizon = 0.06; +	float ssao_sharpness = 0.98; +	float ssao_direct_light_affect = 0.0; +	float ssao_ao_channel_affect = 0.0; + +	/// SSR +	/// +	bool ssr_enabled = false; +	int ssr_max_steps = 64; +	float ssr_fade_in = 0.15; +	float ssr_fade_out = 2.0; +	float ssr_depth_tolerance = 0.2; + +	/// SDFGI +	bool sdfgi_enabled = false; +	RS::EnvironmentSDFGICascades sdfgi_cascades; +	float sdfgi_min_cell_size = 0.2; +	bool sdfgi_use_occlusion = false; +	float sdfgi_bounce_feedback = 0.0; +	bool sdfgi_read_sky_light = false; +	float sdfgi_energy = 1.0; +	float sdfgi_normal_bias = 1.1; +	float sdfgi_probe_bias = 1.1; +	RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED; + +	/// Adjustments + +	bool adjustments_enabled = false; +	float adjustments_brightness = 1.0f; +	float adjustments_contrast = 1.0f; +	float adjustments_saturation = 1.0f; +	bool use_1d_color_correction = false; +	RID color_correction = RID(); + +	void set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color); +	void set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); +	void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap); +	void set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias); +	void set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective); +	void set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount); +	void set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance); +	void set_ssao(bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect); +}; + +#endif /* !RENDERING_SERVER_SCENE_ENVIRONMENT_RD_H */ diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp new file mode 100644 index 0000000000..62589cc97c --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp @@ -0,0 +1,3383 @@ +/*************************************************************************/ +/*  renderer_scene_gi_rd.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 "renderer_scene_gi_rd.h" + +#include "core/config/project_settings.h" +#include "renderer_compositor_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" +#include "servers/rendering/rendering_server_default.h" + +const Vector3i RendererSceneGIRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF); + +//////////////////////////////////////////////////////////////////////////////// +// SDFGI + +void RendererSceneGIRD::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, RendererSceneGIRD *p_gi) { +	storage = p_gi->storage; +	gi = p_gi; +	cascade_mode = p_env->sdfgi_cascades; +	min_cell_size = p_env->sdfgi_min_cell_size; +	uses_occlusion = p_env->sdfgi_use_occlusion; +	y_scale_mode = p_env->sdfgi_y_scale; +	static const float y_scale[3] = { 1.0, 1.5, 2.0 }; +	y_mult = y_scale[y_scale_mode]; +	static const int cascasde_size[3] = { 4, 6, 8 }; +	cascades.resize(cascasde_size[cascade_mode]); +	probe_axis_count = SDFGI::PROBE_DIVISOR + 1; +	solid_cell_ratio = gi->sdfgi_solid_cell_ratio; +	solid_cell_count = uint32_t(float(cascade_size * cascade_size * cascade_size) * solid_cell_ratio); + +	float base_cell_size = min_cell_size; + +	RD::TextureFormat tf_sdf; +	tf_sdf.format = RD::DATA_FORMAT_R8_UNORM; +	tf_sdf.width = cascade_size; // Always 64x64 +	tf_sdf.height = cascade_size; +	tf_sdf.depth = cascade_size; +	tf_sdf.texture_type = RD::TEXTURE_TYPE_3D; +	tf_sdf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + +	{ +		RD::TextureFormat tf_render = tf_sdf; +		tf_render.format = RD::DATA_FORMAT_R16_UINT; +		render_albedo = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); +		tf_render.format = RD::DATA_FORMAT_R32_UINT; +		render_emission = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); +		render_emission_aniso = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + +		tf_render.format = RD::DATA_FORMAT_R8_UNORM; //at least its easy to visualize + +		for (int i = 0; i < 8; i++) { +			render_occlusion[i] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); +		} + +		tf_render.format = RD::DATA_FORMAT_R32_UINT; +		render_geom_facing = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + +		tf_render.format = RD::DATA_FORMAT_R8G8B8A8_UINT; +		render_sdf[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); +		render_sdf[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); + +		tf_render.width /= 2; +		tf_render.height /= 2; +		tf_render.depth /= 2; + +		render_sdf_half[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); +		render_sdf_half[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); +	} + +	RD::TextureFormat tf_occlusion = tf_sdf; +	tf_occlusion.format = RD::DATA_FORMAT_R16_UINT; +	tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT); +	tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16); +	tf_occlusion.depth *= cascades.size(); //use depth for occlusion slices +	tf_occlusion.width *= 2; //use width for the other half + +	RD::TextureFormat tf_light = tf_sdf; +	tf_light.format = RD::DATA_FORMAT_R32_UINT; +	tf_light.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT); +	tf_light.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32); + +	RD::TextureFormat tf_aniso0 = tf_sdf; +	tf_aniso0.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; +	RD::TextureFormat tf_aniso1 = tf_sdf; +	tf_aniso1.format = RD::DATA_FORMAT_R8G8_UNORM; + +	int passes = nearest_shift(cascade_size) - 1; + +	//store lightprobe SH +	RD::TextureFormat tf_probes; +	tf_probes.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; +	tf_probes.width = probe_axis_count * probe_axis_count; +	tf_probes.height = probe_axis_count * SDFGI::SH_SIZE; +	tf_probes.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; +	tf_probes.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + +	history_size = p_requested_history_size; + +	RD::TextureFormat tf_probe_history = tf_probes; +	tf_probe_history.format = RD::DATA_FORMAT_R16G16B16A16_SINT; //signed integer because SH are signed +	tf_probe_history.array_layers = history_size; + +	RD::TextureFormat tf_probe_average = tf_probes; +	tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed +	tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D; + +	lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); +	lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); + +	{ +		//octahedral lightprobes +		RD::TextureFormat tf_octprobes = tf_probes; +		tf_octprobes.array_layers = cascades.size() * 2; +		tf_octprobes.format = RD::DATA_FORMAT_R32_UINT; //pack well with RGBE +		tf_octprobes.width = probe_axis_count * probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2); +		tf_octprobes.height = probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2); +		tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT); +		tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32); +		//lightprobe texture is an octahedral texture + +		lightprobe_data = RD::get_singleton()->texture_create(tf_octprobes, RD::TextureView()); +		RD::TextureView tv; +		tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32; +		lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, lightprobe_data); + +		//texture handling ambient data, to integrate with volumetric foc +		RD::TextureFormat tf_ambient = tf_probes; +		tf_ambient.array_layers = cascades.size(); +		tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE +		tf_ambient.width = probe_axis_count * probe_axis_count; +		tf_ambient.height = probe_axis_count; +		tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; +		//lightprobe texture is an octahedral texture +		ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView()); +	} + +	cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES); + +	occlusion_data = RD::get_singleton()->texture_create(tf_occlusion, RD::TextureView()); +	{ +		RD::TextureView tv; +		tv.format_override = RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16; +		occlusion_texture = RD::get_singleton()->texture_create_shared(tv, occlusion_data); +	} + +	for (uint32_t i = 0; i < cascades.size(); i++) { +		SDFGI::Cascade &cascade = cascades[i]; + +		/* 3D Textures */ + +		cascade.sdf_tex = RD::get_singleton()->texture_create(tf_sdf, RD::TextureView()); + +		cascade.light_data = RD::get_singleton()->texture_create(tf_light, RD::TextureView()); + +		cascade.light_aniso_0_tex = RD::get_singleton()->texture_create(tf_aniso0, RD::TextureView()); +		cascade.light_aniso_1_tex = RD::get_singleton()->texture_create(tf_aniso1, RD::TextureView()); + +		{ +			RD::TextureView tv; +			tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32; +			cascade.light_tex = RD::get_singleton()->texture_create_shared(tv, cascade.light_data); + +			RD::get_singleton()->texture_clear(cascade.light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); +			RD::get_singleton()->texture_clear(cascade.light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); +			RD::get_singleton()->texture_clear(cascade.light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); +		} + +		cascade.cell_size = base_cell_size; +		Vector3 world_position = p_world_position; +		world_position.y *= y_mult; +		int32_t probe_cells = cascade_size / SDFGI::PROBE_DIVISOR; +		Vector3 probe_size = Vector3(1, 1, 1) * cascade.cell_size * probe_cells; +		Vector3i probe_pos = Vector3i((world_position / probe_size + Vector3(0.5, 0.5, 0.5)).floor()); +		cascade.position = probe_pos * probe_cells; + +		cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL; + +		base_cell_size *= 2.0; + +		/* Probe History */ + +		cascade.lightprobe_history_tex = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); +		RD::get_singleton()->texture_clear(cascade.lightprobe_history_tex, Color(0, 0, 0, 0), 0, 1, 0, tf_probe_history.array_layers); //needs to be cleared for average to work + +		cascade.lightprobe_average_tex = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); +		RD::get_singleton()->texture_clear(cascade.lightprobe_average_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); //needs to be cleared for average to work + +		/* Buffers */ + +		cascade.solid_cell_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGI::Cascade::SolidCell) * solid_cell_count); +		cascade.solid_cell_dispatch_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT); +		cascade.lights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDGIShader::Light) * MAX(SDFGI::MAX_STATIC_LIGHTS, SDFGI::MAX_DYNAMIC_LIGHTS)); +		{ +			Vector<RD::Uniform> uniforms; +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 1; +				u.ids.push_back(render_sdf[(passes & 1) ? 1 : 0]); //if passes are even, we read from buffer 0, else we read from buffer 1 +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 2; +				u.ids.push_back(render_albedo); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 3; +				for (int j = 0; j < 8; j++) { +					u.ids.push_back(render_occlusion[j]); +				} +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 4; +				u.ids.push_back(render_emission); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 5; +				u.ids.push_back(render_emission_aniso); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 6; +				u.ids.push_back(render_geom_facing); +				uniforms.push_back(u); +			} + +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 7; +				u.ids.push_back(cascade.sdf_tex); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 8; +				u.ids.push_back(occlusion_data); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +				u.binding = 10; +				u.ids.push_back(cascade.solid_cell_dispatch_buffer); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +				u.binding = 11; +				u.ids.push_back(cascade.solid_cell_buffer); +				uniforms.push_back(u); +			} + +			cascade.sdf_store_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_STORE), 0); +		} + +		{ +			Vector<RD::Uniform> uniforms; +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 1; +				u.ids.push_back(render_albedo); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 2; +				u.ids.push_back(render_geom_facing); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 3; +				u.ids.push_back(render_emission); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 4; +				u.ids.push_back(render_emission_aniso); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +				u.binding = 5; +				u.ids.push_back(cascade.solid_cell_dispatch_buffer); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +				u.binding = 6; +				u.ids.push_back(cascade.solid_cell_buffer); +				uniforms.push_back(u); +			} + +			cascade.scroll_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_SCROLL), 0); +		} +		{ +			Vector<RD::Uniform> uniforms; +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 1; +				for (int j = 0; j < 8; j++) { +					u.ids.push_back(render_occlusion[j]); +				} +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +				u.binding = 2; +				u.ids.push_back(occlusion_data); +				uniforms.push_back(u); +			} + +			cascade.scroll_occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_SCROLL_OCCLUSION), 0); +		} +	} + +	//direct light +	for (uint32_t i = 0; i < cascades.size(); i++) { +		SDFGI::Cascade &cascade = cascades[i]; + +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.binding = 1; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { +				if (j < cascades.size()) { +					u.ids.push_back(cascades[j].sdf_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 2; +			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 3; +			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.ids.push_back(cascade.solid_cell_dispatch_buffer); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 4; +			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.ids.push_back(cascade.solid_cell_buffer); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 5; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.ids.push_back(cascade.light_data); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 6; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.ids.push_back(cascade.light_aniso_0_tex); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 7; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.ids.push_back(cascade.light_aniso_1_tex); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 8; +			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.ids.push_back(cascades_ubo); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 9; +			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.ids.push_back(cascade.lights_buffer); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 10; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.ids.push_back(lightprobe_texture); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 11; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.ids.push_back(occlusion_texture); +			uniforms.push_back(u); +		} + +		cascade.sdf_direct_light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.direct_light.version_get_shader(gi->sdfgi_shader.direct_light_shader, 0), 0); +	} + +	//preprocess initialize uniform set +	{ +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 1; +			u.ids.push_back(render_albedo); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 2; +			u.ids.push_back(render_sdf[0]); +			uniforms.push_back(u); +		} + +		sdf_initialize_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE), 0); +	} + +	{ +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 1; +			u.ids.push_back(render_albedo); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 2; +			u.ids.push_back(render_sdf_half[0]); +			uniforms.push_back(u); +		} + +		sdf_initialize_half_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF), 0); +	} + +	//jump flood uniform set +	{ +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 1; +			u.ids.push_back(render_sdf[0]); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 2; +			u.ids.push_back(render_sdf[1]); +			uniforms.push_back(u); +		} + +		jump_flood_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0); +		SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]); +		jump_flood_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0); +	} +	//jump flood half uniform set +	{ +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 1; +			u.ids.push_back(render_sdf_half[0]); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 2; +			u.ids.push_back(render_sdf_half[1]); +			uniforms.push_back(u); +		} + +		jump_flood_half_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0); +		SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]); +		jump_flood_half_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0); +	} + +	//upscale half size sdf +	{ +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 1; +			u.ids.push_back(render_albedo); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 2; +			u.ids.push_back(render_sdf_half[(passes & 1) ? 0 : 1]); //reverse pass order because half size +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 3; +			u.ids.push_back(render_sdf[(passes & 1) ? 0 : 1]); //reverse pass order because it needs an extra JFA pass +			uniforms.push_back(u); +		} + +		upscale_jfa_uniform_set_index = (passes & 1) ? 0 : 1; +		sdf_upscale_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE), 0); +	} + +	//occlusion uniform set +	{ +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 1; +			u.ids.push_back(render_albedo); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 2; +			for (int i = 0; i < 8; i++) { +				u.ids.push_back(render_occlusion[i]); +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 3; +			u.ids.push_back(render_geom_facing); +			uniforms.push_back(u); +		} + +		occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_OCCLUSION), 0); +	} + +	for (uint32_t i = 0; i < cascades.size(); i++) { +		//integrate uniform + +		Vector<RD::Uniform> uniforms; + +		{ +			RD::Uniform u; +			u.binding = 1; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { +				if (j < cascades.size()) { +					u.ids.push_back(cascades[j].sdf_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 2; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { +				if (j < cascades.size()) { +					u.ids.push_back(cascades[j].light_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 3; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { +				if (j < cascades.size()) { +					u.ids.push_back(cascades[j].light_aniso_0_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 4; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { +				if (j < cascades.size()) { +					u.ids.push_back(cascades[j].light_aniso_1_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +			u.binding = 6; +			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.binding = 7; +			u.ids.push_back(cascades_ubo); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 8; +			u.ids.push_back(lightprobe_data); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 9; +			u.ids.push_back(cascades[i].lightprobe_history_tex); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 10; +			u.ids.push_back(cascades[i].lightprobe_average_tex); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 11; +			u.ids.push_back(lightprobe_history_scroll); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 12; +			u.ids.push_back(lightprobe_average_scroll); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 13; +			RID parent_average; +			if (i < cascades.size() - 1) { +				parent_average = cascades[i + 1].lightprobe_average_tex; +			} else { +				parent_average = cascades[i - 1].lightprobe_average_tex; //to use something, but it won't be used +			} +			u.ids.push_back(parent_average); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 14; +			u.ids.push_back(ambient_texture); +			uniforms.push_back(u); +		} + +		cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.integrate.version_get_shader(gi->sdfgi_shader.integrate_shader, 0), 0); +	} + +	bounce_feedback = p_env->sdfgi_bounce_feedback; +	energy = p_env->sdfgi_energy; +	normal_bias = p_env->sdfgi_normal_bias; +	probe_bias = p_env->sdfgi_probe_bias; +	reads_sky = p_env->sdfgi_read_sky_light; +} + +void RendererSceneGIRD::SDFGI::erase() { +	for (uint32_t i = 0; i < cascades.size(); i++) { +		const SDFGI::Cascade &c = cascades[i]; +		RD::get_singleton()->free(c.light_data); +		RD::get_singleton()->free(c.light_aniso_0_tex); +		RD::get_singleton()->free(c.light_aniso_1_tex); +		RD::get_singleton()->free(c.sdf_tex); +		RD::get_singleton()->free(c.solid_cell_dispatch_buffer); +		RD::get_singleton()->free(c.solid_cell_buffer); +		RD::get_singleton()->free(c.lightprobe_history_tex); +		RD::get_singleton()->free(c.lightprobe_average_tex); +		RD::get_singleton()->free(c.lights_buffer); +	} + +	RD::get_singleton()->free(render_albedo); +	RD::get_singleton()->free(render_emission); +	RD::get_singleton()->free(render_emission_aniso); + +	RD::get_singleton()->free(render_sdf[0]); +	RD::get_singleton()->free(render_sdf[1]); + +	RD::get_singleton()->free(render_sdf_half[0]); +	RD::get_singleton()->free(render_sdf_half[1]); + +	for (int i = 0; i < 8; i++) { +		RD::get_singleton()->free(render_occlusion[i]); +	} + +	RD::get_singleton()->free(render_geom_facing); + +	RD::get_singleton()->free(lightprobe_data); +	RD::get_singleton()->free(lightprobe_history_scroll); +	RD::get_singleton()->free(occlusion_data); +	RD::get_singleton()->free(ambient_texture); + +	RD::get_singleton()->free(cascades_ubo); +} + +void RendererSceneGIRD::SDFGI::update(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position) { +	bounce_feedback = p_env->sdfgi_bounce_feedback; +	energy = p_env->sdfgi_energy; +	normal_bias = p_env->sdfgi_normal_bias; +	probe_bias = p_env->sdfgi_probe_bias; +	reads_sky = p_env->sdfgi_read_sky_light; + +	int32_t drag_margin = (cascade_size / SDFGI::PROBE_DIVISOR) / 2; + +	for (uint32_t i = 0; i < cascades.size(); i++) { +		SDFGI::Cascade &cascade = cascades[i]; +		cascade.dirty_regions = Vector3i(); + +		Vector3 probe_half_size = Vector3(1, 1, 1) * cascade.cell_size * float(cascade_size / SDFGI::PROBE_DIVISOR) * 0.5; +		probe_half_size = Vector3(0, 0, 0); + +		Vector3 world_position = p_world_position; +		world_position.y *= y_mult; +		Vector3i pos_in_cascade = Vector3i((world_position + probe_half_size) / cascade.cell_size); + +		for (int j = 0; j < 3; j++) { +			if (pos_in_cascade[j] < cascade.position[j]) { +				while (pos_in_cascade[j] < (cascade.position[j] - drag_margin)) { +					cascade.position[j] -= drag_margin * 2; +					cascade.dirty_regions[j] += drag_margin * 2; +				} +			} else if (pos_in_cascade[j] > cascade.position[j]) { +				while (pos_in_cascade[j] > (cascade.position[j] + drag_margin)) { +					cascade.position[j] += drag_margin * 2; +					cascade.dirty_regions[j] -= drag_margin * 2; +				} +			} + +			if (cascade.dirty_regions[j] == 0) { +				continue; // not dirty +			} else if (uint32_t(ABS(cascade.dirty_regions[j])) >= cascade_size) { +				//moved too much, just redraw everything (make all dirty) +				cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL; +				break; +			} +		} + +		if (cascade.dirty_regions != Vector3i() && cascade.dirty_regions != SDFGI::Cascade::DIRTY_ALL) { +			//see how much the total dirty volume represents from the total volume +			uint32_t total_volume = cascade_size * cascade_size * cascade_size; +			uint32_t safe_volume = 1; +			for (int j = 0; j < 3; j++) { +				safe_volume *= cascade_size - ABS(cascade.dirty_regions[j]); +			} +			uint32_t dirty_volume = total_volume - safe_volume; +			if (dirty_volume > (safe_volume / 2)) { +				//more than half the volume is dirty, make all dirty so its only rendered once +				cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL; +			} +		} +	} +} + +void RendererSceneGIRD::SDFGI::update_light() { +	RD::get_singleton()->draw_command_begin_label("SDFGI Update dynamic Light"); + +	/* Update dynamic light */ + +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_DYNAMIC]); + +	SDGIShader::DirectLightPushConstant push_constant; + +	push_constant.grid_size[0] = cascade_size; +	push_constant.grid_size[1] = cascade_size; +	push_constant.grid_size[2] = cascade_size; +	push_constant.max_cascades = cascades.size(); +	push_constant.probe_axis_size = probe_axis_count; +	push_constant.bounce_feedback = bounce_feedback; +	push_constant.y_mult = y_mult; +	push_constant.use_occlusion = uses_occlusion; + +	for (uint32_t i = 0; i < cascades.size(); i++) { +		SDFGI::Cascade &cascade = cascades[i]; +		push_constant.light_count = cascade_dynamic_light_count[i]; +		push_constant.cascade = i; + +		if (cascades[i].all_dynamic_lights_dirty || gi->sdfgi_frames_to_update_light == RS::ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME) { +			push_constant.process_offset = 0; +			push_constant.process_increment = 1; +		} else { +			static uint32_t frames_to_update_table[RS::ENV_SDFGI_UPDATE_LIGHT_MAX] = { +				1, 2, 4, 8, 16 +			}; + +			uint32_t frames_to_update = frames_to_update_table[gi->sdfgi_frames_to_update_light]; + +			push_constant.process_offset = RSG::rasterizer->get_frame_number() % frames_to_update; +			push_constant.process_increment = frames_to_update; +		} +		cascades[i].all_dynamic_lights_dirty = false; + +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0); +		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DirectLightPushConstant)); +		RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0); +	} +	RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); +	RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneGIRD::SDFGI::update_probes(RendererSceneEnvironmentRD *p_env, RendererSceneSkyRD::Sky *p_sky) { +	RD::get_singleton()->draw_command_begin_label("SDFGI Update Probes"); + +	SDGIShader::IntegratePushConstant push_constant; +	push_constant.grid_size[1] = cascade_size; +	push_constant.grid_size[2] = cascade_size; +	push_constant.grid_size[0] = cascade_size; +	push_constant.max_cascades = cascades.size(); +	push_constant.probe_axis_size = probe_axis_count; +	push_constant.history_index = render_pass % history_size; +	push_constant.history_size = history_size; +	static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 }; +	push_constant.ray_count = ray_count[gi->sdfgi_ray_count]; +	push_constant.ray_bias = probe_bias; +	push_constant.image_size[0] = probe_axis_count * probe_axis_count; +	push_constant.image_size[1] = probe_axis_count; +	push_constant.store_ambient_texture = p_env->volumetric_fog_enabled; + +	RID sky_uniform_set = gi->sdfgi_shader.integrate_default_sky_uniform_set; +	push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_DISABLED; +	push_constant.y_mult = y_mult; + +	if (reads_sky && p_env) { +		push_constant.sky_energy = p_env->bg_energy; + +		if (p_env->background == RS::ENV_BG_CLEAR_COLOR) { +			push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_COLOR; +			Color c = storage->get_default_clear_color().to_linear(); +			push_constant.sky_color[0] = c.r; +			push_constant.sky_color[1] = c.g; +			push_constant.sky_color[2] = c.b; +		} else if (p_env->background == RS::ENV_BG_COLOR) { +			push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_COLOR; +			Color c = p_env->bg_color; +			push_constant.sky_color[0] = c.r; +			push_constant.sky_color[1] = c.g; +			push_constant.sky_color[2] = c.b; + +		} else if (p_env->background == RS::ENV_BG_SKY) { +			if (p_sky && p_sky->radiance.is_valid()) { +				if (integrate_sky_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(integrate_sky_uniform_set)) { +					Vector<RD::Uniform> uniforms; + +					{ +						RD::Uniform u; +						u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +						u.binding = 0; +						u.ids.push_back(p_sky->radiance); +						uniforms.push_back(u); +					} + +					{ +						RD::Uniform u; +						u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +						u.binding = 1; +						u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +						uniforms.push_back(u); +					} + +					integrate_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.integrate.version_get_shader(gi->sdfgi_shader.integrate_shader, 0), 1); +				} +				sky_uniform_set = integrate_sky_uniform_set; +				push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_SKY; +			} +		} +	} + +	render_pass++; + +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_PROCESS]); + +	int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR; +	for (uint32_t i = 0; i < cascades.size(); i++) { +		push_constant.cascade = i; +		push_constant.world_offset[0] = cascades[i].position.x / probe_divisor; +		push_constant.world_offset[1] = cascades[i].position.y / probe_divisor; +		push_constant.world_offset[2] = cascades[i].position.z / probe_divisor; + +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[i].integrate_uniform_set, 0); +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sky_uniform_set, 1); + +		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant)); +		RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1); +	} + +	//end later after raster to avoid barriering on layout changes +	//RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); + +	RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneGIRD::SDFGI::store_probes() { +	RD::get_singleton()->barrier(RD::BARRIER_MASK_COMPUTE, RD::BARRIER_MASK_COMPUTE); +	RD::get_singleton()->draw_command_begin_label("SDFGI Store Probes"); + +	SDGIShader::IntegratePushConstant push_constant; +	push_constant.grid_size[1] = cascade_size; +	push_constant.grid_size[2] = cascade_size; +	push_constant.grid_size[0] = cascade_size; +	push_constant.max_cascades = cascades.size(); +	push_constant.probe_axis_size = probe_axis_count; +	push_constant.history_index = render_pass % history_size; +	push_constant.history_size = history_size; +	static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 }; +	push_constant.ray_count = ray_count[gi->sdfgi_ray_count]; +	push_constant.ray_bias = probe_bias; +	push_constant.image_size[0] = probe_axis_count * probe_axis_count; +	push_constant.image_size[1] = probe_axis_count; +	push_constant.store_ambient_texture = false; + +	push_constant.sky_mode = 0; +	push_constant.y_mult = y_mult; + +	// Then store values into the lightprobe texture. Separating these steps has a small performance hit, but it allows for multiple bounces +	RENDER_TIMESTAMP("Average Probes"); + +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]); + +	//convert to octahedral to store +	push_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE; +	push_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE; + +	for (uint32_t i = 0; i < cascades.size(); i++) { +		push_constant.cascade = i; +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[i].integrate_uniform_set, 0); +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1); +		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant)); +		RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1); +	} + +	RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); + +	RD::get_singleton()->draw_command_end_label(); +} + +int RendererSceneGIRD::SDFGI::get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const { +	int dirty_count = 0; +	for (uint32_t i = 0; i < cascades.size(); i++) { +		const SDFGI::Cascade &c = cascades[i]; + +		if (c.dirty_regions == SDFGI::Cascade::DIRTY_ALL) { +			if (dirty_count == p_region) { +				r_local_offset = Vector3i(); +				r_local_size = Vector3i(1, 1, 1) * cascade_size; + +				r_bounds.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + c.position)) * c.cell_size * Vector3(1, 1.0 / y_mult, 1); +				r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / y_mult, 1); +				return i; +			} +			dirty_count++; +		} else { +			for (int j = 0; j < 3; j++) { +				if (c.dirty_regions[j] != 0) { +					if (dirty_count == p_region) { +						Vector3i from = Vector3i(0, 0, 0); +						Vector3i to = Vector3i(1, 1, 1) * cascade_size; + +						if (c.dirty_regions[j] > 0) { +							//fill from the beginning +							to[j] = c.dirty_regions[j]; +						} else { +							//fill from the end +							from[j] = to[j] + c.dirty_regions[j]; +						} + +						for (int k = 0; k < j; k++) { +							// "chip" away previous regions to avoid re-voxelizing the same thing +							if (c.dirty_regions[k] > 0) { +								from[k] += c.dirty_regions[k]; +							} else if (c.dirty_regions[k] < 0) { +								to[k] += c.dirty_regions[k]; +							} +						} + +						r_local_offset = from; +						r_local_size = to - from; + +						r_bounds.position = Vector3(from + Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + c.position) * c.cell_size * Vector3(1, 1.0 / y_mult, 1); +						r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / y_mult, 1); + +						return i; +					} + +					dirty_count++; +				} +			} +		} +	} +	return -1; +} + +void RendererSceneGIRD::SDFGI::update_cascades() { +	//update cascades +	SDFGI::Cascade::UBO cascade_data[SDFGI::MAX_CASCADES]; +	int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR; + +	for (uint32_t i = 0; i < cascades.size(); i++) { +		Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[i].position)) * cascades[i].cell_size; + +		cascade_data[i].offset[0] = pos.x; +		cascade_data[i].offset[1] = pos.y; +		cascade_data[i].offset[2] = pos.z; +		cascade_data[i].to_cell = 1.0 / cascades[i].cell_size; +		cascade_data[i].probe_offset[0] = cascades[i].position.x / probe_divisor; +		cascade_data[i].probe_offset[1] = cascades[i].position.y / probe_divisor; +		cascade_data[i].probe_offset[2] = cascades[i].position.z / probe_divisor; +		cascade_data[i].pad = 0; +	} + +	RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE); +} + +void RendererSceneGIRD::SDFGI::debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture) { +	// !BAS! Need to find a nicer way then adding width/height/renderbuffer/texture as parameters + +	if (!debug_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(debug_uniform_set)) { +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.binding = 1; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { +				if (i < cascades.size()) { +					u.ids.push_back(cascades[i].sdf_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 2; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { +				if (i < cascades.size()) { +					u.ids.push_back(cascades[i].light_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 3; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { +				if (i < cascades.size()) { +					u.ids.push_back(cascades[i].light_aniso_0_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 4; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { +				if (i < cascades.size()) { +					u.ids.push_back(cascades[i].light_aniso_1_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 5; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.ids.push_back(occlusion_texture); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 8; +			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 9; +			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.ids.push_back(cascades_ubo); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 10; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.ids.push_back(p_texture); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 11; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.ids.push_back(lightprobe_texture); +			uniforms.push_back(u); +		} +		debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.debug_shader_version, 0); +	} + +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.debug_pipeline); +	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, debug_uniform_set, 0); + +	SDGIShader::DebugPushConstant push_constant; +	push_constant.grid_size[0] = cascade_size; +	push_constant.grid_size[1] = cascade_size; +	push_constant.grid_size[2] = cascade_size; +	push_constant.max_cascades = cascades.size(); +	push_constant.screen_size[0] = p_width; +	push_constant.screen_size[1] = p_height; +	push_constant.probe_axis_size = probe_axis_count; +	push_constant.use_occlusion = uses_occlusion; +	push_constant.y_mult = y_mult; + +	Vector2 vp_half = p_projection.get_viewport_half_extents(); +	push_constant.cam_extent[0] = vp_half.x; +	push_constant.cam_extent[1] = vp_half.y; +	push_constant.cam_extent[2] = -p_projection.get_z_near(); + +	push_constant.cam_transform[0] = p_transform.basis.elements[0][0]; +	push_constant.cam_transform[1] = p_transform.basis.elements[1][0]; +	push_constant.cam_transform[2] = p_transform.basis.elements[2][0]; +	push_constant.cam_transform[3] = 0; +	push_constant.cam_transform[4] = p_transform.basis.elements[0][1]; +	push_constant.cam_transform[5] = p_transform.basis.elements[1][1]; +	push_constant.cam_transform[6] = p_transform.basis.elements[2][1]; +	push_constant.cam_transform[7] = 0; +	push_constant.cam_transform[8] = p_transform.basis.elements[0][2]; +	push_constant.cam_transform[9] = p_transform.basis.elements[1][2]; +	push_constant.cam_transform[10] = p_transform.basis.elements[2][2]; +	push_constant.cam_transform[11] = 0; +	push_constant.cam_transform[12] = p_transform.origin.x; +	push_constant.cam_transform[13] = p_transform.origin.y; +	push_constant.cam_transform[14] = p_transform.origin.z; +	push_constant.cam_transform[15] = 1; + +	RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DebugPushConstant)); + +	RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_width, p_height, 1); +	RD::get_singleton()->compute_list_end(); + +	Size2 rtsize = storage->render_target_get_size(p_render_target); +	storage->get_effects()->copy_to_fb_rect(p_texture, storage->render_target_get_rd_framebuffer(p_render_target), Rect2(Vector2(), rtsize), true); +} + +void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) { +	SDGIShader::DebugProbesPushConstant push_constant; + +	for (int i = 0; i < 4; i++) { +		for (int j = 0; j < 4; j++) { +			push_constant.projection[i * 4 + j] = p_camera_with_transform.matrix[i][j]; +		} +	} + +	//gen spheres from strips +	uint32_t band_points = 16; +	push_constant.band_power = 4; +	push_constant.sections_in_band = ((band_points / 2) - 1); +	push_constant.band_mask = band_points - 2; +	push_constant.section_arc = Math_TAU / float(push_constant.sections_in_band); +	push_constant.y_mult = y_mult; + +	uint32_t total_points = push_constant.sections_in_band * band_points; +	uint32_t total_probes = probe_axis_count * probe_axis_count * probe_axis_count; + +	push_constant.grid_size[0] = cascade_size; +	push_constant.grid_size[1] = cascade_size; +	push_constant.grid_size[2] = cascade_size; +	push_constant.cascade = 0; + +	push_constant.probe_axis_size = probe_axis_count; + +	if (!debug_probes_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(debug_probes_uniform_set)) { +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.binding = 1; +			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.ids.push_back(cascades_ubo); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 2; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.ids.push_back(lightprobe_texture); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 3; +			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 4; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.ids.push_back(occlusion_texture); +			uniforms.push_back(u); +		} + +		debug_probes_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.debug_probes.version_get_shader(gi->sdfgi_shader.debug_probes_shader, 0), 0); +	} + +	RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, gi->sdfgi_shader.debug_probes_pipeline[SDGIShader::PROBE_DEBUG_PROBES].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); +	RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, debug_probes_uniform_set, 0); +	RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDGIShader::DebugProbesPushConstant)); +	RD::get_singleton()->draw_list_draw(p_draw_list, false, total_probes, total_points); + +	if (gi->sdfgi_debug_probe_dir != Vector3()) { +		print_line("CLICK DEBUG ME?"); +		uint32_t cascade = 0; +		Vector3 offset = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[cascade].position)) * cascades[cascade].cell_size * Vector3(1.0, 1.0 / y_mult, 1.0); +		Vector3 probe_size = cascades[cascade].cell_size * (cascade_size / SDFGI::PROBE_DIVISOR) * Vector3(1.0, 1.0 / y_mult, 1.0); +		Vector3 ray_from = gi->sdfgi_debug_probe_pos; +		Vector3 ray_to = gi->sdfgi_debug_probe_pos + gi->sdfgi_debug_probe_dir * cascades[cascade].cell_size * Math::sqrt(3.0) * cascade_size; +		float sphere_radius = 0.2; +		float closest_dist = 1e20; +		gi->sdfgi_debug_probe_enabled = false; + +		Vector3i probe_from = cascades[cascade].position / (cascade_size / SDFGI::PROBE_DIVISOR); +		for (int i = 0; i < (SDFGI::PROBE_DIVISOR + 1); i++) { +			for (int j = 0; j < (SDFGI::PROBE_DIVISOR + 1); j++) { +				for (int k = 0; k < (SDFGI::PROBE_DIVISOR + 1); k++) { +					Vector3 pos = offset + probe_size * Vector3(i, j, k); +					Vector3 res; +					if (Geometry3D::segment_intersects_sphere(ray_from, ray_to, pos, sphere_radius, &res)) { +						float d = ray_from.distance_to(res); +						if (d < closest_dist) { +							closest_dist = d; +							gi->sdfgi_debug_probe_enabled = true; +							gi->sdfgi_debug_probe_index = probe_from + Vector3i(i, j, k); +						} +					} +				} +			} +		} + +		if (gi->sdfgi_debug_probe_enabled) { +			print_line("found: " + gi->sdfgi_debug_probe_index); +		} else { +			print_line("no found"); +		} +		gi->sdfgi_debug_probe_dir = Vector3(); +	} + +	if (gi->sdfgi_debug_probe_enabled) { +		uint32_t cascade = 0; +		uint32_t probe_cells = (cascade_size / SDFGI::PROBE_DIVISOR); +		Vector3i probe_from = cascades[cascade].position / probe_cells; +		Vector3i ofs = gi->sdfgi_debug_probe_index - probe_from; +		if (ofs.x < 0 || ofs.y < 0 || ofs.z < 0) { +			return; +		} +		if (ofs.x > SDFGI::PROBE_DIVISOR || ofs.y > SDFGI::PROBE_DIVISOR || ofs.z > SDFGI::PROBE_DIVISOR) { +			return; +		} + +		uint32_t mult = (SDFGI::PROBE_DIVISOR + 1); +		uint32_t index = ofs.z * mult * mult + ofs.y * mult + ofs.x; + +		push_constant.probe_debug_index = index; + +		uint32_t cell_count = probe_cells * 2 * probe_cells * 2 * probe_cells * 2; + +		RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, gi->sdfgi_shader.debug_probes_pipeline[SDGIShader::PROBE_DEBUG_VISIBILITY].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); +		RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, debug_probes_uniform_set, 0); +		RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDGIShader::DebugProbesPushConstant)); +		RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, total_points); +	} +} + +void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, RendererSceneRenderRD *p_scene_render) { +	/* Update general SDFGI Buffer */ + +	SDFGIData sdfgi_data; + +	sdfgi_data.grid_size[0] = cascade_size; +	sdfgi_data.grid_size[1] = cascade_size; +	sdfgi_data.grid_size[2] = cascade_size; + +	sdfgi_data.max_cascades = cascades.size(); +	sdfgi_data.probe_axis_size = probe_axis_count; +	sdfgi_data.cascade_probe_size[0] = sdfgi_data.probe_axis_size - 1; //float version for performance +	sdfgi_data.cascade_probe_size[1] = sdfgi_data.probe_axis_size - 1; +	sdfgi_data.cascade_probe_size[2] = sdfgi_data.probe_axis_size - 1; + +	float csize = cascade_size; +	sdfgi_data.probe_to_uvw = 1.0 / float(sdfgi_data.cascade_probe_size[0]); +	sdfgi_data.use_occlusion = uses_occlusion; +	//sdfgi_data.energy = energy; + +	sdfgi_data.y_mult = y_mult; + +	float cascade_voxel_size = (csize / sdfgi_data.cascade_probe_size[0]); +	float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size; +	sdfgi_data.occlusion_clamp[0] = occlusion_clamp; +	sdfgi_data.occlusion_clamp[1] = occlusion_clamp; +	sdfgi_data.occlusion_clamp[2] = occlusion_clamp; +	sdfgi_data.normal_bias = (normal_bias / csize) * sdfgi_data.cascade_probe_size[0]; + +	//vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) ); +	//vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx; + +	uint32_t oct_size = SDFGI::LIGHTPROBE_OCT_SIZE; + +	sdfgi_data.lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size * sdfgi_data.probe_axis_size); +	sdfgi_data.lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size); +	sdfgi_data.lightprobe_tex_pixel_size[2] = 1.0; + +	sdfgi_data.energy = energy; + +	sdfgi_data.lightprobe_uv_offset[0] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[0]; +	sdfgi_data.lightprobe_uv_offset[1] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[1]; +	sdfgi_data.lightprobe_uv_offset[2] = float((oct_size + 2) * sdfgi_data.probe_axis_size) * sdfgi_data.lightprobe_tex_pixel_size[0]; + +	sdfgi_data.occlusion_renormalize[0] = 0.5; +	sdfgi_data.occlusion_renormalize[1] = 1.0; +	sdfgi_data.occlusion_renormalize[2] = 1.0 / float(sdfgi_data.max_cascades); + +	int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR; + +	for (uint32_t i = 0; i < sdfgi_data.max_cascades; i++) { +		SDFGIData::ProbeCascadeData &c = sdfgi_data.cascades[i]; +		Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[i].position)) * cascades[i].cell_size; +		Vector3 cam_origin = p_transform.origin; +		cam_origin.y *= y_mult; +		pos -= cam_origin; //make pos local to camera, to reduce numerical error +		c.position[0] = pos.x; +		c.position[1] = pos.y; +		c.position[2] = pos.z; +		c.to_probe = 1.0 / (float(cascade_size) * cascades[i].cell_size / float(probe_axis_count - 1)); + +		Vector3i probe_ofs = cascades[i].position / probe_divisor; +		c.probe_world_offset[0] = probe_ofs.x; +		c.probe_world_offset[1] = probe_ofs.y; +		c.probe_world_offset[2] = probe_ofs.z; + +		c.to_cell = 1.0 / cascades[i].cell_size; +	} + +	RD::get_singleton()->buffer_update(gi->sdfgi_ubo, 0, sizeof(SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE); + +	/* Update dynamic lights in SDFGI cascades */ + +	for (uint32_t i = 0; i < cascades.size(); i++) { +		SDFGI::Cascade &cascade = cascades[i]; + +		SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; +		uint32_t idx = 0; +		for (uint32_t j = 0; j < (uint32_t)p_scene_render->render_state.sdfgi_update_data->directional_lights->size(); j++) { +			if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { +				break; +			} + +			RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j)); +			ERR_CONTINUE(!li); + +			if (storage->light_directional_is_sky_only(li->light)) { +				continue; +			} + +			Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); +			dir.y *= y_mult; +			dir.normalize(); +			lights[idx].direction[0] = dir.x; +			lights[idx].direction[1] = dir.y; +			lights[idx].direction[2] = dir.z; +			Color color = storage->light_get_color(li->light); +			color = color.to_linear(); +			lights[idx].color[0] = color.r; +			lights[idx].color[1] = color.g; +			lights[idx].color[2] = color.b; +			lights[idx].type = RS::LIGHT_DIRECTIONAL; +			lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); +			lights[idx].has_shadow = storage->light_has_shadow(li->light); + +			idx++; +		} + +		AABB cascade_aabb; +		cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascade.position)) * cascade.cell_size; +		cascade_aabb.size = Vector3(1, 1, 1) * cascade_size * cascade.cell_size; + +		for (uint32_t j = 0; j < p_scene_render->render_state.sdfgi_update_data->positional_light_count; j++) { +			if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { +				break; +			} + +			RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]); +			ERR_CONTINUE(!li); + +			uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); +			if (i > max_sdfgi_cascade) { +				continue; +			} + +			if (!cascade_aabb.intersects(li->aabb)) { +				continue; +			} + +			Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); +			//faster to not do this here +			//dir.y *= y_mult; +			//dir.normalize(); +			lights[idx].direction[0] = dir.x; +			lights[idx].direction[1] = dir.y; +			lights[idx].direction[2] = dir.z; +			Vector3 pos = li->transform.origin; +			pos.y *= y_mult; +			lights[idx].position[0] = pos.x; +			lights[idx].position[1] = pos.y; +			lights[idx].position[2] = pos.z; +			Color color = storage->light_get_color(li->light); +			color = color.to_linear(); +			lights[idx].color[0] = color.r; +			lights[idx].color[1] = color.g; +			lights[idx].color[2] = color.b; +			lights[idx].type = storage->light_get_type(li->light); +			lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); +			lights[idx].has_shadow = storage->light_has_shadow(li->light); +			lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); +			lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); +			lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE))); +			lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + +			idx++; +		} + +		if (idx > 0) { +			RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, RD::BARRIER_MASK_COMPUTE); +		} + +		cascade_dynamic_light_count[i] = idx; +	} +} + +void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render) { +	//print_line("rendering region " + itos(p_region)); +	RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but... +	AABB bounds; +	Vector3i from; +	Vector3i size; + +	int cascade_prev = get_pending_region_data(p_region - 1, from, size, bounds); +	int cascade_next = get_pending_region_data(p_region + 1, from, size, bounds); +	int cascade = get_pending_region_data(p_region, from, size, bounds); +	ERR_FAIL_COND(cascade < 0); + +	if (cascade_prev != cascade) { +		//initialize render +		RD::get_singleton()->texture_clear(render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1); +		RD::get_singleton()->texture_clear(render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1); +		RD::get_singleton()->texture_clear(render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1); +		RD::get_singleton()->texture_clear(render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1); +	} + +	//print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(cascades[cascade].cell_size)); +	p_scene_render->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing); + +	if (cascade_next != cascade) { +		RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade"); + +		RENDER_TIMESTAMP(">SDFGI Update SDF"); +		//done rendering! must update SDF +		//clear dispatch indirect data + +		SDGIShader::PreprocessPushConstant push_constant; +		zeromem(&push_constant, sizeof(SDGIShader::PreprocessPushConstant)); + +		RENDER_TIMESTAMP("Scroll SDF"); + +		//scroll +		if (cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) { +			//for scroll +			Vector3i dirty = cascades[cascade].dirty_regions; +			push_constant.scroll[0] = dirty.x; +			push_constant.scroll[1] = dirty.y; +			push_constant.scroll[2] = dirty.z; +		} else { +			//for no scroll +			push_constant.scroll[0] = 0; +			push_constant.scroll[1] = 0; +			push_constant.scroll[2] = 0; +		} + +		cascades[cascade].all_dynamic_lights_dirty = true; + +		push_constant.grid_size = cascade_size; +		push_constant.cascade = cascade; + +		if (cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) { +			RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + +			//must pre scroll existing data because not all is dirty +			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL]); +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_uniform_set, 0); + +			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +			RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascades[cascade].solid_cell_dispatch_buffer, 0); +			// no barrier do all together + +			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL_OCCLUSION]); +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_occlusion_uniform_set, 0); + +			Vector3i dirty = cascades[cascade].dirty_regions; +			Vector3i groups; +			groups.x = cascade_size - ABS(dirty.x); +			groups.y = cascade_size - ABS(dirty.y); +			groups.z = cascade_size - ABS(dirty.z); + +			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +			RD::get_singleton()->compute_list_dispatch_threads(compute_list, groups.x, groups.y, groups.z); + +			//no barrier, continue together + +			{ +				//scroll probes and their history also + +				SDGIShader::IntegratePushConstant ipush_constant; +				ipush_constant.grid_size[1] = cascade_size; +				ipush_constant.grid_size[2] = cascade_size; +				ipush_constant.grid_size[0] = cascade_size; +				ipush_constant.max_cascades = cascades.size(); +				ipush_constant.probe_axis_size = probe_axis_count; +				ipush_constant.history_index = 0; +				ipush_constant.history_size = history_size; +				ipush_constant.ray_count = 0; +				ipush_constant.ray_bias = 0; +				ipush_constant.sky_mode = 0; +				ipush_constant.sky_energy = 0; +				ipush_constant.sky_color[0] = 0; +				ipush_constant.sky_color[1] = 0; +				ipush_constant.sky_color[2] = 0; +				ipush_constant.y_mult = y_mult; +				ipush_constant.store_ambient_texture = false; + +				ipush_constant.image_size[0] = probe_axis_count * probe_axis_count; +				ipush_constant.image_size[1] = probe_axis_count; + +				int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR; +				ipush_constant.cascade = cascade; +				ipush_constant.world_offset[0] = cascades[cascade].position.x / probe_divisor; +				ipush_constant.world_offset[1] = cascades[cascade].position.y / probe_divisor; +				ipush_constant.world_offset[2] = cascades[cascade].position.z / probe_divisor; + +				ipush_constant.scroll[0] = dirty.x / probe_divisor; +				ipush_constant.scroll[1] = dirty.y / probe_divisor; +				ipush_constant.scroll[2] = dirty.z / probe_divisor; + +				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_SCROLL]); +				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0); +				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1); +				RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); +				RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1); + +				RD::get_singleton()->compute_list_add_barrier(compute_list); + +				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_SCROLL_STORE]); +				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0); +				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1); +				RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); +				RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1); + +				RD::get_singleton()->compute_list_add_barrier(compute_list); + +				if (bounce_feedback > 0.0) { +					//multibounce requires this to be stored so direct light can read from it + +					RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]); + +					//convert to octahedral to store +					ipush_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE; +					ipush_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE; + +					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0); +					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1); +					RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); +					RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1); +				} +			} + +			//ok finally barrier +			RD::get_singleton()->compute_list_end(); +		} + +		//clear dispatch indirect data +		uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 }; +		RD::get_singleton()->buffer_update(cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data); + +		RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + +		bool half_size = true; //much faster, very little difference +		static const int optimized_jf_group_size = 8; + +		if (half_size) { +			push_constant.grid_size >>= 1; + +			uint32_t cascade_half_size = cascade_size >> 1; +			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF]); +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_initialize_half_uniform_set, 0); +			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +			RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size); +			RD::get_singleton()->compute_list_add_barrier(compute_list); + +			//must start with regular jumpflood + +			push_constant.half_size = true; +			{ +				RENDER_TIMESTAMP("SDFGI Jump Flood (Half Size)"); + +				uint32_t s = cascade_half_size; + +				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD]); + +				int jf_us = 0; +				//start with regular jump flood for very coarse reads, as this is impossible to optimize +				while (s > 1) { +					s /= 2; +					push_constant.step_size = s; +					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_half_uniform_set[jf_us], 0); +					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +					RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size); +					RD::get_singleton()->compute_list_add_barrier(compute_list); +					jf_us = jf_us == 0 ? 1 : 0; + +					if (cascade_half_size / (s / 2) >= optimized_jf_group_size) { +						break; +					} +				} + +				RENDER_TIMESTAMP("SDFGI Jump Flood Optimized (Half Size)"); + +				//continue with optimized jump flood for smaller reads +				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]); +				while (s > 1) { +					s /= 2; +					push_constant.step_size = s; +					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_half_uniform_set[jf_us], 0); +					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +					RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size); +					RD::get_singleton()->compute_list_add_barrier(compute_list); +					jf_us = jf_us == 0 ? 1 : 0; +				} +			} + +			// restore grid size for last passes +			push_constant.grid_size = cascade_size; + +			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE]); +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_upscale_uniform_set, 0); +			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +			RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size); +			RD::get_singleton()->compute_list_add_barrier(compute_list); + +			//run one pass of fullsize jumpflood to fix up half size arctifacts + +			push_constant.half_size = false; +			push_constant.step_size = 1; +			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]); +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[upscale_jfa_uniform_set_index], 0); +			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +			RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size); +			RD::get_singleton()->compute_list_add_barrier(compute_list); + +		} else { +			//full size jumpflood +			RENDER_TIMESTAMP("SDFGI Jump Flood"); + +			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE]); +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_initialize_uniform_set, 0); +			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +			RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size); + +			RD::get_singleton()->compute_list_add_barrier(compute_list); + +			push_constant.half_size = false; +			{ +				uint32_t s = cascade_size; + +				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD]); + +				int jf_us = 0; +				//start with regular jump flood for very coarse reads, as this is impossible to optimize +				while (s > 1) { +					s /= 2; +					push_constant.step_size = s; +					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[jf_us], 0); +					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +					RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size); +					RD::get_singleton()->compute_list_add_barrier(compute_list); +					jf_us = jf_us == 0 ? 1 : 0; + +					if (cascade_size / (s / 2) >= optimized_jf_group_size) { +						break; +					} +				} + +				RENDER_TIMESTAMP("SDFGI Jump Flood Optimized"); + +				//continue with optimized jump flood for smaller reads +				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]); +				while (s > 1) { +					s /= 2; +					push_constant.step_size = s; +					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[jf_us], 0); +					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +					RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size); +					RD::get_singleton()->compute_list_add_barrier(compute_list); +					jf_us = jf_us == 0 ? 1 : 0; +				} +			} +		} + +		RENDER_TIMESTAMP("SDFGI Occlusion"); + +		// occlusion +		{ +			uint32_t probe_size = cascade_size / SDFGI::PROBE_DIVISOR; +			Vector3i probe_global_pos = cascades[cascade].position / probe_size; + +			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_OCCLUSION]); +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, occlusion_uniform_set, 0); +			for (int i = 0; i < 8; i++) { +				//dispatch all at once for performance +				Vector3i offset(i & 1, (i >> 1) & 1, (i >> 2) & 1); + +				if ((probe_global_pos.x & 1) != 0) { +					offset.x = (offset.x + 1) & 1; +				} +				if ((probe_global_pos.y & 1) != 0) { +					offset.y = (offset.y + 1) & 1; +				} +				if ((probe_global_pos.z & 1) != 0) { +					offset.z = (offset.z + 1) & 1; +				} +				push_constant.probe_offset[0] = offset.x; +				push_constant.probe_offset[1] = offset.y; +				push_constant.probe_offset[2] = offset.z; +				push_constant.occlusion_index = i; +				RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); + +				Vector3i groups = Vector3i(probe_size + 1, probe_size + 1, probe_size + 1) - offset; //if offset, it's one less probe per axis to compute +				RD::get_singleton()->compute_list_dispatch(compute_list, groups.x, groups.y, groups.z); +			} +			RD::get_singleton()->compute_list_add_barrier(compute_list); +		} + +		RENDER_TIMESTAMP("SDFGI Store"); + +		// store +		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_STORE]); +		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].sdf_store_uniform_set, 0); +		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); +		RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size); + +		RD::get_singleton()->compute_list_end(); + +		//clear these textures, as they will have previous garbage on next draw +		RD::get_singleton()->texture_clear(cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); +		RD::get_singleton()->texture_clear(cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); +		RD::get_singleton()->texture_clear(cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); + +#if 0 +		Vector<uint8_t> data = RD::get_singleton()->texture_get_data(cascades[cascade].sdf, 0); +		Ref<Image> img; +		img.instance(); +		for (uint32_t i = 0; i < cascade_size; i++) { +			Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1); +			img->create(cascade_size, cascade_size, false, Image::FORMAT_L8, subarr); +			img->save_png("res://cascade_sdf_" + itos(cascade) + "_" + itos(i) + ".png"); +		} + +		//finalize render and update sdf +#endif + +#if 0 +		Vector<uint8_t> data = RD::get_singleton()->texture_get_data(render_albedo, 0); +		Ref<Image> img; +		img.instance(); +		for (uint32_t i = 0; i < cascade_size; i++) { +			Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1); +			img->createcascade_size, cascade_size, false, Image::FORMAT_RGB565, subarr); +			img->convert(Image::FORMAT_RGBA8); +			img->save_png("res://cascade_" + itos(cascade) + "_" + itos(i) + ".png"); +		} + +		//finalize render and update sdf +#endif + +		RENDER_TIMESTAMP("<SDFGI Update SDF"); +		RD::get_singleton()->draw_command_end_label(); +	} +} + +void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render) { +	RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but... + +	RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lighs"); + +	update_cascades(); +	; //need cascades updated for this + +	SDGIShader::Light lights[SDFGI::MAX_STATIC_LIGHTS]; +	uint32_t light_count[SDFGI::MAX_STATIC_LIGHTS]; + +	for (uint32_t i = 0; i < p_cascade_count; i++) { +		ERR_CONTINUE(p_cascade_indices[i] >= cascades.size()); + +		SDFGI::Cascade &cc = cascades[p_cascade_indices[i]]; + +		{ //fill light buffer + +			AABB cascade_aabb; +			cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cc.position)) * cc.cell_size; +			cascade_aabb.size = Vector3(1, 1, 1) * cascade_size * cc.cell_size; + +			int idx = 0; + +			for (uint32_t j = 0; j < (uint32_t)p_positional_light_cull_result[i].size(); j++) { +				if (idx == SDFGI::MAX_STATIC_LIGHTS) { +					break; +				} + +				RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_positional_light_cull_result[i][j]); +				ERR_CONTINUE(!li); + +				uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); +				if (p_cascade_indices[i] > max_sdfgi_cascade) { +					continue; +				} + +				if (!cascade_aabb.intersects(li->aabb)) { +					continue; +				} + +				lights[idx].type = storage->light_get_type(li->light); + +				Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); +				if (lights[idx].type == RS::LIGHT_DIRECTIONAL) { +					dir.y *= y_mult; //only makes sense for directional +					dir.normalize(); +				} +				lights[idx].direction[0] = dir.x; +				lights[idx].direction[1] = dir.y; +				lights[idx].direction[2] = dir.z; +				Vector3 pos = li->transform.origin; +				pos.y *= y_mult; +				lights[idx].position[0] = pos.x; +				lights[idx].position[1] = pos.y; +				lights[idx].position[2] = pos.z; +				Color color = storage->light_get_color(li->light); +				color = color.to_linear(); +				lights[idx].color[0] = color.r; +				lights[idx].color[1] = color.g; +				lights[idx].color[2] = color.b; +				lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); +				lights[idx].has_shadow = storage->light_has_shadow(li->light); +				lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); +				lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); +				lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE))); +				lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + +				idx++; +			} + +			if (idx > 0) { +				RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights); +			} + +			light_count[i] = idx; +		} +	} + +	/* Static Lights */ +	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + +	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_STATIC]); + +	SDGIShader::DirectLightPushConstant dl_push_constant; + +	dl_push_constant.grid_size[0] = cascade_size; +	dl_push_constant.grid_size[1] = cascade_size; +	dl_push_constant.grid_size[2] = cascade_size; +	dl_push_constant.max_cascades = cascades.size(); +	dl_push_constant.probe_axis_size = probe_axis_count; +	dl_push_constant.bounce_feedback = 0.0; // this is static light, do not multibounce yet +	dl_push_constant.y_mult = y_mult; +	dl_push_constant.use_occlusion = uses_occlusion; + +	//all must be processed +	dl_push_constant.process_offset = 0; +	dl_push_constant.process_increment = 1; + +	for (uint32_t i = 0; i < p_cascade_count; i++) { +		ERR_CONTINUE(p_cascade_indices[i] >= cascades.size()); + +		SDFGI::Cascade &cc = cascades[p_cascade_indices[i]]; + +		dl_push_constant.light_count = light_count[i]; +		dl_push_constant.cascade = p_cascade_indices[i]; + +		if (dl_push_constant.light_count > 0) { +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cc.sdf_direct_light_uniform_set, 0); +			RD::get_singleton()->compute_list_set_push_constant(compute_list, &dl_push_constant, sizeof(SDGIShader::DirectLightPushConstant)); +			RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer, 0); +		} +	} + +	RD::get_singleton()->compute_list_end(); + +	RD::get_singleton()->draw_command_end_label(); +} + +//////////////////////////////////////////////////////////////////////////////// +// GIProbeInstance + +void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) { +	uint32_t data_version = storage->gi_probe_get_data_version(probe); + +	// (RE)CREATE IF NEEDED + +	if (last_probe_data_version != data_version) { +		//need to re-create everything +		if (texture.is_valid()) { +			RD::get_singleton()->free(texture); +			RD::get_singleton()->free(write_buffer); +			mipmaps.clear(); +		} + +		for (int i = 0; i < dynamic_maps.size(); i++) { +			RD::get_singleton()->free(dynamic_maps[i].texture); +			RD::get_singleton()->free(dynamic_maps[i].depth); +		} + +		dynamic_maps.clear(); + +		Vector3i octree_size = storage->gi_probe_get_octree_size(probe); + +		if (octree_size != Vector3i()) { +			//can create a 3D texture +			Vector<int> levels = storage->gi_probe_get_level_counts(probe); + +			RD::TextureFormat tf; +			tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; +			tf.width = octree_size.x; +			tf.height = octree_size.y; +			tf.depth = octree_size.z; +			tf.texture_type = RD::TEXTURE_TYPE_3D; +			tf.mipmaps = levels.size(); + +			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + +			texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + +			RD::get_singleton()->texture_clear(texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1); + +			{ +				int total_elements = 0; +				for (int i = 0; i < levels.size(); i++) { +					total_elements += levels[i]; +				} + +				write_buffer = RD::get_singleton()->storage_buffer_create(total_elements * 16); +			} + +			for (int i = 0; i < levels.size(); i++) { +				GIProbeInstance::Mipmap mipmap; +				mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, RD::TEXTURE_SLICE_3D); +				mipmap.level = levels.size() - i - 1; +				mipmap.cell_offset = 0; +				for (uint32_t j = 0; j < mipmap.level; j++) { +					mipmap.cell_offset += levels[j]; +				} +				mipmap.cell_count = levels[mipmap.level]; + +				Vector<RD::Uniform> uniforms; +				{ +					RD::Uniform u; +					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +					u.binding = 1; +					u.ids.push_back(storage->gi_probe_get_octree_buffer(probe)); +					uniforms.push_back(u); +				} +				{ +					RD::Uniform u; +					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +					u.binding = 2; +					u.ids.push_back(storage->gi_probe_get_data_buffer(probe)); +					uniforms.push_back(u); +				} + +				{ +					RD::Uniform u; +					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +					u.binding = 4; +					u.ids.push_back(write_buffer); +					uniforms.push_back(u); +				} +				{ +					RD::Uniform u; +					u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +					u.binding = 9; +					u.ids.push_back(storage->gi_probe_get_sdf_texture(probe)); +					uniforms.push_back(u); +				} +				{ +					RD::Uniform u; +					u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +					u.binding = 10; +					u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +					uniforms.push_back(u); +				} + +				{ +					Vector<RD::Uniform> copy_uniforms = uniforms; +					if (i == 0) { +						{ +							RD::Uniform u; +							u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +							u.binding = 3; +							u.ids.push_back(gi->gi_probe_lights_uniform); +							copy_uniforms.push_back(u); +						} + +						mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0); + +						copy_uniforms = uniforms; //restore + +						{ +							RD::Uniform u; +							u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +							u.binding = 5; +							u.ids.push_back(texture); +							copy_uniforms.push_back(u); +						} +						mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0); +					} else { +						mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0); +					} +				} + +				{ +					RD::Uniform u; +					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +					u.binding = 5; +					u.ids.push_back(mipmap.texture); +					uniforms.push_back(u); +				} + +				mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0); + +				mipmaps.push_back(mipmap); +			} + +			{ +				uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z); +				uint32_t oversample = nearest_power_of_2_templated(4); +				int mipmap_index = 0; + +				while (mipmap_index < mipmaps.size()) { +					GIProbeInstance::DynamicMap dmap; + +					if (oversample > 0) { +						dmap.size = dynamic_map_size * (1 << oversample); +						dmap.mipmap = -1; +						oversample--; +					} else { +						dmap.size = dynamic_map_size >> mipmap_index; +						dmap.mipmap = mipmap_index; +						mipmap_index++; +					} + +					RD::TextureFormat dtf; +					dtf.width = dmap.size; +					dtf.height = dmap.size; +					dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; +					dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + +					if (dynamic_maps.size() == 0) { +						dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; +					} +					dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + +					if (dynamic_maps.size() == 0) { +						//render depth for first one +						dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; +						dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; +						dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView()); +					} + +					//just use depth as-is +					dtf.format = RD::DATA_FORMAT_R32_SFLOAT; +					dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + +					dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + +					if (dynamic_maps.size() == 0) { +						dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; +						dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; +						dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView()); +						dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView()); +						dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView()); + +						Vector<RID> fb; +						fb.push_back(dmap.albedo); +						fb.push_back(dmap.normal); +						fb.push_back(dmap.orm); +						fb.push_back(dmap.texture); //emission +						fb.push_back(dmap.depth); +						fb.push_back(dmap.fb_depth); + +						dmap.fb = RD::get_singleton()->framebuffer_create(fb); + +						{ +							Vector<RD::Uniform> uniforms; +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +								u.binding = 3; +								u.ids.push_back(gi->gi_probe_lights_uniform); +								uniforms.push_back(u); +							} + +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +								u.binding = 5; +								u.ids.push_back(dmap.albedo); +								uniforms.push_back(u); +							} +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +								u.binding = 6; +								u.ids.push_back(dmap.normal); +								uniforms.push_back(u); +							} +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +								u.binding = 7; +								u.ids.push_back(dmap.orm); +								uniforms.push_back(u); +							} +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +								u.binding = 8; +								u.ids.push_back(dmap.fb_depth); +								uniforms.push_back(u); +							} +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +								u.binding = 9; +								u.ids.push_back(storage->gi_probe_get_sdf_texture(probe)); +								uniforms.push_back(u); +							} +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +								u.binding = 10; +								u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +								uniforms.push_back(u); +							} +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +								u.binding = 11; +								u.ids.push_back(dmap.texture); +								uniforms.push_back(u); +							} +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +								u.binding = 12; +								u.ids.push_back(dmap.depth); +								uniforms.push_back(u); +							} + +							dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0); +						} +					} else { +						bool plot = dmap.mipmap >= 0; +						bool write = dmap.mipmap < (mipmaps.size() - 1); + +						Vector<RD::Uniform> uniforms; + +						{ +							RD::Uniform u; +							u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +							u.binding = 5; +							u.ids.push_back(dynamic_maps[dynamic_maps.size() - 1].texture); +							uniforms.push_back(u); +						} +						{ +							RD::Uniform u; +							u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +							u.binding = 6; +							u.ids.push_back(dynamic_maps[dynamic_maps.size() - 1].depth); +							uniforms.push_back(u); +						} + +						if (write) { +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +								u.binding = 7; +								u.ids.push_back(dmap.texture); +								uniforms.push_back(u); +							} +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +								u.binding = 8; +								u.ids.push_back(dmap.depth); +								uniforms.push_back(u); +							} +						} + +						{ +							RD::Uniform u; +							u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +							u.binding = 9; +							u.ids.push_back(storage->gi_probe_get_sdf_texture(probe)); +							uniforms.push_back(u); +						} +						{ +							RD::Uniform u; +							u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +							u.binding = 10; +							u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +							uniforms.push_back(u); +						} + +						if (plot) { +							{ +								RD::Uniform u; +								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +								u.binding = 11; +								u.ids.push_back(mipmaps[dmap.mipmap].texture); +								uniforms.push_back(u); +							} +						} + +						dmap.uniform_set = RD::get_singleton()->uniform_set_create( +								uniforms, +								gi->giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)], +								0); +					} + +					dynamic_maps.push_back(dmap); +				} +			} +		} + +		last_probe_data_version = data_version; +		p_update_light_instances = true; //just in case + +		p_scene_render->_base_uniforms_changed(); +	} + +	// UDPDATE TIME + +	if (has_dynamic_object_data) { +		//if it has dynamic object data, it needs to be cleared +		RD::get_singleton()->texture_clear(texture, Color(0, 0, 0, 0), 0, mipmaps.size(), 0, 1); +	} + +	uint32_t light_count = 0; + +	if (p_update_light_instances || p_dynamic_objects.size() > 0) { +		light_count = MIN(gi->gi_probe_max_lights, (uint32_t)p_light_instances.size()); + +		{ +			Transform to_cell = storage->gi_probe_get_to_cell_xform(probe); +			Transform to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse(); +			//update lights + +			for (uint32_t i = 0; i < light_count; i++) { +				GIProbeLight &l = gi->gi_probe_lights[i]; +				RID light_instance = p_light_instances[i]; +				RID light = p_scene_render->light_instance_get_base_light(light_instance); + +				l.type = storage->light_get_type(light); +				if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) { +					light_count--; +					continue; +				} + +				l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION); +				l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY); +				l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length(); +				Color color = storage->light_get_color(light).to_linear(); +				l.color[0] = color.r; +				l.color[1] = color.g; +				l.color[2] = color.b; + +				l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE))); +				l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION); + +				Transform xform = p_scene_render->light_instance_get_base_transform(light_instance); + +				Vector3 pos = to_probe_xform.xform(xform.origin); +				Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized(); + +				l.position[0] = pos.x; +				l.position[1] = pos.y; +				l.position[2] = pos.z; + +				l.direction[0] = dir.x; +				l.direction[1] = dir.y; +				l.direction[2] = dir.z; + +				l.has_shadow = storage->light_has_shadow(light); +			} + +			RD::get_singleton()->buffer_update(gi->gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi->gi_probe_lights); +		} +	} + +	if (has_dynamic_object_data || p_update_light_instances || p_dynamic_objects.size()) { +		// PROCESS MIPMAPS +		if (mipmaps.size()) { +			//can update mipmaps + +			Vector3i probe_size = storage->gi_probe_get_octree_size(probe); + +			GIProbePushConstant push_constant; + +			push_constant.limits[0] = probe_size.x; +			push_constant.limits[1] = probe_size.y; +			push_constant.limits[2] = probe_size.z; +			push_constant.stack_size = mipmaps.size(); +			push_constant.emission_scale = 1.0; +			push_constant.propagation = storage->gi_probe_get_propagation(probe); +			push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe); +			push_constant.light_count = light_count; +			push_constant.aniso_strength = 0; + +			/*		print_line("probe update to version " + itos(last_probe_version)); +			print_line("propagation " + rtos(push_constant.propagation)); +			print_line("dynrange " + rtos(push_constant.dynamic_range)); +	*/ +			RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + +			int passes; +			if (p_update_light_instances) { +				passes = storage->gi_probe_is_using_two_bounces(probe) ? 2 : 1; +			} else { +				passes = 1; //only re-blitting is necessary +			} +			int wg_size = 64; +			int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X); + +			for (int pass = 0; pass < passes; pass++) { +				if (p_update_light_instances) { +					for (int i = 0; i < mipmaps.size(); i++) { +						if (i == 0) { +							RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]); +						} else if (i == 1) { +							RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]); +						} + +						if (pass == 1 || i > 0) { +							RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done +						} +						if (pass == 0 || i > 0) { +							RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].uniform_set, 0); +						} else { +							RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].second_bounce_uniform_set, 0); +						} + +						push_constant.cell_offset = mipmaps[i].cell_offset; +						push_constant.cell_count = mipmaps[i].cell_count; + +						int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1; +						while (wg_todo) { +							int wg_count = MIN(wg_todo, wg_limit_x); +							RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); +							RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); +							wg_todo -= wg_count; +							push_constant.cell_offset += wg_count * wg_size; +						} +					} + +					RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done +				} + +				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]); + +				for (int i = 0; i < mipmaps.size(); i++) { +					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].write_uniform_set, 0); + +					push_constant.cell_offset = mipmaps[i].cell_offset; +					push_constant.cell_count = mipmaps[i].cell_count; + +					int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1; +					while (wg_todo) { +						int wg_count = MIN(wg_todo, wg_limit_x); +						RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); +						RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); +						wg_todo -= wg_count; +						push_constant.cell_offset += wg_count * wg_size; +					} +				} +			} + +			RD::get_singleton()->compute_list_end(); +		} +	} + +	has_dynamic_object_data = false; //clear until dynamic object data is used again + +	if (p_dynamic_objects.size() && dynamic_maps.size()) { +		Vector3i octree_size = storage->gi_probe_get_octree_size(probe); +		int multiplier = dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z); + +		Transform oversample_scale; +		oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier)); + +		Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(probe); +		Transform to_world_xform = transform * to_cell.affine_inverse(); +		Transform to_probe_xform = to_world_xform.affine_inverse(); + +		AABB probe_aabb(Vector3(), octree_size); + +		//this could probably be better parallelized in compute.. +		for (int i = 0; i < (int)p_dynamic_objects.size(); i++) { +			RendererSceneRender::GeometryInstance *instance = p_dynamic_objects[i]; + +			//transform aabb to giprobe +			AABB aabb = (to_probe_xform * p_scene_render->geometry_instance_get_transform(instance)).xform(p_scene_render->geometry_instance_get_aabb(instance)); + +			//this needs to wrap to grid resolution to avoid jitter +			//also extend margin a bit just in case +			Vector3i begin = aabb.position - Vector3i(1, 1, 1); +			Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1); + +			for (int j = 0; j < 3; j++) { +				if ((end[j] - begin[j]) & 1) { +					end[j]++; //for half extents split, it needs to be even +				} +				begin[j] = MAX(begin[j], 0); +				end[j] = MIN(end[j], octree_size[j] * multiplier); +			} + +			//aabb = aabb.intersection(probe_aabb); //intersect +			aabb.position = begin; +			aabb.size = end - begin; + +			//print_line("aabb: " + aabb); + +			for (int j = 0; j < 6; j++) { +				//if (j != 0 && j != 3) { +				//	continue; +				//} +				static const Vector3 render_z[6] = { +					Vector3(1, 0, 0), +					Vector3(0, 1, 0), +					Vector3(0, 0, 1), +					Vector3(-1, 0, 0), +					Vector3(0, -1, 0), +					Vector3(0, 0, -1), +				}; +				static const Vector3 render_up[6] = { +					Vector3(0, 1, 0), +					Vector3(0, 0, 1), +					Vector3(0, 1, 0), +					Vector3(0, 1, 0), +					Vector3(0, 0, 1), +					Vector3(0, 1, 0), +				}; + +				Vector3 render_dir = render_z[j]; +				Vector3 up_dir = render_up[j]; + +				Vector3 center = aabb.position + aabb.size * 0.5; +				Transform xform; +				xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir); + +				Vector3 x_dir = xform.basis.get_axis(0).abs(); +				int x_axis = int(Vector3(0, 1, 2).dot(x_dir)); +				Vector3 y_dir = xform.basis.get_axis(1).abs(); +				int y_axis = int(Vector3(0, 1, 2).dot(y_dir)); +				Vector3 z_dir = -xform.basis.get_axis(2); +				int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs())); + +				Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]); +				bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0); +				bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0); +				bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0); + +				CameraMatrix cm; +				cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]); + +				if (p_scene_render->cull_argument.size() == 0) { +					p_scene_render->cull_argument.push_back(nullptr); +				} +				p_scene_render->cull_argument[0] = instance; + +				p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); + +				GIProbeDynamicPushConstant push_constant; +				zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant)); +				push_constant.limits[0] = octree_size.x; +				push_constant.limits[1] = octree_size.y; +				push_constant.limits[2] = octree_size.z; +				push_constant.light_count = p_light_instances.size(); +				push_constant.x_dir[0] = x_dir[0]; +				push_constant.x_dir[1] = x_dir[1]; +				push_constant.x_dir[2] = x_dir[2]; +				push_constant.y_dir[0] = y_dir[0]; +				push_constant.y_dir[1] = y_dir[1]; +				push_constant.y_dir[2] = y_dir[2]; +				push_constant.z_dir[0] = z_dir[0]; +				push_constant.z_dir[1] = z_dir[1]; +				push_constant.z_dir[2] = z_dir[2]; +				push_constant.z_base = xform.origin[z_axis]; +				push_constant.z_sign = (z_flip ? -1.0 : 1.0); +				push_constant.pos_multiplier = float(1.0) / multiplier; +				push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe); +				push_constant.flip_x = x_flip; +				push_constant.flip_y = y_flip; +				push_constant.rect_pos[0] = rect.position[0]; +				push_constant.rect_pos[1] = rect.position[1]; +				push_constant.rect_size[0] = rect.size[0]; +				push_constant.rect_size[1] = rect.size[1]; +				push_constant.prev_rect_ofs[0] = 0; +				push_constant.prev_rect_ofs[1] = 0; +				push_constant.prev_rect_size[0] = 0; +				push_constant.prev_rect_size[1] = 0; +				push_constant.on_mipmap = false; +				push_constant.propagation = storage->gi_probe_get_propagation(probe); +				push_constant.pad[0] = 0; +				push_constant.pad[1] = 0; +				push_constant.pad[2] = 0; + +				//process lighting +				RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); +				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]); +				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[0].uniform_set, 0); +				RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant)); +				RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); +				//print_line("rect: " + itos(i) + ": " + rect); + +				for (int k = 1; k < dynamic_maps.size(); k++) { +					// enlarge the rect if needed so all pixels fit when downscaled, +					// this ensures downsampling is smooth and optimal because no pixels are left behind + +					//x +					if (rect.position.x & 1) { +						rect.size.x++; +						push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal +					} else { +						push_constant.prev_rect_ofs[0] = 0; +					} +					if (rect.size.x & 1) { +						rect.size.x++; +					} + +					rect.position.x >>= 1; +					rect.size.x = MAX(1, rect.size.x >> 1); + +					//y +					if (rect.position.y & 1) { +						rect.size.y++; +						push_constant.prev_rect_ofs[1] = 1; +					} else { +						push_constant.prev_rect_ofs[1] = 0; +					} +					if (rect.size.y & 1) { +						rect.size.y++; +					} + +					rect.position.y >>= 1; +					rect.size.y = MAX(1, rect.size.y >> 1); + +					//shrink limits to ensure plot does not go outside map +					if (dynamic_maps[k].mipmap > 0) { +						for (int l = 0; l < 3; l++) { +							push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1); +						} +					} + +					//print_line("rect: " + itos(i) + ": " + rect); +					push_constant.rect_pos[0] = rect.position[0]; +					push_constant.rect_pos[1] = rect.position[1]; +					push_constant.prev_rect_size[0] = push_constant.rect_size[0]; +					push_constant.prev_rect_size[1] = push_constant.rect_size[1]; +					push_constant.rect_size[0] = rect.size[0]; +					push_constant.rect_size[1] = rect.size[1]; +					push_constant.on_mipmap = dynamic_maps[k].mipmap > 0; + +					RD::get_singleton()->compute_list_add_barrier(compute_list); + +					if (dynamic_maps[k].mipmap < 0) { +						RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]); +					} else if (k < dynamic_maps.size() - 1) { +						RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]); +					} else { +						RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]); +					} +					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[k].uniform_set, 0); +					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant)); +					RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); +				} + +				RD::get_singleton()->compute_list_end(); +			} +		} + +		has_dynamic_object_data = true; //clear until dynamic object data is used again +	} + +	last_probe_version = storage->gi_probe_get_version(probe); +} + +void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { +	if (mipmaps.size() == 0) { +		return; +	} + +	CameraMatrix cam_transform = (p_camera_with_transform * CameraMatrix(transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(probe).affine_inverse()); + +	int level = 0; +	Vector3i octree_size = storage->gi_probe_get_octree_size(probe); + +	GIProbeDebugPushConstant push_constant; +	push_constant.alpha = p_alpha; +	push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe); +	push_constant.cell_offset = mipmaps[level].cell_offset; +	push_constant.level = level; + +	push_constant.bounds[0] = octree_size.x >> level; +	push_constant.bounds[1] = octree_size.y >> level; +	push_constant.bounds[2] = octree_size.z >> level; +	push_constant.pad = 0; + +	for (int i = 0; i < 4; i++) { +		for (int j = 0; j < 4; j++) { +			push_constant.projection[i * 4 + j] = cam_transform.matrix[i][j]; +		} +	} + +	if (gi->giprobe_debug_uniform_set.is_valid()) { +		RD::get_singleton()->free(gi->giprobe_debug_uniform_set); +	} +	Vector<RD::Uniform> uniforms; +	{ +		RD::Uniform u; +		u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +		u.binding = 1; +		u.ids.push_back(storage->gi_probe_get_data_buffer(probe)); +		uniforms.push_back(u); +	} +	{ +		RD::Uniform u; +		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +		u.binding = 2; +		u.ids.push_back(texture); +		uniforms.push_back(u); +	} +	{ +		RD::Uniform u; +		u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +		u.binding = 3; +		u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +		uniforms.push_back(u); +	} + +	int cell_count; +	if (!p_emission && p_lighting && has_dynamic_object_data) { +		cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2]; +	} else { +		cell_count = mipmaps[level].cell_count; +	} + +	gi->giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_debug_shader_version_shaders[0], 0); + +	int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR; +	if (p_emission) { +		giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION; +	} else if (p_lighting) { +		giprobe_debug_pipeline = has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT; +	} +	RD::get_singleton()->draw_list_bind_render_pipeline( +			p_draw_list, +			gi->giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); +	RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, gi->giprobe_debug_uniform_set, 0); +	RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant)); +	RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36); +} + +//////////////////////////////////////////////////////////////////////////////// +// GIRD + +RendererSceneGIRD::RendererSceneGIRD() { +	sdfgi_ray_count = RS::EnvironmentSDFGIRayCount(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/probe_ray_count")), 0, int32_t(RS::ENV_SDFGI_RAY_COUNT_MAX - 1))); +	sdfgi_frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_converge")), 0, int32_t(RS::ENV_SDFGI_CONVERGE_MAX - 1))); +	sdfgi_frames_to_update_light = RS::EnvironmentSDFGIFramesToUpdateLight(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_update_lights")), 0, int32_t(RS::ENV_SDFGI_UPDATE_LIGHT_MAX - 1))); +} + +RendererSceneGIRD::~RendererSceneGIRD() { +} + +void RendererSceneGIRD::init_gi(RendererStorageRD *p_storage) { +	storage = p_storage; + +	{ +		//kinda complicated to compute the amount of slots, we try to use as many as we can + +		gi_probe_max_lights = 32; + +		gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights); +		gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight)); +		gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")), 0, 1)); + +		String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n"; + +		Vector<String> versions; +		versions.push_back("\n#define MODE_COMPUTE_LIGHT\n"); +		versions.push_back("\n#define MODE_SECOND_BOUNCE\n"); +		versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n"); +		versions.push_back("\n#define MODE_WRITE_TEXTURE\n"); +		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n"); +		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n"); +		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n"); +		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n"); + +		giprobe_shader.initialize(versions, defines); +		giprobe_lighting_shader_version = giprobe_shader.version_create(); +		for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) { +			giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i); +			giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]); +		} +	} + +	{ +		String defines; +		Vector<String> versions; +		versions.push_back("\n#define MODE_DEBUG_COLOR\n"); +		versions.push_back("\n#define MODE_DEBUG_LIGHT\n"); +		versions.push_back("\n#define MODE_DEBUG_EMISSION\n"); +		versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n"); + +		giprobe_debug_shader.initialize(versions, defines); +		giprobe_debug_shader_version = giprobe_debug_shader.version_create(); +		for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) { +			giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i); + +			RD::PipelineRasterizationState rs; +			rs.cull_mode = RD::POLYGON_CULL_FRONT; +			RD::PipelineDepthStencilState ds; +			ds.enable_depth_test = true; +			ds.enable_depth_write = true; +			ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + +			giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); +		} +	} +} + +void RendererSceneGIRD::init_sdfgi(RendererSceneSkyRD *p_sky) { +	{ +		Vector<String> preprocess_modes; +		preprocess_modes.push_back("\n#define MODE_SCROLL\n"); +		preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n"); +		preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n"); +		preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n"); +		preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n"); +		preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n"); +		preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n"); +		preprocess_modes.push_back("\n#define MODE_OCCLUSION\n"); +		preprocess_modes.push_back("\n#define MODE_STORE\n"); +		String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n"; +		sdfgi_shader.preprocess.initialize(preprocess_modes, defines); +		sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create(); +		for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) { +			sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i)); +		} +	} + +	{ +		//calculate tables +		String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + +		Vector<String> direct_light_modes; +		direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n"); +		direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n"); +		sdfgi_shader.direct_light.initialize(direct_light_modes, defines); +		sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create(); +		for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) { +			sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i)); +		} +	} + +	{ +		//calculate tables +		String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; +		defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n"; +		if (p_sky->sky_use_cubemap_array) { +			defines += "\n#define USE_CUBEMAP_ARRAY\n"; +		} + +		Vector<String> integrate_modes; +		integrate_modes.push_back("\n#define MODE_PROCESS\n"); +		integrate_modes.push_back("\n#define MODE_STORE\n"); +		integrate_modes.push_back("\n#define MODE_SCROLL\n"); +		integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n"); +		sdfgi_shader.integrate.initialize(integrate_modes, defines); +		sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create(); + +		for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) { +			sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i)); +		} + +		{ +			Vector<RD::Uniform> uniforms; + +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +				u.binding = 0; +				u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); +				uniforms.push_back(u); +			} +			{ +				RD::Uniform u; +				u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +				u.binding = 1; +				u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +				uniforms.push_back(u); +			} + +			sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1); +		} +	} + +	//GK +	{ +		//calculate tables +		String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; +		Vector<String> gi_modes; +		gi_modes.push_back("\n#define USE_GIPROBES\n"); +		gi_modes.push_back("\n#define USE_SDFGI\n"); +		gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); +		gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n"); +		gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n"); +		gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); + +		shader.initialize(gi_modes, defines); +		shader_version = shader.version_create(); +		for (int i = 0; i < MODE_MAX; i++) { +			pipelines[i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, i)); +		} + +		sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGIData)); +	} +	{ +		String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; +		Vector<String> debug_modes; +		debug_modes.push_back(""); +		sdfgi_shader.debug.initialize(debug_modes, defines); +		sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create(); +		sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0); +		sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version); +	} +	{ +		String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + +		Vector<String> versions; +		versions.push_back("\n#define MODE_PROBES\n"); +		versions.push_back("\n#define MODE_VISIBILITY\n"); + +		sdfgi_shader.debug_probes.initialize(versions, defines); +		sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create(); + +		{ +			RD::PipelineRasterizationState rs; +			rs.cull_mode = RD::POLYGON_CULL_DISABLED; +			RD::PipelineDepthStencilState ds; +			ds.enable_depth_test = true; +			ds.enable_depth_write = true; +			ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; +			for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) { +				RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i); +				sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); +			} +		} +	} +	default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES); +} + +void RendererSceneGIRD::free() { +	RD::get_singleton()->free(default_giprobe_buffer); +	RD::get_singleton()->free(gi_probe_lights_uniform); +	RD::get_singleton()->free(sdfgi_ubo); + +	giprobe_debug_shader.version_free(giprobe_debug_shader_version); +	giprobe_shader.version_free(giprobe_lighting_shader_version); +	shader.version_free(shader_version); +	sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader); +	sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader); +	sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader); +	sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader); +	sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); + +	memdelete_arr(gi_probe_lights); +} + +RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size) { +	SDFGI *sdfgi = memnew(SDFGI); + +	sdfgi->create(p_env, p_world_position, p_requested_history_size, this); + +	return sdfgi; +} + +void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render) { +	r_gi_probes_used = 0; + +	// feels a little dirty to use our container this way but.... +	RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND(rb == nullptr); + +	RID gi_probe_buffer = p_scene_render->render_buffers_get_gi_probe_buffer(p_render_buffers); + +	RD::get_singleton()->draw_command_begin_label("GIProbes Setup"); + +	GIProbeData gi_probe_data[MAX_GIPROBES]; + +	bool giprobes_changed = false; + +	Transform to_camera; +	to_camera.origin = p_transform.origin; //only translation, make local + +	for (int i = 0; i < MAX_GIPROBES; i++) { +		RID texture; +		if (i < (int)p_gi_probes.size()) { +			GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probes[i]); + +			if (gipi) { +				texture = gipi->texture; +				GIProbeData &gipd = gi_probe_data[i]; + +				RID base_probe = gipi->probe; + +				Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera; + +				gipd.xform[0] = to_cell.basis.elements[0][0]; +				gipd.xform[1] = to_cell.basis.elements[1][0]; +				gipd.xform[2] = to_cell.basis.elements[2][0]; +				gipd.xform[3] = 0; +				gipd.xform[4] = to_cell.basis.elements[0][1]; +				gipd.xform[5] = to_cell.basis.elements[1][1]; +				gipd.xform[6] = to_cell.basis.elements[2][1]; +				gipd.xform[7] = 0; +				gipd.xform[8] = to_cell.basis.elements[0][2]; +				gipd.xform[9] = to_cell.basis.elements[1][2]; +				gipd.xform[10] = to_cell.basis.elements[2][2]; +				gipd.xform[11] = 0; +				gipd.xform[12] = to_cell.origin.x; +				gipd.xform[13] = to_cell.origin.y; +				gipd.xform[14] = to_cell.origin.z; +				gipd.xform[15] = 1; + +				Vector3 bounds = storage->gi_probe_get_octree_size(base_probe); + +				gipd.bounds[0] = bounds.x; +				gipd.bounds[1] = bounds.y; +				gipd.bounds[2] = bounds.z; + +				gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe); +				gipd.bias = storage->gi_probe_get_bias(base_probe); +				gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe); +				gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe); +				gipd.anisotropy_strength = 0; +				gipd.ao = storage->gi_probe_get_ao(base_probe); +				gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f); +				gipd.mipmaps = gipi->mipmaps.size(); +			} + +			r_gi_probes_used++; +		} + +		if (texture == RID()) { +			texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); +		} + +		if (texture != rb->gi.giprobe_textures[i]) { +			giprobes_changed = true; +			rb->gi.giprobe_textures[i] = texture; +		} +	} + +	if (giprobes_changed) { +		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(); +		if (rb->volumetric_fog) { +			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_set2); +			} +			rb->volumetric_fog->uniform_set = RID(); +			rb->volumetric_fog->uniform_set2 = RID(); +		} +	} + +	if (p_gi_probes.size() > 0) { +		RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GIProbeData) * MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE); +	} + +	RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render) { +	RD::get_singleton()->draw_command_begin_label("GI Render"); + +	RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND(rb == nullptr); +	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_valid()) { +			RD::get_singleton()->free(rb->ambient_buffer); +			RD::get_singleton()->free(rb->reflection_buffer); +		} + +		RD::TextureFormat tf; +		tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; +		tf.width = rb->width; +		tf.height = rb->height; +		if (half_resolution) { +			tf.width >>= 1; +			tf.height >>= 1; +		} +		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->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); +		rb->using_half_size_gi = half_resolution; + +		p_scene_render->_render_buffers_uniform_set_changed(p_render_buffers); +	} + +	PushConstant push_constant; + +	push_constant.screen_size[0] = rb->width; +	push_constant.screen_size[1] = rb->height; +	push_constant.z_near = p_projection.get_z_near(); +	push_constant.z_far = p_projection.get_z_far(); +	push_constant.orthogonal = p_projection.is_orthogonal(); +	push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]); +	push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]); +	push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; +	push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; +	push_constant.max_giprobes = MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size()); +	push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH; + +	bool use_sdfgi = rb->sdfgi != nullptr; +	bool use_giprobes = push_constant.max_giprobes > 0; + +	if (env) { +		push_constant.ao_color[0] = env->ao_color.r; +		push_constant.ao_color[1] = env->ao_color.g; +		push_constant.ao_color[2] = env->ao_color.b; +	} else { +		push_constant.ao_color[0] = 0; +		push_constant.ao_color[1] = 0; +		push_constant.ao_color[2] = 0; +	} + +	push_constant.cam_rotation[0] = p_transform.basis[0][0]; +	push_constant.cam_rotation[1] = p_transform.basis[1][0]; +	push_constant.cam_rotation[2] = p_transform.basis[2][0]; +	push_constant.cam_rotation[3] = 0; +	push_constant.cam_rotation[4] = p_transform.basis[0][1]; +	push_constant.cam_rotation[5] = p_transform.basis[1][1]; +	push_constant.cam_rotation[6] = p_transform.basis[2][1]; +	push_constant.cam_rotation[7] = 0; +	push_constant.cam_rotation[8] = p_transform.basis[0][2]; +	push_constant.cam_rotation[9] = p_transform.basis[1][2]; +	push_constant.cam_rotation[10] = p_transform.basis[2][2]; +	push_constant.cam_rotation[11] = 0; + +	if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) { +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.binding = 1; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { +				if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { +					u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 2; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { +				if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { +					u.ids.push_back(rb->sdfgi->cascades[j].light_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 3; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { +				if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { +					u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_0_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.binding = 4; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { +				if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { +					u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_1_tex); +				} else { +					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +				} +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 5; +			if (rb->sdfgi) { +				u.ids.push_back(rb->sdfgi->occlusion_texture); +			} else { +				u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +			u.binding = 6; +			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +			u.binding = 7; +			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 9; +			u.ids.push_back(rb->ambient_buffer); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +			u.binding = 10; +			u.ids.push_back(rb->reflection_buffer); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 11; +			if (rb->sdfgi) { +				u.ids.push_back(rb->sdfgi->lightprobe_texture); +			} else { +				u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE)); +			} +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 12; +			u.ids.push_back(rb->depth_texture); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 13; +			u.ids.push_back(p_normal_roughness_buffer); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 14; +			RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); +			u.ids.push_back(buffer); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.binding = 15; +			u.ids.push_back(sdfgi_ubo); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.binding = 16; +			u.ids.push_back(rb->gi.giprobe_buffer); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 17; +			for (int i = 0; i < MAX_GIPROBES; i++) { +				u.ids.push_back(rb->gi.giprobe_textures[i]); +			} +			uniforms.push_back(u); +		} + +		rb->gi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0); +	} + +	Mode mode; + +	if (rb->using_half_size_gi) { +		mode = (use_sdfgi && use_giprobes) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_GIPROBE); +	} else { +		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::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_set_push_constant(compute_list, &push_constant, sizeof(PushConstant)); + +	if (rb->using_half_size_gi) { +		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1); +	} else { +		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1); +	} +	//do barrier later to allow oeverlap +	//RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time +	RD::get_singleton()->draw_command_end_label(); +} + +RID RendererSceneGIRD::gi_probe_instance_create(RID p_base) { +	GIProbeInstance gi_probe; +	gi_probe.gi = this; +	gi_probe.storage = storage; +	gi_probe.probe = p_base; +	RID rid = gi_probe_instance_owner.make_rid(gi_probe); +	return rid; +} + +void RendererSceneGIRD::debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { +	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe); +	ERR_FAIL_COND(!gi_probe); + +	gi_probe->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha); +} diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h new file mode 100644 index 0000000000..6cff9b7837 --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h @@ -0,0 +1,653 @@ +/*************************************************************************/ +/*  renderer_scene_gi_rd.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 RENDERING_SERVER_SCENE_GI_RD_H +#define RENDERING_SERVER_SCENE_GI_RD_H + +#include "core/templates/local_vector.h" +#include "core/templates/rid_owner.h" +#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h" +#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering/rendering_device.h" + +// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound +class RendererSceneRenderRD; + +class RendererSceneGIRD { +private: +	// !BAS! need to see which things become internal.. + +	RendererStorageRD *storage; + +public: +	/* GIPROBE INSTANCE */ + +	struct GIProbeLight { +		uint32_t type; +		float energy; +		float radius; +		float attenuation; + +		float color[3]; +		float cos_spot_angle; + +		float position[3]; +		float inv_spot_attenuation; + +		float direction[3]; +		uint32_t has_shadow; +	}; + +	struct GIProbePushConstant { +		int32_t limits[3]; +		uint32_t stack_size; + +		float emission_scale; +		float propagation; +		float dynamic_range; +		uint32_t light_count; + +		uint32_t cell_offset; +		uint32_t cell_count; +		float aniso_strength; +		uint32_t pad; +	}; + +	struct GIProbeDynamicPushConstant { +		int32_t limits[3]; +		uint32_t light_count; +		int32_t x_dir[3]; +		float z_base; +		int32_t y_dir[3]; +		float z_sign; +		int32_t z_dir[3]; +		float pos_multiplier; +		uint32_t rect_pos[2]; +		uint32_t rect_size[2]; +		uint32_t prev_rect_ofs[2]; +		uint32_t prev_rect_size[2]; +		uint32_t flip_x; +		uint32_t flip_y; +		float dynamic_range; +		uint32_t on_mipmap; +		float propagation; +		float pad[3]; +	}; + +	struct GIProbeInstance { +		// access to our containers +		RendererStorageRD *storage; +		RendererSceneGIRD *gi; + +		RID probe; +		RID texture; +		RID write_buffer; + +		struct Mipmap { +			RID texture; +			RID uniform_set; +			RID second_bounce_uniform_set; +			RID write_uniform_set; +			uint32_t level; +			uint32_t cell_offset; +			uint32_t cell_count; +		}; +		Vector<Mipmap> mipmaps; + +		struct DynamicMap { +			RID texture; //color normally, or emission on first pass +			RID fb_depth; //actual depth buffer for the first pass, float depth for later passes +			RID depth; //actual depth buffer for the first pass, float depth for later passes +			RID normal; //normal buffer for the first pass +			RID albedo; //emission buffer for the first pass +			RID orm; //orm buffer for the first pass +			RID fb; //used for rendering, only valid on first map +			RID uniform_set; +			uint32_t size; +			int mipmap; // mipmap to write to, -1 if no mipmap assigned +		}; + +		Vector<DynamicMap> dynamic_maps; + +		int slot = -1; +		uint32_t last_probe_version = 0; +		uint32_t last_probe_data_version = 0; + +		//uint64_t last_pass = 0; +		uint32_t render_index = 0; + +		bool has_dynamic_object_data = false; + +		Transform transform; + +		void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render); +		void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); +	}; + +	GIProbeLight *gi_probe_lights; +	uint32_t gi_probe_max_lights; +	RID gi_probe_lights_uniform; + +	enum { +		GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT, +		GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE, +		GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP, +		GI_PROBE_SHADER_VERSION_WRITE_TEXTURE, +		GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING, +		GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE, +		GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT, +		GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT, +		GI_PROBE_SHADER_VERSION_MAX +	}; + +	GiprobeShaderRD giprobe_shader; +	RID giprobe_lighting_shader_version; +	RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX]; +	RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX]; + +	mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner; + +	RS::GIProbeQuality gi_probe_quality = RS::GI_PROBE_QUALITY_HIGH; + +	enum { +		GI_PROBE_DEBUG_COLOR, +		GI_PROBE_DEBUG_LIGHT, +		GI_PROBE_DEBUG_EMISSION, +		GI_PROBE_DEBUG_LIGHT_FULL, +		GI_PROBE_DEBUG_MAX +	}; + +	struct GIProbeDebugPushConstant { +		float projection[16]; +		uint32_t cell_offset; +		float dynamic_range; +		float alpha; +		uint32_t level; +		int32_t bounds[3]; +		uint32_t pad; +	}; + +	GiprobeDebugShaderRD giprobe_debug_shader; +	RID giprobe_debug_shader_version; +	RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX]; +	PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX]; +	RID giprobe_debug_uniform_set; + +	/* SDFGI */ + +	struct SDFGI { +		enum { +			MAX_CASCADES = 8, +			CASCADE_SIZE = 128, +			PROBE_DIVISOR = 16, +			ANISOTROPY_SIZE = 6, +			MAX_DYNAMIC_LIGHTS = 128, +			MAX_STATIC_LIGHTS = 1024, +			LIGHTPROBE_OCT_SIZE = 6, +			SH_SIZE = 16 +		}; + +		struct Cascade { +			struct UBO { +				float offset[3]; +				float to_cell; +				int32_t probe_offset[3]; +				uint32_t pad; +			}; + +			//cascade blocks are full-size for volume (128^3), half size for albedo/emission +			RID sdf_tex; +			RID light_tex; +			RID light_aniso_0_tex; +			RID light_aniso_1_tex; + +			RID light_data; +			RID light_aniso_0_data; +			RID light_aniso_1_data; + +			struct SolidCell { // this struct is unused, but remains as reference for size +				uint32_t position; +				uint32_t albedo; +				uint32_t static_light; +				uint32_t static_light_aniso; +			}; + +			RID solid_cell_dispatch_buffer; //buffer for indirect compute dispatch +			RID solid_cell_buffer; + +			RID lightprobe_history_tex; +			RID lightprobe_average_tex; + +			float cell_size; +			Vector3i position; + +			static const Vector3i DIRTY_ALL; +			Vector3i dirty_regions; //(0,0,0 is not dirty, negative is refresh from the end, DIRTY_ALL is refresh all. + +			RID sdf_store_uniform_set; +			RID sdf_direct_light_uniform_set; +			RID scroll_uniform_set; +			RID scroll_occlusion_uniform_set; +			RID integrate_uniform_set; +			RID lights_buffer; + +			bool all_dynamic_lights_dirty = true; +		}; + +		// access to our containers +		RendererStorageRD *storage; +		RendererSceneGIRD *gi; + +		// used for rendering (voxelization) +		RID render_albedo; +		RID render_emission; +		RID render_emission_aniso; +		RID render_occlusion[8]; +		RID render_geom_facing; + +		RID render_sdf[2]; +		RID render_sdf_half[2]; + +		// used for ping pong processing in cascades +		RID sdf_initialize_uniform_set; +		RID sdf_initialize_half_uniform_set; +		RID jump_flood_uniform_set[2]; +		RID jump_flood_half_uniform_set[2]; +		RID sdf_upscale_uniform_set; +		int upscale_jfa_uniform_set_index; +		RID occlusion_uniform_set; + +		uint32_t cascade_size = 128; + +		LocalVector<Cascade> cascades; + +		RID lightprobe_texture; +		RID lightprobe_data; +		RID occlusion_texture; +		RID occlusion_data; +		RID ambient_texture; //integrates with volumetric fog + +		RID lightprobe_history_scroll; //used for scrolling lightprobes +		RID lightprobe_average_scroll; //used for scrolling lightprobes + +		uint32_t history_size = 0; +		float solid_cell_ratio = 0; +		uint32_t solid_cell_count = 0; + +		RS::EnvironmentSDFGICascades cascade_mode; +		float min_cell_size = 0; +		uint32_t probe_axis_count = 0; //amount of probes per axis, this is an odd number because it encloses endpoints + +		RID debug_uniform_set; +		RID debug_probes_uniform_set; +		RID cascades_ubo; + +		bool uses_occlusion = false; +		float bounce_feedback = 0.0; +		bool reads_sky = false; +		float energy = 1.0; +		float normal_bias = 1.1; +		float probe_bias = 1.1; +		RS::EnvironmentSDFGIYScale y_scale_mode = RS::ENV_SDFGI_Y_SCALE_DISABLED; + +		float y_mult = 1.0; + +		uint32_t render_pass = 0; + +		int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically +		RID integrate_sky_uniform_set; + +		void create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, RendererSceneGIRD *p_gi); +		void erase(); +		void update(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position); +		void update_light(); +		void update_probes(RendererSceneEnvironmentRD *p_env, RendererSceneSkyRD::Sky *p_sky); +		void store_probes(); +		int get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const; +		void update_cascades(); + +		void debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture); +		void debug_probes(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); + +		void pre_process_gi(const Transform &p_transform, RendererSceneRenderRD *p_scene_render); +		void render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render); +		void render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render); +	}; + +	RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16; +	RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_10_FRAMES; +	RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES; + +	float sdfgi_solid_cell_ratio = 0.25; +	Vector3 sdfgi_debug_probe_pos; +	Vector3 sdfgi_debug_probe_dir; +	bool sdfgi_debug_probe_enabled = false; +	Vector3i sdfgi_debug_probe_index; + +	struct SDGIShader { +		enum SDFGIPreprocessShaderVersion { +			PRE_PROCESS_SCROLL, +			PRE_PROCESS_SCROLL_OCCLUSION, +			PRE_PROCESS_JUMP_FLOOD_INITIALIZE, +			PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF, +			PRE_PROCESS_JUMP_FLOOD, +			PRE_PROCESS_JUMP_FLOOD_OPTIMIZED, +			PRE_PROCESS_JUMP_FLOOD_UPSCALE, +			PRE_PROCESS_OCCLUSION, +			PRE_PROCESS_STORE, +			PRE_PROCESS_MAX +		}; + +		struct PreprocessPushConstant { +			int32_t scroll[3]; +			int32_t grid_size; + +			int32_t probe_offset[3]; +			int32_t step_size; + +			int32_t half_size; +			uint32_t occlusion_index; +			int32_t cascade; +			uint32_t pad; +		}; + +		SdfgiPreprocessShaderRD preprocess; +		RID preprocess_shader; +		RID preprocess_pipeline[PRE_PROCESS_MAX]; + +		struct DebugPushConstant { +			float grid_size[3]; +			uint32_t max_cascades; + +			int32_t screen_size[2]; +			uint32_t use_occlusion; +			float y_mult; + +			float cam_extent[3]; +			uint32_t probe_axis_size; + +			float cam_transform[16]; +		}; + +		SdfgiDebugShaderRD debug; +		RID debug_shader; +		RID debug_shader_version; +		RID debug_pipeline; + +		enum ProbeDebugMode { +			PROBE_DEBUG_PROBES, +			PROBE_DEBUG_VISIBILITY, +			PROBE_DEBUG_MAX +		}; + +		struct DebugProbesPushConstant { +			float projection[16]; + +			uint32_t band_power; +			uint32_t sections_in_band; +			uint32_t band_mask; +			float section_arc; + +			float grid_size[3]; +			uint32_t cascade; + +			uint32_t pad; +			float y_mult; +			int32_t probe_debug_index; +			int32_t probe_axis_size; +		}; + +		SdfgiDebugProbesShaderRD debug_probes; +		RID debug_probes_shader; +		RID debug_probes_shader_version; + +		PipelineCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX]; + +		struct Light { +			float color[3]; +			float energy; + +			float direction[3]; +			uint32_t has_shadow; + +			float position[3]; +			float attenuation; + +			uint32_t type; +			float cos_spot_angle; +			float inv_spot_attenuation; +			float radius; + +			float shadow_color[4]; +		}; + +		struct DirectLightPushConstant { +			float grid_size[3]; +			uint32_t max_cascades; + +			uint32_t cascade; +			uint32_t light_count; +			uint32_t process_offset; +			uint32_t process_increment; + +			int32_t probe_axis_size; +			float bounce_feedback; +			float y_mult; +			uint32_t use_occlusion; +		}; + +		enum { +			DIRECT_LIGHT_MODE_STATIC, +			DIRECT_LIGHT_MODE_DYNAMIC, +			DIRECT_LIGHT_MODE_MAX +		}; +		SdfgiDirectLightShaderRD direct_light; +		RID direct_light_shader; +		RID direct_light_pipeline[DIRECT_LIGHT_MODE_MAX]; + +		enum { +			INTEGRATE_MODE_PROCESS, +			INTEGRATE_MODE_STORE, +			INTEGRATE_MODE_SCROLL, +			INTEGRATE_MODE_SCROLL_STORE, +			INTEGRATE_MODE_MAX +		}; +		struct IntegratePushConstant { +			enum { +				SKY_MODE_DISABLED, +				SKY_MODE_COLOR, +				SKY_MODE_SKY, +			}; + +			float grid_size[3]; +			uint32_t max_cascades; + +			uint32_t probe_axis_size; +			uint32_t cascade; +			uint32_t history_index; +			uint32_t history_size; + +			uint32_t ray_count; +			float ray_bias; +			int32_t image_size[2]; + +			int32_t world_offset[3]; +			uint32_t sky_mode; + +			int32_t scroll[3]; +			float sky_energy; + +			float sky_color[3]; +			float y_mult; + +			uint32_t store_ambient_texture; +			uint32_t pad[3]; +		}; + +		SdfgiIntegrateShaderRD integrate; +		RID integrate_shader; +		RID integrate_pipeline[INTEGRATE_MODE_MAX]; + +		RID integrate_default_sky_uniform_set; + +	} sdfgi_shader; + +	/* SDFGI UPDATE */ + +	int sdfgi_get_lightprobe_octahedron_size() const { return SDFGI::LIGHTPROBE_OCT_SIZE; } + +	/* GI */ +	enum { +		MAX_GIPROBES = 8 +	}; + +	// Struct for use in render buffer +	struct RenderBuffersGI { +		RID giprobe_textures[MAX_GIPROBES]; +		RID giprobe_buffer; + +		RID full_buffer; +		RID full_dispatch; +		RID full_mask; +	}; + +	// struct GI { +	struct SDFGIData { +		float grid_size[3]; +		uint32_t max_cascades; + +		uint32_t use_occlusion; +		int32_t probe_axis_size; +		float probe_to_uvw; +		float normal_bias; + +		float lightprobe_tex_pixel_size[3]; +		float energy; + +		float lightprobe_uv_offset[3]; +		float y_mult; + +		float occlusion_clamp[3]; +		uint32_t pad3; + +		float occlusion_renormalize[3]; +		uint32_t pad4; + +		float cascade_probe_size[3]; +		uint32_t pad5; + +		struct ProbeCascadeData { +			float position[3]; //offset of (0,0,0) in world coordinates +			float to_probe; // 1/bounds * grid_size +			int32_t probe_world_offset[3]; +			float to_cell; // 1/bounds * grid_size +		}; + +		ProbeCascadeData cascades[SDFGI::MAX_CASCADES]; +	}; + +	struct GIProbeData { +		float xform[16]; +		float bounds[3]; +		float dynamic_range; + +		float bias; +		float normal_bias; +		uint32_t blend_ambient; +		uint32_t texture_slot; + +		float anisotropy_strength; +		float ao; +		float ao_size; +		uint32_t mipmaps; +	}; + +	struct PushConstant { +		int32_t screen_size[2]; +		float z_near; +		float z_far; + +		float proj_info[4]; +		float ao_color[3]; +		uint32_t max_giprobes; + +		uint32_t high_quality_vct; +		uint32_t orthogonal; +		uint32_t pad[2]; + +		float cam_rotation[12]; +	}; + +	RID sdfgi_ubo; +	enum Mode { +		MODE_GIPROBE, +		MODE_SDFGI, +		MODE_COMBINED, +		MODE_HALF_RES_GIPROBE, +		MODE_HALF_RES_SDFGI, +		MODE_HALF_RES_COMBINED, +		MODE_MAX +	}; + +	RID default_giprobe_buffer; + +	bool half_resolution = false; +	GiShaderRD shader; +	RID shader_version; +	RID pipelines[MODE_MAX]; +	// } gi; + +	RendererSceneGIRD(); +	~RendererSceneGIRD(); + +	// !BAS! Can we merge these two inits? Possibly, need to check +	void init_gi(RendererStorageRD *p_storage); +	void init_sdfgi(RendererSceneSkyRD *p_sky); +	void free(); + +	SDFGI *create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size); + +	void setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render); +	void process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render); + +	RID gi_probe_instance_create(RID p_base); +	void debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); +}; + +#endif /* !RENDERING_SERVER_SCENE_GI_RD_H */ diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp index a57dee7314..dd8bfda4d6 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp @@ -1130,7 +1130,7 @@ void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_ren  		//vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) );  		//vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx; -		uint32_t oct_size = sdfgi_get_lightprobe_octahedron_size(); +		uint32_t oct_size = gi.sdfgi_get_lightprobe_octahedron_size();  		scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size * scene_state.ubo.sdfgi_probe_axis_size);  		scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size); @@ -1583,6 +1583,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  	if (p_render_buffer.is_valid()) {  		render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer);  	} +	RendererSceneEnvironmentRD *env = get_environment(p_environment);  	//first of all, make a new render pass  	//fill up ubo @@ -1729,7 +1730,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  				clear_color.b *= bg_energy;  				if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {  					draw_sky_fog_only = true; -					storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); +					storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));  				}  			} break;  			case RS::ENV_BG_COLOR: { @@ -1739,7 +1740,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  				clear_color.b *= bg_energy;  				if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {  					draw_sky_fog_only = true; -					storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear())); +					storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));  				}  			} break;  			case RS::ENV_BG_SKY: { @@ -1767,12 +1768,12 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  				projection = correction * p_cam_projection;  			} -			_setup_sky(p_environment, p_render_buffer, projection, p_cam_transform, screen_size); +			sky.setup(env, p_render_buffer, projection, p_cam_transform, screen_size, this); -			RID sky = environment_get_sky(p_environment); -			if (sky.is_valid()) { -				_update_sky(p_environment, projection, p_cam_transform); -				radiance_texture = sky_get_radiance_texture_rd(sky); +			RID sky_rid = env->sky; +			if (sky_rid.is_valid()) { +				sky.update(env, projection, p_cam_transform, time); +				radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);  			} else {  				// do not try to draw sky if invalid  				draw_sky = false; @@ -1890,7 +1891,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);  		RD::get_singleton()->draw_command_begin_label("Debug GIProbes");  		for (int i = 0; i < (int)p_gi_probes.size(); i++) { -			_debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); +			gi.debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0);  		}  		RD::get_singleton()->draw_command_end_label();  		RD::get_singleton()->draw_list_end(); @@ -1921,7 +1922,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  			projection = correction * p_cam_projection;  		}  		RD::get_singleton()->draw_command_begin_label("Draw Sky"); -		_draw_sky(can_continue_color, can_continue_depth, opaque_framebuffer, p_environment, projection, p_cam_transform); +		sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_cam_transform, time);  		RD::get_singleton()->draw_command_end_label();  	} @@ -3346,7 +3347,7 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor  		if (is_using_radiance_cubemap_array()) {  			defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";  		} -		defines += "\n#define SDFGI_OCT_SIZE " + itos(sdfgi_get_lightprobe_octahedron_size()) + "\n"; +		defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";  		defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n";  		{ diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 15e963f6e4..7a6900b0c4 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -35,8 +35,6 @@  #include "renderer_compositor_rd.h"  #include "servers/rendering/rendering_server_default.h" -uint64_t RendererSceneRenderRD::auto_exposure_counter = 2; -  void get_vogel_disk(float *r_kernel, int p_sample_count) {  	const float golden_angle = 2.4; @@ -49,980 +47,42 @@ void get_vogel_disk(float *r_kernel, int p_sample_count) {  	}  } -void RendererSceneRenderRD::_clear_reflection_data(ReflectionData &rd) { -	rd.layers.clear(); -	rd.radiance_base_cubemap = RID(); -	if (rd.downsampled_radiance_cubemap.is_valid()) { -		RD::get_singleton()->free(rd.downsampled_radiance_cubemap); -	} -	rd.downsampled_radiance_cubemap = RID(); -	rd.downsampled_layer.mipmaps.clear(); -	rd.coefficient_buffer = RID(); -} - -void RendererSceneRenderRD::_update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality) { -	//recreate radiance and all data - -	int mipmaps = p_mipmaps; -	uint32_t w = p_size, h = p_size; - -	if (p_use_array) { -		int layers = p_low_quality ? 8 : roughness_layers; - -		for (int i = 0; i < layers; i++) { -			ReflectionData::Layer layer; -			uint32_t mmw = w; -			uint32_t mmh = h; -			layer.mipmaps.resize(mipmaps); -			layer.views.resize(mipmaps); -			for (int j = 0; j < mipmaps; j++) { -				ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; -				mm.size.width = mmw; -				mm.size.height = mmh; -				for (int k = 0; k < 6; k++) { -					mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j); -					Vector<RID> fbtex; -					fbtex.push_back(mm.views[k]); -					mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); -				} - -				layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, RD::TEXTURE_SLICE_CUBEMAP); - -				mmw = MAX(1, mmw >> 1); -				mmh = MAX(1, mmh >> 1); -			} - -			rd.layers.push_back(layer); -		} - -	} else { -		mipmaps = p_low_quality ? 8 : mipmaps; -		//regular cubemap, lower quality (aliasing, less memory) -		ReflectionData::Layer layer; -		uint32_t mmw = w; -		uint32_t mmh = h; -		layer.mipmaps.resize(mipmaps); -		layer.views.resize(mipmaps); -		for (int j = 0; j < mipmaps; j++) { -			ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; -			mm.size.width = mmw; -			mm.size.height = mmh; -			for (int k = 0; k < 6; k++) { -				mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j); -				Vector<RID> fbtex; -				fbtex.push_back(mm.views[k]); -				mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); -			} - -			layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, RD::TEXTURE_SLICE_CUBEMAP); - -			mmw = MAX(1, mmw >> 1); -			mmh = MAX(1, mmh >> 1); -		} - -		rd.layers.push_back(layer); -	} - -	rd.radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP); - -	RD::TextureFormat tf; -	tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; -	tf.width = 64; // Always 64x64 -	tf.height = 64; -	tf.texture_type = RD::TEXTURE_TYPE_CUBE; -	tf.array_layers = 6; -	tf.mipmaps = 7; -	tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - -	rd.downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); -	{ -		uint32_t mmw = 64; -		uint32_t mmh = 64; -		rd.downsampled_layer.mipmaps.resize(7); -		for (int j = 0; j < rd.downsampled_layer.mipmaps.size(); j++) { -			ReflectionData::DownsampleLayer::Mipmap &mm = rd.downsampled_layer.mipmaps.write[j]; -			mm.size.width = mmw; -			mm.size.height = mmh; -			mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP); - -			mmw = MAX(1, mmw >> 1); -			mmh = MAX(1, mmh >> 1); -		} -	} -} - -void RendererSceneRenderRD::_create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays) { -	storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size); - -	for (int i = 1; i < rd.downsampled_layer.mipmaps.size(); i++) { -		storage->get_effects()->cubemap_downsample(rd.downsampled_layer.mipmaps[i - 1].view, rd.downsampled_layer.mipmaps[i].view, rd.downsampled_layer.mipmaps[i].size); -	} - -	Vector<RID> views; -	if (p_use_arrays) { -		for (int i = 1; i < rd.layers.size(); i++) { -			views.push_back(rd.layers[i].views[0]); -		} -	} else { -		for (int i = 1; i < rd.layers[0].views.size(); i++) { -			views.push_back(rd.layers[0].views[i]); -		} -	} - -	storage->get_effects()->cubemap_filter(rd.downsampled_radiance_cubemap, views, p_use_arrays); -} - -void RendererSceneRenderRD::_create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer) { -	if (p_use_arrays) { -		//render directly to the layers -		storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, rd.layers[p_base_layer].views[0], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers.size() - 1.0), rd.layers[p_base_layer].mipmaps[0].size.x); -	} else { -		storage->get_effects()->cubemap_roughness(rd.layers[0].views[p_base_layer - 1], rd.layers[0].views[p_base_layer], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[p_base_layer].size.x); -	} -} - -void RendererSceneRenderRD::_update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end) { -	for (int i = p_start; i < p_end; i++) { -		for (int j = 0; j < rd.layers[i].views.size() - 1; j++) { -			RID view = rd.layers[i].views[j]; -			RID texture = rd.layers[i].views[j + 1]; -			Size2i size = rd.layers[i].mipmaps[j + 1].size; -			storage->get_effects()->cubemap_downsample(view, texture, size); -		} -	} -} - -void RendererSceneRenderRD::_sdfgi_erase(RenderBuffers *rb) { -	for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { -		const SDFGI::Cascade &c = rb->sdfgi->cascades[i]; -		RD::get_singleton()->free(c.light_data); -		RD::get_singleton()->free(c.light_aniso_0_tex); -		RD::get_singleton()->free(c.light_aniso_1_tex); -		RD::get_singleton()->free(c.sdf_tex); -		RD::get_singleton()->free(c.solid_cell_dispatch_buffer); -		RD::get_singleton()->free(c.solid_cell_buffer); -		RD::get_singleton()->free(c.lightprobe_history_tex); -		RD::get_singleton()->free(c.lightprobe_average_tex); -		RD::get_singleton()->free(c.lights_buffer); -	} - -	RD::get_singleton()->free(rb->sdfgi->render_albedo); -	RD::get_singleton()->free(rb->sdfgi->render_emission); -	RD::get_singleton()->free(rb->sdfgi->render_emission_aniso); - -	RD::get_singleton()->free(rb->sdfgi->render_sdf[0]); -	RD::get_singleton()->free(rb->sdfgi->render_sdf[1]); - -	RD::get_singleton()->free(rb->sdfgi->render_sdf_half[0]); -	RD::get_singleton()->free(rb->sdfgi->render_sdf_half[1]); - -	for (int i = 0; i < 8; i++) { -		RD::get_singleton()->free(rb->sdfgi->render_occlusion[i]); -	} - -	RD::get_singleton()->free(rb->sdfgi->render_geom_facing); - -	RD::get_singleton()->free(rb->sdfgi->lightprobe_data); -	RD::get_singleton()->free(rb->sdfgi->lightprobe_history_scroll); -	RD::get_singleton()->free(rb->sdfgi->occlusion_data); -	RD::get_singleton()->free(rb->sdfgi->ambient_texture); - -	RD::get_singleton()->free(rb->sdfgi->cascades_ubo); - -	memdelete(rb->sdfgi); - -	rb->sdfgi = nullptr; -} - -const Vector3i RendererSceneRenderRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF); -  void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) { -	Environment *env = environment_owner.getornull(p_environment); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	bool needs_sdfgi = env && env->sdfgi_enabled;  	if (!needs_sdfgi) {  		if (rb->sdfgi != nullptr) {  			//erase it -			_sdfgi_erase(rb); +			rb->sdfgi->erase(); +			memdelete(rb->sdfgi); +			rb->sdfgi = nullptr; +  			_render_buffers_uniform_set_changed(p_render_buffers);  		}  		return;  	}  	static const uint32_t history_frames_to_converge[RS::ENV_SDFGI_CONVERGE_MAX] = { 5, 10, 15, 20, 25, 30 }; -	uint32_t requested_history_size = history_frames_to_converge[sdfgi_frames_to_converge]; +	uint32_t requested_history_size = history_frames_to_converge[gi.sdfgi_frames_to_converge];  	if (rb->sdfgi && (rb->sdfgi->cascade_mode != env->sdfgi_cascades || rb->sdfgi->min_cell_size != env->sdfgi_min_cell_size || requested_history_size != rb->sdfgi->history_size || rb->sdfgi->uses_occlusion != env->sdfgi_use_occlusion || rb->sdfgi->y_scale_mode != env->sdfgi_y_scale)) {  		//configuration changed, erase -		_sdfgi_erase(rb); +		rb->sdfgi->erase(); +		memdelete(rb->sdfgi); +		rb->sdfgi = nullptr;  	} -	SDFGI *sdfgi = rb->sdfgi; +	RendererSceneGIRD::SDFGI *sdfgi = rb->sdfgi;  	if (sdfgi == nullptr) { -		//re-create -		rb->sdfgi = memnew(SDFGI); -		sdfgi = rb->sdfgi; -		sdfgi->cascade_mode = env->sdfgi_cascades; -		sdfgi->min_cell_size = env->sdfgi_min_cell_size; -		sdfgi->uses_occlusion = env->sdfgi_use_occlusion; -		sdfgi->y_scale_mode = env->sdfgi_y_scale; -		static const float y_scale[3] = { 1.0, 1.5, 2.0 }; -		sdfgi->y_mult = y_scale[sdfgi->y_scale_mode]; -		static const int cascasde_size[3] = { 4, 6, 8 }; -		sdfgi->cascades.resize(cascasde_size[sdfgi->cascade_mode]); -		sdfgi->probe_axis_count = SDFGI::PROBE_DIVISOR + 1; -		sdfgi->solid_cell_ratio = sdfgi_solid_cell_ratio; -		sdfgi->solid_cell_count = uint32_t(float(sdfgi->cascade_size * sdfgi->cascade_size * sdfgi->cascade_size) * sdfgi->solid_cell_ratio); - -		float base_cell_size = sdfgi->min_cell_size; - -		RD::TextureFormat tf_sdf; -		tf_sdf.format = RD::DATA_FORMAT_R8_UNORM; -		tf_sdf.width = sdfgi->cascade_size; // Always 64x64 -		tf_sdf.height = sdfgi->cascade_size; -		tf_sdf.depth = sdfgi->cascade_size; -		tf_sdf.texture_type = RD::TEXTURE_TYPE_3D; -		tf_sdf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; - -		{ -			RD::TextureFormat tf_render = tf_sdf; -			tf_render.format = RD::DATA_FORMAT_R16_UINT; -			sdfgi->render_albedo = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); -			tf_render.format = RD::DATA_FORMAT_R32_UINT; -			sdfgi->render_emission = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); -			sdfgi->render_emission_aniso = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); - -			tf_render.format = RD::DATA_FORMAT_R8_UNORM; //at least its easy to visualize - -			for (int i = 0; i < 8; i++) { -				sdfgi->render_occlusion[i] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); -			} - -			tf_render.format = RD::DATA_FORMAT_R32_UINT; -			sdfgi->render_geom_facing = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); - -			tf_render.format = RD::DATA_FORMAT_R8G8B8A8_UINT; -			sdfgi->render_sdf[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); -			sdfgi->render_sdf[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); - -			tf_render.width /= 2; -			tf_render.height /= 2; -			tf_render.depth /= 2; - -			sdfgi->render_sdf_half[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); -			sdfgi->render_sdf_half[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView()); -		} - -		RD::TextureFormat tf_occlusion = tf_sdf; -		tf_occlusion.format = RD::DATA_FORMAT_R16_UINT; -		tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT); -		tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16); -		tf_occlusion.depth *= sdfgi->cascades.size(); //use depth for occlusion slices -		tf_occlusion.width *= 2; //use width for the other half - -		RD::TextureFormat tf_light = tf_sdf; -		tf_light.format = RD::DATA_FORMAT_R32_UINT; -		tf_light.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT); -		tf_light.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32); - -		RD::TextureFormat tf_aniso0 = tf_sdf; -		tf_aniso0.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; -		RD::TextureFormat tf_aniso1 = tf_sdf; -		tf_aniso1.format = RD::DATA_FORMAT_R8G8_UNORM; - -		int passes = nearest_shift(sdfgi->cascade_size) - 1; - -		//store lightprobe SH -		RD::TextureFormat tf_probes; -		tf_probes.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; -		tf_probes.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count; -		tf_probes.height = sdfgi->probe_axis_count * SDFGI::SH_SIZE; -		tf_probes.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; -		tf_probes.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; - -		sdfgi->history_size = requested_history_size; - -		RD::TextureFormat tf_probe_history = tf_probes; -		tf_probe_history.format = RD::DATA_FORMAT_R16G16B16A16_SINT; //signed integer because SH are signed -		tf_probe_history.array_layers = sdfgi->history_size; - -		RD::TextureFormat tf_probe_average = tf_probes; -		tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed -		tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D; - -		sdfgi->lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); -		sdfgi->lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); - -		{ -			//octahedral lightprobes -			RD::TextureFormat tf_octprobes = tf_probes; -			tf_octprobes.array_layers = sdfgi->cascades.size() * 2; -			tf_octprobes.format = RD::DATA_FORMAT_R32_UINT; //pack well with RGBE -			tf_octprobes.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2); -			tf_octprobes.height = sdfgi->probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2); -			tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT); -			tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32); -			//lightprobe texture is an octahedral texture - -			sdfgi->lightprobe_data = RD::get_singleton()->texture_create(tf_octprobes, RD::TextureView()); -			RD::TextureView tv; -			tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32; -			sdfgi->lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, sdfgi->lightprobe_data); - -			//texture handling ambient data, to integrate with volumetric foc -			RD::TextureFormat tf_ambient = tf_probes; -			tf_ambient.array_layers = sdfgi->cascades.size(); -			tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE -			tf_ambient.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count; -			tf_ambient.height = sdfgi->probe_axis_count; -			tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; -			//lightprobe texture is an octahedral texture -			sdfgi->ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView()); -		} - -		sdfgi->cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES); - -		sdfgi->occlusion_data = RD::get_singleton()->texture_create(tf_occlusion, RD::TextureView()); -		{ -			RD::TextureView tv; -			tv.format_override = RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16; -			sdfgi->occlusion_texture = RD::get_singleton()->texture_create_shared(tv, sdfgi->occlusion_data); -		} - -		for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) { -			SDFGI::Cascade &cascade = sdfgi->cascades[i]; - -			/* 3D Textures */ - -			cascade.sdf_tex = RD::get_singleton()->texture_create(tf_sdf, RD::TextureView()); - -			cascade.light_data = RD::get_singleton()->texture_create(tf_light, RD::TextureView()); - -			cascade.light_aniso_0_tex = RD::get_singleton()->texture_create(tf_aniso0, RD::TextureView()); -			cascade.light_aniso_1_tex = RD::get_singleton()->texture_create(tf_aniso1, RD::TextureView()); - -			{ -				RD::TextureView tv; -				tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32; -				cascade.light_tex = RD::get_singleton()->texture_create_shared(tv, cascade.light_data); - -				RD::get_singleton()->texture_clear(cascade.light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); -				RD::get_singleton()->texture_clear(cascade.light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); -				RD::get_singleton()->texture_clear(cascade.light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); -			} - -			cascade.cell_size = base_cell_size; -			Vector3 world_position = p_world_position; -			world_position.y *= sdfgi->y_mult; -			int32_t probe_cells = sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; -			Vector3 probe_size = Vector3(1, 1, 1) * cascade.cell_size * probe_cells; -			Vector3i probe_pos = Vector3i((world_position / probe_size + Vector3(0.5, 0.5, 0.5)).floor()); -			cascade.position = probe_pos * probe_cells; - -			cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL; - -			base_cell_size *= 2.0; - -			/* Probe History */ - -			cascade.lightprobe_history_tex = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); -			RD::get_singleton()->texture_clear(cascade.lightprobe_history_tex, Color(0, 0, 0, 0), 0, 1, 0, tf_probe_history.array_layers); //needs to be cleared for average to work - -			cascade.lightprobe_average_tex = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); -			RD::get_singleton()->texture_clear(cascade.lightprobe_average_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); //needs to be cleared for average to work - -			/* Buffers */ - -			cascade.solid_cell_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGI::Cascade::SolidCell) * sdfgi->solid_cell_count); -			cascade.solid_cell_dispatch_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT); -			cascade.lights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDGIShader::Light) * MAX(SDFGI::MAX_STATIC_LIGHTS, SDFGI::MAX_DYNAMIC_LIGHTS)); -			{ -				Vector<RD::Uniform> uniforms; -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 1; -					u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 1 : 0]); //if passes are even, we read from buffer 0, else we read from buffer 1 -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 2; -					u.ids.push_back(sdfgi->render_albedo); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 3; -					for (int j = 0; j < 8; j++) { -						u.ids.push_back(sdfgi->render_occlusion[j]); -					} -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 4; -					u.ids.push_back(sdfgi->render_emission); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 5; -					u.ids.push_back(sdfgi->render_emission_aniso); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 6; -					u.ids.push_back(sdfgi->render_geom_facing); -					uniforms.push_back(u); -				} - -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 7; -					u.ids.push_back(cascade.sdf_tex); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 8; -					u.ids.push_back(sdfgi->occlusion_data); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -					u.binding = 10; -					u.ids.push_back(cascade.solid_cell_dispatch_buffer); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -					u.binding = 11; -					u.ids.push_back(cascade.solid_cell_buffer); -					uniforms.push_back(u); -				} - -				cascade.sdf_store_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_STORE), 0); -			} - -			{ -				Vector<RD::Uniform> uniforms; -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 1; -					u.ids.push_back(sdfgi->render_albedo); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 2; -					u.ids.push_back(sdfgi->render_geom_facing); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 3; -					u.ids.push_back(sdfgi->render_emission); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 4; -					u.ids.push_back(sdfgi->render_emission_aniso); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -					u.binding = 5; -					u.ids.push_back(cascade.solid_cell_dispatch_buffer); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -					u.binding = 6; -					u.ids.push_back(cascade.solid_cell_buffer); -					uniforms.push_back(u); -				} - -				cascade.scroll_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_SCROLL), 0); -			} -			{ -				Vector<RD::Uniform> uniforms; -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 1; -					for (int j = 0; j < 8; j++) { -						u.ids.push_back(sdfgi->render_occlusion[j]); -					} -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 2; -					u.ids.push_back(sdfgi->occlusion_data); -					uniforms.push_back(u); -				} - -				cascade.scroll_occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_SCROLL_OCCLUSION), 0); -			} -		} - -		//direct light -		for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) { -			SDFGI::Cascade &cascade = sdfgi->cascades[i]; - -			Vector<RD::Uniform> uniforms; -			{ -				RD::Uniform u; -				u.binding = 1; -				u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -				for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { -					if (j < rb->sdfgi->cascades.size()) { -						u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex); -					} else { -						u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -					} -				} -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 2; -				u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -				u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 3; -				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -				u.ids.push_back(cascade.solid_cell_dispatch_buffer); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 4; -				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -				u.ids.push_back(cascade.solid_cell_buffer); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 5; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.ids.push_back(cascade.light_data); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 6; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.ids.push_back(cascade.light_aniso_0_tex); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 7; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.ids.push_back(cascade.light_aniso_1_tex); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 8; -				u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -				u.ids.push_back(rb->sdfgi->cascades_ubo); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 9; -				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -				u.ids.push_back(cascade.lights_buffer); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 10; -				u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -				u.ids.push_back(rb->sdfgi->lightprobe_texture); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 11; -				u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -				u.ids.push_back(rb->sdfgi->occlusion_texture); -				uniforms.push_back(u); -			} - -			cascade.sdf_direct_light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, 0), 0); -		} - -		//preprocess initialize uniform set -		{ -			Vector<RD::Uniform> uniforms; -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 1; -				u.ids.push_back(sdfgi->render_albedo); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 2; -				u.ids.push_back(sdfgi->render_sdf[0]); -				uniforms.push_back(u); -			} - -			sdfgi->sdf_initialize_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE), 0); -		} - -		{ -			Vector<RD::Uniform> uniforms; -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 1; -				u.ids.push_back(sdfgi->render_albedo); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 2; -				u.ids.push_back(sdfgi->render_sdf_half[0]); -				uniforms.push_back(u); -			} - -			sdfgi->sdf_initialize_half_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF), 0); -		} - -		//jump flood uniform set -		{ -			Vector<RD::Uniform> uniforms; -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 1; -				u.ids.push_back(sdfgi->render_sdf[0]); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 2; -				u.ids.push_back(sdfgi->render_sdf[1]); -				uniforms.push_back(u); -			} - -			sdfgi->jump_flood_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0); -			SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]); -			sdfgi->jump_flood_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0); -		} -		//jump flood half uniform set -		{ -			Vector<RD::Uniform> uniforms; -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 1; -				u.ids.push_back(sdfgi->render_sdf_half[0]); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 2; -				u.ids.push_back(sdfgi->render_sdf_half[1]); -				uniforms.push_back(u); -			} - -			sdfgi->jump_flood_half_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0); -			SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]); -			sdfgi->jump_flood_half_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0); -		} - -		//upscale half size sdf -		{ -			Vector<RD::Uniform> uniforms; -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 1; -				u.ids.push_back(sdfgi->render_albedo); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 2; -				u.ids.push_back(sdfgi->render_sdf_half[(passes & 1) ? 0 : 1]); //reverse pass order because half size -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 3; -				u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 0 : 1]); //reverse pass order because it needs an extra JFA pass -				uniforms.push_back(u); -			} - -			sdfgi->upscale_jfa_uniform_set_index = (passes & 1) ? 0 : 1; -			sdfgi->sdf_upscale_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE), 0); -		} - -		//occlusion uniform set -		{ -			Vector<RD::Uniform> uniforms; -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 1; -				u.ids.push_back(sdfgi->render_albedo); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 2; -				for (int i = 0; i < 8; i++) { -					u.ids.push_back(sdfgi->render_occlusion[i]); -				} -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 3; -				u.ids.push_back(sdfgi->render_geom_facing); -				uniforms.push_back(u); -			} - -			sdfgi->occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_OCCLUSION), 0); -		} - -		for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) { -			//integrate uniform - -			Vector<RD::Uniform> uniforms; - -			{ -				RD::Uniform u; -				u.binding = 1; -				u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -				for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { -					if (j < sdfgi->cascades.size()) { -						u.ids.push_back(sdfgi->cascades[j].sdf_tex); -					} else { -						u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -					} -				} -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 2; -				u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -				for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { -					if (j < sdfgi->cascades.size()) { -						u.ids.push_back(sdfgi->cascades[j].light_tex); -					} else { -						u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -					} -				} -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 3; -				u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -				for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { -					if (j < sdfgi->cascades.size()) { -						u.ids.push_back(sdfgi->cascades[j].light_aniso_0_tex); -					} else { -						u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -					} -				} -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.binding = 4; -				u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -				for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { -					if (j < sdfgi->cascades.size()) { -						u.ids.push_back(sdfgi->cascades[j].light_aniso_1_tex); -					} else { -						u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -					} -				} -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -				u.binding = 6; -				u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -				uniforms.push_back(u); -			} - -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -				u.binding = 7; -				u.ids.push_back(sdfgi->cascades_ubo); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 8; -				u.ids.push_back(sdfgi->lightprobe_data); -				uniforms.push_back(u); -			} - -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 9; -				u.ids.push_back(sdfgi->cascades[i].lightprobe_history_tex); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 10; -				u.ids.push_back(sdfgi->cascades[i].lightprobe_average_tex); -				uniforms.push_back(u); -			} - -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 11; -				u.ids.push_back(sdfgi->lightprobe_history_scroll); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 12; -				u.ids.push_back(sdfgi->lightprobe_average_scroll); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 13; -				RID parent_average; -				if (i < sdfgi->cascades.size() - 1) { -					parent_average = sdfgi->cascades[i + 1].lightprobe_average_tex; -				} else { -					parent_average = sdfgi->cascades[i - 1].lightprobe_average_tex; //to use something, but it won't be used -				} -				u.ids.push_back(parent_average); -				uniforms.push_back(u); -			} -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -				u.binding = 14; -				u.ids.push_back(sdfgi->ambient_texture); -				uniforms.push_back(u); -			} - -			sdfgi->cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 0); -		} - -		sdfgi->bounce_feedback = env->sdfgi_bounce_feedback; -		sdfgi->energy = env->sdfgi_energy; -		sdfgi->normal_bias = env->sdfgi_normal_bias; -		sdfgi->probe_bias = env->sdfgi_probe_bias; -		sdfgi->reads_sky = env->sdfgi_read_sky_light; +		// re-create +		rb->sdfgi = gi.create_sdfgi(env, p_world_position, requested_history_size);  		_render_buffers_uniform_set_changed(p_render_buffers); - -		return; //done. all levels will need to be rendered which its going to take a bit -	} - -	//check for updates - -	sdfgi->bounce_feedback = env->sdfgi_bounce_feedback; -	sdfgi->energy = env->sdfgi_energy; -	sdfgi->normal_bias = env->sdfgi_normal_bias; -	sdfgi->probe_bias = env->sdfgi_probe_bias; -	sdfgi->reads_sky = env->sdfgi_read_sky_light; - -	int32_t drag_margin = (sdfgi->cascade_size / SDFGI::PROBE_DIVISOR) / 2; - -	for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) { -		SDFGI::Cascade &cascade = sdfgi->cascades[i]; -		cascade.dirty_regions = Vector3i(); - -		Vector3 probe_half_size = Vector3(1, 1, 1) * cascade.cell_size * float(sdfgi->cascade_size / SDFGI::PROBE_DIVISOR) * 0.5; -		probe_half_size = Vector3(0, 0, 0); - -		Vector3 world_position = p_world_position; -		world_position.y *= sdfgi->y_mult; -		Vector3i pos_in_cascade = Vector3i((world_position + probe_half_size) / cascade.cell_size); - -		for (int j = 0; j < 3; j++) { -			if (pos_in_cascade[j] < cascade.position[j]) { -				while (pos_in_cascade[j] < (cascade.position[j] - drag_margin)) { -					cascade.position[j] -= drag_margin * 2; -					cascade.dirty_regions[j] += drag_margin * 2; -				} -			} else if (pos_in_cascade[j] > cascade.position[j]) { -				while (pos_in_cascade[j] > (cascade.position[j] + drag_margin)) { -					cascade.position[j] += drag_margin * 2; -					cascade.dirty_regions[j] -= drag_margin * 2; -				} -			} - -			if (cascade.dirty_regions[j] == 0) { -				continue; // not dirty -			} else if (uint32_t(ABS(cascade.dirty_regions[j])) >= sdfgi->cascade_size) { -				//moved too much, just redraw everything (make all dirty) -				cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL; -				break; -			} -		} - -		if (cascade.dirty_regions != Vector3i() && cascade.dirty_regions != SDFGI::Cascade::DIRTY_ALL) { -			//see how much the total dirty volume represents from the total volume -			uint32_t total_volume = sdfgi->cascade_size * sdfgi->cascade_size * sdfgi->cascade_size; -			uint32_t safe_volume = 1; -			for (int j = 0; j < 3; j++) { -				safe_volume *= sdfgi->cascade_size - ABS(cascade.dirty_regions[j]); -			} -			uint32_t dirty_volume = total_volume - safe_volume; -			if (dirty_volume > (safe_volume / 2)) { -				//more than half the volume is dirty, make all dirty so its only rendered once -				cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL; -			} -		} +	} else { +		//check for updates +		rb->sdfgi->update(env, p_world_position);  	}  } @@ -1037,9 +97,9 @@ int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers)  	int dirty_count = 0;  	for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { -		const SDFGI::Cascade &c = rb->sdfgi->cascades[i]; +		const RendererSceneGIRD::SDFGI::Cascade &c = rb->sdfgi->cascades[i]; -		if (c.dirty_regions == SDFGI::Cascade::DIRTY_ALL) { +		if (c.dirty_regions == RendererSceneGIRD::SDFGI::Cascade::DIRTY_ALL) {  			dirty_count++;  		} else {  			for (int j = 0; j < 3; j++) { @@ -1053,72 +113,15 @@ int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers)  	return dirty_count;  } -int RendererSceneRenderRD::_sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const { -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND_V(rb == nullptr, -1); -	ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1); - -	int dirty_count = 0; -	for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { -		const SDFGI::Cascade &c = rb->sdfgi->cascades[i]; - -		if (c.dirty_regions == SDFGI::Cascade::DIRTY_ALL) { -			if (dirty_count == p_region) { -				r_local_offset = Vector3i(); -				r_local_size = Vector3i(1, 1, 1) * rb->sdfgi->cascade_size; - -				r_bounds.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + c.position)) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1); -				r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1); -				return i; -			} -			dirty_count++; -		} else { -			for (int j = 0; j < 3; j++) { -				if (c.dirty_regions[j] != 0) { -					if (dirty_count == p_region) { -						Vector3i from = Vector3i(0, 0, 0); -						Vector3i to = Vector3i(1, 1, 1) * rb->sdfgi->cascade_size; - -						if (c.dirty_regions[j] > 0) { -							//fill from the beginning -							to[j] = c.dirty_regions[j]; -						} else { -							//fill from the end -							from[j] = to[j] + c.dirty_regions[j]; -						} - -						for (int k = 0; k < j; k++) { -							// "chip" away previous regions to avoid re-voxelizing the same thing -							if (c.dirty_regions[k] > 0) { -								from[k] += c.dirty_regions[k]; -							} else if (c.dirty_regions[k] < 0) { -								to[k] += c.dirty_regions[k]; -							} -						} - -						r_local_offset = from; -						r_local_size = to - from; - -						r_bounds.position = Vector3(from + Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + c.position) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1); -						r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1); - -						return i; -					} - -					dirty_count++; -				} -			} -		} -	} -	return -1; -} -  AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const {  	AABB bounds;  	Vector3i from;  	Vector3i size; +	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); +	ERR_FAIL_COND_V(rb == nullptr, AABB()); +	ERR_FAIL_COND_V(rb->sdfgi == nullptr, AABB()); -	int c = _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds); +	int c = rb->sdfgi->get_pending_region_data(p_region, from, size, bounds);  	ERR_FAIL_COND_V(c == -1, AABB());  	return bounds;  } @@ -1127,1956 +130,179 @@ uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(RID p_render_bu  	AABB bounds;  	Vector3i from;  	Vector3i size; - -	return _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds); -} - -void RendererSceneRenderRD::_sdfgi_update_cascades(RID p_render_buffers) {  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(rb == nullptr); -	if (rb->sdfgi == nullptr) { -		return; -	} - -	//update cascades -	SDFGI::Cascade::UBO cascade_data[SDFGI::MAX_CASCADES]; -	int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; - -	for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { -		Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[i].position)) * rb->sdfgi->cascades[i].cell_size; - -		cascade_data[i].offset[0] = pos.x; -		cascade_data[i].offset[1] = pos.y; -		cascade_data[i].offset[2] = pos.z; -		cascade_data[i].to_cell = 1.0 / rb->sdfgi->cascades[i].cell_size; -		cascade_data[i].probe_offset[0] = rb->sdfgi->cascades[i].position.x / probe_divisor; -		cascade_data[i].probe_offset[1] = rb->sdfgi->cascades[i].position.y / probe_divisor; -		cascade_data[i].probe_offset[2] = rb->sdfgi->cascades[i].position.z / probe_divisor; -		cascade_data[i].pad = 0; -	} - -	RD::get_singleton()->buffer_update(rb->sdfgi->cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE); -} - -void RendererSceneRenderRD::_sdfgi_update_light(RID p_render_buffers, RID p_environment) { -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(rb == nullptr); -	if (rb->sdfgi == nullptr) { -		return; -	} - -	RD::get_singleton()->draw_command_begin_label("SDFGI Update dynamic Light"); - -	/* Update dynamic light */ - -	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); -	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_DYNAMIC]); - -	SDGIShader::DirectLightPushConstant push_constant; - -	push_constant.grid_size[0] = rb->sdfgi->cascade_size; -	push_constant.grid_size[1] = rb->sdfgi->cascade_size; -	push_constant.grid_size[2] = rb->sdfgi->cascade_size; -	push_constant.max_cascades = rb->sdfgi->cascades.size(); -	push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; -	push_constant.bounce_feedback = rb->sdfgi->bounce_feedback; -	push_constant.y_mult = rb->sdfgi->y_mult; -	push_constant.use_occlusion = rb->sdfgi->uses_occlusion; - -	for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { -		SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; -		push_constant.light_count = rb->sdfgi->cascade_dynamic_light_count[i]; -		push_constant.cascade = i; - -		if (rb->sdfgi->cascades[i].all_dynamic_lights_dirty || sdfgi_frames_to_update_light == RS::ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME) { -			push_constant.process_offset = 0; -			push_constant.process_increment = 1; -		} else { -			static uint32_t frames_to_update_table[RS::ENV_SDFGI_UPDATE_LIGHT_MAX] = { -				1, 2, 4, 8, 16 -			}; - -			uint32_t frames_to_update = frames_to_update_table[sdfgi_frames_to_update_light]; - -			push_constant.process_offset = RSG::rasterizer->get_frame_number() % frames_to_update; -			push_constant.process_increment = frames_to_update; -		} -		rb->sdfgi->cascades[i].all_dynamic_lights_dirty = false; - -		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0); -		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DirectLightPushConstant)); -		RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0); -	} -	RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); -	RD::get_singleton()->draw_command_end_label(); -} - -void RendererSceneRenderRD::_sdfgi_update_probes(RID p_render_buffers, RID p_environment) { -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(rb == nullptr); -	if (rb->sdfgi == nullptr) { -		return; -	} - -	RD::get_singleton()->draw_command_begin_label("SDFGI Update Probes"); - -	Environment *env = environment_owner.getornull(p_environment); - -	SDGIShader::IntegratePushConstant push_constant; -	push_constant.grid_size[1] = rb->sdfgi->cascade_size; -	push_constant.grid_size[2] = rb->sdfgi->cascade_size; -	push_constant.grid_size[0] = rb->sdfgi->cascade_size; -	push_constant.max_cascades = rb->sdfgi->cascades.size(); -	push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; -	push_constant.history_index = rb->sdfgi->render_pass % rb->sdfgi->history_size; -	push_constant.history_size = rb->sdfgi->history_size; -	static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 }; -	push_constant.ray_count = ray_count[sdfgi_ray_count]; -	push_constant.ray_bias = rb->sdfgi->probe_bias; -	push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; -	push_constant.image_size[1] = rb->sdfgi->probe_axis_count; -	push_constant.store_ambient_texture = env->volumetric_fog_enabled; - -	RID sky_uniform_set = sdfgi_shader.integrate_default_sky_uniform_set; -	push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_DISABLED; -	push_constant.y_mult = rb->sdfgi->y_mult; - -	if (rb->sdfgi->reads_sky && env) { -		push_constant.sky_energy = env->bg_energy; - -		if (env->background == RS::ENV_BG_CLEAR_COLOR) { -			push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_COLOR; -			Color c = storage->get_default_clear_color().to_linear(); -			push_constant.sky_color[0] = c.r; -			push_constant.sky_color[1] = c.g; -			push_constant.sky_color[2] = c.b; -		} else if (env->background == RS::ENV_BG_COLOR) { -			push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_COLOR; -			Color c = env->bg_color; -			push_constant.sky_color[0] = c.r; -			push_constant.sky_color[1] = c.g; -			push_constant.sky_color[2] = c.b; - -		} else if (env->background == RS::ENV_BG_SKY) { -			Sky *sky = sky_owner.getornull(env->sky); -			if (sky && sky->radiance.is_valid()) { -				if (sky->sdfgi_integrate_sky_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(sky->sdfgi_integrate_sky_uniform_set)) { -					Vector<RD::Uniform> uniforms; - -					{ -						RD::Uniform u; -						u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -						u.binding = 0; -						u.ids.push_back(sky->radiance); -						uniforms.push_back(u); -					} - -					{ -						RD::Uniform u; -						u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -						u.binding = 1; -						u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -						uniforms.push_back(u); -					} - -					sky->sdfgi_integrate_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1); -				} -				sky_uniform_set = sky->sdfgi_integrate_sky_uniform_set; -				push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_SKY; -			} -		} -	} - -	rb->sdfgi->render_pass++; - -	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); -	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_PROCESS]); - -	int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; -	for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { -		push_constant.cascade = i; -		push_constant.world_offset[0] = rb->sdfgi->cascades[i].position.x / probe_divisor; -		push_constant.world_offset[1] = rb->sdfgi->cascades[i].position.y / probe_divisor; -		push_constant.world_offset[2] = rb->sdfgi->cascades[i].position.z / probe_divisor; - -		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[i].integrate_uniform_set, 0); -		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sky_uniform_set, 1); - -		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant)); -		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1); -	} - -	//end later after raster to avoid barriering on layout changes -	//RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); - -	RD::get_singleton()->draw_command_end_label(); -} - -void RendererSceneRenderRD::_sdfgi_store_probes(RID p_render_buffers) { -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(rb == nullptr); -	if (rb->sdfgi == nullptr) { -		return; -	} - -	RD::get_singleton()->barrier(RD::BARRIER_MASK_COMPUTE, RD::BARRIER_MASK_COMPUTE); -	RD::get_singleton()->draw_command_begin_label("SDFGI Store Probes"); - -	SDGIShader::IntegratePushConstant push_constant; -	push_constant.grid_size[1] = rb->sdfgi->cascade_size; -	push_constant.grid_size[2] = rb->sdfgi->cascade_size; -	push_constant.grid_size[0] = rb->sdfgi->cascade_size; -	push_constant.max_cascades = rb->sdfgi->cascades.size(); -	push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; -	push_constant.history_index = rb->sdfgi->render_pass % rb->sdfgi->history_size; -	push_constant.history_size = rb->sdfgi->history_size; -	static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 }; -	push_constant.ray_count = ray_count[sdfgi_ray_count]; -	push_constant.ray_bias = rb->sdfgi->probe_bias; -	push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; -	push_constant.image_size[1] = rb->sdfgi->probe_axis_count; -	push_constant.store_ambient_texture = false; - -	push_constant.sky_mode = 0; -	push_constant.y_mult = rb->sdfgi->y_mult; - -	// Then store values into the lightprobe texture. Separating these steps has a small performance hit, but it allows for multiple bounces -	RENDER_TIMESTAMP("Average Probes"); - -	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); -	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]); - -	//convert to octahedral to store -	push_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE; -	push_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE; - -	for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { -		push_constant.cascade = i; -		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[i].integrate_uniform_set, 0); -		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); -		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant)); -		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1); -	} - -	RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); - -	RD::get_singleton()->draw_command_end_label(); -} -void RendererSceneRenderRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used) { -	r_gi_probes_used = 0; -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(rb == nullptr); - -	RD::get_singleton()->draw_command_begin_label("GIProbes Setup"); - -	RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers); -	GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES]; - -	bool giprobes_changed = false; - -	Transform to_camera; -	to_camera.origin = p_transform.origin; //only translation, make local - -	for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { -		RID texture; -		if (i < (int)p_gi_probes.size()) { -			GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probes[i]); - -			if (gipi) { -				texture = gipi->texture; -				GI::GIProbeData &gipd = gi_probe_data[i]; - -				RID base_probe = gipi->probe; - -				Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera; - -				gipd.xform[0] = to_cell.basis.elements[0][0]; -				gipd.xform[1] = to_cell.basis.elements[1][0]; -				gipd.xform[2] = to_cell.basis.elements[2][0]; -				gipd.xform[3] = 0; -				gipd.xform[4] = to_cell.basis.elements[0][1]; -				gipd.xform[5] = to_cell.basis.elements[1][1]; -				gipd.xform[6] = to_cell.basis.elements[2][1]; -				gipd.xform[7] = 0; -				gipd.xform[8] = to_cell.basis.elements[0][2]; -				gipd.xform[9] = to_cell.basis.elements[1][2]; -				gipd.xform[10] = to_cell.basis.elements[2][2]; -				gipd.xform[11] = 0; -				gipd.xform[12] = to_cell.origin.x; -				gipd.xform[13] = to_cell.origin.y; -				gipd.xform[14] = to_cell.origin.z; -				gipd.xform[15] = 1; - -				Vector3 bounds = storage->gi_probe_get_octree_size(base_probe); - -				gipd.bounds[0] = bounds.x; -				gipd.bounds[1] = bounds.y; -				gipd.bounds[2] = bounds.z; - -				gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe); -				gipd.bias = storage->gi_probe_get_bias(base_probe); -				gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe); -				gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe); -				gipd.anisotropy_strength = 0; -				gipd.ao = storage->gi_probe_get_ao(base_probe); -				gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f); -				gipd.mipmaps = gipi->mipmaps.size(); -			} - -			r_gi_probes_used++; -		} - -		if (texture == RID()) { -			texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); -		} - -		if (texture != rb->giprobe_textures[i]) { -			giprobes_changed = true; -			rb->giprobe_textures[i] = texture; -		} -	} - -	if (giprobes_changed) { -		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(); -		if (rb->volumetric_fog) { -			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_set2); -			} -			rb->volumetric_fog->uniform_set = RID(); -			rb->volumetric_fog->uniform_set2 = RID(); -		} -	} - -	if (p_gi_probes.size() > 0) { -		RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE); -	} - -	RD::get_singleton()->draw_command_end_label(); -} - -void RendererSceneRenderRD::_pre_process_gi(RID p_render_buffers, const Transform &p_transform) { -	// Do the required buffer transfers and setup before the depth-pre pass, this way GI can -	// run in parallel during depth-pre pass and shadow rendering. -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(rb == nullptr); - -	/* Update Cascades UBO */ - -	if (rb->sdfgi) { -		/* Update general SDFGI Buffer */ - -		_sdfgi_update_cascades(p_render_buffers); - -		GI::SDFGIData sdfgi_data; - -		sdfgi_data.grid_size[0] = rb->sdfgi->cascade_size; -		sdfgi_data.grid_size[1] = rb->sdfgi->cascade_size; -		sdfgi_data.grid_size[2] = rb->sdfgi->cascade_size; - -		sdfgi_data.max_cascades = rb->sdfgi->cascades.size(); -		sdfgi_data.probe_axis_size = rb->sdfgi->probe_axis_count; -		sdfgi_data.cascade_probe_size[0] = sdfgi_data.probe_axis_size - 1; //float version for performance -		sdfgi_data.cascade_probe_size[1] = sdfgi_data.probe_axis_size - 1; -		sdfgi_data.cascade_probe_size[2] = sdfgi_data.probe_axis_size - 1; - -		float csize = rb->sdfgi->cascade_size; -		sdfgi_data.probe_to_uvw = 1.0 / float(sdfgi_data.cascade_probe_size[0]); -		sdfgi_data.use_occlusion = rb->sdfgi->uses_occlusion; -		//sdfgi_data.energy = rb->sdfgi->energy; - -		sdfgi_data.y_mult = rb->sdfgi->y_mult; - -		float cascade_voxel_size = (csize / sdfgi_data.cascade_probe_size[0]); -		float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size; -		sdfgi_data.occlusion_clamp[0] = occlusion_clamp; -		sdfgi_data.occlusion_clamp[1] = occlusion_clamp; -		sdfgi_data.occlusion_clamp[2] = occlusion_clamp; -		sdfgi_data.normal_bias = (rb->sdfgi->normal_bias / csize) * sdfgi_data.cascade_probe_size[0]; - -		//vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) ); -		//vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx; - -		uint32_t oct_size = SDFGI::LIGHTPROBE_OCT_SIZE; - -		sdfgi_data.lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size * sdfgi_data.probe_axis_size); -		sdfgi_data.lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size); -		sdfgi_data.lightprobe_tex_pixel_size[2] = 1.0; - -		sdfgi_data.energy = rb->sdfgi->energy; - -		sdfgi_data.lightprobe_uv_offset[0] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[0]; -		sdfgi_data.lightprobe_uv_offset[1] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[1]; -		sdfgi_data.lightprobe_uv_offset[2] = float((oct_size + 2) * sdfgi_data.probe_axis_size) * sdfgi_data.lightprobe_tex_pixel_size[0]; - -		sdfgi_data.occlusion_renormalize[0] = 0.5; -		sdfgi_data.occlusion_renormalize[1] = 1.0; -		sdfgi_data.occlusion_renormalize[2] = 1.0 / float(sdfgi_data.max_cascades); - -		int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; - -		for (uint32_t i = 0; i < sdfgi_data.max_cascades; i++) { -			GI::SDFGIData::ProbeCascadeData &c = sdfgi_data.cascades[i]; -			Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[i].position)) * rb->sdfgi->cascades[i].cell_size; -			Vector3 cam_origin = p_transform.origin; -			cam_origin.y *= rb->sdfgi->y_mult; -			pos -= cam_origin; //make pos local to camera, to reduce numerical error -			c.position[0] = pos.x; -			c.position[1] = pos.y; -			c.position[2] = pos.z; -			c.to_probe = 1.0 / (float(rb->sdfgi->cascade_size) * rb->sdfgi->cascades[i].cell_size / float(rb->sdfgi->probe_axis_count - 1)); - -			Vector3i probe_ofs = rb->sdfgi->cascades[i].position / probe_divisor; -			c.probe_world_offset[0] = probe_ofs.x; -			c.probe_world_offset[1] = probe_ofs.y; -			c.probe_world_offset[2] = probe_ofs.z; - -			c.to_cell = 1.0 / rb->sdfgi->cascades[i].cell_size; -		} - -		RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE); - -		/* Update dynamic lights in SDFGI cascades */ - -		for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { -			SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; - -			SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; -			uint32_t idx = 0; -			for (uint32_t j = 0; j < (uint32_t)render_state.sdfgi_update_data->directional_lights->size(); j++) { -				if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { -					break; -				} - -				LightInstance *li = light_instance_owner.getornull(render_state.sdfgi_update_data->directional_lights->get(j)); -				ERR_CONTINUE(!li); - -				if (storage->light_directional_is_sky_only(li->light)) { -					continue; -				} - -				Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); -				dir.y *= rb->sdfgi->y_mult; -				dir.normalize(); -				lights[idx].direction[0] = dir.x; -				lights[idx].direction[1] = dir.y; -				lights[idx].direction[2] = dir.z; -				Color color = storage->light_get_color(li->light); -				color = color.to_linear(); -				lights[idx].color[0] = color.r; -				lights[idx].color[1] = color.g; -				lights[idx].color[2] = color.b; -				lights[idx].type = RS::LIGHT_DIRECTIONAL; -				lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); -				lights[idx].has_shadow = storage->light_has_shadow(li->light); - -				idx++; -			} - -			AABB cascade_aabb; -			cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cascade.position)) * cascade.cell_size; -			cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cascade.cell_size; - -			for (uint32_t j = 0; j < render_state.sdfgi_update_data->positional_light_count; j++) { -				if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { -					break; -				} - -				LightInstance *li = light_instance_owner.getornull(render_state.sdfgi_update_data->positional_light_instances[j]); -				ERR_CONTINUE(!li); - -				uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); -				if (i > max_sdfgi_cascade) { -					continue; -				} - -				if (!cascade_aabb.intersects(li->aabb)) { -					continue; -				} - -				Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); -				//faster to not do this here -				//dir.y *= rb->sdfgi->y_mult; -				//dir.normalize(); -				lights[idx].direction[0] = dir.x; -				lights[idx].direction[1] = dir.y; -				lights[idx].direction[2] = dir.z; -				Vector3 pos = li->transform.origin; -				pos.y *= rb->sdfgi->y_mult; -				lights[idx].position[0] = pos.x; -				lights[idx].position[1] = pos.y; -				lights[idx].position[2] = pos.z; -				Color color = storage->light_get_color(li->light); -				color = color.to_linear(); -				lights[idx].color[0] = color.r; -				lights[idx].color[1] = color.g; -				lights[idx].color[2] = color.b; -				lights[idx].type = storage->light_get_type(li->light); -				lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); -				lights[idx].has_shadow = storage->light_has_shadow(li->light); -				lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); -				lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); -				lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE))); -				lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); - -				idx++; -			} - -			if (idx > 0) { -				RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, RD::BARRIER_MASK_COMPUTE); -			} - -			rb->sdfgi->cascade_dynamic_light_count[i] = idx; -		} -	} -} - -void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes) { -	RD::get_singleton()->draw_command_begin_label("GI Render"); - -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(rb == nullptr); -	Environment *env = environment_owner.getornull(p_environment); - -	if (rb->ambient_buffer.is_null() || rb->using_half_size_gi != gi.half_resolution) { -		if (rb->ambient_buffer.is_valid()) { -			RD::get_singleton()->free(rb->ambient_buffer); -			RD::get_singleton()->free(rb->reflection_buffer); -		} - -		RD::TextureFormat tf; -		tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; -		tf.width = rb->width; -		tf.height = rb->height; -		if (gi.half_resolution) { -			tf.width >>= 1; -			tf.height >>= 1; -		} -		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->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); -		rb->using_half_size_gi = gi.half_resolution; - -		_render_buffers_uniform_set_changed(p_render_buffers); -	} - -	GI::PushConstant push_constant; - -	push_constant.screen_size[0] = rb->width; -	push_constant.screen_size[1] = rb->height; -	push_constant.z_near = p_projection.get_z_near(); -	push_constant.z_far = p_projection.get_z_far(); -	push_constant.orthogonal = p_projection.is_orthogonal(); -	push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]); -	push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]); -	push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; -	push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; -	push_constant.max_giprobes = MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size()); -	push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH; - -	bool use_sdfgi = rb->sdfgi != nullptr; -	bool use_giprobes = push_constant.max_giprobes > 0; - -	if (env) { -		push_constant.ao_color[0] = env->ao_color.r; -		push_constant.ao_color[1] = env->ao_color.g; -		push_constant.ao_color[2] = env->ao_color.b; -	} else { -		push_constant.ao_color[0] = 0; -		push_constant.ao_color[1] = 0; -		push_constant.ao_color[2] = 0; -	} - -	push_constant.cam_rotation[0] = p_transform.basis[0][0]; -	push_constant.cam_rotation[1] = p_transform.basis[1][0]; -	push_constant.cam_rotation[2] = p_transform.basis[2][0]; -	push_constant.cam_rotation[3] = 0; -	push_constant.cam_rotation[4] = p_transform.basis[0][1]; -	push_constant.cam_rotation[5] = p_transform.basis[1][1]; -	push_constant.cam_rotation[6] = p_transform.basis[2][1]; -	push_constant.cam_rotation[7] = 0; -	push_constant.cam_rotation[8] = p_transform.basis[0][2]; -	push_constant.cam_rotation[9] = p_transform.basis[1][2]; -	push_constant.cam_rotation[10] = p_transform.basis[2][2]; -	push_constant.cam_rotation[11] = 0; - -	if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) { -		Vector<RD::Uniform> uniforms; -		{ -			RD::Uniform u; -			u.binding = 1; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { -				if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { -					u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex); -				} else { -					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -				} -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 2; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { -				if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { -					u.ids.push_back(rb->sdfgi->cascades[j].light_tex); -				} else { -					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -				} -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 3; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { -				if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { -					u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_0_tex); -				} else { -					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -				} -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 4; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { -				if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { -					u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_1_tex); -				} else { -					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -				} -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 5; -			if (rb->sdfgi) { -				u.ids.push_back(rb->sdfgi->occlusion_texture); -			} else { -				u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -			u.binding = 6; -			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -			u.binding = 7; -			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -			uniforms.push_back(u); -		} - -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -			u.binding = 9; -			u.ids.push_back(rb->ambient_buffer); -			uniforms.push_back(u); -		} - -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -			u.binding = 10; -			u.ids.push_back(rb->reflection_buffer); -			uniforms.push_back(u); -		} - -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 11; -			if (rb->sdfgi) { -				u.ids.push_back(rb->sdfgi->lightprobe_texture); -			} else { -				u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE)); -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 12; -			u.ids.push_back(rb->depth_texture); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 13; -			u.ids.push_back(p_normal_roughness_buffer); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 14; -			RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); -			u.ids.push_back(buffer); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -			u.binding = 15; -			u.ids.push_back(gi.sdfgi_ubo); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -			u.binding = 16; -			u.ids.push_back(rb->giprobe_buffer); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 17; -			for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { -				u.ids.push_back(rb->giprobe_textures[i]); -			} -			uniforms.push_back(u); -		} - -		rb->gi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi.shader.version_get_shader(gi.shader_version, 0), 0); -	} - -	GI::Mode mode; - -	if (rb->using_half_size_gi) { -		mode = (use_sdfgi && use_giprobes) ? GI::MODE_HALF_RES_COMBINED : (use_sdfgi ? GI::MODE_HALF_RES_SDFGI : GI::MODE_HALF_RES_GIPROBE); -	} else { -		mode = (use_sdfgi && use_giprobes) ? GI::MODE_COMBINED : (use_sdfgi ? GI::MODE_SDFGI : GI::MODE_GIPROBE); -	} -	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); -	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi.pipelines[mode]); -	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(GI::PushConstant)); +	ERR_FAIL_COND_V(rb == nullptr, -1); +	ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1); -	if (rb->using_half_size_gi) { -		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1); -	} else { -		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1); -	} -	//do barrier later to allow oeverlap -	//RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time -	RD::get_singleton()->draw_command_end_label(); +	return rb->sdfgi->get_pending_region_data(p_region, from, size, bounds);  }  RID RendererSceneRenderRD::sky_allocate() { -	return sky_owner.allocate_rid(); +	return sky.allocate_sky_rid();  }  void RendererSceneRenderRD::sky_initialize(RID p_rid) { -	sky_owner.initialize_rid(p_rid, Sky()); -} - -void RendererSceneRenderRD::_sky_invalidate(Sky *p_sky) { -	if (!p_sky->dirty) { -		p_sky->dirty = true; -		p_sky->dirty_list = dirty_sky_list; -		dirty_sky_list = p_sky; -	} +	sky.initialize_sky_rid(p_rid);  }  void RendererSceneRenderRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { -	Sky *sky = sky_owner.getornull(p_sky); -	ERR_FAIL_COND(!sky); -	ERR_FAIL_COND(p_radiance_size < 32 || p_radiance_size > 2048); -	if (sky->radiance_size == p_radiance_size) { -		return; -	} -	sky->radiance_size = p_radiance_size; - -	if (sky->mode == RS::SKY_MODE_REALTIME && sky->radiance_size != 256) { -		WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); -		sky->radiance_size = 256; -	} - -	_sky_invalidate(sky); -	if (sky->radiance.is_valid()) { -		RD::get_singleton()->free(sky->radiance); -		sky->radiance = RID(); -	} -	_clear_reflection_data(sky->reflection); +	sky.sky_set_radiance_size(p_sky, p_radiance_size);  }  void RendererSceneRenderRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { -	Sky *sky = sky_owner.getornull(p_sky); -	ERR_FAIL_COND(!sky); - -	if (sky->mode == p_mode) { -		return; -	} - -	sky->mode = p_mode; - -	if (sky->mode == RS::SKY_MODE_REALTIME && sky->radiance_size != 256) { -		WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); -		sky_set_radiance_size(p_sky, 256); -	} - -	_sky_invalidate(sky); -	if (sky->radiance.is_valid()) { -		RD::get_singleton()->free(sky->radiance); -		sky->radiance = RID(); -	} -	_clear_reflection_data(sky->reflection); +	sky.sky_set_mode(p_sky, p_mode);  }  void RendererSceneRenderRD::sky_set_material(RID p_sky, RID p_material) { -	Sky *sky = sky_owner.getornull(p_sky); -	ERR_FAIL_COND(!sky); -	sky->material = p_material; -	_sky_invalidate(sky); +	sky.sky_set_material(p_sky, p_material);  }  Ref<Image> RendererSceneRenderRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { -	Sky *sky = sky_owner.getornull(p_sky); -	ERR_FAIL_COND_V(!sky, Ref<Image>()); - -	_update_dirty_skys(); - -	if (sky->radiance.is_valid()) { -		RD::TextureFormat tf; -		tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; -		tf.width = p_size.width; -		tf.height = p_size.height; -		tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; - -		RID rad_tex = RD::get_singleton()->texture_create(tf, RD::TextureView()); -		storage->get_effects()->copy_cubemap_to_panorama(sky->radiance, rad_tex, p_size, p_bake_irradiance ? roughness_layers : 0, sky->reflection.layers.size() > 1); -		Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rad_tex, 0); -		RD::get_singleton()->free(rad_tex); - -		Ref<Image> img; -		img.instance(); -		img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data); -		for (int i = 0; i < p_size.width; i++) { -			for (int j = 0; j < p_size.height; j++) { -				Color c = img->get_pixel(i, j); -				c.r *= p_energy; -				c.g *= p_energy; -				c.b *= p_energy; -				img->set_pixel(i, j, c); -			} -		} -		return img; -	} - -	return Ref<Image>(); -} - -void RendererSceneRenderRD::_update_dirty_skys() { -	Sky *sky = dirty_sky_list; - -	while (sky) { -		bool texture_set_dirty = false; -		//update sky configuration if texture is missing - -		if (sky->radiance.is_null()) { -			int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1; - -			uint32_t w = sky->radiance_size, h = sky->radiance_size; -			int layers = roughness_layers; -			if (sky->mode == RS::SKY_MODE_REALTIME) { -				layers = 8; -				if (roughness_layers != 8) { -					WARN_PRINT("When using REALTIME skies, roughness_layers should be set to 8 in the project settings for best quality reflections"); -				} -			} - -			if (sky_use_cubemap_array) { -				//array (higher quality, 6 times more memory) -				RD::TextureFormat tf; -				tf.array_layers = layers * 6; -				tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; -				tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; -				tf.mipmaps = mipmaps; -				tf.width = w; -				tf.height = h; -				tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - -				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - -				_update_reflection_data(sky->reflection, sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME); - -			} else { -				//regular cubemap, lower quality (aliasing, less memory) -				RD::TextureFormat tf; -				tf.array_layers = 6; -				tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; -				tf.texture_type = RD::TEXTURE_TYPE_CUBE; -				tf.mipmaps = MIN(mipmaps, layers); -				tf.width = w; -				tf.height = h; -				tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - -				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - -				_update_reflection_data(sky->reflection, sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME); -			} -			texture_set_dirty = true; -		} - -		// Create subpass buffers if they haven't been created already -		if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) { -			RD::TextureFormat tformat; -			tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; -			tformat.width = sky->screen_size.x / 2; -			tformat.height = sky->screen_size.y / 2; -			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; -			tformat.texture_type = RD::TEXTURE_TYPE_2D; - -			sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); -			Vector<RID> texs; -			texs.push_back(sky->half_res_pass); -			sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs); -			texture_set_dirty = true; -		} - -		if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) { -			RD::TextureFormat tformat; -			tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; -			tformat.width = sky->screen_size.x / 4; -			tformat.height = sky->screen_size.y / 4; -			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; -			tformat.texture_type = RD::TEXTURE_TYPE_2D; - -			sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); -			Vector<RID> texs; -			texs.push_back(sky->quarter_res_pass); -			sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs); -			texture_set_dirty = true; -		} - -		if (texture_set_dirty) { -			for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) { -				if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) { -					RD::get_singleton()->free(sky->texture_uniform_sets[i]); -					sky->texture_uniform_sets[i] = RID(); -				} -			} -		} - -		sky->reflection.dirty = true; -		sky->processing_layer = 0; - -		Sky *next = sky->dirty_list; -		sky->dirty_list = nullptr; -		sky->dirty = false; -		sky = next; -	} - -	dirty_sky_list = nullptr; -} - -RID RendererSceneRenderRD::sky_get_radiance_texture_rd(RID p_sky) const { -	Sky *sky = sky_owner.getornull(p_sky); -	ERR_FAIL_COND_V(!sky, RID()); - -	return sky->radiance; -} - -RID RendererSceneRenderRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const { -	Sky *sky = sky_owner.getornull(p_sky); -	ERR_FAIL_COND_V(!sky, RID()); - -	if (sky->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(sky->uniform_set)) { -		sky->uniform_set = RID(); -		if (sky->radiance.is_valid()) { -			Vector<RD::Uniform> uniforms; -			{ -				RD::Uniform u; -				u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -				u.binding = 0; -				u.ids.push_back(sky->radiance); -				uniforms.push_back(u); -			} - -			sky->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set); -		} -	} - -	return sky->uniform_set; -} - -RID RendererSceneRenderRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version) { -	if (p_sky->texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(p_sky->texture_uniform_sets[p_version])) { -		return p_sky->texture_uniform_sets[p_version]; -	} -	Vector<RD::Uniform> uniforms; -	{ -		RD::Uniform u; -		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -		u.binding = 0; -		if (p_sky->radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) { -			u.ids.push_back(p_sky->radiance); -		} else { -			u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); -		} -		uniforms.push_back(u); -	} -	{ -		RD::Uniform u; -		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -		u.binding = 1; // half res -		if (p_sky->half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) { -			if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { -				u.ids.push_back(p_sky->reflection.layers[0].views[1]); -			} else { -				u.ids.push_back(p_sky->half_res_pass); -			} -		} else { -			if (p_version < SKY_TEXTURE_SET_CUBEMAP) { -				u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); -			} else { -				u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); -			} -		} -		uniforms.push_back(u); -	} -	{ -		RD::Uniform u; -		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -		u.binding = 2; // quarter res -		if (p_sky->quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) { -			if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { -				u.ids.push_back(p_sky->reflection.layers[0].views[2]); -			} else { -				u.ids.push_back(p_sky->quarter_res_pass); -			} -		} else { -			if (p_version < SKY_TEXTURE_SET_CUBEMAP) { -				u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); -			} else { -				u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); -			} -		} -		uniforms.push_back(u); -	} - -	p_sky->texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES); -	return p_sky->texture_uniform_sets[p_version]; -} - -RID RendererSceneRenderRD::sky_get_material(RID p_sky) const { -	Sky *sky = sky_owner.getornull(p_sky); -	ERR_FAIL_COND_V(!sky, RID()); - -	return sky->material; -} - -void RendererSceneRenderRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { -	ERR_FAIL_COND(!is_environment(p_environment)); - -	SkyMaterialData *material = nullptr; - -	Sky *sky = sky_owner.getornull(environment_get_sky(p_environment)); - -	RID sky_material; - -	RS::EnvironmentBG background = environment_get_background(p_environment); - -	if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { -		ERR_FAIL_COND(!sky); -		sky_material = sky_get_material(environment_get_sky(p_environment)); - -		if (sky_material.is_valid()) { -			material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); -			if (!material || !material->shader_data->valid) { -				material = nullptr; -			} -		} - -		if (!material) { -			sky_material = sky_shader.default_material; -			material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); -		} -	} - -	if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { -		sky_material = sky_scene_state.fog_material; -		material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); -	} - -	ERR_FAIL_COND(!material); - -	SkyShaderData *shader_data = material->shader_data; - -	ERR_FAIL_COND(!shader_data); - -	Basis sky_transform = environment_get_sky_orientation(p_environment); -	sky_transform.invert(); - -	float multiplier = environment_get_bg_energy(p_environment); -	float custom_fov = environment_get_sky_custom_fov(p_environment); -	// Camera -	CameraMatrix camera; - -	if (custom_fov) { -		float near_plane = p_projection.get_z_near(); -		float far_plane = p_projection.get_z_far(); -		float aspect = p_projection.get_aspect(); - -		camera.set_perspective(custom_fov, aspect, near_plane, far_plane); - -	} else { -		camera = p_projection; -	} - -	sky_transform = p_transform.basis * sky_transform; - -	if (shader_data->uses_quarter_res) { -		PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES]; - -		RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_QUARTER_RES); - -		Vector<Color> clear_colors; -		clear_colors.push_back(Color(0.0, 0.0, 0.0)); - -		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); -		storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); -		RD::get_singleton()->draw_list_end(); -	} - -	if (shader_data->uses_half_res) { -		PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES]; - -		RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_HALF_RES); - -		Vector<Color> clear_colors; -		clear_colors.push_back(Color(0.0, 0.0, 0.0)); - -		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); -		storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); -		RD::get_singleton()->draw_list_end(); -	} - -	PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND]; - -	RID texture_uniform_set; -	if (sky) { -		texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND); -	} else { -		texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set; -	} - -	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); -	storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); -	RD::get_singleton()->draw_list_end(); -} - -void RendererSceneRenderRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) { -	ERR_FAIL_COND(!is_environment(p_environment)); - -	SkyMaterialData *material = nullptr; - -	Sky *sky = sky_owner.getornull(environment_get_sky(p_environment)); - -	RID sky_material; - -	SkyShaderData *shader_data = nullptr; - -	RS::EnvironmentBG background = environment_get_background(p_environment); - -	if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { -		ERR_FAIL_COND(!sky); -		sky_material = sky_get_material(environment_get_sky(p_environment)); - -		if (sky_material.is_valid()) { -			material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); -			if (!material || !material->shader_data->valid) { -				material = nullptr; -			} -		} - -		if (!material) { -			sky_material = sky_shader.default_material; -			material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); -		} - -		ERR_FAIL_COND(!material); - -		shader_data = material->shader_data; - -		ERR_FAIL_COND(!shader_data); -	} - -	if (sky) { -		// Invalidate supbass buffers if screen size changes -		if (sky->screen_size != p_screen_size) { -			sky->screen_size = p_screen_size; -			sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x; -			sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y; -			if (shader_data->uses_half_res) { -				if (sky->half_res_pass.is_valid()) { -					RD::get_singleton()->free(sky->half_res_pass); -					sky->half_res_pass = RID(); -				} -				_sky_invalidate(sky); -			} -			if (shader_data->uses_quarter_res) { -				if (sky->quarter_res_pass.is_valid()) { -					RD::get_singleton()->free(sky->quarter_res_pass); -					sky->quarter_res_pass = RID(); -				} -				_sky_invalidate(sky); -			} -		} - -		// Create new subpass buffers if necessary -		if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) || -				(shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) || -				sky->radiance.is_null()) { -			_sky_invalidate(sky); -			_update_dirty_skys(); -		} - -		if (shader_data->uses_time && time - sky->prev_time > 0.00001) { -			sky->prev_time = time; -			sky->reflection.dirty = true; -			RenderingServerDefault::redraw_request(); -		} - -		if (material != sky->prev_material) { -			sky->prev_material = material; -			sky->reflection.dirty = true; -		} - -		if (material->uniform_set_updated) { -			material->uniform_set_updated = false; -			sky->reflection.dirty = true; -		} - -		if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) { -			sky->prev_position = p_transform.origin; -			sky->reflection.dirty = true; -		} - -		if (shader_data->uses_light) { -			// Check whether the directional_light_buffer changes -			bool light_data_dirty = false; - -			if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) { -				light_data_dirty = true; -				for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) { -					sky_scene_state.directional_lights[i].enabled = false; -				} -			} -			if (!light_data_dirty) { -				for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) { -					if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] || -							sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] || -							sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] || -							sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy || -							sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] || -							sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] || -							sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] || -							sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled || -							sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) { -						light_data_dirty = true; -						break; -					} -				} -			} - -			if (light_data_dirty) { -				RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights); - -				RendererSceneRenderRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights; -				sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights; -				sky_scene_state.directional_lights = temp; -				sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count; -				sky->reflection.dirty = true; -			} -		} -	} - -	//setup fog variables -	sky_scene_state.ubo.volumetric_fog_enabled = false; -	if (p_render_buffers.is_valid()) { -		if (render_buffers_has_volumetric_fog(p_render_buffers)) { -			sky_scene_state.ubo.volumetric_fog_enabled = true; - -			float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers); -			if (fog_end > 0.0) { -				sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end; -			} else { -				sky_scene_state.ubo.volumetric_fog_inv_length = 1.0; -			} - -			float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup -			if (fog_detail_spread > 0.0) { -				sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread; -			} else { -				sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0; -			} -		} - -		RID fog_uniform_set = render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers); - -		if (fog_uniform_set != RID()) { -			sky_scene_state.fog_uniform_set = fog_uniform_set; -		} else { -			sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set; -		} -	} - -	sky_scene_state.ubo.z_far = p_projection.get_z_far(); -	sky_scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment); -	sky_scene_state.ubo.fog_density = environment_get_fog_density(p_environment); -	sky_scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment); -	Color fog_color = environment_get_fog_light_color(p_environment).to_linear(); -	float fog_energy = environment_get_fog_light_energy(p_environment); -	sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; -	sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; -	sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; -	sky_scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment); - -	RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo); -} - -void RendererSceneRenderRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { -	ERR_FAIL_COND(!is_environment(p_environment)); - -	Sky *sky = sky_owner.getornull(environment_get_sky(p_environment)); -	ERR_FAIL_COND(!sky); - -	RID sky_material = sky_get_material(environment_get_sky(p_environment)); - -	SkyMaterialData *material = nullptr; - -	if (sky_material.is_valid()) { -		material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); -		if (!material || !material->shader_data->valid) { -			material = nullptr; -		} -	} - -	if (!material) { -		sky_material = sky_shader.default_material; -		material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); -	} - -	ERR_FAIL_COND(!material); - -	SkyShaderData *shader_data = material->shader_data; - -	ERR_FAIL_COND(!shader_data); - -	float multiplier = environment_get_bg_energy(p_environment); - -	bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY; -	RS::SkyMode sky_mode = sky->mode; - -	if (sky_mode == RS::SKY_MODE_AUTOMATIC) { -		if (shader_data->uses_time || shader_data->uses_position) { -			update_single_frame = true; -			sky_mode = RS::SKY_MODE_REALTIME; -		} else if (shader_data->uses_light || shader_data->ubo_size > 0) { -			update_single_frame = false; -			sky_mode = RS::SKY_MODE_INCREMENTAL; -		} else { -			update_single_frame = true; -			sky_mode = RS::SKY_MODE_QUALITY; -		} -	} - -	if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) { -		// On the first frame after creating sky, rebuild in single frame -		update_single_frame = true; -		sky_mode = RS::SKY_MODE_QUALITY; -	} - -	int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size(); - -	// Update radiance cubemap -	if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) { -		static const Vector3 view_normals[6] = { -			Vector3(+1, 0, 0), -			Vector3(-1, 0, 0), -			Vector3(0, +1, 0), -			Vector3(0, -1, 0), -			Vector3(0, 0, +1), -			Vector3(0, 0, -1) -		}; -		static const Vector3 view_up[6] = { -			Vector3(0, -1, 0), -			Vector3(0, -1, 0), -			Vector3(0, 0, +1), -			Vector3(0, 0, -1), -			Vector3(0, -1, 0), -			Vector3(0, -1, 0) -		}; - -		CameraMatrix cm; -		cm.set_perspective(90, 1, 0.01, 10.0); -		CameraMatrix correction; -		correction.set_depth_correction(true); -		cm = correction * cm; - -		if (shader_data->uses_quarter_res) { -			PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; - -			Vector<Color> clear_colors; -			clear_colors.push_back(Color(0.0, 0.0, 0.0)); -			RD::DrawListID cubemap_draw_list; - -			for (int i = 0; i < 6; i++) { -				Transform local_view; -				local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); -				RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES); - -				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); -				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); -				RD::get_singleton()->draw_list_end(); -			} -		} - -		if (shader_data->uses_half_res) { -			PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; - -			Vector<Color> clear_colors; -			clear_colors.push_back(Color(0.0, 0.0, 0.0)); -			RD::DrawListID cubemap_draw_list; - -			for (int i = 0; i < 6; i++) { -				Transform local_view; -				local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); -				RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_HALF_RES); - -				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); -				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); -				RD::get_singleton()->draw_list_end(); -			} -		} - -		RD::DrawListID cubemap_draw_list; -		PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; - -		for (int i = 0; i < 6; i++) { -			Transform local_view; -			local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); -			RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP); - -			cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); -			storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); -			RD::get_singleton()->draw_list_end(); -		} - -		if (sky_mode == RS::SKY_MODE_REALTIME) { -			_create_reflection_fast_filter(sky->reflection, sky_use_cubemap_array); -			if (sky_use_cubemap_array) { -				_update_reflection_mipmaps(sky->reflection, 0, sky->reflection.layers.size()); -			} -		} else { -			if (update_single_frame) { -				for (int i = 1; i < max_processing_layer; i++) { -					_create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, i); -				} -				if (sky_use_cubemap_array) { -					_update_reflection_mipmaps(sky->reflection, 0, sky->reflection.layers.size()); -				} -			} else { -				if (sky_use_cubemap_array) { -					// Multi-Frame so just update the first array level -					_update_reflection_mipmaps(sky->reflection, 0, 1); -				} -			} -			sky->processing_layer = 1; -		} - -		sky->reflection.dirty = false; - -	} else { -		if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) { -			_create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, sky->processing_layer); - -			if (sky_use_cubemap_array) { -				_update_reflection_mipmaps(sky->reflection, sky->processing_layer, sky->processing_layer + 1); -			} - -			sky->processing_layer++; -		} -	} -} - -/* SKY SHADER */ - -void RendererSceneRenderRD::SkyShaderData::set_code(const String &p_code) { -	//compile - -	code = p_code; -	valid = false; -	ubo_size = 0; -	uniforms.clear(); - -	if (code == String()) { -		return; //just invalid, but no error -	} - -	ShaderCompilerRD::GeneratedCode gen_code; -	ShaderCompilerRD::IdentifierActions actions; - -	uses_time = false; -	uses_half_res = false; -	uses_quarter_res = false; -	uses_position = false; -	uses_light = false; - -	actions.render_mode_flags["use_half_res_pass"] = &uses_half_res; -	actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res; - -	actions.usage_flag_pointers["TIME"] = &uses_time; -	actions.usage_flag_pointers["POSITION"] = &uses_position; -	actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light; -	actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light; -	actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light; -	actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light; -	actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light; -	actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light; -	actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light; -	actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light; -	actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light; -	actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light; -	actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light; -	actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light; -	actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light; -	actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light; -	actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light; -	actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light; -	actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light; -	actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light; -	actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light; -	actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light; - -	actions.uniforms = &uniforms; - -	RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; - -	Error err = scene_singleton->sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code); - -	ERR_FAIL_COND(err != OK); - -	if (version.is_null()) { -		version = scene_singleton->sky_shader.shader.version_create(); -	} - -#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 - -	scene_singleton->sky_shader.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(!scene_singleton->sky_shader.shader.version_is_valid(version)); - -	ubo_size = gen_code.uniform_total_size; -	ubo_offsets = gen_code.uniform_offsets; -	texture_uniforms = gen_code.texture_uniforms; - -	//update pipelines - -	for (int i = 0; i < SKY_VERSION_MAX; i++) { -		RD::PipelineDepthStencilState depth_stencil_state; -		depth_stencil_state.enable_depth_test = true; -		depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - -		RID shader_variant = scene_singleton->sky_shader.shader.version_get_shader(version, i); -		pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0); -	} - -	valid = true; -} - -void RendererSceneRenderRD::SkyShaderData::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 RendererSceneRenderRD::SkyShaderData::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_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { -			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 RendererSceneRenderRD::SkyShaderData::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 RendererSceneRenderRD::SkyShaderData::is_param_texture(const StringName &p_param) const { -	if (!uniforms.has(p_param)) { -		return false; -	} - -	return uniforms[p_param].texture_order >= 0; -} - -bool RendererSceneRenderRD::SkyShaderData::is_animated() const { -	return false; -} - -bool RendererSceneRenderRD::SkyShaderData::casts_shadows() const { -	return false; -} - -Variant RendererSceneRenderRD::SkyShaderData::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 RendererSceneRenderRD::SkyShaderData::get_native_source_code() const { -	RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; - -	return scene_singleton->sky_shader.shader.version_get_native_source_code(version); -} - -RendererSceneRenderRD::SkyShaderData::SkyShaderData() { -	valid = false; -} - -RendererSceneRenderRD::SkyShaderData::~SkyShaderData() { -	RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; -	ERR_FAIL_COND(!scene_singleton); -	//pipeline variants will clear themselves if shader is gone -	if (version.is_valid()) { -		scene_singleton->sky_shader.shader.version_free(version); -	} -} - -RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_sky_shader_func() { -	SkyShaderData *shader_data = memnew(SkyShaderData); -	return shader_data; -} - -void RendererSceneRenderRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { -	RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; - -	uniform_set_updated = true; - -	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()); -	} - -	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, scene_singleton->sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL); -} - -RendererSceneRenderRD::SkyMaterialData::~SkyMaterialData() { -	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 *RendererSceneRenderRD::_create_sky_material_func(SkyShaderData *p_shader) { -	SkyMaterialData *material_data = memnew(SkyMaterialData); -	material_data->shader_data = p_shader; -	material_data->last_frame = false; -	//update will happen later anyway so do nothing. -	return material_data; +	return sky.sky_bake_panorama(p_sky, p_energy, p_bake_irradiance, p_size);  }  RID RendererSceneRenderRD::environment_allocate() {  	return environment_owner.allocate_rid();  }  void RendererSceneRenderRD::environment_initialize(RID p_rid) { -	environment_owner.initialize_rid(p_rid, Environment()); +	environment_owner.initialize_rid(p_rid, RendererSceneEnvironmentRD());  }  void RendererSceneRenderRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	env->background = p_bg;  }  void RendererSceneRenderRD::environment_set_sky(RID p_env, RID p_sky) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	env->sky = p_sky;  }  void RendererSceneRenderRD::environment_set_sky_custom_fov(RID p_env, float p_scale) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	env->sky_custom_fov = p_scale;  }  void RendererSceneRenderRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	env->sky_orientation = p_orientation;  }  void RendererSceneRenderRD::environment_set_bg_color(RID p_env, const Color &p_color) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	env->bg_color = p_color;  }  void RendererSceneRenderRD::environment_set_bg_energy(RID p_env, float p_energy) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	env->bg_energy = p_energy;  }  void RendererSceneRenderRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	env->canvas_max_layer = p_max_layer;  }  void RendererSceneRenderRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env); -	env->ambient_light = p_color; -	env->ambient_source = p_ambient; -	env->ambient_light_energy = p_energy; -	env->ambient_sky_contribution = p_sky_contribution; -	env->reflection_source = p_reflection_source; -	env->ao_color = p_ao_color; +	env->set_ambient_light(p_color, p_ambient, p_energy, p_sky_contribution, p_reflection_source, p_ao_color);  }  RS::EnvironmentBG RendererSceneRenderRD::environment_get_background(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX);  	return env->background;  }  RID RendererSceneRenderRD::environment_get_sky(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, RID());  	return env->sky;  }  float RendererSceneRenderRD::environment_get_sky_custom_fov(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->sky_custom_fov;  }  Basis RendererSceneRenderRD::environment_get_sky_orientation(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, Basis());  	return env->sky_orientation;  }  Color RendererSceneRenderRD::environment_get_bg_color(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, Color());  	return env->bg_color;  }  float RendererSceneRenderRD::environment_get_bg_energy(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->bg_energy;  }  int RendererSceneRenderRD::environment_get_canvas_max_layer(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->canvas_max_layer;  }  Color RendererSceneRenderRD::environment_get_ambient_light_color(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, Color());  	return env->ambient_light;  }  RS::EnvironmentAmbientSource RendererSceneRenderRD::environment_get_ambient_source(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG);  	return env->ambient_source;  }  float RendererSceneRenderRD::environment_get_ambient_light_energy(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->ambient_light_energy;  }  float RendererSceneRenderRD::environment_get_ambient_sky_contribution(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->ambient_sky_contribution;  }  RS::EnvironmentReflectionSource RendererSceneRenderRD::environment_get_reflection_source(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, RS::ENV_REFLECTION_SOURCE_DISABLED);  	return env->reflection_source;  }  Color RendererSceneRenderRD::environment_get_ao_color(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, Color());  	return env->ao_color;  }  void RendererSceneRenderRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env); -	env->exposure = p_exposure; -	env->tone_mapper = p_tone_mapper; -	if (!env->auto_exposure && p_auto_exposure) { -		env->auto_exposure_version = ++auto_exposure_counter; -	} -	env->auto_exposure = p_auto_exposure; -	env->white = p_white; -	env->min_luminance = p_min_luminance; -	env->max_luminance = p_max_luminance; -	env->auto_exp_speed = p_auto_exp_speed; -	env->auto_exp_scale = p_auto_exp_scale; +	env->set_tonemap(p_tone_mapper, p_exposure, p_white, p_auto_exposure, p_min_luminance, p_max_luminance, p_auto_exp_speed, p_auto_exp_scale);  }  void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env); -	ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7"); -	env->glow_enabled = p_enable; -	env->glow_levels = p_levels; -	env->glow_intensity = p_intensity; -	env->glow_strength = p_strength; -	env->glow_mix = p_mix; -	env->glow_bloom = p_bloom_threshold; -	env->glow_blend_mode = p_blend_mode; -	env->glow_hdr_bleed_threshold = p_hdr_bleed_threshold; -	env->glow_hdr_bleed_scale = p_hdr_bleed_scale; -	env->glow_hdr_luminance_cap = p_hdr_luminance_cap; +	env->set_glow(p_enable, p_levels, p_intensity, p_strength, p_mix, p_bloom_threshold, p_blend_mode, p_hdr_bleed_threshold, p_hdr_bleed_scale, p_hdr_luminance_cap);  }  void RendererSceneRenderRD::environment_glow_set_use_bicubic_upscale(bool p_enable) { @@ -3088,100 +314,76 @@ void RendererSceneRenderRD::environment_glow_set_use_high_quality(bool p_enable)  }  void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	if (low_end) {  		return;  	} -	env->sdfgi_enabled = p_enable; -	env->sdfgi_cascades = p_cascades; -	env->sdfgi_min_cell_size = p_min_cell_size; -	env->sdfgi_use_occlusion = p_use_occlusion; -	env->sdfgi_bounce_feedback = p_bounce_feedback; -	env->sdfgi_read_sky_light = p_read_sky; -	env->sdfgi_energy = p_energy; -	env->sdfgi_normal_bias = p_normal_bias; -	env->sdfgi_probe_bias = p_probe_bias; -	env->sdfgi_y_scale = p_y_scale; +	env->set_sdfgi(p_enable, p_cascades, p_min_cell_size, p_y_scale, p_use_occlusion, p_bounce_feedback, p_read_sky, p_energy, p_normal_bias, p_probe_bias);  }  void RendererSceneRenderRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env); -	env->fog_enabled = p_enable; -	env->fog_light_color = p_light_color; -	env->fog_light_energy = p_light_energy; -	env->fog_sun_scatter = p_sun_scatter; -	env->fog_density = p_density; -	env->fog_height = p_height; -	env->fog_height_density = p_height_density; -	env->fog_aerial_perspective = p_fog_aerial_perspective; +	env->set_fog(p_enable, p_light_color, p_light_energy, p_sun_scatter, p_density, p_height, p_height_density, p_fog_aerial_perspective);  }  bool RendererSceneRenderRD::environment_is_fog_enabled(RID p_env) const { -	const Environment *env = environment_owner.getornull(p_env); +	const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, false);  	return env->fog_enabled;  }  Color RendererSceneRenderRD::environment_get_fog_light_color(RID p_env) const { -	const Environment *env = environment_owner.getornull(p_env); +	const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, Color());  	return env->fog_light_color;  }  float RendererSceneRenderRD::environment_get_fog_light_energy(RID p_env) const { -	const Environment *env = environment_owner.getornull(p_env); +	const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->fog_light_energy;  }  float RendererSceneRenderRD::environment_get_fog_sun_scatter(RID p_env) const { -	const Environment *env = environment_owner.getornull(p_env); +	const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->fog_sun_scatter;  }  float RendererSceneRenderRD::environment_get_fog_density(RID p_env) const { -	const Environment *env = environment_owner.getornull(p_env); +	const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->fog_density;  }  float RendererSceneRenderRD::environment_get_fog_height(RID p_env) const { -	const Environment *env = environment_owner.getornull(p_env); +	const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->fog_height;  }  float RendererSceneRenderRD::environment_get_fog_height_density(RID p_env) const { -	const Environment *env = environment_owner.getornull(p_env); +	const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->fog_height_density;  }  float RendererSceneRenderRD::environment_get_fog_aerial_perspective(RID p_env) const { -	const Environment *env = environment_owner.getornull(p_env); +	const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0);  	return env->fog_aerial_perspective;  }  void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	if (low_end) {  		return;  	} -	env->volumetric_fog_enabled = p_enable; -	env->volumetric_fog_density = p_density; -	env->volumetric_fog_light = p_light; -	env->volumetric_fog_light_energy = p_light_energy; -	env->volumetric_fog_length = p_length; -	env->volumetric_fog_detail_spread = p_detail_spread; -	env->volumetric_fog_gi_inject = p_gi_inject; -	env->volumetric_fog_temporal_reprojection = p_temporal_reprojection; -	env->volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount; +	env->set_volumetric_fog(p_enable, p_density, p_light, p_light_energy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount);  }  void RendererSceneRenderRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) { @@ -3194,29 +396,25 @@ void RendererSceneRenderRD::environment_set_volumetric_fog_filter_active(bool p_  }  void RendererSceneRenderRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) { -	sdfgi_ray_count = p_ray_count; +	gi.sdfgi_ray_count = p_ray_count;  }  void RendererSceneRenderRD::environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) { -	sdfgi_frames_to_converge = p_frames; +	gi.sdfgi_frames_to_converge = p_frames;  }  void RendererSceneRenderRD::environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) { -	sdfgi_frames_to_update_light = p_update; +	gi.sdfgi_frames_to_update_light = p_update;  }  void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	if (low_end) {  		return;  	} -	env->ssr_enabled = p_enable; -	env->ssr_max_steps = p_max_steps; -	env->ssr_fade_in = p_fade_int; -	env->ssr_fade_out = p_fade_out; -	env->ssr_depth_tolerance = p_depth_tolerance; +	env->set_ssr(p_enable, p_max_steps, p_fade_int, p_fade_out, p_depth_tolerance);  }  void RendererSceneRenderRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { @@ -3228,22 +426,14 @@ RS::EnvironmentSSRRoughnessQuality RendererSceneRenderRD::environment_get_ssr_ro  }  void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	if (low_end) {  		return;  	} -	env->ssao_enabled = p_enable; -	env->ssao_radius = p_radius; -	env->ssao_intensity = p_intensity; -	env->ssao_power = p_power; -	env->ssao_detail = p_detail; -	env->ssao_horizon = p_horizon; -	env->ssao_sharpness = p_sharpness; -	env->ssao_direct_light_affect = p_light_affect; -	env->ssao_ao_channel_affect = p_ao_channel_affect; +	env->set_ssao(p_enable, p_radius, p_intensity, p_power, p_detail, p_horizon, p_sharpness, p_light_affect, p_ao_channel_affect);  }  void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { @@ -3256,30 +446,30 @@ void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQual  }  bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, false);  	return env->ssao_enabled;  }  float RendererSceneRenderRD::environment_get_ssao_ao_affect(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0.0);  	return env->ssao_ao_channel_affect;  }  float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, 0.0);  	return env->ssao_direct_light_affect;  }  bool RendererSceneRenderRD::environment_is_ssr_enabled(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, false);  	return env->ssr_enabled;  }  bool RendererSceneRenderRD::environment_is_sdfgi_enabled(RID p_env) const { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, false);  	return env->sdfgi_enabled;  } @@ -3289,7 +479,7 @@ bool RendererSceneRenderRD::is_environment(RID p_env) const {  }  Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND_V(!env, Ref<Image>());  	if (env->background == RS::ENV_BG_CAMERA_FEED || env->background == RS::ENV_BG_CANVAS || env->background == RS::ENV_BG_KEEP) { @@ -3359,7 +549,7 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref  		RD::get_singleton()->free(ra->depth_buffer);  		ra->depth_buffer = RID();  		for (int i = 0; i < ra->reflections.size(); i++) { -			_clear_reflection_data(ra->reflections.write[i].data); +			ra->reflections.write[i].data.clear_reflection_data();  			if (ra->reflections[i].owner.is_null()) {  				continue;  			} @@ -3463,7 +653,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc  	}  	if (atlas->reflection.is_null()) { -		int mipmaps = MIN(roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1); +		int mipmaps = MIN(sky.roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);  		mipmaps = storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS ? 8 : mipmaps; // always use 8 mipmaps with real time filtering  		{  			//reflection atlas was unused, create: @@ -3488,7 +678,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc  		}  		atlas->reflections.resize(atlas->count);  		for (int i = 0; i < atlas->count; i++) { -			_update_reflection_data(atlas->reflections.write[i].data, atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS); +			atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers);  			for (int j = 0; j < 6; j++) {  				Vector<RID> fb;  				fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]); @@ -3548,7 +738,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins  	if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) {  		// Using real time reflections, all roughness is done in one step -		_create_reflection_fast_filter(atlas->reflections.write[rpi->atlas_index].data, false); +		atlas->reflections.write[rpi->atlas_index].data.create_reflection_fast_filter(storage, false);  		rpi->rendering = false;  		rpi->processing_side = 0;  		rpi->processing_layer = 1; @@ -3556,7 +746,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins  	}  	if (rpi->processing_layer > 1) { -		_create_reflection_importance_sample(atlas->reflections.write[rpi->atlas_index].data, false, 10, rpi->processing_layer); +		atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(storage, false, 10, rpi->processing_layer, sky.sky_ggx_samples_quality);  		rpi->processing_layer++;  		if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) {  			rpi->rendering = false; @@ -3567,7 +757,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins  		return false;  	} else { -		_create_reflection_importance_sample(atlas->reflections.write[rpi->atlas_index].data, false, rpi->processing_side, rpi->processing_layer); +		atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(storage, false, rpi->processing_side, rpi->processing_layer, sky.sky_ggx_samples_quality);  	}  	rpi->processing_side++; @@ -4142,21 +1332,18 @@ void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, cons  /////////////////////////////////  RID RendererSceneRenderRD::gi_probe_instance_create(RID p_base) { -	GIProbeInstance gi_probe; -	gi_probe.probe = p_base; -	RID rid = gi_probe_instance_owner.make_rid(gi_probe); -	return rid; +	return gi.gi_probe_instance_create(p_base);  }  void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { -	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); +	RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_probe);  	ERR_FAIL_COND(!gi_probe);  	gi_probe->transform = p_xform;  }  bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const { -	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); +	RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_probe);  	ERR_FAIL_COND_V(!gi_probe, false);  	if (low_end) { @@ -4168,791 +1355,14 @@ bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const {  }  void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) { -	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); +	RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_probe);  	ERR_FAIL_COND(!gi_probe);  	if (low_end) {  		return;  	} -	uint32_t data_version = storage->gi_probe_get_data_version(gi_probe->probe); - -	// (RE)CREATE IF NEEDED - -	if (gi_probe->last_probe_data_version != data_version) { -		//need to re-create everything -		if (gi_probe->texture.is_valid()) { -			RD::get_singleton()->free(gi_probe->texture); -			RD::get_singleton()->free(gi_probe->write_buffer); -			gi_probe->mipmaps.clear(); -		} - -		for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) { -			RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture); -			RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth); -		} - -		gi_probe->dynamic_maps.clear(); - -		Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe); - -		if (octree_size != Vector3i()) { -			//can create a 3D texture -			Vector<int> levels = storage->gi_probe_get_level_counts(gi_probe->probe); - -			RD::TextureFormat tf; -			tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; -			tf.width = octree_size.x; -			tf.height = octree_size.y; -			tf.depth = octree_size.z; -			tf.texture_type = RD::TEXTURE_TYPE_3D; -			tf.mipmaps = levels.size(); - -			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; - -			gi_probe->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - -			RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1); - -			{ -				int total_elements = 0; -				for (int i = 0; i < levels.size(); i++) { -					total_elements += levels[i]; -				} - -				gi_probe->write_buffer = RD::get_singleton()->storage_buffer_create(total_elements * 16); -			} - -			for (int i = 0; i < levels.size(); i++) { -				GIProbeInstance::Mipmap mipmap; -				mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), gi_probe->texture, 0, i, RD::TEXTURE_SLICE_3D); -				mipmap.level = levels.size() - i - 1; -				mipmap.cell_offset = 0; -				for (uint32_t j = 0; j < mipmap.level; j++) { -					mipmap.cell_offset += levels[j]; -				} -				mipmap.cell_count = levels[mipmap.level]; - -				Vector<RD::Uniform> uniforms; -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -					u.binding = 1; -					u.ids.push_back(storage->gi_probe_get_octree_buffer(gi_probe->probe)); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -					u.binding = 2; -					u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe)); -					uniforms.push_back(u); -				} - -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -					u.binding = 4; -					u.ids.push_back(gi_probe->write_buffer); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -					u.binding = 9; -					u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -					u.binding = 10; -					u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -					uniforms.push_back(u); -				} - -				{ -					Vector<RD::Uniform> copy_uniforms = uniforms; -					if (i == 0) { -						{ -							RD::Uniform u; -							u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -							u.binding = 3; -							u.ids.push_back(gi_probe_lights_uniform); -							copy_uniforms.push_back(u); -						} - -						mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0); - -						copy_uniforms = uniforms; //restore - -						{ -							RD::Uniform u; -							u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -							u.binding = 5; -							u.ids.push_back(gi_probe->texture); -							copy_uniforms.push_back(u); -						} -						mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0); -					} else { -						mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0); -					} -				} - -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -					u.binding = 5; -					u.ids.push_back(mipmap.texture); -					uniforms.push_back(u); -				} - -				mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0); - -				gi_probe->mipmaps.push_back(mipmap); -			} - -			{ -				uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z); -				uint32_t oversample = nearest_power_of_2_templated(4); -				int mipmap_index = 0; - -				while (mipmap_index < gi_probe->mipmaps.size()) { -					GIProbeInstance::DynamicMap dmap; - -					if (oversample > 0) { -						dmap.size = dynamic_map_size * (1 << oversample); -						dmap.mipmap = -1; -						oversample--; -					} else { -						dmap.size = dynamic_map_size >> mipmap_index; -						dmap.mipmap = mipmap_index; -						mipmap_index++; -					} - -					RD::TextureFormat dtf; -					dtf.width = dmap.size; -					dtf.height = dmap.size; -					dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; -					dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; - -					if (gi_probe->dynamic_maps.size() == 0) { -						dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; -					} -					dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView()); - -					if (gi_probe->dynamic_maps.size() == 0) { -						//render depth for first one -						dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; -						dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; -						dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView()); -					} - -					//just use depth as-is -					dtf.format = RD::DATA_FORMAT_R32_SFLOAT; -					dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - -					dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView()); - -					if (gi_probe->dynamic_maps.size() == 0) { -						dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; -						dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; -						dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView()); -						dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView()); -						dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView()); - -						Vector<RID> fb; -						fb.push_back(dmap.albedo); -						fb.push_back(dmap.normal); -						fb.push_back(dmap.orm); -						fb.push_back(dmap.texture); //emission -						fb.push_back(dmap.depth); -						fb.push_back(dmap.fb_depth); - -						dmap.fb = RD::get_singleton()->framebuffer_create(fb); - -						{ -							Vector<RD::Uniform> uniforms; -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -								u.binding = 3; -								u.ids.push_back(gi_probe_lights_uniform); -								uniforms.push_back(u); -							} - -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -								u.binding = 5; -								u.ids.push_back(dmap.albedo); -								uniforms.push_back(u); -							} -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -								u.binding = 6; -								u.ids.push_back(dmap.normal); -								uniforms.push_back(u); -							} -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -								u.binding = 7; -								u.ids.push_back(dmap.orm); -								uniforms.push_back(u); -							} -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -								u.binding = 8; -								u.ids.push_back(dmap.fb_depth); -								uniforms.push_back(u); -							} -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -								u.binding = 9; -								u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); -								uniforms.push_back(u); -							} -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -								u.binding = 10; -								u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -								uniforms.push_back(u); -							} -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -								u.binding = 11; -								u.ids.push_back(dmap.texture); -								uniforms.push_back(u); -							} -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -								u.binding = 12; -								u.ids.push_back(dmap.depth); -								uniforms.push_back(u); -							} - -							dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0); -						} -					} else { -						bool plot = dmap.mipmap >= 0; -						bool write = dmap.mipmap < (gi_probe->mipmaps.size() - 1); - -						Vector<RD::Uniform> uniforms; - -						{ -							RD::Uniform u; -							u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -							u.binding = 5; -							u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture); -							uniforms.push_back(u); -						} -						{ -							RD::Uniform u; -							u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -							u.binding = 6; -							u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth); -							uniforms.push_back(u); -						} - -						if (write) { -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -								u.binding = 7; -								u.ids.push_back(dmap.texture); -								uniforms.push_back(u); -							} -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -								u.binding = 8; -								u.ids.push_back(dmap.depth); -								uniforms.push_back(u); -							} -						} - -						{ -							RD::Uniform u; -							u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -							u.binding = 9; -							u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); -							uniforms.push_back(u); -						} -						{ -							RD::Uniform u; -							u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -							u.binding = 10; -							u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -							uniforms.push_back(u); -						} - -						if (plot) { -							{ -								RD::Uniform u; -								u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -								u.binding = 11; -								u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture); -								uniforms.push_back(u); -							} -						} - -						dmap.uniform_set = RD::get_singleton()->uniform_set_create( -								uniforms, -								giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)], -								0); -					} - -					gi_probe->dynamic_maps.push_back(dmap); -				} -			} -		} - -		gi_probe->last_probe_data_version = data_version; -		p_update_light_instances = true; //just in case - -		_base_uniforms_changed(); -	} - -	// UDPDATE TIME - -	if (gi_probe->has_dynamic_object_data) { -		//if it has dynamic object data, it needs to be cleared -		RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1); -	} - -	uint32_t light_count = 0; - -	if (p_update_light_instances || p_dynamic_objects.size() > 0) { -		light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size()); - -		{ -			Transform to_cell = storage->gi_probe_get_to_cell_xform(gi_probe->probe); -			Transform to_probe_xform = (gi_probe->transform * to_cell.affine_inverse()).affine_inverse(); -			//update lights - -			for (uint32_t i = 0; i < light_count; i++) { -				GIProbeLight &l = gi_probe_lights[i]; -				RID light_instance = p_light_instances[i]; -				RID light = light_instance_get_base_light(light_instance); - -				l.type = storage->light_get_type(light); -				if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) { -					light_count--; -					continue; -				} - -				l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION); -				l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY); -				l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length(); -				Color color = storage->light_get_color(light).to_linear(); -				l.color[0] = color.r; -				l.color[1] = color.g; -				l.color[2] = color.b; - -				l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE))); -				l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION); - -				Transform xform = light_instance_get_base_transform(light_instance); - -				Vector3 pos = to_probe_xform.xform(xform.origin); -				Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized(); - -				l.position[0] = pos.x; -				l.position[1] = pos.y; -				l.position[2] = pos.z; - -				l.direction[0] = dir.x; -				l.direction[1] = dir.y; -				l.direction[2] = dir.z; - -				l.has_shadow = storage->light_has_shadow(light); -			} - -			RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights); -		} -	} - -	if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_objects.size()) { -		// PROCESS MIPMAPS -		if (gi_probe->mipmaps.size()) { -			//can update mipmaps - -			Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe); - -			GIProbePushConstant push_constant; - -			push_constant.limits[0] = probe_size.x; -			push_constant.limits[1] = probe_size.y; -			push_constant.limits[2] = probe_size.z; -			push_constant.stack_size = gi_probe->mipmaps.size(); -			push_constant.emission_scale = 1.0; -			push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe); -			push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe); -			push_constant.light_count = light_count; -			push_constant.aniso_strength = 0; - -			/*		print_line("probe update to version " + itos(gi_probe->last_probe_version)); -			print_line("propagation " + rtos(push_constant.propagation)); -			print_line("dynrange " + rtos(push_constant.dynamic_range)); -	*/ -			RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - -			int passes; -			if (p_update_light_instances) { -				passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1; -			} else { -				passes = 1; //only re-blitting is necessary -			} -			int wg_size = 64; -			int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X); - -			for (int pass = 0; pass < passes; pass++) { -				if (p_update_light_instances) { -					for (int i = 0; i < gi_probe->mipmaps.size(); i++) { -						if (i == 0) { -							RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]); -						} else if (i == 1) { -							RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]); -						} - -						if (pass == 1 || i > 0) { -							RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done -						} -						if (pass == 0 || i > 0) { -							RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0); -						} else { -							RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0); -						} - -						push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset; -						push_constant.cell_count = gi_probe->mipmaps[i].cell_count; - -						int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1; -						while (wg_todo) { -							int wg_count = MIN(wg_todo, wg_limit_x); -							RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); -							RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); -							wg_todo -= wg_count; -							push_constant.cell_offset += wg_count * wg_size; -						} -					} - -					RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done -				} - -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]); - -				for (int i = 0; i < gi_probe->mipmaps.size(); i++) { -					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0); - -					push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset; -					push_constant.cell_count = gi_probe->mipmaps[i].cell_count; - -					int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1; -					while (wg_todo) { -						int wg_count = MIN(wg_todo, wg_limit_x); -						RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); -						RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); -						wg_todo -= wg_count; -						push_constant.cell_offset += wg_count * wg_size; -					} -				} -			} - -			RD::get_singleton()->compute_list_end(); -		} -	} - -	gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again - -	if (p_dynamic_objects.size() && gi_probe->dynamic_maps.size()) { -		Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe); -		int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z); - -		Transform oversample_scale; -		oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier)); - -		Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(gi_probe->probe); -		Transform to_world_xform = gi_probe->transform * to_cell.affine_inverse(); -		Transform to_probe_xform = to_world_xform.affine_inverse(); - -		AABB probe_aabb(Vector3(), octree_size); - -		//this could probably be better parallelized in compute.. -		for (int i = 0; i < (int)p_dynamic_objects.size(); i++) { -			GeometryInstance *instance = p_dynamic_objects[i]; - -			//transform aabb to giprobe -			AABB aabb = (to_probe_xform * geometry_instance_get_transform(instance)).xform(geometry_instance_get_aabb(instance)); - -			//this needs to wrap to grid resolution to avoid jitter -			//also extend margin a bit just in case -			Vector3i begin = aabb.position - Vector3i(1, 1, 1); -			Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1); - -			for (int j = 0; j < 3; j++) { -				if ((end[j] - begin[j]) & 1) { -					end[j]++; //for half extents split, it needs to be even -				} -				begin[j] = MAX(begin[j], 0); -				end[j] = MIN(end[j], octree_size[j] * multiplier); -			} - -			//aabb = aabb.intersection(probe_aabb); //intersect -			aabb.position = begin; -			aabb.size = end - begin; - -			//print_line("aabb: " + aabb); - -			for (int j = 0; j < 6; j++) { -				//if (j != 0 && j != 3) { -				//	continue; -				//} -				static const Vector3 render_z[6] = { -					Vector3(1, 0, 0), -					Vector3(0, 1, 0), -					Vector3(0, 0, 1), -					Vector3(-1, 0, 0), -					Vector3(0, -1, 0), -					Vector3(0, 0, -1), -				}; -				static const Vector3 render_up[6] = { -					Vector3(0, 1, 0), -					Vector3(0, 0, 1), -					Vector3(0, 1, 0), -					Vector3(0, 1, 0), -					Vector3(0, 0, 1), -					Vector3(0, 1, 0), -				}; - -				Vector3 render_dir = render_z[j]; -				Vector3 up_dir = render_up[j]; - -				Vector3 center = aabb.position + aabb.size * 0.5; -				Transform xform; -				xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir); - -				Vector3 x_dir = xform.basis.get_axis(0).abs(); -				int x_axis = int(Vector3(0, 1, 2).dot(x_dir)); -				Vector3 y_dir = xform.basis.get_axis(1).abs(); -				int y_axis = int(Vector3(0, 1, 2).dot(y_dir)); -				Vector3 z_dir = -xform.basis.get_axis(2); -				int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs())); - -				Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]); -				bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0); -				bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0); -				bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0); - -				CameraMatrix cm; -				cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]); - -				if (cull_argument.size() == 0) { -					cull_argument.push_back(nullptr); -				} -				cull_argument[0] = instance; - -				_render_material(to_world_xform * xform, cm, true, cull_argument, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); - -				GIProbeDynamicPushConstant push_constant; -				zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant)); -				push_constant.limits[0] = octree_size.x; -				push_constant.limits[1] = octree_size.y; -				push_constant.limits[2] = octree_size.z; -				push_constant.light_count = p_light_instances.size(); -				push_constant.x_dir[0] = x_dir[0]; -				push_constant.x_dir[1] = x_dir[1]; -				push_constant.x_dir[2] = x_dir[2]; -				push_constant.y_dir[0] = y_dir[0]; -				push_constant.y_dir[1] = y_dir[1]; -				push_constant.y_dir[2] = y_dir[2]; -				push_constant.z_dir[0] = z_dir[0]; -				push_constant.z_dir[1] = z_dir[1]; -				push_constant.z_dir[2] = z_dir[2]; -				push_constant.z_base = xform.origin[z_axis]; -				push_constant.z_sign = (z_flip ? -1.0 : 1.0); -				push_constant.pos_multiplier = float(1.0) / multiplier; -				push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe); -				push_constant.flip_x = x_flip; -				push_constant.flip_y = y_flip; -				push_constant.rect_pos[0] = rect.position[0]; -				push_constant.rect_pos[1] = rect.position[1]; -				push_constant.rect_size[0] = rect.size[0]; -				push_constant.rect_size[1] = rect.size[1]; -				push_constant.prev_rect_ofs[0] = 0; -				push_constant.prev_rect_ofs[1] = 0; -				push_constant.prev_rect_size[0] = 0; -				push_constant.prev_rect_size[1] = 0; -				push_constant.on_mipmap = false; -				push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe); -				push_constant.pad[0] = 0; -				push_constant.pad[1] = 0; -				push_constant.pad[2] = 0; - -				//process lighting -				RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]); -				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[0].uniform_set, 0); -				RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant)); -				RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); -				//print_line("rect: " + itos(i) + ": " + rect); - -				for (int k = 1; k < gi_probe->dynamic_maps.size(); k++) { -					// enlarge the rect if needed so all pixels fit when downscaled, -					// this ensures downsampling is smooth and optimal because no pixels are left behind - -					//x -					if (rect.position.x & 1) { -						rect.size.x++; -						push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal -					} else { -						push_constant.prev_rect_ofs[0] = 0; -					} -					if (rect.size.x & 1) { -						rect.size.x++; -					} - -					rect.position.x >>= 1; -					rect.size.x = MAX(1, rect.size.x >> 1); - -					//y -					if (rect.position.y & 1) { -						rect.size.y++; -						push_constant.prev_rect_ofs[1] = 1; -					} else { -						push_constant.prev_rect_ofs[1] = 0; -					} -					if (rect.size.y & 1) { -						rect.size.y++; -					} - -					rect.position.y >>= 1; -					rect.size.y = MAX(1, rect.size.y >> 1); - -					//shrink limits to ensure plot does not go outside map -					if (gi_probe->dynamic_maps[k].mipmap > 0) { -						for (int l = 0; l < 3; l++) { -							push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1); -						} -					} - -					//print_line("rect: " + itos(i) + ": " + rect); -					push_constant.rect_pos[0] = rect.position[0]; -					push_constant.rect_pos[1] = rect.position[1]; -					push_constant.prev_rect_size[0] = push_constant.rect_size[0]; -					push_constant.prev_rect_size[1] = push_constant.rect_size[1]; -					push_constant.rect_size[0] = rect.size[0]; -					push_constant.rect_size[1] = rect.size[1]; -					push_constant.on_mipmap = gi_probe->dynamic_maps[k].mipmap > 0; - -					RD::get_singleton()->compute_list_add_barrier(compute_list); - -					if (gi_probe->dynamic_maps[k].mipmap < 0) { -						RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]); -					} else if (k < gi_probe->dynamic_maps.size() - 1) { -						RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]); -					} else { -						RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]); -					} -					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[k].uniform_set, 0); -					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant)); -					RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); -				} - -				RD::get_singleton()->compute_list_end(); -			} -		} - -		gi_probe->has_dynamic_object_data = true; //clear until dynamic object data is used again -	} - -	gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe); -} - -void RendererSceneRenderRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { -	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe); -	ERR_FAIL_COND(!gi_probe); - -	if (gi_probe->mipmaps.size() == 0) { -		return; -	} - -	CameraMatrix transform = (p_camera_with_transform * CameraMatrix(gi_probe->transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(gi_probe->probe).affine_inverse()); - -	int level = 0; -	Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe); - -	GIProbeDebugPushConstant push_constant; -	push_constant.alpha = p_alpha; -	push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe); -	push_constant.cell_offset = gi_probe->mipmaps[level].cell_offset; -	push_constant.level = level; - -	push_constant.bounds[0] = octree_size.x >> level; -	push_constant.bounds[1] = octree_size.y >> level; -	push_constant.bounds[2] = octree_size.z >> level; -	push_constant.pad = 0; - -	for (int i = 0; i < 4; i++) { -		for (int j = 0; j < 4; j++) { -			push_constant.projection[i * 4 + j] = transform.matrix[i][j]; -		} -	} - -	if (giprobe_debug_uniform_set.is_valid()) { -		RD::get_singleton()->free(giprobe_debug_uniform_set); -	} -	Vector<RD::Uniform> uniforms; -	{ -		RD::Uniform u; -		u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -		u.binding = 1; -		u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe)); -		uniforms.push_back(u); -	} -	{ -		RD::Uniform u; -		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -		u.binding = 2; -		u.ids.push_back(gi_probe->texture); -		uniforms.push_back(u); -	} -	{ -		RD::Uniform u; -		u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -		u.binding = 3; -		u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -		uniforms.push_back(u); -	} - -	int cell_count; -	if (!p_emission && p_lighting && gi_probe->has_dynamic_object_data) { -		cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2]; -	} else { -		cell_count = gi_probe->mipmaps[level].cell_count; -	} - -	giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_debug_shader_version_shaders[0], 0); - -	int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR; -	if (p_emission) { -		giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION; -	} else if (p_lighting) { -		giprobe_debug_pipeline = gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT; -	} -	RD::get_singleton()->draw_list_bind_render_pipeline( -			p_draw_list, -			giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); -	RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, giprobe_debug_uniform_set, 0); -	RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant)); -	RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36); +	gi_probe->update(p_update_light_instances, p_light_instances, p_dynamic_objects, this);  }  void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) { @@ -4963,132 +1373,7 @@ void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawLi  		return; //nothing to debug  	} -	SDGIShader::DebugProbesPushConstant push_constant; - -	for (int i = 0; i < 4; i++) { -		for (int j = 0; j < 4; j++) { -			push_constant.projection[i * 4 + j] = p_camera_with_transform.matrix[i][j]; -		} -	} - -	//gen spheres from strips -	uint32_t band_points = 16; -	push_constant.band_power = 4; -	push_constant.sections_in_band = ((band_points / 2) - 1); -	push_constant.band_mask = band_points - 2; -	push_constant.section_arc = Math_TAU / float(push_constant.sections_in_band); -	push_constant.y_mult = rb->sdfgi->y_mult; - -	uint32_t total_points = push_constant.sections_in_band * band_points; -	uint32_t total_probes = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; - -	push_constant.grid_size[0] = rb->sdfgi->cascade_size; -	push_constant.grid_size[1] = rb->sdfgi->cascade_size; -	push_constant.grid_size[2] = rb->sdfgi->cascade_size; -	push_constant.cascade = 0; - -	push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; - -	if (!rb->sdfgi->debug_probes_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(rb->sdfgi->debug_probes_uniform_set)) { -		Vector<RD::Uniform> uniforms; -		{ -			RD::Uniform u; -			u.binding = 1; -			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -			u.ids.push_back(rb->sdfgi->cascades_ubo); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 2; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.ids.push_back(rb->sdfgi->lightprobe_texture); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 3; -			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 4; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.ids.push_back(rb->sdfgi->occlusion_texture); -			uniforms.push_back(u); -		} - -		rb->sdfgi->debug_probes_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, 0), 0); -	} - -	RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, sdfgi_shader.debug_probes_pipeline[SDGIShader::PROBE_DEBUG_PROBES].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); -	RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, rb->sdfgi->debug_probes_uniform_set, 0); -	RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDGIShader::DebugProbesPushConstant)); -	RD::get_singleton()->draw_list_draw(p_draw_list, false, total_probes, total_points); - -	if (sdfgi_debug_probe_dir != Vector3()) { -		print_line("CLICK DEBUG ME?"); -		uint32_t cascade = 0; -		Vector3 offset = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[cascade].position)) * rb->sdfgi->cascades[cascade].cell_size * Vector3(1.0, 1.0 / rb->sdfgi->y_mult, 1.0); -		Vector3 probe_size = rb->sdfgi->cascades[cascade].cell_size * (rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR) * Vector3(1.0, 1.0 / rb->sdfgi->y_mult, 1.0); -		Vector3 ray_from = sdfgi_debug_probe_pos; -		Vector3 ray_to = sdfgi_debug_probe_pos + sdfgi_debug_probe_dir * rb->sdfgi->cascades[cascade].cell_size * Math::sqrt(3.0) * rb->sdfgi->cascade_size; -		float sphere_radius = 0.2; -		float closest_dist = 1e20; -		sdfgi_debug_probe_enabled = false; - -		Vector3i probe_from = rb->sdfgi->cascades[cascade].position / (rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR); -		for (int i = 0; i < (SDFGI::PROBE_DIVISOR + 1); i++) { -			for (int j = 0; j < (SDFGI::PROBE_DIVISOR + 1); j++) { -				for (int k = 0; k < (SDFGI::PROBE_DIVISOR + 1); k++) { -					Vector3 pos = offset + probe_size * Vector3(i, j, k); -					Vector3 res; -					if (Geometry3D::segment_intersects_sphere(ray_from, ray_to, pos, sphere_radius, &res)) { -						float d = ray_from.distance_to(res); -						if (d < closest_dist) { -							closest_dist = d; -							sdfgi_debug_probe_enabled = true; -							sdfgi_debug_probe_index = probe_from + Vector3i(i, j, k); -						} -					} -				} -			} -		} - -		if (sdfgi_debug_probe_enabled) { -			print_line("found: " + sdfgi_debug_probe_index); -		} else { -			print_line("no found"); -		} -		sdfgi_debug_probe_dir = Vector3(); -	} - -	if (sdfgi_debug_probe_enabled) { -		uint32_t cascade = 0; -		uint32_t probe_cells = (rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR); -		Vector3i probe_from = rb->sdfgi->cascades[cascade].position / probe_cells; -		Vector3i ofs = sdfgi_debug_probe_index - probe_from; -		if (ofs.x < 0 || ofs.y < 0 || ofs.z < 0) { -			return; -		} -		if (ofs.x > SDFGI::PROBE_DIVISOR || ofs.y > SDFGI::PROBE_DIVISOR || ofs.z > SDFGI::PROBE_DIVISOR) { -			return; -		} - -		uint32_t mult = (SDFGI::PROBE_DIVISOR + 1); -		uint32_t index = ofs.z * mult * mult + ofs.y * mult + ofs.x; - -		push_constant.probe_debug_index = index; - -		uint32_t cell_count = probe_cells * 2 * probe_cells * 2 * probe_cells * 2; - -		RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, sdfgi_shader.debug_probes_pipeline[SDGIShader::PROBE_DEBUG_VISIBILITY].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); -		RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, rb->sdfgi->debug_probes_uniform_set, 0); -		RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDGIShader::DebugProbesPushConstant)); -		RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, total_points); -	} +	rb->sdfgi->debug_probes(p_draw_list, p_framebuffer, p_camera_with_transform);  }  //////////////////////////////// @@ -5277,7 +1562,7 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb  		return;  	} -	Environment *env = environment_owner.getornull(p_environment); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);  	ERR_FAIL_COND(!env);  	ERR_FAIL_COND(!env->ssr_enabled); @@ -5322,7 +1607,7 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND(!rb); -	Environment *env = environment_owner.getornull(p_environment); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);  	ERR_FAIL_COND(!env);  	RENDER_TIMESTAMP("Process SSAO"); @@ -5468,7 +1753,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND(!rb); -	Environment *env = environment_owner.getornull(p_environment); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);  	//glow (if enabled)  	CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); @@ -5661,7 +1946,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID  }  void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) { -	Environment *env = environment_owner.getornull(p_env); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);  	ERR_FAIL_COND(!env);  	env->adjustments_enabled = p_enable; @@ -5672,152 +1957,6 @@ void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable,  	env->color_correction = p_color_correction;  } -void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform) { -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(!rb); - -	if (!rb->sdfgi) { -		return; //eh -	} - -	if (!rb->sdfgi->debug_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(rb->sdfgi->debug_uniform_set)) { -		Vector<RD::Uniform> uniforms; -		{ -			RD::Uniform u; -			u.binding = 1; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { -				if (i < rb->sdfgi->cascades.size()) { -					u.ids.push_back(rb->sdfgi->cascades[i].sdf_tex); -				} else { -					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -				} -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 2; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { -				if (i < rb->sdfgi->cascades.size()) { -					u.ids.push_back(rb->sdfgi->cascades[i].light_tex); -				} else { -					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -				} -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 3; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { -				if (i < rb->sdfgi->cascades.size()) { -					u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_0_tex); -				} else { -					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -				} -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 4; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { -				if (i < rb->sdfgi->cascades.size()) { -					u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_1_tex); -				} else { -					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); -				} -			} -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 5; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.ids.push_back(rb->sdfgi->occlusion_texture); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 8; -			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -			u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 9; -			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -			u.ids.push_back(rb->sdfgi->cascades_ubo); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 10; -			u.uniform_type = RD::UNIFORM_TYPE_IMAGE; -			u.ids.push_back(rb->texture); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.binding = 11; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.ids.push_back(rb->sdfgi->lightprobe_texture); -			uniforms.push_back(u); -		} -		rb->sdfgi->debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.debug_shader_version, 0); -	} - -	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); -	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.debug_pipeline); -	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->debug_uniform_set, 0); - -	SDGIShader::DebugPushConstant push_constant; -	push_constant.grid_size[0] = rb->sdfgi->cascade_size; -	push_constant.grid_size[1] = rb->sdfgi->cascade_size; -	push_constant.grid_size[2] = rb->sdfgi->cascade_size; -	push_constant.max_cascades = rb->sdfgi->cascades.size(); -	push_constant.screen_size[0] = rb->width; -	push_constant.screen_size[1] = rb->height; -	push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; -	push_constant.use_occlusion = rb->sdfgi->uses_occlusion; -	push_constant.y_mult = rb->sdfgi->y_mult; - -	Vector2 vp_half = p_projection.get_viewport_half_extents(); -	push_constant.cam_extent[0] = vp_half.x; -	push_constant.cam_extent[1] = vp_half.y; -	push_constant.cam_extent[2] = -p_projection.get_z_near(); - -	push_constant.cam_transform[0] = p_transform.basis.elements[0][0]; -	push_constant.cam_transform[1] = p_transform.basis.elements[1][0]; -	push_constant.cam_transform[2] = p_transform.basis.elements[2][0]; -	push_constant.cam_transform[3] = 0; -	push_constant.cam_transform[4] = p_transform.basis.elements[0][1]; -	push_constant.cam_transform[5] = p_transform.basis.elements[1][1]; -	push_constant.cam_transform[6] = p_transform.basis.elements[2][1]; -	push_constant.cam_transform[7] = 0; -	push_constant.cam_transform[8] = p_transform.basis.elements[0][2]; -	push_constant.cam_transform[9] = p_transform.basis.elements[1][2]; -	push_constant.cam_transform[10] = p_transform.basis.elements[2][2]; -	push_constant.cam_transform[11] = 0; -	push_constant.cam_transform[12] = p_transform.origin.x; -	push_constant.cam_transform[13] = p_transform.origin.y; -	push_constant.cam_transform[14] = p_transform.origin.z; -	push_constant.cam_transform[15] = 1; - -	RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DebugPushConstant)); - -	RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1); -	RD::get_singleton()->compute_list_end(); - -	Size2 rtsize = storage->render_target_get_size(rb->render_target); -	storage->get_effects()->copy_to_fb_rect(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), true); -} -  RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) {  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND_V(!rb, RID()); @@ -5837,14 +1976,14 @@ RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) {  RID RendererSceneRenderRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) {  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND_V(!rb, RID()); -	if (rb->giprobe_buffer.is_null()) { -		rb->giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES); +	if (rb->gi.giprobe_buffer.is_null()) { +		rb->gi.giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::GIProbeData) * RendererSceneGIRD::MAX_GIPROBES);  	} -	return rb->giprobe_buffer; +	return rb->gi.giprobe_buffer;  }  RID RendererSceneRenderRD::render_buffers_get_default_gi_probe_buffer() { -	return default_giprobe_buffer; +	return gi.default_giprobe_buffer;  }  RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) { @@ -5893,7 +2032,7 @@ Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RI  	ERR_FAIL_COND_V(!rb, Vector3i());  	ERR_FAIL_COND_V(!rb->sdfgi, Vector3i());  	ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), Vector3i()); -	int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; +	int32_t probe_divisor = rb->sdfgi->cascade_size / RendererSceneGIRD::SDFGI::PROBE_DIVISOR;  	return rb->sdfgi->cascades[p_cascade].position / probe_divisor;  } @@ -6142,11 +2281,11 @@ void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_q  }  int RendererSceneRenderRD::get_roughness_layers() const { -	return roughness_layers; +	return sky.roughness_layers;  }  bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const { -	return sky_use_cubemap_array; +	return sky.sky_use_cubemap_array;  }  RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_get_data(RID p_render_buffers) { @@ -6223,7 +2362,7 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti  	}  	if (cluster.reflection_count) { -		RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE); +		RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(RendererSceneSkyRD::ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);  	}  } @@ -6232,7 +2371,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const  	r_directional_light_count = 0;  	r_positional_light_count = 0; -	sky_scene_state.ubo.directional_light_count = 0; +	sky.sky_scene_state.ubo.directional_light_count = 0;  	Plane camera_plane(p_camera_transform.origin, -p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized()); @@ -6252,8 +2391,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const  		switch (type) {  			case RS::LIGHT_DIRECTIONAL: {  				//	Copy to SkyDirectionalLightData -				if (r_directional_light_count < sky_scene_state.max_directional_lights) { -					SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count]; +				if (r_directional_light_count < sky.sky_scene_state.max_directional_lights) { +					RendererSceneSkyRD::SkyDirectionalLightData &sky_light_data = sky.sky_scene_state.directional_lights[r_directional_light_count];  					Transform light_transform = li->transform;  					Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized(); @@ -6281,7 +2420,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const  						angular_diameter = 0.0;  					}  					sky_light_data.size = angular_diameter; -					sky_scene_state.ubo.directional_light_count++; +					sky.sky_scene_state.ubo.directional_light_count++;  				}  				if (r_directional_light_count >= cluster.max_directional_lights || storage->light_directional_is_sky_only(base)) { @@ -6816,7 +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) {  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND(!rb); -	Environment *env = environment_owner.getornull(p_environment); +	RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);  	float ratio = float(rb->width) / float((rb->width + rb->height) / 2);  	uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio); @@ -6873,7 +3012,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e  			uniforms.push_back(u);  		} -		rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG); +		rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky.sky_shader.default_shader_rd, RendererSceneSkyRD::SKY_SET_FOG);  	}  	//update volumetric fog @@ -6984,8 +3123,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e  			RD::Uniform u;  			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;  			u.binding = 12; -			for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { -				u.ids.push_back(rb->giprobe_textures[i]); +			for (int i = 0; i < RendererSceneGIRD::MAX_GIPROBES; i++) { +				u.ids.push_back(rb->gi.giprobe_textures[i]);  			}  			uniforms.push_back(u);  		} @@ -7224,7 +3363,14 @@ bool RendererSceneRenderRD::_needs_post_prepass_render(bool p_use_gi) {  void RendererSceneRenderRD::_post_prepass_render(bool p_use_gi) {  	if (render_state.render_buffers.is_valid()) {  		if (p_use_gi) { -			_sdfgi_update_probes(render_state.render_buffers, render_state.environment); +			RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers); +			ERR_FAIL_COND(rb == nullptr); +			if (rb->sdfgi == nullptr) { +				return; +			} + +			RendererSceneEnvironmentRD *env = environment_owner.getornull(render_state.environment); +			rb->sdfgi->update_probes(env, sky.sky_owner.getornull(env->sky));  		}  	}  } @@ -7241,7 +3387,13 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R  	// Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time  	if (render_state.render_buffers.is_valid() && p_use_gi) { -		_sdfgi_store_probes(render_state.render_buffers); +		RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers); +		ERR_FAIL_COND(rb == nullptr); +		if (rb->sdfgi == nullptr) { +			return; +		} + +		rb->sdfgi->store_probes();  	}  	render_state.cube_shadows.clear(); @@ -7308,7 +3460,7 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R  	//start GI  	if (render_gi) { -		_process_gi(render_state.render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, render_state.environment, render_state.cam_projection, render_state.cam_transform, *render_state.gi_probes); +		gi.process_gi(render_state.render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, render_state.environment, render_state.cam_projection, render_state.cam_transform, *render_state.gi_probes, this);  	}  	//Do shadow rendering (in parallel with GI) @@ -7368,6 +3520,13 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R  }  void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) { +	// getting this here now so we can direct call a bunch of things more easily +	RenderBuffers *rb = nullptr; +	if (p_render_buffers.is_valid()) { +		rb = render_buffers_owner.getornull(p_render_buffers); +		ERR_FAIL_COND(!rb); // !BAS! Do we fail here or skip the parts that won't work. can't really see a case why we would be rendering without buffers.... +	} +  	//assign render data  	{  		render_state.render_buffers = p_render_buffers; @@ -7404,19 +3563,17 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &  	}  	//sdfgi first -	if (p_render_buffers.is_valid()) { +	if (rb != nullptr && rb->sdfgi != nullptr) {  		for (int i = 0; i < render_state.render_sdfgi_region_count; i++) { -			_render_sdfgi_region(p_render_buffers, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances); +			rb->sdfgi->render_region(p_render_buffers, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances, this);  		}  		if (render_state.sdfgi_update_data->update_static) { -			_render_sdfgi_static_lights(p_render_buffers, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights); +			rb->sdfgi->render_static_lights(p_render_buffers, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights, this);  		}  	}  	Color clear_color;  	if (p_render_buffers.is_valid()) { -		RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -		ERR_FAIL_COND(!rb);  		clear_color = storage->render_target_get_clear_request_color(rb->render_target);  	} else {  		clear_color = storage->get_default_clear_color(); @@ -7424,15 +3581,15 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &  	//assign render indices to giprobes  	for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) { -		GIProbeInstance *giprobe_inst = gi_probe_instance_owner.getornull(p_gi_probes[i]); +		RendererSceneGIRD::GIProbeInstance *giprobe_inst = gi.gi_probe_instance_owner.getornull(p_gi_probes[i]);  		if (giprobe_inst) {  			giprobe_inst->render_index = i;  		}  	}  	if (render_buffers_owner.owns(render_state.render_buffers)) { -		RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers); -		current_cluster_builder = rb->cluster_builder; +		RenderBuffers *rs_rb = render_buffers_owner.getornull(render_state.render_buffers); +		current_cluster_builder = rs_rb->cluster_builder;  	} else if (reflection_probe_instance_owner.owns(render_state.reflection_probe)) {  		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_state.reflection_probe);  		ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas); @@ -7447,14 +3604,17 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &  		current_cluster_builder = nullptr;  	} -	if (p_render_buffers.is_valid()) { -		_pre_process_gi(p_render_buffers, p_cam_transform); +	if (rb != nullptr && rb->sdfgi != nullptr) { +		rb->sdfgi->update_cascades(); + +		rb->sdfgi->pre_process_gi(p_cam_transform, this);  	}  	render_state.gi_probe_count = 0; -	if (render_state.render_buffers.is_valid()) { -		_setup_giprobes(render_state.render_buffers, render_state.cam_transform, *render_state.gi_probes, render_state.gi_probe_count); -		_sdfgi_update_light(render_state.render_buffers, render_state.environment); +	if (rb != nullptr && rb->sdfgi != nullptr) { +		gi.setup_giprobes(render_state.render_buffers, render_state.cam_transform, *render_state.gi_probes, render_state.gi_probe_count, this); + +		rb->sdfgi->update_light();  	}  	render_state.depth_prepass_used = false; @@ -7487,8 +3647,8 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &  		_render_buffers_post_process_and_tonemap(p_render_buffers, p_environment, p_camera_effects, p_cam_projection);  		_render_buffers_debug_draw(p_render_buffers, p_shadow_atlas); -		if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI) { -			_sdfgi_debug_draw(p_render_buffers, p_cam_projection, p_cam_transform); +		if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) { +			rb->sdfgi->debug_draw(p_cam_projection, p_cam_transform, rb->width, rb->height, rb->render_target, rb->texture);  		}  	}  } @@ -7668,366 +3828,6 @@ void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, co  	_render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, p_framebuffer, p_region);  } -void RendererSceneRenderRD::_render_sdfgi_region(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances) { -	//print_line("rendering region " + itos(p_region)); -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(!rb); -	ERR_FAIL_COND(!rb->sdfgi); -	AABB bounds; -	Vector3i from; -	Vector3i size; - -	int cascade_prev = _sdfgi_get_pending_region_data(p_render_buffers, p_region - 1, from, size, bounds); -	int cascade_next = _sdfgi_get_pending_region_data(p_render_buffers, p_region + 1, from, size, bounds); -	int cascade = _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds); -	ERR_FAIL_COND(cascade < 0); - -	if (cascade_prev != cascade) { -		//initialize render -		RD::get_singleton()->texture_clear(rb->sdfgi->render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1); -		RD::get_singleton()->texture_clear(rb->sdfgi->render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1); -		RD::get_singleton()->texture_clear(rb->sdfgi->render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1); -		RD::get_singleton()->texture_clear(rb->sdfgi->render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1); -	} - -	//print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(rb->sdfgi->cascades[cascade].cell_size)); -	_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, rb->sdfgi->render_albedo, rb->sdfgi->render_emission, rb->sdfgi->render_emission_aniso, rb->sdfgi->render_geom_facing); - -	if (cascade_next != cascade) { -		RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade"); - -		RENDER_TIMESTAMP(">SDFGI Update SDF"); -		//done rendering! must update SDF -		//clear dispatch indirect data - -		SDGIShader::PreprocessPushConstant push_constant; -		zeromem(&push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - -		RENDER_TIMESTAMP("Scroll SDF"); - -		//scroll -		if (rb->sdfgi->cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) { -			//for scroll -			Vector3i dirty = rb->sdfgi->cascades[cascade].dirty_regions; -			push_constant.scroll[0] = dirty.x; -			push_constant.scroll[1] = dirty.y; -			push_constant.scroll[2] = dirty.z; -		} else { -			//for no scroll -			push_constant.scroll[0] = 0; -			push_constant.scroll[1] = 0; -			push_constant.scroll[2] = 0; -		} - -		rb->sdfgi->cascades[cascade].all_dynamic_lights_dirty = true; - -		push_constant.grid_size = rb->sdfgi->cascade_size; -		push_constant.cascade = cascade; - -		if (rb->sdfgi->cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) { -			RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - -			//must pre scroll existing data because not all is dirty -			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL]); -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].scroll_uniform_set, 0); - -			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -			RD::get_singleton()->compute_list_dispatch_indirect(compute_list, rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0); -			// no barrier do all together - -			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL_OCCLUSION]); -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].scroll_occlusion_uniform_set, 0); - -			Vector3i dirty = rb->sdfgi->cascades[cascade].dirty_regions; -			Vector3i groups; -			groups.x = rb->sdfgi->cascade_size - ABS(dirty.x); -			groups.y = rb->sdfgi->cascade_size - ABS(dirty.y); -			groups.z = rb->sdfgi->cascade_size - ABS(dirty.z); - -			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -			RD::get_singleton()->compute_list_dispatch_threads(compute_list, groups.x, groups.y, groups.z); - -			//no barrier, continue together - -			{ -				//scroll probes and their history also - -				SDGIShader::IntegratePushConstant ipush_constant; -				ipush_constant.grid_size[1] = rb->sdfgi->cascade_size; -				ipush_constant.grid_size[2] = rb->sdfgi->cascade_size; -				ipush_constant.grid_size[0] = rb->sdfgi->cascade_size; -				ipush_constant.max_cascades = rb->sdfgi->cascades.size(); -				ipush_constant.probe_axis_size = rb->sdfgi->probe_axis_count; -				ipush_constant.history_index = 0; -				ipush_constant.history_size = rb->sdfgi->history_size; -				ipush_constant.ray_count = 0; -				ipush_constant.ray_bias = 0; -				ipush_constant.sky_mode = 0; -				ipush_constant.sky_energy = 0; -				ipush_constant.sky_color[0] = 0; -				ipush_constant.sky_color[1] = 0; -				ipush_constant.sky_color[2] = 0; -				ipush_constant.y_mult = rb->sdfgi->y_mult; -				ipush_constant.store_ambient_texture = false; - -				ipush_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; -				ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count; - -				int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; -				ipush_constant.cascade = cascade; -				ipush_constant.world_offset[0] = rb->sdfgi->cascades[cascade].position.x / probe_divisor; -				ipush_constant.world_offset[1] = rb->sdfgi->cascades[cascade].position.y / probe_divisor; -				ipush_constant.world_offset[2] = rb->sdfgi->cascades[cascade].position.z / probe_divisor; - -				ipush_constant.scroll[0] = dirty.x / probe_divisor; -				ipush_constant.scroll[1] = dirty.y / probe_divisor; -				ipush_constant.scroll[2] = dirty.z / probe_divisor; - -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_SCROLL]); -				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0); -				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); -				RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); -				RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1); - -				RD::get_singleton()->compute_list_add_barrier(compute_list); - -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_SCROLL_STORE]); -				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0); -				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); -				RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); -				RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1); - -				RD::get_singleton()->compute_list_add_barrier(compute_list); - -				if (rb->sdfgi->bounce_feedback > 0.0) { -					//multibounce requires this to be stored so direct light can read from it - -					RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]); - -					//convert to octahedral to store -					ipush_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE; -					ipush_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE; - -					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0); -					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); -					RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); -					RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1); -				} -			} - -			//ok finally barrier -			RD::get_singleton()->compute_list_end(); -		} - -		//clear dispatch indirect data -		uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 }; -		RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data); - -		RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - -		bool half_size = true; //much faster, very little difference -		static const int optimized_jf_group_size = 8; - -		if (half_size) { -			push_constant.grid_size >>= 1; - -			uint32_t cascade_half_size = rb->sdfgi->cascade_size >> 1; -			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF]); -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_initialize_half_uniform_set, 0); -			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -			RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size); -			RD::get_singleton()->compute_list_add_barrier(compute_list); - -			//must start with regular jumpflood - -			push_constant.half_size = true; -			{ -				RENDER_TIMESTAMP("SDFGI Jump Flood (Half Size)"); - -				uint32_t s = cascade_half_size; - -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD]); - -				int jf_us = 0; -				//start with regular jump flood for very coarse reads, as this is impossible to optimize -				while (s > 1) { -					s /= 2; -					push_constant.step_size = s; -					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_half_uniform_set[jf_us], 0); -					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -					RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size); -					RD::get_singleton()->compute_list_add_barrier(compute_list); -					jf_us = jf_us == 0 ? 1 : 0; - -					if (cascade_half_size / (s / 2) >= optimized_jf_group_size) { -						break; -					} -				} - -				RENDER_TIMESTAMP("SDFGI Jump Flood Optimized (Half Size)"); - -				//continue with optimized jump flood for smaller reads -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]); -				while (s > 1) { -					s /= 2; -					push_constant.step_size = s; -					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_half_uniform_set[jf_us], 0); -					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -					RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size); -					RD::get_singleton()->compute_list_add_barrier(compute_list); -					jf_us = jf_us == 0 ? 1 : 0; -				} -			} - -			// restore grid size for last passes -			push_constant.grid_size = rb->sdfgi->cascade_size; - -			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE]); -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_upscale_uniform_set, 0); -			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -			RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); -			RD::get_singleton()->compute_list_add_barrier(compute_list); - -			//run one pass of fullsize jumpflood to fix up half size arctifacts - -			push_constant.half_size = false; -			push_constant.step_size = 1; -			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]); -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[rb->sdfgi->upscale_jfa_uniform_set_index], 0); -			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -			RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); -			RD::get_singleton()->compute_list_add_barrier(compute_list); - -		} else { -			//full size jumpflood -			RENDER_TIMESTAMP("SDFGI Jump Flood"); - -			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE]); -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_initialize_uniform_set, 0); -			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -			RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); - -			RD::get_singleton()->compute_list_add_barrier(compute_list); - -			push_constant.half_size = false; -			{ -				uint32_t s = rb->sdfgi->cascade_size; - -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD]); - -				int jf_us = 0; -				//start with regular jump flood for very coarse reads, as this is impossible to optimize -				while (s > 1) { -					s /= 2; -					push_constant.step_size = s; -					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[jf_us], 0); -					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -					RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); -					RD::get_singleton()->compute_list_add_barrier(compute_list); -					jf_us = jf_us == 0 ? 1 : 0; - -					if (rb->sdfgi->cascade_size / (s / 2) >= optimized_jf_group_size) { -						break; -					} -				} - -				RENDER_TIMESTAMP("SDFGI Jump Flood Optimized"); - -				//continue with optimized jump flood for smaller reads -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]); -				while (s > 1) { -					s /= 2; -					push_constant.step_size = s; -					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[jf_us], 0); -					RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -					RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); -					RD::get_singleton()->compute_list_add_barrier(compute_list); -					jf_us = jf_us == 0 ? 1 : 0; -				} -			} -		} - -		RENDER_TIMESTAMP("SDFGI Occlusion"); - -		// occlusion -		{ -			uint32_t probe_size = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; -			Vector3i probe_global_pos = rb->sdfgi->cascades[cascade].position / probe_size; - -			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_OCCLUSION]); -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->occlusion_uniform_set, 0); -			for (int i = 0; i < 8; i++) { -				//dispatch all at once for performance -				Vector3i offset(i & 1, (i >> 1) & 1, (i >> 2) & 1); - -				if ((probe_global_pos.x & 1) != 0) { -					offset.x = (offset.x + 1) & 1; -				} -				if ((probe_global_pos.y & 1) != 0) { -					offset.y = (offset.y + 1) & 1; -				} -				if ((probe_global_pos.z & 1) != 0) { -					offset.z = (offset.z + 1) & 1; -				} -				push_constant.probe_offset[0] = offset.x; -				push_constant.probe_offset[1] = offset.y; -				push_constant.probe_offset[2] = offset.z; -				push_constant.occlusion_index = i; -				RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); - -				Vector3i groups = Vector3i(probe_size + 1, probe_size + 1, probe_size + 1) - offset; //if offset, it's one less probe per axis to compute -				RD::get_singleton()->compute_list_dispatch(compute_list, groups.x, groups.y, groups.z); -			} -			RD::get_singleton()->compute_list_add_barrier(compute_list); -		} - -		RENDER_TIMESTAMP("SDFGI Store"); - -		// store -		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_STORE]); -		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].sdf_store_uniform_set, 0); -		RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant)); -		RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size); - -		RD::get_singleton()->compute_list_end(); - -		//clear these textures, as they will have previous garbage on next draw -		RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); -		RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); -		RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); - -#if 0 -		Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rb->sdfgi->cascades[cascade].sdf, 0); -		Ref<Image> img; -		img.instance(); -		for (uint32_t i = 0; i < rb->sdfgi->cascade_size; i++) { -			Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1); -			img->create(rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, false, Image::FORMAT_L8, subarr); -			img->save_png("res://cascade_sdf_" + itos(cascade) + "_" + itos(i) + ".png"); -		} - -		//finalize render and update sdf -#endif - -#if 0 -		Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rb->sdfgi->render_albedo, 0); -		Ref<Image> img; -		img.instance(); -		for (uint32_t i = 0; i < rb->sdfgi->cascade_size; i++) { -			Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1); -			img->create(rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, false, Image::FORMAT_RGB565, subarr); -			img->convert(Image::FORMAT_RGBA8); -			img->save_png("res://cascade_" + itos(cascade) + "_" + itos(i) + ".png"); -		} - -		//finalize render and update sdf -#endif - -		RENDER_TIMESTAMP("<SDFGI Update SDF"); -		RD::get_singleton()->draw_command_end_label(); -	} -} -  void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) {  	ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider));  	Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale(); @@ -8045,133 +3845,15 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider,  	_render_particle_collider_heightfield(fb, cam_xform, cm, p_instances);  } -void RendererSceneRenderRD::_render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result) { -	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); -	ERR_FAIL_COND(!rb); -	ERR_FAIL_COND(!rb->sdfgi); - -	RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lighs"); - -	_sdfgi_update_cascades(p_render_buffers); //need cascades updated for this - -	SDGIShader::Light lights[SDFGI::MAX_STATIC_LIGHTS]; -	uint32_t light_count[SDFGI::MAX_STATIC_LIGHTS]; - -	for (uint32_t i = 0; i < p_cascade_count; i++) { -		ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size()); - -		SDFGI::Cascade &cc = rb->sdfgi->cascades[p_cascade_indices[i]]; - -		{ //fill light buffer - -			AABB cascade_aabb; -			cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cc.position)) * cc.cell_size; -			cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cc.cell_size; - -			int idx = 0; - -			for (uint32_t j = 0; j < (uint32_t)p_positional_light_cull_result[i].size(); j++) { -				if (idx == SDFGI::MAX_STATIC_LIGHTS) { -					break; -				} - -				LightInstance *li = light_instance_owner.getornull(p_positional_light_cull_result[i][j]); -				ERR_CONTINUE(!li); - -				uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); -				if (p_cascade_indices[i] > max_sdfgi_cascade) { -					continue; -				} - -				if (!cascade_aabb.intersects(li->aabb)) { -					continue; -				} - -				lights[idx].type = storage->light_get_type(li->light); - -				Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); -				if (lights[idx].type == RS::LIGHT_DIRECTIONAL) { -					dir.y *= rb->sdfgi->y_mult; //only makes sense for directional -					dir.normalize(); -				} -				lights[idx].direction[0] = dir.x; -				lights[idx].direction[1] = dir.y; -				lights[idx].direction[2] = dir.z; -				Vector3 pos = li->transform.origin; -				pos.y *= rb->sdfgi->y_mult; -				lights[idx].position[0] = pos.x; -				lights[idx].position[1] = pos.y; -				lights[idx].position[2] = pos.z; -				Color color = storage->light_get_color(li->light); -				color = color.to_linear(); -				lights[idx].color[0] = color.r; -				lights[idx].color[1] = color.g; -				lights[idx].color[2] = color.b; -				lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); -				lights[idx].has_shadow = storage->light_has_shadow(li->light); -				lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); -				lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); -				lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE))); -				lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION); - -				idx++; -			} - -			if (idx > 0) { -				RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights); -			} - -			light_count[i] = idx; -		} -	} - -	/* Static Lights */ -	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - -	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_STATIC]); - -	SDGIShader::DirectLightPushConstant dl_push_constant; - -	dl_push_constant.grid_size[0] = rb->sdfgi->cascade_size; -	dl_push_constant.grid_size[1] = rb->sdfgi->cascade_size; -	dl_push_constant.grid_size[2] = rb->sdfgi->cascade_size; -	dl_push_constant.max_cascades = rb->sdfgi->cascades.size(); -	dl_push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; -	dl_push_constant.bounce_feedback = 0.0; // this is static light, do not multibounce yet -	dl_push_constant.y_mult = rb->sdfgi->y_mult; -	dl_push_constant.use_occlusion = rb->sdfgi->uses_occlusion; - -	//all must be processed -	dl_push_constant.process_offset = 0; -	dl_push_constant.process_increment = 1; - -	for (uint32_t i = 0; i < p_cascade_count; i++) { -		ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size()); - -		SDFGI::Cascade &cc = rb->sdfgi->cascades[p_cascade_indices[i]]; - -		dl_push_constant.light_count = light_count[i]; -		dl_push_constant.cascade = p_cascade_indices[i]; - -		if (dl_push_constant.light_count > 0) { -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cc.sdf_direct_light_uniform_set, 0); -			RD::get_singleton()->compute_list_set_push_constant(compute_list, &dl_push_constant, sizeof(SDGIShader::DirectLightPushConstant)); -			RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer, 0); -		} -	} - -	RD::get_singleton()->compute_list_end(); - -	RD::get_singleton()->draw_command_end_label(); -} -  bool RendererSceneRenderRD::free(RID p_rid) {  	if (render_buffers_owner.owns(p_rid)) {  		RenderBuffers *rb = render_buffers_owner.getornull(p_rid);  		_free_render_buffer_data(rb);  		memdelete(rb->data);  		if (rb->sdfgi) { -			_sdfgi_erase(rb); +			rb->sdfgi->erase(); +			memdelete(rb->sdfgi); +			rb->sdfgi = nullptr;  		}  		if (rb->volumetric_fog) {  			_volumetric_fog_erase(rb); @@ -8202,8 +3884,8 @@ bool RendererSceneRenderRD::free(RID p_rid) {  		decal_instance_owner.free(p_rid);  	} else if (lightmap_instance_owner.owns(p_rid)) {  		lightmap_instance_owner.free(p_rid); -	} else if (gi_probe_instance_owner.owns(p_rid)) { -		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid); +	} else if (gi.gi_probe_instance_owner.owns(p_rid)) { +		RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_rid);  		if (gi_probe->texture.is_valid()) {  			RD::get_singleton()->free(gi_probe->texture);  			RD::get_singleton()->free(gi_probe->write_buffer); @@ -8214,37 +3896,10 @@ bool RendererSceneRenderRD::free(RID p_rid) {  			RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);  		} -		gi_probe_instance_owner.free(p_rid); -	} else if (sky_owner.owns(p_rid)) { -		_update_dirty_skys(); -		Sky *sky = sky_owner.getornull(p_rid); - -		if (sky->radiance.is_valid()) { -			RD::get_singleton()->free(sky->radiance); -			sky->radiance = RID(); -		} -		_clear_reflection_data(sky->reflection); - -		if (sky->uniform_buffer.is_valid()) { -			RD::get_singleton()->free(sky->uniform_buffer); -			sky->uniform_buffer = RID(); -		} - -		if (sky->half_res_pass.is_valid()) { -			RD::get_singleton()->free(sky->half_res_pass); -			sky->half_res_pass = RID(); -		} - -		if (sky->quarter_res_pass.is_valid()) { -			RD::get_singleton()->free(sky->quarter_res_pass); -			sky->quarter_res_pass = RID(); -		} - -		if (sky->material.is_valid()) { -			storage->free(sky->material); -		} - -		sky_owner.free(p_rid); +		gi.gi_probe_instance_owner.free(p_rid); +	} else if (sky.sky_owner.owns(p_rid)) { +		sky.update_dirty_skys(); +		sky.free_sky(p_rid);  	} else if (light_instance_owner.owns(p_rid)) {  		LightInstance *light_instance = light_instance_owner.getornull(p_rid); @@ -8278,7 +3933,7 @@ void RendererSceneRenderRD::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_dr  }  void RendererSceneRenderRD::update() { -	_update_dirty_skys(); +	sky.update_dirty_skys();  }  void RendererSceneRenderRD::set_time(double p_time, double p_step) { @@ -8404,8 +4059,8 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto  }  void RendererSceneRenderRD::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { -	sdfgi_debug_probe_pos = p_position; -	sdfgi_debug_probe_dir = p_dir; +	gi.sdfgi_debug_probe_pos = p_position; +	gi.sdfgi_debug_probe_dir = p_dir;  }  RendererSceneRenderRD *RendererSceneRenderRD::singleton = nullptr; @@ -8441,14 +4096,6 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {  	storage = p_storage;  	singleton = this; -	roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers"); -	sky_ggx_samples_quality = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples"); -	sky_use_cubemap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections"); - -	sdfgi_ray_count = RS::EnvironmentSDFGIRayCount(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/probe_ray_count")), 0, int32_t(RS::ENV_SDFGI_RAY_COUNT_MAX - 1))); -	sdfgi_frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_converge")), 0, int32_t(RS::ENV_SDFGI_CONVERGE_MAX - 1))); -	sdfgi_frames_to_update_light = RS::EnvironmentSDFGIFramesToUpdateLight(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_update_lights")), 0, int32_t(RS::ENV_SDFGI_UPDATE_LIGHT_MAX - 1))); -  	directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size");  	directional_shadow.use_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits"); @@ -8461,388 +4108,16 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {  	}  	if (!low_end) { -		//kinda complicated to compute the amount of slots, we try to use as many as we can - -		gi_probe_max_lights = 32; - -		gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights); -		gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight)); -		gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")), 0, 1)); - -		String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n"; - -		Vector<String> versions; -		versions.push_back("\n#define MODE_COMPUTE_LIGHT\n"); -		versions.push_back("\n#define MODE_SECOND_BOUNCE\n"); -		versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n"); -		versions.push_back("\n#define MODE_WRITE_TEXTURE\n"); -		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n"); -		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n"); -		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n"); -		versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n"); - -		giprobe_shader.initialize(versions, defines); -		giprobe_lighting_shader_version = giprobe_shader.version_create(); -		for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) { -			giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i); -			giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]); -		} -	} - -	if (!low_end) { -		String defines; -		Vector<String> versions; -		versions.push_back("\n#define MODE_DEBUG_COLOR\n"); -		versions.push_back("\n#define MODE_DEBUG_LIGHT\n"); -		versions.push_back("\n#define MODE_DEBUG_EMISSION\n"); -		versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n"); - -		giprobe_debug_shader.initialize(versions, defines); -		giprobe_debug_shader_version = giprobe_debug_shader.version_create(); -		for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) { -			giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i); - -			RD::PipelineRasterizationState rs; -			rs.cull_mode = RD::POLYGON_CULL_FRONT; -			RD::PipelineDepthStencilState ds; -			ds.enable_depth_test = true; -			ds.enable_depth_write = true; -			ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - -			giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); -		} +		gi.init_gi(storage);  	}  	/* SKY SHADER */ -	{ -		// Start with the directional lights for the sky -		sky_scene_state.max_directional_lights = 4; -		uint32_t directional_light_buffer_size = sky_scene_state.max_directional_lights * sizeof(SkyDirectionalLightData); -		sky_scene_state.directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights); -		sky_scene_state.last_frame_directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights); -		sky_scene_state.last_frame_directional_light_count = sky_scene_state.max_directional_lights + 1; -		sky_scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); - -		String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_scene_state.max_directional_lights) + "\n"; - -		// Initialize sky -		Vector<String> sky_modes; -		sky_modes.push_back(""); // Full size -		sky_modes.push_back("\n#define USE_HALF_RES_PASS\n"); // Half Res -		sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n"); // Quarter res -		sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap -		sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap -		sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap -		sky_shader.shader.initialize(sky_modes, defines); -	} - -	// register our shader funds -	storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs); -	storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs); - -	{ -		ShaderCompilerRD::DefaultIdentifierActions actions; - -		actions.renames["COLOR"] = "color"; -		actions.renames["ALPHA"] = "alpha"; -		actions.renames["EYEDIR"] = "cube_normal"; -		actions.renames["POSITION"] = "params.position_multiplier.xyz"; -		actions.renames["SKY_COORDS"] = "panorama_coords"; -		actions.renames["SCREEN_UV"] = "uv"; -		actions.renames["TIME"] = "params.time"; -		actions.renames["HALF_RES_COLOR"] = "half_res_color"; -		actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color"; -		actions.renames["RADIANCE"] = "radiance"; -		actions.renames["FOG"] = "custom_fog"; -		actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled"; -		actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz"; -		actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w"; -		actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz"; -		actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w"; -		actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled"; -		actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz"; -		actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w"; -		actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz"; -		actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w"; -		actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled"; -		actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz"; -		actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w"; -		actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz"; -		actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w"; -		actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled"; -		actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz"; -		actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w"; -		actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz"; -		actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w"; -		actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS"; -		actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS"; -		actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS"; -		actions.custom_samplers["RADIANCE"] = "material_samplers[3]"; -		actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n"; -		actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n"; -		actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n"; - -		actions.sampler_array_name = "material_samplers"; -		actions.base_texture_binding_index = 1; -		actions.texture_layout_set = 1; -		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"; - -		sky_shader.compiler.initialize(actions); -	} - -	{ -		// default material and shader for sky shader -		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 fragment() { COLOR = vec3(0.0); } \n"); - -		sky_shader.default_material = storage->material_allocate(); -		storage->material_initialize(sky_shader.default_material); - -		storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader); - -		SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); -		sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND); - -		sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO)); - -		Vector<RD::Uniform> uniforms; - -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -			u.binding = 0; -			u.ids.resize(12); -			RID *ids_ptr = u.ids.ptrw(); -			ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -			ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); -			uniforms.push_back(u); -		} - -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; -			u.binding = 1; -			u.ids.push_back(storage->global_variables_get_storage_buffer()); -			uniforms.push_back(u); -		} - -		{ -			RD::Uniform u; -			u.binding = 2; -			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -			u.ids.push_back(sky_scene_state.uniform_buffer); -			uniforms.push_back(u); -		} - -		{ -			RD::Uniform u; -			u.binding = 3; -			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; -			u.ids.push_back(sky_scene_state.directional_light_buffer); -			uniforms.push_back(u); -		} - -		sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS); -	} - -	{ -		Vector<RD::Uniform> uniforms; -		{ -			RD::Uniform u; -			u.binding = 0; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			RID vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); -			u.ids.push_back(vfog); -			uniforms.push_back(u); -		} - -		sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG); -	} - -	{ -		// Need defaults for using fog with clear color -		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 fragment() { COLOR = clear_color.rgb; } \n"); -		sky_scene_state.fog_material = storage->material_allocate(); -		storage->material_initialize(sky_scene_state.fog_material); - -		storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader); - -		Vector<RD::Uniform> uniforms; -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 0; -			u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 1; -			u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); -			uniforms.push_back(u); -		} -		{ -			RD::Uniform u; -			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -			u.binding = 2; -			u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); -			uniforms.push_back(u); -		} - -		sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES); -	} +	sky.init(storage);  	if (!low_end) {  		//SDFGI -		{ -			Vector<String> preprocess_modes; -			preprocess_modes.push_back("\n#define MODE_SCROLL\n"); -			preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n"); -			preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n"); -			preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n"); -			preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n"); -			preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n"); -			preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n"); -			preprocess_modes.push_back("\n#define MODE_OCCLUSION\n"); -			preprocess_modes.push_back("\n#define MODE_STORE\n"); -			String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n"; -			sdfgi_shader.preprocess.initialize(preprocess_modes, defines); -			sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create(); -			for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) { -				sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i)); -			} -		} - -		{ -			//calculate tables -			String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - -			Vector<String> direct_light_modes; -			direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n"); -			direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n"); -			sdfgi_shader.direct_light.initialize(direct_light_modes, defines); -			sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create(); -			for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) { -				sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i)); -			} -		} - -		{ -			//calculate tables -			String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; -			defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n"; -			if (sky_use_cubemap_array) { -				defines += "\n#define USE_CUBEMAP_ARRAY\n"; -			} - -			Vector<String> integrate_modes; -			integrate_modes.push_back("\n#define MODE_PROCESS\n"); -			integrate_modes.push_back("\n#define MODE_STORE\n"); -			integrate_modes.push_back("\n#define MODE_SCROLL\n"); -			integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n"); -			sdfgi_shader.integrate.initialize(integrate_modes, defines); -			sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create(); - -			for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) { -				sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i)); -			} - -			{ -				Vector<RD::Uniform> uniforms; - -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; -					u.binding = 0; -					u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); -					uniforms.push_back(u); -				} -				{ -					RD::Uniform u; -					u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; -					u.binding = 1; -					u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); -					uniforms.push_back(u); -				} - -				sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1); -			} -		} -		//GK -		{ -			//calculate tables -			String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; -			Vector<String> gi_modes; -			gi_modes.push_back("\n#define USE_GIPROBES\n"); -			gi_modes.push_back("\n#define USE_SDFGI\n"); -			gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); -			gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n"); -			gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n"); -			gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); - -			gi.shader.initialize(gi_modes, defines); -			gi.shader_version = gi.shader.version_create(); -			for (int i = 0; i < GI::MODE_MAX; i++) { -				gi.pipelines[i] = RD::get_singleton()->compute_pipeline_create(gi.shader.version_get_shader(gi.shader_version, i)); -			} - -			gi.sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(GI::SDFGIData)); -		} -		{ -			String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; -			Vector<String> debug_modes; -			debug_modes.push_back(""); -			sdfgi_shader.debug.initialize(debug_modes, defines); -			sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create(); -			sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0); -			sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version); -		} -		{ -			String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - -			Vector<String> versions; -			versions.push_back("\n#define MODE_PROBES\n"); -			versions.push_back("\n#define MODE_VISIBILITY\n"); - -			sdfgi_shader.debug_probes.initialize(versions, defines); -			sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create(); - -			{ -				RD::PipelineRasterizationState rs; -				rs.cull_mode = RD::POLYGON_CULL_DISABLED; -				RD::PipelineDepthStencilState ds; -				ds.enable_depth_test = true; -				ds.enable_depth_write = true; -				ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; -				for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) { -					RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i); -					sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); -				} -			} -		} -		default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES); +		gi.init_sdfgi(&sky);  	}  	{ //decals @@ -8935,40 +4210,27 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {  		RD::get_singleton()->free(E->get().cubemap);  	} -	if (sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) { -		RD::get_singleton()->free(sky_scene_state.uniform_set); +	if (sky.sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky.sky_scene_state.uniform_set)) { +		RD::get_singleton()->free(sky.sky_scene_state.uniform_set);  	}  	if (!low_end) { -		RD::get_singleton()->free(default_giprobe_buffer); -		RD::get_singleton()->free(gi_probe_lights_uniform); -		RD::get_singleton()->free(gi.sdfgi_ubo); - -		giprobe_debug_shader.version_free(giprobe_debug_shader_version); -		giprobe_shader.version_free(giprobe_lighting_shader_version); -		gi.shader.version_free(gi.shader_version); -		sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader); -		sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader); -		sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader); -		sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader); -		sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); +		gi.free();  		volumetric_fog.shader.version_free(volumetric_fog.shader_version);  		RD::get_singleton()->free(volumetric_fog.params_ubo); - -		memdelete_arr(gi_probe_lights);  	} -	SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); -	sky_shader.shader.version_free(md->shader_data->version); -	RD::get_singleton()->free(sky_scene_state.directional_light_buffer); -	RD::get_singleton()->free(sky_scene_state.uniform_buffer); -	memdelete_arr(sky_scene_state.directional_lights); -	memdelete_arr(sky_scene_state.last_frame_directional_lights); -	storage->free(sky_shader.default_shader); -	storage->free(sky_shader.default_material); -	storage->free(sky_scene_state.fog_shader); -	storage->free(sky_scene_state.fog_material); +	RendererSceneSkyRD::SkyMaterialData *md = (RendererSceneSkyRD::SkyMaterialData *)storage->material_get_data(sky.sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); +	sky.sky_shader.shader.version_free(md->shader_data->version); +	RD::get_singleton()->free(sky.sky_scene_state.directional_light_buffer); +	RD::get_singleton()->free(sky.sky_scene_state.uniform_buffer); +	memdelete_arr(sky.sky_scene_state.directional_lights); +	memdelete_arr(sky.sky_scene_state.last_frame_directional_lights); +	storage->free(sky.sky_shader.default_shader); +	storage->free(sky.sky_shader.default_material); +	storage->free(sky.sky_scene_state.fog_shader); +	storage->free(sky.sky_scene_state.fog_material);  	memdelete_arr(directional_penumbra_shadow_kernel);  	memdelete_arr(directional_soft_shadow_kernel);  	memdelete_arr(penumbra_shadow_kernel); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index e4eaa93212..d41dd3358d 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -35,68 +35,21 @@  #include "core/templates/rid_owner.h"  #include "servers/rendering/renderer_compositor.h"  #include "servers/rendering/renderer_rd/cluster_builder_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_gi_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"  #include "servers/rendering/renderer_rd/renderer_storage_rd.h" -#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/sky.glsl.gen.h"  #include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h"  #include "servers/rendering/renderer_scene_render.h"  #include "servers/rendering/rendering_device.h"  class RendererSceneRenderRD : public RendererSceneRender { +	friend RendererSceneSkyRD; +	friend RendererSceneGIRD; +  protected:  	double time; - -	// Skys need less info from Directional Lights than the normal shaders -	struct SkyDirectionalLightData { -		float direction[3]; -		float energy; -		float color[3]; -		float size; -		uint32_t enabled; -		uint32_t pad[3]; -	}; - -	struct SkySceneState { -		struct UBO { -			uint32_t volumetric_fog_enabled; -			float volumetric_fog_inv_length; -			float volumetric_fog_detail_spread; - -			float fog_aerial_perspective; - -			float fog_light_color[3]; -			float fog_sun_scatter; - -			uint32_t fog_enabled; -			float fog_density; - -			float z_far; -			uint32_t directional_light_count; -		}; - -		UBO ubo; - -		SkyDirectionalLightData *directional_lights; -		SkyDirectionalLightData *last_frame_directional_lights; -		uint32_t max_directional_lights; -		uint32_t last_frame_directional_light_count; -		RID directional_light_buffer; -		RID uniform_set; -		RID uniform_buffer; -		RID fog_uniform_set; -		RID default_fog_uniform_set; - -		RID fog_shader; -		RID fog_material; -		RID fog_only_texture_uniform_set; -	} sky_scene_state; +	double time_step = 0;  	struct RenderBufferData {  		virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0; @@ -107,7 +60,6 @@ protected:  	void _setup_lights(const PagedArray<RID> &p_lights, const Transform &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_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform);  	void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment); -	void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used);  	virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_cluster_max_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color, float p_screen_lod_threshold) = 0; @@ -121,7 +73,6 @@ protected:  	virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0;  	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0; -	virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);  	void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);  	RenderBufferData *render_buffers_get_data(RID p_render_buffers); @@ -134,12 +85,6 @@ protected:  	void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive);  	void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera); -	void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size); -	void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); -	void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); -	void _pre_process_gi(RID p_render_buffers, const Transform &p_transform); -	void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes); -  	bool _needs_post_prepass_render(bool p_use_gi);  	void _post_prepass_render(bool p_use_gi);  	void _pre_resolve_render(bool p_use_gi); @@ -150,191 +95,24 @@ protected:  	// needed for a single argument calls (material and uv2)  	PagedArrayPool<GeometryInstance *> cull_argument_pool;  	PagedArray<GeometryInstance *> cull_argument; //need this to exist + +	RendererSceneGIRD gi; +	RendererSceneSkyRD sky; + +	RendererSceneEnvironmentRD *get_environment(RID p_environment) { +		if (p_environment.is_valid()) { +			return environment_owner.getornull(p_environment); +		} else { +			return nullptr; +		} +	} +  private:  	RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED; -	double time_step = 0;  	static RendererSceneRenderRD *singleton; -	int roughness_layers; -  	RendererStorageRD *storage; -	struct ReflectionData { -		struct Layer { -			struct Mipmap { -				RID framebuffers[6]; -				RID views[6]; -				Size2i size; -			}; -			Vector<Mipmap> mipmaps; //per-face view -			Vector<RID> views; // per-cubemap view -		}; - -		struct DownsampleLayer { -			struct Mipmap { -				RID view; -				Size2i size; -			}; -			Vector<Mipmap> mipmaps; -		}; - -		RID radiance_base_cubemap; //cubemap for first layer, first cubemap -		RID downsampled_radiance_cubemap; -		DownsampleLayer downsampled_layer; -		RID coefficient_buffer; - -		bool dirty = true; - -		Vector<Layer> layers; -	}; - -	void _clear_reflection_data(ReflectionData &rd); -	void _update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality); -	void _create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays); -	void _create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer); -	void _update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end); - -	/* Sky shader */ - -	enum SkyVersion { -		SKY_VERSION_BACKGROUND, -		SKY_VERSION_HALF_RES, -		SKY_VERSION_QUARTER_RES, -		SKY_VERSION_CUBEMAP, -		SKY_VERSION_CUBEMAP_HALF_RES, -		SKY_VERSION_CUBEMAP_QUARTER_RES, -		SKY_VERSION_MAX -	}; - -	struct SkyShader { -		SkyShaderRD shader; -		ShaderCompilerRD compiler; - -		RID default_shader; -		RID default_material; -		RID default_shader_rd; -	} sky_shader; - -	struct SkyShaderData : public RendererStorageRD::ShaderData { -		bool valid; -		RID version; - -		PipelineCacheRD pipelines[SKY_VERSION_MAX]; -		Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; -		Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; - -		Vector<uint32_t> ubo_offsets; -		uint32_t ubo_size; - -		String path; -		String code; -		Map<StringName, RID> default_texture_params; - -		bool uses_time; -		bool uses_position; -		bool uses_half_res; -		bool uses_quarter_res; -		bool uses_light; - -		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; -		virtual 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; -		SkyShaderData(); -		virtual ~SkyShaderData(); -	}; - -	RendererStorageRD::ShaderData *_create_sky_shader_func(); -	static RendererStorageRD::ShaderData *_create_sky_shader_funcs() { -		return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_shader_func(); -	}; - -	struct SkyMaterialData : public RendererStorageRD::MaterialData { -		uint64_t last_frame; -		SkyShaderData *shader_data; -		RID uniform_buffer; -		RID uniform_set; -		Vector<RID> texture_cache; -		Vector<uint8_t> ubo_data; -		bool uniform_set_updated; - -		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 ~SkyMaterialData(); -	}; - -	RendererStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader); -	static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader) { -		return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_material_func(static_cast<SkyShaderData *>(p_shader)); -	}; - -	enum SkyTextureSetVersion { -		SKY_TEXTURE_SET_BACKGROUND, -		SKY_TEXTURE_SET_HALF_RES, -		SKY_TEXTURE_SET_QUARTER_RES, -		SKY_TEXTURE_SET_CUBEMAP, -		SKY_TEXTURE_SET_CUBEMAP_HALF_RES, -		SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, -		SKY_TEXTURE_SET_MAX -	}; - -	enum SkySet { -		SKY_SET_UNIFORMS, -		SKY_SET_MATERIAL, -		SKY_SET_TEXTURES, -		SKY_SET_FOG, -		SKY_SET_MAX -	}; - -	/* SKY */ -	struct Sky { -		RID radiance; -		RID half_res_pass; -		RID half_res_framebuffer; -		RID quarter_res_pass; -		RID quarter_res_framebuffer; -		Size2i screen_size; - -		RID texture_uniform_sets[SKY_TEXTURE_SET_MAX]; -		RID uniform_set; - -		RID material; -		RID uniform_buffer; - -		int radiance_size = 256; - -		RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC; - -		ReflectionData reflection; -		bool dirty = false; -		int processing_layer = 0; -		Sky *dirty_list = nullptr; - -		//State to track when radiance cubemap needs updating -		SkyMaterialData *prev_material; -		Vector3 prev_position; -		float prev_time; - -		RID sdfgi_integrate_sky_uniform_set; -	}; - -	Sky *dirty_sky_list = nullptr; - -	void _sky_invalidate(Sky *p_sky); -	void _update_dirty_skys(); -	RID _get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version); - -	uint32_t sky_ggx_samples_quality; -	bool sky_use_cubemap_array; - -	mutable RID_Owner<Sky, true> sky_owner; -  	/* REFLECTION ATLAS */  	struct ReflectionAtlas { @@ -347,7 +125,7 @@ private:  		struct Reflection {  			RID owner; -			ReflectionData data; +			RendererSceneSkyRD::ReflectionData data;  			RID fbs[6];  		}; @@ -397,151 +175,6 @@ private:  	mutable RID_Owner<LightmapInstance> lightmap_instance_owner; -	/* GIPROBE INSTANCE */ - -	struct GIProbeLight { -		uint32_t type; -		float energy; -		float radius; -		float attenuation; - -		float color[3]; -		float cos_spot_angle; - -		float position[3]; -		float inv_spot_attenuation; - -		float direction[3]; -		uint32_t has_shadow; -	}; - -	struct GIProbePushConstant { -		int32_t limits[3]; -		uint32_t stack_size; - -		float emission_scale; -		float propagation; -		float dynamic_range; -		uint32_t light_count; - -		uint32_t cell_offset; -		uint32_t cell_count; -		float aniso_strength; -		uint32_t pad; -	}; - -	struct GIProbeDynamicPushConstant { -		int32_t limits[3]; -		uint32_t light_count; -		int32_t x_dir[3]; -		float z_base; -		int32_t y_dir[3]; -		float z_sign; -		int32_t z_dir[3]; -		float pos_multiplier; -		uint32_t rect_pos[2]; -		uint32_t rect_size[2]; -		uint32_t prev_rect_ofs[2]; -		uint32_t prev_rect_size[2]; -		uint32_t flip_x; -		uint32_t flip_y; -		float dynamic_range; -		uint32_t on_mipmap; -		float propagation; -		float pad[3]; -	}; - -	struct GIProbeInstance { -		RID probe; -		RID texture; -		RID write_buffer; - -		struct Mipmap { -			RID texture; -			RID uniform_set; -			RID second_bounce_uniform_set; -			RID write_uniform_set; -			uint32_t level; -			uint32_t cell_offset; -			uint32_t cell_count; -		}; -		Vector<Mipmap> mipmaps; - -		struct DynamicMap { -			RID texture; //color normally, or emission on first pass -			RID fb_depth; //actual depth buffer for the first pass, float depth for later passes -			RID depth; //actual depth buffer for the first pass, float depth for later passes -			RID normal; //normal buffer for the first pass -			RID albedo; //emission buffer for the first pass -			RID orm; //orm buffer for the first pass -			RID fb; //used for rendering, only valid on first map -			RID uniform_set; -			uint32_t size; -			int mipmap; // mipmap to write to, -1 if no mipmap assigned -		}; - -		Vector<DynamicMap> dynamic_maps; - -		int slot = -1; -		uint32_t last_probe_version = 0; -		uint32_t last_probe_data_version = 0; - -		//uint64_t last_pass = 0; -		uint32_t render_index = 0; - -		bool has_dynamic_object_data = false; - -		Transform transform; -	}; - -	GIProbeLight *gi_probe_lights; -	uint32_t gi_probe_max_lights; -	RID gi_probe_lights_uniform; - -	enum { -		GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT, -		GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE, -		GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP, -		GI_PROBE_SHADER_VERSION_WRITE_TEXTURE, -		GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING, -		GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE, -		GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT, -		GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT, -		GI_PROBE_SHADER_VERSION_MAX -	}; -	GiprobeShaderRD giprobe_shader; -	RID giprobe_lighting_shader_version; -	RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX]; -	RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX]; - -	mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner; - -	RS::GIProbeQuality gi_probe_quality = RS::GI_PROBE_QUALITY_HIGH; - -	enum { -		GI_PROBE_DEBUG_COLOR, -		GI_PROBE_DEBUG_LIGHT, -		GI_PROBE_DEBUG_EMISSION, -		GI_PROBE_DEBUG_LIGHT_FULL, -		GI_PROBE_DEBUG_MAX -	}; - -	struct GIProbeDebugPushConstant { -		float projection[16]; -		uint32_t cell_offset; -		float dynamic_range; -		float alpha; -		uint32_t level; -		int32_t bounds[3]; -		uint32_t pad; -	}; - -	GiprobeDebugShaderRD giprobe_debug_shader; -	RID giprobe_debug_shader_version; -	RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX]; -	PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX]; -	RID giprobe_debug_uniform_set; -  	/* SHADOW ATLAS */  	struct ShadowShrinkStage { @@ -690,111 +323,6 @@ private:  	/* ENVIRONMENT */ -	struct Environment { -		// BG -		RS::EnvironmentBG background = RS::ENV_BG_CLEAR_COLOR; -		RID sky; -		float sky_custom_fov = 0.0; -		Basis sky_orientation; -		Color bg_color; -		float bg_energy = 1.0; -		int canvas_max_layer = 0; -		RS::EnvironmentAmbientSource ambient_source = RS::ENV_AMBIENT_SOURCE_BG; -		Color ambient_light; -		float ambient_light_energy = 1.0; -		float ambient_sky_contribution = 1.0; -		RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG; -		Color ao_color; - -		/// Tonemap - -		RS::EnvironmentToneMapper tone_mapper; -		float exposure = 1.0; -		float white = 1.0; -		bool auto_exposure = false; -		float min_luminance = 0.2; -		float max_luminance = 8.0; -		float auto_exp_speed = 0.2; -		float auto_exp_scale = 0.5; -		uint64_t auto_exposure_version = 0; - -		// Fog -		bool fog_enabled = false; -		Color fog_light_color = Color(0.5, 0.6, 0.7); -		float fog_light_energy = 1.0; -		float fog_sun_scatter = 0.0; -		float fog_density = 0.001; -		float fog_height = 0.0; -		float fog_height_density = 0.0; //can be negative to invert effect -		float fog_aerial_perspective = 0.0; - -		/// Volumetric Fog -		/// -		bool volumetric_fog_enabled = false; -		float volumetric_fog_density = 0.01; -		Color volumetric_fog_light = Color(0, 0, 0); -		float volumetric_fog_light_energy = 0.0; -		float volumetric_fog_length = 64.0; -		float volumetric_fog_detail_spread = 2.0; -		float volumetric_fog_gi_inject = 0.0; -		bool volumetric_fog_temporal_reprojection = true; -		float volumetric_fog_temporal_reprojection_amount = 0.9; - -		/// Glow - -		bool glow_enabled = false; -		Vector<float> glow_levels; -		float glow_intensity = 0.8; -		float glow_strength = 1.0; -		float glow_bloom = 0.0; -		float glow_mix = 0.01; -		RS::EnvironmentGlowBlendMode glow_blend_mode = RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT; -		float glow_hdr_bleed_threshold = 1.0; -		float glow_hdr_luminance_cap = 12.0; -		float glow_hdr_bleed_scale = 2.0; - -		/// SSAO - -		bool ssao_enabled = false; -		float ssao_radius = 1.0; -		float ssao_intensity = 2.0; -		float ssao_power = 1.5; -		float ssao_detail = 0.5; -		float ssao_horizon = 0.06; -		float ssao_sharpness = 0.98; -		float ssao_direct_light_affect = 0.0; -		float ssao_ao_channel_affect = 0.0; - -		/// SSR -		/// -		bool ssr_enabled = false; -		int ssr_max_steps = 64; -		float ssr_fade_in = 0.15; -		float ssr_fade_out = 2.0; -		float ssr_depth_tolerance = 0.2; - -		/// SDFGI -		bool sdfgi_enabled = false; -		RS::EnvironmentSDFGICascades sdfgi_cascades; -		float sdfgi_min_cell_size = 0.2; -		bool sdfgi_use_occlusion = false; -		float sdfgi_bounce_feedback = 0.0; -		bool sdfgi_read_sky_light = false; -		float sdfgi_energy = 1.0; -		float sdfgi_normal_bias = 1.1; -		float sdfgi_probe_bias = 1.1; -		RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED; - -		/// Adjustments - -		bool adjustments_enabled = false; -		float adjustments_brightness = 1.0f; -		float adjustments_contrast = 1.0f; -		float adjustments_saturation = 1.0f; -		bool use_1d_color_correction = false; -		RID color_correction = RID(); -	}; -  	RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;  	bool ssao_half_size = false;  	bool ssao_using_half_size = false; @@ -807,9 +335,7 @@ private:  	bool glow_high_quality = false;  	RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW; -	static uint64_t auto_exposure_counter; - -	mutable RID_Owner<Environment, true> environment_owner; +	mutable RID_Owner<RendererSceneEnvironmentRD, true> environment_owner;  	/* CAMERA EFFECTS */ @@ -842,14 +368,9 @@ private:  	ClusterBuilderSharedDataRD cluster_builder_shared;  	ClusterBuilderRD *current_cluster_builder = nullptr; -	struct SDFGI;  	struct VolumetricFog;  	struct RenderBuffers { -		enum { -			MAX_GIPROBES = 8 -		}; -  		RenderBufferData *data = nullptr;  		int width = 0, height = 0;  		RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; @@ -864,7 +385,7 @@ private:  		RID depth_texture; //main depth texture  		RID gi_uniform_set; -		SDFGI *sdfgi = nullptr; +		RendererSceneGIRD::SDFGI *sdfgi = nullptr;  		VolumetricFog *volumetric_fog = nullptr;  		ClusterBuilderRD *cluster_builder = nullptr; @@ -906,414 +427,14 @@ private:  			RID blur_radius[2];  		} ssr; -		RID giprobe_textures[MAX_GIPROBES]; -		RID giprobe_buffer; -  		RID ambient_buffer;  		RID reflection_buffer;  		bool using_half_size_gi = false; -		struct GI { -			RID full_buffer; -			RID full_dispatch; -			RID full_mask; -		} gi; +		RendererSceneGIRD::RenderBuffersGI gi;  	}; -	RID default_giprobe_buffer; - -	/* SDFGI */ - -	struct SDFGI { -		enum { -			MAX_CASCADES = 8, -			CASCADE_SIZE = 128, -			PROBE_DIVISOR = 16, -			ANISOTROPY_SIZE = 6, -			MAX_DYNAMIC_LIGHTS = 128, -			MAX_STATIC_LIGHTS = 1024, -			LIGHTPROBE_OCT_SIZE = 6, -			SH_SIZE = 16 -		}; - -		struct Cascade { -			struct UBO { -				float offset[3]; -				float to_cell; -				int32_t probe_offset[3]; -				uint32_t pad; -			}; - -			//cascade blocks are full-size for volume (128^3), half size for albedo/emission -			RID sdf_tex; -			RID light_tex; -			RID light_aniso_0_tex; -			RID light_aniso_1_tex; - -			RID light_data; -			RID light_aniso_0_data; -			RID light_aniso_1_data; - -			struct SolidCell { // this struct is unused, but remains as reference for size -				uint32_t position; -				uint32_t albedo; -				uint32_t static_light; -				uint32_t static_light_aniso; -			}; - -			RID solid_cell_dispatch_buffer; //buffer for indirect compute dispatch -			RID solid_cell_buffer; - -			RID lightprobe_history_tex; -			RID lightprobe_average_tex; - -			float cell_size; -			Vector3i position; - -			static const Vector3i DIRTY_ALL; -			Vector3i dirty_regions; //(0,0,0 is not dirty, negative is refresh from the end, DIRTY_ALL is refresh all. - -			RID sdf_store_uniform_set; -			RID sdf_direct_light_uniform_set; -			RID scroll_uniform_set; -			RID scroll_occlusion_uniform_set; -			RID integrate_uniform_set; -			RID lights_buffer; - -			bool all_dynamic_lights_dirty = true; -		}; - -		//used for rendering (voxelization) -		RID render_albedo; -		RID render_emission; -		RID render_emission_aniso; -		RID render_occlusion[8]; -		RID render_geom_facing; - -		RID render_sdf[2]; -		RID render_sdf_half[2]; - -		//used for ping pong processing in cascades -		RID sdf_initialize_uniform_set; -		RID sdf_initialize_half_uniform_set; -		RID jump_flood_uniform_set[2]; -		RID jump_flood_half_uniform_set[2]; -		RID sdf_upscale_uniform_set; -		int upscale_jfa_uniform_set_index; -		RID occlusion_uniform_set; - -		uint32_t cascade_size = 128; - -		LocalVector<Cascade> cascades; - -		RID lightprobe_texture; -		RID lightprobe_data; -		RID occlusion_texture; -		RID occlusion_data; -		RID ambient_texture; //integrates with volumetric fog - -		RID lightprobe_history_scroll; //used for scrolling lightprobes -		RID lightprobe_average_scroll; //used for scrolling lightprobes - -		uint32_t history_size = 0; -		float solid_cell_ratio = 0; -		uint32_t solid_cell_count = 0; - -		RS::EnvironmentSDFGICascades cascade_mode; -		float min_cell_size = 0; -		uint32_t probe_axis_count = 0; //amount of probes per axis, this is an odd number because it encloses endpoints - -		RID debug_uniform_set; -		RID debug_probes_uniform_set; -		RID cascades_ubo; - -		bool uses_occlusion = false; -		float bounce_feedback = 0.0; -		bool reads_sky = false; -		float energy = 1.0; -		float normal_bias = 1.1; -		float probe_bias = 1.1; -		RS::EnvironmentSDFGIYScale y_scale_mode = RS::ENV_SDFGI_Y_SCALE_DISABLED; - -		float y_mult = 1.0; - -		uint32_t render_pass = 0; - -		int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically -	}; - -	void _sdfgi_update_light(RID p_render_buffers, RID p_environment); -	void _sdfgi_update_probes(RID p_render_buffers, RID p_environment); -	void _sdfgi_store_probes(RID p_render_buffers); - -	RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16; -	RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_10_FRAMES; -	RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES; - -	float sdfgi_solid_cell_ratio = 0.25; -	Vector3 sdfgi_debug_probe_pos; -	Vector3 sdfgi_debug_probe_dir; -	bool sdfgi_debug_probe_enabled = false; -	Vector3i sdfgi_debug_probe_index; - -	struct SDGIShader { -		enum SDFGIPreprocessShaderVersion { -			PRE_PROCESS_SCROLL, -			PRE_PROCESS_SCROLL_OCCLUSION, -			PRE_PROCESS_JUMP_FLOOD_INITIALIZE, -			PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF, -			PRE_PROCESS_JUMP_FLOOD, -			PRE_PROCESS_JUMP_FLOOD_OPTIMIZED, -			PRE_PROCESS_JUMP_FLOOD_UPSCALE, -			PRE_PROCESS_OCCLUSION, -			PRE_PROCESS_STORE, -			PRE_PROCESS_MAX -		}; - -		struct PreprocessPushConstant { -			int32_t scroll[3]; -			int32_t grid_size; - -			int32_t probe_offset[3]; -			int32_t step_size; - -			int32_t half_size; -			uint32_t occlusion_index; -			int32_t cascade; -			uint32_t pad; -		}; - -		SdfgiPreprocessShaderRD preprocess; -		RID preprocess_shader; -		RID preprocess_pipeline[PRE_PROCESS_MAX]; - -		struct DebugPushConstant { -			float grid_size[3]; -			uint32_t max_cascades; - -			int32_t screen_size[2]; -			uint32_t use_occlusion; -			float y_mult; - -			float cam_extent[3]; -			uint32_t probe_axis_size; - -			float cam_transform[16]; -		}; - -		SdfgiDebugShaderRD debug; -		RID debug_shader; -		RID debug_shader_version; -		RID debug_pipeline; - -		enum ProbeDebugMode { -			PROBE_DEBUG_PROBES, -			PROBE_DEBUG_VISIBILITY, -			PROBE_DEBUG_MAX -		}; - -		struct DebugProbesPushConstant { -			float projection[16]; - -			uint32_t band_power; -			uint32_t sections_in_band; -			uint32_t band_mask; -			float section_arc; - -			float grid_size[3]; -			uint32_t cascade; - -			uint32_t pad; -			float y_mult; -			int32_t probe_debug_index; -			int32_t probe_axis_size; -		}; - -		SdfgiDebugProbesShaderRD debug_probes; -		RID debug_probes_shader; -		RID debug_probes_shader_version; - -		PipelineCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX]; - -		struct Light { -			float color[3]; -			float energy; - -			float direction[3]; -			uint32_t has_shadow; - -			float position[3]; -			float attenuation; - -			uint32_t type; -			float cos_spot_angle; -			float inv_spot_attenuation; -			float radius; - -			float shadow_color[4]; -		}; - -		struct DirectLightPushConstant { -			float grid_size[3]; -			uint32_t max_cascades; - -			uint32_t cascade; -			uint32_t light_count; -			uint32_t process_offset; -			uint32_t process_increment; - -			int32_t probe_axis_size; -			float bounce_feedback; -			float y_mult; -			uint32_t use_occlusion; -		}; - -		enum { -			DIRECT_LIGHT_MODE_STATIC, -			DIRECT_LIGHT_MODE_DYNAMIC, -			DIRECT_LIGHT_MODE_MAX -		}; -		SdfgiDirectLightShaderRD direct_light; -		RID direct_light_shader; -		RID direct_light_pipeline[DIRECT_LIGHT_MODE_MAX]; - -		enum { -			INTEGRATE_MODE_PROCESS, -			INTEGRATE_MODE_STORE, -			INTEGRATE_MODE_SCROLL, -			INTEGRATE_MODE_SCROLL_STORE, -			INTEGRATE_MODE_MAX -		}; -		struct IntegratePushConstant { -			enum { -				SKY_MODE_DISABLED, -				SKY_MODE_COLOR, -				SKY_MODE_SKY, -			}; - -			float grid_size[3]; -			uint32_t max_cascades; - -			uint32_t probe_axis_size; -			uint32_t cascade; -			uint32_t history_index; -			uint32_t history_size; - -			uint32_t ray_count; -			float ray_bias; -			int32_t image_size[2]; - -			int32_t world_offset[3]; -			uint32_t sky_mode; - -			int32_t scroll[3]; -			float sky_energy; - -			float sky_color[3]; -			float y_mult; - -			uint32_t store_ambient_texture; -			uint32_t pad[3]; -		}; - -		SdfgiIntegrateShaderRD integrate; -		RID integrate_shader; -		RID integrate_pipeline[INTEGRATE_MODE_MAX]; - -		RID integrate_default_sky_uniform_set; - -	} sdfgi_shader; - -	void _sdfgi_erase(RenderBuffers *rb); -	int _sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const; -	void _sdfgi_update_cascades(RID p_render_buffers); -  	/* GI */ - -	struct GI { -		struct SDFGIData { -			float grid_size[3]; -			uint32_t max_cascades; - -			uint32_t use_occlusion; -			int32_t probe_axis_size; -			float probe_to_uvw; -			float normal_bias; - -			float lightprobe_tex_pixel_size[3]; -			float energy; - -			float lightprobe_uv_offset[3]; -			float y_mult; - -			float occlusion_clamp[3]; -			uint32_t pad3; - -			float occlusion_renormalize[3]; -			uint32_t pad4; - -			float cascade_probe_size[3]; -			uint32_t pad5; - -			struct ProbeCascadeData { -				float position[3]; //offset of (0,0,0) in world coordinates -				float to_probe; // 1/bounds * grid_size -				int32_t probe_world_offset[3]; -				float to_cell; // 1/bounds * grid_size -			}; - -			ProbeCascadeData cascades[SDFGI::MAX_CASCADES]; -		}; - -		struct GIProbeData { -			float xform[16]; -			float bounds[3]; -			float dynamic_range; - -			float bias; -			float normal_bias; -			uint32_t blend_ambient; -			uint32_t texture_slot; - -			float anisotropy_strength; -			float ao; -			float ao_size; -			uint32_t mipmaps; -		}; - -		struct PushConstant { -			int32_t screen_size[2]; -			float z_near; -			float z_far; - -			float proj_info[4]; -			float ao_color[3]; -			uint32_t max_giprobes; - -			uint32_t high_quality_vct; -			uint32_t orthogonal; -			uint32_t pad[2]; - -			float cam_rotation[12]; -		}; - -		RID sdfgi_ubo; -		enum Mode { -			MODE_GIPROBE, -			MODE_SDFGI, -			MODE_COMBINED, -			MODE_HALF_RES_GIPROBE, -			MODE_HALF_RES_SDFGI, -			MODE_HALF_RES_COMBINED, -			MODE_MAX -		}; - -		bool half_resolution = false; -		GiShaderRD shader; -		RID shader_version; -		RID pipelines[MODE_MAX]; -	} gi; -  	bool screen_space_roughness_limiter = false;  	float screen_space_roughness_limiter_amount = 0.25;  	float screen_space_roughness_limiter_limit = 0.18; @@ -1326,7 +447,6 @@ private:  	void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas);  	void _render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection); -	void _sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform);  	/* Cluster */ @@ -1592,17 +712,17 @@ private:  	uint64_t scene_pass = 0;  	uint64_t shadow_atlas_realloc_tolerance_msec = 500; +	/* !BAS! is this used anywhere?  	struct SDFGICosineNeighbour {  		uint32_t neighbour;  		float weight;  	}; +	*/  	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_sdfgi_region(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances); -	void _render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result);  public:  	virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance) = 0; @@ -1646,12 +766,12 @@ public:  	/* SDFGI UPDATE */ -	int sdfgi_get_lightprobe_octahedron_size() const { return SDFGI::LIGHTPROBE_OCT_SIZE; }  	virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position);  	virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const;  	virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const;  	virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const;  	RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; } +  	/* SKY API */  	virtual RID sky_allocate(); @@ -1662,10 +782,6 @@ public:  	void sky_set_material(RID p_sky, RID p_material);  	Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size); -	RID sky_get_radiance_texture_rd(RID p_sky) const; -	RID sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const; -	RID sky_get_material(RID p_sky) const; -  	/* ENVIRONMENT API */  	virtual RID environment_allocate(); @@ -1974,52 +1090,54 @@ public:  		return li->transform;  	} +	// !BAS! Need to check which of these we move into RenderSceneGIRD or whether we keep this the way it is now +  	RID gi_probe_instance_create(RID p_base);  	void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);  	bool gi_probe_needs_update(RID p_probe) const;  	void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects); -	void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi_probe_quality = p_quality; } +	void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi.gi_probe_quality = p_quality; }  	_FORCE_INLINE_ uint32_t gi_probe_instance_get_slot(RID p_probe) { -		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); +		RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_probe);  		return gi_probe->slot;  	}  	_FORCE_INLINE_ RID gi_probe_instance_get_base_probe(RID p_probe) { -		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); +		RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_probe);  		return gi_probe->probe;  	}  	_FORCE_INLINE_ Transform gi_probe_instance_get_transform_to_cell(RID p_probe) { -		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); +		RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_probe);  		return storage->gi_probe_get_to_cell_xform(gi_probe->probe) * gi_probe->transform.affine_inverse();  	}  	_FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) { -		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); +		RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_probe);  		return gi_probe->texture;  	}  	_FORCE_INLINE_ void gi_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) { -		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance); +		RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_instance);  		ERR_FAIL_COND(!gi_probe);  		gi_probe->render_index = p_render_index;  	}  	_FORCE_INLINE_ uint32_t gi_probe_instance_get_render_index(RID p_instance) { -		GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance); +		RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_instance);  		ERR_FAIL_COND_V(!gi_probe, 0);  		return gi_probe->render_index;  	}  	/*  	_FORCE_INLINE_ void gi_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) { -		GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance); +		RendererSceneGIRD::GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);  		ERR_FAIL_COND(!g_probe);  		g_probe->last_pass = p_render_pass;  	}  	_FORCE_INLINE_ uint32_t gi_probe_instance_get_render_pass(RID p_instance) { -		GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance); +		RendererSceneGIRD::GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);  		ERR_FAIL_COND_V(!g_probe, 0);  		return g_probe->last_pass; diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp new file mode 100644 index 0000000000..769335ac16 --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -0,0 +1,1491 @@ +/*************************************************************************/ +/*  renderer_scene_sky_rd.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 "renderer_scene_sky_rd.h" +#include "core/config/project_settings.h" +#include "renderer_scene_render_rd.h" +#include "servers/rendering/rendering_server_default.h" + +//////////////////////////////////////////////////////////////////////////////// +// SKY SHADER + +void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) { +	//compile + +	code = p_code; +	valid = false; +	ubo_size = 0; +	uniforms.clear(); + +	if (code == String()) { +		return; //just invalid, but no error +	} + +	ShaderCompilerRD::GeneratedCode gen_code; +	ShaderCompilerRD::IdentifierActions actions; + +	uses_time = false; +	uses_half_res = false; +	uses_quarter_res = false; +	uses_position = false; +	uses_light = false; + +	actions.render_mode_flags["use_half_res_pass"] = &uses_half_res; +	actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res; + +	actions.usage_flag_pointers["TIME"] = &uses_time; +	actions.usage_flag_pointers["POSITION"] = &uses_position; +	actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light; +	actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light; +	actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light; +	actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light; +	actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light; +	actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light; +	actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light; +	actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light; +	actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light; +	actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light; +	actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light; +	actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light; +	actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light; +	actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light; +	actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light; +	actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light; +	actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light; +	actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light; +	actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light; +	actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light; + +	actions.uniforms = &uniforms; + +	// !BAS! Contemplate making `SkyShader sky` accessible from this struct or even part of this struct. +	RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; + +	Error err = scene_singleton->sky.sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code); + +	ERR_FAIL_COND(err != OK); + +	if (version.is_null()) { +		version = scene_singleton->sky.sky_shader.shader.version_create(); +	} + +#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 + +	scene_singleton->sky.sky_shader.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(!scene_singleton->sky.sky_shader.shader.version_is_valid(version)); + +	ubo_size = gen_code.uniform_total_size; +	ubo_offsets = gen_code.uniform_offsets; +	texture_uniforms = gen_code.texture_uniforms; + +	//update pipelines + +	for (int i = 0; i < SKY_VERSION_MAX; i++) { +		RD::PipelineDepthStencilState depth_stencil_state; +		depth_stencil_state.enable_depth_test = true; +		depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + +		RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i); +		pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0); +	} + +	valid = true; +} + +void RendererSceneSkyRD::SkyShaderData::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 RendererSceneSkyRD::SkyShaderData::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_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { +			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 RendererSceneSkyRD::SkyShaderData::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 RendererSceneSkyRD::SkyShaderData::is_param_texture(const StringName &p_param) const { +	if (!uniforms.has(p_param)) { +		return false; +	} + +	return uniforms[p_param].texture_order >= 0; +} + +bool RendererSceneSkyRD::SkyShaderData::is_animated() const { +	return false; +} + +bool RendererSceneSkyRD::SkyShaderData::casts_shadows() const { +	return false; +} + +Variant RendererSceneSkyRD::SkyShaderData::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 RendererSceneSkyRD::SkyShaderData::get_native_source_code() const { +	RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; + +	return scene_singleton->sky.sky_shader.shader.version_get_native_source_code(version); +} + +RendererSceneSkyRD::SkyShaderData::SkyShaderData() { +	valid = false; +} + +RendererSceneSkyRD::SkyShaderData::~SkyShaderData() { +	RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; +	ERR_FAIL_COND(!scene_singleton); +	//pipeline variants will clear themselves if shader is gone +	if (version.is_valid()) { +		scene_singleton->sky.sky_shader.shader.version_free(version); +	} +} + +//////////////////////////////////////////////////////////////////////////////// +// Sky material + +void RendererSceneSkyRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +	RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; + +	uniform_set_updated = true; + +	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()); +	} + +	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, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL); +} + +RendererSceneSkyRD::SkyMaterialData::~SkyMaterialData() { +	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); +	} +} + +//////////////////////////////////////////////////////////////////////////////// +// ReflectionData + +void RendererSceneSkyRD::ReflectionData::clear_reflection_data() { +	layers.clear(); +	radiance_base_cubemap = RID(); +	if (downsampled_radiance_cubemap.is_valid()) { +		RD::get_singleton()->free(downsampled_radiance_cubemap); +	} +	downsampled_radiance_cubemap = RID(); +	downsampled_layer.mipmaps.clear(); +	coefficient_buffer = RID(); +} + +void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers) { +	//recreate radiance and all data + +	int mipmaps = p_mipmaps; +	uint32_t w = p_size, h = p_size; + +	if (p_use_array) { +		int num_layers = p_low_quality ? 8 : p_roughness_layers; + +		for (int i = 0; i < num_layers; i++) { +			ReflectionData::Layer layer; +			uint32_t mmw = w; +			uint32_t mmh = h; +			layer.mipmaps.resize(mipmaps); +			layer.views.resize(mipmaps); +			for (int j = 0; j < mipmaps; j++) { +				ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; +				mm.size.width = mmw; +				mm.size.height = mmh; +				for (int k = 0; k < 6; k++) { +					mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j); +					Vector<RID> fbtex; +					fbtex.push_back(mm.views[k]); +					mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); +				} + +				layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, RD::TEXTURE_SLICE_CUBEMAP); + +				mmw = MAX(1, mmw >> 1); +				mmh = MAX(1, mmh >> 1); +			} + +			layers.push_back(layer); +		} + +	} else { +		mipmaps = p_low_quality ? 8 : mipmaps; +		//regular cubemap, lower quality (aliasing, less memory) +		ReflectionData::Layer layer; +		uint32_t mmw = w; +		uint32_t mmh = h; +		layer.mipmaps.resize(mipmaps); +		layer.views.resize(mipmaps); +		for (int j = 0; j < mipmaps; j++) { +			ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j]; +			mm.size.width = mmw; +			mm.size.height = mmh; +			for (int k = 0; k < 6; k++) { +				mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j); +				Vector<RID> fbtex; +				fbtex.push_back(mm.views[k]); +				mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); +			} + +			layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, RD::TEXTURE_SLICE_CUBEMAP); + +			mmw = MAX(1, mmw >> 1); +			mmh = MAX(1, mmh >> 1); +		} + +		layers.push_back(layer); +	} + +	radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP); + +	RD::TextureFormat tf; +	tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; +	tf.width = 64; // Always 64x64 +	tf.height = 64; +	tf.texture_type = RD::TEXTURE_TYPE_CUBE; +	tf.array_layers = 6; +	tf.mipmaps = 7; +	tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + +	downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); +	{ +		uint32_t mmw = 64; +		uint32_t mmh = 64; +		downsampled_layer.mipmaps.resize(7); +		for (int j = 0; j < downsampled_layer.mipmaps.size(); j++) { +			ReflectionData::DownsampleLayer::Mipmap &mm = downsampled_layer.mipmaps.write[j]; +			mm.size.width = mmw; +			mm.size.height = mmh; +			mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP); + +			mmw = MAX(1, mmw >> 1); +			mmh = MAX(1, mmh >> 1); +		} +	} +} + +void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) { +	p_storage->get_effects()->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + +	for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { +		p_storage->get_effects()->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); +	} + +	Vector<RID> views; +	if (p_use_arrays) { +		for (int i = 1; i < layers.size(); i++) { +			views.push_back(layers[i].views[0]); +		} +	} else { +		for (int i = 1; i < layers[0].views.size(); i++) { +			views.push_back(layers[0].views[i]); +		} +	} + +	p_storage->get_effects()->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays); +} + +void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) { +	if (p_use_arrays) { +		//render directly to the layers +		p_storage->get_effects()->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); +	} else { +		p_storage->get_effects()->cubemap_roughness( +				layers[0].views[p_base_layer - 1], +				layers[0].views[p_base_layer], +				p_cube_side, +				p_sky_ggx_samples_quality, +				float(p_base_layer) / (layers[0].mipmaps.size() - 1.0), +				layers[0].mipmaps[p_base_layer].size.x); +	} +} + +void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) { +	for (int i = p_start; i < p_end; i++) { +		for (int j = 0; j < layers[i].views.size() - 1; j++) { +			RID view = layers[i].views[j]; +			RID texture = layers[i].views[j + 1]; +			Size2i size = layers[i].mipmaps[j + 1].size; +			p_storage->get_effects()->cubemap_downsample(view, texture, size); +		} +	} +} + +//////////////////////////////////////////////////////////////////////////////// +// RendererSceneSkyRD::Sky + +void RendererSceneSkyRD::Sky::free(RendererStorageRD *p_storage) { +	if (radiance.is_valid()) { +		RD::get_singleton()->free(radiance); +		radiance = RID(); +	} +	reflection.clear_reflection_data(); + +	if (uniform_buffer.is_valid()) { +		RD::get_singleton()->free(uniform_buffer); +		uniform_buffer = RID(); +	} + +	if (half_res_pass.is_valid()) { +		RD::get_singleton()->free(half_res_pass); +		half_res_pass = RID(); +	} + +	if (quarter_res_pass.is_valid()) { +		RD::get_singleton()->free(quarter_res_pass); +		quarter_res_pass = RID(); +	} + +	if (material.is_valid()) { +		p_storage->free(material); +	} +} + +RID RendererSceneSkyRD::Sky::get_textures(RendererStorageRD *p_storage, SkyTextureSetVersion p_version, RID p_default_shader_rd) { +	if (texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(texture_uniform_sets[p_version])) { +		return texture_uniform_sets[p_version]; +	} +	Vector<RD::Uniform> uniforms; +	{ +		RD::Uniform u; +		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +		u.binding = 0; +		if (radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) { +			u.ids.push_back(radiance); +		} else { +			u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); +		} +		uniforms.push_back(u); +	} +	{ +		RD::Uniform u; +		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +		u.binding = 1; // half res +		if (half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) { +			if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { +				u.ids.push_back(reflection.layers[0].views[1]); +			} else { +				u.ids.push_back(half_res_pass); +			} +		} else { +			if (p_version < SKY_TEXTURE_SET_CUBEMAP) { +				u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); +			} else { +				u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); +			} +		} +		uniforms.push_back(u); +	} +	{ +		RD::Uniform u; +		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +		u.binding = 2; // quarter res +		if (quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) { +			if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { +				u.ids.push_back(reflection.layers[0].views[2]); +			} else { +				u.ids.push_back(quarter_res_pass); +			} +		} else { +			if (p_version < SKY_TEXTURE_SET_CUBEMAP) { +				u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); +			} else { +				u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); +			} +		} +		uniforms.push_back(u); +	} + +	texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, p_default_shader_rd, SKY_SET_TEXTURES); +	return texture_uniform_sets[p_version]; +} + +bool RendererSceneSkyRD::Sky::set_radiance_size(int p_radiance_size) { +	ERR_FAIL_COND_V(p_radiance_size < 32 || p_radiance_size > 2048, false); +	if (radiance_size == p_radiance_size) { +		return false; +	} +	radiance_size = p_radiance_size; + +	if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) { +		WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); +		radiance_size = 256; +	} + +	if (radiance.is_valid()) { +		RD::get_singleton()->free(radiance); +		radiance = RID(); +	} +	reflection.clear_reflection_data(); + +	return true; +} + +bool RendererSceneSkyRD::Sky::set_mode(RS::SkyMode p_mode) { +	if (mode == p_mode) { +		return false; +	} + +	mode = p_mode; + +	if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) { +		WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally."); +		set_radiance_size(256); +	} + +	if (radiance.is_valid()) { +		RD::get_singleton()->free(radiance); +		radiance = RID(); +	} +	reflection.clear_reflection_data(); + +	return true; +} + +bool RendererSceneSkyRD::Sky::set_material(RID p_material) { +	if (material == p_material) { +		return false; +	} + +	material = p_material; +	return true; +} + +Ref<Image> RendererSceneSkyRD::Sky::bake_panorama(RendererStorageRD *p_storage, float p_energy, int p_roughness_layers, const Size2i &p_size) { +	if (radiance.is_valid()) { +		RD::TextureFormat tf; +		tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; +		tf.width = p_size.width; +		tf.height = p_size.height; +		tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + +		RID rad_tex = RD::get_singleton()->texture_create(tf, RD::TextureView()); +		p_storage->get_effects()->copy_cubemap_to_panorama(radiance, rad_tex, p_size, p_roughness_layers, reflection.layers.size() > 1); +		Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rad_tex, 0); +		RD::get_singleton()->free(rad_tex); + +		Ref<Image> img; +		img.instance(); +		img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data); +		for (int i = 0; i < p_size.width; i++) { +			for (int j = 0; j < p_size.height; j++) { +				Color c = img->get_pixel(i, j); +				c.r *= p_energy; +				c.g *= p_energy; +				c.b *= p_energy; +				img->set_pixel(i, j, c); +			} +		} +		return img; +	} + +	return Ref<Image>(); +} + +//////////////////////////////////////////////////////////////////////////////// +// RendererSceneSkyRD + +RendererStorageRD::ShaderData *RendererSceneSkyRD::_create_sky_shader_func() { +	SkyShaderData *shader_data = memnew(SkyShaderData); +	return shader_data; +} + +RendererStorageRD::ShaderData *RendererSceneSkyRD::_create_sky_shader_funcs() { +	// !BAS! Why isn't _create_sky_shader_func not just static too? +	return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_shader_func(); +}; + +RendererStorageRD::MaterialData *RendererSceneSkyRD::_create_sky_material_func(SkyShaderData *p_shader) { +	SkyMaterialData *material_data = memnew(SkyMaterialData); +	material_data->shader_data = p_shader; +	material_data->last_frame = false; +	//update will happen later anyway so do nothing. +	return material_data; +} + +RendererStorageRD::MaterialData *RendererSceneSkyRD::_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader) { +	// !BAS! same here, we could just make _create_sky_material_func static? +	return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_material_func(static_cast<SkyShaderData *>(p_shader)); +}; + +RendererSceneSkyRD::RendererSceneSkyRD() { +	roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers"); +	sky_ggx_samples_quality = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples"); +	sky_use_cubemap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections"); +} + +void RendererSceneSkyRD::init(RendererStorageRD *p_storage) { +	storage = p_storage; + +	{ +		// Start with the directional lights for the sky +		sky_scene_state.max_directional_lights = 4; +		uint32_t directional_light_buffer_size = sky_scene_state.max_directional_lights * sizeof(SkyDirectionalLightData); +		sky_scene_state.directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights); +		sky_scene_state.last_frame_directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights); +		sky_scene_state.last_frame_directional_light_count = sky_scene_state.max_directional_lights + 1; +		sky_scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); + +		String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_scene_state.max_directional_lights) + "\n"; + +		// Initialize sky +		Vector<String> sky_modes; +		sky_modes.push_back(""); // Full size +		sky_modes.push_back("\n#define USE_HALF_RES_PASS\n"); // Half Res +		sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n"); // Quarter res +		sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap +		sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap +		sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap +		sky_shader.shader.initialize(sky_modes, defines); +	} + +	// register our shader funds +	storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs); +	storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs); + +	{ +		ShaderCompilerRD::DefaultIdentifierActions actions; + +		actions.renames["COLOR"] = "color"; +		actions.renames["ALPHA"] = "alpha"; +		actions.renames["EYEDIR"] = "cube_normal"; +		actions.renames["POSITION"] = "params.position_multiplier.xyz"; +		actions.renames["SKY_COORDS"] = "panorama_coords"; +		actions.renames["SCREEN_UV"] = "uv"; +		actions.renames["TIME"] = "params.time"; +		actions.renames["HALF_RES_COLOR"] = "half_res_color"; +		actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color"; +		actions.renames["RADIANCE"] = "radiance"; +		actions.renames["FOG"] = "custom_fog"; +		actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled"; +		actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz"; +		actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w"; +		actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz"; +		actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w"; +		actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled"; +		actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz"; +		actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w"; +		actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz"; +		actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w"; +		actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled"; +		actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz"; +		actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w"; +		actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz"; +		actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w"; +		actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled"; +		actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz"; +		actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w"; +		actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz"; +		actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w"; +		actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS"; +		actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS"; +		actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS"; +		actions.custom_samplers["RADIANCE"] = "material_samplers[3]"; +		actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n"; +		actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n"; +		actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n"; + +		actions.sampler_array_name = "material_samplers"; +		actions.base_texture_binding_index = 1; +		actions.texture_layout_set = 1; +		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"; + +		sky_shader.compiler.initialize(actions); +	} + +	{ +		// default material and shader for sky shader +		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 fragment() { COLOR = vec3(0.0); } \n"); + +		sky_shader.default_material = storage->material_allocate(); +		storage->material_initialize(sky_shader.default_material); + +		storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader); + +		SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); +		sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND); + +		sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO)); + +		Vector<RD::Uniform> uniforms; + +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; +			u.binding = 0; +			u.ids.resize(12); +			RID *ids_ptr = u.ids.ptrw(); +			ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +			ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +			u.binding = 1; +			u.ids.push_back(storage->global_variables_get_storage_buffer()); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.binding = 2; +			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.ids.push_back(sky_scene_state.uniform_buffer); +			uniforms.push_back(u); +		} + +		{ +			RD::Uniform u; +			u.binding = 3; +			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; +			u.ids.push_back(sky_scene_state.directional_light_buffer); +			uniforms.push_back(u); +		} + +		sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS); +	} + +	{ +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.binding = 0; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			RID vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); +			u.ids.push_back(vfog); +			uniforms.push_back(u); +		} + +		sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG); +	} + +	{ +		// Need defaults for using fog with clear color +		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 fragment() { COLOR = clear_color.rgb; } \n"); +		sky_scene_state.fog_material = storage->material_allocate(); +		storage->material_initialize(sky_scene_state.fog_material); + +		storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader); + +		Vector<RD::Uniform> uniforms; +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 0; +			u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 1; +			u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); +			uniforms.push_back(u); +		} +		{ +			RD::Uniform u; +			u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; +			u.binding = 2; +			u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); +			uniforms.push_back(u); +		} + +		sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES); +	} +} + +void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) { +	ERR_FAIL_COND(!p_env); // I guess without an environment we also can't have a sky... + +	SkyMaterialData *material = nullptr; +	Sky *sky = get_sky(p_env->sky); + +	RID sky_material; + +	SkyShaderData *shader_data = nullptr; + +	RS::EnvironmentBG background = p_env->background; + +	if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { +		// !BAS! Possibly silently fail here, we now get error spam when you select sky as the background but haven't setup the sky yet. +		ERR_FAIL_COND(!sky); +		sky_material = sky_get_material(p_env->sky); + +		if (sky_material.is_valid()) { +			material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); +			if (!material || !material->shader_data->valid) { +				material = nullptr; +			} +		} + +		if (!material) { +			sky_material = sky_shader.default_material; +			material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); +		} + +		ERR_FAIL_COND(!material); + +		shader_data = material->shader_data; + +		ERR_FAIL_COND(!shader_data); +	} + +	if (sky) { +		// Invalidate supbass buffers if screen size changes +		if (sky->screen_size != p_screen_size) { +			sky->screen_size = p_screen_size; +			sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x; +			sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y; +			if (shader_data->uses_half_res) { +				if (sky->half_res_pass.is_valid()) { +					RD::get_singleton()->free(sky->half_res_pass); +					sky->half_res_pass = RID(); +				} +				invalidate_sky(sky); +			} +			if (shader_data->uses_quarter_res) { +				if (sky->quarter_res_pass.is_valid()) { +					RD::get_singleton()->free(sky->quarter_res_pass); +					sky->quarter_res_pass = RID(); +				} +				invalidate_sky(sky); +			} +		} + +		// Create new subpass buffers if necessary +		if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) || +				(shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) || +				sky->radiance.is_null()) { +			invalidate_sky(sky); +			update_dirty_skys(); +		} + +		if (shader_data->uses_time && p_scene_render->time - sky->prev_time > 0.00001) { +			sky->prev_time = p_scene_render->time; +			sky->reflection.dirty = true; +			RenderingServerDefault::redraw_request(); +		} + +		if (material != sky->prev_material) { +			sky->prev_material = material; +			sky->reflection.dirty = true; +		} + +		if (material->uniform_set_updated) { +			material->uniform_set_updated = false; +			sky->reflection.dirty = true; +		} + +		if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) { +			sky->prev_position = p_transform.origin; +			sky->reflection.dirty = true; +		} + +		if (shader_data->uses_light) { +			// Check whether the directional_light_buffer changes +			bool light_data_dirty = false; + +			if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) { +				light_data_dirty = true; +				for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) { +					sky_scene_state.directional_lights[i].enabled = false; +				} +			} +			if (!light_data_dirty) { +				for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) { +					if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] || +							sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] || +							sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] || +							sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy || +							sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] || +							sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] || +							sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] || +							sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled || +							sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) { +						light_data_dirty = true; +						break; +					} +				} +			} + +			if (light_data_dirty) { +				RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights); + +				SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights; +				sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights; +				sky_scene_state.directional_lights = temp; +				sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count; +				sky->reflection.dirty = true; +			} +		} +	} + +	//setup fog variables +	sky_scene_state.ubo.volumetric_fog_enabled = false; +	if (p_render_buffers.is_valid()) { +		if (p_scene_render->render_buffers_has_volumetric_fog(p_render_buffers)) { +			sky_scene_state.ubo.volumetric_fog_enabled = true; + +			float fog_end = p_scene_render->render_buffers_get_volumetric_fog_end(p_render_buffers); +			if (fog_end > 0.0) { +				sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end; +			} else { +				sky_scene_state.ubo.volumetric_fog_inv_length = 1.0; +			} + +			float fog_detail_spread = p_scene_render->render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup +			if (fog_detail_spread > 0.0) { +				sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread; +			} else { +				sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0; +			} +		} + +		RID fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers); + +		if (fog_uniform_set != RID()) { +			sky_scene_state.fog_uniform_set = fog_uniform_set; +		} else { +			sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set; +		} +	} + +	sky_scene_state.ubo.z_far = p_projection.get_z_far(); +	sky_scene_state.ubo.fog_enabled = p_env->fog_enabled; +	sky_scene_state.ubo.fog_density = p_env->fog_density; +	sky_scene_state.ubo.fog_aerial_perspective = p_env->fog_aerial_perspective; +	Color fog_color = p_env->fog_light_color.to_linear(); +	float fog_energy = p_env->fog_light_energy; +	sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy; +	sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy; +	sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; +	sky_scene_state.ubo.fog_sun_scatter = p_env->fog_sun_scatter; + +	RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo); +} + +void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) { +	ERR_FAIL_COND(!p_env); + +	Sky *sky = get_sky(p_env->sky); +	ERR_FAIL_COND(!sky); + +	RID sky_material = sky_get_material(p_env->sky); + +	SkyMaterialData *material = nullptr; + +	if (sky_material.is_valid()) { +		material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); +		if (!material || !material->shader_data->valid) { +			material = nullptr; +		} +	} + +	if (!material) { +		sky_material = sky_shader.default_material; +		material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); +	} + +	ERR_FAIL_COND(!material); + +	SkyShaderData *shader_data = material->shader_data; + +	ERR_FAIL_COND(!shader_data); + +	float multiplier = p_env->bg_energy; + +	bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY; +	RS::SkyMode sky_mode = sky->mode; + +	if (sky_mode == RS::SKY_MODE_AUTOMATIC) { +		if (shader_data->uses_time || shader_data->uses_position) { +			update_single_frame = true; +			sky_mode = RS::SKY_MODE_REALTIME; +		} else if (shader_data->uses_light || shader_data->ubo_size > 0) { +			update_single_frame = false; +			sky_mode = RS::SKY_MODE_INCREMENTAL; +		} else { +			update_single_frame = true; +			sky_mode = RS::SKY_MODE_QUALITY; +		} +	} + +	if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) { +		// On the first frame after creating sky, rebuild in single frame +		update_single_frame = true; +		sky_mode = RS::SKY_MODE_QUALITY; +	} + +	int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size(); + +	// Update radiance cubemap +	if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) { +		static const Vector3 view_normals[6] = { +			Vector3(+1, 0, 0), +			Vector3(-1, 0, 0), +			Vector3(0, +1, 0), +			Vector3(0, -1, 0), +			Vector3(0, 0, +1), +			Vector3(0, 0, -1) +		}; +		static const Vector3 view_up[6] = { +			Vector3(0, -1, 0), +			Vector3(0, -1, 0), +			Vector3(0, 0, +1), +			Vector3(0, 0, -1), +			Vector3(0, -1, 0), +			Vector3(0, -1, 0) +		}; + +		CameraMatrix cm; +		cm.set_perspective(90, 1, 0.01, 10.0); +		CameraMatrix correction; +		correction.set_depth_correction(true); +		cm = correction * cm; + +		if (shader_data->uses_quarter_res) { +			PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; + +			Vector<Color> clear_colors; +			clear_colors.push_back(Color(0.0, 0.0, 0.0)); +			RD::DrawListID cubemap_draw_list; + +			for (int i = 0; i < 6; i++) { +				Transform local_view; +				local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); +				RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd); + +				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); +				storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); +				RD::get_singleton()->draw_list_end(); +			} +		} + +		if (shader_data->uses_half_res) { +			PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; + +			Vector<Color> clear_colors; +			clear_colors.push_back(Color(0.0, 0.0, 0.0)); +			RD::DrawListID cubemap_draw_list; + +			for (int i = 0; i < 6; i++) { +				Transform local_view; +				local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); +				RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd); + +				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); +				storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); +				RD::get_singleton()->draw_list_end(); +			} +		} + +		RD::DrawListID cubemap_draw_list; +		PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; + +		for (int i = 0; i < 6; i++) { +			Transform local_view; +			local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); +			RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd); + +			cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); +			storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); +			RD::get_singleton()->draw_list_end(); +		} + +		if (sky_mode == RS::SKY_MODE_REALTIME) { +			sky->reflection.create_reflection_fast_filter(storage, sky_use_cubemap_array); +			if (sky_use_cubemap_array) { +				sky->reflection.update_reflection_mipmaps(storage, 0, sky->reflection.layers.size()); +			} +		} else { +			if (update_single_frame) { +				for (int i = 1; i < max_processing_layer; i++) { +					sky->reflection.create_reflection_importance_sample(storage, sky_use_cubemap_array, 10, i, sky_ggx_samples_quality); +				} +				if (sky_use_cubemap_array) { +					sky->reflection.update_reflection_mipmaps(storage, 0, sky->reflection.layers.size()); +				} +			} else { +				if (sky_use_cubemap_array) { +					// Multi-Frame so just update the first array level +					sky->reflection.update_reflection_mipmaps(storage, 0, 1); +				} +			} +			sky->processing_layer = 1; +		} + +		sky->reflection.dirty = false; + +	} else { +		if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) { +			sky->reflection.create_reflection_importance_sample(storage, sky_use_cubemap_array, 10, sky->processing_layer, sky_ggx_samples_quality); + +			if (sky_use_cubemap_array) { +				sky->reflection.update_reflection_mipmaps(storage, sky->processing_layer, sky->processing_layer + 1); +			} + +			sky->processing_layer++; +		} +	} +} + +void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) { +	ERR_FAIL_COND(!p_env); + +	Sky *sky = get_sky(p_env->sky); +	ERR_FAIL_COND(!sky); + +	SkyMaterialData *material = nullptr; +	RID sky_material; + +	RS::EnvironmentBG background = p_env->background; + +	if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { +		ERR_FAIL_COND(!sky); +		sky_material = sky_get_material(p_env->sky); + +		if (sky_material.is_valid()) { +			material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); +			if (!material || !material->shader_data->valid) { +				material = nullptr; +			} +		} + +		if (!material) { +			sky_material = sky_shader.default_material; +			material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); +		} +	} + +	if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { +		sky_material = sky_scene_state.fog_material; +		material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); +	} + +	ERR_FAIL_COND(!material); + +	SkyShaderData *shader_data = material->shader_data; + +	ERR_FAIL_COND(!shader_data); + +	Basis sky_transform = p_env->sky_orientation; +	sky_transform.invert(); + +	float multiplier = p_env->bg_energy; +	float custom_fov = p_env->sky_custom_fov; +	// Camera +	CameraMatrix camera; + +	if (custom_fov) { +		float near_plane = p_projection.get_z_near(); +		float far_plane = p_projection.get_z_far(); +		float aspect = p_projection.get_aspect(); + +		camera.set_perspective(custom_fov, aspect, near_plane, far_plane); + +	} else { +		camera = p_projection; +	} + +	sky_transform = p_transform.basis * sky_transform; + +	if (shader_data->uses_quarter_res) { +		PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES]; + +		RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd); + +		Vector<Color> clear_colors; +		clear_colors.push_back(Color(0.0, 0.0, 0.0)); + +		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); +		storage->get_effects()->render_sky(draw_list, p_time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); +		RD::get_singleton()->draw_list_end(); +	} + +	if (shader_data->uses_half_res) { +		PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES]; + +		RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd); + +		Vector<Color> clear_colors; +		clear_colors.push_back(Color(0.0, 0.0, 0.0)); + +		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); +		storage->get_effects()->render_sky(draw_list, p_time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); +		RD::get_singleton()->draw_list_end(); +	} + +	PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND]; + +	RID texture_uniform_set; +	if (sky) { +		texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd); +	} else { +		texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set; +	} + +	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); +	storage->get_effects()->render_sky(draw_list, p_time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); +	RD::get_singleton()->draw_list_end(); +} + +void RendererSceneSkyRD::invalidate_sky(Sky *p_sky) { +	if (!p_sky->dirty) { +		p_sky->dirty = true; +		p_sky->dirty_list = dirty_sky_list; +		dirty_sky_list = p_sky; +	} +} + +void RendererSceneSkyRD::update_dirty_skys() { +	Sky *sky = dirty_sky_list; + +	while (sky) { +		bool texture_set_dirty = false; +		//update sky configuration if texture is missing + +		if (sky->radiance.is_null()) { +			int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1; + +			uint32_t w = sky->radiance_size, h = sky->radiance_size; +			int layers = roughness_layers; +			if (sky->mode == RS::SKY_MODE_REALTIME) { +				layers = 8; +				if (roughness_layers != 8) { +					WARN_PRINT("When using REALTIME skies, roughness_layers should be set to 8 in the project settings for best quality reflections"); +				} +			} + +			if (sky_use_cubemap_array) { +				//array (higher quality, 6 times more memory) +				RD::TextureFormat tf; +				tf.array_layers = layers * 6; +				tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; +				tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; +				tf.mipmaps = mipmaps; +				tf.width = w; +				tf.height = h; +				tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + +				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + +				sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers); + +			} else { +				//regular cubemap, lower quality (aliasing, less memory) +				RD::TextureFormat tf; +				tf.array_layers = 6; +				tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; +				tf.texture_type = RD::TEXTURE_TYPE_CUBE; +				tf.mipmaps = MIN(mipmaps, layers); +				tf.width = w; +				tf.height = h; +				tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + +				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + +				sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers); +			} +			texture_set_dirty = true; +		} + +		// Create subpass buffers if they haven't been created already +		if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) { +			RD::TextureFormat tformat; +			tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; +			tformat.width = sky->screen_size.x / 2; +			tformat.height = sky->screen_size.y / 2; +			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; +			tformat.texture_type = RD::TEXTURE_TYPE_2D; + +			sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); +			Vector<RID> texs; +			texs.push_back(sky->half_res_pass); +			sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs); +			texture_set_dirty = true; +		} + +		if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) { +			RD::TextureFormat tformat; +			tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; +			tformat.width = sky->screen_size.x / 4; +			tformat.height = sky->screen_size.y / 4; +			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; +			tformat.texture_type = RD::TEXTURE_TYPE_2D; + +			sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); +			Vector<RID> texs; +			texs.push_back(sky->quarter_res_pass); +			sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs); +			texture_set_dirty = true; +		} + +		if (texture_set_dirty) { +			for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) { +				if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) { +					RD::get_singleton()->free(sky->texture_uniform_sets[i]); +					sky->texture_uniform_sets[i] = RID(); +				} +			} +		} + +		sky->reflection.dirty = true; +		sky->processing_layer = 0; + +		Sky *next = sky->dirty_list; +		sky->dirty_list = nullptr; +		sky->dirty = false; +		sky = next; +	} + +	dirty_sky_list = nullptr; +} + +RID RendererSceneSkyRD::sky_get_material(RID p_sky) const { +	Sky *sky = get_sky(p_sky); +	ERR_FAIL_COND_V(!sky, RID()); + +	return sky->material; +} + +RID RendererSceneSkyRD::allocate_sky_rid() { +	return sky_owner.allocate_rid(); +} + +void RendererSceneSkyRD::initialize_sky_rid(RID p_rid) { +	sky_owner.initialize_rid(p_rid, Sky()); +} + +RendererSceneSkyRD::Sky *RendererSceneSkyRD::get_sky(RID p_sky) const { +	return sky_owner.getornull(p_sky); +} + +void RendererSceneSkyRD::free_sky(RID p_sky) { +	Sky *sky = get_sky(p_sky); +	ERR_FAIL_COND(!sky); + +	sky->free(storage); +	sky_owner.free(p_sky); +} + +void RendererSceneSkyRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { +	Sky *sky = get_sky(p_sky); +	ERR_FAIL_COND(!sky); + +	if (sky->set_radiance_size(p_radiance_size)) { +		invalidate_sky(sky); +	} +} + +void RendererSceneSkyRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { +	Sky *sky = get_sky(p_sky); +	ERR_FAIL_COND(!sky); + +	if (sky->set_mode(p_mode)) { +		invalidate_sky(sky); +	} +} + +void RendererSceneSkyRD::sky_set_material(RID p_sky, RID p_material) { +	Sky *sky = get_sky(p_sky); +	ERR_FAIL_COND(!sky); + +	if (sky->set_material(p_material)) { +		invalidate_sky(sky); +	} +} + +Ref<Image> RendererSceneSkyRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { +	Sky *sky = get_sky(p_sky); +	ERR_FAIL_COND_V(!sky, Ref<Image>()); + +	update_dirty_skys(); + +	return sky->bake_panorama(storage, p_energy, p_bake_irradiance ? roughness_layers : 0, p_size); +} + +RID RendererSceneSkyRD::sky_get_radiance_texture_rd(RID p_sky) const { +	Sky *sky = get_sky(p_sky); +	ERR_FAIL_COND_V(!sky, RID()); + +	return sky->radiance; +} diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h new file mode 100644 index 0000000000..73390a586b --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -0,0 +1,292 @@ +/*************************************************************************/ +/*  renderer_scene_sky_rd.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 RENDERING_SERVER_SCENE_SKY_RD_H +#define RENDERING_SERVER_SCENE_SKY_RD_H + +#include "core/templates/rid_owner.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/sky.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering/rendering_device.h" + +// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound +class RendererSceneRenderRD; + +class RendererSceneSkyRD { +private: +	RendererStorageRD *storage; + +public: +	enum SkySet { +		SKY_SET_UNIFORMS, +		SKY_SET_MATERIAL, +		SKY_SET_TEXTURES, +		SKY_SET_FOG, +		SKY_SET_MAX +	}; + +	enum SkyTextureSetVersion { +		SKY_TEXTURE_SET_BACKGROUND, +		SKY_TEXTURE_SET_HALF_RES, +		SKY_TEXTURE_SET_QUARTER_RES, +		SKY_TEXTURE_SET_CUBEMAP, +		SKY_TEXTURE_SET_CUBEMAP_HALF_RES, +		SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, +		SKY_TEXTURE_SET_MAX +	}; + +	enum SkyVersion { +		SKY_VERSION_BACKGROUND, +		SKY_VERSION_HALF_RES, +		SKY_VERSION_QUARTER_RES, +		SKY_VERSION_CUBEMAP, +		SKY_VERSION_CUBEMAP_HALF_RES, +		SKY_VERSION_CUBEMAP_QUARTER_RES, +		SKY_VERSION_MAX +	}; + +	// Skys need less info from Directional Lights than the normal shaders +	struct SkyDirectionalLightData { +		float direction[3]; +		float energy; +		float color[3]; +		float size; +		uint32_t enabled; +		uint32_t pad[3]; +	}; + +	struct SkySceneState { +		struct UBO { +			uint32_t volumetric_fog_enabled; +			float volumetric_fog_inv_length; +			float volumetric_fog_detail_spread; + +			float fog_aerial_perspective; + +			float fog_light_color[3]; +			float fog_sun_scatter; + +			uint32_t fog_enabled; +			float fog_density; + +			float z_far; +			uint32_t directional_light_count; +		}; + +		UBO ubo; + +		SkyDirectionalLightData *directional_lights; +		SkyDirectionalLightData *last_frame_directional_lights; +		uint32_t max_directional_lights; +		uint32_t last_frame_directional_light_count; +		RID directional_light_buffer; +		RID uniform_set; +		RID uniform_buffer; +		RID fog_uniform_set; +		RID default_fog_uniform_set; + +		RID fog_shader; +		RID fog_material; +		RID fog_only_texture_uniform_set; +	} sky_scene_state; + +	struct ReflectionData { +		struct Layer { +			struct Mipmap { +				RID framebuffers[6]; +				RID views[6]; +				Size2i size; +			}; +			Vector<Mipmap> mipmaps; //per-face view +			Vector<RID> views; // per-cubemap view +		}; + +		struct DownsampleLayer { +			struct Mipmap { +				RID view; +				Size2i size; +			}; +			Vector<Mipmap> mipmaps; +		}; + +		RID radiance_base_cubemap; //cubemap for first layer, first cubemap +		RID downsampled_radiance_cubemap; +		DownsampleLayer downsampled_layer; +		RID coefficient_buffer; + +		bool dirty = true; + +		Vector<Layer> layers; + +		void clear_reflection_data(); +		void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers); +		void create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays); +		void create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality); +		void update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end); +	}; + +	struct SkyShaderData : public RendererStorageRD::ShaderData { +		bool valid; +		RID version; + +		PipelineCacheRD pipelines[SKY_VERSION_MAX]; +		Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; +		Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; + +		Vector<uint32_t> ubo_offsets; +		uint32_t ubo_size; + +		String path; +		String code; +		Map<StringName, RID> default_texture_params; + +		bool uses_time; +		bool uses_position; +		bool uses_half_res; +		bool uses_quarter_res; +		bool uses_light; + +		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; +		virtual 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; +		SkyShaderData(); +		virtual ~SkyShaderData(); +	}; + +	/* Sky shader */ + +	struct SkyShader { +		SkyShaderRD shader; +		ShaderCompilerRD compiler; + +		RID default_shader; +		RID default_material; +		RID default_shader_rd; +	} sky_shader; + +	struct SkyMaterialData : public RendererStorageRD::MaterialData { +		uint64_t last_frame; +		SkyShaderData *shader_data; +		RID uniform_buffer; +		RID uniform_set; +		Vector<RID> texture_cache; +		Vector<uint8_t> ubo_data; +		bool uniform_set_updated; + +		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 ~SkyMaterialData(); +	}; + +	struct Sky { +		RID radiance; +		RID half_res_pass; +		RID half_res_framebuffer; +		RID quarter_res_pass; +		RID quarter_res_framebuffer; +		Size2i screen_size; + +		RID texture_uniform_sets[SKY_TEXTURE_SET_MAX]; +		RID uniform_set; + +		RID material; +		RID uniform_buffer; + +		int radiance_size = 256; + +		RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC; + +		ReflectionData reflection; +		bool dirty = false; +		int processing_layer = 0; +		Sky *dirty_list = nullptr; + +		//State to track when radiance cubemap needs updating +		SkyMaterialData *prev_material; +		Vector3 prev_position; +		float prev_time; + +		void free(RendererStorageRD *p_storage); + +		RID get_textures(RendererStorageRD *p_storage, SkyTextureSetVersion p_version, RID p_default_shader_rd); +		bool set_radiance_size(int p_radiance_size); +		bool set_mode(RS::SkyMode p_mode); +		bool set_material(RID p_material); +		Ref<Image> bake_panorama(RendererStorageRD *p_storage, float p_energy, int p_roughness_layers, const Size2i &p_size); +	}; + +	uint32_t sky_ggx_samples_quality; +	bool sky_use_cubemap_array; +	Sky *dirty_sky_list = nullptr; +	mutable RID_Owner<Sky, true> sky_owner; +	int roughness_layers; + +	RendererStorageRD::ShaderData *_create_sky_shader_func(); +	static RendererStorageRD::ShaderData *_create_sky_shader_funcs(); + +	RendererStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader); +	static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader); + +	RendererSceneSkyRD(); + +	void init(RendererStorageRD *p_storage); + +	void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render); +	void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time); +	void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time); + +	void invalidate_sky(Sky *p_sky); +	void update_dirty_skys(); + +	RID sky_get_material(RID p_sky) const; + +	RID allocate_sky_rid(); +	void initialize_sky_rid(RID p_rid); +	Sky *get_sky(RID p_sky) const; +	void free_sky(RID p_sky); +	void sky_set_radiance_size(RID p_sky, int p_radiance_size); +	void sky_set_mode(RID p_sky, RS::SkyMode p_mode); +	void sky_set_material(RID p_sky, RID p_material); +	Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size); + +	RID sky_get_radiance_texture_rd(RID p_sky) const; +}; + +#endif /* RENDERING_SERVER_SCENE_SKY_RD_H */ diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index cb98a71e86..df1a7d58d0 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -558,13 +558,13 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {  								return _make_token(TK_ERROR, "Invalid numeric constant");  							}  							hexa_found = true; -						} else if (GETCHAR(i) == 'e') { -							if (hexa_found || exponent_found || float_suffix_found) { +						} else if (GETCHAR(i) == 'e' && !hexa_found) { +							if (exponent_found || float_suffix_found) {  								return _make_token(TK_ERROR, "Invalid numeric constant");  							}  							exponent_found = true; -						} else if (GETCHAR(i) == 'f') { -							if (hexa_found || exponent_found) { +						} else if (GETCHAR(i) == 'f' && !hexa_found) { +							if (exponent_found) {  								return _make_token(TK_ERROR, "Invalid numeric constant");  							}  							float_suffix_found = true; @@ -5926,15 +5926,15 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun  			pos = _get_tkpos();  			tk = _get_token();  			if (tk.type != TK_SEMICOLON) { -				//all is good  				_set_error("Expected ';' after discard"); +				return ERR_PARSE_ERROR;  			}  			p_block->statements.push_back(flow);  		} else if (tk.type == TK_CF_BREAK) {  			if (!p_can_break) { -				//all is good -				_set_error("Breaking is not allowed here"); +				_set_error("'break' is not allowed outside of a loop or 'switch' statement"); +				return ERR_PARSE_ERROR;  			}  			ControlFlowNode *flow = alloc_node<ControlFlowNode>(); @@ -5943,8 +5943,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun  			pos = _get_tkpos();  			tk = _get_token();  			if (tk.type != TK_SEMICOLON) { -				//all is good  				_set_error("Expected ';' after break"); +				return ERR_PARSE_ERROR;  			}  			p_block->statements.push_back(flow); @@ -5959,8 +5959,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun  		} else if (tk.type == TK_CF_CONTINUE) {  			if (!p_can_continue) { -				//all is good -				_set_error("Continuing is not allowed here"); +				_set_error("'continue' is not allowed outside of a loop"); +				return ERR_PARSE_ERROR;  			}  			ControlFlowNode *flow = alloc_node<ControlFlowNode>(); @@ -5971,6 +5971,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun  			if (tk.type != TK_SEMICOLON) {  				//all is good  				_set_error("Expected ';' after continue"); +				return ERR_PARSE_ERROR;  			}  			p_block->statements.push_back(flow);  |