OSDN Git Service

vmwgfx: Major KMS refactoring / cleanup in preparation of screen targets
authorSinclair Yeh <syeh@vmware.com>
Fri, 26 Jun 2015 08:23:42 +0000 (01:23 -0700)
committerThomas Hellstrom <thellstrom@vmware.com>
Wed, 5 Aug 2015 12:01:06 +0000 (14:01 +0200)
Signed-off-by: Sinclair Yeh <syeh@vmware.com>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c

index c300a0a..b65eb02 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -330,6 +330,17 @@ struct vmw_ctx_binding_state {
        struct vmw_ctx_binding shaders[SVGA3D_SHADERTYPE_MAX];
 };
 
+
+/*
+ * enum vmw_display_unit_type - Describes the display unit
+ */
+enum vmw_display_unit_type {
+       vmw_du_invalid = 0,
+       vmw_du_legacy,
+       vmw_du_screen_object
+};
+
+
 struct vmw_sw_context{
        struct drm_open_hash res_ht;
        bool res_ht_initialized;
@@ -421,6 +432,7 @@ struct vmw_private {
         */
 
        void *fb_info;
+       enum vmw_display_unit_type active_display_unit;
        struct vmw_legacy_display *ldu_priv;
        struct vmw_screen_object_display *sou_priv;
        struct vmw_overlay *overlay_priv;
@@ -844,8 +856,8 @@ extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
 
 extern irqreturn_t vmw_irq_handler(int irq, void *arg);
 extern int vmw_wait_seqno(struct vmw_private *dev_priv, bool lazy,
-                            uint32_t seqno, bool interruptible,
-                            unsigned long timeout);
+                         uint32_t seqno, bool interruptible,
+                         unsigned long timeout);
 extern void vmw_irq_preinstall(struct drm_device *dev);
 extern int vmw_irq_postinstall(struct drm_device *dev);
 extern void vmw_irq_uninstall(struct drm_device *dev);
@@ -876,9 +888,9 @@ extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv,
 extern void vmw_marker_queue_init(struct vmw_marker_queue *queue);
 extern void vmw_marker_queue_takedown(struct vmw_marker_queue *queue);
 extern int vmw_marker_push(struct vmw_marker_queue *queue,
-                         uint32_t seqno);
+                          uint32_t seqno);
 extern int vmw_marker_pull(struct vmw_marker_queue *queue,
-                         uint32_t signaled_seqno);
+                          uint32_t signaled_seqno);
 extern int vmw_wait_lag(struct vmw_private *dev_priv,
                        struct vmw_marker_queue *queue, uint32_t us);
 
index 189102d..239815c 100644 (file)
@@ -71,8 +71,8 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
        if (hwversion < SVGA3D_HWVERSION_WS8_B1)
                return false;
 
-       /* Non-Screen Object path does not support surfaces */
-       if (!dev_priv->sou_priv)
+       /* Legacy Display Unit does not support surfaces */
+       if (dev_priv->active_display_unit == vmw_du_legacy)
                return false;
 
        return true;
index b5632c2..cac17c2 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
 #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
 
 
-struct vmw_clip_rect {
-       int x1, x2, y1, y2;
-};
 
 /**
  * Clip @num_rects number of @rects against @clip storing the
  * results in @out_rects and the number of passed rects in @out_num.
  */
