st/xorg, vmware: Make throttling configurable.
authorThomas Hellstrom <thellstrom@vmware.com>
Mon, 31 May 2010 19:34:59 +0000 (20:34 +0100)
committerJakob Bornecrantz <jakob@vmware.com>
Mon, 31 May 2010 21:34:59 +0000 (22:34 +0100)
The xorg state tracker gets two new options to let the user choose
whether to enable / disable dirty throttling and swapbuffer throttling.
The default value of these options are enabled, unless the winsys
supplies a customizer with other values. The customizer record has been
extended to allow this, and also to set winsys-based throttling on a per-
context basis.

The vmware part of this patch disables the dirty throttling if the kernel
supports command submission throttling, and also in that case sets kernel
based throttling for everything but swapbuffers. The vmware winsys does not
set throttling per context, even if it theoretically could, but instead
sets throttling per screen. This should perhaps be changed, should the
xorg state tracker start to use multiple rendering contexts. Kernel throttling
is off by default for all new screens/contexts, so the dri state tracker
is not affected.

This significantly improves interactivity of the vmware xorg driver.

Cherry-picked from commit a8f3b3f88acc1f0193fa740e76e9d815f07f32ab

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Jakob Bornecrantz <jakob@vmware.com>
src/gallium/state_trackers/xorg/xorg_dri2.c
src/gallium/state_trackers/xorg/xorg_driver.c
src/gallium/state_trackers/xorg/xorg_exa.c
src/gallium/state_trackers/xorg/xorg_tracker.h
src/gallium/targets/xorg-vmwgfx/vmw_screen.c
src/gallium/winsys/svga/drm/vmw_context.c
src/gallium/winsys/svga/drm/vmw_context.h
src/gallium/winsys/svga/drm/vmw_screen.c
src/gallium/winsys/svga/drm/vmw_screen.h
src/gallium/winsys/svga/drm/vmw_screen_ioctl.c

index e719644d340c5ab3ff226b172789f8df176d3f7e..4e01bd103066bb1ea671b64f6af0ab5b362f3d08 100644 (file)
@@ -299,6 +299,7 @@ dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
     GCPtr gc;
     RegionPtr copy_clip;
     Bool save_accel;
+    CustomizerPtr cust = ms->cust;
 
     /*
      * In driCreateBuffers we dewrap windows into the
@@ -352,7 +353,8 @@ dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
     ValidateGC(dst_draw, gc);
 
     /* If this is a full buffer swap, throttle on the previous one */
-    if (dst_priv->fence && REGION_NUM_RECTS(pRegion) == 1) {
+    if (ms->swapThrottling &&
+       dst_priv->fence && REGION_NUM_RECTS(pRegion) == 1) {
        BoxPtr extents = REGION_EXTENTS(pScreen, pRegion);
 
        if (extents->x1 == 0 && extents->y1 == 0 &&
@@ -374,6 +376,9 @@ dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
     DamageRegionAppend(src_draw, pRegion);
     DamageRegionProcessPending(src_draw);
 
+   if (cust && cust->winsys_context_throttle)
+       cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_SWAP);
+
     (*gc->ops->CopyArea)(src_draw, dst_draw, gc,
                         0, 0, pDraw->width, pDraw->height, 0, 0);
     ms->exa->accel = save_accel;
@@ -381,8 +386,13 @@ dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
     FreeScratchGC(gc);
 
     ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS,
-                  pDestBuffer->attachment == DRI2BufferFrontLeft ?
+                  (pDestBuffer->attachment == DRI2BufferFrontLeft
+                   && ms->swapThrottling) ?
                   &dst_priv->fence : NULL);
+
+   if (cust && cust->winsys_context_throttle)
+       cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_RENDER);
+
 }
 
 Bool
index 84c0545b1b76db51a13c0213ac3b45c548eff5e3..6b6e2009fea4209202a7bc9facde41e92220d892 100644 (file)
@@ -79,12 +79,16 @@ typedef enum
     OPTION_SW_CURSOR,
     OPTION_2D_ACCEL,
     OPTION_DEBUG_FALLBACK,
