/* * Copyright (c) 1999-2003 by The XFree86 Project, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of the copyright holder(s) * and author(s) shall not be used in advertising or otherwise to promote * the sale, use or other dealings in this Software without prior written * authorization from the copyright holder(s) and author(s). */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include #include "misc.h" #include "os.h" #include "extinit.h" #ifdef XF86VIDMODE #include "randrstr.h" #include "vidmodestr.h" #include "xwayland-screen.h" #include "xwayland-vidmode.h" static DevPrivateKeyRec xwlVidModePrivateKeyRec; #define xwlVidModePrivateKey (&xwlVidModePrivateKeyRec) /* Taken from xrandr, h sync frequency in KHz */ static double mode_hsync(const xRRModeInfo *mode_info) { double rate; if (mode_info->hTotal) rate = (double) mode_info->dotClock / (double) mode_info->hTotal; else rate = 0.0; return rate / 1000.0; } /* Taken from xrandr, v refresh frequency in Hz */ static double mode_refresh(const xRRModeInfo *mode_info) { double rate; double vTotal = mode_info->vTotal; if (mode_info->modeFlags & RR_DoubleScan) vTotal *= 2.0; if (mode_info->modeFlags & RR_Interlace) vTotal /= 2.0; if (mode_info->hTotal > 0.0 && vTotal > 0.0) rate = ((double) mode_info->dotClock / ((double) mode_info->hTotal * (double) vTotal)); else rate = 0.0; return rate; } static void xwlRRModeToDisplayMode(RRModePtr rrmode, DisplayModePtr mode) { const xRRModeInfo *mode_info = &rrmode->mode; mode->next = mode; mode->prev = mode; mode->name = ""; mode->VScan = 1; mode->Private = NULL; mode->HDisplay = mode_info->width; mode->HSyncStart = mode_info->hSyncStart; mode->HSyncEnd = mode_info->hSyncEnd; mode->HTotal = mode_info->hTotal; mode->HSkew = mode_info->hSkew; mode->VDisplay = mode_info->height; mode->VSyncStart = mode_info->vSyncStart; mode->VSyncEnd = mode_info->vSyncEnd; mode->VTotal = mode_info->vTotal; mode->Flags = mode_info->modeFlags; mode->Clock = mode_info->dotClock / 1000.0; mode->VRefresh = mode_refresh(mode_info); /* Or RRVerticalRefresh() */ mode->HSync = mode_hsync(mode_info); } static RRModePtr xwlVidModeGetRRMode(ScreenPtr pScreen, int32_t width, int32_t height) { struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); if (!xwl_output) return NULL; return xwl_output_find_mode(xwl_output, width, height); } static RRModePtr xwlVidModeGetCurrentRRMode(ScreenPtr pScreen) { struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); struct xwl_emulated_mode *emulated_mode; if (!xwl_output) return NULL; emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, GetCurrentClient()); if (emulated_mode) { return xwl_output_find_mode(xwl_output, emulated_mode->width, emulated_mode->height); } else { return xwl_output_find_mode(xwl_output, -1, -1); } } static Bool xwlVidModeGetCurrentModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock) { DisplayModePtr pMod; RRModePtr rrmode; pMod = dixLookupPrivate(&pScreen->devPrivates, xwlVidModePrivateKey); if (pMod == NULL) return FALSE; rrmode = xwlVidModeGetCurrentRRMode(pScreen); if (rrmode == NULL) return FALSE; xwlRRModeToDisplayMode(rrmode, pMod); *mode = pMod; if (dotClock != NULL) *dotClock = pMod->Clock; return TRUE; } static vidMonitorValue xwlVidModeGetMonitorValue(ScreenPtr pScreen, int valtyp, int indx) { vidMonitorValue ret = { NULL, }; RRModePtr rrmode; rrmode = xwlVidModeGetCurrentRRMode(pScreen); if (rrmode == NULL) return ret; switch (valtyp) { case VIDMODE_MON_VENDOR: ret.ptr = XVENDORNAME; break; case VIDMODE_MON_MODEL: ret.ptr = "XWAYLAND"; break; case VIDMODE_MON_NHSYNC: ret.i = 1; break; case VIDMODE_MON_NVREFRESH: ret.i = 1; break; case VIDMODE_MON_HSYNC_LO: case VIDMODE_MON_HSYNC_HI: ret.f = mode_hsync(&rrmode->mode) * 100.0; break; case VIDMODE_MON_VREFRESH_LO: case VIDMODE_MON_VREFRESH_HI: ret.f = mode_refresh(&rrmode->mode) * 100.0; break; } return ret; } static int xwlVidModeGetDotClock(ScreenPtr pScreen, int Clock) { return Clock; } static int xwlVidModeGetNumOfClocks(ScreenPtr pScreen, Bool *progClock) { /* We emulate a programmable clock, rather then a fixed set of clocks */ *progClock = TRUE; return 0; } static Bool xwlVidModeGetClocks(ScreenPtr pScreen, int *Clocks) { return FALSE; /* Programmable clock, no clock list */ } /* GetFirstModeline and GetNextModeline are used from Xext/vidmode.c like this: * if (pVidMode->GetFirstModeline(pScreen, &mode, &dotClock)) { * do { * ... * if (...) * break; * } while (pVidMode->GetNextModeline(pScreen, &mode, &dotClock)); * } * IOW our caller basically always loops over all the modes. There never is a * return to the mainloop between GetFirstModeline and NextModeline calls where * other parts of the server may change our state so we do not need to worry * about xwl_output->randr_output->modes changing underneath us. * Thus we can simply implement these two callbacks by storing the enumeration * index in pVidMode->Next. */ static Bool xwlVidModeGetNextModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock) { struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); VidModePtr pVidMode; DisplayModePtr pMod; intptr_t index; pMod = dixLookupPrivate(&pScreen->devPrivates, xwlVidModePrivateKey); pVidMode = VidModeGetPtr(pScreen); if (xwl_output == NULL || pMod == NULL || pVidMode == NULL) return FALSE; index = (intptr_t)pVidMode->Next; if (index >= xwl_output->randr_output->numModes) return FALSE; xwlRRModeToDisplayMode(xwl_output->randr_output->modes[index], pMod); index++; pVidMode->Next = (void *)index; *mode = pMod; if (dotClock != NULL) *dotClock = pMod->Clock; return TRUE; } static Bool xwlVidModeGetFirstModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock) { VidModePtr pVidMode; intptr_t index = 0; pVidMode = VidModeGetPtr(pScreen); if (pVidMode == NULL) return FALSE; pVidMode->Next = (void *)index; /* 0 */ return xwlVidModeGetNextModeline(pScreen, mode, dotClock); } static Bool xwlVidModeDeleteModeline(ScreenPtr pScreen, DisplayModePtr mode) { /* Unsupported */ return FALSE; } static Bool xwlVidModeZoomViewport(ScreenPtr pScreen, int zoom) { /* Support only no zoom */ return (zoom == 1); } static Bool xwlVidModeSetViewPort(ScreenPtr pScreen, int x, int y) { struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); if (!xwl_output) return FALSE; /* Support only default viewport */ return (x == xwl_output->x && y == xwl_output->y); } static Bool xwlVidModeGetViewPort(ScreenPtr pScreen, int *x, int *y) { struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); if (!xwl_output) return FALSE; *x = xwl_output->x; *y = xwl_output->y; return TRUE; } static Bool xwlVidModeSwitchMode(ScreenPtr pScreen, DisplayModePtr mode) { struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); RRModePtr rrmode; if (!xwl_output) return FALSE; rrmode = xwl_output_find_mode(xwl_output, mode->HDisplay, mode->VDisplay); if (rrmode == NULL) return FALSE; xwl_output_set_emulated_mode(xwl_output, GetCurrentClient(), rrmode, TRUE); return TRUE; } static Bool xwlVidModeLockZoom(ScreenPtr pScreen, Bool lock) { /* Unsupported for now, but pretend it works */ return TRUE; } static ModeStatus xwlVidModeCheckModeForMonitor(ScreenPtr pScreen, DisplayModePtr mode) { RRModePtr rrmode; rrmode = xwlVidModeGetRRMode(pScreen, mode->HDisplay, mode->VDisplay); if (rrmode == NULL) return MODE_ERROR; /* Only support mode with the same HSync/VRefresh as we advertise */ if (mode->HSync == mode_hsync(&rrmode->mode) && mode->VRefresh == mode_refresh(&rrmode->mode)) return MODE_OK; /* All the rest is unsupported - If we want to succeed, return MODE_OK instead */ return MODE_ONE_SIZE; } static ModeStatus xwlVidModeCheckModeForDriver(ScreenPtr pScreen, DisplayModePtr mode) { RRModePtr rrmode; rrmode = xwlVidModeGetRRMode(pScreen, mode->HDisplay, mode->VDisplay); return rrmode ? MODE_OK : MODE_ERROR; } static void xwlVidModeSetCrtcForMode(ScreenPtr pScreen, DisplayModePtr mode) { /* Unsupported */ return; } static Bool xwlVidModeAddModeline(ScreenPtr pScreen, DisplayModePtr mode) { /* Unsupported */ return FALSE; } static int xwlVidModeGetNumOfModes(ScreenPtr pScreen) { struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); return xwl_output ? xwl_output->randr_output->numModes : 0; } static Bool xwlVidModeSetGamma(ScreenPtr pScreen, float red, float green, float blue) { /* Unsupported for now, but pretend it works */ return TRUE; } static Bool xwlVidModeGetGamma(ScreenPtr pScreen, float *red, float *green, float *blue) { /* Unsupported for now, but pretend it works */ *red = *green = *blue = 1.0f; return TRUE; } static Bool xwlVidModeSetGammaRamp(ScreenPtr pScreen, int size, CARD16 *r, CARD16 *g, CARD16 *b) { /* Unsupported for now */ return FALSE; } static Bool xwlVidModeGetGammaRamp(ScreenPtr pScreen, int size, CARD16 *r, CARD16 *g, CARD16 *b) { /* Unsupported for now */ return FALSE; } static int xwlVidModeGetGammaRampSize(ScreenPtr pScreen) { /* Unsupported for now */ return 0; } static Bool xwlVidModeInit(ScreenPtr pScreen) { VidModePtr pVidMode = NULL; pVidMode = VidModeInit(pScreen); if (!pVidMode) return FALSE; pVidMode->Flags = 0; pVidMode->Next = NULL; pVidMode->GetMonitorValue = xwlVidModeGetMonitorValue; pVidMode->GetCurrentModeline = xwlVidModeGetCurrentModeline; pVidMode->GetFirstModeline = xwlVidModeGetFirstModeline; pVidMode->GetNextModeline = xwlVidModeGetNextModeline; pVidMode->DeleteModeline = xwlVidModeDeleteModeline; pVidMode->ZoomViewport = xwlVidModeZoomViewport; pVidMode->GetViewPort = xwlVidModeGetViewPort; pVidMode->SetViewPort = xwlVidModeSetViewPort; pVidMode->SwitchMode = xwlVidModeSwitchMode; pVidMode->LockZoom = xwlVidModeLockZoom; pVidMode->GetNumOfClocks = xwlVidModeGetNumOfClocks; pVidMode->GetClocks = xwlVidModeGetClocks; pVidMode->CheckModeForMonitor = xwlVidModeCheckModeForMonitor; pVidMode->CheckModeForDriver = xwlVidModeCheckModeForDriver; pVidMode->SetCrtcForMode = xwlVidModeSetCrtcForMode; pVidMode->AddModeline = xwlVidModeAddModeline; pVidMode->GetDotClock = xwlVidModeGetDotClock; pVidMode->GetNumOfModes = xwlVidModeGetNumOfModes; pVidMode->SetGamma = xwlVidModeSetGamma; pVidMode->GetGamma = xwlVidModeGetGamma; pVidMode->SetGammaRamp = xwlVidModeSetGammaRamp; pVidMode->GetGammaRamp = xwlVidModeGetGammaRamp; pVidMode->GetGammaRampSize = xwlVidModeGetGammaRampSize; return TRUE; } void xwlVidModeExtensionInit(void) { int i; Bool enabled = FALSE; for (i = 0; i < screenInfo.numScreens; i++) { if (xwlVidModeInit (screenInfo.screens[i])) enabled = TRUE; } /* This means that the DDX doesn't want the vidmode extension enabled */ if (!enabled) return; if (!dixRegisterPrivateKey(xwlVidModePrivateKey, PRIVATE_SCREEN, sizeof(DisplayModeRec))) return; VidModeAddExtension(FALSE); } #endif /* XF86VIDMODE */