-static void vmw_clip_cliprects(struct drm_clip_rect *rects,
+void vmw_clip_cliprects(struct drm_clip_rect *rects,
                        int num_rects,
                        struct vmw_clip_rect clip,
                        SVGASignedRect *out_rects,
@@ -69,7 +66,7 @@ static void vmw_clip_cliprects(struct drm_clip_rect *rects,
        *out_num = k;
 }
 
-void vmw_display_unit_cleanup(struct vmw_display_unit *du)
+void vmw_du_cleanup(struct vmw_display_unit *du)
 {
        if (du->cursor_surface)
                vmw_surface_unreference(&du->cursor_surface);
@@ -367,15 +364,6 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
 
        srf->snooper.age++;
 
-       /* we can't call this function from this function since execbuf has
-        * reserved fifo space.
-        *
-        * if (srf->snooper.crtc)
-        *      vmw_ldu_crtc_cursor_update_image(dev_priv,
-        *                                       srf->snooper.image, 64, 64,
-        *                                       du->hotspot_x, du->hotspot_y);
-        */
-
        ttm_bo_kunmap(&map);
 err_unreserve:
        ttm_bo_unreserve(bo);
@@ -412,17 +400,6 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
  * Surface framebuffer code
  */
 
-#define vmw_framebuffer_to_vfbs(x) \
-       container_of(x, struct vmw_framebuffer_surface, base.base)
-
-struct vmw_framebuffer_surface {
-       struct vmw_framebuffer base;
-       struct vmw_surface *surface;
-       struct vmw_dma_buffer *buffer;
-       struct list_head head;
-       struct drm_master *master;
-};
-
 static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
 {
        struct vmw_framebuffer_surface *vfbs =
@@ -442,153 +419,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
        kfree(vfbs);
 }
 
-static int do_surface_dirty_sou(struct vmw_private *dev_priv,
-                               struct drm_file *file_priv,
-                               struct vmw_framebuffer *framebuffer,
-                               unsigned flags, unsigned color,
-                               struct drm_clip_rect *clips,
-                               unsigned num_clips, int inc,
-                               struct vmw_fence_obj **out_fence)
-{
-       struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
-       struct drm_clip_rect *clips_ptr;
-       struct drm_clip_rect *tmp;
-       struct drm_crtc *crtc;
-       size_t fifo_size;
-       int i, num_units;
-       int ret = 0; /* silence warning */
-       int left, right, top, bottom;
-
-       struct {
-               SVGA3dCmdHeader header;
-               SVGA3dCmdBlitSurfaceToScreen body;
-       } *cmd;
-       SVGASignedRect *blits;
-
-       num_units = 0;
-       list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
-                           head) {
-               if (crtc->primary->fb != &framebuffer->base)
-                       continue;
-               units[num_units++] = vmw_crtc_to_du(crtc);
-       }
-
-       BUG_ON(!clips || !num_clips);
-
-       tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL);
-       if (unlikely(tmp == NULL)) {
-               DRM_ERROR("Temporary cliprect memory alloc failed.\n");
-               return -ENOMEM;
-       }
-
-       fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips;
-       cmd = kzalloc(fifo_size, GFP_KERNEL);
-       if (unlikely(cmd == NULL)) {
-               DRM_ERROR("Temporary fifo memory alloc failed.\n");
-               ret = -ENOMEM;
-               goto out_free_tmp;
-       }
-
-       /* setup blits pointer */
-       blits = (SVGASignedRect *)&cmd[1];
-
-       /* initial clip region */
-       left = clips->x1;
-       right = clips->x2;
-       top = clips->y1;
-       bottom = clips->y2;
-
-       /* skip the first clip rect */
-       for (i = 1, clips_ptr = clips + inc;
-            i < num_clips; i++, clips_ptr += inc) {
-               left = min_t(int, left, (int)clips_ptr->x1);
-               right = max_t(int, right, (int)clips_ptr->x2);
-               top = min_t(int, top, (int)clips_ptr->y1);
-               bottom = max_t(int, bottom, (int)clips_ptr->y2);
-       }
-
-       /* only need to do this once */
-       cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN);
-       cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
-
-       cmd->body.srcRect.left = left;
-       cmd->body.srcRect.right = right;
-       cmd->body.srcRect.top = top;
-       cmd->body.srcRect.bottom = bottom;
-
-       clips_ptr = clips;
-       for (i = 0; i < num_clips; i++, clips_ptr += inc) {
-               tmp[i].x1 = clips_ptr->x1 - left;
-               tmp[i].x2 = clips_ptr->x2 - left;
-               tmp[i].y1 = clips_ptr->y1 - top;
-               tmp[i].y2 = clips_ptr->y2 - top;
-       }
-
-       /* do per unit writing, reuse fifo for each */
-       for (i = 0; i < num_units; i++) {
-               struct vmw_display_unit *unit = units[i];
-               struct vmw_clip_rect clip;
-               int num;
-
-               clip.x1 = left - unit->crtc.x;
-               clip.y1 = top - unit->crtc.y;
-               clip.x2 = right - unit->crtc.x;
-               clip.y2 = bottom - unit->crtc.y;
-
-               /* skip any crtcs that misses the clip region */
-               if (clip.x1 >= unit->crtc.mode.hdisplay ||
-                   clip.y1 >= unit->crtc.mode.vdisplay ||
-                   clip.x2 <= 0 || clip.y2 <= 0)
-                       continue;
-
-               /*
-                * In order for the clip rects to be correctly scaled
-                * the src and dest rects needs to be the same size.
-                */
-               cmd->body.destRect.left = clip.x1;
-               cmd->body.destRect.right = clip.x2;
-               cmd->body.destRect.top = clip.y1;
-               cmd->body.destRect.bottom = clip.y2;
-
-               /* create a clip rect of the crtc in dest coords */
-               clip.x2 = unit->crtc.mode.hdisplay - clip.x1;
-               clip.y2 = unit->crtc.mode.vdisplay - clip.y1;
-               clip.x1 = 0 - clip.x1;
-               clip.y1 = 0 - clip.y1;
-
-               /* need to reset sid as it is changed by execbuf */
-               cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle);
-               cmd->body.destScreenId = unit->unit;
-
-               /* clip and write blits to cmd stream */
-               vmw_clip_cliprects(tmp, num_clips, clip, blits, &num);
-
-               /* if no cliprects hit skip this */
-               if (num == 0)
-                       continue;
-
-               /* only return the last fence */
-               if (out_fence && *out_fence)
-                       vmw_fence_obj_unreference(out_fence);
-
-               /* recalculate package length */
-               fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
-               cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
-               ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
-                                         fifo_size, 0, NULL, out_fence);
-
-               if (unlikely(ret != 0))
-                       break;
-       }
-
-
-       kfree(cmd);
-out_free_tmp:
-       kfree(tmp);
-
-       return ret;
-}
-
 static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                                  struct drm_file *file_priv,
                                  unsigned flags, unsigned color,
@@ -604,8 +434,8 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
        if (unlikely(vfbs->master != file_priv->master))
                return -EINVAL;
 
-       /* Require ScreenObject support for 3D */
-       if (!dev_priv->sou_priv)
+       /* Legacy Display Unit does not support 3D */
+       if (dev_priv->active_display_unit == vmw_du_legacy)
                return -EINVAL;
 
        drm_modeset_lock_all(dev_priv->dev);
@@ -627,9 +457,12 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                inc = 2; /* skip source rects */
        }
 
-       ret = do_surface_dirty_sou(dev_priv, file_priv, &vfbs->base,
-                                  flags, color,
-                                  clips, num_clips, inc, NULL);
+       if (dev_priv->active_display_unit == vmw_du_screen_object)
+               ret = vmw_kms_sou_do_surface_dirty(dev_priv, file_priv,
+                                                  &vfbs->base,
+                                                  flags, color,
+                                                  clips, num_clips,
+                                                  inc, NULL);
 
        vmw_fifo_flush(dev_priv, false);
        ttm_read_unlock(&dev_priv->reservation_sem);
@@ -658,8 +491,8 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
        struct vmw_master *vmaster = vmw_master(file_priv->master);
        int ret;
 
-       /* 3D is only supported on HWv8 hosts which supports screen objects */
-       if (!dev_priv->sou_priv)
+       /* 3D is only supported on HWv8 and newer hosts */
+       if (dev_priv->active_display_unit == vmw_du_legacy)
                return -ENOSYS;
 
        /*
@@ -693,9 +526,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
        case 15:
                format = SVGA3D_A1R5G5B5;
                break;
-       case 8:
-               format = SVGA3D_LUMINANCE8;
-               break;
        default:
                DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth);
                return -EINVAL;
@@ -753,14 +583,6 @@ out_err1:
  * Dmabuf framebuffer code
  */
 
-#define vmw_framebuffer_to_vfbd(x) \
-       container_of(x, struct vmw_framebuffer_dmabuf, base.base)
-
-struct vmw_framebuffer_dmabuf {
-       struct vmw_framebuffer base;
-       struct vmw_dma_buffer *buffer;
-};
-
 static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
 {
        struct vmw_framebuffer_dmabuf *vfbd =
@@ -773,180 +595,6 @@ static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
        kfree(vfbd);
 }
 