+    OPTION_THROTTLE_SWAP,
+    OPTION_THROTTLE_DIRTY
 } drv_option_enums;
 
 static const OptionInfoRec drv_options[] = {
     {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
     {OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE},
     {OPTION_DEBUG_FALLBACK, "DebugFallback", OPTV_BOOLEAN, {0}, FALSE},
+    {OPTION_THROTTLE_SWAP, "SwapThrottling", OPTV_BOOLEAN, {0}, FALSE},
+    {OPTION_THROTTLE_DIRTY, "DirtyThrottling", OPTV_BOOLEAN, {0}, FALSE},
     {-1, NULL, OPTV_NONE, {0}, FALSE}
 };
 
@@ -534,23 +538,29 @@ static void drv_block_handler(int i, pointer blockData, pointer pTimeout,
     if (ms->ctx) {
        int j;
 
-       ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, &ms->fence[XORG_NR_FENCES-1]);
+       ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE,
+                     ms->dirtyThrottling ?
+                     &ms->fence[XORG_NR_FENCES-1] :
+                     NULL);
        
-       if (ms->fence[0])
-          ms->ctx->screen->fence_finish(ms->ctx->screen, ms->fence[0], 0);
+       if (ms->dirtyThrottling) {
+          if (ms->fence[0])
+              ms->ctx->screen->fence_finish(ms->ctx->screen,
+                                            ms->fence[0], 0);
   
-       /* The amount of rendering generated by a block handler can be
-        * quite small.  Let us get a fair way ahead of hardware before
-        * throttling.
-        */
-       for (j = 0; j < XORG_NR_FENCES - 1; j++)
-          ms->screen->fence_reference(ms->screen,
-                                      &ms->fence[j],
-                                      ms->fence[j+1]);
-
-       ms->screen->fence_reference(ms->screen,
-                                   &ms->fence[XORG_NR_FENCES-1],
-                                   NULL);
+          /* The amount of rendering generated by a block handler can be
+           * quite small.  Let us get a fair way ahead of hardware before
+           * throttling.
+           */
+          for (j = 0; j < XORG_NR_FENCES - 1; j++)
+              ms->screen->fence_reference(ms->screen,
+                                          &ms->fence[j],
+                                          ms->fence[j+1]);
+
+          ms->screen->fence_reference(ms->screen,
+                                      &ms->fence[XORG_NR_FENCES-1],
+                                      NULL);
+       }
     }
         
 
@@ -634,6 +644,8 @@ drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
     unsigned max_width, max_height;
     VisualPtr visual;
     CustomizerPtr cust = ms->cust;
+    MessageType from_st;
+    MessageType from_dt;
 
     if (!drv_init_drm(pScrn)) {
        FatalError("Could not init DRM");
@@ -720,6 +732,19 @@ drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
     ms->accelerate_2d = xf86ReturnOptValBool(ms->Options, OPTION_2D_ACCEL, FALSE);
     ms->debug_fallback = xf86ReturnOptValBool(ms->Options, OPTION_DEBUG_FALLBACK, ms->accelerate_2d);
 
+    if (cust && cust->winsys_screen_init)
+       cust->winsys_screen_init(cust, ms->fd);
+
+    ms->swapThrottling = cust ?  cust->swap_throttling : TRUE;
+    from_st = xf86GetOptValBool(ms->Options, OPTION_THROTTLE_SWAP,
+                               &ms->swapThrottling) ?
+       X_CONFIG : X_DEFAULT;
+
+    ms->dirtyThrottling = cust ?  cust->dirty_throttling : TRUE;
+    from_dt = xf86GetOptValBool(ms->Options, OPTION_THROTTLE_DIRTY,
+                               &ms->dirtyThrottling) ?
+       X_CONFIG : X_DEFAULT;
+
     if (ms->screen) {
        ms->exa = xorg_exa_init(pScrn, ms->accelerate_2d);
 
@@ -744,6 +769,11 @@ drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
 #else
     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is disabled\n");
 #endif
+    xf86DrvMsg(pScrn->scrnIndex, from_st, "Swap Throttling is %s.\n",
+              ms->swapThrottling ? "enabled" : "disabled");
+    xf86DrvMsg(pScrn->scrnIndex, from_dt, "Dirty Throttling is %s.\n",
+              ms->dirtyThrottling ? "enabled" : "disabled");
+
     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
 
     miInitializeBackingStore(pScreen);
@@ -776,9 +806,6 @@ drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
     if (serverGeneration == 1)
        xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
 
-    if (cust && cust->winsys_screen_init)
-       cust->winsys_screen_init(cust, ms->fd);
-
     return drv_enter_vt(scrnIndex, 1);
 }
 
index ce5e5874e79dd23904464616300efcfdc1e7aa2c..bd8466830008c8e26a258ed00a639783ea0262df 100644 (file)
@@ -986,6 +986,7 @@ xorg_exa_init(ScrnInfoPtr pScrn, Bool accel)
    modesettingPtr ms = modesettingPTR(pScrn);
    struct exa_context *exa;
    ExaDriverPtr pExa;
+   CustomizerPtr cust = ms->cust;
 
    exa = xcalloc(1, sizeof(struct exa_context));
    if (!exa)
@@ -1047,6 +1048,8 @@ xorg_exa_init(ScrnInfoPtr pScrn, Bool accel)
 
    /* Share context with DRI */
    ms->ctx = exa->pipe;
+   if (cust && cust->winsys_context_throttle)
+       cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_RENDER);
 
    exa->renderer = renderer_create(exa->pipe);
    exa->accel = accel;
