drm/vmwgfx: Add a new interface for plane update on a display unit
authorDeepak Rawat <drawat@vmware.com>
Wed, 11 Jul 2018 22:42:45 +0000 (15:42 -0700)
committerThomas Hellstrom <thellstrom@vmware.com>
Wed, 5 Dec 2018 09:00:37 +0000 (10:00 +0100)
Add a new struct vmw_du_update_plane similar to vmw_kms_dirty which
represent the flow of operations needed to update a display unit from
surface or bo (blit a new framebuffer).

v2:
- Kernel doc correction.
- Rebase.

v3: Rebase to new resource validation.

Signed-off-by: Deepak Rawat <drawat@vmware.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h

index e6b11f6ae2e45481e246d70c5e4dfb16ed9f0dae..a2c0a95798f24c7cd18f3b616d3297ffd8bdea02 100644 (file)
@@ -30,6 +30,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_damage_helper.h>
 
 /* Might need a hrtimer here? */
 #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
@@ -2935,3 +2936,124 @@ void vmw_kms_lost_device(struct drm_device *dev)
 {
        drm_atomic_helper_shutdown(dev);
 }
+
+/**
+ * vmw_du_helper_plane_update - Helper to do plane update on a display unit.
+ * @update: The closure structure.
+ *
+ * Call this helper after setting callbacks in &vmw_du_update_plane to do plane
+ * update on display unit.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int vmw_du_helper_plane_update(struct vmw_du_update_plane *update)
+{
+       struct drm_plane_state *state = update->plane->state;
+       struct drm_plane_state *old_state = update->old_state;
+       struct drm_atomic_helper_damage_iter iter;
+       struct drm_rect clip;
+       struct drm_rect bb;
+       DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
+       uint32_t reserved_size = 0;
+       uint32_t submit_size = 0;
+       uint32_t curr_size = 0;
+       uint32_t num_hits = 0;
+       void *cmd_start;
+       char *cmd_next;
+       int ret;
+
+       /*
+        * Iterate in advance to check if really need plane update and find the
+        * number of clips that actually are in plane src for fifo allocation.
+        */
+       drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+       drm_atomic_for_each_plane_damage(&iter, &clip)
+               num_hits++;
+
+       if (num_hits == 0)
+               return 0;
+
+       if (update->vfb->bo) {
+               struct vmw_framebuffer_bo *vfbbo =
+                       container_of(update->vfb, typeof(*vfbbo), base);
+
+               ret = vmw_validation_add_bo(&val_ctx, vfbbo->buffer, false,
+                                           update->cpu_blit);
+       } else {
+               struct vmw_framebuffer_surface *vfbs =
+                       container_of(update->vfb, typeof(*vfbs), base);
+
+               ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res,
+                                                 0, NULL, NULL);
+       }
+
+       if (ret)
+               return ret;
+
+       ret = vmw_validation_prepare(&val_ctx, update->mutex, update->intr);
+       if (ret)
+               goto out_unref;
+
+       reserved_size = update->calc_fifo_size(update, num_hits);
+       cmd_start = vmw_fifo_reserve(update->dev_priv, reserved_size);
+       if (!cmd_start) {
+               ret = -ENOMEM;
+               goto out_revert;
+       }
+
+       cmd_next = cmd_start;
+
+       if (update->post_prepare) {
+               curr_size = update->post_prepare(update, cmd_next);
+               cmd_next += curr_size;
+               submit_size += curr_size;
+       }
+
+       if (update->pre_clip) {
+               curr_size = update->pre_clip(update, cmd_next, num_hits);
+               cmd_next += curr_size;
+               submit_size += curr_size;
+       }
+
+       bb.x1 = INT_MAX;
+       bb.y1 = INT_MAX;
+       bb.x2 = INT_MIN;
+       bb.y2 = INT_MIN;
+
+       drm_atomic_helper_damage_iter_init(&iter, old_state, state);
+       drm_atomic_for_each_plane_damage(&iter, &clip) {
+               uint32_t fb_x = clip.x1;
+               uint32_t fb_y = clip.y1;
+
+               vmw_du_translate_to_crtc(state, &clip);
+               if (update->clip) {
+                       curr_size = update->clip(update, cmd_next, &clip, fb_x,
+                                                fb_y);
+                       cmd_next += curr_size;
+                       submit_size += curr_size;
+               }
+               bb.x1 = min_t(int, bb.x1, clip.x1);
+               bb.y1 = min_t(int, bb.y1, clip.y1);
+               bb.x2 = max_t(int, bb.x2, clip.x2);
+               bb.y2 = max_t(int, bb.y2, clip.y2);
+       }
+
+       curr_size = update->post_clip(update, cmd_next, &bb);
+       submit_size += curr_size;
+
+       if (reserved_size < submit_size)
+               submit_size = 0;
+
+       vmw_fifo_commit(update->dev_priv, submit_size);
+
+       vmw_kms_helper_validation_finish(update->dev_priv, NULL, &val_ctx,
+                                        update->out_fence, NULL);
+       return ret;
+
+out_revert:
+       vmw_validation_revert(&val_ctx);
+
+out_unref:
+       vmw_validation_unref_lists(&val_ctx);
+       return ret;
+}
index 76ec570c0684f4c2e17dad2973912840c3b9281f..f2f57e58dd88ca398893b686c6a6871d238a548c 100644 (file)
 #include <drm/drm_encoder.h>
 #include "vmwgfx_drv.h"
 