-static int do_dmabuf_dirty_ldu(struct vmw_private *dev_priv,
-                              struct vmw_framebuffer *framebuffer,
-                              unsigned flags, unsigned color,
-                              struct drm_clip_rect *clips,
-                              unsigned num_clips, int increment)
-{
-       size_t fifo_size;
-       int i;
-
-       struct {
-               uint32_t header;
-               SVGAFifoCmdUpdate body;
-       } *cmd;
-
-       fifo_size = sizeof(*cmd) * num_clips;
-       cmd = vmw_fifo_reserve(dev_priv, fifo_size);
-       if (unlikely(cmd == NULL)) {
-               DRM_ERROR("Fifo reserve failed.\n");
-               return -ENOMEM;
-       }
-
-       memset(cmd, 0, fifo_size);
-       for (i = 0; i < num_clips; i++, clips += increment) {
-               cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE);
-               cmd[i].body.x = cpu_to_le32(clips->x1);
-               cmd[i].body.y = cpu_to_le32(clips->y1);
-               cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1);
-               cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1);
-       }
-
-       vmw_fifo_commit(dev_priv, fifo_size);
-       return 0;
-}
-
-static int do_dmabuf_define_gmrfb(struct drm_file *file_priv,
-                                 struct vmw_private *dev_priv,
-                                 struct vmw_framebuffer *framebuffer)
-{
-       int depth = framebuffer->base.depth;
-       size_t fifo_size;
-       int ret;
-
-       struct {
-               uint32_t header;
-               SVGAFifoCmdDefineGMRFB body;
-       } *cmd;
-
-       /* Emulate RGBA support, contrary to svga_reg.h this is not
-        * supported by hosts. This is only a problem if we are reading
-        * this value later and expecting what we uploaded back.
-        */
-       if (depth == 32)
-               depth = 24;
-
-       fifo_size = sizeof(*cmd);
-       cmd = kmalloc(fifo_size, GFP_KERNEL);
-       if (unlikely(cmd == NULL)) {
-               DRM_ERROR("Failed to allocate temporary cmd buffer.\n");
-               return -ENOMEM;
-       }
-
-       memset(cmd, 0, fifo_size);
-       cmd->header = SVGA_CMD_DEFINE_GMRFB;
-       cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel;
-       cmd->body.format.colorDepth = depth;
-       cmd->body.format.reserved = 0;
-       cmd->body.bytesPerLine = framebuffer->base.pitches[0];
-       cmd->body.ptr.gmrId = framebuffer->user_handle;
-       cmd->body.ptr.offset = 0;
-
-       ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
-                                 fifo_size, 0, NULL, NULL);
-
-       kfree(cmd);
-
-       return ret;
-}
-
-static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
-                              struct vmw_private *dev_priv,
-                              struct vmw_framebuffer *framebuffer,
-                              unsigned flags, unsigned color,
-                              struct drm_clip_rect *clips,
-                              unsigned num_clips, int increment,
-                              struct vmw_fence_obj **out_fence)
-{
-       struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
-       struct drm_clip_rect *clips_ptr;
-       int i, k, num_units, ret;
-       struct drm_crtc *crtc;
-       size_t fifo_size;
-
-       struct {
-               uint32_t header;
-               SVGAFifoCmdBlitGMRFBToScreen body;
-       } *blits;
-
-       ret = do_dmabuf_define_gmrfb(file_priv, dev_priv, framebuffer);
-       if (unlikely(ret != 0))
-               return ret; /* define_gmrfb prints warnings */
-
-       fifo_size = sizeof(*blits) * num_clips;
-       blits = kmalloc(fifo_size, GFP_KERNEL);
-       if (unlikely(blits == NULL)) {
-               DRM_ERROR("Failed to allocate temporary cmd buffer.\n");
-               return -ENOMEM;
-       }
-
-       num_units = 0;
-       list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
-               if (crtc->primary->fb != &framebuffer->base)
-                       continue;
-               units[num_units++] = vmw_crtc_to_du(crtc);
-       }
-
-       for (k = 0; k < num_units; k++) {
-               struct vmw_display_unit *unit = units[k];
-               int hit_num = 0;
-
-               clips_ptr = clips;
-               for (i = 0; i < num_clips; i++, clips_ptr += increment) {
-                       int clip_x1 = clips_ptr->x1 - unit->crtc.x;
-                       int clip_y1 = clips_ptr->y1 - unit->crtc.y;
-                       int clip_x2 = clips_ptr->x2 - unit->crtc.x;
-                       int clip_y2 = clips_ptr->y2 - unit->crtc.y;
-                       int move_x, move_y;
-
-                       /* skip any crtcs that misses the clip region */
-                       if (clip_x1 >= unit->crtc.mode.hdisplay ||
-                           clip_y1 >= unit->crtc.mode.vdisplay ||
-                           clip_x2 <= 0 || clip_y2 <= 0)
-                               continue;
-
-                       /* clip size to crtc size */
-                       clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay);
-                       clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay);
-
-                       /* translate both src and dest to bring clip into screen */
-                       move_x = min_t(int, clip_x1, 0);
-                       move_y = min_t(int, clip_y1, 0);
-
-                       /* actual translate done here */
-                       blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
-                       blits[hit_num].body.destScreenId = unit->unit;
-                       blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x;
-                       blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y;
-                       blits[hit_num].body.destRect.left = clip_x1 - move_x;
-                       blits[hit_num].body.destRect.top = clip_y1 - move_y;
-                       blits[hit_num].body.destRect.right = clip_x2;
-                       blits[hit_num].body.destRect.bottom = clip_y2;
-                       hit_num++;
-               }
-
-               /* no clips hit the crtc */
-               if (hit_num == 0)
-                       continue;
-
-               /* only return the last fence */
-               if (out_fence && *out_fence)
-                       vmw_fence_obj_unreference(out_fence);
-
-               fifo_size = sizeof(*blits) * hit_num;
-               ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits,
-                                         fifo_size, 0, NULL, out_fence);
-
-               if (unlikely(ret != 0))
-                       break;
-       }
-
-       kfree(blits);
-
-       return ret;
-}
-
 static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
                                 struct drm_file *file_priv,
                                 unsigned flags, unsigned color,
@@ -979,13 +627,15 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
        }
 
        if (dev_priv->ldu_priv) {
-               ret = do_dmabuf_dirty_ldu(dev_priv, &vfbd->base,
-                                         flags, color,
-                                         clips, num_clips, increment);
-       } else {
-               ret = do_dmabuf_dirty_sou(file_priv, dev_priv, &vfbd->base,
-                                         flags, color,
-                                         clips, num_clips, increment, NULL);
+               ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base,
+                                                 flags, color,
+                                                 clips, num_clips, increment);
+       } else if (dev_priv->active_display_unit == vmw_du_screen_object) {
+               ret = vmw_kms_sou_do_dmabuf_dirty(file_priv, dev_priv,
+                                                 &vfbd->base,
+                                                 flags, color,
+                                                 clips, num_clips, increment,
+                                                 NULL);
        }
 
        vmw_fifo_flush(dev_priv, false);
@@ -1011,8 +661,8 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb)
                vmw_framebuffer_to_vfbd(&vfb->base);
        int ret;
 
-       /* This code should not be used with screen objects */
-       BUG_ON(dev_priv->sou_priv);
+       /* This code should only be used with Legacy Display Unit */
+       BUG_ON(dev_priv->active_display_unit != vmw_du_legacy);
 
        vmw_overlay_pause_all(dev_priv);
 
