vmwgfx: Add page flip support
authorJakob Bornecrantz <jakob@vmware.com>
Thu, 9 Feb 2012 15:56:45 +0000 (16:56 +0100)
committerDave Airlie <airlied@redhat.com>
Mon, 13 Feb 2012 12:01:35 +0000 (12:01 +0000)
Signed-off-by: Jakob Bornecrantz <jakob@vmware.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c

index 24efcae3e2f52e68821414ed23c5736eb1e65892..2286d47e5022029af20bf4e03de6b81879bd911c 100644 (file)
@@ -1681,6 +1681,70 @@ 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)
+{
+       struct vmw_private *dev_priv = vmw_priv(crtc->dev);
+       struct drm_framebuffer *old_fb = crtc->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_kms_screen_object_flippable(dev_priv, crtc))
+               return -EINVAL;
+
+       crtc->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->fb = old_fb;
+       return ret;
+}
+
+
 void vmw_du_crtc_save(struct drm_crtc *crtc)
 {
 }
index a4f7f034996a87bc45d805b82022932e44f35d00..8184bc5b17301eb038920447ae78372519c2e11d 100644 (file)
@@ -121,6 +121,9 @@ 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);
 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,
@@ -154,5 +157,10 @@ 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);
+
 
 #endif
index 4defdcf1c72e2023eaf23f8598c0b83f2803b289..97aca0bf94d0df19f050e757860bbf0fdab617c7 100644 (file)
@@ -394,6 +394,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,
 };
 
 /*
@@ -535,3 +536,36 @@ 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)
+{
+       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_kms_screen_object_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.fb);
+}