diff options
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 34 |
3 files changed, 106 insertions, 0 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 24efcae3e2f5..2286d47e5022 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -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) { } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index a4f7f034996a..8184bc5b1730 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -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 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 4defdcf1c72e..97aca0bf94d0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -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); +} |