@@ -1059,7 +709,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
        }
 
        /* Limited framebuffer color depth support for screen objects */
-       if (dev_priv->sou_priv) {
+       if (dev_priv->active_display_unit == vmw_du_screen_object) {
                switch (mode_cmd->depth) {
                case 32:
                case 24:
@@ -1102,7 +752,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
        vfbd->base.base.depth = mode_cmd->depth;
        vfbd->base.base.width = mode_cmd->width;
        vfbd->base.base.height = mode_cmd->height;
-       if (!dev_priv->sou_priv) {
+       if (dev_priv->active_display_unit == vmw_du_legacy) {
                vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
                vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
        }
@@ -1159,7 +809,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
        if (!vmw_kms_validate_mode_vram(dev_priv,
                                        mode_cmd.pitch,
                                        mode_cmd.height)) {
-               DRM_ERROR("VRAM size is too small for requested mode.\n");
+               DRM_ERROR("Requested mode exceed bounding box limit.\n");
                return ERR_PTR(-ENOMEM);
        }
 
@@ -1220,7 +870,7 @@ static const struct drm_mode_config_funcs vmw_kms_funcs = {
        .fb_create = vmw_kms_fb_create,
 };
 
-int vmw_kms_present(struct vmw_private *dev_priv,
+int vmw_kms_generic_present(struct vmw_private *dev_priv,
                    struct drm_file *file_priv,
                    struct vmw_framebuffer *vfb,
                    struct vmw_surface *surface,
@@ -1358,6 +1008,19 @@ out_free_tmp:
        return ret;
 }
 
+int vmw_kms_present(struct vmw_private *dev_priv,
+                   struct drm_file *file_priv,
+                   struct vmw_framebuffer *vfb,
+                   struct vmw_surface *surface,
+                   uint32_t sid,
+                   int32_t destX, int32_t destY,
+                   struct drm_vmw_rect *clips,
+                   uint32_t num_clips)
+{
+       return vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, sid,
+                                      destX, destY, clips, num_clips);
+}
+
 int vmw_kms_readback(struct vmw_private *dev_priv,
                     struct drm_file *file_priv,
                     struct vmw_framebuffer *vfb,
@@ -1478,26 +1141,29 @@ int vmw_kms_init(struct vmw_private *dev_priv)
        dev->mode_config.max_width = 8192;
        dev->mode_config.max_height = 8192;
 
-       ret = vmw_kms_init_screen_object_display(dev_priv);
+       ret = vmw_kms_sou_init_display(dev_priv);
        if (ret) /* Fallback */
-               (void)vmw_kms_init_legacy_display_system(dev_priv);
+               ret = vmw_kms_ldu_init_display(dev_priv);
 
-       return 0;
+       return ret;
 }
 
 int vmw_kms_close(struct vmw_private *dev_priv)
 {
+       int ret;
+
        /*
         * Docs says we should take the lock before calling this function
         * but since it destroys encoders and our destructor calls
         * drm_encoder_cleanup which takes the lock we deadlock.
         */
        drm_mode_config_cleanup(dev_priv->dev);
-       if (dev_priv->sou_priv)
-               vmw_kms_close_screen_object_display(dev_priv);
+       if (dev_priv->active_display_unit == vmw_du_screen_object)
+               ret = vmw_kms_sou_close_display(dev_priv);
        else
-               vmw_kms_close_legacy_display_system(dev_priv);
-       return 0;
+               ret = vmw_kms_ldu_close_display(dev_priv);
+
+       return ret;
 }
 
 int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
@@ -1573,7 +1239,7 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
                  vmw_read(vmw_priv, SVGA_REG_PITCHLOCK);
        else if (vmw_fifo_have_pitchlock(vmw_priv))
                vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt +
-                                                      SVGA_FIFO_PITCHLOCK);
+                                                  SVGA_FIFO_PITCHLOCK);
 
        if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY))
                return 0;
@@ -1719,75 +1385,6 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
        return 0;
 }
 
-int vmw_du_page_flip(struct drm_crtc *crtc,
-                    struct drm_framebuffer *fb,
-                    struct drm_pending_vblank_event *event,
-                    uint32_t page_flip_flags)
-{
-       struct vmw_private *dev_priv = vmw_priv(crtc->dev);
-       struct drm_framebuffer *old_fb = crtc->primary->fb;
-       struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
-       struct drm_file *file_priv ;
-       struct vmw_fence_obj *fence = NULL;
-       struct drm_clip_rect clips;
-       int ret;
-
-       if (event == NULL)
-               return -EINVAL;
-
-       /* require ScreenObject support for page flipping */
-       if (!dev_priv->sou_priv)
-               return -ENOSYS;
-
-       file_priv = event->base.file_priv;
-       if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
-               return -EINVAL;
-
-       crtc->primary->fb = fb;
-
-       /* do a full screen dirty update */
-       clips.x1 = clips.y1 = 0;
-       clips.x2 = fb->width;
-       clips.y2 = fb->height;
-
-       if (vfb->dmabuf)
-               ret = do_dmabuf_dirty_sou(file_priv, dev_priv, vfb,
-                                         0, 0, &clips, 1, 1, &fence);
-       else
-               ret = do_surface_dirty_sou(dev_priv, file_priv, vfb,
-                                          0, 0, &clips, 1, 1, &fence);
-
-
-       if (ret != 0)
-               goto out_no_fence;
-       if (!fence) {
-               ret = -EINVAL;
-               goto out_no_fence;
-       }
-
-       ret = vmw_event_fence_action_queue(file_priv, fence,
-                                          &event->base,
-                                          &event->event.tv_sec,
-                                          &event->event.tv_usec,
-                                          true);
-
-       /*
-        * No need to hold on to this now. The only cleanup
-        * we need to do if we fail is unref the fence.
-        */
-       vmw_fence_obj_unreference(&fence);
-
-       if (vmw_crtc_to_du(crtc)->is_implicit)
-               vmw_kms_screen_object_update_implicit_fb(dev_priv, crtc);
-
-       return ret;
-
-out_no_fence:
-       crtc->primary->fb = old_fb;
-       return ret;
-}
-
-
 void vmw_du_crtc_save(struct drm_crtc *crtc)
 {
 }
@@ -1958,36 +1555,34 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
         * If using screen objects, then assume 32-bpp because that's what the
         * SVGA device is assuming
         */
-       if (dev_priv->sou_priv)
+       if (dev_priv->active_display_unit == vmw_du_screen_object)
                assumed_bpp = 4;
 
        /* Add preferred mode */
