drm/vmwgfx: Clean up cursor mobs
Clean up the cursor mob path by moving ownership of the mobs into the plane_state, and just leaving a cache of unused mobs in the plane itself. Signed-off-by: Michael Banack <banackm@vmware.com> Signed-off-by: Zack Rusin <zackr@vmware.com> Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-7-zack@kde.org
This commit is contained in:
parent
9e931f2e09
commit
53bc3f6fb6
2 changed files with 271 additions and 197 deletions
|
@ -53,33 +53,33 @@ void vmw_du_cleanup(struct vmw_display_unit *du)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
|
static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
|
||||||
struct ttm_buffer_object *bo,
|
struct vmw_plane_state *vps,
|
||||||
struct ttm_bo_kmap_obj *map,
|
|
||||||
u32 *image, u32 width, u32 height,
|
u32 *image, u32 width, u32 height,
|
||||||
u32 hotspotX, u32 hotspotY);
|
u32 hotspotX, u32 hotspotY);
|
||||||
|
static int vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps);
|
||||||
|
|
||||||
struct vmw_svga_fifo_cmd_define_cursor {
|
struct vmw_svga_fifo_cmd_define_cursor {
|
||||||
u32 cmd;
|
u32 cmd;
|
||||||
SVGAFifoCmdDefineAlphaCursor cursor;
|
SVGAFifoCmdDefineAlphaCursor cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vmw_cursor_update_image(struct vmw_private *dev_priv,
|
/**
|
||||||
struct ttm_buffer_object *cm_bo,
|
* vmw_send_define_cursor_cmd - queue a define cursor command
|
||||||
struct ttm_bo_kmap_obj *cm_map,
|
* @dev_priv: the private driver struct
|
||||||
u32 *image, u32 width, u32 height,
|
* @image: buffer which holds the cursor image
|
||||||
u32 hotspotX, u32 hotspotY)
|
* @width: width of the mouse cursor image
|
||||||
|
* @height: height of the mouse cursor image
|
||||||
|
* @hotspotX: the horizontal position of mouse hotspot
|
||||||
|
* @hotspotY: the vertical position of mouse hotspot
|
||||||
|
*/
|
||||||
|
static void vmw_send_define_cursor_cmd(struct vmw_private *dev_priv,
|
||||||
|
u32 *image, u32 width, u32 height,
|
||||||
|
u32 hotspotX, u32 hotspotY)
|
||||||
{
|
{
|
||||||
struct vmw_svga_fifo_cmd_define_cursor *cmd;
|
struct vmw_svga_fifo_cmd_define_cursor *cmd;
|
||||||
const u32 image_size = width * height * sizeof(*image);
|
const u32 image_size = width * height * sizeof(*image);
|
||||||
const u32 cmd_size = sizeof(*cmd) + image_size;
|
const u32 cmd_size = sizeof(*cmd) + image_size;
|
||||||
|
|
||||||
if (cm_bo != NULL) {
|
|
||||||
vmw_cursor_update_mob(dev_priv, cm_bo, cm_map, image,
|
|
||||||
width, height,
|
|
||||||
hotspotX, hotspotY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to reserve fifocmd space and swallow any failures;
|
/* Try to reserve fifocmd space and swallow any failures;
|
||||||
such reservations cannot be left unconsumed for long
|
such reservations cannot be left unconsumed for long
|
||||||
under the risk of clogging other fifocmd users, so
|
under the risk of clogging other fifocmd users, so
|
||||||
|
@ -104,12 +104,39 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv,
|
||||||
vmw_cmd_commit_flush(dev_priv, cmd_size);
|
vmw_cmd_commit_flush(dev_priv, cmd_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vmw_cursor_update_image - update the cursor image on the provided plane
|
||||||
|
* @dev_priv: the private driver struct
|
||||||
|
* @vps: the plane state of the cursor plane
|
||||||
|
* @image: buffer which holds the cursor image
|
||||||
|
* @width: width of the mouse cursor image
|
||||||
|
* @height: height of the mouse cursor image
|
||||||
|
* @hotspotX: the horizontal position of mouse hotspot
|
||||||
|
* @hotspotY: the vertical position of mouse hotspot
|
||||||
|
*/
|
||||||
|
static void vmw_cursor_update_image(struct vmw_private *dev_priv,
|
||||||
|
struct vmw_plane_state *vps,
|
||||||
|
u32 *image, u32 width, u32 height,
|
||||||
|
u32 hotspotX, u32 hotspotY)
|
||||||
|
{
|
||||||
|
if (vps->cursor.bo != NULL)
|
||||||
|
vmw_cursor_update_mob(dev_priv, vps, image,
|
||||||
|
width, height,
|
||||||
|
hotspotX, hotspotY);
|
||||||
|
else
|
||||||
|
vmw_send_define_cursor_cmd(dev_priv, image, width, height,
|
||||||
|
hotspotX, hotspotY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vmw_cursor_update_mob - Update cursor vis CursorMob mechanism
|
* vmw_cursor_update_mob - Update cursor vis CursorMob mechanism
|
||||||
*
|
*
|
||||||
|
* Called from inside vmw_du_cursor_plane_atomic_update to actually
|
||||||
|
* make the cursor-image live.
|
||||||
|
*
|
||||||
* @dev_priv: device to work with
|
* @dev_priv: device to work with
|
||||||
* @bo: BO for the MOB
|
* @vps: the plane state of the cursor plane
|
||||||
* @map: kmap obj for the BO
|
|
||||||
* @image: cursor source data to fill the MOB with
|
* @image: cursor source data to fill the MOB with
|
||||||
* @width: source data width
|
* @width: source data width
|
||||||
* @height: source data height
|
* @height: source data height
|
||||||
|
@ -117,8 +144,7 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv,
|
||||||
* @hotspotY: cursor hotspot Y
|
* @hotspotY: cursor hotspot Y
|
||||||
*/
|
*/
|
||||||
static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
|
static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
|
||||||
struct ttm_buffer_object *bo,
|
struct vmw_plane_state *vps,
|
||||||
struct ttm_bo_kmap_obj *map,
|
|
||||||
u32 *image, u32 width, u32 height,
|
u32 *image, u32 width, u32 height,
|
||||||
u32 hotspotX, u32 hotspotY)
|
u32 hotspotX, u32 hotspotY)
|
||||||
{
|
{
|
||||||
|
@ -127,11 +153,11 @@ static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
|
||||||
const u32 image_size = width * height * sizeof(*image);
|
const u32 image_size = width * height * sizeof(*image);
|
||||||
bool dummy;
|
bool dummy;
|
||||||
|
|
||||||
BUG_ON(!image);
|
header = ttm_kmap_obj_virtual(&vps->cursor.map, &dummy);
|
||||||
|
|
||||||
header = (SVGAGBCursorHeader *)ttm_kmap_obj_virtual(map, &dummy);
|
|
||||||
alpha_header = &header->header.alphaHeader;
|
alpha_header = &header->header.alphaHeader;
|
||||||
|
|
||||||
|
memset(header, 0, sizeof(*header));
|
||||||
|
|
||||||
header->type = SVGA_ALPHA_CURSOR;
|
header->type = SVGA_ALPHA_CURSOR;
|
||||||
header->sizeInBytes = image_size;
|
header->sizeInBytes = image_size;
|
||||||
|
|
||||||
|
@ -141,102 +167,116 @@ static void vmw_cursor_update_mob(struct vmw_private *dev_priv,
|
||||||
alpha_header->height = height;
|
alpha_header->height = height;
|
||||||
|
|
||||||
memcpy(header + 1, image, image_size);
|
memcpy(header + 1, image, image_size);
|
||||||
|
vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID,
|
||||||
vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, bo->resource->start);
|
vps->cursor.bo->resource->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp)
|
static u32 vmw_du_cursor_mob_size(u32 w, u32 h)
|
||||||
{
|
{
|
||||||
size_t i;
|
return w * h * sizeof(u32) + sizeof(SVGAGBCursorHeader);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(vcp->cursor_mob); i++) {
|
static void vmw_du_destroy_cursor_mob(struct ttm_buffer_object **bo)
|
||||||
if (vcp->cursor_mob[i] != NULL) {
|
{
|
||||||
ttm_bo_unpin(vcp->cursor_mob[i]);
|
if (*bo == NULL)
|
||||||
ttm_bo_put(vcp->cursor_mob[i]);
|
return;
|
||||||
kfree(vcp->cursor_mob[i]);
|
|
||||||
vcp->cursor_mob[i] = NULL;
|
ttm_bo_unpin(*bo);
|
||||||
|
ttm_bo_put(*bo);
|
||||||
|
kfree(*bo);
|
||||||
|
*bo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vmw_du_put_cursor_mob(struct vmw_cursor_plane *vcp,
|
||||||
|
struct vmw_plane_state *vps)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
if (vps->cursor.bo == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vmw_du_cursor_plane_unmap_cm(vps);
|
||||||
|
|
||||||
|
/* Look for a free slot to return this mob to the cache. */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) {
|
||||||
|
if (vcp->cursor_mobs[i] == NULL) {
|
||||||
|
vcp->cursor_mobs[i] = vps->cursor.bo;
|
||||||
|
vps->cursor.bo = NULL;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cache is full: See if this mob is bigger than an existing mob. */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) {
|
||||||
|
if (vcp->cursor_mobs[i]->base.size <
|
||||||
|
vps->cursor.bo->base.size) {
|
||||||
|
vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]);
|
||||||
|
vcp->cursor_mobs[i] = vps->cursor.bo;
|
||||||
|
vps->cursor.bo = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destroy it if it's not worth caching. */
|
||||||
|
vmw_du_destroy_cursor_mob(&vps->cursor.bo);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CURSOR_MOB_SIZE(dimension) \
|
static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp,
|
||||||
((dimension) * (dimension) * sizeof(u32) + sizeof(SVGAGBCursorHeader))
|
struct vmw_plane_state *vps)
|
||||||
|
|
||||||
int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *cursor)
|
|
||||||
{
|
{
|
||||||
struct vmw_private *dev_priv = cursor->base.dev->dev_private;
|
struct vmw_private *dev_priv = vcp->base.dev->dev_private;
|
||||||
uint32_t cursor_max_dim, mob_max_size;
|
u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h);
|
||||||
int ret = 0;
|
u32 i;
|
||||||
size_t i;
|
u32 cursor_max_dim, mob_max_size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!dev_priv->has_mob || (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0)
|
if (!dev_priv->has_mob ||
|
||||||
return -ENOSYS;
|
(dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE);
|
mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE);
|
||||||
cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION);
|
cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION);
|
||||||
|
|
||||||
if (CURSOR_MOB_SIZE(cursor_max_dim) > mob_max_size)
|
if (size > mob_max_size || vps->base.crtc_w > cursor_max_dim ||
|
||||||
cursor_max_dim = 64; /* Mandatorily-supported cursor dimension */
|
vps->base.crtc_h > cursor_max_dim)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(cursor->cursor_mob); i++) {
|
if (vps->cursor.bo != NULL) {
|
||||||
struct ttm_buffer_object **const bo = &cursor->cursor_mob[i];
|
if (vps->cursor.bo->base.size >= size)
|
||||||
|
return 0;
|
||||||
ret = vmw_bo_create_kernel(dev_priv,
|
vmw_du_put_cursor_mob(vcp, vps);
|
||||||
CURSOR_MOB_SIZE(cursor_max_dim),
|
|
||||||
&vmw_mob_placement, bo);
|
|
||||||
|
|
||||||
if (ret != 0)
|
|
||||||
goto teardown;
|
|
||||||
|
|
||||||
if ((*bo)->resource->mem_type != VMW_PL_MOB) {
|
|
||||||
DRM_ERROR("Obtained buffer object is not a MOB.\n");
|
|
||||||
ret = -ENOSYS;
|
|
||||||
goto teardown;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fence the mob creation so we are guarateed to have the mob */
|
|
||||||
ret = ttm_bo_reserve(*bo, false, false, NULL);
|
|
||||||
|
|
||||||
if (ret != 0)
|
|
||||||
goto teardown;
|
|
||||||
|
|
||||||
vmw_bo_fence_single(*bo, NULL);
|
|
||||||
|
|
||||||
ttm_bo_unreserve(*bo);
|
|
||||||
|
|
||||||
drm_info(&dev_priv->drm, "Using CursorMob mobid %lu, max dimension %u\n",
|
|
||||||
(*bo)->resource->start, cursor_max_dim);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Look for an unused mob in the cache. */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) {
|
||||||
|
if (vcp->cursor_mobs[i] != NULL &&
|
||||||
|
vcp->cursor_mobs[i]->base.size >= size) {
|
||||||
|
vps->cursor.bo = vcp->cursor_mobs[i];
|
||||||
|
vcp->cursor_mobs[i] = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Create a new mob if we can't find an existing one. */
|
||||||
|
ret = vmw_bo_create_kernel(dev_priv, size, &vmw_mob_placement,
|
||||||
|
&vps->cursor.bo);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Fence the mob creation so we are guarateed to have the mob */
|
||||||
|
ret = ttm_bo_reserve(vps->cursor.bo, false, false, NULL);
|
||||||
|
if (ret != 0)
|
||||||
|
goto teardown;
|
||||||
|
|
||||||
|
vmw_bo_fence_single(vps->cursor.bo, NULL);
|
||||||
|
ttm_bo_unreserve(vps->cursor.bo);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
teardown:
|
teardown:
|
||||||
vmw_du_destroy_cursor_mob_array(cursor);
|
vmw_du_destroy_cursor_mob(&vps->cursor.bo);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef CURSOR_MOB_SIZE
|
|
||||||
|
|
||||||
static void vmw_cursor_update_bo(struct vmw_private *dev_priv,
|
|
||||||
struct ttm_buffer_object *cm_bo,
|
|
||||||
struct ttm_bo_kmap_obj *cm_map,
|
|
||||||
struct vmw_buffer_object *bo,
|
|
||||||
u32 width, u32 height,
|
|
||||||
u32 hotspotX, u32 hotspotY)
|
|
||||||
{
|
|
||||||
void *virtual;
|
|
||||||
bool dummy;
|
|
||||||
|
|
||||||
virtual = ttm_kmap_obj_virtual(&bo->map, &dummy);
|
|
||||||
if (virtual) {
|
|
||||||
vmw_cursor_update_image(dev_priv, cm_bo, cm_map, virtual,
|
|
||||||
width, height,
|
|
||||||
hotspotX, hotspotY);
|
|
||||||
atomic_dec(&bo->base_mapped_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void vmw_cursor_update_position(struct vmw_private *dev_priv,
|
static void vmw_cursor_update_position(struct vmw_private *dev_priv,
|
||||||
bool show, int x, int y)
|
bool show, int x, int y)
|
||||||
|
@ -391,11 +431,11 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
du->cursor_age = du->cursor_surface->snooper.age;
|
du->cursor_age = du->cursor_surface->snooper.age;
|
||||||
vmw_cursor_update_image(dev_priv, NULL, NULL,
|
vmw_send_define_cursor_cmd(dev_priv,
|
||||||
du->cursor_surface->snooper.image,
|
du->cursor_surface->snooper.image,
|
||||||
64, 64,
|
64, 64,
|
||||||
du->hotspot_x + du->core_hotspot_x,
|
du->hotspot_x + du->core_hotspot_x,
|
||||||
du->hotspot_y + du->core_hotspot_y);
|
du->hotspot_y + du->core_hotspot_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&dev->mode_config.mutex);
|
mutex_unlock(&dev->mode_config.mutex);
|
||||||
|
@ -404,8 +444,14 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
|
||||||
|
|
||||||
void vmw_du_cursor_plane_destroy(struct drm_plane *plane)
|
void vmw_du_cursor_plane_destroy(struct drm_plane *plane)
|
||||||
{
|
{
|
||||||
|
struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
|
||||||
|
u32 i;
|
||||||
|
|
||||||
vmw_cursor_update_position(plane->dev->dev_private, false, 0, 0);
|
vmw_cursor_update_position(plane->dev->dev_private, false, 0, 0);
|
||||||
vmw_du_destroy_cursor_mob_array(vmw_plane_to_vcp(plane));
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++)
|
||||||
|
vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]);
|
||||||
|
|
||||||
drm_plane_cleanup(plane);
|
drm_plane_cleanup(plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,6 +508,87 @@ vmw_du_plane_cleanup_fb(struct drm_plane *plane,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vmw_du_cursor_plane_map_cm - Maps the cursor mobs.
|
||||||
|
*
|
||||||
|
* @vps: plane_state
|
||||||
|
*
|
||||||
|
* Returns 0 on success
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
vmw_du_cursor_plane_map_cm(struct vmw_plane_state *vps)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h);
|
||||||
|
struct ttm_buffer_object *bo = vps->cursor.bo;
|
||||||
|
|
||||||
|
if (bo == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (bo->base.size < size)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (vps->cursor.mapped)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = ttm_bo_reserve(bo, false, false, NULL);
|
||||||
|
|
||||||
|
if (unlikely(ret != 0))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = ttm_bo_kmap(bo, 0, PFN_UP(size), &vps->cursor.map);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We just want to try to get mob bind to finish
|
||||||
|
* so that the first write to SVGA_REG_CURSOR_MOBID
|
||||||
|
* is done with a buffer that the device has already
|
||||||
|
* seen
|
||||||
|
*/
|
||||||
|
(void) ttm_bo_wait(bo, false, false);
|
||||||
|
|
||||||
|
ttm_bo_unreserve(bo);
|
||||||
|
|
||||||
|
if (unlikely(ret != 0))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
vps->cursor.mapped = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vmw_du_cursor_plane_unmap_cm - Unmaps the cursor mobs.
|
||||||
|
*
|
||||||
|
* @vps: state of the cursor plane
|
||||||
|
*
|
||||||
|
* Returns 0 on success
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct ttm_buffer_object *bo = vps->cursor.bo;
|
||||||
|
|
||||||
|
if (!vps->cursor.mapped)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (bo == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = ttm_bo_reserve(bo, true, false, NULL);
|
||||||
|
if (likely(ret == 0)) {
|
||||||
|
ttm_bo_kunmap(&vps->cursor.map);
|
||||||
|
ttm_bo_unreserve(bo);
|
||||||
|
vps->cursor.mapped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vmw_du_cursor_plane_cleanup_fb - Unpins the plane surface
|
* vmw_du_cursor_plane_cleanup_fb - Unpins the plane surface
|
||||||
*
|
*
|
||||||
|
@ -476,6 +603,7 @@ void
|
||||||
vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
|
vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
|
||||||
struct drm_plane_state *old_state)
|
struct drm_plane_state *old_state)
|
||||||
{
|
{
|
||||||
|
struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
|
||||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
|
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
|
||||||
bool dummy;
|
bool dummy;
|
||||||
|
|
||||||
|
@ -489,28 +617,23 @@ vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vps->cm_bo != NULL && ttm_kmap_obj_virtual(&vps->cm_map, &dummy) != NULL) {
|
vmw_du_cursor_plane_unmap_cm(vps);
|
||||||
const int ret = ttm_bo_reserve(vps->cm_bo, true, false, NULL);
|
vmw_du_put_cursor_mob(vcp, vps);
|
||||||
|
|
||||||
if (likely(ret == 0)) {
|
|
||||||
ttm_bo_kunmap(&vps->cm_map);
|
|
||||||
ttm_bo_unreserve(vps->cm_bo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vmw_du_plane_unpin_surf(vps, false);
|
vmw_du_plane_unpin_surf(vps, false);
|
||||||
|
|
||||||
if (vps->surf) {
|
if (vps->surf != NULL) {
|
||||||
vmw_surface_unreference(&vps->surf);
|
vmw_surface_unreference(&vps->surf);
|
||||||
vps->surf = NULL;
|
vps->surf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vps->bo) {
|
if (vps->bo != NULL) {
|
||||||
vmw_bo_unreference(&vps->bo);
|
vmw_bo_unreference(&vps->bo);
|
||||||
vps->bo = NULL;
|
vps->bo = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it
|
* vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it
|
||||||
*
|
*
|
||||||
|
@ -526,8 +649,6 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
|
||||||
struct drm_framebuffer *fb = new_state->fb;
|
struct drm_framebuffer *fb = new_state->fb;
|
||||||
struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
|
struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
|
||||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
|
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
|
||||||
struct ttm_buffer_object *cm_bo = NULL;
|
|
||||||
bool dummy;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (vps->surf) {
|
if (vps->surf) {
|
||||||
|
@ -550,13 +671,14 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vps->cm_bo = NULL;
|
|
||||||
|
|
||||||
if (vps->surf == NULL && vps->bo != NULL) {
|
if (vps->surf == NULL && vps->bo != NULL) {
|
||||||
const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32);
|
const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32);
|
||||||
|
|
||||||
/* Not using vmw_bo_map_and_cache() helper here as we need to reserve
|
/*
|
||||||
the ttm_buffer_object first which wmw_bo_map_and_cache() omits. */
|
* Not using vmw_bo_map_and_cache() helper here as we need to
|
||||||
|
* reserve the ttm_buffer_object first which
|
||||||
|
* vmw_bo_map_and_cache() omits.
|
||||||
|
*/
|
||||||
ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
|
ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
|
||||||
|
|
||||||
if (unlikely(ret != 0))
|
if (unlikely(ret != 0))
|
||||||
|
@ -573,67 +695,12 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vps->surf || vps->bo) {
|
if (vps->surf != NULL || vps->bo != NULL) {
|
||||||
unsigned cursor_mob_idx = vps->cursor_mob_idx;
|
vmw_du_get_cursor_mob(vcp, vps);
|
||||||
|
vmw_du_cursor_plane_map_cm(vps);
|
||||||
/* Lazily set up cursor MOBs just once -- no reattempts. */
|
|
||||||
if (cursor_mob_idx == 0 && vcp->cursor_mob[0] == NULL)
|
|
||||||
if (vmw_du_create_cursor_mob_array(vcp) != 0)
|
|
||||||
vps->cursor_mob_idx = cursor_mob_idx = -1U;
|
|
||||||
|
|
||||||
if (cursor_mob_idx < ARRAY_SIZE(vcp->cursor_mob)) {
|
|
||||||
const u32 size = sizeof(SVGAGBCursorHeader) +
|
|
||||||
new_state->crtc_w * new_state->crtc_h * sizeof(u32);
|
|
||||||
|
|
||||||
cm_bo = vcp->cursor_mob[cursor_mob_idx];
|
|
||||||
|
|
||||||
if (cm_bo->resource->num_pages * PAGE_SIZE < size) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto error_bo_unmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ttm_bo_reserve(cm_bo, false, false, NULL);
|
|
||||||
|
|
||||||
if (unlikely(ret != 0)) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto error_bo_unmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ttm_bo_kmap(cm_bo, 0, PFN_UP(size), &vps->cm_map);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We just want to try to get mob bind to finish
|
|
||||||
* so that the first write to SVGA_REG_CURSOR_MOBID
|
|
||||||
* is done with a buffer that the device has already
|
|
||||||
* seen
|
|
||||||
*/
|
|
||||||
(void) ttm_bo_wait(cm_bo, false, false);
|
|
||||||
|
|
||||||
ttm_bo_unreserve(cm_bo);
|
|
||||||
|
|
||||||
if (unlikely(ret != 0)) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto error_bo_unmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
vps->cursor_mob_idx = cursor_mob_idx ^ 1;
|
|
||||||
vps->cm_bo = cm_bo;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_bo_unmap:
|
|
||||||
if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) {
|
|
||||||
const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL);
|
|
||||||
if (likely(ret == 0)) {
|
|
||||||
atomic_dec(&vps->bo->base_mapped_count);
|
|
||||||
ttm_bo_kunmap(&vps->bo->map);
|
|
||||||
ttm_bo_unreserve(&vps->bo->base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -650,6 +717,8 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
|
||||||
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
|
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
|
||||||
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
|
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
|
||||||
s32 hotspot_x, hotspot_y;
|
s32 hotspot_x, hotspot_y;
|
||||||
|
void *virtual;
|
||||||
|
bool dummy;
|
||||||
|
|
||||||
hotspot_x = du->hotspot_x;
|
hotspot_x = du->hotspot_x;
|
||||||
hotspot_y = du->hotspot_y;
|
hotspot_y = du->hotspot_y;
|
||||||
|
@ -662,23 +731,29 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
|
||||||
du->cursor_surface = vps->surf;
|
du->cursor_surface = vps->surf;
|
||||||
du->cursor_bo = vps->bo;
|
du->cursor_bo = vps->bo;
|
||||||
|
|
||||||
if (vps->surf) {
|
if (vps->surf == NULL && vps->bo == NULL) {
|
||||||
|
vmw_cursor_update_position(dev_priv, false, 0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vps->surf != NULL) {
|
||||||
du->cursor_age = du->cursor_surface->snooper.age;
|
du->cursor_age = du->cursor_surface->snooper.age;
|
||||||
|
|
||||||
vmw_cursor_update_image(dev_priv, vps->cm_bo, &vps->cm_map,
|
vmw_cursor_update_image(dev_priv, vps,
|
||||||
vps->surf->snooper.image,
|
vps->surf->snooper.image,
|
||||||
new_state->crtc_w,
|
new_state->crtc_w,
|
||||||
new_state->crtc_h,
|
new_state->crtc_h,
|
||||||
hotspot_x, hotspot_y);
|
hotspot_x, hotspot_y);
|
||||||
} else if (vps->bo) {
|
|
||||||
vmw_cursor_update_bo(dev_priv, vps->cm_bo, &vps->cm_map,
|
|
||||||
vps->bo,
|
|
||||||
new_state->crtc_w,
|
|
||||||
new_state->crtc_h,
|
|
||||||
hotspot_x, hotspot_y);
|
|
||||||
} else {
|
} else {
|
||||||
vmw_cursor_update_position(dev_priv, false, 0, 0);
|
|
||||||
return;
|
virtual = ttm_kmap_obj_virtual(&vps->bo->map, &dummy);
|
||||||
|
if (virtual) {
|
||||||
|
vmw_cursor_update_image(dev_priv, vps, virtual,
|
||||||
|
new_state->crtc_w,
|
||||||
|
new_state->crtc_h,
|
||||||
|
hotspot_x, hotspot_y);
|
||||||
|
atomic_dec(&vps->bo->base_mapped_count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
du->cursor_x = new_state->crtc_x + du->set_gui_x;
|
du->cursor_x = new_state->crtc_x + du->set_gui_x;
|
||||||
|
@ -943,11 +1018,13 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane)
|
||||||
vps->pinned = 0;
|
vps->pinned = 0;
|
||||||
vps->cpp = 0;
|
vps->cpp = 0;
|
||||||
|
|
||||||
|
memset(&vps->cursor, 0, sizeof(vps->cursor));
|
||||||
|
|
||||||
/* Each ref counted resource needs to be acquired again */
|
/* Each ref counted resource needs to be acquired again */
|
||||||
if (vps->surf)
|
if (vps->surf != NULL)
|
||||||
(void) vmw_surface_reference(vps->surf);
|
(void) vmw_surface_reference(vps->surf);
|
||||||
|
|
||||||
if (vps->bo)
|
if (vps->bo != NULL)
|
||||||
(void) vmw_bo_reference(vps->bo);
|
(void) vmw_bo_reference(vps->bo);
|
||||||
|
|
||||||
state = &vps->base;
|
state = &vps->base;
|
||||||
|
|
|
@ -295,13 +295,11 @@ struct vmw_plane_state {
|
||||||
/* For CPU Blit */
|
/* For CPU Blit */
|
||||||
unsigned int cpp;
|
unsigned int cpp;
|
||||||
|
|
||||||
/* CursorMob flipping index; -1 if cursor mobs not used */
|
struct {
|
||||||
unsigned int cursor_mob_idx;
|
struct ttm_buffer_object *bo;
|
||||||
/* Currently-active CursorMob */
|
struct ttm_bo_kmap_obj map;
|
||||||
struct ttm_buffer_object *cm_bo;
|
bool mapped;
|
||||||
/* CursorMob kmap_obj; expected valid at cursor_plane_atomic_update
|
} cursor;
|
||||||
IFF currently-active CursorMob above is valid */
|
|
||||||
struct ttm_bo_kmap_obj cm_map;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -338,11 +336,12 @@ struct vmw_connector_state {
|
||||||
* Derived class for cursor plane object
|
* Derived class for cursor plane object
|
||||||
*
|
*
|
||||||
* @base DRM plane object
|
* @base DRM plane object
|
||||||
* @cursor_mob array of two MOBs for CursorMob flipping
|
* @cursor.cursor_mobs Cursor mobs available for re-use
|
||||||
*/
|
*/
|
||||||
struct vmw_cursor_plane {
|
struct vmw_cursor_plane {
|
||||||
struct drm_plane base;
|
struct drm_plane base;
|
||||||
struct ttm_buffer_object *cursor_mob[2];
|
|
||||||
|
struct ttm_buffer_object *cursor_mobs[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -472,8 +471,6 @@ void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
|
||||||
/* Universal Plane Helpers */
|
/* Universal Plane Helpers */
|
||||||
void vmw_du_primary_plane_destroy(struct drm_plane *plane);
|
void vmw_du_primary_plane_destroy(struct drm_plane *plane);
|
||||||
void vmw_du_cursor_plane_destroy(struct drm_plane *plane);
|
void vmw_du_cursor_plane_destroy(struct drm_plane *plane);
|
||||||
int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *vcp);
|
|
||||||
void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp);
|
|
||||||
|
|
||||||
/* Atomic Helpers */
|
/* Atomic Helpers */
|
||||||
int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
|
int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
|
||||||
|
|
Loading…
Add table
Reference in a new issue