From e41774c08ede53d96501f28f68645107f232960d Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Wed, 11 Jul 2018 15:42:45 -0700 Subject: [PATCH] drm/vmwgfx: Add a new interface for plane update on a display unit 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 Reviewed-by: Thomas Hellstrom Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 122 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 111 ++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index e6b11f6ae2e4..a2c0a95798f2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -30,6 +30,7 @@ #include #include #include +#include /* 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; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 76ec570c0684..f2f57e58dd88 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -33,7 +33,101 @@ #include #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 -- 2.11.0