-       {
-               mode = drm_mode_duplicate(dev, &prefmode);
-               if (!mode)
-                       return 0;
-               mode->hdisplay = du->pref_width;
-               mode->vdisplay = du->pref_height;
-               vmw_guess_mode_timing(mode);
-
-               if (vmw_kms_validate_mode_vram(dev_priv,
-                                               mode->hdisplay * assumed_bpp,
-                                               mode->vdisplay)) {
-                       drm_mode_probed_add(connector, mode);
-               } else {
-                       drm_mode_destroy(dev, mode);
-                       mode = NULL;
-               }
+       mode = drm_mode_duplicate(dev, &prefmode);
+       if (!mode)
+               return 0;
+       mode->hdisplay = du->pref_width;
+       mode->vdisplay = du->pref_height;
+       vmw_guess_mode_timing(mode);
 
-               if (du->pref_mode) {
-                       list_del_init(&du->pref_mode->head);
-                       drm_mode_destroy(dev, du->pref_mode);
-               }
+       if (vmw_kms_validate_mode_vram(dev_priv,
+                                       mode->hdisplay * assumed_bpp,
+                                       mode->vdisplay)) {
+               drm_mode_probed_add(connector, mode);
+       } else {
+               drm_mode_destroy(dev, mode);
+               mode = NULL;
+       }
 
-               /* mode might be null here, this is intended */
-               du->pref_mode = mode;
+       if (du->pref_mode) {
+               list_del_init(&du->pref_mode->head);
+               drm_mode_destroy(dev, du->pref_mode);
        }
 
+       /* mode might be null here, this is intended */
+       du->pref_mode = mode;
+
        for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) {
                bmode = &vmw_kms_connector_builtin[i];
                if (bmode->hdisplay > max_width ||
@@ -2036,6 +1631,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
        int ret;
        int i;
        struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_vmw_rect bounding_box = {0};
 
        if (!arg->num_outputs) {
                struct drm_vmw_rect def_rect = {0, 0, 800, 600};
@@ -2066,6 +1662,16 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
                        ret = -EINVAL;
                        goto out_free;
                }
+
+               /*
+                * bounding_box.w and bunding_box.h are used as
+                * lower-right coordinates
+                */
+               if (rects[i].x + rects[i].w > bounding_box.w)
+                       bounding_box.w = rects[i].x + rects[i].w;
+
+               if (rects[i].y + rects[i].h > bounding_box.h)
+                       bounding_box.h = rects[i].y + rects[i].h;
        }
 
        vmw_du_update_layout(dev_priv, arg->num_outputs, rects);
index 8d038c3..0f2c291 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
 #include <drm/drm_crtc_helper.h>
 #include "vmwgfx_drv.h"
 
+
+
 #define VMWGFX_NUM_DISPLAY_UNITS 8
 
 
 #define vmw_framebuffer_to_vfb(x) \
        container_of(x, struct vmw_framebuffer, base)
+#define vmw_framebuffer_to_vfbs(x) \
+       container_of(x, struct vmw_framebuffer_surface, base.base)
+#define vmw_framebuffer_to_vfbd(x) \
+       container_of(x, struct vmw_framebuffer_dmabuf, base.base)
 
 /**
  * Base class for framebuffers
@@ -53,9 +59,36 @@ struct vmw_framebuffer {
        uint32_t user_handle;
 };
 
+/*
+ * Clip rectangle
+ */
+struct vmw_clip_rect {
+       int x1, x2, y1, y2;
+};
+
+struct vmw_framebuffer_surface {
+       struct vmw_framebuffer base;
+       struct vmw_surface *surface;
+       struct vmw_dma_buffer *buffer;
+       struct list_head head;
+       struct drm_master *master;
+};
 
-#define vmw_crtc_to_du(x) \
-       container_of(x, struct vmw_display_unit, crtc)
+
+struct vmw_framebuffer_dmabuf {
+       struct vmw_framebuffer base;
+       struct vmw_dma_buffer *buffer;
+};
+
+
+/*
+ * Basic clip rect manipulation
+ */
+void vmw_clip_cliprects(struct drm_clip_rect *rects,
+                       int num_rects,
+                       struct vmw_clip_rect clip,
+                       SVGASignedRect *out_rects,
+                       int *out_num);
 
 /*
  * Basic cursor manipulation
@@ -120,11 +153,7 @@ struct vmw_display_unit {
 /*
  * Shared display unit functions - vmwgfx_kms.c
  */
-void vmw_display_unit_cleanup(struct vmw_display_unit *du);
-int vmw_du_page_flip(struct drm_crtc *crtc,
-                    struct drm_framebuffer *fb,
-                    struct drm_pending_vblank_event *event,
-                    uint32_t page_flip_flags);
+void vmw_du_cleanup(struct vmw_display_unit *du);
 void vmw_du_crtc_save(struct drm_crtc *crtc);
 void vmw_du_crtc_restore(struct drm_crtc *crtc);
 void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
@@ -148,20 +177,31 @@ int vmw_du_connector_set_property(struct drm_connector *connector,
 /*
  * Legacy display unit functions - vmwgfx_ldu.c
  */
-int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv);
-int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv);
+int vmw_kms_ldu_init_display(struct vmw_private *dev_priv);
+int vmw_kms_ldu_close_display(struct vmw_private *dev_priv);
+int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv,
+                               struct vmw_framebuffer *framebuffer,
+                               unsigned flags, unsigned color,
+                               struct drm_clip_rect *clips,
+                               unsigned num_clips, int increment);
 
 /*
  * Screen Objects display functions - vmwgfx_scrn.c
  */
-int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv);
-int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv);
-int vmw_kms_sou_update_layout(struct vmw_private *dev_priv, unsigned num,
-                             struct drm_vmw_rect *rects);
-bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv,
-                                    struct drm_crtc *crtc);
-void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
-                                             struct drm_crtc *crtc);
-
-
+int vmw_kms_sou_init_display(struct vmw_private *dev_priv);
+int vmw_kms_sou_close_display(struct vmw_private *dev_priv);
+int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
+                                struct drm_file *file_priv,
+                                struct vmw_framebuffer *framebuffer,
+                                unsigned flags, unsigned color,
+                                struct drm_clip_rect *clips,
+                                unsigned num_clips, int inc,
+                                struct vmw_fence_obj **out_fence);
+int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv,
+                               struct vmw_private *dev_priv,
+                               struct vmw_framebuffer *framebuffer,
+                               unsigned flags, unsigned color,
+                               struct drm_clip_rect *clips,
+                               unsigned num_clips, int increment,
+                               struct vmw_fence_obj **out_fence);
 #endif
index 53579f2..f0fd565 100644 (file)
@@ -57,7 +57,7 @@ struct vmw_legacy_display_unit {
 static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu)
 {
        list_del_init(&ldu->active);
-       vmw_display_unit_cleanup(&ldu->base);
+       vmw_du_cleanup(&ldu->base);
        kfree(ldu);
 }
 
