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 <[email protected]>
---
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
_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to