index 65fbc3234ba70a013cb5bb74c805342d62675b95..25da9b1a3bd9170fb24dda9ab60d6a45004980ce 100644 (file)
@@ -67,12 +67,22 @@ typedef struct
 
 #define XORG_NR_FENCES 3
 
+enum xorg_throttling_reason {
+    THROTTLE_RENDER,
+    THROTTLE_SWAP
+};
+
 typedef struct _CustomizerRec
 {
+    Bool dirty_throttling;
+    Bool swap_throttling;
     Bool (*winsys_screen_init)(struct _CustomizerRec *cust, int fd);
     Bool (*winsys_screen_close)(struct _CustomizerRec *cust);
     Bool (*winsys_enter_vt)(struct _CustomizerRec *cust);
     Bool (*winsys_leave_vt)(struct _CustomizerRec *cust);
+    void (*winsys_context_throttle)(struct _CustomizerRec *cust,
+                                   struct pipe_context *pipe,
+                                   enum xorg_throttling_reason reason);
 } CustomizerRec, *CustomizerPtr;
 
 typedef struct _modesettingRec
@@ -91,6 +101,8 @@ typedef struct _modesettingRec
     Bool noAccel;
     Bool SWCursor;
     CursorPtr cursor;
+    Bool swapThrottling;
+    Bool dirtyThrottling;
     CloseScreenProcPtr CloseScreen;
 
     /* Broken-out options. */
index 5e4ef41688d8d02001a1d438c3b6a78455f75931..e0edf32adb4938dc8bb4e6f40f8ce401ee30916f 100644 (file)
 
 #include "vmw_hook.h"
 #include "vmw_driver.h"
+#include <pipe/p_context.h>
 
 #include "cursorstr.h"
 
+void vmw_winsys_screen_set_throttling(struct pipe_screen *screen,
+                                     uint32_t throttle_us);
+
+
 /* modified version of crtc functions */
 xf86CrtcFuncsRec vmw_screen_crtc_funcs;
 
@@ -83,12 +88,51 @@ vmw_screen_cursor_close(struct vmw_customizer *vmw)
        config->crtc[i]->funcs = vmw->cursor_priv;
 }
 
+static void
+vmw_context_throttle(CustomizerPtr cust,
+                    struct pipe_context *pipe,
+                    enum xorg_throttling_reason reason)
+{
+    switch (reason) {
+    case THROTTLE_RENDER:
+       vmw_winsys_screen_set_throttling(pipe->screen, 20000);
+       break;
+    default:
+      vmw_winsys_screen_set_throttling(pipe->screen, 0);
+    }
+}
+
+static void
+vmw_context_no_throttle(CustomizerPtr cust,
+                    struct pipe_context *pipe,
+                    enum xorg_throttling_reason reason)
+{
+    vmw_winsys_screen_set_throttling(pipe->screen, 0);
+}
+
 static Bool
 vmw_screen_init(CustomizerPtr cust, int fd)
 {
     struct vmw_customizer *vmw = vmw_customizer(cust);
+    drmVersionPtr ver;
 
     vmw->fd = fd;
+    ver = drmGetVersion(fd);
+    if (ver == NULL ||
+       (ver->version_major == 1 && ver->version_minor < 1)) {
+       cust->swap_throttling = TRUE;
+       cust->dirty_throttling = TRUE;
+       cust->winsys_context_throttle = vmw_context_no_throttle;
+    } else {
+       cust->swap_throttling = TRUE;
+       cust->dirty_throttling = FALSE;
+       cust->winsys_context_throttle = vmw_context_throttle;
+       debug_printf("%s: Enabling kernel throttling.\n", __func__);
+    }
+
+    if (ver)
+       drmFreeVersion(ver);
+
     vmw_screen_cursor_init(vmw);
 
     vmw_ctrl_ext_init(vmw);
index 104d03f27300c593016455231e6b9dc270b62d50..11626ee637d9a93db90a85a7ce4e60c4800b1bc8 100644 (file)
@@ -103,6 +103,9 @@ struct vmw_svga_winsys_context
     * referred.
     */
    boolean preemptive_flush;
+
+   boolean throttle_set;
+   uint32_t throttle_us;
 };
 
 