@@ -386,7 +386,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
        return 0;
 }
 
-int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
+int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
        int i, ret;
@@ -423,6 +423,10 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
        else
                vmw_ldu_init(dev_priv, 0);
 
+       dev_priv->active_display_unit = vmw_du_legacy;
+
+       DRM_INFO("Legacy Display Unit initialized\n");
+
        return 0;
 
 err_vblank_cleanup:
@@ -433,7 +437,7 @@ err_free:
        return ret;
 }
 
-int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv)
+int vmw_kms_ldu_close_display(struct vmw_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
 
@@ -448,3 +452,38 @@ int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv)
 
        return 0;
 }
+
+
+int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv,
+                               struct vmw_framebuffer *framebuffer,
+                               unsigned flags, unsigned color,
+                               struct drm_clip_rect *clips,
+                               unsigned num_clips, int increment)
+{
+       size_t fifo_size;
+       int i;
+
+       struct {
+               uint32_t header;
+               SVGAFifoCmdUpdate body;
+       } *cmd;
+
+       fifo_size = sizeof(*cmd) * num_clips;
+       cmd = vmw_fifo_reserve(dev_priv, fifo_size);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Fifo reserve failed.\n");
+               return -ENOMEM;
+       }
+
+       memset(cmd, 0, fifo_size);
+       for (i = 0; i < num_clips; i++, clips += increment) {
+               cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE);
+               cmd[i].body.x = cpu_to_le32(clips->x1);
+               cmd[i].body.y = cpu_to_le32(clips->y1);
+               cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1);
+               cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1);
+       }
+
+       vmw_fifo_commit(dev_priv, fifo_size);
+       return 0;
+}
index 87e39f6..7f4b2f0 100644 (file)
@@ -100,7 +100,7 @@ static int vmw_overlay_send_put(struct vmw_private *dev_priv,
 {
        struct vmw_escape_video_flush *flush;
        size_t fifo_size;
-       bool have_so = dev_priv->sou_priv ? true : false;
+       bool have_so = (dev_priv->active_display_unit == vmw_du_screen_object);
        int i, num_items;
        SVGAGuestPtr ptr;
 
@@ -231,7 +231,7 @@ static int vmw_overlay_move_buffer(struct vmw_private *dev_priv,
        if (!pin)
                return vmw_dmabuf_unpin(dev_priv, buf, inter);
 
-       if (!dev_priv->sou_priv)
+       if (dev_priv->active_display_unit == vmw_du_legacy)
                return vmw_dmabuf_to_vram(dev_priv, buf, true, inter);
 
        return vmw_dmabuf_to_vram_or_gmr(dev_priv, buf, true, inter);
@@ -453,7 +453,7 @@ int vmw_overlay_pause_all(struct vmw_private *dev_priv)
 
 static bool vmw_overlay_available(const struct vmw_private *dev_priv)
 {
-       return (dev_priv->overlay_priv != NULL && 
+       return (dev_priv->overlay_priv != NULL &&
                ((dev_priv->fifo.capabilities & VMW_OVERLAY_CAP_MASK) ==
                 VMW_OVERLAY_CAP_MASK));
 }
index 9e8eb36..807fc87 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright © 2011 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2011-2014 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -57,7 +57,7 @@ struct vmw_screen_object_unit {
 
 static void vmw_sou_destroy(struct vmw_screen_object_unit *sou)
 {
-       vmw_display_unit_cleanup(&sou->base);
+       vmw_du_cleanup(&sou->base);
        kfree(sou);
 }
 
@@ -72,7 +72,7 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc)
 }
 
 static void vmw_sou_del_active(struct vmw_private *vmw_priv,
-                             struct vmw_screen_object_unit *sou)
+                              struct vmw_screen_object_unit *sou)
 {
        struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
 
@@ -84,8 +84,8 @@ static void vmw_sou_del_active(struct vmw_private *vmw_priv,
 }
 
 static void vmw_sou_add_active(struct vmw_private *vmw_priv,
-                             struct vmw_screen_object_unit *sou,
-                             struct vmw_framebuffer *vfb)
+                              struct vmw_screen_object_unit *sou,
+                              struct vmw_framebuffer *vfb)
 {
        struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
 
@@ -274,13 +274,13 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
        dev_priv = vmw_priv(crtc->dev);
 
        if (set->num_connectors > 1) {
-               DRM_ERROR("to many connectors\n");
+               DRM_ERROR("Too many connectors\n");
                return -EINVAL;
        }
 
        if (set->num_connectors == 1 &&
            set->connectors[0] != &sou->base.connector) {
-               DRM_ERROR("connector doesn't match %p %p\n",
+               DRM_ERROR("Connector doesn't match %p %p\n",
                        set->connectors[0], &sou->base.connector);
                return -EINVAL;
        }
@@ -391,6 +391,250 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
        return 0;
 }
 
+/**
+ * Returns if this unit can be page flipped.
+ * Must be called with the mode_config mutex held.
+ */
+static bool vmw_sou_screen_object_flippable(struct vmw_private *dev_priv,
+                                           struct drm_crtc *crtc)
+{
+       struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
+
+       if (!sou->base.is_implicit)
+               return true;
+
+       if (dev_priv->sou_priv->num_implicit != 1)
+               return false;
+
+       return true;
+}
+
+/**
+ * Update the implicit fb to the current fb of this crtc.
+ * Must be called with the mode_config mutex held.
+ */
+void vmw_sou_update_implicit_fb(struct vmw_private *dev_priv,
+                               struct drm_crtc *crtc)
+{
+       struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
+
+       BUG_ON(!sou->base.is_implicit);
+
+       dev_priv->sou_priv->implicit_fb =
+               vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
+}
+
+static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc,
+                                 struct drm_framebuffer *fb,
+                                 struct drm_pending_vblank_event *event,
+                                 uint32_t flags)
+{
+       struct vmw_private *dev_priv = vmw_priv(crtc->dev);
+       struct drm_framebuffer *old_fb = crtc->primary->fb;
+       struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
+       struct drm_file *file_priv = event->base.file_priv;
+       struct vmw_fence_obj *fence = NULL;
+       struct drm_clip_rect clips;
+       int ret;
+
+       /* require ScreenObject support for page flipping */
+       if (!dev_priv->sou_priv)
+               return -ENOSYS;
+
+       if (!vmw_sou_screen_object_flippable(dev_priv, crtc))
+               return -EINVAL;
+
+       crtc->primary->fb = fb;
+
+       /* do a full screen dirty update */
+       clips.x1 = clips.y1 = 0;
+       clips.x2 = fb->width;
+       clips.y2 = fb->height;
+
+       if (vfb->dmabuf)
+               ret = vmw_kms_sou_do_dmabuf_dirty(file_priv, dev_priv, vfb,
+                                                 0, 0, &clips, 1, 1, &fence);
+       else
+               ret = vmw_kms_sou_do_surface_dirty(dev_priv, file_priv, vfb,
+                                                  0, 0, &clips, 1, 1, &fence);
+
+
+       if (ret != 0)
+               goto out_no_fence;
+       if (!fence) {
+               ret = -EINVAL;
+               goto out_no_fence;
+       }
+
+       ret = vmw_event_fence_action_queue(file_priv, fence,
+                                          &event->base,
+                                          &event->event.tv_sec,
+                                          &event->event.tv_usec,
+                                          true);
+
+       /*
+        * No need to hold on to this now. The only cleanup
+        * we need to do if we fail is unref the fence.
+        */
+       vmw_fence_obj_unreference(&fence);
+
+       if (vmw_crtc_to_du(crtc)->is_implicit)
+               vmw_sou_update_implicit_fb(dev_priv, crtc);
+
+       return ret;
+
+out_no_fence:
+       crtc->primary->fb = old_fb;
+       return ret;
+}
+
+int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
+                                struct drm_file *file_priv,
+                                struct vmw_framebuffer *framebuffer,
+                                unsigned flags, unsigned color,
+                                struct drm_clip_rect *clips,
+                                unsigned num_clips, int inc,
+                                struct vmw_fence_obj **out_fence)
+{
+       struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
+       struct drm_clip_rect *clips_ptr;
+       struct drm_clip_rect *tmp;
+       struct drm_crtc *crtc;
+       size_t fifo_size;
+       int i, num_units;
+       int ret = 0; /* silence warning */
+       int left, right, top, bottom;
+
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBlitSurfaceToScreen body;
+       } *cmd;
+       SVGASignedRect *blits;
+
+       num_units = 0;
+       list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
+                           head) {
+               if (crtc->primary->fb != &framebuffer->base)
+                       continue;
+               units[num_units++] = vmw_crtc_to_du(crtc);
+       }
+
+       BUG_ON(!clips || !num_clips);
+
+       tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL);
+       if (unlikely(tmp == NULL)) {
+               DRM_ERROR("Temporary cliprect memory alloc failed.\n");
+               return -ENOMEM;
+       }
+
+       fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips;
+       cmd = kzalloc(fifo_size, GFP_KERNEL);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Temporary fifo memory alloc failed.\n");
+               ret = -ENOMEM;
+               goto out_free_tmp;
+       }
+
+       /* setup blits pointer */
+       blits = (SVGASignedRect *)&cmd[1];
+
+       /* initial clip region */
+       left = clips->x1;
+       right = clips->x2;
+       top = clips->y1;
+       bottom = clips->y2;
+
+       /* skip the first clip rect */
+       for (i = 1, clips_ptr = clips + inc;
+            i < num_clips; i++, clips_ptr += inc) {
+               left = min_t(int, left, (int)clips_ptr->x1);
+               right = max_t(int, right, (int)clips_ptr->x2);
+               top = min_t(int, top, (int)clips_ptr->y1);
+               bottom = max_t(int, bottom, (int)clips_ptr->y2);
+       }
+
+       /* only need to do this once */
+       cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN);
+       cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
+
+       cmd->body.srcRect.left = left;
+       cmd->body.srcRect.right = right;
+       cmd->body.srcRect.top = top;
+       cmd->body.srcRect.bottom = bottom;
+
+       clips_ptr = clips;
+       for (i = 0; i < num_clips; i++, clips_ptr += inc) {
+               tmp[i].x1 = clips_ptr->x1 - left;
+               tmp[i].x2 = clips_ptr->x2 - left;
+               tmp[i].y1 = clips_ptr->y1 - top;
+               tmp[i].y2 = clips_ptr->y2 - top;
+       }
+
+       /* do per unit writing, reuse fifo for each */
+       for (i = 0; i < num_units; i++) {
+               struct vmw_display_unit *unit = units[i];
+               struct vmw_clip_rect clip;
+               int num;
+
+               clip.x1 = left - unit->crtc.x;
+               clip.y1 = top - unit->crtc.y;
+               clip.x2 = right - unit->crtc.x;
+               clip.y2 = bottom - unit->crtc.y;
+
+               /* skip any crtcs that misses the clip region */
+               if (clip.x1 >= unit->crtc.mode.hdisplay ||
+                   clip.y1 >= unit->crtc.mode.vdisplay ||
+                   clip.x2 <= 0 || clip.y2 <= 0)
+                       continue;
+
+               /*
+                * In order for the clip rects to be correctly scaled
+                * the src and dest rects needs to be the same size.
+                */
+               cmd->body.destRect.left = clip.x1;
+               cmd->body.destRect.right = clip.x2;
+               cmd->body.destRect.top = clip.y1;
+               cmd->body.destRect.bottom = clip.y2;
+
+               /* create a clip rect of the crtc in dest coords */
+               clip.x2 = unit->crtc.mode.hdisplay - clip.x1;
+               clip.y2 = unit->crtc.mode.vdisplay - clip.y1;
+               clip.x1 = 0 - clip.x1;
+               clip.y1 = 0 - clip.y1;
+
+               /* need to reset sid as it is changed by execbuf */
+               cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle);
+               cmd->body.destScreenId = unit->unit;
+
+               /* clip and write blits to cmd stream */
+               vmw_clip_cliprects(tmp, num_clips, clip, blits, &num);
+
+               /* if no cliprects hit skip this */
+               if (num == 0)
+                       continue;
+
+               /* only return the last fence */
+               if (out_fence && *out_fence)
+                       vmw_fence_obj_unreference(out_fence);
+
+               /* recalculate package length */
+               fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
+               cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
+               ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
+                                         fifo_size, 0, NULL, out_fence);
+
+               if (unlikely(ret != 0))
+                       break;
+       }
+
+
+       kfree(cmd);
+out_free_tmp:
+       kfree(tmp);
+
+       return ret;
+}
+
 static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
        .save = vmw_du_crtc_save,
        .restore = vmw_du_crtc_restore,
