Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting shader parameter to const array causes error when material is freed #97343

Open
Stovehead opened this issue Sep 22, 2024 · 1 comment

Comments

@Stovehead
Copy link

Tested versions

  • Reproducible in: v4.3.stable.steam [77dcf97], v4.4.dev2.official [97ef3c8], v4.0.stable.official [92bee43]
  • Not reproducible in: v2.1.stable.official, v3.0.stable.official, v3.5.1.stable.official [6fed1ff]

System information

Godot v4.3.stable (77dcf97) - Windows 10.0.22631 - Vulkan (Mobile) - integrated Intel(R) Iris(R) Xe Graphics (Intel Corporation; 31.0.101.5186) - 13th Gen Intel(R) Core(TM) i7-1360P (16 Threads)

Issue description

If a shader parameter on a material is set to an array that is declared as const, the engine erroneously attempts to clear the array when the material is freed. This results in an error in the debugger tab, "clear: Array is in read-only state". In the MRP, I achieved this with the following code:

const TEST_CONST = []

func _ready() -> void:
	var new_node = Node2D.new()
	new_node.material = ShaderMaterial.new()
	new_node.material.set_shader_parameter("test", TEST_CONST)
	new_node.queue_free()

Steps to reproduce

Run the minimal reproduction project and check the debugger tab.

Minimal reproduction project (MRP)

clearbug.zip

@Stovehead
Copy link
Author

The issue seems to come from this code in material_storage.cpp:

void MaterialStorage::material_free(RID p_rid) {
	Material *material = material_owner.get_or_null(p_rid);
	ERR_FAIL_NULL(material);

	// Need to clear texture arrays to prevent spin locking of their RID's.
	// This happens when the app is being closed.
	for (KeyValue<StringName, Variant> &E : material->params) {
		if (E.value.get_type() == Variant::ARRAY) {
			Array(E.value).clear();
		}
	}

	material_set_shader(p_rid, RID()); //clean up shader
	material->dependency.deleted_notify(p_rid);

	material_owner.free(p_rid);
}

Adding a check for the array being read-only seems to do the trick.

void MaterialStorage::material_free(RID p_rid) {
	Material *material = material_owner.get_or_null(p_rid);
	ERR_FAIL_NULL(material);

	// Need to clear texture arrays to prevent spin locking of their RID's.
	// This happens when the app is being closed.
	for (KeyValue<StringName, Variant> &E : material->params) {
		if (E.value.get_type() == Variant::ARRAY && !Array(E.value).is_read_only()) {
			Array(E.value).clear();
		}
	}

	material_set_shader(p_rid, RID()); //clean up shader
	material->dependency.deleted_notify(p_rid);

	material_owner.free(p_rid);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants