ODROID-U3 xorg-server debian package fork :
[deb_xorg-server.git] / debian / patches / xmir.patch
... / ...
CommitLineData
1--- a/configure.ac
2+++ b/configure.ac
3@@ -632,6 +632,7 @@ AC_ARG_ENABLE(windowswm, AS_HELP_ST
4 AC_ARG_ENABLE(libdrm, AS_HELP_STRING([--enable-libdrm], [Build Xorg with libdrm support (default: enabled)]), [DRM=$enableval],[DRM=yes])
5 AC_ARG_ENABLE(clientids, AS_HELP_STRING([--disable-clientids], [Build Xorg with client ID tracking (default: enabled)]), [CLIENTIDS=$enableval], [CLIENTIDS=yes])
6 AC_ARG_ENABLE(pciaccess, AS_HELP_STRING([--enable-pciaccess], [Build Xorg with pciaccess library (default: enabled)]), [PCI=$enableval], [PCI=yes])
7+AC_ARG_ENABLE(xmir, AS_HELP_STRING([--enable-xmir], [Build support for nesting in Mir (default: auto)]), [XMIR=$enableval], [XMIR=auto])
8 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])
9 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])
10
11@@ -1334,6 +1335,15 @@ if test "x$XINERAMA" = xyes; then
12 SDK_REQUIRED_MODULES="$SDK_REQUIRED_MODULES $XINERAMAPROTO"
13 fi
14
15+if test "x$XMIR" != xno; then
16+ PKG_CHECK_MODULES([XMIR], [mirclient], [XMIR=yes], [XMIR=no])
17+ AC_SUBST([XMIR_LIBS])
18+ AC_SUBST([XMIR_CFLAGS])
19+ AC_DEFINE(XMIR, 1, [Support Mir nested mode])
20+ SDK_REQUIRED_MODULES="$SDK_REQUIRED_MODULES mirclient"
21+fi
22+AM_CONDITIONAL(XMIR, [test "x$XMIR" = xyes])
23+
24 AM_CONDITIONAL(XACE, [test "x$XACE" = xyes])
25 if test "x$XACE" = xyes; then
26 AC_DEFINE(XACE, 1, [Build X-ACE extension])
27@@ -2510,6 +2520,7 @@ hw/xfree86/utils/Makefile
28 hw/xfree86/utils/man/Makefile
29 hw/xfree86/utils/cvt/Makefile
30 hw/xfree86/utils/gtf/Makefile
31+hw/xfree86/xmir/Makefile
32 hw/dmx/config/Makefile
33 hw/dmx/config/man/Makefile
34 hw/dmx/doc/Makefile
35--- a/hw/xfree86/Makefile.am
36+++ b/hw/xfree86/Makefile.am
37@@ -30,15 +30,20 @@ if INT10MODULE
38 INT10_SUBDIR = int10
39 endif
40
41+if XMIR
42+XMIR_SUBDIR = xmir
43+endif
44+
45 SUBDIRS = common ddc x86emu $(INT10_SUBDIR) os-support parser \
46 ramdac $(VGAHW_SUBDIR) loader modes $(DRI_SUBDIR) \
47 $(DRI2_SUBDIR) . $(VBE_SUBDIR) i2c dixmods \
48- fbdevhw shadowfb exa $(XF86UTILS_SUBDIR) doc man
49+ fbdevhw shadowfb exa $(XF86UTILS_SUBDIR) doc man \
50+ $(XMIR_SUBDIR)
51
52 DIST_SUBDIRS = common ddc i2c x86emu int10 fbdevhw os-support \
53 parser ramdac shadowfb vbe vgahw \
54 loader dixmods dri dri2 exa modes \
55- utils doc man
56+ utils doc man xmir
57
58 bin_PROGRAMS = Xorg
59 nodist_Xorg_SOURCES = sdksyms.c
60--- a/hw/xfree86/common/xf86Config.c
61+++ b/hw/xfree86/common/xf86Config.c
62@@ -118,6 +118,7 @@ static ModuleDefault ModuleDefaults[] =
63 {.name = "fb",.toLoad = TRUE,.load_opt = NULL},
64 {.name = "shadow",.toLoad = TRUE,.load_opt = NULL},
65 #endif
66+ {.name = "xmir", .toLoad = FALSE, .load_opt = NULL},
67 {.name = NULL,.toLoad = FALSE,.load_opt = NULL}
68 };
69
70@@ -260,6 +261,17 @@ xf86ModulelistFromConfig(pointer **optli
71 return NULL;
72 }
73
74+ /*
75+ * Set the xmir module to autoload if requested.
76+ */
77+ if (xorgMir) {
78+ for (i=0 ; ModuleDefaults[i].name != NULL ; i++) {
79+ if (strcmp(ModuleDefaults[i].name, "xmir") == 0) {
80+ ModuleDefaults[i].toLoad = TRUE;
81+ }
82+ }
83+ }
84+
85 if (xf86configptr->conf_modules) {
86 /* Walk the disable list and let people know what we've parsed to
87 * not be loaded
88--- a/hw/xfree86/common/xf86Events.c
89+++ b/hw/xfree86/common/xf86Events.c
90@@ -105,8 +105,6 @@ extern fd_set EnabledDevices;
91 extern void (*xf86OSPMClose) (void);
92 #endif
93
94-static void xf86VTSwitch(void);
95-
96 /*
97 * Allow arbitrary drivers or other XFree86 code to register with our main
98 * Wakeup handler.
99@@ -411,7 +409,7 @@ xf86ReleaseKeys(DeviceIntPtr pDev)
100 * xf86VTSwitch --
101 * Handle requests for switching the vt.
102 */
103-static void
104+_X_EXPORT void
105 xf86VTSwitch(void)
106 {
107 int i;
108@@ -471,7 +469,7 @@ xf86VTSwitch(void)
109
110 xf86AccessLeave(); /* We need this here, otherwise */
111
112- if (!xf86VTSwitchAway()) {
113+ if (!xorgMir && !xf86VTSwitchAway()) {
114 /*
115 * switch failed
116 */
117@@ -530,7 +528,7 @@ xf86VTSwitch(void)
118 }
119 else {
120 DebugF("xf86VTSwitch: Entering\n");
121- if (!xf86VTSwitchTo())
122+ if (!xorgMir && !xf86VTSwitchTo())
123 return;
124
125 #ifdef XF86PM
126--- a/hw/xfree86/common/xf86Globals.c
127+++ b/hw/xfree86/common/xf86Globals.c
128@@ -207,3 +207,6 @@ Bool xf86VidModeAllowNonLocal = FALSE;
129 #endif
130 RootWinPropPtr *xf86RegisteredPropertiesTable = NULL;
131 Bool xorgHWAccess = FALSE;
132+Bool xorgMir = FALSE;
133+const char *mirID = NULL;
134+const char *mirSocket = NULL;
135--- a/hw/xfree86/common/xf86Helper.c
136+++ b/hw/xfree86/common/xf86Helper.c
137@@ -100,7 +100,14 @@ xf86DeleteDriver(int drvIndex)
138 if (xf86DriverList[drvIndex]->module)
139 UnloadModule(xf86DriverList[drvIndex]->module);
140 free(xf86DriverList[drvIndex]);
141- xf86DriverList[drvIndex] = NULL;
142+
143+ /* Compact xf86DriverList array, update xf86NumDrivers */
144+ xf86NumDrivers--;
145+ if(drvIndex != xf86NumDrivers)
146+ memmove(xf86DriverList + drvIndex,
147+ xf86DriverList + drvIndex + 1,
148+ sizeof(DriverPtr) * (xf86NumDrivers - drvIndex));
149+ xf86DriverList = realloc(xf86DriverList, xf86NumDrivers * sizeof(DriverPtr));
150 }
151 }
152
153--- a/hw/xfree86/common/xf86Init.c
154+++ b/hw/xfree86/common/xf86Init.c
155@@ -554,7 +554,7 @@ InitOutput(ScreenInfo * pScreenInfo, int
156 * needed at this early stage.
157 */
158
159- for (i = 0; i < xf86NumDrivers; i++) {
160+ for (i = 0; i < xf86NumDrivers; ) {
161 xorgHWFlags flags = HW_IO;
162
163 if (xf86DriverList[i]->Identify != NULL)
164@@ -565,11 +565,20 @@ InitOutput(ScreenInfo * pScreenInfo, int
165 GET_REQUIRED_HW_INTERFACES,
166 &flags);
167
168+ if (xorgMir &&
169+ (NEED_IO_ENABLED(flags) || !(flags & HW_SKIP_CONSOLE))) {
170+ ErrorF("Driver needs flags %lu, incompatible with nested, deleting.\n", flags);
171+ xf86DeleteDriver(i);
172+ continue;
173+ }
174+
175 if (NEED_IO_ENABLED(flags))
176 want_hw_access = TRUE;
177
178 if (!(flags & HW_SKIP_CONSOLE))
179 xorgHWOpenConsole = TRUE;
180+
181+ i++;
182 }
183
184 if (xorgHWOpenConsole)
185@@ -662,9 +671,13 @@ InitOutput(ScreenInfo * pScreenInfo, int
186 }
187
188 /* Remove (unload) drivers that are not required */
189- for (i = 0; i < xf86NumDrivers; i++)
190- if (xf86DriverList[i] && xf86DriverList[i]->refCount <= 0)
191+ for (i = 0; i < xf86NumDrivers; )
192+ if (xf86DriverList[i] &&
193+ !xf86DriverHasEntities(xf86DriverList[i]) &&
194+ xf86DriverList[i]->refCount <= 0)
195 xf86DeleteDriver(i);
196+ else
197+ i++;
198
199 /*
200 * At this stage we know how many screens there are.
201@@ -1490,6 +1503,17 @@ ddxProcessArgument(int argc, char **argv
202 xf86Info.ShareVTs = TRUE;
203 return 1;
204 }
205+ if (!strcmp(argv[i], "-mir")) {
206+ CHECK_FOR_REQUIRED_ARGUMENT();
207+ mirID = argv[++i];
208+ xorgMir = TRUE;
209+ return 2;
210+ }
211+ if (!strcmp(argv[i], "-mirSocket")) {
212+ CHECK_FOR_REQUIRED_ARGUMENT();
213+ mirSocket = argv[++i];
214+ return 2;
215+ }
216
217 /* OS-specific processing */
218 return xf86ProcessArgument(argc, argv, i);
219@@ -1563,6 +1587,8 @@ ddxUseMsg(void)
220 ErrorF
221 ("-novtswitch don't automatically switch VT at reset & exit\n");
222 ErrorF("-sharevts share VTs with another X server\n");
223+ ErrorF
224+ ("-mir MirID run nested in a Mir compositor with app id MirID\n");
225 /* OS-specific usage */
226 xf86UseMsg();
227 ErrorF("\n");
228--- a/hw/xfree86/common/xf86Priv.h
229+++ b/hw/xfree86/common/xf86Priv.h
230@@ -93,6 +93,9 @@ extern _X_EXPORT Bool xf86AttemptedFallb
231 extern _X_EXPORT const char *xf86VisualNames[];
232 extern _X_EXPORT int xf86Verbose; /* verbosity level */
233 extern _X_EXPORT int xf86LogVerbose; /* log file verbosity level */
234+extern _X_EXPORT Bool xorgMir;
235+extern _X_EXPORT const char *mirID;
236+extern _X_EXPORT const char *mirSocket;
237
238 extern _X_EXPORT RootWinPropPtr *xf86RegisteredPropertiesTable;
239
240@@ -149,6 +152,9 @@ xf86HandlePMEvents(int fd, pointer data)
241 extern _X_EXPORT int (*xf86PMGetEventFromOs) (int fd, pmEvent * events,
242 int num);
243 extern _X_EXPORT pmWait (*xf86PMConfirmEventToOs) (int fd, pmEvent event);
244+extern _X_EXPORT void
245+xf86VTSwitch(void);
246+
247
248 /* xf86Helper.c */
249 extern _X_EXPORT void
250--- a/hw/xfree86/ramdac/xf86Cursor.c
251+++ b/hw/xfree86/ramdac/xf86Cursor.c
252@@ -58,7 +58,12 @@ xf86InitCursor(ScreenPtr pScreen, xf86Cu
253 xf86CursorScreenPtr ScreenPriv;
254 miPointerScreenPtr PointPriv;
255
256- if (!xf86InitHardwareCursor(pScreen, infoPtr))
257+ infoPtr->pScrn = xf86ScreenToScrn(pScreen);
258+
259+ /* If we can't create a hardware cursor don't bother initialising HW cursor support */
260+ if (infoPtr->MaxWidth != 0 &&
261+ infoPtr->MaxHeight != 0 &&
262+ !xf86InitHardwareCursor(pScreen, infoPtr))
263 return FALSE;
264
265 if (!dixRegisterPrivateKey(&xf86CursorScreenKeyRec, PRIVATE_SCREEN, 0))
266--- a/hw/xfree86/ramdac/xf86HWCurs.c
267+++ b/hw/xfree86/ramdac/xf86HWCurs.c
268@@ -114,8 +114,6 @@ xf86InitHardwareCursor(ScreenPtr pScreen
269 infoPtr->RealizeCursor = RealizeCursorInterleave0;
270 }
271
272- infoPtr->pScrn = xf86ScreenToScrn(pScreen);
273-
274 return TRUE;
275 }
276
277--- /dev/null
278+++ b/hw/xfree86/xmir/Makefile.am
279@@ -0,0 +1,26 @@
280+INCLUDES = \
281+ $(XORG_INCS) \
282+ -I$(srcdir)/../ddc \
283+ -I$(srcdir)/../ramdac \
284+ -I$(srcdir)/../i2c \
285+ -I$(srcdir)/../parser \
286+ -I$(srcdir)/../modes
287+
288+libxmir_la_LTLIBRARIES = libxmir.la
289+libxmir_la_CFLAGS = \
290+ -DHAVE_XORG_CONFIG_H \
291+ $(DRI_CFLAGS) \
292+ $(DIX_CFLAGS) $(XORG_CFLAGS) $(LIBDRM_CFLAGS) \
293+ $(XMIR_CFLAGS)
294+
295+libxmir_la_LDFLAGS = -module -avoid-version $(LIBDRM_LIBS) $(XMIR_LIBS)
296+libxmir_ladir = $(moduledir)/extensions
297+libxmir_la_SOURCES = \
298+ xmir.c \
299+ xmir-window.c \
300+ xmir-output.c \
301+ xmir-thread-proxy.c \
302+ xmir.h \
303+ xmir-private.h
304+
305+sdk_HEADERS = xmir.h
306--- /dev/null
307+++ b/hw/xfree86/xmir/xmir-output.c
308@@ -0,0 +1,678 @@
309+/*
310+ * Copyright © 2012 Canonical, Inc
311+ *
312+ * Permission is hereby granted, free of charge, to any person obtaining a
313+ * copy of this software and associated documentation files (the "Soft-
314+ * ware"), to deal in the Software without restriction, including without
315+ * limitation the rights to use, copy, modify, merge, publish, distribute,
316+ * and/or sell copies of the Software, and to permit persons to whom the
317+ * Software is furnished to do so, provided that the above copyright
318+ * notice(s) and this permission notice appear in all copies of the Soft-
319+ * ware and that both the above copyright notice(s) and this permission
320+ * notice appear in supporting documentation.
321+ *
322+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
323+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
324+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
325+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
326+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
327+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
328+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
329+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
330+ * MANCE OF THIS SOFTWARE.
331+ *
332+ * Except as contained in this notice, the name of a copyright holder shall
333+ * not be used in advertising or otherwise to promote the sale, use or
334+ * other dealings in this Software without prior written authorization of
335+ * the copyright holder.
336+ *
337+ * Authors:
338+ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
339+ */
340+
341+#include <stdlib.h>
342+#include <stdio.h>
343+#include <math.h>
344+
345+#include <xorg-config.h>
346+#include "xmir.h"
347+#include "xmir-private.h"
348+#include "xf86Crtc.h"
349+#include "xf86Priv.h"
350+
351+struct xmir_crtc {
352+ xmir_screen *xmir;
353+ xmir_window *root_fragment;
354+ MirDisplayConfiguration *config;
355+};
356+
357+static const char *
358+xmir_mir_dpms_mode_description(MirPowerMode mode)
359+{
360+ switch (mode)
361+ {
362+ case mir_power_mode_on:
363+ return "mir_power_mode_on";
364+ case mir_power_mode_standby:
365+ return "mir_power_mode_standby";
366+ case mir_power_mode_suspend:
367+ return "mir_power_mode_suspend";
368+ case mir_power_mode_off:
369+ return "mir_power_mode_off";
370+ default:
371+ return "OMGUNKNOWN!";
372+ }
373+}
374+
375+static void
376+xmir_crtc_dpms(xf86CrtcPtr crtc, int mode)
377+{
378+ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(crtc->scrn);
379+ struct xmir_crtc *xmir_crtc = crtc->driver_private;
380+
381+ for (int i = 0; i < crtc_cfg->num_output; i++) {
382+ /* If this output should be driven by our "CRTC", set DPMS mode */
383+ MirDisplayOutput *output = crtc_cfg->output[i]->driver_private;
384+ if (crtc_cfg->output[i]->crtc == crtc) {
385+ xf86Msg(X_INFO, "Setting DPMS mode for output %d to %d\n", i, mode);
386+ switch (mode) {
387+ case DPMSModeOn:
388+ output->power_mode = mir_power_mode_on;
389+ xmir_crtc->xmir->dpms_on = TRUE;
390+ break;
391+ case DPMSModeStandby:
392+ output->power_mode = mir_power_mode_standby;
393+ xmir_crtc->xmir->dpms_on = FALSE;
394+ break;
395+ case DPMSModeSuspend:
396+ output->power_mode = mir_power_mode_suspend;
397+ xmir_crtc->xmir->dpms_on = FALSE;
398+ break;
399+ case DPMSModeOff:
400+ output->power_mode = mir_power_mode_off;
401+ xmir_crtc->xmir->dpms_on = FALSE;
402+ break;
403+ }
404+ }
405+ }
406+ mir_wait_for(mir_connection_apply_display_config(xmir_connection_get(),
407+ xmir_crtc->config));
408+}
409+
410+static const char*
411+xmir_get_output_type_str(MirDisplayOutput *mir_output)
412+{
413+ const char *str = "Invalid";
414+
415+ switch(mir_output->type)
416+ {
417+ case mir_display_output_type_vga: str = "VGA"; break;
418+ case mir_display_output_type_dvii: str = "DVI"; break;
419+ case mir_display_output_type_dvid: str = "DVI"; break;
420+ case mir_display_output_type_dvia: str = "DVI"; break;
421+ case mir_display_output_type_composite: str = "Composite"; break;
422+ case mir_display_output_type_svideo: str = "TV"; break;
423+ case mir_display_output_type_lvds: str = "LVDS"; break;
424+ case mir_display_output_type_component: str = "CTV"; break;
425+ case mir_display_output_type_ninepindin: str = "DIN"; break;
426+ case mir_display_output_type_displayport: str = "DP"; break;
427+ case mir_display_output_type_hdmia: str = "HDMI"; break;
428+ case mir_display_output_type_hdmib: str = "HDMI"; break;
429+ case mir_display_output_type_tv: str = "TV"; break;
430+ case mir_display_output_type_edp: str = "eDP"; break;
431+
432+ case mir_display_output_type_unknown: str = "None"; break;
433+ default: break;
434+ }
435+
436+ return str;
437+}
438+
439+static void
440+xmir_output_populate(xf86OutputPtr xf86output, MirDisplayOutput *output)
441+{
442+ /* We can always arbitrarily clone and output */
443+ xf86output->possible_crtcs = 0xffffffff;
444+ xf86output->possible_clones = 0xffffffff;
445+
446+ xf86output->driver_private = output;
447+
448+ xf86output->interlaceAllowed = FALSE;
449+ xf86output->doubleScanAllowed = FALSE;
450+ xf86output->mm_width = output->physical_width_mm;
451+ xf86output->mm_height = output->physical_height_mm;
452+ /* TODO: Subpixel order from Mir */
453+ xf86output->subpixel_order = SubPixelUnknown;
454+}
455+
456+static DisplayModePtr
457+xmir_create_xf86mode(const struct MirDisplayMode *mir_mode)
458+{
459+ DisplayModePtr mode;
460+
461+ mode = xf86CVTMode(mir_mode->horizontal_resolution,
462+ mir_mode->vertical_resolution,
463+ mir_mode->refresh_rate,
464+ FALSE, FALSE);
465+
466+ /*
467+ * And now, because the CVT standard doesn't support such common
468+ * resolutions as 1366x768...
469+ */
470+ mode->VDisplay = mir_mode->vertical_resolution;
471+ mode->HDisplay = mir_mode->horizontal_resolution;
472+
473+ xf86SetModeDefaultName(mode);
474+
475+ return mode;
476+}
477+
478+static void
479+xmir_free_xf86mode(DisplayModePtr mode)
480+{
481+ free(mode->name);
482+ free(mode);
483+}
484+
485+static Bool
486+xmir_set_mode_for_output(MirDisplayOutput *output,
487+ DisplayModePtr mode)
488+{
489+ for (int i = 0; i < output->num_modes; i++) {
490+ Bool modes_equal = FALSE;
491+ DisplayModePtr mir_mode = NULL;
492+ xf86Msg(X_INFO, "Checking against mode (%dx%d)@%.2f\n",
493+ output->modes[i].horizontal_resolution,
494+ output->modes[i].vertical_resolution,
495+ output->modes[i].refresh_rate);
496+
497+ mir_mode = xmir_create_xf86mode(&output->modes[i]);
498+ modes_equal = xf86ModesEqual(mode, mir_mode);
499+ xmir_free_xf86mode(mir_mode);
500+
501+ if (modes_equal) {
502+ output->current_mode = i;
503+ output->used = 1;
504+ xf86Msg(X_INFO, "Matched mode %d\n", i);
505+ return TRUE;
506+ }
507+ }
508+ return FALSE;
509+}
510+
511+static uint32_t
512+xmir_update_outputs_for_crtc(xf86CrtcPtr crtc, DisplayModePtr mode, int x, int y)
513+{
514+ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(crtc->scrn);
515+ uint32_t representative_output_id = mir_display_output_id_invalid;
516+
517+ for (int i = 0; i < crtc_cfg->num_output; i++) {
518+ /* If this output should be driven by our "CRTC", set its mode */
519+ if (crtc_cfg->output[i]->crtc == crtc) {
520+ MirDisplayOutput *output = crtc_cfg->output[i]->driver_private;
521+ xmir_set_mode_for_output(output, mode);
522+ output->position_x = x;
523+ output->position_y = y;
524+ representative_output_id = output->output_id;
525+ }
526+ }
527+ return representative_output_id;
528+}
529+
530+static void
531+xmir_disable_unused_outputs(xf86CrtcPtr crtc)
532+{
533+ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(crtc->scrn);
534+
535+ for (int i = 0; i < crtc_cfg->num_output; i++)
536+ /* If any outputs are no longer associated with a CRTC, disable them */
537+ if (crtc_cfg->output[i]->crtc == NULL)
538+ ((MirDisplayOutput*)crtc_cfg->output[i]->driver_private)->used = 0;
539+}
540+
541+static void
542+xmir_stupid_callback(MirSurface *surf, void *ctx)
543+{
544+}
545+
546+static void
547+xmir_dump_config(MirDisplayConfiguration *config)
548+{
549+ for (int i = 0; i < config->num_outputs; i++)
550+ {
551+ xf86Msg(X_INFO, "Output %d (%s, %s) has mode %d (%d x %d @ %.2f), position (%d,%d), dpms: %s\n",
552+ config->outputs[i].output_id,
553+ config->outputs[i].connected ? "connected" : "disconnected",
554+ config->outputs[i].used ? "enabled" : "disabled",
555+ config->outputs[i].current_mode,
556+ config->outputs[i].used ? config->outputs[i].modes[config->outputs[i].current_mode].horizontal_resolution : 0,
557+ config->outputs[i].used ? config->outputs[i].modes[config->outputs[i].current_mode].vertical_resolution : 0,
558+ config->outputs[i].used ? config->outputs[i].modes[config->outputs[i].current_mode].refresh_rate : 0,
559+ config->outputs[i].position_x,
560+ config->outputs[i].position_y,
561+ xmir_mir_dpms_mode_description(config->outputs[i].power_mode));
562+ for (int m = 0; m < config->outputs[i].num_modes; m++)
563+ {
564+ xf86Msg(X_INFO, " mode %d: (%d x %d @ %.2f)\n",
565+ m,
566+ config->outputs[i].modes[m].horizontal_resolution,
567+
568+ config->outputs[i].modes[m].vertical_resolution,
569+ config->outputs[i].modes[m].refresh_rate);
570+ }
571+ }
572+}
573+
574+static void
575+xmir_update_config(xf86CrtcConfigPtr crtc_cfg)
576+{
577+ MirDisplayConfiguration *new_config;
578+ struct xmir_crtc *xmir_crtc = crtc_cfg->crtc[0]->driver_private;
579+
580+ mir_display_config_destroy(xmir_crtc->config);
581+
582+ new_config = mir_connection_create_display_config(xmir_connection_get());
583+ for (int i = 0; i < crtc_cfg->num_crtc; i++) {
584+ xmir_crtc = crtc_cfg->crtc[i]->driver_private;
585+ xmir_crtc-> config = new_config;
586+ }
587+
588+ if (crtc_cfg->num_output != new_config->num_outputs)
589+ FatalError("[xmir] New Mir config has different number of outputs?");
590+
591+ for (int i = 0; i < crtc_cfg->num_output ; i++) {
592+ /* TODO: Ensure that the order actually matches up */
593+ xmir_output_populate(crtc_cfg->output[i], new_config->outputs + i);
594+ }
595+ xf86Msg(X_INFO, "Recieved updated config from Mir:\n");
596+ xmir_dump_config(new_config);
597+}
598+
599+static void
600+xmir_crtc_surface_created(MirSurface *surface, void *ctx)
601+{
602+ xf86CrtcPtr crtc = ctx;
603+ struct xmir_crtc *xmir_crtc = crtc->driver_private;
604+
605+ if (xmir_crtc->root_fragment->surface != NULL)
606+ mir_surface_release(xmir_crtc->root_fragment->surface, xmir_stupid_callback, NULL);
607+
608+ xmir_crtc->root_fragment->surface = surface;
609+}
610+
611+static Bool
612+xmir_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
613+ Rotation rotation, int x, int y)
614+{
615+ MirSurfaceParameters params = {
616+ .name = "Xorg",
617+ .width = mode->HDisplay,
618+ .height = mode->VDisplay,
619+ .pixel_format = mir_pixel_format_xrgb_8888,
620+ .buffer_usage = mir_buffer_usage_hardware,
621+ .output_id = mir_display_output_id_invalid
622+ };
623+ BoxRec output_bounds = {
624+ .x1 = x,
625+ .y1 = y,
626+ .x2 = x + mode->HDisplay,
627+ .y2 = y + mode->VDisplay
628+ };
629+ struct xmir_crtc *xmir_crtc = crtc->driver_private;
630+ uint32_t output_id = mir_display_output_id_invalid;
631+ const char *error_msg;
632+
633+ if (mode->HDisplay == 0 || mode->VDisplay == 0)
634+ return FALSE;
635+
636+ xf86Msg(X_INFO, "Initial configuration for crtc %p:\n", crtc);
637+ xmir_dump_config(xmir_crtc->config);
638+
639+ xf86Msg(X_INFO, "Setting mode to %dx%d (%.2f)\n", mode->HDisplay, mode->VDisplay, mode->VRefresh);
640+ output_id = xmir_update_outputs_for_crtc(crtc, mode, x, y);
641+ xmir_disable_unused_outputs(crtc);
642+
643+ xf86Msg(X_INFO, "Updated configuration:\n");
644+
645+ xmir_dump_config(xmir_crtc->config);
646+ mir_wait_for(mir_connection_apply_display_config(xmir_connection_get(),
647+ xmir_crtc->config));
648+ error_msg = mir_connection_get_error_message(xmir_connection_get());
649+ if (*error_msg != '\0') {
650+ xf86Msg(X_ERROR, "[xmir] Failed to set new display config: %s\n",
651+ error_msg);
652+ return FALSE;
653+ /* TODO: Restore correct config cache */
654+ }
655+
656+ xf86Msg(X_INFO, "Post-modeset config:\n");
657+ xmir_update_config(XF86_CRTC_CONFIG_PTR(crtc->scrn));
658+
659+ if (output_id == mir_display_output_id_invalid) {
660+ if (xmir_crtc->root_fragment->surface != NULL)
661+ mir_wait_for(mir_surface_release(xmir_crtc->root_fragment->surface, xmir_stupid_callback, NULL));
662+ xmir_crtc->root_fragment->surface = NULL;
663+ return TRUE;
664+ }
665+
666+ params.output_id = output_id;
667+ xf86Msg(X_INFO, "Putting surface on output %d\n", output_id);
668+ mir_wait_for(mir_connection_create_surface(xmir_connection_get(),
669+ &params,
670+ xmir_crtc_surface_created,
671+ crtc));
672+ if (!mir_surface_is_valid(xmir_crtc->root_fragment->surface)) {
673+ xf86Msg(X_ERROR,
674+ "[xmir] Failed to create surface for %dx%d mode: %s\n",
675+ mode->HDisplay, mode->VDisplay,
676+ mir_surface_get_error_message(xmir_crtc->root_fragment->surface));
677+ return FALSE;
678+ }
679+
680+
681+ /* During X server init this will be NULL.
682+ This is fixed up in xmir_window_create */
683+ xmir_crtc->root_fragment->win = xf86ScrnToScreen(crtc->scrn)->root;
684+
685+ RegionInit(&xmir_crtc->root_fragment->region, &output_bounds, 0);
686+ xmir_crtc->root_fragment->has_free_buffer = TRUE;
687+
688+ return TRUE;
689+}
690+
691+static void
692+crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
693+{
694+}
695+
696+static void
697+crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
698+{
699+}
700+
701+static void
702+crtc_show_cursor (xf86CrtcPtr crtc)
703+{
704+}
705+
706+static void
707+crtc_hide_cursor (xf86CrtcPtr crtc)
708+{
709+}
710+
711+static void
712+crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
713+{
714+}
715+
716+static PixmapPtr
717+crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
718+{
719+ return NULL;
720+}
721+
722+static void *
723+crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
724+{
725+ return NULL;
726+}
727+
728+static void
729+crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
730+{
731+}
732+
733+static void
734+xmir_crtc_destroy(xf86CrtcPtr crtc)
735+{
736+ struct xmir_crtc *xmir_crtc = crtc->driver_private;
737+
738+ if (xmir_crtc->root_fragment->surface != NULL)
739+ mir_surface_release(xmir_crtc->root_fragment->surface, NULL, NULL);
740+
741+ free(xmir_crtc);
742+}
743+
744+static const xf86CrtcFuncsRec crtc_funcs = {
745+ .dpms = xmir_crtc_dpms,
746+ .set_mode_major = xmir_crtc_set_mode_major,
747+ .set_cursor_colors = crtc_set_cursor_colors,
748+ .set_cursor_position = crtc_set_cursor_position,
749+ .show_cursor = crtc_show_cursor,
750+ .hide_cursor = crtc_hide_cursor,
751+ .load_cursor_argb = crtc_load_cursor_argb,
752+ .shadow_create = crtc_shadow_create,
753+ .shadow_allocate = crtc_shadow_allocate,
754+ .shadow_destroy = crtc_shadow_destroy,
755+ .destroy = xmir_crtc_destroy,
756+};
757+
758+static void
759+xmir_output_dpms(xf86OutputPtr output, int mode)
760+{
761+ return;
762+}
763+
764+static xf86OutputStatus
765+xmir_output_detect(xf86OutputPtr output)
766+{
767+ MirDisplayOutput *mir_output = output->driver_private;
768+ return mir_output->connected ? XF86OutputStatusConnected : XF86OutputStatusDisconnected;
769+}
770+
771+static Bool
772+xmir_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
773+{
774+ return MODE_OK;
775+}
776+
777+static DisplayModePtr
778+xmir_output_get_modes(xf86OutputPtr xf86output)
779+{
780+ MirDisplayOutput *mir_output = xf86output->driver_private;
781+ DisplayModePtr modes = NULL;
782+
783+ for (int i = 0; i < mir_output->num_modes; i++) {
784+ DisplayModePtr mode = xmir_create_xf86mode(&mir_output->modes[i]);
785+
786+ mode->type = M_T_DRIVER;
787+ if (i == mir_output->preferred_mode)
788+ mode->type |= M_T_PREFERRED;
789+
790+ modes = xf86ModesAdd(modes, mode);
791+ }
792+ /* TODO: Get Mir to send us the EDID blob and add that */
793+
794+ return modes;
795+}
796+
797+static void
798+xmir_output_destroy(xf86OutputPtr xf86output)
799+{
800+ /* The MirDisplayOutput* in driver_private gets cleaned up by
801+ mir_display_config_destroy() */
802+}
803+
804+static const xf86OutputFuncsRec xmir_output_funcs = {
805+ .dpms = xmir_output_dpms,
806+ .detect = xmir_output_detect,
807+ .mode_valid = xmir_output_mode_valid,
808+ .get_modes = xmir_output_get_modes,
809+ .destroy = xmir_output_destroy
810+};
811+
812+
813+struct xmir_visit_set_pixmap_window {
814+ PixmapPtr old, new;
815+};
816+
817+static int
818+xmir_visit_set_window_pixmap(WindowPtr window, pointer data)
819+{
820+ struct xmir_visit_set_pixmap_window *visit = data;
821+
822+ if (window->drawable.pScreen->GetWindowPixmap(window) == visit->old) {
823+ window->drawable.pScreen->SetWindowPixmap(window, visit->new);
824+ return WT_WALKCHILDREN;
825+ }
826+
827+ return WT_DONTWALKCHILDREN;
828+}
829+
830+static void
831+xmir_set_screen_pixmap(PixmapPtr old_front, PixmapPtr new_front)
832+{
833+ struct xmir_visit_set_pixmap_window visit = {
834+ .old = old_front,
835+ .new = new_front
836+ };
837+ (old_front->drawable.pScreen->SetScreenPixmap)(new_front);
838+
839+ TraverseTree(old_front->drawable.pScreen->root, &xmir_visit_set_window_pixmap, &visit);
840+}
841+
842+static Bool
843+xmir_resize(ScrnInfoPtr scrn, int width, int height)
844+{
845+ xf86CrtcConfigPtr crtc_cfg = XF86_CRTC_CONFIG_PTR(scrn);
846+ ScreenPtr screen = xf86ScrnToScreen(scrn);
847+ PixmapPtr old_screen_pixmap, new_screen_pixmap;
848+
849+ if (scrn->virtualX == width && scrn->virtualY == height)
850+ return TRUE;
851+
852+ old_screen_pixmap = screen->GetScreenPixmap(screen);
853+ new_screen_pixmap = screen->CreatePixmap(screen, width, height, scrn->depth,
854+ CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
855+
856+ if (!new_screen_pixmap)
857+ return FALSE;
858+
859+ scrn->virtualX = width;
860+ scrn->virtualY = height;
861+ scrn->displayWidth = width;
862+
863+ for (int i = 0; i < crtc_cfg->num_crtc; i++) {
864+ xf86CrtcPtr crtc = crtc_cfg->crtc[i];
865+
866+ if (!crtc->enabled)
867+ continue;
868+
869+ xmir_crtc_set_mode_major(crtc, &crtc->mode,
870+ crtc->rotation, crtc->x, crtc->y);
871+ }
872+
873+ xmir_set_screen_pixmap(old_screen_pixmap, new_screen_pixmap);
874+ screen->DestroyPixmap(old_screen_pixmap);
875+
876+ xf86_reload_cursors(screen);
877+
878+ return TRUE;
879+}
880+
881+static const xf86CrtcConfigFuncsRec config_funcs = {
882+ xmir_resize
883+};
884+
885+static void
886+xmir_handle_hotplug(void *ctx)
887+{
888+ ScrnInfoPtr scrn = *(ScrnInfoPtr *)ctx;
889+ xf86CrtcConfigPtr crtc_config = XF86_CRTC_CONFIG_PTR(scrn);
890+
891+ if (crtc_config->num_crtc == 0)
892+ FatalError("[xmir] Received hotplug event, but have no CRTCs?\n");
893+
894+ xmir_update_config(crtc_config);
895+
896+ /* Trigger RANDR refresh */
897+ RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
898+}
899+
900+static void
901+xmir_display_config_callback(MirConnection *unused, void *ctx)
902+{
903+ xmir_screen *xmir = ctx;
904+
905+ xmir_post_to_eventloop(xmir->hotplug_event_handler, &xmir->scrn);
906+}
907+
908+Bool
909+xmir_mode_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir)
910+{
911+ int i;
912+ MirDisplayConfiguration *display_config;
913+ xf86CrtcPtr xf86crtc;
914+ int output_type_count[mir_display_output_type_edp + 1];
915+
916+ memset(output_type_count, 0, sizeof output_type_count);
917+
918+ /* Set up CRTC config functions */
919+ xf86CrtcConfigInit(scrn, &config_funcs);
920+
921+ /* We don't scanout of a single surface, so we don't have a scanout limit */
922+ xf86CrtcSetSizeRange(scrn,
923+ 320, 320,
924+ INT16_MAX, INT16_MAX);
925+
926+ /* Hook up hotplug notification */
927+ xmir->hotplug_event_handler =
928+ xmir_register_handler(&xmir_handle_hotplug,
929+ sizeof (ScreenPtr));
930+
931+ mir_connection_set_display_config_change_callback(
932+ xmir_connection_get(),
933+ &xmir_display_config_callback, xmir);
934+
935+ display_config =
936+ mir_connection_create_display_config(xmir_connection_get());
937+
938+ xmir->root_window_fragments = malloc((display_config->cards[0].max_simultaneous_outputs + 1) *
939+ sizeof(xmir_window *));
940+ xmir->root_window_fragments[display_config->cards[0].max_simultaneous_outputs] = NULL;
941+
942+ if (xmir->root_window_fragments == NULL)
943+ return FALSE;
944+
945+ for (i = 0; i < display_config->num_outputs; i++) {
946+ xf86OutputPtr xf86output;
947+ char name[32];
948+ MirDisplayOutput *mir_output = &display_config->outputs[i];
949+ const char* output_type_str = xmir_get_output_type_str(mir_output);
950+ int type_count = i;
951+
952+ if (mir_output->type >= 0 && mir_output->type <= mir_display_output_type_edp)
953+ type_count = output_type_count[mir_output->type]++;
954+
955+ snprintf(name, sizeof name, "%s-%d", output_type_str, type_count);
956+ xf86output = xf86OutputCreate(scrn, &xmir_output_funcs, name);
957+
958+ xmir_output_populate(xf86output, mir_output);
959+ }
960+
961+ for (i = 0; i < display_config->cards[0].max_simultaneous_outputs; i++) {
962+ struct xmir_crtc *xmir_crtc = malloc(sizeof *xmir_crtc);
963+ if (xmir_crtc == NULL)
964+ return FALSE;
965+
966+ xmir_crtc->xmir = xmir;
967+ xmir_crtc->root_fragment = calloc(1, sizeof *xmir_crtc->root_fragment);
968+ xmir_crtc->config = display_config;
969+
970+ if (xmir_crtc->root_fragment == NULL)
971+ return FALSE;
972+
973+ xmir->root_window_fragments[i] = xmir_crtc->root_fragment;
974+ RegionNull(&xmir_crtc->root_fragment->region);
975+
976+ xf86crtc = xf86CrtcCreate(scrn, &crtc_funcs);
977+ xf86crtc->driver_private = xmir_crtc;
978+ }
979+
980+ xf86SetScrnInfoModes(scrn);
981+
982+ /* TODO: Use initial Mir state rather than setting up our own */
983+ xf86InitialConfiguration(scrn, TRUE);
984+
985+ return TRUE;
986+}
987--- /dev/null
988+++ b/hw/xfree86/xmir/xmir-private.h
989@@ -0,0 +1,106 @@
990+/*
991+ * Copyright © 2012 Canonical, Inc
992+ *
993+ * Permission is hereby granted, free of charge, to any person obtaining a
994+ * copy of this software and associated documentation files (the "Soft-
995+ * ware"), to deal in the Software without restriction, including without
996+ * limitation the rights to use, copy, modify, merge, publish, distribute,
997+ * and/or sell copies of the Software, and to permit persons to whom the
998+ * Software is furnished to do so, provided that the above copyright
999+ * notice(s) and this permission notice appear in all copies of the Soft-
1000+ * ware and that both the above copyright notice(s) and this permission
1001+ * notice appear in supporting documentation.
1002+ *
1003+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1004+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
1005+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
1006+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
1007+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
1008+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1009+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1010+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
1011+ * MANCE OF THIS SOFTWARE.
1012+ *
1013+ * Except as contained in this notice, the name of a copyright holder shall
1014+ * not be used in advertising or otherwise to promote the sale, use or
1015+ * other dealings in this Software without prior written authorization of
1016+ * the copyright holder.
1017+ *
1018+ * Authors:
1019+ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
1020+ */
1021+
1022+#ifndef _XMIR_PRIVATE_H
1023+#define _XMIR_PRIVATE_H
1024+
1025+#include <mir_toolkit/mir_client_library.h>
1026+#include "xmir.h"
1027+#include "xf86str.h"
1028+#include "list.h"
1029+#include "scrnintstr.h"
1030+#include "regionstr.h"
1031+
1032+#define MIR_MAX_BUFFER_AGE 3
1033+
1034+typedef struct xmir_marshall_handler xmir_marshall_handler;
1035+
1036+struct xmir_screen {
1037+ ScrnInfoPtr scrn;
1038+ CreateWindowProcPtr CreateWindow;
1039+ DestroyWindowProcPtr DestroyWindow;
1040+ xmir_driver * driver;
1041+ xmir_marshall_handler *submit_rendering_handler;
1042+ xmir_marshall_handler *hotplug_event_handler;
1043+ xmir_marshall_handler *focus_event_handler;
1044+ struct xorg_list damage_list;
1045+ struct xmir_window **root_window_fragments; /* NULL terminated array of xmir_window * */
1046+ unsigned int dpms_on:1; /* Until Mir is less stupid about DPMS */
1047+};
1048+
1049+struct xmir_window {
1050+ WindowPtr win;
1051+ MirSurface *surface;
1052+ RegionRec region;
1053+ RegionRec past_damage[MIR_MAX_BUFFER_AGE];
1054+ DamagePtr damage;
1055+ int damage_index;
1056+ struct xorg_list link_damage;
1057+ unsigned int has_free_buffer:1;
1058+ unsigned int damaged:1;
1059+};
1060+
1061+MirConnection *
1062+xmir_connection_get(void);
1063+
1064+xmir_screen *
1065+xmir_screen_get(ScreenPtr screen);
1066+
1067+xmir_window *
1068+xmir_window_get(WindowPtr win);
1069+
1070+void
1071+xmir_window_enable_damage_tracking(xmir_window *xmir_win);
1072+
1073+void
1074+xmir_window_disable_damage_tracking(xmir_window *xmir_win);
1075+
1076+
1077+Bool
1078+xmir_screen_init_window(ScreenPtr screen, xmir_screen *xmir);
1079+
1080+Bool
1081+xmir_mode_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir);
1082+
1083+void
1084+xmir_init_thread_to_eventloop(void);
1085+
1086+xmir_marshall_handler *
1087+xmir_register_handler(void (*msg_handler)(void *msg), size_t msg_size);
1088+
1089+void
1090+xmir_post_to_eventloop(xmir_marshall_handler *handler, void *msg);
1091+
1092+void
1093+xmir_process_from_eventloop(void);
1094+
1095+ #endif /* _MIR_PRIVATE_H */
1096--- /dev/null
1097+++ b/hw/xfree86/xmir/xmir-thread-proxy.c
1098@@ -0,0 +1,124 @@
1099+/*
1100+ * Copyright © 2012 Canonical, Inc
1101+ *
1102+ * Permission is hereby granted, free of charge, to any person obtaining a
1103+ * copy of this software and associated documentation files (the "Soft-
1104+ * ware"), to deal in the Software without restriction, including without
1105+ * limitation the rights to use, copy, modify, merge, publish, distribute,
1106+ * and/or sell copies of the Software, and to permit persons to whom the
1107+ * Software is furnished to do so, provided that the above copyright
1108+ * notice(s) and this permission notice appear in all copies of the Soft-
1109+ * ware and that both the above copyright notice(s) and this permission
1110+ * notice appear in supporting documentation.
1111+ *
1112+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1113+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
1114+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
1115+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
1116+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
1117+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1118+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1119+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
1120+ * MANCE OF THIS SOFTWARE.
1121+ *
1122+ * Except as contained in this notice, the name of a copyright holder shall
1123+ * not be used in advertising or otherwise to promote the sale, use or
1124+ * other dealings in this Software without prior written authorization of
1125+ * the copyright holder.
1126+ *
1127+ * Authors:
1128+ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
1129+ */
1130+
1131+#include <stdint.h>
1132+#include <string.h>
1133+#include <unistd.h>
1134+#include <fcntl.h>
1135+#include <errno.h>
1136+
1137+#include "xf86.h"
1138+#include "xmir-private.h"
1139+
1140+struct xmir_marshall_handler {
1141+ void (*msg_handler)(void *msg);
1142+ size_t msg_size;
1143+ char msg[];
1144+};
1145+
1146+static int pipefds[2];
1147+
1148+static void
1149+xmir_wakeup_handler(pointer data, int err, pointer read_mask)
1150+{
1151+ if (err >= 0 && FD_ISSET(pipefds[0], (fd_set *)read_mask))
1152+ xmir_process_from_eventloop();
1153+}
1154+
1155+void
1156+xmir_init_thread_to_eventloop(void)
1157+{
1158+ int err = pipe(pipefds);
1159+ if (err == -1)
1160+ FatalError("[XMIR] Failed to create thread-proxy pipes: %s\n", strerror(errno));
1161+
1162+ /* Set the read end to not block; we'll pull from this in the event loop
1163+ * We don't need to care about the write end, as that'll be written to
1164+ * from its own thread
1165+ */
1166+ fcntl(pipefds[0], F_SETFL, O_NONBLOCK);
1167+
1168+ AddGeneralSocket(pipefds[0]);
1169+ RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1170+ xmir_wakeup_handler,
1171+ NULL);
1172+}
1173+
1174+xmir_marshall_handler *
1175+xmir_register_handler(void (*msg_handler)(void *msg), size_t msg_size)
1176+{
1177+ xmir_marshall_handler *handler;
1178+
1179+ if (msg_size + sizeof *handler > PIPE_BUF)
1180+ return NULL;
1181+
1182+ handler = malloc(sizeof *handler + msg_size);
1183+ if (!handler)
1184+ return NULL;
1185+
1186+ handler->msg_handler = msg_handler;
1187+ handler->msg_size = msg_size;
1188+ return handler;
1189+}
1190+
1191+void
1192+xmir_post_to_eventloop(xmir_marshall_handler *handler, void *msg)
1193+{
1194+ ssize_t written;
1195+ const int total_size = sizeof *handler + handler->msg_size;
1196+ /* We require the total size to be less than PIPE_BUF to ensure an atomic write */
1197+ assert(total_size < PIPE_BUF);
1198+
1199+ memcpy(handler->msg, msg, handler->msg_size);
1200+ written = write(pipefds[1], handler, total_size);
1201+ if (written != total_size)
1202+ xf86Msg(X_ERROR, "[XMIR] Failed to proxy message to mainloop\n");
1203+}
1204+
1205+void
1206+xmir_process_from_eventloop(void)
1207+{
1208+ xmir_marshall_handler handler;
1209+ void *msg;
1210+
1211+ for (;;) {
1212+ if (read(pipefds[0], &handler, sizeof handler) < 0) {
1213+ return;
1214+ }
1215+
1216+ msg = malloc(handler.msg_size);
1217+ if(read(pipefds[0], msg, handler.msg_size) == handler.msg_size)
1218+ (*handler.msg_handler)(msg);
1219+ free(msg);
1220+ }
1221+}
1222+
1223--- /dev/null
1224+++ b/hw/xfree86/xmir/xmir-window.c
1225@@ -0,0 +1,343 @@
1226+/*
1227+ * Copyright © 2012 Canonical, Inc
1228+ *
1229+ * Permission is hereby granted, free of charge, to any person obtaining a
1230+ * copy of this software and associated documentation files (the "Soft-
1231+ * ware"), to deal in the Software without restriction, including without
1232+ * limitation the rights to use, copy, modify, merge, publish, distribute,
1233+ * and/or sell copies of the Software, and to permit persons to whom the
1234+ * Software is furnished to do so, provided that the above copyright
1235+ * notice(s) and this permission notice appear in all copies of the Soft-
1236+ * ware and that both the above copyright notice(s) and this permission
1237+ * notice appear in supporting documentation.
1238+ *
1239+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1240+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
1241+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
1242+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
1243+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
1244+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1245+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1246+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
1247+ * MANCE OF THIS SOFTWARE.
1248+ *
1249+ * Except as contained in this notice, the name of a copyright holder shall
1250+ * not be used in advertising or otherwise to promote the sale, use or
1251+ * other dealings in this Software without prior written authorization of
1252+ * the copyright holder.
1253+ *
1254+ * Authors:
1255+ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
1256+ */
1257+
1258+#ifdef HAVE_XORG_CONFIG_H
1259+#include "xorg-config.h"
1260+#endif
1261+#include <xorg-server.h>
1262+#include "windowstr.h"
1263+#include "regionstr.h"
1264+#include "damagestr.h"
1265+
1266+#include "xmir.h"
1267+#include "xmir-private.h"
1268+
1269+#include "xf86.h"
1270+
1271+#include <stdlib.h>
1272+#include <unistd.h>
1273+
1274+static DevPrivateKeyRec xmir_window_private_key;
1275+static const RegionRec xmir_empty_region = { {0, 0, 0, 0}, &RegionBrokenData };
1276+
1277+xmir_window *
1278+xmir_window_get(WindowPtr win)
1279+{
1280+ /* The root window is handled specially */
1281+ assert(win->parent != NULL);
1282+
1283+ return dixGetPrivate(&win->devPrivates, &xmir_window_private_key);
1284+}
1285+
1286+_X_EXPORT int
1287+xmir_window_get_fd(xmir_window *xmir_win)
1288+{
1289+ MirBufferPackage *package;
1290+
1291+ if (mir_platform_type_gbm != mir_surface_get_platform_type(xmir_win->surface))
1292+ FatalError("[xmir] Only supported on DRM Mir platform\n");
1293+
1294+ mir_surface_get_current_buffer(xmir_win->surface, &package);
1295+ if (package->fd_items != 1)
1296+ FatalError("[xmir] Unexpected buffer contents from Mir; this is a programming error\n");
1297+
1298+ return package->fd[0];
1299+}
1300+
1301+static void
1302+xmir_handle_buffer_available(void *ctx)
1303+{
1304+ xmir_screen *xmir;
1305+ xmir_window *mir_win = *(xmir_window **)ctx;
1306+
1307+ if (mir_win->surface == NULL)
1308+ return;
1309+
1310+ xmir = xmir_screen_get(xmir_window_to_windowptr(mir_win)->drawable.pScreen);
1311+
1312+ mir_win->has_free_buffer = TRUE;
1313+ mir_win->damage_index = (mir_win->damage_index + 1) % MIR_MAX_BUFFER_AGE;
1314+
1315+ if (xmir_window_is_dirty(mir_win))
1316+ (*xmir->driver->BufferAvailableForWindow)(mir_win,
1317+ xmir_window_get_dirty(mir_win));
1318+}
1319+
1320+static inline int
1321+index_in_damage_buffer(int current_index, int age)
1322+{
1323+ int index = (current_index - age) % MIR_MAX_BUFFER_AGE;
1324+
1325+ return index < 0 ? MIR_MAX_BUFFER_AGE + index : index;
1326+}
1327+
1328+static void
1329+handle_buffer_received(MirSurface *surf, void *ctx)
1330+{
1331+ xmir_window *xmir_win = ctx;
1332+
1333+ xmir_screen *xmir =
1334+ xmir_screen_get(xmir_window_to_windowptr(xmir_win)->drawable.pScreen);
1335+
1336+ xmir_post_to_eventloop(xmir->submit_rendering_handler, &xmir_win);
1337+}
1338+
1339+static RegionPtr
1340+damage_region_for_current_buffer(xmir_window *xmir_win)
1341+{
1342+ MirBufferPackage *package;
1343+ RegionPtr region;
1344+ int age;
1345+
1346+ mir_surface_get_current_buffer(xmir_win->surface, &package);
1347+ age = package->age;
1348+
1349+ region = &xmir_win->past_damage[index_in_damage_buffer(xmir_win->damage_index, age)];
1350+
1351+ /* As per EGL_EXT_buffer_age, contents are undefined for age == 0 */
1352+ if (age == 0)
1353+ RegionCopy(region, &xmir_win->region);
1354+
1355+ return region;
1356+}
1357+
1358+/* Submit rendering for @window to Mir
1359+ * @region is an (optional) damage region, to hint the compositor as to what
1360+ * region has changed. It can be NULL to indicate the whole window should be
1361+ * considered dirty.
1362+ */
1363+_X_EXPORT int
1364+xmir_submit_rendering_for_window(xmir_window *xmir_win,
1365+ RegionPtr region)
1366+{
1367+ RegionPtr tracking;
1368+
1369+ if (!xmir_screen_get(xmir_win->win->drawable.pScreen)->dpms_on)
1370+ return Success;
1371+
1372+ xmir_win->has_free_buffer = FALSE;
1373+ tracking = damage_region_for_current_buffer(xmir_win);
1374+ mir_surface_swap_buffers(xmir_win->surface, &handle_buffer_received, xmir_win);
1375+
1376+ if (region == NULL)
1377+ RegionEmpty(tracking);
1378+ else
1379+ RegionSubtract(tracking, tracking, region);
1380+
1381+ if (RegionNil(tracking))
1382+ xorg_list_del(&xmir_win->link_damage);
1383+
1384+ return Success;
1385+}
1386+
1387+_X_EXPORT Bool
1388+xmir_window_has_free_buffer(xmir_window *xmir_win)
1389+{
1390+ return xmir_win->has_free_buffer;
1391+}
1392+
1393+_X_EXPORT RegionPtr
1394+xmir_window_get_dirty(xmir_window *xmir_win)
1395+{
1396+ if (xorg_list_is_empty(&xmir_win->link_damage))
1397+ return (RegionPtr)&xmir_empty_region;
1398+
1399+ if (xmir_win->damaged) {
1400+ int i;
1401+ RegionPtr damage = DamageRegion(xmir_win->damage);
1402+ RegionIntersect(damage, damage, &xmir_win->region);
1403+
1404+ for (i = 0; i < MIR_MAX_BUFFER_AGE; i++) {
1405+ RegionUnion(&xmir_win->past_damage[i],
1406+ &xmir_win->past_damage[i],
1407+ damage);
1408+ }
1409+
1410+ DamageEmpty(xmir_win->damage);
1411+ xmir_win->damaged = 0;
1412+ }
1413+
1414+ return damage_region_for_current_buffer(xmir_win);
1415+}
1416+
1417+_X_EXPORT Bool
1418+xmir_window_is_dirty(xmir_window *xmir_win)
1419+{
1420+ return RegionNotEmpty(xmir_window_get_dirty(xmir_win));
1421+}
1422+
1423+_X_EXPORT WindowPtr
1424+xmir_window_to_windowptr(xmir_window *xmir_win)
1425+{
1426+ return xmir_win->win;
1427+}
1428+
1429+_X_EXPORT BoxPtr
1430+xmir_window_get_drawable_region(xmir_window *xmir_win)
1431+{
1432+ return RegionExtents(&xmir_win->region);
1433+}
1434+
1435+_X_EXPORT int32_t
1436+xmir_window_get_stride(xmir_window *xmir_win)
1437+{
1438+ MirBufferPackage *package;
1439+
1440+ mir_surface_get_current_buffer(xmir_win->surface, &package);
1441+
1442+ return package->stride;
1443+}
1444+
1445+static void
1446+damage_report(DamagePtr damage, RegionPtr region, void *ctx)
1447+{
1448+ xmir_window *xmir_win = ctx;
1449+
1450+ xmir_win->damaged = 1;
1451+ xorg_list_move(&xmir_win->link_damage,
1452+ &xmir_screen_get(damage->pScreen)->damage_list);
1453+}
1454+
1455+static void
1456+damage_destroy(DamagePtr damage, void *ctx)
1457+{
1458+ xmir_window *xmir_win = ctx;
1459+ xorg_list_del(&xmir_win->link_damage);
1460+}
1461+
1462+void
1463+xmir_window_enable_damage_tracking(xmir_window *xmir_win)
1464+{
1465+ WindowPtr win = xmir_win->win;
1466+
1467+ if (xmir_win->damage != NULL)
1468+ return;
1469+
1470+ xorg_list_init(&xmir_win->link_damage);
1471+ xmir_win->damage = DamageCreate(damage_report, damage_destroy,
1472+ DamageReportNonEmpty, TRUE,
1473+ win->drawable.pScreen, xmir_win);
1474+ DamageRegister(&win->drawable, xmir_win->damage);
1475+
1476+ for (int i = 0; i < MIR_MAX_BUFFER_AGE; i++) {
1477+ RegionNull(&xmir_win->past_damage[i]);
1478+ }
1479+ xmir_win->damage_index = 0;
1480+ xmir_win->damaged = 0;
1481+}
1482+
1483+void
1484+xmir_window_disable_damage_tracking(xmir_window *xmir_win)
1485+{
1486+ if (xmir_win->damage != NULL) {
1487+ DamageUnregister(xmir_win->damage);
1488+ DamageDestroy(xmir_win->damage);
1489+ xmir_win->damage = NULL;
1490+ }
1491+}
1492+
1493+static Bool
1494+xmir_create_window(WindowPtr win)
1495+{
1496+ ScreenPtr screen = win->drawable.pScreen;
1497+ xmir_screen *xmir = xmir_screen_get(screen);
1498+ Bool ret;
1499+
1500+ screen->CreateWindow = xmir->CreateWindow;
1501+ ret = (*screen->CreateWindow)(win);
1502+ screen->CreateWindow = xmir_create_window;
1503+
1504+ /* Until we support rootless operation, we care only for the root
1505+ * window, which has no parent.
1506+ */
1507+ if (win->parent == NULL) {
1508+ /* The CRTC setup has already created the root_window_fragments
1509+ array. We need to hook the root window into it */
1510+ for (int i = 0; xmir->root_window_fragments[i] != NULL; i++) {
1511+ xmir->root_window_fragments[i]->win = win;
1512+
1513+ /* TODO: This creates one Damage tracker per fragment; we only
1514+ really need one, though */
1515+ xmir_window_enable_damage_tracking(xmir->root_window_fragments[i]);
1516+ }
1517+ }
1518+ return ret;
1519+}
1520+
1521+static Bool
1522+xmir_destroy_window(WindowPtr win)
1523+{
1524+ ScreenPtr screen = win->drawable.pScreen;
1525+ xmir_screen *xmir = xmir_screen_get(screen);
1526+ Bool ret;
1527+
1528+ screen->DestroyWindow = xmir->DestroyWindow;
1529+ ret = (*screen->DestroyWindow)(win);
1530+ screen->DestroyWindow = xmir_destroy_window;
1531+
1532+ /* Until we support rootless operation, we care only for the root
1533+ * window, which has no parent.
1534+ */
1535+ if (win->parent == NULL) {
1536+ /* Break the link with the root_window_fragments */
1537+ for (int i = 0; xmir->root_window_fragments[i] != NULL; i++) {
1538+ xmir->root_window_fragments[i]->win = NULL;
1539+
1540+ /* We cannot use xmir_window_disable_damage_tracking here because
1541+ * the Damage extension will also clean it up on window destruction
1542+ */
1543+ xorg_list_del(&xmir->root_window_fragments[i]->link_damage);
1544+ }
1545+ }
1546+
1547+ return ret;
1548+}
1549+
1550+Bool
1551+xmir_screen_init_window(ScreenPtr screen, xmir_screen *xmir)
1552+{
1553+ if (!dixRegisterPrivateKey(&xmir_window_private_key, PRIVATE_WINDOW, 0))
1554+ return FALSE;
1555+
1556+ xmir->CreateWindow = screen->CreateWindow;
1557+ screen->CreateWindow = xmir_create_window;
1558+ xmir->DestroyWindow = screen->DestroyWindow;
1559+ screen->DestroyWindow = xmir_destroy_window;
1560+
1561+ xmir->submit_rendering_handler =
1562+ xmir_register_handler(&xmir_handle_buffer_available,
1563+ sizeof (xmir_window *));
1564+ if (xmir->submit_rendering_handler == NULL)
1565+ return FALSE;
1566+
1567+ return TRUE;
1568+}
1569--- /dev/null
1570+++ b/hw/xfree86/xmir/xmir.c
1571@@ -0,0 +1,263 @@
1572+/*
1573+ * Copyright © 2012 Canonical, Inc
1574+ *
1575+ * Permission is hereby granted, free of charge, to any person obtaining a
1576+ * copy of this software and associated documentation files (the "Soft-
1577+ * ware"), to deal in the Software without restriction, including without
1578+ * limitation the rights to use, copy, modify, merge, publish, distribute,
1579+ * and/or sell copies of the Software, and to permit persons to whom the
1580+ * Software is furnished to do so, provided that the above copyright
1581+ * notice(s) and this permission notice appear in all copies of the Soft-
1582+ * ware and that both the above copyright notice(s) and this permission
1583+ * notice appear in supporting documentation.
1584+ *
1585+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1586+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
1587+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
1588+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
1589+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
1590+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1591+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1592+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
1593+ * MANCE OF THIS SOFTWARE.
1594+ *
1595+ * Except as contained in this notice, the name of a copyright holder shall
1596+ * not be used in advertising or otherwise to promote the sale, use or
1597+ * other dealings in this Software without prior written authorization of
1598+ * the copyright holder.
1599+ *
1600+ * Authors:
1601+ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
1602+ */
1603+
1604+#ifdef HAVE_XORG_CONFIG_H
1605+#include <xorg-config.h>
1606+#endif
1607+
1608+#include "xmir.h"
1609+#include "xmir-private.h"
1610+
1611+#include "list.h"
1612+#include "xf86.h"
1613+#include "xf86Crtc.h"
1614+#include "xf86Priv.h"
1615+
1616+#include <xf86drm.h>
1617+#include <string.h>
1618+
1619+#include <mir_toolkit/mir_client_library.h>
1620+#include <mir_toolkit/mir_client_library_drm.h>
1621+
1622+static DevPrivateKeyRec xmir_screen_private_key;
1623+/*
1624+ * We have only a single Mir connection, regardless of how many
1625+ * drivers load.
1626+ */
1627+static MirConnection *conn;
1628+
1629+MirConnection *
1630+xmir_connection_get(void)
1631+{
1632+ return conn;
1633+}
1634+
1635+xmir_screen *
1636+xmir_screen_get(ScreenPtr screen)
1637+{
1638+ return dixGetPrivate(&screen->devPrivates, &xmir_screen_private_key);
1639+}
1640+
1641+_X_EXPORT int
1642+xmir_get_drm_fd(const char *busid)
1643+{
1644+ MirPlatformPackage platform;
1645+ int i, fd = -1;
1646+
1647+ mir_connection_get_platform(conn, &platform);
1648+
1649+ for (i = 0; i < platform.fd_items; ++i) {
1650+ char *fd_busid = drmGetBusid(platform.fd[i]);
1651+ if (!strcasecmp(busid, fd_busid))
1652+ fd = platform.fd[i];
1653+ drmFreeBusid(fd_busid);
1654+ }
1655+ return fd;
1656+}
1657+
1658+static void
1659+handle_auth_magic(int status, void *ctx)
1660+{
1661+ int *retVal = ctx;
1662+ *retVal = status;
1663+}
1664+
1665+_X_EXPORT int
1666+xmir_auth_drm_magic(xmir_screen *xmir, uint32_t magic)
1667+{
1668+ int status;
1669+ mir_wait_for(mir_connection_drm_auth_magic(xmir_connection_get(),
1670+ magic,
1671+ &handle_auth_magic,
1672+ &status));
1673+ return status;
1674+}
1675+
1676+_X_EXPORT xmir_screen *
1677+xmir_screen_create(ScrnInfoPtr scrn)
1678+{
1679+ xmir_screen *xmir = calloc (1, sizeof *xmir);
1680+ if (xmir == NULL)
1681+ return NULL;
1682+
1683+ xmir->scrn = scrn;
1684+ xmir->dpms_on = TRUE;
1685+
1686+ return xmir;
1687+}
1688+
1689+_X_EXPORT Bool
1690+xmir_screen_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir, xmir_driver *driver)
1691+{
1692+ xmir->driver = driver;
1693+ xorg_list_init(&xmir->damage_list);
1694+
1695+ if (!xmir_mode_pre_init(scrn, xmir))
1696+ return FALSE;
1697+
1698+ return TRUE;
1699+}
1700+
1701+static void xmir_handle_focus_event(void *ctx)
1702+{
1703+ Bool new_focus = *(Bool *)ctx;
1704+ xf86Msg(X_INFO, "[XMir] Handling focus event, new_focus = %s\n", new_focus ? "TRUE" : "FALSE");
1705+
1706+ /* TODO: Split xf86VTSwitch out so that we don't need to check xf86VTOwner*/
1707+ /* TODO: Disable input on startup until we receive a usc ACK */
1708+ if (new_focus && !xf86VTOwner())
1709+ xf86VTSwitch();
1710+
1711+ if (!new_focus && xf86VTOwner())
1712+ xf86VTSwitch();
1713+}
1714+
1715+static void xmir_handle_lifecycle_event(MirConnection *unused, MirLifecycleState state, void *ctx)
1716+{
1717+ (void)unused;
1718+ xmir_screen *xmir = ctx;
1719+ Bool new_focus;
1720+ switch(state)
1721+ {
1722+ case mir_lifecycle_state_will_suspend:
1723+ new_focus = FALSE;
1724+ break;
1725+ case mir_lifecycle_state_resumed:
1726+ new_focus = TRUE;
1727+ break;
1728+ default:
1729+ xf86Msg(X_ERROR, "Received unknown Mir lifetime event\n");
1730+ return;
1731+ }
1732+ xmir_post_to_eventloop(xmir->focus_event_handler, &new_focus);
1733+}
1734+
1735+_X_EXPORT Bool
1736+xmir_screen_init(ScreenPtr screen, xmir_screen *xmir)
1737+{
1738+ if (!dixRegisterPrivateKey(&xmir_screen_private_key, PRIVATE_SCREEN, 0))
1739+ return FALSE;
1740+ dixSetPrivate(&screen->devPrivates, &xmir_screen_private_key, xmir);
1741+
1742+ if (!xmir_screen_init_window(screen, xmir))
1743+ return FALSE;
1744+
1745+ if (!xf86_cursors_init(screen, 0,0,0))
1746+ xf86Msg(X_WARNING, "xf86Cursor initialisation failed\n");
1747+
1748+ /* Hook up focus -> VT switch proxy */
1749+ xmir->focus_event_handler =
1750+ xmir_register_handler(&xmir_handle_focus_event,
1751+ sizeof(Bool));
1752+ if (xmir->focus_event_handler == NULL)
1753+ return FALSE;
1754+
1755+ mir_connection_set_lifecycle_event_callback(xmir_connection_get(),
1756+ &xmir_handle_lifecycle_event,
1757+ xmir);
1758+
1759+ return TRUE;
1760+}
1761+
1762+_X_EXPORT void
1763+xmir_screen_close(ScreenPtr screen, xmir_screen *xmir)
1764+{
1765+
1766+}
1767+
1768+_X_EXPORT void
1769+xmir_screen_destroy(xmir_screen *xmir)
1770+{
1771+
1772+}
1773+
1774+_X_EXPORT void
1775+xmir_screen_for_each_damaged_window(xmir_screen *xmir, xmir_window_proc callback)
1776+{
1777+ xmir_window *xmir_win, *tmp_win;
1778+ xorg_list_for_each_entry_safe(xmir_win, tmp_win, &xmir->damage_list, link_damage) {
1779+ if (xmir_window_has_free_buffer(xmir_win) &&
1780+ xmir_window_is_dirty(xmir_win))
1781+ (*callback)(xmir_win, xmir_window_get_dirty(xmir_win));
1782+ }
1783+}
1784+
1785+static MODULESETUPPROTO(xMirSetup);
1786+static MODULETEARDOWNPROTO(xMirTeardown);
1787+
1788+static XF86ModuleVersionInfo VersRec = {
1789+ "xmir",
1790+ MODULEVENDORSTRING,
1791+ MODINFOSTRING1,
1792+ MODINFOSTRING2,
1793+ XORG_VERSION_CURRENT,
1794+ 1, 0, 0,
1795+ ABI_CLASS_EXTENSION,
1796+ ABI_EXTENSION_VERSION,
1797+ MOD_CLASS_NONE,
1798+ {0, 0, 0, 0}
1799+};
1800+
1801+_X_EXPORT XF86ModuleData xmirModuleData = { &VersRec, xMirSetup, xMirTeardown };
1802+
1803+static pointer
1804+xMirSetup(pointer module, pointer opts, int *errmaj, int *errmin)
1805+{
1806+ static Bool setupDone = FALSE;
1807+
1808+ if (setupDone) {
1809+ if (errmaj)
1810+ *errmaj = LDR_ONCEONLY;
1811+ return NULL;
1812+ }
1813+
1814+ conn = mir_connect_sync(mirSocket, mirID);
1815+
1816+ if (!mir_connection_is_valid(conn)) {
1817+ if (errmaj)
1818+ *errmaj = LDR_MODSPECIFIC;
1819+ FatalError("Failed to connect to Mir: %s\n",
1820+ mir_connection_get_error_message(conn));
1821+ return NULL;
1822+ }
1823+
1824+ xmir_init_thread_to_eventloop();
1825+
1826+ setupDone = TRUE;
1827+
1828+ return module;
1829+}
1830+
1831+static void
1832+xMirTeardown(pointer module)
1833+{
1834+}
1835--- /dev/null
1836+++ b/hw/xfree86/xmir/xmir.h
1837@@ -0,0 +1,103 @@
1838+/*
1839+ * Copyright © 2012 Canonical, Inc
1840+ *
1841+ * Permission is hereby granted, free of charge, to any person obtaining a
1842+ * copy of this software and associated documentation files (the "Soft-
1843+ * ware"), to deal in the Software without restriction, including without
1844+ * limitation the rights to use, copy, modify, merge, publish, distribute,
1845+ * and/or sell copies of the Software, and to permit persons to whom the
1846+ * Software is furnished to do so, provided that the above copyright
1847+ * notice(s) and this permission notice appear in all copies of the Soft-
1848+ * ware and that both the above copyright notice(s) and this permission
1849+ * notice appear in supporting documentation.
1850+ *
1851+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1852+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
1853+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
1854+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
1855+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
1856+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1857+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1858+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
1859+ * MANCE OF THIS SOFTWARE.
1860+ *
1861+ * Except as contained in this notice, the name of a copyright holder shall
1862+ * not be used in advertising or otherwise to promote the sale, use or
1863+ * other dealings in this Software without prior written authorization of
1864+ * the copyright holder.
1865+ *
1866+ * Authors:
1867+ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
1868+ */
1869+
1870+#ifndef _XMIR_H
1871+#define _XMIR_H
1872+
1873+#include <stdint.h>
1874+#include <mir_toolkit/mir_client_library.h>
1875+
1876+#include "xf86str.h"
1877+#include "scrnintstr.h"
1878+#include "window.h"
1879+
1880+typedef struct xmir_screen xmir_screen;
1881+typedef struct xmir_window xmir_window;
1882+
1883+typedef void (*xmir_window_proc)(xmir_window *xmir_win, RegionPtr damaged_region);
1884+
1885+#define XMIR_DRIVER_VERSION 1
1886+typedef struct {
1887+ int version;
1888+ xmir_window_proc BufferAvailableForWindow;
1889+} xmir_driver;
1890+
1891+_X_EXPORT int
1892+xmir_get_drm_fd(const char *busid);
1893+
1894+_X_EXPORT int
1895+xmir_auth_drm_magic(xmir_screen *xmir, uint32_t magic);
1896+
1897+_X_EXPORT xmir_screen *
1898+xmir_screen_create(ScrnInfoPtr scrn);
1899+
1900+_X_EXPORT Bool
1901+xmir_screen_pre_init(ScrnInfoPtr scrn, xmir_screen *xmir, xmir_driver *driver);
1902+
1903+_X_EXPORT Bool
1904+xmir_screen_init(ScreenPtr screen, xmir_screen *xmir);
1905+
1906+_X_EXPORT void
1907+xmir_screen_close(ScreenPtr screen, xmir_screen *xmir);
1908+
1909+_X_EXPORT void
1910+xmir_screen_destroy(xmir_screen *xmir);
1911+
1912+_X_EXPORT WindowPtr
1913+xmir_window_to_windowptr(xmir_window *xmir_win);
1914+
1915+_X_EXPORT int
1916+xmir_window_get_fd(xmir_window *xmir_win);
1917+
1918+_X_EXPORT int
1919+xmir_submit_rendering_for_window(xmir_window *xmir_win,
1920+ RegionPtr region);
1921+
1922+_X_EXPORT Bool
1923+xmir_window_has_free_buffer(xmir_window *xmir_win);
1924+
1925+_X_EXPORT RegionPtr
1926+xmir_window_get_dirty(xmir_window *xmir_win);
1927+
1928+_X_EXPORT Bool
1929+xmir_window_is_dirty(xmir_window *xmir_win);
1930+
1931+_X_EXPORT BoxPtr
1932+xmir_window_get_drawable_region(xmir_window *xmir_win);
1933+
1934+_X_EXPORT int32_t
1935+xmir_window_get_stride(xmir_window *xmir_win);
1936+
1937+_X_EXPORT void
1938+xmir_screen_for_each_damaged_window(xmir_screen *xmir, xmir_window_proc callback);
1939+
1940+#endif /* _XMIR_H */
1941--- a/include/list.h
1942+++ b/include/list.h
1943@@ -184,6 +184,14 @@ __xorg_list_del(struct xorg_list *prev,
1944 prev->next = next;
1945 }
1946
1947+static inline void
1948+xorg_list_move(struct xorg_list *entry, struct xorg_list *head)
1949+{
1950+ __xorg_list_del(entry->prev, entry->next);
1951+ __xorg_list_add(entry, head->prev, head);
1952+}
1953+
1954+
1955 /**
1956 * Remove the element from the list it is in. Using this function will reset
1957 * the pointers to/from this element so it is removed from the list. It does
1958--- a/include/xorg-server.h.in
1959+++ b/include/xorg-server.h.in
1960@@ -224,4 +224,7 @@
1961 /* Use XTrans FD passing support */
1962 #undef XTRANS_SEND_FDS
1963
1964+/* Build XMIR nested server */
1965+#undef XMIR
1966+
1967 #endif /* _XORG_SERVER_H_ */
1968--- a/test/Makefile.am
1969+++ b/test/Makefile.am
1970@@ -6,6 +6,9 @@ if XORG
1971 # For now, requires xf86 ddx, could be adjusted to use another
1972 SUBDIRS += xi2
1973 noinst_PROGRAMS += xkb input xtest misc fixes xfree86 hashtabletest os signal-logging touch
1974+if XMIR
1975+noinst_PROGRAMS += xmir-thread-proxy
1976+endif #XMIR
1977 endif
1978 check_LTLIBRARIES = libxservertest.la
1979
1980@@ -38,6 +41,8 @@ touch_LDADD=$(TEST_LDADD)
1981 signal_logging_LDADD=$(TEST_LDADD)
1982 hashtabletest_LDADD=$(TEST_LDADD) $(top_srcdir)/Xext/hashtable.c
1983 os_LDADD=$(TEST_LDADD)
1984+xmir_thread_proxy_LDADD=$(TEST_LDADD) $(top_srcdir)/hw/xfree86/xmir/xmir-thread-proxy.c -lpthread
1985+xmir_thread_proxy_CFLAGS=$(AM_CFLAGS) $(XMIR_CFLAGS) -I$(top_srcdir)/hw/xfree86/xmir -I$(top_srcdir)/hw/xfree86/common
1986
1987 libxservertest_la_LIBADD = $(XSERVER_LIBS)
1988 if XORG
1989--- /dev/null
1990+++ b/test/xmir-thread-proxy.c
1991@@ -0,0 +1,154 @@
1992+/*
1993+ * Copyright © 2012 Canonical, Inc
1994+ *
1995+ * Permission is hereby granted, free of charge, to any person obtaining a
1996+ * copy of this software and associated documentation files (the "Soft-
1997+ * ware"), to deal in the Software without restriction, including without
1998+ * limitation the rights to use, copy, modify, merge, publish, distribute,
1999+ * and/or sell copies of the Software, and to permit persons to whom the
2000+ * Software is furnished to do so, provided that the above copyright
2001+ * notice(s) and this permission notice appear in all copies of the Soft-
2002+ * ware and that both the above copyright notice(s) and this permission
2003+ * notice appear in supporting documentation.
2004+ *
2005+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2006+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
2007+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
2008+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
2009+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
2010+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2011+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2012+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
2013+ * MANCE OF THIS SOFTWARE.
2014+ *
2015+ * Except as contained in this notice, the name of a copyright holder shall
2016+ * not be used in advertising or otherwise to promote the sale, use or
2017+ * other dealings in this Software without prior written authorization of
2018+ * the copyright holder.
2019+ *
2020+ * Authors:
2021+ * Christopher James Halse Rogers (christopher.halse.rogers@canonical.com)
2022+ */
2023+
2024+#ifdef HAVE_DIX_CONFIG_H
2025+#include <dix-config.h>
2026+#endif
2027+
2028+#include <stdio.h>
2029+#include <stdlib.h>
2030+#include <pthread.h>
2031+#include <unistd.h>
2032+
2033+#include "xmir-private.h"
2034+
2035+struct test_content {
2036+ int *variable;
2037+ int value;
2038+};
2039+
2040+static void
2041+_test_callback(void *msg_content)
2042+{
2043+ struct test_content *content = msg_content;
2044+ *content->variable = content->value;
2045+}
2046+
2047+static void
2048+xmir_test_marshall_to_eventloop(void)
2049+{
2050+ xmir_marshall_handler *test_marshaller;
2051+ struct test_content msg;
2052+ int check = 0;
2053+
2054+ xmir_init_thread_to_eventloop();
2055+
2056+ test_marshaller = xmir_register_handler(&_test_callback, sizeof msg);
2057+
2058+ msg.variable = &check;
2059+ msg.value = 1;
2060+
2061+ xmir_post_to_eventloop(test_marshaller, &msg);
2062+ xmir_process_from_eventloop();
2063+
2064+ assert(check == 1);
2065+}
2066+
2067+static void
2068+_racy_test_callback(void *msg_content)
2069+{
2070+ struct test_content *content = msg_content;
2071+ int new_value = *content->variable + 1;
2072+ /* Ensure the other threads get to run and see the old value of content->variable */
2073+ usleep(100);
2074+ *content->variable = new_value;
2075+}
2076+
2077+struct thread_context {
2078+ xmir_marshall_handler *marshaller;
2079+ struct test_content *msg;
2080+};
2081+
2082+static void *
2083+_post_racy_msg(void *thread_ctx)
2084+{
2085+ struct thread_context *ctx = thread_ctx;
2086+
2087+ xmir_post_to_eventloop(ctx->marshaller, ctx->msg);
2088+
2089+ return NULL;
2090+}
2091+
2092+#define NUM_THREADS 10
2093+
2094+static void
2095+xmir_test_many_threads_to_eventloop(void)
2096+{
2097+ pthread_t threads[NUM_THREADS];
2098+ pthread_attr_t attr;
2099+ xmir_marshall_handler *test_marshaller;
2100+ struct thread_context ctx;
2101+ struct test_content msg;
2102+ int check = 0, i;
2103+
2104+ pthread_attr_init(&attr);
2105+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
2106+
2107+ xmir_init_thread_to_eventloop();
2108+
2109+ test_marshaller = xmir_register_handler(&_racy_test_callback, sizeof msg);
2110+
2111+ msg.variable = &check;
2112+
2113+ ctx.marshaller = test_marshaller;
2114+ ctx.msg = &msg;
2115+
2116+ for (i = 0; i < NUM_THREADS; i++) {
2117+ pthread_create(&threads[i], &attr, _post_racy_msg, (void *)&ctx);
2118+ }
2119+
2120+ pthread_attr_destroy(&attr);
2121+
2122+ for (i = 0; i < NUM_THREADS; i++) {
2123+ pthread_join(threads[i], NULL);
2124+ }
2125+
2126+ xmir_process_from_eventloop();
2127+
2128+ assert(check == NUM_THREADS);
2129+}
2130+
2131+static void
2132+xmir_test_refuses_to_marshall_too_large_msg(void)
2133+{
2134+ xmir_init_thread_to_eventloop();
2135+
2136+ assert(xmir_register_handler(&_test_callback, PIPE_BUF) == NULL);
2137+}
2138+
2139+int
2140+main(int argc, char **argv)
2141+{
2142+ xmir_test_marshall_to_eventloop();
2143+ xmir_test_many_threads_to_eventloop();
2144+ xmir_test_refuses_to_marshall_too_large_msg();
2145+}