@@ -399,7 +643,7 @@ static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
        .gamma_set = vmw_du_crtc_gamma_set,
        .destroy = vmw_sou_crtc_destroy,
        .set_config = vmw_sou_crtc_set_config,
-       .page_flip = vmw_du_page_flip,
+       .page_flip = vmw_sou_crtc_page_flip,
 };
 
 /*
@@ -424,7 +668,7 @@ static void vmw_sou_connector_destroy(struct drm_connector *connector)
        vmw_sou_destroy(vmw_connector_to_sou(connector));
 }
 
-static struct drm_connector_funcs vmw_legacy_connector_funcs = {
+static struct drm_connector_funcs vmw_sou_connector_funcs = {
        .dpms = vmw_du_connector_dpms,
        .save = vmw_du_connector_save,
        .restore = vmw_du_connector_restore,
@@ -459,7 +703,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
        sou->base.pref_mode = NULL;
        sou->base.is_implicit = true;
 
-       drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
+       drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
                           DRM_MODE_CONNECTOR_VIRTUAL);
        connector->status = vmw_du_connector_detect(connector, true);
 
@@ -482,7 +726,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
        return 0;
 }
 
-int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv)
+int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
        int i, ret;
@@ -517,7 +761,9 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv)
        for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
                vmw_sou_init(dev_priv, i);
 
-       DRM_INFO("Screen objects system initialized\n");
+       dev_priv->active_display_unit = vmw_du_screen_object;
+
+       DRM_INFO("Screen Objects Display Unit initialized\n");
 
        return 0;
 
@@ -530,7 +776,7 @@ err_no_mem:
        return ret;
 }
 
-int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv)
+int vmw_kms_sou_close_display(struct vmw_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
 
@@ -544,35 +790,143 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv)
        return 0;
 }
 
-/**
- * Returns if this unit can be page flipped.
- * Must be called with the mode_config mutex held.
- */
-bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv,
-                                    struct drm_crtc *crtc)
+static int do_dmabuf_define_gmrfb(struct drm_file *file_priv,
+                                 struct vmw_private *dev_priv,
+                                 struct vmw_framebuffer *framebuffer)
 {
-       struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
+       int depth = framebuffer->base.depth;
+       size_t fifo_size;
+       int ret;
 
-       if (!sou->base.is_implicit)
-               return true;
+       struct {
+               uint32_t header;
+               SVGAFifoCmdDefineGMRFB body;
+       } *cmd;
 
-       if (dev_priv->sou_priv->num_implicit != 1)
-               return false;
+       /* Emulate RGBA support, contrary to svga_reg.h this is not
+        * supported by hosts. This is only a problem if we are reading
+        * this value later and expecting what we uploaded back.
+        */
+       if (depth == 32)
+               depth = 24;
 
-       return true;
+       fifo_size = sizeof(*cmd);
+       cmd = kmalloc(fifo_size, GFP_KERNEL);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed to allocate temporary cmd buffer.\n");
+               return -ENOMEM;
+       }
+
+       memset(cmd, 0, fifo_size);
+       cmd->header = SVGA_CMD_DEFINE_GMRFB;
+       cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel;
+       cmd->body.format.colorDepth = depth;
+       cmd->body.format.reserved = 0;
+       cmd->body.bytesPerLine = framebuffer->base.pitches[0];
+       cmd->body.ptr.gmrId = framebuffer->user_handle;
+       cmd->body.ptr.offset = 0;
+
+       ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
+                                 fifo_size, 0, NULL, NULL);
+
+       kfree(cmd);
+
+       return ret;
 }
 