+/**
+ * struct vmw_du_update_plane - Closure structure for vmw_du_helper_plane_update
+ * @plane: Plane which is being updated.
+ * @old_state: Old state of plane.
+ * @dev_priv: Device private.
+ * @du: Display unit on which to update the plane.
+ * @vfb: Framebuffer which is blitted to display unit.
+ * @out_fence: Out fence for resource finish.
+ * @mutex: The mutex used to protect resource reservation.
+ * @cpu_blit: True if need cpu blit.
+ * @intr: Whether to perform waits interruptible if possible.
+ *
+ * This structure loosely represent the set of operations needed to perform a
+ * plane update on a display unit. Implementer will define that functionality
+ * according to the function callbacks for this structure. In brief it involves
+ * surface/buffer object validation, populate FIFO commands and command
+ * submission to the device.
+ */
+struct vmw_du_update_plane {
+       /**
+        * @calc_fifo_size: Calculate fifo size.
+        *
+        * Determine fifo size for the commands needed for update. The number of
+        * damage clips on display unit @num_hits will be passed to allocate
+        * sufficient fifo space.
+        *
+        * Return: Fifo size needed
+        */
+       uint32_t (*calc_fifo_size)(struct vmw_du_update_plane *update,
+                                  uint32_t num_hits);
+
+       /**
+        * @post_prepare: Populate fifo for resource preparation.
+        *
+        * Some surface resource or buffer object need some extra cmd submission
+        * like update GB image for proxy surface and define a GMRFB for screen
+        * object. That should should be done here as this callback will be
+        * called after FIFO allocation with the address of command buufer.
+        *
+        * This callback is optional.
+        *
+        * Return: Size of commands populated to command buffer.
+        */
+       uint32_t (*post_prepare)(struct vmw_du_update_plane *update, void *cmd);
+
+       /**
+        * @pre_clip: Populate fifo before clip.
+        *
+        * This is where pre clip related command should be populated like
+        * surface copy/DMA, etc.
+        *
+        * This callback is optional.
+        *
+        * Return: Size of commands populated to command buffer.
+        */
+       uint32_t (*pre_clip)(struct vmw_du_update_plane *update, void *cmd,
+                            uint32_t num_hits);
 
+       /**
+        * @clip: Populate fifo for clip.
+        *
+        * This is where to populate clips for surface copy/dma or blit commands
+        * if needed. This will be called times have damage in display unit,
+        * which is one if doing full update. @clip is the damage in destination
+        * coordinates which is crtc/DU and @src_x, @src_y is damage clip src in
+        * framebuffer coordinate.
+        *
+        * This callback is optional.
+        *
+        * Return: Size of commands populated to command buffer.
+        */
+       uint32_t (*clip)(struct vmw_du_update_plane *update, void *cmd,
+                        struct drm_rect *clip, uint32_t src_x, uint32_t src_y);
+
+       /**
+        * @post_clip: Populate fifo after clip.
+        *
+        * This is where to populate display unit update commands or blit
+        * commands.
+        *
+        * Return: Size of commands populated to command buffer.
+        */
+       uint32_t (*post_clip)(struct vmw_du_update_plane *update, void *cmd,
+                                   struct drm_rect *bb);
+
+       struct drm_plane *plane;
+       struct drm_plane_state *old_state;
+       struct vmw_private *dev_priv;
+       struct vmw_display_unit *du;
+       struct vmw_framebuffer *vfb;
+       struct vmw_fence_obj **out_fence;
+       struct mutex *mutex;
+       bool cpu_blit;
+       bool intr;
+};
 
 /**
  * struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty
@@ -458,4 +552,21 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
 
 int vmw_kms_set_config(struct drm_mode_set *set,
                       struct drm_modeset_acquire_ctx *ctx);
+
+int vmw_du_helper_plane_update(struct vmw_du_update_plane *update);
+
+/**
+ * vmw_du_translate_to_crtc - Translate a rect from framebuffer to crtc
+ * @state: Plane state.
+ * @r: Rectangle to translate.
+ */
+static inline void vmw_du_translate_to_crtc(struct drm_plane_state *state,
+                                           struct drm_rect *r)
+{
+       int translate_crtc_x = -((state->src_x >> 16) - state->crtc_x);
+       int translate_crtc_y = -((state->src_y >> 16) - state->crtc_y);
+
+       drm_rect_translate(r, translate_crtc_x, translate_crtc_y);
+}
+
 #endif