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 <drawat@vmware.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
This commit is contained in:
Deepak Rawat 2018-07-11 15:42:45 -07:00 committed by Thomas Hellstrom
parent b9fc5e01d1
commit e41774c08e
2 changed files with 233 additions and 0 deletions

View 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;
}

View file

@ -33,7 +33,101 @@
#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