Browse Source

Merge pull request #75313 from ChibiDenDen/gles_sampler_uniform_array_fix

Fix gles texture uniform array binding
Yuri Sizov 2 years ago
parent
commit
08fcf27038

+ 11 - 4
drivers/gles3/shader_gles3.cpp

@@ -268,10 +268,17 @@ void ShaderGLES3::_get_uniform_locations(Version::Specialization &spec, Version
 		}
 		}
 	}
 	}
 	// textures
 	// textures
-	for (int i = 0; i < p_version->texture_uniforms.size(); i++) {
-		String native_uniform_name = _mkid(p_version->texture_uniforms[i]);
+	int texture_index = 0;
+	for (uint32_t i = 0; i < p_version->texture_uniforms.size(); i++) {
+		String native_uniform_name = _mkid(p_version->texture_uniforms[i].name);
 		GLint location = glGetUniformLocation(spec.id, (native_uniform_name).ascii().get_data());
 		GLint location = glGetUniformLocation(spec.id, (native_uniform_name).ascii().get_data());
-		glUniform1i(location, i + base_texture_index);
+		Vector<int32_t> texture_uniform_bindings;
+		int texture_count = p_version->texture_uniforms[i].array_size;
+		for (int j = 0; j < texture_count; j++) {
+			texture_uniform_bindings.append(texture_index + base_texture_index);
+			texture_index++;
+		}
+		glUniform1iv(location, texture_uniform_bindings.size(), texture_uniform_bindings.ptr());
 	}
 	}
 
 
 	glUseProgram(0);
 	glUseProgram(0);
@@ -674,7 +681,7 @@ void ShaderGLES3::_initialize_version(Version *p_version) {
 	_save_to_cache(p_version);
 	_save_to_cache(p_version);
 }
 }
 
 
-void ShaderGLES3::version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const Vector<StringName> &p_texture_uniforms, bool p_initialize) {
+void ShaderGLES3::version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const LocalVector<ShaderGLES3::TextureUniformData> &p_texture_uniforms, bool p_initialize) {
 	Version *version = version_owner.get_or_null(p_version);
 	Version *version = version_owner.get_or_null(p_version);
 	ERR_FAIL_COND(!version);
 	ERR_FAIL_COND(!version);
 
 

+ 8 - 2
drivers/gles3/shader_gles3.h

@@ -54,6 +54,12 @@
 #include <stdio.h>
 #include <stdio.h>
 
 
 class ShaderGLES3 {
 class ShaderGLES3 {
+public:
+	struct TextureUniformData {
+		StringName name;
+		int array_size;
+	};
+
 protected:
 protected:
 	struct TexUnitPair {
 	struct TexUnitPair {
 		const char *name;
 		const char *name;
@@ -85,7 +91,7 @@ private:
 	// Specializations use #ifdefs to toggle behavior on and off for performance, on supporting hardware, they will compile a version with everything enabled, and then compile more copies to improve performance
 	// Specializations use #ifdefs to toggle behavior on and off for performance, on supporting hardware, they will compile a version with everything enabled, and then compile more copies to improve performance
 	// Use specializations to enable and disabled advanced features, use variants to toggle behavior when different data may be used (e.g. using a samplerArray vs a sampler, or doing a depth prepass vs a color pass)
 	// Use specializations to enable and disabled advanced features, use variants to toggle behavior when different data may be used (e.g. using a samplerArray vs a sampler, or doing a depth prepass vs a color pass)
 	struct Version {
 	struct Version {
-		Vector<StringName> texture_uniforms;
+		LocalVector<TextureUniformData> texture_uniforms;
 		CharString uniforms;
 		CharString uniforms;
 		CharString vertex_globals;
 		CharString vertex_globals;
 		CharString fragment_globals;
 		CharString fragment_globals;
@@ -242,7 +248,7 @@ protected:
 public:
 public:
 	RID version_create();
 	RID version_create();
 
 
-	void version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const Vector<StringName> &p_texture_uniforms, bool p_initialize = false);
+	void version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const LocalVector<ShaderGLES3::TextureUniformData> &p_texture_uniforms, bool p_initialize = false);
 
 
 	bool version_is_valid(RID p_version);
 	bool version_is_valid(RID p_version);
 
 

+ 51 - 72
drivers/gles3/storage/material_storage.cpp

@@ -2950,6 +2950,18 @@ void MaterialStorage::material_update_dependency(RID p_material, DependencyTrack
 	}
 	}
 }
 }
 
 
+LocalVector<ShaderGLES3::TextureUniformData> get_texture_uniform_data(const Vector<ShaderCompiler::GeneratedCode::Texture> &texture_uniforms) {
+	LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data;
+	for (int i = 0; i < texture_uniforms.size(); i++) {
+		int num_textures = texture_uniforms[i].array_size;
+		if (num_textures == 0) {
+			num_textures = 1;
+		}
+		texture_uniform_data.push_back({ texture_uniforms[i].name, num_textures });
+	}
+	return texture_uniform_data;
+}
+
 /* Canvas Shader Data */
 /* Canvas Shader Data */
 
 
 void CanvasShaderData::set_code(const String &p_code) {
 void CanvasShaderData::set_code(const String &p_code) {
@@ -3017,12 +3029,9 @@ void CanvasShaderData::set_code(const String &p_code) {
 	print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
 	print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
 #endif
 #endif
 
 
-	Vector<StringName> texture_uniform_names;
-	for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
-		texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
-	}
+	LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data = get_texture_uniform_data(gen_code.texture_uniforms);
 
 
-	MaterialStorage::get_singleton()->shaders.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
+	MaterialStorage::get_singleton()->shaders.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data);
 	ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.canvas_shader.version_is_valid(version));
 	ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.canvas_shader.version_is_valid(version));
 
 
 	ubo_size = gen_code.uniform_total_size;
 	ubo_size = gen_code.uniform_total_size;
@@ -3065,23 +3074,38 @@ void CanvasMaterialData::update_parameters(const HashMap<StringName, Variant> &p
 	update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
 	update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
 }
 }
 
 
