[gnome-desktop/randr-transformations: 1/2] RANDR - Add API for projective transformations
- From: Federico Mena Quintero <federico src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-desktop/randr-transformations: 1/2] RANDR - Add API for projective transformations
- Date: Tue, 26 Jan 2010 21:29:28 +0000 (UTC)
commit 26e42397e5d16b15b82e96595e4d70d972b37b6b
Author: David Reveman <dreveman novell com>
Date: Tue Jan 26 15:10:20 2010 -0600
RANDR - Add API for projective transformations
Signed-off-by: Federico Mena Quintero <federico novell com>
libgnome-desktop/gnome-rr-config.c | 148 ++++++++++-----
libgnome-desktop/gnome-rr.c | 251 ++++++++++++++++++++++++-
libgnome-desktop/libgnomeui/gnome-rr-config.h | 1 +
libgnome-desktop/libgnomeui/gnome-rr.h | 19 ++
4 files changed, 363 insertions(+), 56 deletions(-)
---
diff --git a/libgnome-desktop/gnome-rr-config.c b/libgnome-desktop/gnome-rr-config.c
index 6a8f8ae..19705bf 100644
--- a/libgnome-desktop/gnome-rr-config.c
+++ b/libgnome-desktop/gnome-rr-config.c
@@ -98,6 +98,19 @@ struct Parser
GQueue * stack;
};
+static void
+init_transform (GnomeRRTransform *transform)
+{
+ int i, j;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ if (i == j)
+ transform->transform[i][j] = 1.0;
+ else
+ transform->transform[i][j] = 0.0;
+}
+
static int
parse_int (const char *text)
{
@@ -168,6 +181,7 @@ handle_start_element (GMarkupParseContext *context,
parser->output = g_new0 (GnomeOutputInfo, 1);
parser->output->rotation = 0;
+ init_transform (&parser->output->transform);
for (i = 0; attr_names[i] != NULL; ++i)
{
@@ -352,6 +366,30 @@ handle_text (GMarkupParseContext *context,
parser->output->primary = TRUE;
}
}
+ else if (stack_is (parser, "transform", "output", "configuration", TOPLEVEL_ELEMENT, NULL))
+ {
+ float transform[3][3];
+
+ if (sscanf (text,
+ "[%f,%f,%f,%f,%f,%f,%f,%f,%f]",
+ &transform[0][0],
+ &transform[0][1],
+ &transform[0][2],
+ &transform[1][0],
+ &transform[1][1],
+ &transform[1][2],
+ &transform[2][0],
+ &transform[2][1],
+ &transform[2][2]) == 9)
+ {
+ int i, j;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ parser->output->transform.transform[i][j] =
+ transform[i][j];
+ }
+ }
else
{
/* Ignore other properties so we can expand the format in the future */
@@ -472,6 +510,7 @@ gnome_rr_config_new_current (GnomeRRScreen *screen)
output->height = -1;
output->rate = -1;
output->rotation = GNOME_RR_ROTATION_0;
+ init_transform (&output->transform);
}
else
{
@@ -513,6 +552,7 @@ gnome_rr_config_new_current (GnomeRRScreen *screen)
output->height = gnome_rr_mode_get_height (mode);
output->rate = gnome_rr_mode_get_freq (mode);
output->rotation = gnome_rr_crtc_get_current_rotation (crtc);
+ gnome_rr_crtc_get_current_transform (crtc, &output->transform);
if (output->x == 0 && output->y == 0) {
if (clone_width == -1) {
@@ -762,6 +802,10 @@ output_equal (GnomeOutputInfo *output1, GnomeOutputInfo *output2)
if (output1->rotation != output2->rotation)
return FALSE;
+
+ if (memcmp (&output1->transform, &output2->transform,
+ sizeof (GnomeRRTransform)) != 0)
+ return FALSE;
}
return TRUE;
@@ -852,6 +896,7 @@ make_outputs (GnomeRRConfig *config)
new->width = first_on->width;
new->height = first_on->height;
new->rotation = first_on->rotation;
+ new->transform = first_on->transform;
new->x = 0;
new->y = 0;
}
@@ -997,6 +1042,11 @@ emit_configuration (GnomeRRConfig *config,
string, " <reflect_y>%s</reflect_y>\n", get_reflect_y (output->rotation));
g_string_append_printf (
string, " <primary>%s</primary>\n", yes_no (output->primary));
+ g_string_append_printf (
+ string, " <transform>[%f,%f,%f,%f,%f,%f,%f,%f,%f]</transform>\n",
+ output->transform.transform[0][0], output->transform.transform[0][1], output->transform.transform[0][2],
+ output->transform.transform[1][0], output->transform.transform[1][1], output->transform.transform[1][2],
+ output->transform.transform[2][0], output->transform.transform[2][1], output->transform.transform[2][2]);
}
g_string_append_printf (string, " </output>\n");
@@ -1369,6 +1419,7 @@ struct CrtcInfo
int x;
int y;
GnomeRRRotation rotation;
+ GnomeRRTransform transform;
GPtrArray *outputs;
};
@@ -1404,13 +1455,15 @@ crtc_assignment_assign (CrtcAssignment *assign,
int y,
GnomeRRRotation rotation,
gboolean primary,
+ GnomeRRTransform *transform,
GnomeRROutput *output)
{
CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
if (!gnome_rr_crtc_can_drive_output (crtc, output) ||
!gnome_rr_output_supports_mode (output, mode) ||
- !gnome_rr_crtc_supports_rotation (crtc, rotation))
+ !gnome_rr_crtc_supports_rotation (crtc, rotation) ||
+ !gnome_rr_crtc_supports_transform (crtc, transform))
{
return FALSE;
}
@@ -1421,6 +1474,9 @@ crtc_assignment_assign (CrtcAssignment *assign,
info->x == x &&
info->y == y &&
info->rotation == rotation &&
+ memcmp (&info->transform,
+ transform,
+ sizeof (GnomeRRTransform)) == 0 &&
can_clone (info, output))
{
g_ptr_array_add (info->outputs, output);
@@ -1441,6 +1497,7 @@ crtc_assignment_assign (CrtcAssignment *assign,
info->x = x;
info->y = y;
info->rotation = rotation;
+ info->transform = *transform;
info->outputs = g_ptr_array_new ();
g_ptr_array_add (info->outputs, output);
@@ -1505,6 +1562,15 @@ configure_crtc (gpointer key,
if (state->has_error)
return;
+ if (gnome_rr_crtc_supports_transform (crtc, &info->transform))
+ {
+ if (!gnome_rr_crtc_set_transform (crtc, &info->transform))
+ {
+ state->has_error = TRUE;
+ return;
+ }
+ }
+
if (!gnome_rr_crtc_set_config_with_time (crtc,
state->timestamp,
info->x, info->y,
@@ -1516,31 +1582,6 @@ configure_crtc (gpointer key,
state->has_error = TRUE;
}
-static gboolean
-mode_is_rotated (CrtcInfo *info)
-{
- if ((info->rotation & GNOME_RR_ROTATION_270) ||
- (info->rotation & GNOME_RR_ROTATION_90))
- {
- return TRUE;
- }
- return FALSE;
-}
-
-static gboolean
-crtc_is_rotated (GnomeRRCrtc *crtc)
-{
- GnomeRRRotation r = gnome_rr_crtc_get_current_rotation (crtc);
-
- if ((r & GNOME_RR_ROTATION_270) ||
- (r & GNOME_RR_ROTATION_90))
- {
- return TRUE;
- }
-
- return FALSE;
-}
-
/* Check whether the given set of settings can be used
* at the same time -- ie. whether there is an assignment
* of CRTC's to outputs.
@@ -1595,6 +1636,7 @@ real_assign_crtcs (GnomeRRScreen *screen,
output->x, output->y,
output->rotation,
output->primary,
+ &output->transform,
gnome_rr_output))
{
if (real_assign_crtcs (screen, outputs + 1, assignment))
@@ -1635,20 +1677,21 @@ get_required_virtual_size (CrtcAssignment *assign, int *width, int *height)
{
GnomeRRCrtc *crtc = list->data;
CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
- int w, h;
+ int x, y, w, h;
+ int x1, y1, x2, y2;
- w = gnome_rr_mode_get_width (info->mode);
- h = gnome_rr_mode_get_height (info->mode);
-
- if (mode_is_rotated (info))
- {
- int tmp = h;
- h = w;
- w = tmp;
- }
-
- *width = MAX (*width, info->x + w);
- *height = MAX (*height, info->y + h);
+ gnome_rr_mode_get_geometry (info->mode,
+ info->rotation,
+ &info->transform,
+ &x1, &y1, &x2, &y2);
+
+ x = info->x + x1;
+ y = info->y + y1;
+ w = x2 - x1;
+ h = y2 - y1;
+
+ *width = MAX (*width, x + w);
+ *height = MAX (*height, y + h);
}
g_list_free (active_crtcs);
@@ -1745,23 +1788,28 @@ crtc_assignment_apply (CrtcAssignment *assign, guint32 timestamp, GError **error
{
GnomeRRCrtc *crtc = all_crtcs[i];
GnomeRRMode *mode = gnome_rr_crtc_get_current_mode (crtc);
- int x, y;
+ GnomeRRRotation rotation = gnome_rr_crtc_get_current_rotation (crtc);
+ GnomeRRTransform transform;
+
+ gnome_rr_crtc_get_current_transform (crtc, &transform);
if (mode)
{
- int w, h;
+ int x, y, w, h;
+ int x1, y1, x2, y2;
+
+ gnome_rr_mode_get_geometry (mode,
+ rotation,
+ &transform,
+ &x1, &y1, &x2, &y2);
+
gnome_rr_crtc_get_position (crtc, &x, &y);
- w = gnome_rr_mode_get_width (mode);
- h = gnome_rr_mode_get_height (mode);
+ x += x1;
+ y += y1;
+ w = x2 - x1;
+ h = y2 - y1;
- if (crtc_is_rotated (crtc))
- {
- int tmp = h;
- h = w;
- w = tmp;
- }
-
if (x + w > width || y + h > height || !g_hash_table_lookup (assign->info, crtc))
{
if (!gnome_rr_crtc_set_config_with_time (crtc, timestamp, 0, 0, NULL, GNOME_RR_ROTATION_0, NULL, 0, error))
diff --git a/libgnome-desktop/gnome-rr.c b/libgnome-desktop/gnome-rr.c
index 6f23fbb..a56c02a 100644
--- a/libgnome-desktop/gnome-rr.c
+++ b/libgnome-desktop/gnome-rr.c
@@ -28,7 +28,9 @@
#include <glib/gi18n-lib.h>
#include "libgnomeui/gnome-rr.h"
#include <string.h>
+#include <math.h>
#include <X11/Xlib.h>
+#include <X11/extensions/Xrender.h>
#include <X11/extensions/Xrandr.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
@@ -71,10 +73,11 @@ struct GnomeRRCrtc
GnomeRROutput ** possible_outputs;
int x;
int y;
-
GnomeRRRotation current_rotation;
GnomeRRRotation rotations;
int gamma_size;
+ GnomeRRTransform current_transform;
+ GnomeRRTransform pending_transform;
};
struct GnomeRRMode
@@ -911,7 +914,7 @@ output_initialize (GnomeRROutput *output, XRRScreenResources *res, GError **erro
DISPLAY (output), res, output->id);
GPtrArray *a;
int i;
-
+
#if 0
g_print ("Output %lx Timestamp: %u\n", output->id, (guint32)info->timestamp);
#endif
@@ -973,7 +976,7 @@ output_initialize (GnomeRROutput *output, XRRScreenResources *res, GError **erro
/* Edid data */
output->edid_data = read_edid_data (output);
-
+
XRRFreeOutputInfo (info);
return TRUE;
@@ -1276,7 +1279,31 @@ gnome_rr_crtc_set_config_with_time (GnomeRRCrtc *crtc,
for (i = 0; i < n_outputs; ++i)
g_array_append_val (output_ids, outputs[i]->id);
}
-
+
+#if RANDR_MAJOR > 1 || RANDR_MINOR >= 3
+ if (memcmp (&crtc->current_transform,
+ &crtc->pending_transform,
+ sizeof (GnomeRRTransform)) != 0)
+ {
+ XTransform xtransform;
+ int j;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ xtransform.matrix[i][j] =
+ XDoubleToFixed (crtc->pending_transform.transform[i][j]);
+
+ gdk_error_trap_push ();
+ XRRSetCrtcTransform (DISPLAY (crtc), crtc->id,
+ &xtransform,
+ "bilinear",
+ NULL,
+ 0);
+ XSync (DISPLAY (crtc), FALSE);
+ gdk_error_trap_pop ();
+ }
+#endif
+
status = XRRSetCrtcConfig (DISPLAY (crtc), info->resources, crtc->id,
timestamp,
x, y,
@@ -1393,7 +1420,11 @@ crtc_initialize (GnomeRRCrtc *crtc,
XRRCrtcInfo *info = XRRGetCrtcInfo (DISPLAY (crtc), res, crtc->id);
GPtrArray *a;
int i;
-
+
+#if RANDR_MAJOR > 1 || RANDR_MINOR >= 3
+ XRRCrtcTransformAttributes *attr;
+#endif
+
#if 0
g_print ("CRTC %lx Timestamp: %u\n", crtc->id, (guint32)info->timestamp);
#endif
@@ -1445,7 +1476,34 @@ crtc_initialize (GnomeRRCrtc *crtc,
/* Rotations */
crtc->current_rotation = gnome_rr_rotation_from_xrotation (info->rotation);
crtc->rotations = gnome_rr_rotation_from_xrotation (info->rotations);
-
+
+#if RANDR_MAJOR > 1 || RANDR_MINOR >= 3
+ if (XRRGetCrtcTransform (DISPLAY (crtc), crtc->id, &attr) && attr) {
+ int j;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ crtc->current_transform.transform[i][j] =
+ XFixedToDouble (attr->currentTransform.matrix[i][j]);
+
+ XFree (attr);
+ }
+ else
+#endif
+ {
+ crtc->current_transform.transform[0][0] = 1.0;
+ crtc->current_transform.transform[0][1] = 0.0;
+ crtc->current_transform.transform[0][2] = 0.0;
+ crtc->current_transform.transform[1][0] = 0.0;
+ crtc->current_transform.transform[1][1] = 1.0;
+ crtc->current_transform.transform[1][2] = 0.0;
+ crtc->current_transform.transform[2][0] = 0.0;
+ crtc->current_transform.transform[2][1] = 0.0;
+ crtc->current_transform.transform[2][2] = 1.0;
+ }
+
+ crtc->pending_transform = crtc->current_transform;
+
XRRFreeCrtcInfo (info);
/* get an store gamma size */
@@ -1592,3 +1650,184 @@ gnome_rr_crtc_get_gamma (GnomeRRCrtc *crtc, int *size,
return TRUE;
}
+typedef struct {
+ int x, y, width, height;
+} rectangle_t;
+
+typedef struct {
+ int x1, y1, x2, y2;
+} box_t;
+
+typedef struct {
+ int x, y;
+} point_t;
+
+static gboolean
+transform_point (GnomeRRTransform *transform, double *xp, double *yp)
+{
+ double vector[3];
+ double result[3];
+ int i, j;
+ double v;
+
+ vector[0] = *xp;
+ vector[1] = *yp;
+ vector[2] = 1;
+ for (j = 0; j < 3; j++)
+ {
+ v = 0;
+ for (i = 0; i < 3; i++)
+ v += (transform->transform[j][i] * vector[i]);
+ if (v > 32767 || v < -32767)
+ return FALSE;
+ result[j] = v;
+ }
+ if (!result[2])
+ return FALSE;
+ for (j = 0; j < 2; j++)
+ vector[j] = result[j] / result[2];
+ *xp = vector[0];
+ *yp = vector[1];
+ return TRUE;
+}
+
+static void
+path_bounds (GnomeRRTransform *transform, point_t *points, int npoints, box_t *box)
+{
+ int i;
+ box_t point;
+
+ for (i = 0; i < npoints; i++) {
+ double x, y;
+ x = points[i].x;
+ y = points[i].y;
+ transform_point (transform, &x, &y);
+ point.x1 = floor (x);
+ point.y1 = floor (y);
+ point.x2 = ceil (x);
+ point.y2 = ceil (y);
+ if (i == 0)
+ *box = point;
+ else {
+ if (point.x1 < box->x1) box->x1 = point.x1;
+ if (point.y1 < box->y1) box->y1 = point.y1;
+ if (point.x2 > box->x2) box->x2 = point.x2;
+ if (point.y2 > box->y2) box->y2 = point.y2;
+ }
+ }
+}
+
+static int
+mode_height (GnomeRRMode *mode, GnomeRRRotation rotation)
+{
+ switch (rotation & 0xf) {
+ case GNOME_RR_ROTATION_0:
+ case GNOME_RR_ROTATION_180:
+ return gnome_rr_mode_get_height (mode);
+ case GNOME_RR_ROTATION_90:
+ case GNOME_RR_ROTATION_270:
+ return gnome_rr_mode_get_width (mode);
+ default:
+ return 0;
+ }
+}
+
+static int
+mode_width (GnomeRRMode *mode, GnomeRRRotation rotation)
+{
+ switch (rotation & 0xf) {
+ case GNOME_RR_ROTATION_0:
+ case GNOME_RR_ROTATION_180:
+ return gnome_rr_mode_get_width (mode);
+ case GNOME_RR_ROTATION_90:
+ case GNOME_RR_ROTATION_270:
+ return gnome_rr_mode_get_height (mode);
+ default:
+ return 0;
+ }
+}
+
+static void
+mode_get_geometry (GnomeRRMode *mode,
+ GnomeRRRotation rotation,
+ GnomeRRTransform *transform,
+ box_t *bounds)
+{
+ point_t rect[4];
+ int width = mode_width (mode, rotation);
+ int height = mode_height (mode, rotation);
+
+ rect[0].x = 0;
+ rect[0].y = 0;
+ rect[1].x = width;
+ rect[1].y = 0;
+ rect[2].x = width;
+ rect[2].y = height;
+ rect[3].x = 0;
+ rect[3].y = height;
+
+ path_bounds (transform, rect, 4, bounds);
+}
+
+void
+gnome_rr_mode_get_geometry (GnomeRRMode *mode,
+ GnomeRRRotation rotation,
+ GnomeRRTransform *transform,
+ int *x1,
+ int *y1,
+ int *x2,
+ int *y2)
+{
+ box_t bounds = { 0 };
+
+ mode_get_geometry (mode, rotation, transform, &bounds);
+
+ *x1 = bounds.x1;
+ *y1 = bounds.y1;
+ *x2 = bounds.x2;
+ *y2 = bounds.y2;
+}
+
+void
+gnome_rr_crtc_get_current_transform (GnomeRRCrtc *crtc,
+ GnomeRRTransform *transform)
+{
+ *transform = crtc->current_transform;
+}
+
+gboolean
+gnome_rr_crtc_supports_transform (GnomeRRCrtc *crtc,
+ GnomeRRTransform *transform)
+{
+ const static GnomeRRTransform identity = {
+ {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ }
+ };
+
+ if (memcmp (transform, &identity, sizeof (identity)) == 0)
+ return TRUE;
+
+#if RANDR_MAJOR > 1 || RANDR_MINOR >= 3
+ int major, minor;
+
+ XRRQueryVersion (DISPLAY (crtc), &major, &minor);
+ if (major > 1 || (major == 1 && minor >= 3))
+ return TRUE;
+#endif
+
+ return FALSE;
+}
+
+gboolean
+gnome_rr_crtc_set_transform (GnomeRRCrtc *crtc,
+ GnomeRRTransform *transform)
+{
+ if (!gnome_rr_crtc_supports_transform (crtc, transform))
+ return FALSE;
+
+ crtc->pending_transform = *transform;
+ return TRUE;
+}
diff --git a/libgnome-desktop/libgnomeui/gnome-rr-config.h b/libgnome-desktop/libgnomeui/gnome-rr-config.h
index d55a38c..1a402d1 100644
--- a/libgnome-desktop/libgnomeui/gnome-rr-config.h
+++ b/libgnome-desktop/libgnomeui/gnome-rr-config.h
@@ -52,6 +52,7 @@ struct GnomeOutputInfo
int x;
int y;
GnomeRRRotation rotation;
+ GnomeRRTransform transform;
gboolean connected; /* whether the output is physically connected to a monitor */
char vendor[4];
diff --git a/libgnome-desktop/libgnomeui/gnome-rr.h b/libgnome-desktop/libgnomeui/gnome-rr.h
index c43bd8f..122c3ac 100644
--- a/libgnome-desktop/libgnomeui/gnome-rr.h
+++ b/libgnome-desktop/libgnomeui/gnome-rr.h
@@ -48,6 +48,11 @@ typedef enum
GNOME_RR_REFLECT_Y = (1 << 5)
} GnomeRRRotation;
+typedef struct
+{
+ double transform[3][3];
+} GnomeRRTransform;
+
/* Error codes */
#define GNOME_RR_ERROR (gnome_rr_error_quark ())
@@ -125,6 +130,14 @@ guint32 gnome_rr_mode_get_id (GnomeRRMode *mode)
guint gnome_rr_mode_get_width (GnomeRRMode *mode);
guint gnome_rr_mode_get_height (GnomeRRMode *mode);
int gnome_rr_mode_get_freq (GnomeRRMode *mode);
+void gnome_rr_mode_get_geometry (GnomeRRMode *mode,
+ GnomeRRRotation rotation,
+ GnomeRRTransform *transform,
+ int *x1,
+ int *y1,
+ int *x2,
+ int *y2);
+
/* GnomeRRCrtc */
guint32 gnome_rr_crtc_get_id (GnomeRRCrtc *crtc);
@@ -159,6 +172,12 @@ GnomeRRRotation gnome_rr_crtc_get_current_rotation (GnomeRRCrtc *crtc)
GnomeRRRotation gnome_rr_crtc_get_rotations (GnomeRRCrtc *crtc);
gboolean gnome_rr_crtc_supports_rotation (GnomeRRCrtc *crtc,
GnomeRRRotation rotation);
+void gnome_rr_crtc_get_current_transform (GnomeRRCrtc *crtc,
+ GnomeRRTransform *transform);
+gboolean gnome_rr_crtc_supports_transform (GnomeRRCrtc *crtc,
+ GnomeRRTransform *transform);
+gboolean gnome_rr_crtc_set_transform (GnomeRRCrtc *crtc,
+ GnomeRRTransform *transform);
gboolean gnome_rr_crtc_get_gamma (GnomeRRCrtc *crtc,
int *size,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]