X-Git-Url: https://git.piment-noir.org/?p=deb_xorg-server.git;a=blobdiff_plain;f=debian%2Fpatches%2Fxmir.patch;fp=debian%2Fpatches%2Fxmir.patch;h=c6498890d9fc4e6d368eb455747810e2e559c77f;hp=0000000000000000000000000000000000000000;hb=7217e0ca50bba73dad94782e67980aeeb24ab693;hpb=a09e091a5c996d46a398abb27b06fe504591673f diff --git a/debian/patches/xmir.patch b/debian/patches/xmir.patch new file mode 100644 index 0000000..c649889 --- /dev/null +++ b/debian/patches/xmir.patch @@ -0,0 +1,2145 @@ +--- a/configure.ac ++++ b/configure.ac +@@ -631,6 +631,7 @@ + AC_ARG_ENABLE(libdrm, AS_HELP_STRING([--enable-libdrm], [Build Xorg with libdrm support (default: enabled)]), [DRM=$enableval],[DRM=yes]) + AC_ARG_ENABLE(clientids, AS_HELP_STRING([--disable-clientids], [Build Xorg with client ID tracking (default: enabled)]), [CLIENTIDS=$enableval], [CLIENTIDS=yes]) + AC_ARG_ENABLE(pciaccess, AS_HELP_STRING([--enable-pciaccess], [Build Xorg with pciaccess library (default: enabled)]), [PCI=$enableval], [PCI=yes]) ++AC_ARG_ENABLE(xmir, AS_HELP_STRING([--enable-xmir], [Build support for nesting in Mir (default: auto)]), [XMIR=$enableval], [XMIR=auto]) + AC_ARG_ENABLE(linux_acpi, AC_HELP_STRING([--disable-linux-acpi], [Disable building ACPI support on Linux (if available).]), [enable_linux_acpi=$enableval], [enable_linux_acpi=yes]) + AC_ARG_ENABLE(linux_apm, AC_HELP_STRING([--disable-linux-apm], [Disable building APM support on Linux (if available).]), [enable_linux_apm=$enableval], [enable_linux_apm=yes]) + +@@ -1275,6 +1276,15 @@ + SDK_REQUIRED_MODULES="$SDK_REQUIRED_MODULES $XINERAMAPROTO" + fi + ++if test "x$XMIR" != xno; then ++ PKG_CHECK_MODULES([XMIR], [mirclient], [XMIR=yes], [XMIR=no]) ++ AC_SUBST([XMIR_LIBS]) ++ AC_SUBST([XMIR_CFLAGS]) ++ AC_DEFINE(XMIR, 1, [Support Mir nested mode]) ++ SDK_REQUIRED_MODULES="$SDK_REQUIRED_MODULES mirclient" ++fi ++AM_CONDITIONAL(XMIR, [test "x$XMIR" = xyes]) ++ + AM_CONDITIONAL(XACE, [test "x$XACE" = xyes]) + if test "x$XACE" = xyes; then + AC_DEFINE(XACE, 1, [Build X-ACE extension]) +@@ -2439,6 +2449,7 @@ + hw/xfree86/utils/man/Makefile + hw/xfree86/utils/cvt/Makefile + hw/xfree86/utils/gtf/Makefile ++hw/xfree86/xmir/Makefile + hw/dmx/config/Makefile + hw/dmx/config/man/Makefile + hw/dmx/doc/Makefile +--- a/hw/xfree86/Makefile.am ++++ b/hw/xfree86/Makefile.am +@@ -30,15 +30,20 @@ + INT10_SUBDIR = int10 + endif + ++if XMIR ++XMIR_SUBDIR = xmir ++endif ++ + SUBDIRS = common ddc x86emu $(INT10_SUBDIR) os-support parser \ + ramdac $(VGAHW_SUBDIR) loader modes $(DRI_SUBDIR) \ + $(DRI2_SUBDIR) . $(VBE_SUBDIR) i2c dixmods \ +- fbdevhw shadowfb exa $(XF86UTILS_SUBDIR) doc man ++ fbdevhw shadowfb exa $(XF86UTILS_SUBDIR) doc man \ ++ $(XMIR_SUBDIR) + + DIST_SUBDIRS = common ddc i2c x86emu int10 fbdevhw os-support \ + parser ramdac shadowfb vbe vgahw \ + loader dixmods dri dri2 exa modes \ +- utils doc man ++ utils doc man xmir + + bin_PROGRAMS = Xorg + nodist_Xorg_SOURCES = sdksyms.c +--- a/hw/xfree86/common/xf86Config.c ++++ b/hw/xfree86/common/xf86Config.c +@@ -118,6 +118,7 @@ + {.name = "fb",.toLoad = TRUE,.load_opt = NULL}, + {.name = "shadow",.toLoad = TRUE,.load_opt = NULL}, + #endif ++ {.name = "xmir", .toLoad = FALSE, .load_opt = NULL}, + {.name = NULL,.toLoad = FALSE,.load_opt = NULL} + }; + +@@ -260,6 +261,17 @@ + return NULL; + } + ++ /* ++ * Set the xmir module to autoload if requested. ++ */ ++ if (xorgMir) { ++ for (i=0 ; ModuleDefaults[i].name != NULL ; i++) { ++ if (strcmp(ModuleDefaults[i].name, "xmir") == 0) { ++ ModuleDefaults[i].toLoad = TRUE; ++ } ++ } ++ } ++ + if (xf86configptr->conf_modules) { + /* Walk the disable list and let people know what we've parsed to + * not be loaded +--- a/hw/xfree86/common/xf86Events.c ++++ b/hw/xfree86/common/xf86Events.c +@@ -105,8 +105,6 @@ + extern void (*xf86OSPMClose) (void); + #endif + +-static void xf86VTSwitch(void); +- + /* + * Allow arbitrary drivers or other XFree86 code to register with our main + * Wakeup handler. +@@ -411,7 +409,7 @@ + * xf86VTSwitch -- + * Handle requests for switching the vt. + */ +-static void ++_X_EXPORT void + xf86VTSwitch(void) + { + int i; +@@ -471,7 +469,7 @@ + + xf86AccessLeave(); /* We need this here, otherwise */ + +- if (!xf86VTSwitchAway()) { ++ if (!xorgMir && !xf86VTSwitchAway()) { + /* + * switch failed + */ +@@ -530,7 +528,7 @@ + } + else { + DebugF("xf86VTSwitch: Entering\n"); +- if (!xf86VTSwitchTo()) ++ if (!xorgMir && !xf86VTSwitchTo()) + return; + + #ifdef XF86PM +--- a/hw/xfree86/common/xf86Globals.c ++++ b/hw/xfree86/common/xf86Globals.c +@@ -206,3 +206,6 @@ + #endif + RootWinPropPtr *xf86RegisteredPropertiesTable = NULL; + Bool xorgHWAccess = FALSE; ++Bool xorgMir = FALSE; ++const char *mirID = NULL; ++const char *mirSocket = NULL; +--- a/hw/xfree86/common/xf86Helper.c ++++ b/hw/xfree86/common/xf86Helper.c +@@ -100,7 +100,14 @@ + if (xf86DriverList[drvIndex]->module) + UnloadModule(xf86DriverList[drvIndex]->module); + free(xf86DriverList[drvIndex]); +- xf86DriverList[drvIndex] = NULL; ++ ++ /* Compact xf86DriverList array, update xf86NumDrivers */ ++ xf86NumDrivers--; ++ if(drvIndex != xf86NumDrivers) ++ memmove(xf86DriverList + drvIndex, ++ xf86DriverList + drvIndex + 1, ++ sizeof(DriverPtr) * (xf86NumDrivers - drvIndex)); ++ xf86DriverList = realloc(xf86DriverList, xf86NumDrivers * sizeof(DriverPtr)); + } + } + +--- a/hw/xfree86/common/xf86Init.c ++++ b/hw/xfree86/common/xf86Init.c +@@ -554,7 +554,7 @@ + * needed at this early stage. + */ + +- for (i = 0; i < xf86NumDrivers; i++) { ++ for (i = 0; i < xf86NumDrivers; ) { + xorgHWFlags flags = HW_IO; + + if (xf86DriverList[i]->Identify != NULL) +@@ -565,11 +565,20 @@ + GET_REQUIRED_HW_INTERFACES, + &flags); + ++ if (xorgMir && ++ (NEED_IO_ENABLED(flags) || !(flags & HW_SKIP_CONSOLE))) { ++ ErrorF("Driver needs flags %lu, incompatible with nested, deleting.\n", flags); ++ xf86DeleteDriver(i); ++ continue; ++ } ++ + if (NEED_IO_ENABLED(flags)) + want_hw_access = TRUE; + + if (!(flags & HW_SKIP_CONSOLE)) + xorgHWOpenConsole = TRUE; ++ ++ i++; + } + + if (xorgHWOpenConsole) +@@ -662,9 +671,13 @@ + } + + /* Remove (unload) drivers that are not required */ +- for (i = 0; i < xf86NumDrivers; i++) +- if (xf86DriverList[i] && xf86DriverList[i]->refCount <= 0) ++ for (i = 0; i < xf86NumDrivers; ) ++ if (xf86DriverList[i] && ++ !xf86DriverHasEntities(xf86DriverList[i]) && ++ xf86DriverList[i]->refCount <= 0) + xf86DeleteDriver(i); ++ else ++ i++; + + /* + * At this stage we know how many screens there are. +@@ -1490,6 +1503,17 @@ + xf86Info.ShareVTs = TRUE; + return 1; + } ++ if (!strcmp(argv[i], "-mir")) { ++ CHECK_FOR_REQUIRED_ARGUMENT(); ++ mirID = argv[++i]; ++ xorgMir = TRUE; ++ return 2; ++ } ++ if (!strcmp(argv[i], "-mirSocket")) { ++ CHECK_FOR_REQUIRED_ARGUMENT(); ++ mirSocket = argv[++i]; ++ return 2; ++ } + + /* OS-specific processing */ + return xf86ProcessArgument(argc, argv, i); +@@ -1563,6 +1587,8 @@ + ErrorF + ("-novtswitch don't automatically switch VT at reset & exit\n"); + ErrorF("-sharevts share VTs with another X server\n"); ++ ErrorF ++ ("-mir MirID run nested in a Mir compositor with app id MirID\n"); + /* OS-specific usage */ + xf86UseMsg(); + ErrorF("\n"); +--- a/hw/xfree86/common/xf86Priv.h ++++ b/hw/xfree86/common/xf86Priv.h +@@ -93,6 +93,9 @@ + extern _X_EXPORT const char *xf86VisualNames[]; + extern _X_EXPORT int xf86Verbose; /* verbosity level */ + extern _X_EXPORT int xf86LogVerbose; /* log file verbosity level */ ++extern _X_EXPORT Bool xorgMir; ++extern _X_EXPORT const char *mirID; ++extern _X_EXPORT const char *mirSocket; + + extern _X_EXPORT RootWinPropPtr *xf86RegisteredPropertiesTable; + +@@ -149,6 +152,9 @@ + extern _X_EXPORT int (*xf86PMGetEventFromOs) (int fd, pmEvent * events, + int num); + extern _X_EXPORT pmWait (*xf86PMConfirmEventToOs) (int fd, pmEvent event); ++extern _X_EXPORT void ++xf86VTSwitch(void); ++ + + /* xf86Helper.c */ + extern _X_EXPORT void +--- a/hw/xfree86/ramdac/xf86Cursor.c ++++ b/hw/xfree86/ramdac/xf86Cursor.c +@@ -58,7 +58,12 @@ + xf86CursorScreenPtr ScreenPriv; + miPointerScreenPtr PointPriv; + +- if (!xf86InitHardwareCursor(pScreen, infoPtr)) ++ infoPtr->pScrn = xf86ScreenToScrn(pScreen); ++ ++ /* If we can't create a hardware cursor don't bother initialising HW cursor support */ ++ if (infoPtr->MaxWidth != 0 && ++ infoPtr->MaxHeight != 0 && ++ !xf86InitHardwareCursor(pScreen, infoPtr)) + return FALSE; + + if (!dixRegisterPrivateKey(&xf86CursorScreenKeyRec, PRIVATE_SCREEN, 0)) +--- a/hw/xfree86/ramdac/xf86HWCurs.c ++++ b/hw/xfree86/ramdac/xf86HWCurs.c +@@ -114,8 +114,6 @@ + infoPtr->RealizeCursor = RealizeCursorInterleave0; + } + +- infoPtr->pScrn = xf86ScreenToScrn(pScreen); +- + return TRUE; + } + +--- /dev/null ++++ b/hw/xfree86/xmir/Makefile.am +@@ -0,0 +1,26 @@ ++INCLUDES = \ ++ $(XORG_INCS) \ ++ -I$(srcdir)/../ddc \ ++ -I$(srcdir)/../ramdac \ ++ -I$(srcdir)/../i2c \ ++ -I$(srcdir)/../parser \ ++ -I$(srcdir)/../modes ++ ++libxmir_la_LTLIBRARIES = libxmir.la ++libxmir_la_CFLAGS = \ ++ -DHAVE_XORG_CONFIG_H \ ++ $(DRI_CFLAGS) \ ++ $(DIX_CFLAGS) $(XORG_CFLAGS) $(LIBDRM_CFLAGS) \ ++ $(XMIR_CFLAGS) ++ ++libxmir_la_LDFLAGS = -module -avoid-version $(LIBDRM_LIBS) $(XMIR_LIBS) ++libxmir_ladir = $(moduledir)/extensions ++libxmir_la_SOURCES = \ ++ xmir.c \ ++ xmir-window.c \ ++ xmir-output.c \ ++ xmir-thread-proxy.c \ ++ xmir.h \ ++ xmir-private.h ++ ++sdk_HEADERS = xmir.h +--- /dev/null ++++ b/hw/xfree86/xmir/xmir-output.c +@@ -0,0 +1,678 @@ ++/* ++ * Copyright © 2012 Canonical, Inc ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Soft- ++ * ware"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, provided that the above copyright ++ * notice(s) and this permission notice appear in all copies of the Soft- ++ * ware and that both the above copyright notice(s) and this permission ++ * notice appear in supporting documentation. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- ++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY ++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN ++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- ++ * QUENTIAL 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 PERFOR- ++ * MANCE OF THIS SOFTWARE. ++ * ++ * Except as contained in this notice, the name of a copyright holder shall ++ * not be used in advertising or otherwise to promote the sale, use or ++ * other dealings in this Software without prior written authorization of ++ * the copyright holder. ++ * ++ * Authors: ++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com) ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include "xmir.h" ++#include "xmir-private.h" ++#include "xf86Crtc.h" ++#include "xf86Priv.h" ++ ++struct xmir_crtc { ++ xmir_screen *xmir; ++ xmir_window *root_fragment; ++ MirDisplayConfiguration *config; ++}; ++ ++static const char * ++xmir_mir_dpms_mode_description(MirPowerMode mode) ++{ ++ switch (mode) ++ { ++ case mir_power_mode_on: ++ return "mir_power_mode_on"; ++ case mir_power_mode_standby: ++ return "mir_power_mode_standby"; ++ case mir_power_mode_suspend: ++ return "mir_power_mode_suspend"; ++ case mir_power_mode_off: ++ return "mir_power_mode_off"; ++ default: ++ return "OMGUNKNOWN!"; ++ } ++} ++ ++static void ++xmir_crtc_dpms(xf86CrtcPtr crtc, int mode) ++{ ++ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(crtc->scrn); ++ struct xmir_crtc *xmir_crtc = crtc->driver_private; ++ ++ for (int i = 0; i < crtc_cfg->num_output; i++) { ++ /* If this output should be driven by our "CRTC", set DPMS mode */ ++ MirDisplayOutput *output = crtc_cfg->output[i]->driver_private; ++ if (crtc_cfg->output[i]->crtc == crtc) { ++ xf86Msg(X_INFO, "Setting DPMS mode for output %d to %d\n", i, mode); ++ switch (mode) { ++ case DPMSModeOn: ++ output->power_mode = mir_power_mode_on; ++ xmir_crtc->xmir->dpms_on = TRUE; ++ break; ++ case DPMSModeStandby: ++ output->power_mode = mir_power_mode_standby; ++ xmir_crtc->xmir->dpms_on = FALSE; ++ break; ++ case DPMSModeSuspend: ++ output->power_mode = mir_power_mode_suspend; ++ xmir_crtc->xmir->dpms_on = FALSE; ++ break; ++ case DPMSModeOff: ++ output->power_mode = mir_power_mode_off; ++ xmir_crtc->xmir->dpms_on = FALSE; ++ break; ++ } ++ } ++ } ++ mir_wait_for(mir_connection_apply_display_config(xmir_connection_get(), ++ xmir_crtc->config)); ++} ++ ++static const char* ++xmir_get_output_type_str(MirDisplayOutput *mir_output) ++{ ++ const char *str = "Invalid"; ++ ++ switch(mir_output->type) ++ { ++ case mir_display_output_type_vga: str = "VGA"; break; ++ case mir_display_output_type_dvii: str = "DVI"; break; ++ case mir_display_output_type_dvid: str = "DVI"; break; ++ case mir_display_output_type_dvia: str = "DVI"; break; ++ case mir_display_output_type_composite: str = "Composite"; break; ++ case mir_display_output_type_svideo: str = "TV"; break; ++ case mir_display_output_type_lvds: str = "LVDS"; break; ++ case mir_display_output_type_component: str = "CTV"; break; ++ case mir_display_output_type_ninepindin: str = "DIN"; break; ++ case mir_display_output_type_displayport: str = "DP"; break; ++ case mir_display_output_type_hdmia: str = "HDMI"; break; ++ case mir_display_output_type_hdmib: str = "HDMI"; break; ++ case mir_display_output_type_tv: str = "TV"; break; ++ case mir_display_output_type_edp: str = "eDP"; break; ++ ++ case mir_display_output_type_unknown: str = "None"; break; ++ default: break; ++ } ++ ++ return str; ++} ++ ++static void ++xmir_output_populate(xf86OutputPtr xf86output, MirDisplayOutput *output) ++{ ++ /* We can always arbitrarily clone and output */ ++ xf86output->possible_crtcs = 0xffffffff; ++ xf86output->possible_clones = 0xffffffff; ++ ++ xf86output->driver_private = output; ++ ++ xf86output->interlaceAllowed = FALSE; ++ xf86output->doubleScanAllowed = FALSE; ++ xf86output->mm_width = output->physical_width_mm; ++ xf86output->mm_height = output->physical_height_mm; ++ /* TODO: Subpixel order from Mir */ ++ xf86output->subpixel_order = SubPixelUnknown; ++} ++ ++static DisplayModePtr ++xmir_create_xf86mode(const struct MirDisplayMode *mir_mode) ++{ ++ DisplayModePtr mode; ++ ++ mode = xf86CVTMode(mir_mode->horizontal_resolution, ++ mir_mode->vertical_resolution, ++ mir_mode->refresh_rate, ++ FALSE, FALSE); ++ ++ /* ++ * And now, because the CVT standard doesn't support such common ++ * resolutions as 1366x768... ++ */ ++ mode->VDisplay = mir_mode->vertical_resolution; ++ mode->HDisplay = mir_mode->horizontal_resolution; ++ ++ xf86SetModeDefaultName(mode); ++ ++ return mode; ++} ++ ++static void ++xmir_free_xf86mode(DisplayModePtr mode) ++{ ++ free(mode->name); ++ free(mode); ++} ++ ++static Bool ++xmir_set_mode_for_output(MirDisplayOutput *output, ++ DisplayModePtr mode) ++{ ++ for (int i = 0; i < output->num_modes; i++) { ++ Bool modes_equal = FALSE; ++ DisplayModePtr mir_mode = NULL; ++ xf86Msg(X_INFO, "Checking against mode (%dx%d)@%.2f\n", ++ output->modes[i].horizontal_resolution, ++ output->modes[i].vertical_resolution, ++ output->modes[i].refresh_rate); ++ ++ mir_mode = xmir_create_xf86mode(&output->modes[i]); ++ modes_equal = xf86ModesEqual(mode, mir_mode); ++ xmir_free_xf86mode(mir_mode); ++ ++ if (modes_equal) { ++ output->current_mode = i; ++ output->used = 1; ++ xf86Msg(X_INFO, "Matched mode %d\n", i); ++ return TRUE; ++ } ++ } ++ return FALSE; ++} ++ ++static uint32_t ++xmir_update_outputs_for_crtc(xf86CrtcPtr crtc, DisplayModePtr mode, int x, int y) ++{ ++ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(crtc->scrn); ++ uint32_t representative_output_id = mir_display_output_id_invalid; ++ ++ for (int i = 0; i < crtc_cfg->num_output; i++) { ++ /* If this output should be driven by our "CRTC", set its mode */ ++ if (crtc_cfg->output[i]->crtc == crtc) { ++ MirDisplayOutput *output = crtc_cfg->output[i]->driver_private; ++ xmir_set_mode_for_output(output, mode); ++ output->position_x = x; ++ output->position_y = y; ++ representative_output_id = output->output_id; ++ } ++ } ++ return representative_output_id; ++} ++ ++static void ++xmir_disable_unused_outputs(xf86CrtcPtr crtc) ++{ ++ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(crtc->scrn); ++ ++ for (int i = 0; i < crtc_cfg->num_output; i++) ++ /* If any outputs are no longer associated with a CRTC, disable them */ ++ if (crtc_cfg->output[i]->crtc == NULL) ++ ((MirDisplayOutput*)crtc_cfg->output[i]->driver_private)->used = 0; ++} ++ ++static void ++xmir_stupid_callback(MirSurface *surf, void *ctx) ++{ ++} ++ ++static void ++xmir_dump_config(MirDisplayConfiguration *config) ++{ ++ for (int i = 0; i < config->num_outputs; i++) ++ { ++ xf86Msg(X_INFO, "Output %d (%s, %s) has mode %d (%d x %d @ %.2f), position (%d,%d), dpms: %s\n", ++ config->outputs[i].output_id, ++ config->outputs[i].connected ? "connected" : "disconnected", ++ config->outputs[i].used ? "enabled" : "disabled", ++ config->outputs[i].current_mode, ++ config->outputs[i].used ? config->outputs[i].modes[config->outputs[i].current_mode].horizontal_resolution : 0, ++ config->outputs[i].used ? config->outputs[i].modes[config->outputs[i].current_mode].vertical_resolution : 0, ++ config->outputs[i].used ? config->outputs[i].modes[config->outputs[i].current_mode].refresh_rate : 0, ++ config->outputs[i].position_x, ++ config->outputs[i].position_y, ++ xmir_mir_dpms_mode_description(config->outputs[i].power_mode)); ++ for (int m = 0; m < config->outputs[i].num_modes; m++) ++ { ++ xf86Msg(X_INFO, " mode %d: (%d x %d @ %.2f)\n", ++ m, ++ config->outputs[i].modes[m].horizontal_resolution, ++ ++ config->outputs[i].modes[m].vertical_resolution, ++ config->outputs[i].modes[m].refresh_rate); ++ } ++ } ++} ++ ++static void ++xmir_update_config(xf86CrtcConfigPtr crtc_cfg) ++{ ++ MirDisplayConfiguration *new_config; ++ struct xmir_crtc *xmir_crtc = crtc_cfg->crtc[0]->driver_private; ++ ++ mir_display_config_destroy(xmir_crtc->config); ++ ++ new_config = mir_connection_create_display_config(xmir_connection_get()); ++ for (int i = 0; i < crtc_cfg->num_crtc; i++) { ++ xmir_crtc = crtc_cfg->crtc[i]->driver_private; ++ xmir_crtc-> config = new_config; ++ } ++ ++ if (crtc_cfg->num_output != new_config->num_outputs) ++ FatalError("[xmir] New Mir config has different number of outputs?"); ++ ++ for (int i = 0; i < crtc_cfg->num_output ; i++) { ++ /* TODO: Ensure that the order actually matches up */ ++ xmir_output_populate(crtc_cfg->output[i], new_config->outputs + i); ++ } ++ xf86Msg(X_INFO, "Recieved updated config from Mir:\n"); ++ xmir_dump_config(new_config); ++} ++ ++static void ++xmir_crtc_surface_created(MirSurface *surface, void *ctx) ++{ ++ xf86CrtcPtr crtc = ctx; ++ struct xmir_crtc *xmir_crtc = crtc->driver_private; ++ ++ if (xmir_crtc->root_fragment->surface != NULL) ++ mir_surface_release(xmir_crtc->root_fragment->surface, xmir_stupid_callback, NULL); ++ ++ xmir_crtc->root_fragment->surface = surface; ++} ++ ++static Bool ++xmir_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, ++ Rotation rotation, int x, int y) ++{ ++ MirSurfaceParameters params = { ++ .name = "Xorg", ++ .width = mode->HDisplay, ++ .height = mode->VDisplay, ++ .pixel_format = mir_pixel_format_xrgb_8888, ++ .buffer_usage = mir_buffer_usage_hardware, ++ .output_id = mir_display_output_id_invalid ++ }; ++ BoxRec output_bounds = { ++ .x1 = x, ++ .y1 = y, ++ .x2 = x + mode->HDisplay, ++ .y2 = y + mode->VDisplay ++ }; ++ struct xmir_crtc *xmir_crtc = crtc->driver_private; ++ uint32_t output_id = mir_display_output_id_invalid; ++ const char *error_msg; ++ ++ if (mode->HDisplay == 0 || mode->VDisplay == 0) ++ return FALSE; ++ ++ xf86Msg(X_INFO, "Initial configuration for crtc %p:\n", crtc); ++ xmir_dump_config(xmir_crtc->config); ++ ++ xf86Msg(X_INFO, "Setting mode to %dx%d (%.2f)\n", mode->HDisplay, mode->VDisplay, mode->VRefresh); ++ output_id = xmir_update_outputs_for_crtc(crtc, mode, x, y); ++ xmir_disable_unused_outputs(crtc); ++ ++ xf86Msg(X_INFO, "Updated configuration:\n"); ++ ++ xmir_dump_config(xmir_crtc->config); ++ mir_wait_for(mir_connection_apply_display_config(xmir_connection_get(), ++ xmir_crtc->config)); ++ error_msg = mir_connection_get_error_message(xmir_connection_get()); ++ if (*error_msg != '\0') { ++ xf86Msg(X_ERROR, "[xmir] Failed to set new display config: %s\n", ++ error_msg); ++ return FALSE; ++ /* TODO: Restore correct config cache */ ++ } ++ ++ xf86Msg(X_INFO, "Post-modeset config:\n"); ++ xmir_update_config(XF86_CRTC_CONFIG_PTR(crtc->scrn)); ++ ++ if (output_id == mir_display_output_id_invalid) { ++ if (xmir_crtc->root_fragment->surface != NULL) ++ mir_wait_for(mir_surface_release(xmir_crtc->root_fragment->surface, xmir_stupid_callback, NULL)); ++ xmir_crtc->root_fragment->surface = NULL; ++ return TRUE; ++ } ++ ++ params.output_id = output_id; ++ xf86Msg(X_INFO, "Putting surface on output %d\n", output_id); ++ mir_wait_for(mir_connection_create_surface(xmir_connection_get(), ++ ¶ms, ++ xmir_crtc_surface_created, ++ crtc)); ++ if (!mir_surface_is_valid(xmir_crtc->root_fragment->surface)) { ++ xf86Msg(X_ERROR, ++ "[xmir] Failed to create surface for %dx%d mode: %s\n", ++ mode->HDisplay, mode->VDisplay, ++ mir_surface_get_error_message(xmir_crtc->root_fragment->surface)); ++ return FALSE; ++ } ++ ++ ++ /* During X server init this will be NULL. ++ This is fixed up in xmir_window_create */ ++ xmir_crtc->root_fragment->win = xf86ScrnToScreen(crtc->scrn)->root; ++ ++ RegionInit(&xmir_crtc->root_fragment->region, &output_bounds, 0); ++ xmir_crtc->root_fragment->has_free_buffer = TRUE; ++ ++ return TRUE; ++} ++ ++static void ++crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) ++{ ++} ++ ++static void ++crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) ++{ ++} ++ ++static void ++crtc_show_cursor (xf86CrtcPtr crtc) ++{ ++} ++ ++static void ++crtc_hide_cursor (xf86CrtcPtr crtc) ++{ ++} ++ ++static void ++crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) ++{ ++} ++ ++static PixmapPtr ++crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) ++{ ++ return NULL; ++} ++ ++static void * ++crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) ++{ ++ return NULL; ++} ++ ++static void ++crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) ++{ ++} ++ ++static void ++xmir_crtc_destroy(xf86CrtcPtr crtc) ++{ ++ struct xmir_crtc *xmir_crtc = crtc->driver_private; ++ ++ if (xmir_crtc->root_fragment->surface != NULL) ++ mir_surface_release(xmir_crtc->root_fragment->surface, NULL, NULL); ++ ++ free(xmir_crtc); ++} ++ ++static const xf86CrtcFuncsRec crtc_funcs = { ++ .dpms = xmir_crtc_dpms, ++ .set_mode_major = xmir_crtc_set_mode_major, ++ .set_cursor_colors = crtc_set_cursor_colors, ++ .set_cursor_position = crtc_set_cursor_position, ++ .show_cursor = crtc_show_cursor, ++ .hide_cursor = crtc_hide_cursor, ++ .load_cursor_argb = crtc_load_cursor_argb, ++ .shadow_create = crtc_shadow_create, ++ .shadow_allocate = crtc_shadow_allocate, ++ .shadow_destroy = crtc_shadow_destroy, ++ .destroy = xmir_crtc_destroy, ++}; ++ ++static void ++xmir_output_dpms(xf86OutputPtr output, int mode) ++{ ++ return; ++} ++ ++static xf86OutputStatus ++xmir_output_detect(xf86OutputPtr output) ++{ ++ MirDisplayOutput *mir_output = output->driver_private; ++ return mir_output->connected ? XF86OutputStatusConnected : XF86OutputStatusDisconnected; ++} ++ ++static Bool ++xmir_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) ++{ ++ return MODE_OK; ++} ++ ++static DisplayModePtr ++xmir_output_get_modes(xf86OutputPtr xf86output) ++{ ++ MirDisplayOutput *mir_output = xf86output->driver_private; ++ DisplayModePtr modes = NULL; ++ ++ for (int i = 0; i < mir_output->num_modes; i++) { ++ DisplayModePtr mode = xmir_create_xf86mode(&mir_output->modes[i]); ++ ++ mode->type = M_T_DRIVER; ++ if (i == mir_output->preferred_mode) ++ mode->type |= M_T_PREFERRED; ++ ++ modes = xf86ModesAdd(modes, mode); ++ } ++ /* TODO: Get Mir to send us the EDID blob and add that */ ++ ++ return modes; ++} ++ ++static void ++xmir_output_destroy(xf86OutputPtr xf86output) ++{ ++ /* The MirDisplayOutput* in driver_private gets cleaned up by ++ mir_display_config_destroy() */ ++} ++ ++static const xf86OutputFuncsRec xmir_output_funcs = { ++ .dpms = xmir_output_dpms, ++ .detect = xmir_output_detect, ++ .mode_valid = xmir_output_mode_valid, ++ .get_modes = xmir_output_get_modes, ++ .destroy = xmir_output_destroy ++}; ++ ++ ++struct xmir_visit_set_pixmap_window { ++ PixmapPtr old, new; ++}; ++ ++static int ++xmir_visit_set_window_pixmap(WindowPtr window, pointer data) ++{ ++ struct xmir_visit_set_pixmap_window *visit = data; ++ ++ if (window->drawable.pScreen->GetWindowPixmap(window) == visit->old) { ++ window->drawable.pScreen->SetWindowPixmap(window, visit->new); ++ return WT_WALKCHILDREN; ++ } ++ ++ return WT_DONTWALKCHILDREN; ++} ++ ++static void ++xmir_set_screen_pixmap(PixmapPtr old_front, PixmapPtr new_front) ++{ ++ struct xmir_visit_set_pixmap_window visit = { ++ .old = old_front, ++ .new = new_front ++ }; ++ (old_front->drawable.pScreen->SetScreenPixmap)(new_front); ++ ++ TraverseTree(old_front->drawable.pScreen->root, &xmir_visit_set_window_pixmap, &visit); ++} ++ ++static Bool ++xmir_resize(ScrnInfoPtr scrn, int width, int height) ++{ ++ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(scrn); ++ ScreenPtr screen = xf86ScrnToScreen(scrn); ++ PixmapPtr old_screen_pixmap, new_screen_pixmap; ++ ++ if (scrn->virtualX == width && scrn->virtualY == height) ++ return TRUE; ++ ++ old_screen_pixmap = screen->GetScreenPixmap(screen); ++ new_screen_pixmap = screen->CreatePixmap(screen, width, height, scrn->depth, ++ CREATE_PIXMAP_USAGE_BACKING_PIXMAP); ++ ++ if (!new_screen_pixmap) ++ return FALSE; ++ ++ scrn->virtualX = width; ++ scrn->virtualY = height; ++ scrn->displayWidth = width; ++ ++ for (int i = 0; i < crtc_cfg->num_crtc; i++) { ++ xf86CrtcPtr crtc = crtc_cfg->crtc[i]; ++ ++ if (!crtc->enabled) ++ continue; ++ ++ xmir_crtc_set_mode_major(crtc, &crtc->mode, ++ crtc->rotation, crtc->x, crtc->y); ++ } ++ ++ xmir_set_screen_pixmap(old_screen_pixmap, new_screen_pixmap); ++ screen->DestroyPixmap(old_screen_pixmap); ++ ++ xf86_reload_cursors(screen); ++ ++ return TRUE; ++} ++ ++static const xf86CrtcConfigFuncsRec config_funcs = { ++ xmir_resize ++}; ++ ++static void ++xmir_handle_hotplug(void *ctx) ++{ ++ ScrnInfoPtr scrn = *(ScrnInfoPtr *)ctx; ++ xf86CrtcConfigPtr crtc_config = XF86_CRTC_CONFIG_PTR(scrn); ++ ++ if (crtc_config->num_crtc == 0) ++ FatalError("[xmir] Received hotplug event, but have no CRTCs?\n"); ++ ++ xmir_update_config(crtc_config); ++ ++ /* Trigger RANDR refresh */ ++ RRGetInfo(xf86ScrnToScreen(scrn), TRUE); ++} ++ ++static void ++xmir_display_config_callback(MirConnection *unused, void *ctx) ++{ ++ xmir_screen *xmir = ctx; ++ ++ xmir_post_to_eventloop(xmir->hotplug_event_handler, &xmir->scrn); ++} ++ ++Bool ++xmir_mode_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir) ++{ ++ int i; ++ MirDisplayConfiguration *display_config; ++ xf86CrtcPtr xf86crtc; ++ int output_type_count[mir_display_output_type_edp + 1]; ++ ++ memset(output_type_count, 0, sizeof output_type_count); ++ ++ /* Set up CRTC config functions */ ++ xf86CrtcConfigInit(scrn, &config_funcs); ++ ++ /* We don't scanout of a single surface, so we don't have a scanout limit */ ++ xf86CrtcSetSizeRange(scrn, ++ 320, 320, ++ INT16_MAX, INT16_MAX); ++ ++ /* Hook up hotplug notification */ ++ xmir->hotplug_event_handler = ++ xmir_register_handler(&xmir_handle_hotplug, ++ sizeof (ScreenPtr)); ++ ++ mir_connection_set_display_config_change_callback( ++ xmir_connection_get(), ++ &xmir_display_config_callback, xmir); ++ ++ display_config = ++ mir_connection_create_display_config(xmir_connection_get()); ++ ++ xmir->root_window_fragments = malloc((display_config->cards[0].max_simultaneous_outputs + 1) * ++ sizeof(xmir_window *)); ++ xmir->root_window_fragments[display_config->cards[0].max_simultaneous_outputs] = NULL; ++ ++ if (xmir->root_window_fragments == NULL) ++ return FALSE; ++ ++ for (i = 0; i < display_config->num_outputs; i++) { ++ xf86OutputPtr xf86output; ++ char name[32]; ++ MirDisplayOutput *mir_output = &display_config->outputs[i]; ++ const char* output_type_str = xmir_get_output_type_str(mir_output); ++ int type_count = i; ++ ++ if (mir_output->type >= 0 && mir_output->type <= mir_display_output_type_edp) ++ type_count = output_type_count[mir_output->type]++; ++ ++ snprintf(name, sizeof name, "%s-%d", output_type_str, type_count); ++ xf86output = xf86OutputCreate(scrn, &xmir_output_funcs, name); ++ ++ xmir_output_populate(xf86output, mir_output); ++ } ++ ++ for (i = 0; i < display_config->cards[0].max_simultaneous_outputs; i++) { ++ struct xmir_crtc *xmir_crtc = malloc(sizeof *xmir_crtc); ++ if (xmir_crtc == NULL) ++ return FALSE; ++ ++ xmir_crtc->xmir = xmir; ++ xmir_crtc->root_fragment = calloc(1, sizeof *xmir_crtc->root_fragment); ++ xmir_crtc->config = display_config; ++ ++ if (xmir_crtc->root_fragment == NULL) ++ return FALSE; ++ ++ xmir->root_window_fragments[i] = xmir_crtc->root_fragment; ++ RegionNull(&xmir_crtc->root_fragment->region); ++ ++ xf86crtc = xf86CrtcCreate(scrn, &crtc_funcs); ++ xf86crtc->driver_private = xmir_crtc; ++ } ++ ++ xf86SetScrnInfoModes(scrn); ++ ++ /* TODO: Use initial Mir state rather than setting up our own */ ++ xf86InitialConfiguration(scrn, TRUE); ++ ++ return TRUE; ++} +--- /dev/null ++++ b/hw/xfree86/xmir/xmir-private.h +@@ -0,0 +1,106 @@ ++/* ++ * Copyright © 2012 Canonical, Inc ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Soft- ++ * ware"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, provided that the above copyright ++ * notice(s) and this permission notice appear in all copies of the Soft- ++ * ware and that both the above copyright notice(s) and this permission ++ * notice appear in supporting documentation. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- ++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY ++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN ++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- ++ * QUENTIAL 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 PERFOR- ++ * MANCE OF THIS SOFTWARE. ++ * ++ * Except as contained in this notice, the name of a copyright holder shall ++ * not be used in advertising or otherwise to promote the sale, use or ++ * other dealings in this Software without prior written authorization of ++ * the copyright holder. ++ * ++ * Authors: ++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com) ++ */ ++ ++#ifndef _XMIR_PRIVATE_H ++#define _XMIR_PRIVATE_H ++ ++#include ++#include "xmir.h" ++#include "xf86str.h" ++#include "list.h" ++#include "scrnintstr.h" ++#include "regionstr.h" ++ ++#define MIR_MAX_BUFFER_AGE 3 ++ ++typedef struct xmir_marshall_handler xmir_marshall_handler; ++ ++struct xmir_screen { ++ ScrnInfoPtr scrn; ++ CreateWindowProcPtr CreateWindow; ++ DestroyWindowProcPtr DestroyWindow; ++ xmir_driver * driver; ++ xmir_marshall_handler *submit_rendering_handler; ++ xmir_marshall_handler *hotplug_event_handler; ++ xmir_marshall_handler *focus_event_handler; ++ struct xorg_list damage_list; ++ struct xmir_window **root_window_fragments; /* NULL terminated array of xmir_window * */ ++ unsigned int dpms_on:1; /* Until Mir is less stupid about DPMS */ ++}; ++ ++struct xmir_window { ++ WindowPtr win; ++ MirSurface *surface; ++ RegionRec region; ++ RegionRec past_damage[MIR_MAX_BUFFER_AGE]; ++ DamagePtr damage; ++ int damage_index; ++ struct xorg_list link_damage; ++ unsigned int has_free_buffer:1; ++ unsigned int damaged:1; ++}; ++ ++MirConnection * ++xmir_connection_get(void); ++ ++xmir_screen * ++xmir_screen_get(ScreenPtr screen); ++ ++xmir_window * ++xmir_window_get(WindowPtr win); ++ ++void ++xmir_window_enable_damage_tracking(xmir_window *xmir_win); ++ ++void ++xmir_window_disable_damage_tracking(xmir_window *xmir_win); ++ ++ ++Bool ++xmir_screen_init_window(ScreenPtr screen, xmir_screen *xmir); ++ ++Bool ++xmir_mode_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir); ++ ++void ++xmir_init_thread_to_eventloop(void); ++ ++xmir_marshall_handler * ++xmir_register_handler(void (*msg_handler)(void *msg), size_t msg_size); ++ ++void ++xmir_post_to_eventloop(xmir_marshall_handler *handler, void *msg); ++ ++void ++xmir_process_from_eventloop(void); ++ ++ #endif /* _MIR_PRIVATE_H */ +--- /dev/null ++++ b/hw/xfree86/xmir/xmir-thread-proxy.c +@@ -0,0 +1,124 @@ ++/* ++ * Copyright © 2012 Canonical, Inc ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Soft- ++ * ware"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, provided that the above copyright ++ * notice(s) and this permission notice appear in all copies of the Soft- ++ * ware and that both the above copyright notice(s) and this permission ++ * notice appear in supporting documentation. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- ++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY ++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN ++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- ++ * QUENTIAL 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 PERFOR- ++ * MANCE OF THIS SOFTWARE. ++ * ++ * Except as contained in this notice, the name of a copyright holder shall ++ * not be used in advertising or otherwise to promote the sale, use or ++ * other dealings in this Software without prior written authorization of ++ * the copyright holder. ++ * ++ * Authors: ++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "xf86.h" ++#include "xmir-private.h" ++ ++struct xmir_marshall_handler { ++ void (*msg_handler)(void *msg); ++ size_t msg_size; ++ char msg[]; ++}; ++ ++static int pipefds[2]; ++ ++static void ++xmir_wakeup_handler(pointer data, int err, pointer read_mask) ++{ ++ if (err >= 0 && FD_ISSET(pipefds[0], (fd_set *)read_mask)) ++ xmir_process_from_eventloop(); ++} ++ ++void ++xmir_init_thread_to_eventloop(void) ++{ ++ int err = pipe(pipefds); ++ if (err == -1) ++ FatalError("[XMIR] Failed to create thread-proxy pipes: %s\n", strerror(errno)); ++ ++ /* Set the read end to not block; we'll pull from this in the event loop ++ * We don't need to care about the write end, as that'll be written to ++ * from its own thread ++ */ ++ fcntl(pipefds[0], F_SETFL, O_NONBLOCK); ++ ++ AddGeneralSocket(pipefds[0]); ++ RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, ++ xmir_wakeup_handler, ++ NULL); ++} ++ ++xmir_marshall_handler * ++xmir_register_handler(void (*msg_handler)(void *msg), size_t msg_size) ++{ ++ xmir_marshall_handler *handler; ++ ++ if (msg_size + sizeof *handler > PIPE_BUF) ++ return NULL; ++ ++ handler = malloc(sizeof *handler + msg_size); ++ if (!handler) ++ return NULL; ++ ++ handler->msg_handler = msg_handler; ++ handler->msg_size = msg_size; ++ return handler; ++} ++ ++void ++xmir_post_to_eventloop(xmir_marshall_handler *handler, void *msg) ++{ ++ ssize_t written; ++ const int total_size = sizeof *handler + handler->msg_size; ++ /* We require the total size to be less than PIPE_BUF to ensure an atomic write */ ++ assert(total_size < PIPE_BUF); ++ ++ memcpy(handler->msg, msg, handler->msg_size); ++ written = write(pipefds[1], handler, total_size); ++ if (written != total_size) ++ xf86Msg(X_ERROR, "[XMIR] Failed to proxy message to mainloop\n"); ++} ++ ++void ++xmir_process_from_eventloop(void) ++{ ++ xmir_marshall_handler handler; ++ void *msg; ++ ++ for (;;) { ++ if (read(pipefds[0], &handler, sizeof handler) < 0) { ++ return; ++ } ++ ++ msg = malloc(handler.msg_size); ++ if(read(pipefds[0], msg, handler.msg_size) == handler.msg_size) ++ (*handler.msg_handler)(msg); ++ free(msg); ++ } ++} ++ +--- /dev/null ++++ b/hw/xfree86/xmir/xmir-window.c +@@ -0,0 +1,343 @@ ++/* ++ * Copyright © 2012 Canonical, Inc ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Soft- ++ * ware"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, provided that the above copyright ++ * notice(s) and this permission notice appear in all copies of the Soft- ++ * ware and that both the above copyright notice(s) and this permission ++ * notice appear in supporting documentation. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- ++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY ++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN ++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- ++ * QUENTIAL 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 PERFOR- ++ * MANCE OF THIS SOFTWARE. ++ * ++ * Except as contained in this notice, the name of a copyright holder shall ++ * not be used in advertising or otherwise to promote the sale, use or ++ * other dealings in this Software without prior written authorization of ++ * the copyright holder. ++ * ++ * Authors: ++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com) ++ */ ++ ++#ifdef HAVE_XORG_CONFIG_H ++#include "xorg-config.h" ++#endif ++#include ++#include "windowstr.h" ++#include "regionstr.h" ++#include "damagestr.h" ++ ++#include "xmir.h" ++#include "xmir-private.h" ++ ++#include "xf86.h" ++ ++#include ++#include ++ ++static DevPrivateKeyRec xmir_window_private_key; ++static const RegionRec xmir_empty_region = { {0, 0, 0, 0}, &RegionBrokenData }; ++ ++xmir_window * ++xmir_window_get(WindowPtr win) ++{ ++ /* The root window is handled specially */ ++ assert(win->parent != NULL); ++ ++ return dixGetPrivate(&win->devPrivates, &xmir_window_private_key); ++} ++ ++_X_EXPORT int ++xmir_window_get_fd(xmir_window *xmir_win) ++{ ++ MirBufferPackage *package; ++ ++ if (mir_platform_type_gbm != mir_surface_get_platform_type(xmir_win->surface)) ++ FatalError("[xmir] Only supported on DRM Mir platform\n"); ++ ++ mir_surface_get_current_buffer(xmir_win->surface, &package); ++ if (package->fd_items != 1) ++ FatalError("[xmir] Unexpected buffer contents from Mir; this is a programming error\n"); ++ ++ return package->fd[0]; ++} ++ ++static void ++xmir_handle_buffer_available(void *ctx) ++{ ++ xmir_screen *xmir; ++ xmir_window *mir_win = *(xmir_window **)ctx; ++ ++ if (mir_win->surface == NULL) ++ return; ++ ++ xmir = xmir_screen_get(xmir_window_to_windowptr(mir_win)->drawable.pScreen); ++ ++ mir_win->has_free_buffer = TRUE; ++ mir_win->damage_index = (mir_win->damage_index + 1) % MIR_MAX_BUFFER_AGE; ++ ++ if (xmir_window_is_dirty(mir_win)) ++ (*xmir->driver->BufferAvailableForWindow)(mir_win, ++ xmir_window_get_dirty(mir_win)); ++} ++ ++static inline int ++index_in_damage_buffer(int current_index, int age) ++{ ++ int index = (current_index - age) % MIR_MAX_BUFFER_AGE; ++ ++ return index < 0 ? MIR_MAX_BUFFER_AGE + index : index; ++} ++ ++static void ++handle_buffer_received(MirSurface *surf, void *ctx) ++{ ++ xmir_window *xmir_win = ctx; ++ ++ xmir_screen *xmir = ++ xmir_screen_get(xmir_window_to_windowptr(xmir_win)->drawable.pScreen); ++ ++ xmir_post_to_eventloop(xmir->submit_rendering_handler, &xmir_win); ++} ++ ++static RegionPtr ++damage_region_for_current_buffer(xmir_window *xmir_win) ++{ ++ MirBufferPackage *package; ++ RegionPtr region; ++ int age; ++ ++ mir_surface_get_current_buffer(xmir_win->surface, &package); ++ age = package->age; ++ ++ region = &xmir_win->past_damage[index_in_damage_buffer(xmir_win->damage_index, age)]; ++ ++ /* As per EGL_EXT_buffer_age, contents are undefined for age == 0 */ ++ if (age == 0) ++ RegionCopy(region, &xmir_win->region); ++ ++ return region; ++} ++ ++/* Submit rendering for @window to Mir ++ * @region is an (optional) damage region, to hint the compositor as to what ++ * region has changed. It can be NULL to indicate the whole window should be ++ * considered dirty. ++ */ ++_X_EXPORT int ++xmir_submit_rendering_for_window(xmir_window *xmir_win, ++ RegionPtr region) ++{ ++ RegionPtr tracking; ++ ++ if (!xmir_screen_get(xmir_win->win->drawable.pScreen)->dpms_on) ++ return Success; ++ ++ xmir_win->has_free_buffer = FALSE; ++ tracking = damage_region_for_current_buffer(xmir_win); ++ mir_surface_swap_buffers(xmir_win->surface, &handle_buffer_received, xmir_win); ++ ++ if (region == NULL) ++ RegionEmpty(tracking); ++ else ++ RegionSubtract(tracking, tracking, region); ++ ++ if (RegionNil(tracking)) ++ xorg_list_del(&xmir_win->link_damage); ++ ++ return Success; ++} ++ ++_X_EXPORT Bool ++xmir_window_has_free_buffer(xmir_window *xmir_win) ++{ ++ return xmir_win->has_free_buffer; ++} ++ ++_X_EXPORT RegionPtr ++xmir_window_get_dirty(xmir_window *xmir_win) ++{ ++ if (xorg_list_is_empty(&xmir_win->link_damage)) ++ return (RegionPtr)&xmir_empty_region; ++ ++ if (xmir_win->damaged) { ++ int i; ++ RegionPtr damage = DamageRegion(xmir_win->damage); ++ RegionIntersect(damage, damage, &xmir_win->region); ++ ++ for (i = 0; i < MIR_MAX_BUFFER_AGE; i++) { ++ RegionUnion(&xmir_win->past_damage[i], ++ &xmir_win->past_damage[i], ++ damage); ++ } ++ ++ DamageEmpty(xmir_win->damage); ++ xmir_win->damaged = 0; ++ } ++ ++ return damage_region_for_current_buffer(xmir_win); ++} ++ ++_X_EXPORT Bool ++xmir_window_is_dirty(xmir_window *xmir_win) ++{ ++ return RegionNotEmpty(xmir_window_get_dirty(xmir_win)); ++} ++ ++_X_EXPORT WindowPtr ++xmir_window_to_windowptr(xmir_window *xmir_win) ++{ ++ return xmir_win->win; ++} ++ ++_X_EXPORT BoxPtr ++xmir_window_get_drawable_region(xmir_window *xmir_win) ++{ ++ return RegionExtents(&xmir_win->region); ++} ++ ++_X_EXPORT int32_t ++xmir_window_get_stride(xmir_window *xmir_win) ++{ ++ MirBufferPackage *package; ++ ++ mir_surface_get_current_buffer(xmir_win->surface, &package); ++ ++ return package->stride; ++} ++ ++static void ++damage_report(DamagePtr damage, RegionPtr region, void *ctx) ++{ ++ xmir_window *xmir_win = ctx; ++ ++ xmir_win->damaged = 1; ++ xorg_list_move(&xmir_win->link_damage, ++ &xmir_screen_get(damage->pScreen)->damage_list); ++} ++ ++static void ++damage_destroy(DamagePtr damage, void *ctx) ++{ ++ xmir_window *xmir_win = ctx; ++ xorg_list_del(&xmir_win->link_damage); ++} ++ ++void ++xmir_window_enable_damage_tracking(xmir_window *xmir_win) ++{ ++ WindowPtr win = xmir_win->win; ++ ++ if (xmir_win->damage != NULL) ++ return; ++ ++ xorg_list_init(&xmir_win->link_damage); ++ xmir_win->damage = DamageCreate(damage_report, damage_destroy, ++ DamageReportNonEmpty, TRUE, ++ win->drawable.pScreen, xmir_win); ++ DamageRegister(&win->drawable, xmir_win->damage); ++ ++ for (int i = 0; i < MIR_MAX_BUFFER_AGE; i++) { ++ RegionNull(&xmir_win->past_damage[i]); ++ } ++ xmir_win->damage_index = 0; ++ xmir_win->damaged = 0; ++} ++ ++void ++xmir_window_disable_damage_tracking(xmir_window *xmir_win) ++{ ++ if (xmir_win->damage != NULL) { ++ DamageUnregister(xmir_win->damage); ++ DamageDestroy(xmir_win->damage); ++ xmir_win->damage = NULL; ++ } ++} ++ ++static Bool ++xmir_create_window(WindowPtr win) ++{ ++ ScreenPtr screen = win->drawable.pScreen; ++ xmir_screen *xmir = xmir_screen_get(screen); ++ Bool ret; ++ ++ screen->CreateWindow = xmir->CreateWindow; ++ ret = (*screen->CreateWindow)(win); ++ screen->CreateWindow = xmir_create_window; ++ ++ /* Until we support rootless operation, we care only for the root ++ * window, which has no parent. ++ */ ++ if (win->parent == NULL) { ++ /* The CRTC setup has already created the root_window_fragments ++ array. We need to hook the root window into it */ ++ for (int i = 0; xmir->root_window_fragments[i] != NULL; i++) { ++ xmir->root_window_fragments[i]->win = win; ++ ++ /* TODO: This creates one Damage tracker per fragment; we only ++ really need one, though */ ++ xmir_window_enable_damage_tracking(xmir->root_window_fragments[i]); ++ } ++ } ++ return ret; ++} ++ ++static Bool ++xmir_destroy_window(WindowPtr win) ++{ ++ ScreenPtr screen = win->drawable.pScreen; ++ xmir_screen *xmir = xmir_screen_get(screen); ++ Bool ret; ++ ++ screen->DestroyWindow = xmir->DestroyWindow; ++ ret = (*screen->DestroyWindow)(win); ++ screen->DestroyWindow = xmir_destroy_window; ++ ++ /* Until we support rootless operation, we care only for the root ++ * window, which has no parent. ++ */ ++ if (win->parent == NULL) { ++ /* Break the link with the root_window_fragments */ ++ for (int i = 0; xmir->root_window_fragments[i] != NULL; i++) { ++ xmir->root_window_fragments[i]->win = NULL; ++ ++ /* We cannot use xmir_window_disable_damage_tracking here because ++ * the Damage extension will also clean it up on window destruction ++ */ ++ xorg_list_del(&xmir->root_window_fragments[i]->link_damage); ++ } ++ } ++ ++ return ret; ++} ++ ++Bool ++xmir_screen_init_window(ScreenPtr screen, xmir_screen *xmir) ++{ ++ if (!dixRegisterPrivateKey(&xmir_window_private_key, PRIVATE_WINDOW, 0)) ++ return FALSE; ++ ++ xmir->CreateWindow = screen->CreateWindow; ++ screen->CreateWindow = xmir_create_window; ++ xmir->DestroyWindow = screen->DestroyWindow; ++ screen->DestroyWindow = xmir_destroy_window; ++ ++ xmir->submit_rendering_handler = ++ xmir_register_handler(&xmir_handle_buffer_available, ++ sizeof (xmir_window *)); ++ if (xmir->submit_rendering_handler == NULL) ++ return FALSE; ++ ++ return TRUE; ++} +--- /dev/null ++++ b/hw/xfree86/xmir/xmir.c +@@ -0,0 +1,263 @@ ++/* ++ * Copyright © 2012 Canonical, Inc ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Soft- ++ * ware"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, provided that the above copyright ++ * notice(s) and this permission notice appear in all copies of the Soft- ++ * ware and that both the above copyright notice(s) and this permission ++ * notice appear in supporting documentation. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- ++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY ++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN ++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- ++ * QUENTIAL 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 PERFOR- ++ * MANCE OF THIS SOFTWARE. ++ * ++ * Except as contained in this notice, the name of a copyright holder shall ++ * not be used in advertising or otherwise to promote the sale, use or ++ * other dealings in this Software without prior written authorization of ++ * the copyright holder. ++ * ++ * Authors: ++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com) ++ */ ++ ++#ifdef HAVE_XORG_CONFIG_H ++#include ++#endif ++ ++#include "xmir.h" ++#include "xmir-private.h" ++ ++#include "list.h" ++#include "xf86.h" ++#include "xf86Crtc.h" ++#include "xf86Priv.h" ++ ++#include ++#include ++ ++#include ++#include ++ ++static DevPrivateKeyRec xmir_screen_private_key; ++/* ++ * We have only a single Mir connection, regardless of how many ++ * drivers load. ++ */ ++static MirConnection *conn; ++ ++MirConnection * ++xmir_connection_get(void) ++{ ++ return conn; ++} ++ ++xmir_screen * ++xmir_screen_get(ScreenPtr screen) ++{ ++ return dixGetPrivate(&screen->devPrivates, &xmir_screen_private_key); ++} ++ ++_X_EXPORT int ++xmir_get_drm_fd(const char *busid) ++{ ++ MirPlatformPackage platform; ++ int i, fd = -1; ++ ++ mir_connection_get_platform(conn, &platform); ++ ++ for (i = 0; i < platform.fd_items; ++i) { ++ char *fd_busid = drmGetBusid(platform.fd[i]); ++ if (!strcasecmp(busid, fd_busid)) ++ fd = platform.fd[i]; ++ drmFreeBusid(fd_busid); ++ } ++ return fd; ++} ++ ++static void ++handle_auth_magic(int status, void *ctx) ++{ ++ int *retVal = ctx; ++ *retVal = status; ++} ++ ++_X_EXPORT int ++xmir_auth_drm_magic(xmir_screen *xmir, uint32_t magic) ++{ ++ int status; ++ mir_wait_for(mir_connection_drm_auth_magic(xmir_connection_get(), ++ magic, ++ &handle_auth_magic, ++ &status)); ++ return status; ++} ++ ++_X_EXPORT xmir_screen * ++xmir_screen_create(ScrnInfoPtr scrn) ++{ ++ xmir_screen *xmir = calloc (1, sizeof *xmir); ++ if (xmir == NULL) ++ return NULL; ++ ++ xmir->scrn = scrn; ++ xmir->dpms_on = TRUE; ++ ++ return xmir; ++} ++ ++_X_EXPORT Bool ++xmir_screen_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir, xmir_driver *driver) ++{ ++ xmir->driver = driver; ++ xorg_list_init(&xmir->damage_list); ++ ++ if (!xmir_mode_pre_init(scrn, xmir)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++static void xmir_handle_focus_event(void *ctx) ++{ ++ Bool new_focus = *(Bool *)ctx; ++ xf86Msg(X_INFO, "[XMir] Handling focus event, new_focus = %s\n", new_focus ? "TRUE" : "FALSE"); ++ ++ /* TODO: Split xf86VTSwitch out so that we don't need to check xf86VTOwner*/ ++ /* TODO: Disable input on startup until we receive a usc ACK */ ++ if (new_focus && !xf86VTOwner()) ++ xf86VTSwitch(); ++ ++ if (!new_focus && xf86VTOwner()) ++ xf86VTSwitch(); ++} ++ ++static void xmir_handle_lifecycle_event(MirConnection *unused, MirLifecycleState state, void *ctx) ++{ ++ (void)unused; ++ xmir_screen *xmir = ctx; ++ Bool new_focus; ++ switch(state) ++ { ++ case mir_lifecycle_state_will_suspend: ++ new_focus = FALSE; ++ break; ++ case mir_lifecycle_state_resumed: ++ new_focus = TRUE; ++ break; ++ default: ++ xf86Msg(X_ERROR, "Received unknown Mir lifetime event\n"); ++ return; ++ } ++ xmir_post_to_eventloop(xmir->focus_event_handler, &new_focus); ++} ++ ++_X_EXPORT Bool ++xmir_screen_init(ScreenPtr screen, xmir_screen *xmir) ++{ ++ if (!dixRegisterPrivateKey(&xmir_screen_private_key, PRIVATE_SCREEN, 0)) ++ return FALSE; ++ dixSetPrivate(&screen->devPrivates, &xmir_screen_private_key, xmir); ++ ++ if (!xmir_screen_init_window(screen, xmir)) ++ return FALSE; ++ ++ if (!xf86_cursors_init(screen, 0,0,0)) ++ xf86Msg(X_WARNING, "xf86Cursor initialisation failed\n"); ++ ++ /* Hook up focus -> VT switch proxy */ ++ xmir->focus_event_handler = ++ xmir_register_handler(&xmir_handle_focus_event, ++ sizeof(Bool)); ++ if (xmir->focus_event_handler == NULL) ++ return FALSE; ++ ++ mir_connection_set_lifecycle_event_callback(xmir_connection_get(), ++ &xmir_handle_lifecycle_event, ++ xmir); ++ ++ return TRUE; ++} ++ ++_X_EXPORT void ++xmir_screen_close(ScreenPtr screen, xmir_screen *xmir) ++{ ++ ++} ++ ++_X_EXPORT void ++xmir_screen_destroy(xmir_screen *xmir) ++{ ++ ++} ++ ++_X_EXPORT void ++xmir_screen_for_each_damaged_window(xmir_screen *xmir, xmir_window_proc callback) ++{ ++ xmir_window *xmir_win, *tmp_win; ++ xorg_list_for_each_entry_safe(xmir_win, tmp_win, &xmir->damage_list, link_damage) { ++ if (xmir_window_has_free_buffer(xmir_win) && ++ xmir_window_is_dirty(xmir_win)) ++ (*callback)(xmir_win, xmir_window_get_dirty(xmir_win)); ++ } ++} ++ ++static MODULESETUPPROTO(xMirSetup); ++static MODULETEARDOWNPROTO(xMirTeardown); ++ ++static XF86ModuleVersionInfo VersRec = { ++ "xmir", ++ MODULEVENDORSTRING, ++ MODINFOSTRING1, ++ MODINFOSTRING2, ++ XORG_VERSION_CURRENT, ++ 1, 0, 0, ++ ABI_CLASS_EXTENSION, ++ ABI_EXTENSION_VERSION, ++ MOD_CLASS_NONE, ++ {0, 0, 0, 0} ++}; ++ ++_X_EXPORT XF86ModuleData xmirModuleData = { &VersRec, xMirSetup, xMirTeardown }; ++ ++static pointer ++xMirSetup(pointer module, pointer opts, int *errmaj, int *errmin) ++{ ++ static Bool setupDone = FALSE; ++ ++ if (setupDone) { ++ if (errmaj) ++ *errmaj = LDR_ONCEONLY; ++ return NULL; ++ } ++ ++ conn = mir_connect_sync(mirSocket, mirID); ++ ++ if (!mir_connection_is_valid(conn)) { ++ if (errmaj) ++ *errmaj = LDR_MODSPECIFIC; ++ FatalError("Failed to connect to Mir: %s\n", ++ mir_connection_get_error_message(conn)); ++ return NULL; ++ } ++ ++ xmir_init_thread_to_eventloop(); ++ ++ setupDone = TRUE; ++ ++ return module; ++} ++ ++static void ++xMirTeardown(pointer module) ++{ ++} +--- /dev/null ++++ b/hw/xfree86/xmir/xmir.h +@@ -0,0 +1,103 @@ ++/* ++ * Copyright © 2012 Canonical, Inc ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Soft- ++ * ware"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, provided that the above copyright ++ * notice(s) and this permission notice appear in all copies of the Soft- ++ * ware and that both the above copyright notice(s) and this permission ++ * notice appear in supporting documentation. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- ++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY ++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN ++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- ++ * QUENTIAL 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 PERFOR- ++ * MANCE OF THIS SOFTWARE. ++ * ++ * Except as contained in this notice, the name of a copyright holder shall ++ * not be used in advertising or otherwise to promote the sale, use or ++ * other dealings in this Software without prior written authorization of ++ * the copyright holder. ++ * ++ * Authors: ++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com) ++ */ ++ ++#ifndef _XMIR_H ++#define _XMIR_H ++ ++#include ++#include ++ ++#include "xf86str.h" ++#include "scrnintstr.h" ++#include "window.h" ++ ++typedef struct xmir_screen xmir_screen; ++typedef struct xmir_window xmir_window; ++ ++typedef void (*xmir_window_proc)(xmir_window *xmir_win, RegionPtr damaged_region); ++ ++#define XMIR_DRIVER_VERSION 1 ++typedef struct { ++ int version; ++ xmir_window_proc BufferAvailableForWindow; ++} xmir_driver; ++ ++_X_EXPORT int ++xmir_get_drm_fd(const char *busid); ++ ++_X_EXPORT int ++xmir_auth_drm_magic(xmir_screen *xmir, uint32_t magic); ++ ++_X_EXPORT xmir_screen * ++xmir_screen_create(ScrnInfoPtr scrn); ++ ++_X_EXPORT Bool ++xmir_screen_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir, xmir_driver *driver); ++ ++_X_EXPORT Bool ++xmir_screen_init(ScreenPtr screen, xmir_screen *xmir); ++ ++_X_EXPORT void ++xmir_screen_close(ScreenPtr screen, xmir_screen *xmir); ++ ++_X_EXPORT void ++xmir_screen_destroy(xmir_screen *xmir); ++ ++_X_EXPORT WindowPtr ++xmir_window_to_windowptr(xmir_window *xmir_win); ++ ++_X_EXPORT int ++xmir_window_get_fd(xmir_window *xmir_win); ++ ++_X_EXPORT int ++xmir_submit_rendering_for_window(xmir_window *xmir_win, ++ RegionPtr region); ++ ++_X_EXPORT Bool ++xmir_window_has_free_buffer(xmir_window *xmir_win); ++ ++_X_EXPORT RegionPtr ++xmir_window_get_dirty(xmir_window *xmir_win); ++ ++_X_EXPORT Bool ++xmir_window_is_dirty(xmir_window *xmir_win); ++ ++_X_EXPORT BoxPtr ++xmir_window_get_drawable_region(xmir_window *xmir_win); ++ ++_X_EXPORT int32_t ++xmir_window_get_stride(xmir_window *xmir_win); ++ ++_X_EXPORT void ++xmir_screen_for_each_damaged_window(xmir_screen *xmir, xmir_window_proc callback); ++ ++#endif /* _XMIR_H */ +--- a/include/list.h ++++ b/include/list.h +@@ -184,6 +184,14 @@ + prev->next = next; + } + ++static inline void ++xorg_list_move(struct xorg_list *entry, struct xorg_list *head) ++{ ++ __xorg_list_del(entry->prev, entry->next); ++ __xorg_list_add(entry, head->prev, head); ++} ++ ++ + /** + * Remove the element from the list it is in. Using this function will reset + * the pointers to/from this element so it is removed from the list. It does +--- a/include/xorg-server.h.in ++++ b/include/xorg-server.h.in +@@ -224,4 +224,7 @@ + /* Use XTrans FD passing support */ + #undef XTRANS_SEND_FDS + ++/* Build XMIR nested server */ ++#undef XMIR ++ + #endif /* _XORG_SERVER_H_ */ +--- a/test/Makefile.am ++++ b/test/Makefile.am +@@ -6,6 +6,9 @@ + # For now, requires xf86 ddx, could be adjusted to use another + SUBDIRS += xi2 + noinst_PROGRAMS += xkb input xtest misc fixes xfree86 hashtabletest os signal-logging touch ++if XMIR ++noinst_PROGRAMS += xmir-thread-proxy ++endif #XMIR + endif + check_LTLIBRARIES = libxservertest.la + +@@ -38,6 +41,8 @@ + signal_logging_LDADD=$(TEST_LDADD) + hashtabletest_LDADD=$(TEST_LDADD) $(top_srcdir)/Xext/hashtable.c + os_LDADD=$(TEST_LDADD) ++xmir_thread_proxy_LDADD=$(TEST_LDADD) $(top_srcdir)/hw/xfree86/xmir/xmir-thread-proxy.c -lpthread ++xmir_thread_proxy_CFLAGS=$(AM_CFLAGS) $(XMIR_CFLAGS) -I$(top_srcdir)/hw/xfree86/xmir -I$(top_srcdir)/hw/xfree86/common + + libxservertest_la_LIBADD = $(XSERVER_LIBS) + if XORG +--- /dev/null ++++ b/test/xmir-thread-proxy.c +@@ -0,0 +1,154 @@ ++/* ++ * Copyright © 2012 Canonical, Inc ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Soft- ++ * ware"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, provided that the above copyright ++ * notice(s) and this permission notice appear in all copies of the Soft- ++ * ware and that both the above copyright notice(s) and this permission ++ * notice appear in supporting documentation. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- ++ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY ++ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN ++ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- ++ * QUENTIAL 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 PERFOR- ++ * MANCE OF THIS SOFTWARE. ++ * ++ * Except as contained in this notice, the name of a copyright holder shall ++ * not be used in advertising or otherwise to promote the sale, use or ++ * other dealings in this Software without prior written authorization of ++ * the copyright holder. ++ * ++ * Authors: ++ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com) ++ */ ++ ++#ifdef HAVE_DIX_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++ ++#include "xmir-private.h" ++ ++struct test_content { ++ int *variable; ++ int value; ++}; ++ ++static void ++_test_callback(void *msg_content) ++{ ++ struct test_content *content = msg_content; ++ *content->variable = content->value; ++} ++ ++static void ++xmir_test_marshall_to_eventloop(void) ++{ ++ xmir_marshall_handler *test_marshaller; ++ struct test_content msg; ++ int check = 0; ++ ++ xmir_init_thread_to_eventloop(); ++ ++ test_marshaller = xmir_register_handler(&_test_callback, sizeof msg); ++ ++ msg.variable = ✓ ++ msg.value = 1; ++ ++ xmir_post_to_eventloop(test_marshaller, &msg); ++ xmir_process_from_eventloop(); ++ ++ assert(check == 1); ++} ++ ++static void ++_racy_test_callback(void *msg_content) ++{ ++ struct test_content *content = msg_content; ++ int new_value = *content->variable + 1; ++ /* Ensure the other threads get to run and see the old value of content->variable */ ++ usleep(100); ++ *content->variable = new_value; ++} ++ ++struct thread_context { ++ xmir_marshall_handler *marshaller; ++ struct test_content *msg; ++}; ++ ++static void * ++_post_racy_msg(void *thread_ctx) ++{ ++ struct thread_context *ctx = thread_ctx; ++ ++ xmir_post_to_eventloop(ctx->marshaller, ctx->msg); ++ ++ return NULL; ++} ++ ++#define NUM_THREADS 10 ++ ++static void ++xmir_test_many_threads_to_eventloop(void) ++{ ++ pthread_t threads[NUM_THREADS]; ++ pthread_attr_t attr; ++ xmir_marshall_handler *test_marshaller; ++ struct thread_context ctx; ++ struct test_content msg; ++ int check = 0, i; ++ ++ pthread_attr_init(&attr); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); ++ ++ xmir_init_thread_to_eventloop(); ++ ++ test_marshaller = xmir_register_handler(&_racy_test_callback, sizeof msg); ++ ++ msg.variable = ✓ ++ ++ ctx.marshaller = test_marshaller; ++ ctx.msg = &msg; ++ ++ for (i = 0; i < NUM_THREADS; i++) { ++ pthread_create(&threads[i], &attr, _post_racy_msg, (void *)&ctx); ++ } ++ ++ pthread_attr_destroy(&attr); ++ ++ for (i = 0; i < NUM_THREADS; i++) { ++ pthread_join(threads[i], NULL); ++ } ++ ++ xmir_process_from_eventloop(); ++ ++ assert(check == NUM_THREADS); ++} ++ ++static void ++xmir_test_refuses_to_marshall_too_large_msg(void) ++{ ++ xmir_init_thread_to_eventloop(); ++ ++ assert(xmir_register_handler(&_test_callback, PIPE_BUF) == NULL); ++} ++ ++int ++main(int argc, char **argv) ++{ ++ xmir_test_marshall_to_eventloop(); ++ xmir_test_many_threads_to_eventloop(); ++ xmir_test_refuses_to_marshall_too_large_msg(); ++}