+static void bind_uniforms_generic(const Vector<RID> &p_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, int texture_offset = 0, const RS::CanvasItemTextureFilter *filter_mapping = filter_from_uniform, const RS::CanvasItemTextureRepeat *repeat_mapping = repeat_from_uniform) {
+	const RID *textures = p_textures.ptr();
+	const ShaderCompiler::GeneratedCode::Texture *texture_uniforms = p_texture_uniforms.ptr();
+	int texture_uniform_index = 0;
+	int texture_uniform_count = 0;
+	for (int ti = 0; ti < p_textures.size(); ti++) {
+		ERR_FAIL_COND_MSG(texture_uniform_index >= p_texture_uniforms.size(), "texture_uniform_index out of bounds");
+		GLES3::Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
+		const ShaderCompiler::GeneratedCode::Texture &texture_uniform = texture_uniforms[texture_uniform_index];
+		if (texture) {
+			glActiveTexture(GL_TEXTURE0 + texture_offset + ti);
+			glBindTexture(target_from_type[texture_uniform.type], texture->tex_id);
+			if (texture->render_target) {
+				texture->render_target->used_in_frame = true;
+			}
+
+			texture->gl_set_filter(filter_mapping[int(texture_uniform.filter)]);
+			texture->gl_set_repeat(repeat_mapping[int(texture_uniform.repeat)]);
+		}
+		texture_uniform_count++;
+		if (texture_uniform_count >= texture_uniform.array_size) {
+			texture_uniform_index++;
+			texture_uniform_count = 0;
+		}
+	}
+}
+
 void CanvasMaterialData::bind_uniforms() {
 void CanvasMaterialData::bind_uniforms() {
 	// Bind Material Uniforms
 	// Bind Material Uniforms
 	glBindBufferBase(GL_UNIFORM_BUFFER, RasterizerCanvasGLES3::MATERIAL_UNIFORM_LOCATION, uniform_buffer);
 	glBindBufferBase(GL_UNIFORM_BUFFER, RasterizerCanvasGLES3::MATERIAL_UNIFORM_LOCATION, uniform_buffer);
 
 
-	RID *textures = texture_cache.ptrw();
-	ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
-	for (int ti = 0; ti < texture_cache.size(); ti++) {
-		Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
-		glActiveTexture(GL_TEXTURE1 + ti); // Start at GL_TEXTURE1 because texture slot 0 is used by the base texture
-		glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
-		if (texture->render_target) {
-			texture->render_target->used_in_frame = true;
-		}
-
-		texture->gl_set_filter(filter_from_uniform_canvas[int(texture_uniforms[ti].filter)]);
-		texture->gl_set_repeat(repeat_from_uniform_canvas[int(texture_uniforms[ti].repeat)]);
-	}
+	bind_uniforms_generic(texture_cache, shader_data->texture_uniforms, 1, filter_from_uniform_canvas, repeat_from_uniform_canvas); // Start at GL_TEXTURE1 because texture slot 0 is used by the base texture
 }
 }
 
 
 CanvasMaterialData::~CanvasMaterialData() {
 CanvasMaterialData::~CanvasMaterialData() {
@@ -3172,12 +3196,9 @@ void SkyShaderData::set_code(const String &p_code) {
 	print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
 	print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
 #endif
 #endif
 
 
-	Vector<StringName> texture_uniform_names;
-	for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
-		texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
-	}
+	LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data = get_texture_uniform_data(gen_code.texture_uniforms);
 
 
-	MaterialStorage::get_singleton()->shaders.sky_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
+	MaterialStorage::get_singleton()->shaders.sky_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data);
 	ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.sky_shader.version_is_valid(version));
 	ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.sky_shader.version_is_valid(version));
 
 
 	ubo_size = gen_code.uniform_total_size;
 	ubo_size = gen_code.uniform_total_size;
