| 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 | + ¶ms, |
| 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 = ✓ |
| 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 = ✓ |
| 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 | +} |