compositor: q&d solution for surface drift
When a transformed (rotated) surface is continuously resized from its
top-left corner, its location will drift. This is due to accumulating
rounding errors in transforming an offset from surface-local to global
coordinates in surface_attach().
Diminish the drift down to unobservable level by changing the
weston_surface global position from integer to float.
The offset transformation is now done without rounding. To preserve the
precision, wl_shell::configure() interface must use floats, and so does
weston_surface_configure(), too.
The con of this patch is that it adds inconsistency to the surface
position coordinates: sometimes they are floats, sometimes integers.
diff --git a/src/compositor.c b/src/compositor.c
index 6b15a54..bd5d2e7 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -311,12 +311,10 @@
&surface->transform.boundingbox);
}
-WL_EXPORT void
-weston_surface_to_global(struct weston_surface *surface,
- int32_t sx, int32_t sy, int32_t *x, int32_t *y)
+static void
+surface_to_global_float(struct weston_surface *surface,
+ int32_t sx, int32_t sy, GLfloat *x, GLfloat *y)
{
- weston_surface_update_transform(surface);
-
if (surface->transform.enabled) {
struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
@@ -331,14 +329,27 @@
return;
}
- *x = floorf(v.f[0] / v.f[3]);
- *y = floorf(v.f[1] / v.f[3]);
+ *x = v.f[0] / v.f[3];
+ *y = v.f[1] / v.f[3];
} else {
*x = sx + surface->geometry.x;
*y = sy + surface->geometry.y;
}
}
+WL_EXPORT void
+weston_surface_to_global(struct weston_surface *surface,
+ int32_t sx, int32_t sy, int32_t *x, int32_t *y)
+{
+ GLfloat xf, yf;
+
+ weston_surface_update_transform(surface);
+
+ surface_to_global_float(surface, sx, sy, &xf, &yf);
+ *x = floorf(xf);
+ *y = floorf(yf);
+}
+
static void
surface_from_global_float(struct weston_surface *surface,
int32_t x, int32_t y, GLfloat *sx, GLfloat *sy)
@@ -449,7 +460,7 @@
WL_EXPORT void
weston_surface_configure(struct weston_surface *surface,
- int x, int y, int width, int height)
+ GLfloat x, GLfloat y, int width, int height)
{
weston_surface_damage_below(surface);
@@ -1100,12 +1111,11 @@
} else if (sx != 0 || sy != 0 ||
es->geometry.width != buffer->width ||
es->geometry.height != buffer->height) {
- int32_t from_x, from_y;
- int32_t to_x, to_y;
+ GLfloat from_x, from_y;
+ GLfloat to_x, to_y;
- /* FIXME: this has serious cumulating rounding errors */
- weston_surface_to_global(es, 0, 0, &from_x, &from_y);
- weston_surface_to_global(es, sx, sy, &to_x, &to_y);
+ surface_to_global_float(es, 0, 0, &from_x, &from_y);
+ surface_to_global_float(es, sx, sy, &to_x, &to_y);
shell->configure(shell, es,
es->geometry.x + to_x - from_x,
es->geometry.y + to_y - from_y,