@@ -3235,19 +3256,7 @@ void SkyMaterialData::bind_uniforms() {
 	// Bind Material Uniforms
 	// Bind Material Uniforms
 	glBindBufferBase(GL_UNIFORM_BUFFER, SKY_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
 	glBindBufferBase(GL_UNIFORM_BUFFER, SKY_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
 
 
-	RID *textures = texture_cache.ptrw();
-	ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
-	for (int ti = 0; ti < texture_cache.size(); ti++) {
-		Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
-		glActiveTexture(GL_TEXTURE0 + ti);
-		glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
-		if (texture->render_target) {
-			texture->render_target->used_in_frame = true;
-		}
-
-		texture->gl_set_filter(filter_from_uniform[int(texture_uniforms[ti].filter)]);
-		texture->gl_set_repeat(repeat_from_uniform[int(texture_uniforms[ti].repeat)]);
-	}
+	bind_uniforms_generic(texture_cache, shader_data->texture_uniforms);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
@@ -3435,12 +3444,9 @@ void SceneShaderData::set_code(const String &p_code) {
 	print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
 	print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
 #endif
 #endif
 
 
-	Vector<StringName> texture_uniform_names;
-	for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
-		texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
-	}
+	LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data = get_texture_uniform_data(gen_code.texture_uniforms);
 
 
-	MaterialStorage::get_singleton()->shaders.scene_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
+	MaterialStorage::get_singleton()->shaders.scene_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data);
 	ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.scene_shader.version_is_valid(version));
 	ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.scene_shader.version_is_valid(version));
 
 
 	ubo_size = gen_code.uniform_total_size;
 	ubo_size = gen_code.uniform_total_size;
@@ -3517,19 +3523,7 @@ void SceneMaterialData::bind_uniforms() {
 	// Bind Material Uniforms
 	// Bind Material Uniforms
 	glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
 	glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
 
 
-	RID *textures = texture_cache.ptrw();
-	ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
-	for (int ti = 0; ti < texture_cache.size(); ti++) {
-		Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
-		glActiveTexture(GL_TEXTURE0 + ti);
-		glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
-		if (texture->render_target) {
-			texture->render_target->used_in_frame = true;
-		}
-
-		texture->gl_set_filter(filter_from_uniform[int(texture_uniforms[ti].filter)]);
-		texture->gl_set_repeat(repeat_from_uniform[int(texture_uniforms[ti].repeat)]);
-	}
+	bind_uniforms_generic(texture_cache, shader_data->texture_uniforms);
 }
 }
 
 
 /* Particles SHADER */
 /* Particles SHADER */
@@ -3575,12 +3569,9 @@ void ParticlesShaderData::set_code(const String &p_code) {
 		}
 		}
 	}
 	}
 
 
-	Vector<StringName> texture_uniform_names;
-	for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
-		texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
-	}
+	LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data = get_texture_uniform_data(gen_code.texture_uniforms);
 
 
-	MaterialStorage::get_singleton()->shaders.particles_process_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
+	MaterialStorage::get_singleton()->shaders.particles_process_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data);
 	ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.particles_process_shader.version_is_valid(version));
 	ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.particles_process_shader.version_is_valid(version));
 
 
 	ubo_size = gen_code.uniform_total_size;
 	ubo_size = gen_code.uniform_total_size;
@@ -3631,19 +3622,7 @@ void ParticleProcessMaterialData::bind_uniforms() {
 	// Bind Material Uniforms
 	// Bind Material Uniforms
 	glBindBufferBase(GL_UNIFORM_BUFFER, GLES3::PARTICLES_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
 	glBindBufferBase(GL_UNIFORM_BUFFER, GLES3::PARTICLES_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
 
 
-	RID *textures = texture_cache.ptrw();
-	ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
-	for (int ti = 0; ti < texture_cache.size(); ti++) {
-		Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
-		glActiveTexture(GL_TEXTURE1 + ti); // Start at GL_TEXTURE1 because texture slot 0 is reserved for the heightmap texture.
-		glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
-		if (texture->render_target) {
-			texture->render_target->used_in_frame = true;
-		}
-
-		texture->gl_set_filter(filter_from_uniform[int(texture_uniforms[ti].filter)]);
-		texture->gl_set_repeat(repeat_from_uniform[int(texture_uniforms[ti].repeat)]);
-	}
+	bind_uniforms_generic(texture_cache, shader_data->texture_uniforms, 1); // Start at GL_TEXTURE1 because texture slot 0 is reserved for the heightmap texture.
 }
 }
 
 
 #endif // !GLES3_ENABLED
 #endif // !GLES3_ENABLED