@@ -135,6 +138,7 @@ vmw_swc_flush(struct svga_winsys_context *swc,
    struct pipe_fence_handle *fence = NULL;
    unsigned i;
    enum pipe_error ret;
+   uint32_t throttle_us;
 
    ret = pb_validate_validate(vswc->validate);
    assert(ret == PIPE_OK);
@@ -153,8 +157,13 @@ vmw_swc_flush(struct svga_winsys_context *swc,
          *reloc->where = ptr;
       }
 
+      throttle_us = vswc->throttle_set ?
+        vswc->throttle_us : vswc->vws->default_throttle_us;
+
       if (vswc->command.used)
          vmw_ioctl_command(vswc->vws,
+                          vswc->base.cid,
+                          throttle_us,
                            vswc->command.buffer,
                            vswc->command.used,
                            &vswc->last_fence);
@@ -395,3 +404,13 @@ vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
 }
 
 
+void
+vmw_svga_context_set_throttling(struct pipe_context *pipe,
+                               uint32_t throttle_us)
+{
+   struct svga_winsys_context *swc = svga_winsys_context(pipe);
+   struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
+
+   vswc->throttle_us = throttle_us;
+   vswc->throttle_set = TRUE;
+}
index d4884d24e996064b0b42aa1315ce749b77ae505b..aed8b93734b2c3cf61ea2d2c67eb65104e04b1ef 100644 (file)
@@ -52,5 +52,8 @@ struct pipe_screen;
 struct svga_winsys_context *
 vmw_svga_winsys_context_create(struct svga_winsys_screen *sws);
 
+void
+vmw_svga_context_set_throttling(struct pipe_context *pipe,
+                               uint32_t throttle_us);
 
 #endif /* VMW_CONTEXT_H_ */
index 6cc9b38293219b1a18a10071af0680123acb56d2..51a4c55e5a2815537d756a471e6809cb8094d365 100644 (file)
@@ -75,3 +75,13 @@ vmw_winsys_destroy(struct vmw_winsys_screen *vws)
    vmw_ioctl_cleanup(vws);
    FREE(vws);
 }
+
+void
+vmw_winsys_screen_set_throttling(struct pipe_screen *screen,
+                                uint32_t throttle_us)
+{
+   struct vmw_winsys_screen  *vws =
+      vmw_winsys_screen(svga_winsys_screen(screen));
+
+   vws->default_throttle_us = throttle_us;
+}
index d3f2c2c7f568274cdc8fa1dee5e736703f388154..b3de72df881dbb8c29a35c5f912830e4288c630e 100644 (file)
@@ -53,6 +53,7 @@ struct vmw_winsys_screen
    struct svga_winsys_screen base;
 
    boolean use_old_scanout_flag;
+   uint32_t default_throttle_us;
 
    struct {
       volatile uint32_t *fifo_map;
@@ -96,9 +97,11 @@ vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws,
 
 void
 vmw_ioctl_command(struct vmw_winsys_screen *vws,
-                       void *commands,
-                       uint32_t size,
-                       uint32_t *fence);
+                 int32_t cid,
+                 uint32_t throttle_us,
+                 void *commands,
+                 uint32_t size,
+                 uint32_t *fence);
 
 struct vmw_region *
 vmw_ioctl_region_create(struct vmw_winsys_screen *vws, uint32_t size);
@@ -135,6 +138,7 @@ void vmw_pools_cleanup(struct vmw_winsys_screen *vws);
 
 struct vmw_winsys_screen *vmw_winsys_create(int fd, boolean use_old_scanout_flag);
 void vmw_winsys_destroy(struct vmw_winsys_screen *sws);
-
+void vmw_winsys_screen_set_throttling(struct pipe_screen *screen,
+                                     uint32_t throttle_us);
 
 #endif /* VMW_SCREEN_H_ */
index 5d81fa8c4a6de223e58a39df14474dec4711a7b6..d92ba389d354642e096585a10b680e484e87d1c0 100644 (file)
@@ -241,8 +241,9 @@ vmw_ioctl_surface_destroy(struct vmw_winsys_screen *vws, uint32 sid)
 }
 
 void
-vmw_ioctl_command(struct vmw_winsys_screen *vws, void *commands, uint32_t size,
-                      uint32_t * pfence)
+vmw_ioctl_command(struct vmw_winsys_screen *vws, int32_t cid,
+                 uint32_t throttle_us, void *commands, uint32_t size,
+                 uint32_t *pfence)
 {
    struct drm_vmw_execbuf_arg arg;
    struct drm_vmw_fence_rep rep;
@@ -275,6 +276,7 @@ vmw_ioctl_command(struct vmw_winsys_screen *vws, void *commands, uint32_t size,
    arg.fence_rep = (unsigned long)&rep;
    arg.commands = (unsigned long)commands;
    arg.command_size = size;
+   arg.throttle_us = throttle_us;
 
    do {
        ret = drmCommandWrite(vws->ioctl.drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));