[PATCH] dummy: Add support for custom resolutions (RandR 1.2)
Aaron Plattner
aplattner at nvidia.com
Fri Nov 21 09:22:00 PST 2014
On 11/13/2014 10:33 AM, Nicolas Boichat wrote:
> Defining and setting custom resolutions at runtime is not
> currently possible with dummy, which is unconvenient for remote
> desktop applications, see:
> http://lists.x.org/archives/xorg-devel/2014-September/043928.html
>
> This patch adds support XRandR 1.2, which allows custom modes.
> This is done by using more recent initialization functions such
> as xf86CrtcConfigInit/xf86OutputCreate/xf86InitialConfiguration.
>
> Signed-off-by: Nicolas Boichat <drinkcat at chromium.org>
> ---
> I'm not 100% sure that I'm calling the right functions in the
> right order, or if other parts of Init/PreInit could be removed
> (e.g. do we still want DGA/cursor support?). Hoping somebody
> here can verify that.
>
> In any case, this works without glitches in my application.
>
> Thank you,
>
> Best,
>
> src/dummy_driver.c | 213 ++++++++++++++++++++++++++++++++++++-----------------
> 1 file changed, 144 insertions(+), 69 deletions(-)
>
> diff --git a/src/dummy_driver.c b/src/dummy_driver.c
> index 6062c39..d15f77d 100644
> --- a/src/dummy_driver.c
> +++ b/src/dummy_driver.c
> @@ -34,6 +34,8 @@
> #include <X11/extensions/Xv.h>
> #endif
>
> +#include "xf86Crtc.h"
> +
> /*
> * Driver data structures.
> */
> @@ -178,6 +180,115 @@ dummySetup(pointer module, pointer opts, int *errmaj, int *errmin)
> #endif /* XFree86LOADER */
>
> static Bool
> +size_valid(ScrnInfoPtr pScrn, int width, int height)
> +{
> + /* Guard against invalid parameters */
> + if (width == 0 || height == 0 ||
> + width > DUMMY_MAX_WIDTH || height > DUMMY_MAX_HEIGHT)
> + return FALSE;
Did you ever see this actually happen? The server is supposed to reject
requests to set sizes that are outside the range the driver specifies in
xf86CrtcSetSizeRange.
> + /* videoRam is in kb, divide first to avoid 32-bit int overflow */
> + if ((width*height+1023)/1024*pScrn->bitsPerPixel/8 > pScrn->videoRam)
This seems okay for a first revision, but it would be nice if the driver
just ignored videoRam and instead reallocated the screen memory to the
appropriate size here.
> + return FALSE;
> +
> + return TRUE;
> +}
> +
> +static Bool
> +dummy_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
> +{
> + int old_width, old_height;
> +
> + old_width = pScrn->virtualX;
> + old_height = pScrn->virtualY;
> +
> + if (size_valid(pScrn, width, height)) {
> + PixmapPtr rootPixmap;
> + ScreenPtr pScreen = pScrn->pScreen;
> +
> + pScrn->virtualX = width;
> + pScrn->virtualY = height;
> +
> + rootPixmap = pScreen->GetScreenPixmap(pScreen);
> + if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height,
> + -1, -1, -1, NULL)) {
This is really recomputing rootPixmap->devKind, right?
xf86RandR12ScreenSetSize overrides the width and height later. That's
counterintuitive enough that it might be worth mentioning in a comment.
> + pScrn->virtualX = old_width;
> + pScrn->virtualY = old_height;
> + return FALSE;
> + }
> +
> + pScrn->displayWidth = rootPixmap->devKind /
> + (rootPixmap->drawable.bitsPerPixel / 8);
> +
> + return TRUE;
> + } else {
> + return FALSE;
> + }
> +}
> +
> +static const xf86CrtcConfigFuncsRec dummy_xf86crtc_config_funcs = {
> + dummy_xf86crtc_resize
> +};
> +
> +static xf86OutputStatus
> +dummy_output_detect(xf86OutputPtr output)
> +{
> + return XF86OutputStatusConnected;
> +}
> +
> +static int
> +dummy_output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
> +{
> + if (size_valid(output->scrn, pMode->HDisplay, pMode->VDisplay)) {
> + return MODE_OK;
> + } else {
> + return MODE_MEM;
> + }
> +}
> +
> +static DisplayModePtr
> +dummy_output_get_modes(xf86OutputPtr output)
> +{
> + return NULL;
> +}
> +
> +static void
> +dummy_output_dpms(xf86OutputPtr output, int dpms)
> +{
> + return;
> +}
> +
> +static const xf86OutputFuncsRec dummy_output_funcs = {
> + .detect = dummy_output_detect,
> + .mode_valid = dummy_output_mode_valid,
> + .get_modes = dummy_output_get_modes,
> + .dpms = dummy_output_dpms,
> +};
It seems unfortunate that you have to deal with outputs at all. You can
delete all of this stuff if you stop calling xf86InitialConfiguration()
and construct a dummy DisplayModeRec that just has a width and a height.
> +static Bool
> +dummy_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
> + Rotation rotation, int x, int y)
> +{
> + crtc->mode = *mode;
> + crtc->x = x;
> + crtc->y = y;
> + crtc->rotation = rotation;
> +
> + return TRUE;
> +}
> +
> +static void
> +dummy_crtc_dpms(xf86CrtcPtr output, int dpms)
> +{
> + return;
> +}
> +
> +static const xf86CrtcFuncsRec dummy_crtc_funcs = {
> + .set_mode_major = dummy_crtc_set_mode_major,
> + .dpms = dummy_crtc_dpms,
> +};
> +
> +static Bool
> DUMMYGetRec(ScrnInfoPtr pScrn)
> {
> /*
> @@ -283,6 +394,8 @@ DUMMYPreInit(ScrnInfoPtr pScrn, int flags)
> DUMMYPtr dPtr;
> int maxClock = 230000;
> GDevPtr device = xf86GetEntityInfo(pScrn->entityList[0])->device;
> + xf86OutputPtr output;
> + xf86CrtcPtr crtc;
>
> if (flags & PROBE_DETECT)
> return TRUE;
> @@ -346,13 +459,6 @@ DUMMYPreInit(ScrnInfoPtr pScrn, int flags)
> if (!xf86SetDefaultVisual(pScrn, -1))
> return FALSE;
>
> - if (pScrn->depth > 1) {
> - Gamma zeros = {0.0, 0.0, 0.0};
> -
> - if (!xf86SetGamma(pScrn, zeros))
> - return FALSE;
> - }
> -
> xf86CollectOptions(pScrn, device->options);
> /* Process the options */
> if (!(dPtr->Options = malloc(sizeof(DUMMYOptions))))
> @@ -382,64 +488,45 @@ DUMMYPreInit(ScrnInfoPtr pScrn, int flags)
> maxClock);
> }
>
> - pScrn->progClock = TRUE;
> - /*
> - * Setup the ClockRanges, which describe what clock ranges are available,
> - * and what sort of modes they can be used for.
> - */
> - clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1);
> - clockRanges->next = NULL;
> - clockRanges->ClockMulFactor = 1;
> - clockRanges->minClock = 11000; /* guessed ยงยงยง */
> - clockRanges->maxClock = 300000;
> - clockRanges->clockIndex = -1; /* programmable */
> - clockRanges->interlaceAllowed = TRUE;
> - clockRanges->doubleScanAllowed = TRUE;
> -
> - /* Subtract memory for HW cursor */
> -
> -
> - {
> - int apertureSize = (pScrn->videoRam * 1024);
> - i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
> - pScrn->display->modes, clockRanges,
> - NULL, 256, DUMMY_MAX_WIDTH,
> - (8 * pScrn->bitsPerPixel),
> - 128, DUMMY_MAX_HEIGHT, pScrn->display->virtualX,
> - pScrn->display->virtualY, apertureSize,
> - LOOKUP_BEST_REFRESH);
> -
> - if (i == -1)
> - RETURN;
> - }
> + xf86CrtcConfigInit(pScrn, &dummy_xf86crtc_config_funcs);
> +
> + xf86CrtcSetSizeRange(pScrn, 256, 256, DUMMY_MAX_WIDTH, DUMMY_MAX_HEIGHT);
> +
> + crtc = xf86CrtcCreate(pScrn, &dummy_crtc_funcs);
> +
> + output = xf86OutputCreate(pScrn, &dummy_output_funcs, "default");
> +
> + output->possible_crtcs = 0x7f;
>
> - /* Prune the modes marked as invalid */
> - xf86PruneDriverModes(pScrn);
> + xf86InitialConfiguration(pScrn, TRUE);
> +
> + if (pScrn->depth > 1) {
> + Gamma zeros = {0.0, 0.0, 0.0};
> +
> + if (!xf86SetGamma(pScrn, zeros))
> + return FALSE;
> + }
>
> - if (i == 0 || pScrn->modes == NULL) {
> + if (pScrn->modes == NULL) {
> xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
> RETURN;
> }
>
> - /*
> - * Set the CRTC parameters for all of the modes based on the type
> - * of mode, and the chipset's interlace requirements.
> - *
> - * Calling this is required if the mode->Crtc* values are used by the
> - * driver and if the driver doesn't provide code to set them. They
> - * are not pre-initialised at all.
> - */
> - xf86SetCrtcForModes(pScrn, 0);
> -
> /* Set the current mode to the first in the list */
> pScrn->currentMode = pScrn->modes;
>
> - /* Print the list of modes being used */
> - xf86PrintModes(pScrn);
> + /* Set default mode in CRTC */
> + crtc->funcs->set_mode_major(crtc, pScrn->currentMode, RR_Rotate_0, 0, 0);
>
> /* If monitor resolution is set on the command line, use it */
> xf86SetDpi(pScrn, 0, 0);
>
> + /* Set monitor size based on DPI */
> + output->mm_width = pScrn->xDpi > 0 ?
> + (pScrn->virtualX * 254 / (10*pScrn->xDpi)) : 0;
> + output->mm_height = pScrn->yDpi > 0 ?
> + (pScrn->virtualY * 254 / (10*pScrn->yDpi)) : 0;
> +
> if (xf86LoadSubModule(pScrn, "fb") == NULL) {
> RETURN;
> }
> @@ -559,6 +646,8 @@ DUMMYScreenInit(SCREEN_INIT_ARGS_DECL)
>
> if (!miSetPixmapDepths ()) return FALSE;
>
> + pScrn->displayWidth = pScrn->virtualX;
> +
> /*
> * Call the framebuffer layer's ScreenInit function, and fill in other
> * pScreen fields.
> @@ -597,23 +686,6 @@ DUMMYScreenInit(SCREEN_INIT_ARGS_DECL)
> if (dPtr->swCursor)
> xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using Software Cursor.\n");
>
> - {
> -
> -
> - BoxRec AvailFBArea;
> - int lines = pScrn->videoRam * 1024 /
> - (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
> - AvailFBArea.x1 = 0;
> - AvailFBArea.y1 = 0;
> - AvailFBArea.x2 = pScrn->displayWidth;
> - AvailFBArea.y2 = lines;
> - xf86InitFBManager(pScreen, &AvailFBArea);
> -
> - xf86DrvMsg(pScrn->scrnIndex, X_INFO,
> - "Using %i scanlines of offscreen memory \n"
> - , lines - pScrn->virtualY);
> - }
> -
> xf86SetBackingStore(pScreen);
> xf86SetSilkenMouse(pScreen);
>
> @@ -640,6 +712,9 @@ DUMMYScreenInit(SCREEN_INIT_ARGS_DECL)
> | CMAP_RELOAD_ON_MODE_SWITCH))
> return FALSE;
>
> + if (!xf86CrtcScreenInit(pScreen))
> + return FALSE;
> +
> /* DUMMYInitVideo(pScreen); */
>
> pScreen->SaveScreen = DUMMYSaveScreen;
>
--
Aaron
More information about the xorg-devel
mailing list