Browse Source

Fix transforms in custom shaders using large FVF

In small batches using hardware transform, vertices would be drawn in incorrect positions due to the item transform being applied twice - once in the transform uniform, and once from the transform passed as a vertex attribute.

This PR alters the shader to ignore uniform transforms when using large FVF.
lawnjelly 4 years ago
parent
commit
f4cb88e232

+ 3 - 1
drivers/gles2/rasterizer_canvas_gles2.cpp

@@ -2176,7 +2176,9 @@ void RasterizerCanvasGLES2::render_joined_item(const BItemJoined &p_bij, RenderI
 		}
 		}
 	}
 	}
 
 
-	// using software transform
+	// using software transform?
+	// (i.e. don't send the transform matrix, send identity, and either use baked verts,
+	// or large fvf where the transform is done in the shader from transform stored in the fvf.)
 	if (!p_bij.use_hardware_transform()) {
 	if (!p_bij.use_hardware_transform()) {
 		state.uniforms.modelview_matrix = Transform2D();
 		state.uniforms.modelview_matrix = Transform2D();
 		// final_modulate will be baked per item ref so the final_modulate can be an identity color
 		// final_modulate will be baked per item ref so the final_modulate can be an identity color

+ 4 - 1
drivers/gles2/shaders/canvas.glsl

@@ -203,13 +203,16 @@ VERTEX_SHADER_CODE
 	temp += translate_attrib;
 	temp += translate_attrib;
 	outvec.xy = temp;
 	outvec.xy = temp;
 
 
-#endif
+#else
 
 
+	// transform is in uniforms
 #if !defined(SKIP_TRANSFORM_USED)
 #if !defined(SKIP_TRANSFORM_USED)
 	outvec = extra_matrix_instance * outvec;
 	outvec = extra_matrix_instance * outvec;
 	outvec = modelview_matrix * outvec;
 	outvec = modelview_matrix * outvec;
 #endif
 #endif
 
 
+#endif // not large integer
+
 	color_interp = color;
 	color_interp = color;
 
 
 #ifdef USE_PIXEL_SNAP
 #ifdef USE_PIXEL_SNAP

+ 3 - 1
drivers/gles3/rasterizer_canvas_gles3.cpp

@@ -1439,7 +1439,9 @@ void RasterizerCanvasGLES3::render_joined_item(const BItemJoined &p_bij, RenderI
 	//	state.final_transform = p_ci->final_transform;
 	//	state.final_transform = p_ci->final_transform;
 	//	state.extra_matrix = Transform2D();
 	//	state.extra_matrix = Transform2D();
 
 
-	// using software transform
+	// using software transform?
+	// (i.e. don't send the transform matrix, send identity, and either use baked verts,
+	// or large fvf where the transform is done in the shader from transform stored in the fvf.)
 	if (!p_bij.use_hardware_transform()) {
 	if (!p_bij.use_hardware_transform()) {
 		state.final_transform = Transform2D();
 		state.final_transform = Transform2D();
 		// final_modulate will be baked per item ref so the final_modulate can be an identity color
 		// final_modulate will be baked per item ref so the final_modulate can be an identity color

+ 5 - 1
drivers/gles3/shaders/canvas.glsl

@@ -208,13 +208,17 @@ VERTEX_SHADER_CODE
 
 
 	temp += translate_attrib;
 	temp += translate_attrib;
 	outvec.xy = temp;
 	outvec.xy = temp;
-#endif
 
 
+#else
+
+	// transform is in uniforms
 #if !defined(SKIP_TRANSFORM_USED)
 #if !defined(SKIP_TRANSFORM_USED)
 	outvec = extra_matrix * outvec;
 	outvec = extra_matrix * outvec;
 	outvec = modelview_matrix * outvec;
 	outvec = modelview_matrix * outvec;
 #endif
 #endif
 
 
+#endif // not large integer
+
 #undef extra_matrix
 #undef extra_matrix
 
 
 	color_interp = color;
 	color_interp = color;

+ 5 - 0
drivers/gles_common/rasterizer_canvas_batcher.h

@@ -2068,6 +2068,11 @@ PREAMBLE(bool)::prefill_joined_item(FillState &r_fill_state, int &r_command_star
 				// break this extra matrix software path (as we don't want to unset it on the GPU etc)
 				// break this extra matrix software path (as we don't want to unset it on the GPU etc)
 				if (r_fill_state.extra_matrix_sent) {
 				if (r_fill_state.extra_matrix_sent) {
 					_prefill_default_batch(r_fill_state, command_num, *p_item);
 					_prefill_default_batch(r_fill_state, command_num, *p_item);
+
+					// keep track of the combined matrix on the CPU in parallel, in case we use large vertex format
+					RasterizerCanvas::Item::CommandTransform *transform = static_cast<RasterizerCanvas::Item::CommandTransform *>(command);
+					const Transform2D &extra_matrix = transform->xform;
+					r_fill_state.transform_combined = p_item->final_transform * extra_matrix;
 				} else {
 				} else {
 					// Extra matrix fast path.
 					// Extra matrix fast path.
 					// Instead of sending the command immediately, we store the modified transform (in combined)
 					// Instead of sending the command immediately, we store the modified transform (in combined)