// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * * Copyright (c) 2024-2025 Broadcom. All Rights Reserved. The term * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
**************************************************************************/ #include"vmwgfx_cursor_plane.h"
/** * vmw_send_define_cursor_cmd - queue a define cursor command * @dev_priv: the private driver struct * @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
*/ staticvoid 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; const u32 image_size = width * height * sizeof(*image); const u32 cmd_size = sizeof(*cmd) + image_size;
/* * Try to reserve fifocmd space and swallow any failures; * such reservations cannot be left unconsumed for long * under the risk of clogging other fifocmd users, so * we treat reservations separtely from the way we treat * other fallible KMS-atomic resources at prepare_fb
*/
cmd = VMW_CMD_RESERVE(dev_priv, cmd_size);
/* 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]) {
vcp->cursor_mobs[i] = vps->cursor.mob;
vps->cursor.mob = 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]->tbo.base.size <
vps->cursor.mob->tbo.base.size) {
vmw_cursor_mob_destroy(&vcp->cursor_mobs[i]);
vcp->cursor_mobs[i] = vps->cursor.mob;
vps->cursor.mob = NULL; return;
}
}
/* Destroy it if it's not worth caching. */
vmw_cursor_mob_destroy(&vps->cursor.mob);
}
if (vps->cursor.mob) { if (vps->cursor.mob->tbo.base.size >= size) return 0;
vmw_cursor_mob_put(vcp, vps);
}
/* Look for an unused mob in the cache. */ for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { if (vcp->cursor_mobs[i] &&
vcp->cursor_mobs[i]->tbo.base.size >= size) {
vps->cursor.mob = 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_and_populate(dev_priv, size, VMW_BO_DOMAIN_MOB,
&vps->cursor.mob);
if (ret != 0) return ret;
/* Fence the mob creation so we are guarateed to have the mob */
ret = ttm_bo_reserve(&vps->cursor.mob->tbo, false, false, NULL); if (ret != 0) goto teardown;
ret = vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); if (ret != 0) {
ttm_bo_unreserve(&vps->cursor.mob->tbo); goto teardown;
}
if (new_bo) { if (!old_bo) { returntrue;
} elseif (new_bo->dirty) {
vmw_bo_dirty_scan(new_bo);
dirty = vmw_bo_is_dirty(new_bo); if (dirty) {
surf = vmw_user_object_surface(&new_vps->uo); if (surf)
vmw_bo_dirty_transfer_to_res(&surf->res); else
vmw_bo_dirty_clear(new_bo);
} return dirty;
} elseif (new_bo != old_bo) { /* * Currently unused because the top exits right away. * In most cases buffer being different will mean * that the contents is different. For the few percent * of cases where that's not true the cost of doing * the memcmp on all other seems to outweight the * benefits. Leave the conditional to be able to * trivially validate it by removing the initial * if (new_bo != old_bo) at the start.
*/ void *old_image; void *new_image; bool changed = false; struct ww_acquire_ctx ctx; const u32 size = new_vps->base.crtc_w *
new_vps->base.crtc_h * sizeof(u32);
ww_acquire_init(&ctx, &reservation_ww_class);
ret = ttm_bo_reserve(&old_bo->tbo, false, false, &ctx); if (ret != 0) {
ww_acquire_fini(&ctx); returntrue;
}
ret = ttm_bo_reserve(&new_bo->tbo, false, false, &ctx); if (ret != 0) {
ttm_bo_unreserve(&old_bo->tbo);
ww_acquire_fini(&ctx); returntrue;
}
(void)vmw_bo_map_and_cache_size(bo, size);
} else {
vmw_bo_map_and_cache(bo);
}
ttm_bo_unreserve(&bo->tbo);
} if (!vmw_user_object_is_null(&vps->uo)) { if (!vmw_cursor_plane_changed(vps, old_vps) &&
!vmw_cursor_buffer_changed(vps, old_vps)) {
vps->cursor.update_type =
VMW_CURSOR_UPDATE_NONE;
} else {
vmw_cursor_mob_get(vcp, vps);
vmw_cursor_mob_map(vps);
}
}
} break; case VMW_CURSOR_UPDATE_NONE: /* do nothing */ break;
}
return 0;
}
/** * vmw_cursor_plane_atomic_check - check if the new state is okay * * @plane: cursor plane * @state: info on the new plane state * * This is a chance to fail if the new cursor state does not fit * our requirements. * * Returns 0 on success
*/ int vmw_cursor_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)
{ struct drm_plane_state *new_state =
drm_atomic_get_new_plane_state(state, plane); struct vmw_private *vmw = vmw_priv(plane->dev); int ret = 0; struct drm_crtc_state *crtc_state = NULL; struct vmw_surface *surface = NULL; struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); enum vmw_cursor_update_type update_type; struct drm_framebuffer *fb = new_state->fb;
if (new_state->crtc)
crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
new_state->crtc);
ret = drm_atomic_helper_check_plane_state(new_state, crtc_state,
DRM_PLANE_NO_SCALING,
DRM_PLANE_NO_SCALING, true, true); if (ret) return ret;
/* Turning off */ if (!fb) return 0;
update_type = vmw_cursor_update_type(vmw, vps); if (update_type == VMW_CURSOR_UPDATE_LEGACY) { if (new_state->crtc_w != VMW_CURSOR_SNOOP_WIDTH ||
new_state->crtc_h != VMW_CURSOR_SNOOP_HEIGHT) {
drm_warn(&vmw->drm, "Invalid cursor dimensions (%d, %d)\n",
new_state->crtc_w, new_state->crtc_h); return -EINVAL;
}
surface = vmw_user_object_surface(&vps->uo); if (!surface || !surface->snooper.image) {
drm_warn(&vmw->drm, "surface not suitable for cursor\n"); return -EINVAL;
}
}
/* * Hide the cursor if the new bo is null
*/ if (vmw_user_object_is_null(&vps->uo)) {
vmw_cursor_update_position(dev_priv, false, 0, 0); return;
}
switch (vps->cursor.update_type) { case VMW_CURSOR_UPDATE_LEGACY:
vmw_cursor_plane_update_legacy(dev_priv, vps); break; case VMW_CURSOR_UPDATE_MOB:
vmw_cursor_update_mob(dev_priv, vps); break; case VMW_CURSOR_UPDATE_GB_ONLY:
bo = vmw_user_object_buffer(&vps->uo); if (bo)
vmw_send_define_cursor_cmd(dev_priv, bo->map.virtual,
vps->base.crtc_w,
vps->base.crtc_h,
vps->base.hotspot_x,
vps->base.hotspot_y); break; case VMW_CURSOR_UPDATE_NONE: /* do nothing */ break;
}
/* * For all update types update the cursor position
*/
cursor_x = new_state->crtc_x + du->set_gui_x;
cursor_y = new_state->crtc_y + du->set_gui_y;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.