浏览代码

Merge pull request #38694 from lawnjelly/kessel_builtins

GLES2 Batching - Prevent baking colors with COLOR writes
Rémi Verschelde 5 年之前
父节点
当前提交
b7ce9ad1bf

+ 30 - 18
drivers/gles2/rasterizer_canvas_gles2.cpp

@@ -1908,6 +1908,7 @@ void RasterizerCanvasGLES2::join_sorted_items() {
 			_render_item_state.joined_item->num_item_refs = 1;
 			_render_item_state.joined_item->bounding_rect = ci->global_rect_cache;
 			_render_item_state.joined_item->z_index = z;
+			_render_item_state.joined_item->flags = bdata.joined_item_batch_flags;
 
 			// add the reference
 			BItemRef *r = bdata.item_refs.request_with_grow();
@@ -2184,7 +2185,8 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo
 	}
 
 	// if there are any state changes we change join to false
-	// we also set r_batch_break to true if we don't want this item joined
+	// we also set r_batch_break to true if we don't want this item joined to the next
+	// (e.g. an item that must not be joined at all)
 	r_batch_break = false;
 	bool join = true;
 
@@ -2271,17 +2273,6 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo
 	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 should break the batching?
-	if (r_ris.shader_cache && !unshaded) {
-		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;
-			r_batch_break = true;
-		}
-	}
-
 	// we are precalculating the final_modulate ahead of time because we need this for baking of final modulate into vertex colors
 	// (only in software transform mode)
 	// This maybe inefficient storing it...
@@ -2292,6 +2283,33 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo
 		r_ris.last_blend_mode = blend_mode;
 	}
 
+	// does the shader contain BUILTINs which should break the batching?
+	bdata.joined_item_batch_flags = 0;
+	if (r_ris.shader_cache && !unshaded) {
+
+		unsigned int and_flags = r_ris.shader_cache->canvas_item.batch_flags & (RasterizerStorageGLES2::Shader::CanvasItem::PREVENT_COLOR_BAKING | RasterizerStorageGLES2::Shader::CanvasItem::PREVENT_VERTEX_BAKING);
+		if (and_flags) {
+
+			bool break_batching = true;
+
+			if (and_flags == RasterizerStorageGLES2::Shader::CanvasItem::PREVENT_COLOR_BAKING) {
+				// in some circumstances, if the modulate is identity, we still allow baking because reading modulate / color
+				// will still be okay to do in the shader with no ill effects
+				if (r_ris.final_modulate == Color(1, 1, 1, 1)) {
+					break_batching = false;
+				}
+			}
+
+			if (break_batching) {
+				join = false;
+				r_batch_break = true;
+
+				// save the flags so that they don't need to be recalculated in the 2nd pass
+				bdata.joined_item_batch_flags |= r_ris.shader_cache->canvas_item.batch_flags;
+			}
+		}
+	}
+
 	if ((blend_mode == RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX || blend_mode == RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA) && r_ris.item_group_light && !unshaded) {
 
 		// we cannot join lit items easily.
@@ -3004,12 +3022,6 @@ 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 or vertex baking?
-	bdata.joined_item_batch_flags = 0;
-	if (r_ris.shader_cache && !unshaded) {
-		bdata.joined_item_batch_flags = r_ris.shader_cache->canvas_item.batch_flags;
-	}
-
 	if (r_ris.last_blend_mode != blend_mode) {
 
 		switch (blend_mode) {

+ 5 - 2
drivers/gles2/rasterizer_canvas_gles2.h

@@ -135,7 +135,10 @@ class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 {
 
 		// note the z_index  may only be correct for the first of the joined item references
 		// this has implications for light culling with z ranged lights.
-		int z_index;
+		int16_t z_index;
+
+		// these are defined in RasterizerStorageGLES2::Shader::CanvasItem::BatchFlags
+		uint16_t flags;
 
 		// we are always splitting items with lots of commands,
 		// and items with unhandled primitives (default)
@@ -205,7 +208,7 @@ class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 {
 		// 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;
+		uint32_t joined_item_batch_flags;
 
 		// measured in pixels, recalculated each frame
 		float scissor_threshold_area;

+ 3 - 3
drivers/gles2/rasterizer_storage_gles2.cpp

@@ -1425,7 +1425,7 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
 			p_shader->canvas_item.uses_screen_uv = false;
 			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.uses_color = false;
 			p_shader->canvas_item.reads_vertex = false;
 			p_shader->canvas_item.batch_flags = 0;
 
@@ -1443,8 +1443,8 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
 			shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture;
 			shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time;
 			shaders.actions_canvas.usage_flag_pointers["MODULATE"] = &p_shader->canvas_item.uses_modulate;
+			shaders.actions_canvas.usage_flag_pointers["COLOR"] = &p_shader->canvas_item.uses_color;
 
-			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;
@@ -1535,7 +1535,7 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
 
 	// some logic for batching
 	if (p_shader->mode == VS::SHADER_CANVAS_ITEM) {
-		if (p_shader->canvas_item.uses_modulate | p_shader->canvas_item.reads_color) {
+		if (p_shader->canvas_item.uses_modulate | p_shader->canvas_item.uses_color) {
 			p_shader->canvas_item.batch_flags |= Shader::CanvasItem::PREVENT_COLOR_BAKING;
 		}
 		if (p_shader->canvas_item.reads_vertex) {

+ 4 - 4
drivers/gles2/rasterizer_storage_gles2.h

@@ -447,20 +447,20 @@ public:
 
 			int light_mode;
 
+			// 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
 			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;
+			bool uses_color;
 			bool reads_vertex;
 
 		} canvas_item;