-/**
- * Update the implicit fb to the current fb of this crtc.
- * Must be called with the mode_config mutex held.
- */
-void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
-                                             struct drm_crtc *crtc)
+int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv,
+                               struct vmw_private *dev_priv,
+                               struct vmw_framebuffer *framebuffer,
+                               unsigned flags, unsigned color,
+                               struct drm_clip_rect *clips,
+                               unsigned num_clips, int increment,
+                               struct vmw_fence_obj **out_fence)
 {
-       struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
+       struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
+       struct drm_clip_rect *clips_ptr;
+       int i, k, num_units, ret;
+       struct drm_crtc *crtc;
+       size_t fifo_size;
 
-       BUG_ON(!sou->base.is_implicit);
+       struct {
+               uint32_t header;
+               SVGAFifoCmdBlitGMRFBToScreen body;
+       } *blits;
 
-       dev_priv->sou_priv->implicit_fb =
-               vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
+       ret = do_dmabuf_define_gmrfb(file_priv, dev_priv, framebuffer);
+       if (unlikely(ret != 0))
+               return ret; /* define_gmrfb prints warnings */
+
+       fifo_size = sizeof(*blits) * num_clips;
+       blits = kmalloc(fifo_size, GFP_KERNEL);
+       if (unlikely(blits == NULL)) {
+               DRM_ERROR("Failed to allocate temporary cmd buffer.\n");
+               return -ENOMEM;
+       }
+
+       num_units = 0;
+       list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
+               if (crtc->primary->fb != &framebuffer->base)
+                       continue;
+               units[num_units++] = vmw_crtc_to_du(crtc);
+       }
+
+       for (k = 0; k < num_units; k++) {
+               struct vmw_display_unit *unit = units[k];
+               int hit_num = 0;
+
+               clips_ptr = clips;
+               for (i = 0; i < num_clips; i++, clips_ptr += increment) {
+                       int clip_x1 = clips_ptr->x1 - unit->crtc.x;
+                       int clip_y1 = clips_ptr->y1 - unit->crtc.y;
+                       int clip_x2 = clips_ptr->x2 - unit->crtc.x;
+                       int clip_y2 = clips_ptr->y2 - unit->crtc.y;
+                       int move_x, move_y;
+
+                       /* skip any crtcs that misses the clip region */
+                       if (clip_x1 >= unit->crtc.mode.hdisplay ||
+                           clip_y1 >= unit->crtc.mode.vdisplay ||
+                           clip_x2 <= 0 || clip_y2 <= 0)
+                               continue;
+
+                       /* clip size to crtc size */
+                       clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay);
+                       clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay);
+
+                       /* translate both src and dest to bring clip into screen */
+                       move_x = min_t(int, clip_x1, 0);
+                       move_y = min_t(int, clip_y1, 0);
+
+                       /* actual translate done here */
+                       blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
+                       blits[hit_num].body.destScreenId = unit->unit;
+                       blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x;
+                       blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y;
+                       blits[hit_num].body.destRect.left = clip_x1 - move_x;
+                       blits[hit_num].body.destRect.top = clip_y1 - move_y;
+                       blits[hit_num].body.destRect.right = clip_x2;
+                       blits[hit_num].body.destRect.bottom = clip_y2;
+                       hit_num++;
+               }
+
+               /* no clips hit the crtc */
+               if (hit_num == 0)
+                       continue;
+
+               /* only return the last fence */
+               if (out_fence && *out_fence)
+                       vmw_fence_obj_unreference(out_fence);
+
+               fifo_size = sizeof(*blits) * hit_num;
+               ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits,
+                                         fifo_size, 0, NULL, out_fence);
+
+               if (unlikely(ret != 0))
+                       break;
+       }
+
+       kfree(blits);
+
+       return ret;
 }
+