aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/randr/mirrcrtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/randr/mirrcrtc.c')
-rw-r--r--xorg-server/randr/mirrcrtc.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/xorg-server/randr/mirrcrtc.c b/xorg-server/randr/mirrcrtc.c
new file mode 100644
index 000000000..812b2b68b
--- /dev/null
+++ b/xorg-server/randr/mirrcrtc.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright © 2010 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "randrstr.h"
+
+Bool
+miRRSetScreenConfig(ScreenPtr screen,
+ RRScreenConfigPtr screen_config)
+{
+ RRScreenConfigRec old_screen_config;
+
+ RRScreenCurrentConfig(screen, &old_screen_config);
+
+ /* Check and see if nothing has changed */
+ if (old_screen_config.screen_width == screen_config->screen_width &&
+ old_screen_config.screen_height == screen_config->screen_height &&
+ old_screen_config.screen_pixmap_width == screen_config->screen_pixmap_width &&
+ old_screen_config.screen_pixmap_height == screen_config->screen_pixmap_height &&
+ old_screen_config.mm_width == screen_config->mm_width &&
+ old_screen_config.mm_height == screen_config->mm_height)
+ return TRUE;
+
+ return RRScreenSizeSet(screen,
+ screen_config->screen_width,
+ screen_config->screen_height,
+ screen_config->screen_pixmap_width,
+ screen_config->screen_pixmap_height,
+ screen_config->mm_width,
+ screen_config->mm_height);
+}
+
+Bool
+miRRSetCrtcConfig(RRCrtcConfigPtr crtc_config)
+{
+ int x = crtc_config->x, y = crtc_config->y;
+
+ if (crtc_config->pixmap) {
+ x = crtc_config->pixmap_x;
+ y = crtc_config->pixmap_y;
+ }
+ if (!RRCrtcSet(crtc_config->crtc,
+ crtc_config->mode,
+ x,
+ y,
+ crtc_config->rotation,
+ crtc_config->numOutputs,
+ crtc_config->outputs,
+ crtc_config->pixmap))
+ return FALSE;
+ RRCrtcSpriteTransformSet(crtc_config->crtc,
+ &crtc_config->sprite_position_transform,
+ &crtc_config->sprite_image_transform,
+ &crtc_config->sprite_position_f_transform,
+ &crtc_config->sprite_image_f_transform);
+ return TRUE;
+}
+
+Bool
+miRRDisableCrtc(RRCrtcPtr crtc)
+{
+ RRCrtcConfigRec off_config;
+
+ memset(&off_config, '\0', sizeof (RRCrtcConfigRec));
+ off_config.crtc = crtc;
+ return miRRSetCrtcConfig(&off_config);
+}
+
+/*
+ * If the current crtc configuration doesn't fit
+ * with the new screen config, disable it
+ */
+Bool
+miRRCheckDisableCrtc(RRScreenConfigPtr new_screen_config,
+ RRCrtcConfigPtr old_crtc_config)
+{
+ RRCrtcPtr crtc = old_crtc_config->crtc;
+
+ /* If it's already disabled, we're done */
+ if (!old_crtc_config->mode)
+ return TRUE;
+
+ /* If the crtc isn't scanning from the screen pixmap,
+ * we're done
+ */
+ if (old_crtc_config->pixmap)
+ return TRUE;
+
+ /* If the new screen configuration covers the existing CRTC space,
+ * we're done
+ */
+ if (RRScreenCoversCrtc(new_screen_config, old_crtc_config,
+ &crtc->client_current_transform, NULL))
+ return TRUE;
+
+ /* Disable the crtc and let it get re-enabled */
+ return miRRDisableCrtc(crtc);
+}
+
+Bool
+miRRSetCrtcConfigs(ScreenPtr screen,
+ RRScreenConfigPtr screen_config,
+ RRCrtcConfigPtr crtc_configs,
+ int num_configs)
+{
+ RRScreenConfigRec old_screen_config;
+ RRCrtcConfigPtr old_crtc_configs;
+ int i;
+
+ /*
+ * Save existing state
+ */
+
+ RRScreenCurrentConfig(screen, &old_screen_config);
+ old_crtc_configs = calloc(num_configs, sizeof (RRCrtcConfigRec));
+ if (!old_crtc_configs)
+ return FALSE;
+
+ for (i = 0; i < num_configs; i++)
+ if (!RRCrtcCurrentConfig(crtc_configs[i].crtc, &old_crtc_configs[i]))
+ goto fail_save;
+ /*
+ * Set the new configuration. If anything goes wrong,
+ * bail and restore the old configuration
+ */
+ for (i = 0; i < num_configs; i++)
+ if (!miRRCheckDisableCrtc(screen_config, &old_crtc_configs[i]))
+ goto fail_disable;
+
+ if (!miRRSetScreenConfig(screen, screen_config))
+ goto fail_set_screen;
+
+ for (i = 0; i < num_configs; i++)
+ if (!miRRSetCrtcConfig(&crtc_configs[i]))
+ goto fail_set_crtc;
+
+ RRFreeCrtcConfigs(old_crtc_configs, num_configs);
+ return TRUE;
+
+fail_set_crtc:
+ /*
+ * Restore the previous configuration. Ignore any errors
+ * as we just need to hope that the driver can manage to
+ * get back to the previous state without trouble.
+ */
+ for (i = 0; i < num_configs; i++)
+ (void) miRRDisableCrtc(old_crtc_configs[i].crtc);
+ (void) miRRSetScreenConfig(screen, &old_screen_config);
+fail_set_screen:
+fail_disable:
+ for (i = 0; i < num_configs; i++)
+ (void) miRRSetCrtcConfig(&old_crtc_configs[i]);
+fail_save:
+ RRFreeCrtcConfigs(old_crtc_configs, num_configs);
+ return FALSE;
+}