// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * * Copyright (c) 2011-2024 Broadcom. All Rights Reserved. The term * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. *
**************************************************************************/
/** * struct vmw_kms_sou_surface_dirty - Closure structure for * blit surface to screen command. * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). * @left: Left side of bounding box. * @right: Right side of bounding box. * @top: Top side of bounding box. * @bottom: Bottom side of bounding box. * @dst_x: Difference between source clip rects and framebuffer coordinates. * @dst_y: Difference between source clip rects and framebuffer coordinates. * @sid: Surface id of surface to copy from.
*/ struct vmw_kms_sou_surface_dirty { struct vmw_kms_dirty base;
s32 left, right, top, bottom;
s32 dst_x, dst_y;
u32 sid;
};
/* * SVGA commands that are used by this code. Please see the device headers * for explanation.
*/ struct vmw_kms_sou_readback_blit {
uint32 header;
SVGAFifoCmdBlitScreenToGMRFB body;
};
/* * Send the fifo command to create a screen.
*/ staticint vmw_sou_fifo_create(struct vmw_private *dev_priv, struct vmw_screen_object_unit *sou, int x, int y, struct drm_display_mode *mode)
{
size_t fifo_size;
/* Ok to assume that buffer is pinned in vram */
vmw_bo_get_guest_ptr(&sou->buffer->tbo, &cmd->obj.backingStore.ptr);
cmd->obj.backingStore.pitch = mode->hdisplay * 4;
vmw_cmd_commit(dev_priv, fifo_size);
sou->defined = true;
return 0;
}
/* * Send the fifo command to destroy a screen.
*/ staticint vmw_sou_fifo_destroy(struct vmw_private *dev_priv, struct vmw_screen_object_unit *sou)
{
size_t fifo_size; int ret;
/* Force sync */
ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); if (unlikely(ret != 0))
DRM_ERROR("Failed to sync with HW"); else
sou->defined = false;
return ret;
}
/** * vmw_sou_crtc_mode_set_nofb - Create new screen * * @crtc: CRTC associated with the new screen * * This function creates/destroys a screen. This function cannot fail, so if * somehow we run into a failure, just do the best we can to get out.
*/ staticvoid vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
{ struct vmw_private *dev_priv; struct vmw_screen_object_unit *sou; struct vmw_framebuffer *vfb; struct drm_framebuffer *fb; struct drm_plane_state *ps; struct vmw_plane_state *vps; int ret;
x = vmw_conn_state->gui_x;
y = vmw_conn_state->gui_y;
ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); if (ret)
DRM_ERROR("Failed to define Screen Object %dx%d\n",
crtc->x, crtc->y);
} else {
sou->buffer = NULL;
}
}
/** * vmw_sou_crtc_helper_prepare - Noop * * @crtc: CRTC associated with the new screen * * Prepares the CRTC for a mode set, but we don't need to do anything here.
*/ staticvoid vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc)
{
}
/** * vmw_sou_crtc_atomic_disable - Turns off CRTC * * @crtc: CRTC to be turned off * @state: Unused
*/ staticvoid vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state)
{ struct vmw_private *dev_priv; struct vmw_screen_object_unit *sou; int ret;
if (!crtc) {
DRM_ERROR("CRTC is NULL\n"); return;
}
sou = vmw_crtc_to_sou(crtc);
dev_priv = vmw_priv(crtc->dev);
if (dev_priv->vkms_enabled)
drm_crtc_vblank_off(crtc);
if (sou->defined) {
ret = vmw_sou_fifo_destroy(dev_priv, sou); if (ret)
DRM_ERROR("Failed to destroy Screen Object\n");
}
}
bo = vmw_user_object_buffer(&vps->uo); if (bo) { if (vps->bo_size == bo_params.size) { /* * Note that this might temporarily up the pin-count * to 2, until cleanup_fb() is called.
*/ return vmw_bo_pin_in_vram(dev_priv, bo, true);
}
/* After we have alloced the backing store might not be able to * resume the overlays, this is preferred to failing to alloc.
*/
vmw_overlay_pause_all(dev_priv);
ret = vmw_bo_create(dev_priv, &bo_params, &vps->uo.buffer);
vmw_overlay_resume_all(dev_priv); if (ret) return ret;
vps->bo_size = bo_params.size;
/* * TTM already thinks the buffer is pinned, but make sure the * pin_count is upped.
*/ return vmw_bo_pin_in_vram(dev_priv, vps->uo.buffer, true);
}
/* Emulate RGBA support, contrary to svga_reg.h this is not * supported by hosts. This is only a problem if we are reading * this value later and expecting what we uploaded back.
*/ if (depth == 32)
depth = 24;
/** * vmw_sou_plane_update_bo - Update display unit for bo backed fb. * @dev_priv: Device private. * @plane: Plane state. * @old_state: Old plane state. * @vfb: Framebuffer which is blitted to display unit. * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. * The returned fence pointer may be NULL in which case the device * has already synchronized. * * Return: 0 on success or a negative error code on failure.
*/ staticint vmw_sou_plane_update_bo(struct vmw_private *dev_priv, struct drm_plane *plane, struct drm_plane_state *old_state, struct vmw_framebuffer *vfb, struct vmw_fence_obj **out_fence)
{ struct vmw_du_update_plane_buffer bo_update;
/* * SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that * its bounding box is filled before iterating over all the clips. So * store the FIFO start address and revisit to fill the details.
*/
srf_update->cmd_start = cmd;
/* * rects are relative to dest bounding box rect on screen object, so * translate to it later in post_clip
*/
rect->left = clip->x1;
rect->top = clip->y1;
rect->right = clip->x2;
rect->bottom = clip->y2;
/* rects are relative to dest bb rect */ for (i = 0; i < num_hits; i++) {
rect->left -= bb->x1;
rect->top -= bb->y1;
rect->right -= bb->x1;
rect->bottom -= bb->y1;
rect++;
}
return 0;
}
/** * vmw_sou_plane_update_surface - Update display unit for surface backed fb. * @dev_priv: Device private. * @plane: Plane state. * @old_state: Old plane state. * @vfb: Framebuffer which is blitted to display unit * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. * The returned fence pointer may be NULL in which case the device * has already synchronized. * * Return: 0 on success or a negative error code on failure.
*/ staticint vmw_sou_plane_update_surface(struct vmw_private *dev_priv, struct drm_plane *plane, struct drm_plane_state *old_state, struct vmw_framebuffer *vfb, struct vmw_fence_obj **out_fence)
{ struct vmw_du_update_plane_surface srf_update;
/* In case of device error, maintain consistent atomic state */ if (crtc && new_state->fb) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct vmw_framebuffer *vfb =
vmw_framebuffer_to_vfb(new_state->fb);
if (vfb->bo)
ret = vmw_sou_plane_update_bo(dev_priv, plane,
old_state, vfb, &fence); else
ret = vmw_sou_plane_update_surface(dev_priv, plane,
old_state, vfb,
&fence); if (ret != 0)
DRM_ERROR("Failed to update screen.\n");
} else { /* Do nothing when fb and crtc is NULL (blank crtc) */ return;
}
/* Emulate RGBA support, contrary to svga_reg.h this is not * supported by hosts. This is only a problem if we are reading * this value later and expecting what we uploaded back.
*/ if (depth == 32)
depth = 24;
cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); if (!cmd) return -ENOMEM;
cmd->header = SVGA_CMD_DEFINE_GMRFB;
cmd->body.format.bitsPerPixel = framebuffer->base.format->cpp[0] * 8;
cmd->body.format.colorDepth = depth;
cmd->body.format.reserved = 0;
cmd->body.bytesPerLine = framebuffer->base.pitches[0]; /* Buffer is reserved in vram or GMR */
vmw_bo_get_guest_ptr(&buf->tbo, &cmd->body.ptr);
vmw_cmd_commit(dev_priv, sizeof(*cmd));
return 0;
}
/** * vmw_sou_surface_fifo_commit - Callback to fill in and submit a * blit surface to screen command. * * @dirty: The closure structure. * * Fills in the missing fields in the command, and translates the cliprects * to match the destination bounding box encoded.
*/ staticvoid vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty)
{ struct vmw_kms_sou_surface_dirty *sdirty =
container_of(dirty, typeof(*sdirty), base); struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd;
s32 trans_x = dirty->unit->crtc.x - sdirty->dst_x;
s32 trans_y = dirty->unit->crtc.y - sdirty->dst_y;
size_t region_size = dirty->num_hits * sizeof(SVGASignedRect);
SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; int i;
if (!dirty->num_hits) {
vmw_cmd_commit(dirty->dev_priv, 0); return;
}
/** * vmw_kms_sou_do_surface_dirty - Dirty part of a surface backed framebuffer * * @dev_priv: Pointer to the device private structure. * @framebuffer: Pointer to the surface-buffer backed framebuffer. * @clips: Array of clip rects. Either @clips or @vclips must be NULL. * @vclips: Alternate array of clip rects. Either @clips or @vclips must * be NULL. * @srf: Pointer to surface to blit from. If NULL, the surface attached * to @framebuffer will be used. * @dest_x: X coordinate offset to align @srf with framebuffer coordinates. * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates. * @num_clips: Number of clip rects in @clips. * @inc: Increment to use when looping over @clips. * @out_fence: If non-NULL, will return a ref-counted pointer to a * struct vmw_fence_obj. The returned fence pointer may be NULL in which * case the device has already synchronized. * @crtc: If crtc is passed, perform surface dirty on that crtc only. * * Returns 0 on success, negative error code on failure. -ERESTARTSYS if * interrupted.
*/ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer, struct drm_clip_rect *clips, struct drm_vmw_rect *vclips, struct vmw_resource *srf,
s32 dest_x,
s32 dest_y, unsigned num_clips, int inc, struct vmw_fence_obj **out_fence, struct drm_crtc *crtc)
{ struct vmw_framebuffer_surface *vfbs =
container_of(framebuffer, typeof(*vfbs), base); struct vmw_kms_sou_surface_dirty sdirty;
DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); int ret;
if (!srf)
srf = &vmw_user_object_surface(&vfbs->uo)->res;
ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE,
NULL, NULL); if (ret) return ret;
ret = vmw_validation_prepare(&val_ctx, &dev_priv->cmdbuf_mutex, true); if (ret) goto out_unref;
/** * vmw_sou_bo_fifo_commit - Callback to submit a set of readback clips. * * @dirty: The closure structure. * * Commits a previously built command buffer of readback clips.
*/ staticvoid vmw_sou_bo_fifo_commit(struct vmw_kms_dirty *dirty)
{ if (!dirty->num_hits) {
vmw_cmd_commit(dirty->dev_priv, 0); return;
}
/** * vmw_kms_sou_do_bo_dirty - Dirty part of a buffer-object backed framebuffer * * @dev_priv: Pointer to the device private structure. * @framebuffer: Pointer to the buffer-object backed framebuffer. * @clips: Array of clip rects. * @vclips: Alternate array of clip rects. Either @clips or @vclips must * be NULL. * @num_clips: Number of clip rects in @clips. * @increment: Increment to use when looping over @clips. * @interruptible: Whether to perform waits interruptible if possible. * @out_fence: If non-NULL, will return a ref-counted pointer to a * struct vmw_fence_obj. The returned fence pointer may be NULL in which * case the device has already synchronized. * @crtc: If crtc is passed, perform bo dirty on that crtc only. * * Returns 0 on success, negative error code on failure. -ERESTARTSYS if * interrupted.
*/ int vmw_kms_sou_do_bo_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer, struct drm_clip_rect *clips, struct drm_vmw_rect *vclips, unsigned num_clips, int increment, bool interruptible, struct vmw_fence_obj **out_fence, struct drm_crtc *crtc)
{ struct vmw_bo *buf =
container_of(framebuffer, struct vmw_framebuffer_bo,
base)->buffer; struct vmw_kms_dirty dirty;
DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); int ret;
vmw_bo_placement_set(buf, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM);
ret = vmw_validation_add_bo(&val_ctx, buf); if (ret) return ret;
ret = vmw_validation_prepare(&val_ctx, NULL, interruptible); if (ret) goto out_unref;
ret = do_bo_define_gmrfb(dev_priv, framebuffer); if (unlikely(ret != 0)) goto out_revert;
/** * vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips. * * @dirty: The closure structure. * * Commits a previously built command buffer of readback clips.
*/ staticvoid vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty)
{ if (!dirty->num_hits) {
vmw_cmd_commit(dirty->dev_priv, 0); return;
}
/** * vmw_kms_sou_readback - Perform a readback from the screen object system to * a buffer-object backed framebuffer. * * @dev_priv: Pointer to the device private structure. * @file_priv: Pointer to a struct drm_file identifying the caller. * Must be set to NULL if @user_fence_rep is NULL. * @vfb: Pointer to the buffer-object backed framebuffer. * @user_fence_rep: User-space provided structure for fence information. * Must be set to non-NULL if @file_priv is non-NULL. * @vclips: Array of clip rects. * @num_clips: Number of clip rects in @vclips. * @crtc: If crtc is passed, readback on that crtc only. * * Returns 0 on success, negative error code on failure. -ERESTARTSYS if * interrupted.
*/ int vmw_kms_sou_readback(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, struct drm_vmw_fence_rep __user *user_fence_rep, struct drm_vmw_rect *vclips,
uint32_t num_clips, struct drm_crtc *crtc)
{ struct vmw_bo *buf =
container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; struct vmw_kms_dirty dirty;
DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); int ret;
vmw_bo_placement_set(buf, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM);
ret = vmw_validation_add_bo(&val_ctx, buf); if (ret) return ret;
ret = vmw_validation_prepare(&val_ctx, NULL, true); if (ret) goto out_unref;
ret = do_bo_define_gmrfb(dev_priv, vfb); if (unlikely(ret != 0)) goto out_revert;
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.