Kaynağa Gözat

Merge pull request #38669 from lawnjelly/kessel_vertex_read

GLES2 Batching - Fix custom shaders reading VERTEX
Rémi Verschelde 5 yıl önce
ebeveyn
işleme
4b91111acb

+ 13 - 8
drivers/gles2/rasterizer_canvas_gles2.cpp

@@ -60,7 +60,7 @@ RasterizerCanvasGLES2::BatchData::BatchData() {
 	settings_colored_vertex_format_threshold = 0.0f;
 	settings_batch_buffer_num_verts = 0;
 	scissor_threshold_area = 0.0f;
-	prevent_color_baking = false;
+	joined_item_batch_flags = 0;
 	diagnose_frame = false;
 	next_diagnose_tick = 10000;
 	diagnose_frame_number = 9999999999; // some high number
@@ -1629,6 +1629,12 @@ void RasterizerCanvasGLES2::render_joined_item_commands(const BItemJoined &p_bij
 	fill_state.use_hardware_transform = p_bij.use_hardware_transform();
 	fill_state.extra_matrix_sent = false;
 
+	// in the special case of custom shaders that read from VERTEX (i.e. vertex position)
+	// we want to disable software transform of extra matrix
+	if (bdata.joined_item_batch_flags & RasterizerStorageGLES2::Shader::CanvasItem::PREVENT_VERTEX_BAKING) {
+		fill_state.extra_matrix_sent = true;
+	}
+
 	for (unsigned int i = 0; i < p_bij.num_item_refs; i++) {
 		const BItemRef &ref = bdata.item_refs[p_bij.first_item_ref + i];
 		item = ref.item;
@@ -1688,7 +1694,7 @@ void RasterizerCanvasGLES2::flush_render_batches(Item *p_first_item, Item *p_cur
 	// only check whether to convert if there are quads (prevent divide by zero)
 	// and we haven't decided to prevent color baking (due to e.g. MODULATE
 	// being used in a shader)
-	if (bdata.total_quads && !bdata.prevent_color_baking) {
+	if (bdata.total_quads && !(bdata.joined_item_batch_flags & RasterizerStorageGLES2::Shader::CanvasItem::PREVENT_COLOR_BAKING)) {
 		// minus 1 to prevent single primitives (ratio 1.0) always being converted to colored..
 		// in that case it is slightly cheaper to just have the color as part of the batch
 		float ratio = (float)(bdata.total_color_changes - 1) / (float)bdata.total_quads;
@@ -2267,7 +2273,8 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo
 
 	// does the shader contain BUILTINs which should break the batching?
 	if (r_ris.shader_cache && !unshaded) {
-		if (r_ris.shader_cache->canvas_item.prevent_color_baking) {
+		const unsigned int test_flags = RasterizerStorageGLES2::Shader::CanvasItem::PREVENT_COLOR_BAKING | RasterizerStorageGLES2::Shader::CanvasItem::PREVENT_VERTEX_BAKING;
+		if (r_ris.shader_cache->canvas_item.batch_flags & test_flags) {
 			// we will do this same test on the shader during the rendering pass in order to set a bool not to bake vertex colors
 			// instead of saving this info as it is cheap to calculate
 			join = false;
@@ -2997,12 +3004,10 @@ void RasterizerCanvasGLES2::render_joined_item(const BItemJoined &p_bij, RenderI
 	bool unshaded = r_ris.shader_cache && (r_ris.shader_cache->canvas_item.light_mode == RasterizerStorageGLES2::Shader::CanvasItem::LIGHT_MODE_UNSHADED || (blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX && blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA));
 	bool reclip = false;
 
-	// does the shader contain BUILTINs which break the batching and should prevent color baking?
-	bdata.prevent_color_baking = false;
+	// does the shader contain BUILTINs which break the batching and should prevent color baking or vertex baking?
+	bdata.joined_item_batch_flags = 0;
 	if (r_ris.shader_cache && !unshaded) {
-		if (r_ris.shader_cache->canvas_item.prevent_color_baking) {
-			bdata.prevent_color_baking = true;
-		}
+		bdata.joined_item_batch_flags = r_ris.shader_cache->canvas_item.batch_flags;
 	}
 
 	if (r_ris.last_blend_mode != blend_mode) {

+ 6 - 3
drivers/gles2/rasterizer_canvas_gles2.h

@@ -200,9 +200,12 @@ class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 {
 		// to alternate batching method and add color to the vertex format.
 		int total_color_changes;
 
-		// if the shader is using MODULATE, we prevent baking so the final_modulate can
-		// be read in the shader
-		bool prevent_color_baking;
+		// if the shader is using MODULATE, we prevent baking color so the final_modulate can
+		// be read in the shader.
+		// if the shader is reading VERTEX, we prevent baking vertex positions with extra matrices etc
+		// to prevent the read position being incorrect.
+		// These flags are defined in RasterizerStorageGLES2::Shader::CanvasItem::BatchFlags
+		unsigned int joined_item_batch_flags;
 
 		// measured in pixels, recalculated each frame
 		float scissor_threshold_area;

+ 9 - 2
drivers/gles2/rasterizer_storage_gles2.cpp

@@ -1426,7 +1426,8 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
 			p_shader->canvas_item.uses_time = false;
 			p_shader->canvas_item.uses_modulate = false;
 			p_shader->canvas_item.reads_color = false;
-			p_shader->canvas_item.prevent_color_baking = false;
+			p_shader->canvas_item.reads_vertex = false;
+			p_shader->canvas_item.batch_flags = 0;
 
 			shaders.actions_canvas.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD);
 			shaders.actions_canvas.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX);
@@ -1444,6 +1445,7 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
 			shaders.actions_canvas.usage_flag_pointers["MODULATE"] = &p_shader->canvas_item.uses_modulate;
 
 			shaders.actions_canvas.read_flag_pointers["COLOR"] = &p_shader->canvas_item.reads_color;
+			shaders.actions_canvas.read_flag_pointers["VERTEX"] = &p_shader->canvas_item.reads_vertex;
 
 			actions = &shaders.actions_canvas;
 			actions->uniforms = &p_shader->uniforms;
@@ -1533,7 +1535,12 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
 
 	// some logic for batching
 	if (p_shader->mode == VS::SHADER_CANVAS_ITEM) {
-		p_shader->canvas_item.prevent_color_baking = p_shader->canvas_item.uses_modulate | p_shader->canvas_item.reads_color;
+		if (p_shader->canvas_item.uses_modulate | p_shader->canvas_item.reads_color) {
+			p_shader->canvas_item.batch_flags |= Shader::CanvasItem::PREVENT_COLOR_BAKING;
+		}
+		if (p_shader->canvas_item.reads_vertex) {
+			p_shader->canvas_item.batch_flags |= Shader::CanvasItem::PREVENT_VERTEX_BAKING;
+		}
 	}
 
 	p_shader->shader->set_custom_shader(p_shader->custom_code_id);

+ 10 - 5
drivers/gles2/rasterizer_storage_gles2.h

@@ -447,16 +447,21 @@ public:
 
 			int light_mode;
 
+			enum BatchFlags {
+				PREVENT_COLOR_BAKING = 1 << 0,
+				PREVENT_VERTEX_BAKING = 1 << 1,
+			};
+			// these flags are specifically for batching
+			// some of the logic is thus in rasterizer_storage.cpp
+			// we could alternatively set bitflags for each 'uses' and test on the fly
+			unsigned int batch_flags;
+
 			bool uses_screen_texture;
 			bool uses_screen_uv;
 			bool uses_time;
 			bool uses_modulate;
 			bool reads_color;
-
-			// this flag is specifically for batching
-			// some of the logic is thus in rasterizer_storage.cpp
-			// we could alternatively set some bitflags here and test on the fly
-			bool prevent_color_baking;
+			bool reads_vertex;
 
 		} canvas_item;