diff options
| author | Thomas Hellstrom <thellstrom@vmware.com> | 2015-06-26 02:22:40 -0700 |
|---|---|---|
| committer | Thomas Hellstrom <thellstrom@vmware.com> | 2015-08-05 14:01:09 +0200 |
| commit | 6bf6bf03b37b5ba0f3399fa9bb3d62edfa117c87 (patch) | |
| tree | f09e4ecc302cd792b98baacec3704c4f8b1dfe87 | |
| parent | 10b1e0ca9c32deb3a9b0ecc93fc4920fc24b4a57 (diff) | |
| download | linux-6bf6bf03b37b5ba0f3399fa9bb3d62edfa117c87.tar.gz linux-6bf6bf03b37b5ba0f3399fa9bb3d62edfa117c87.tar.bz2 linux-6bf6bf03b37b5ba0f3399fa9bb3d62edfa117c87.zip | |
drm/vmwgfx: Convert screen targets to new helpers v3
Also implements the missing readback function and
fixes page flip in case of no event.
v2:
- Adapt to the work done for screen targets for 2d, in particular
Handle proxy surface updates.
- Remove execbuf quirks since we now use fifo reserve / commit.
- Revert the initial placement of vmw dma buffers.
v3: Address review comments.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 24 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 149 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 37 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 996 |
6 files changed, 534 insertions, 679 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d60ae207136c..d6b247b1994a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -343,9 +343,6 @@ enum vmw_display_unit_type { }; -#define VMW_QUIRK_DST_SID_OK (1U << 0) -#define VMW_QUIRK_SRC_SID_OK (1U << 1) - struct vmw_sw_context{ struct drm_open_hash res_ht; bool res_ht_initialized; @@ -368,7 +365,6 @@ struct vmw_sw_context{ struct vmw_resource *error_resource; struct vmw_ctx_binding_state staged_bindings; struct list_head staged_cmd_res; - uint32_t quirks; }; struct vmw_legacy_display; @@ -842,7 +838,6 @@ extern int vmw_execbuf_process(struct drm_file *file_priv, void *kernel_commands, uint32_t command_size, uint64_t throttle_us, - uint32_t quirks, struct drm_vmw_fence_rep __user *user_fence_rep, struct vmw_fence_obj **out_fence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 698a0e2add53..64dba53ca54c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -675,16 +675,11 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv, cmd = container_of(header, struct vmw_sid_cmd, header); - if (!(sw_context->quirks & VMW_QUIRK_SRC_SID_OK)) { - ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, - user_surface_converter, - &cmd->body.src.sid, NULL); - if (ret != 0) - return ret; - } - - if (sw_context->quirks & VMW_QUIRK_DST_SID_OK) - return 0; + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.src.sid, NULL); + if (ret) + return ret; return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, @@ -1266,9 +1261,6 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, if (unlikely(suffix->maximumOffset > bo_size)) suffix->maximumOffset = bo_size; - if (sw_context->quirks & VMW_QUIRK_DST_SID_OK) - goto out_no_surface; - ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->dma.host.sid, NULL); @@ -1507,9 +1499,6 @@ static int vmw_cmd_update_gb_image(struct vmw_private *dev_priv, cmd = container_of(header, struct vmw_gb_surface_cmd, header); - if (sw_context->quirks & VMW_QUIRK_SRC_SID_OK) - return 0; - return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->body.image.sid, NULL); @@ -2554,7 +2543,6 @@ int vmw_execbuf_process(struct drm_file *file_priv, void *kernel_commands, uint32_t command_size, uint64_t throttle_us, - uint32_t quirks, struct drm_vmw_fence_rep __user *user_fence_rep, struct vmw_fence_obj **out_fence) { @@ -2609,7 +2597,6 @@ int vmw_execbuf_process(struct drm_file *file_priv, sw_context->fp = vmw_fpriv(file_priv); sw_context->cur_reloc = 0; sw_context->cur_val_buf = 0; - sw_context->quirks = quirks; INIT_LIST_HEAD(&sw_context->resource_list); sw_context->cur_query_bo = dev_priv->pinned_bo; sw_context->last_query_ctx = NULL; @@ -2921,7 +2908,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ret = vmw_execbuf_process(file_priv, dev_priv, (void __user *)(unsigned long)arg->commands, NULL, arg->command_size, arg->throttle_us, - 0, (void __user *)(unsigned long)arg->fence_rep, NULL); ttm_read_unlock(&dev_priv->reservation_sem); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 5901d32d0273..234a3cef1c25 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -427,10 +427,9 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, clips, NULL, NULL, 0, 0, num_clips, inc, NULL); else - ret = vmw_kms_stdu_do_surface_dirty(dev_priv, file_priv, - &vfbs->base, - clips, num_clips, - inc); + ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, + clips, NULL, NULL, 0, 0, + num_clips, inc, NULL); vmw_fifo_flush(dev_priv, false); ttm_read_unlock(&dev_priv->reservation_sem); @@ -467,10 +466,14 @@ int vmw_kms_readback(struct vmw_private *dev_priv, case vmw_du_screen_object: return vmw_kms_sou_readback(dev_priv, file_priv, vfb, user_fence_rep, vclips, num_clips); + case vmw_du_screen_target: + return vmw_kms_stdu_dma(dev_priv, file_priv, vfb, + user_fence_rep, NULL, vclips, num_clips, + 1, false, true); default: WARN_ONCE(true, "Readback called with invalid display system.\n"); - } +} return -ENOSYS; } @@ -632,20 +635,23 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, increment = 2; } - if (dev_priv->ldu_priv) { - ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, - flags, color, - clips, num_clips, increment); - } else if (dev_priv->active_display_unit == vmw_du_screen_object) { + switch (dev_priv->active_display_unit) { + case vmw_du_screen_target: + ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, + clips, NULL, num_clips, increment, + true, true); + break; + case vmw_du_screen_object: ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, clips, num_clips, increment, true, NULL); - } else { - ret = vmw_kms_stdu_do_surface_dirty(dev_priv, file_priv, - &vfbd->base, - clips, num_clips, - increment); + break; + default: + ret = -ENOSYS; + WARN_ONCE(true, + "Dirty called with invalid display system.\n"); + break; } vmw_fifo_flush(dev_priv, false); @@ -721,9 +727,9 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, { uint32_t format; struct drm_vmw_size content_base_size; + struct vmw_resource *res; int ret; - switch (mode_cmd->depth) { case 32: case 24: @@ -762,15 +768,18 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, return ret; } - /* Use the same MOB backing for surface */ - vmw_dmabuf_reference(dmabuf_mob); - - (*srf_out)->res.backup = dmabuf_mob; + res = &(*srf_out)->res; - /* FIXME: Waiting for fbdev rework to do a proper reserve/pin */ - ret = vmw_resource_validate(&(*srf_out)->res); + /* Reserve and switch the backing mob. */ + mutex_lock(&res->dev_priv->cmdbuf_mutex); + (void) vmw_resource_reserve(res, false, true); + vmw_dmabuf_unreference(&res->backup); + res->backup = vmw_dmabuf_reference(dmabuf_mob); + res->backup_offset = 0; + vmw_resource_unreserve(res, NULL, 0); + mutex_unlock(&res->dev_priv->cmdbuf_mutex); - return ret; + return 0; } @@ -987,6 +996,7 @@ int vmw_kms_generic_present(struct vmw_private *dev_priv, num_clips, 1, NULL); } + int vmw_kms_present(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, @@ -998,13 +1008,23 @@ int vmw_kms_present(struct vmw_private *dev_priv, { int ret; - if (dev_priv->active_display_unit == vmw_du_screen_target) - ret = vmw_kms_stdu_present(dev_priv, file_priv, vfb, sid, - destX, destY, clips, num_clips); - else - ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, - surface, sid, destX, destY, - clips, num_clips); + switch (dev_priv->active_display_unit) { + case vmw_du_screen_target: + ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, clips, + &surface->res, destX, destY, + num_clips, 1, NULL); + break; + case vmw_du_screen_object: + ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, + sid, destX, destY, clips, + num_clips); + break; + default: + WARN_ONCE(true, + "Present called with invalid display system.\n"); + ret = -ENOSYS; + break; + } if (ret) return ret; @@ -1882,3 +1902,72 @@ void vmw_kms_helper_resource_finish(struct vmw_resource *res, vmw_resource_unreserve(res, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); } + +/** + * vmw_kms_update_proxy - Helper function to update a proxy surface from + * its backing MOB. + * + * @res: Pointer to the surface resource + * @clips: Clip rects in framebuffer (surface) space. + * @num_clips: Number of clips in @clips. + * @increment: Integer with which to increment the clip counter when looping. + * Used to skip a predetermined number of clip rects. + * + * This function makes sure the proxy surface is updated from its backing MOB + * using the region given by @clips. The surface resource @res and its backing + * MOB needs to be reserved and validated on call. + */ +int vmw_kms_update_proxy(struct vmw_resource *res, + const struct drm_clip_rect *clips, + unsigned num_clips, + int increment) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct drm_vmw_size *size = &vmw_res_to_srf(res)->base_size; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBImage body; + } *cmd; + SVGA3dBox *box; + size_t copy_size = 0; + int i; + + if (!clips) + return 0; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) * num_clips); + if (!cmd) { + DRM_ERROR("Couldn't reserve fifo space for proxy surface " + "update.\n"); + return -ENOMEM; + } + + for (i = 0; i < num_clips; ++i, clips += increment, ++cmd) { + box = &cmd->body.box; + + cmd->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; + cmd->header.size = sizeof(cmd->body); + cmd->body.image.sid = res->id; + cmd->body.image.face = 0; + cmd->body.image.mipmap = 0; + + if (clips->x1 > size->width || clips->x2 > size->width || + clips->y1 > size->height || clips->y2 > size->height) { + DRM_ERROR("Invalid clips outsize of framebuffer.\n"); + return -EINVAL; + } + + box->x = clips->x1; + box->y = clips->y1; + box->z = 0; + box->w = clips->x2 - clips->x1; + box->h = clips->y2 - clips->y1; + box->d = 1; + + copy_size += sizeof(*cmd); + } + + vmw_fifo_commit(dev_priv, copy_size); + + return 0; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 8a8203c66adc..f941f92338a6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -239,6 +239,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv, struct drm_vmw_rect *vclips, uint32_t num_clips); + /* * Legacy display unit functions - vmwgfx_ldu.c */ @@ -249,6 +250,10 @@ int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips, int increment); +int vmw_kms_update_proxy(struct vmw_resource *res, + const struct drm_clip_rect *clips, + unsigned num_clips, + int increment); /* * Screen Objects display functions - vmwgfx_scrn.c @@ -282,17 +287,25 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, */ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv); int vmw_kms_stdu_close_display(struct vmw_private *dev_priv); -int vmw_kms_stdu_do_surface_dirty(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *framebuffer, - struct drm_clip_rect *clips, - unsigned num_clips, int increment); -int vmw_kms_stdu_present(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *vfb, - uint32_t user_handle, - int32_t dest_x, int32_t dest_y, - struct drm_vmw_rect *clips, - uint32_t num_clips); +int vmw_kms_stdu_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); +int vmw_kms_stdu_dma(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_clip_rect *clips, + struct drm_vmw_rect *vclips, + uint32_t num_clips, + int increment, + bool to_surface, + bool interruptible); + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 521f1947b4e9..69b471af0130 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -497,7 +497,7 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, ret = vmw_dmabuf_init(dev_priv, &user_bo->dma, size, (dev_priv->has_mob) ? - &vmw_mob_placement : + &vmw_sys_placement : &vmw_vram_sys_placement, true, &vmw_user_dmabuf_destroy); if (unlikely(ret != 0)) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index becf9650c228..493fcd1eb803 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright © 2014 VMware, Inc., Palo Alto, CA., USA + * COPYRIGHT © 2014 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -44,6 +44,47 @@ enum stdu_content_type { SEPARATE_DMA }; +/** + * struct vmw_stdu_dirty - closure structure for the update functions + * + * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). + * @transfer: Transfer direction for DMA command. + * @left: Left side of bounding box. + * @right: Right side of bounding box. + * @top: Top side of bounding box. + * @bottom: Bottom side of bounding box. + * @buf: DMA buffer when DMA-ing between buffer and screen targets. + * @sid: Surface ID when copying between surface and screen targets. + */ +struct vmw_stdu_dirty { + struct vmw_kms_dirty base; + SVGA3dTransferType transfer; + s32 left, right, top, bottom; + u32 pitch; + union { + struct vmw_dma_buffer *buf; + u32 sid; + }; +}; + +/* + * SVGA commands that are used by this code. Please see the device headers + * for explanation. + */ +struct vmw_stdu_update { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBScreenTarget body; +}; + +struct vmw_stdu_dma { + SVGA3dCmdHeader header; + SVGA3dCmdSurfaceDMA body; +}; + +struct vmw_stdu_surface_copy { + SVGA3dCmdHeader header; + SVGA3dCmdSurfaceCopy body; +}; /** @@ -139,254 +180,6 @@ static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc) vmw_stdu_destroy(vmw_crtc_to_stdu(crtc)); } - - -/** - * vmw_stdu_dma_update - Update DMA buf dirty region on the SVGA device - * - * @dev_priv: VMW DRM device - * @file_priv: Pointer to a drm file private structure - * @vfbs: VMW framebuffer surface that may need a DMA buf update - * @x: top/left corner of the content area to blit from - * @y: top/left corner of the content area to blit from - * @width: width of the blit area - * @height: height of the blit area - * - * The SVGA device may have the DMA buf cached, so before letting the - * device use it as the source image for a subsequent operation, we - * update the cached copy. - * - * RETURNs: - * 0 on success, error code on failure - */ -static int vmw_stdu_dma_update(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer_surface *vfbs, - uint32_t x, uint32_t y, - uint32_t width, uint32_t height) -{ - size_t fifo_size; - struct { - SVGA3dCmdHeader header; - SVGA3dCmdUpdateGBImage body; - } img_update_cmd; - - - /* Only need to do this if the surface is a DMA buf proxy */ - if (!vfbs->is_dmabuf_proxy) - return 0; - - fifo_size = sizeof(img_update_cmd); - - memset(&img_update_cmd, 0, fifo_size); - img_update_cmd.header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; - img_update_cmd.header.size = sizeof(img_update_cmd.body); - - img_update_cmd.body.image.sid = vfbs->surface->res.id; - - img_update_cmd.body.box.x = x; - img_update_cmd.body.box.y = y; - img_update_cmd.body.box.w = width; - img_update_cmd.body.box.h = height; - img_update_cmd.body.box.d = 1; - - return vmw_execbuf_process(file_priv, dev_priv, NULL, - (void *) &img_update_cmd, - fifo_size, 0, VMW_QUIRK_SRC_SID_OK, - NULL, NULL); -} - - - -/** - * vmw_stdu_content_copy - copies an area from the content to display surface - * - * @dev_priv: VMW DRM device - * @file_priv: Pointer to a drm file private structure - * @stdu: STDU whose display surface will be blitted to - * @content_x: top/left corner of the content area to blit from - * @content_y: top/left corner of the content area to blit from - * @width: width of the blit area - * @height: height of the blit area - * @display_x: top/left corner of the display area to blit to - * @display_y: top/left corner of the display area to blit to - * - * Copies an area from the content surface to the display surface. - * - * RETURNs: - * 0 on success, error code on failure - */ -static int vmw_stdu_content_copy(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_screen_target_display_unit *stdu, - uint32_t content_x, uint32_t content_y, - uint32_t width, uint32_t height, - uint32_t display_x, uint32_t display_y) -{ - struct vmw_framebuffer_surface *content_vfbs; - size_t fifo_size; - int ret; - void *cmd; - u32 quirks = VMW_QUIRK_DST_SID_OK; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdSurfaceDMA body; - SVGA3dCopyBox area; - SVGA3dCmdSurfaceDMASuffix suffix; - } surface_dma_cmd; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdSurfaceCopy body; - SVGA3dCopyBox area; - } surface_cpy_cmd; - - - /* - * Can only copy if content and display surfaces exist and are not - * the same surface - */ - if (stdu->display_srf == NULL || stdu->content_fb == NULL || - stdu->content_fb_type == SAME_AS_DISPLAY) { - return -EINVAL; - } - - - if (stdu->content_fb_type == SEPARATE_DMA) { - struct vmw_framebuffer *content_vfb; - struct drm_vmw_size cur_size = {0}; - const struct svga3d_surface_desc *desc; - enum SVGA3dSurfaceFormat format; - SVGA3dCmdSurfaceDMASuffix *suffix; - SVGAGuestPtr ptr; - - - content_vfb = vmw_framebuffer_to_vfb(stdu->content_fb); - - cur_size.width = width; - cur_size.height = height; - cur_size.depth = 1; - - /* Derive a SVGA3dSurfaceFormat for the DMA buf */ - switch (content_vfb->base.bits_per_pixel) { - case 32: - format = SVGA3D_A8R8G8B8; - break; - case 24: - format = SVGA3D_X8R8G8B8; - break; - case 16: - format = SVGA3D_R5G6B5; - break; - case 15: - format = SVGA3D_A1R5G5B5; - break; - default: - DRM_ERROR("Invalid color depth: %d\n", - content_vfb->base.depth); - return -EINVAL; - } - - desc = svga3dsurface_get_desc(format); - - - fifo_size = sizeof(surface_dma_cmd); - - memset(&surface_dma_cmd, 0, fifo_size); - - ptr.gmrId = content_vfb->user_handle; - ptr.offset = 0; - - surface_dma_cmd.header.id = SVGA_3D_CMD_SURFACE_DMA; - surface_dma_cmd.header.size = sizeof(surface_dma_cmd.body) + - sizeof(surface_dma_cmd.area) + - sizeof(surface_dma_cmd.suffix); - - surface_dma_cmd.body.guest.ptr = ptr; - surface_dma_cmd.body.guest.pitch = stdu->content_fb->pitches[0]; - surface_dma_cmd.body.host.sid = stdu->display_srf->res.id; - surface_dma_cmd.body.host.face = 0; - surface_dma_cmd.body.host.mipmap = 0; - surface_dma_cmd.body.transfer = SVGA3D_WRITE_HOST_VRAM; - - surface_dma_cmd.area.srcx = content_x; - surface_dma_cmd.area.srcy = content_y; - surface_dma_cmd.area.x = display_x; - surface_dma_cmd.area.y = display_y; - surface_dma_cmd.area.d = 1; - surface_dma_cmd.area.w = width; - surface_dma_cmd.area.h = height; - - suffix = &surface_dma_cmd.suffix; - - suffix->suffixSize = sizeof(*suffix); - suffix->maximumOffset = svga3dsurface_get_image_buffer_size( - desc, - &cur_size, - stdu->content_fb->pitches[0]); - - cmd = (void *) &surface_dma_cmd; - } else { - u32 src_id; - - - content_vfbs = vmw_framebuffer_to_vfbs(stdu->content_fb); - - if (content_vfbs->is_dmabuf_proxy) { - ret = vmw_stdu_dma_update(dev_priv, file_priv, - content_vfbs, - content_x, content_y, - width, height); - - if (ret != 0) { - DRM_ERROR("Failed to update cached DMA buf\n"); - return ret; - } - - quirks |= VMW_QUIRK_SRC_SID_OK; - src_id = content_vfbs->surface->res.id; - } else { - struct vmw_framebuffer *content_vfb; - - content_vfb = vmw_framebuffer_to_vfb(stdu->content_fb); - src_id = content_vfb->user_handle; - } - - fifo_size = sizeof(surface_cpy_cmd); - - memset(&surface_cpy_cmd, 0, fifo_size); - - surface_cpy_cmd.header.id = SVGA_3D_CMD_SURFACE_COPY; - surface_cpy_cmd.header.size = sizeof(surface_cpy_cmd.body) + - sizeof(surface_cpy_cmd.area); - - surface_cpy_cmd.body.src.sid = src_id; - surface_cpy_cmd.body.dest.sid = stdu->display_srf->res.id; - - surface_cpy_cmd.area.srcx = content_x; - surface_cpy_cmd.area.srcy = content_y; - surface_cpy_cmd.area.x = display_x; - surface_cpy_cmd.area.y = display_y; - surface_cpy_cmd.area.d = 1; - surface_cpy_cmd.area.w = width; - surface_cpy_cmd.area.h = height; - - cmd = (void *) &surface_cpy_cmd; - } - - - - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, - (void *) cmd, - fifo_size, 0, quirks, - NULL, NULL); - - return ret; -} - - - /** * vmw_stdu_define_st - Defines a Screen Target * @@ -487,108 +280,56 @@ static int vmw_stdu_bind_st(struct vmw_private *dev_priv, return 0; } +/** + * vmw_stdu_populate_update - populate an UPDATE_GB_SCREENTARGET command with a + * bounding box. + * + * @cmd: Pointer to command stream. + * @unit: Screen target unit. + * @left: Left side of bounding box. + * @right: Right side of bounding box. + * @top: Top side of bounding box. + * @bottom: Bottom side of bounding box. + */ +static void vmw_stdu_populate_update(void *cmd, int unit, + s32 left, s32 right, s32 top, s32 bottom) +{ + struct vmw_stdu_update *update = cmd; + + update->header.id = SVGA_3D_CMD_UPDATE_GB_SCREENTARGET; + update->header.size = sizeof(update->body); + update->body.stid = unit; + update->body.rect.x = left; + update->body.rect.y = top; + update->body.rect.w = right - left; + update->body.rect.h = bottom - top; +} /** - * vmw_stdu_update_st - Updates a Screen Target + * vmw_stdu_update_st - Full update of a Screen Target * * @dev_priv: VMW DRM device - * @file_priv: Pointer to DRM file private structure. Set to NULL when - * we want to blank display. * @stdu: display unit affected - * @update_area: area that needs to be updated * * This function needs to be called whenever the content of a screen - * target changes. - * If the display and content buffers are different, then this function does - * a blit first from the content buffer to the display buffer before issuing - * the Screen Target update command. + * target has changed completely. Typically as a result of a backing + * surface change. * * RETURNS: * 0 on success, error code on failure */ static int vmw_stdu_update_st(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_screen_target_display_unit *stdu, - struct drm_clip_rect *update_area) + struct vmw_screen_target_display_unit *stdu) { - u32 width, height; - u32 display_update_x, display_update_y; - unsigned short display_x1, display_y1, display_x2, display_y2; - int ret; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdUpdateGBScreenTarget body; - } *cmd; - + struct vmw_stdu_update *cmd; + struct drm_crtc *crtc = &stdu->base.crtc; if (!stdu->defined) { DRM_ERROR("No screen target defined"); return -EINVAL; } - /* Display coordinates relative to its position in content surface */ - display_x1 = stdu->base.crtc.x; - display_y1 = stdu->base.crtc.y; - display_x2 = display_x1 + stdu->display_srf->base_size.width; - display_y2 = display_y1 + stdu->display_srf->base_size.height; - - /* Do nothing if the update area is outside of the display surface */ - if (update_area->x2 <= display_x1 || update_area->x1 >= display_x2 || - update_area->y2 <= display_y1 || update_area->y1 >= display_y2) - return 0; - - /* The top-left hand corner of the update area in display surface */ - display_update_x = max(update_area->x1 - display_x1, 0); - display_update_y = max(update_area->y1 - display_y1, 0); - - width = min(update_area->x2, display_x2) - - max(update_area->x1, display_x1); - height = min(update_area->y2, display_y2) - - max(update_area->y1, display_y1); - - /* - * If content is on a separate surface, then copy the dirty area to - * the display surface - */ - if (file_priv && stdu->content_fb_type != SAME_AS_DISPLAY) { - - ret = vmw_stdu_content_copy(dev_priv, file_priv, - stdu, - max(update_area->x1, display_x1), - max(update_area->y1, display_y1), - width, height, - display_update_x, display_update_y); - if (unlikely(ret != 0)) { - DRM_ERROR("Failed to blit content\n"); - return ret; - } - } - - - /* - * If the display surface is the same as the content surface, then - * it may be backed by a DMA buf. If it is then we need to update - * the device's cached copy of the DMA buf before issuing the screen - * target update. - */ - if (file_priv && stdu->content_fb_type == SAME_AS_DISPLAY) { - struct vmw_framebuffer_surface *vfbs; - - vfbs = vmw_framebuffer_to_vfbs(stdu->content_fb); - ret = vmw_stdu_dma_update(dev_priv, file_priv, - vfbs, - max(update_area->x1, display_x1), - max(update_area->y1, display_y1), - width, height); - - if (ret != 0) { - DRM_ERROR("Failed to update cached DMA buffer\n"); - return ret; - } - } - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); if (unlikely(cmd == NULL)) { @@ -596,14 +337,8 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv, return -ENOMEM; } - cmd->header.id = SVGA_3D_CMD_UPDATE_GB_SCREENTARGET; - cmd->header.size = sizeof(cmd->body); - - cmd->body.stid = stdu->base.unit; - cmd->body.rect.x = display_update_x; - cmd->body.rect.y = display_update_y; - cmd->body.rect.w = width; - cmd->body.rect.h = height; + vmw_stdu_populate_update(cmd, stdu->base.unit, 0, crtc->mode.hdisplay, + 0, crtc->mode.vdisplay); vmw_fifo_commit(dev_priv, sizeof(*cmd)); @@ -682,7 +417,6 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector *connector; - struct drm_clip_rect update_area = {0}; int ret; @@ -728,12 +462,7 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) /* Update Screen Target, display will now be blank */ if (crtc->primary->fb) { - update_area.x2 = crtc->primary->fb->width; - update_area.y2 = crtc->primary->fb->height; - - ret = vmw_stdu_update_st(dev_priv, NULL, - stdu, - &update_area); + vmw_stdu_update_st(dev_priv, stdu); if (unlikely(ret != 0)) return ret; } @@ -852,7 +581,6 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) goto err_unref_content; } - vmw_fb_off(dev_priv); vmw_svga_enable(dev_priv); /* @@ -919,17 +647,8 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct vmw_screen_target_display_unit *stdu; - struct drm_file *file_priv; - struct drm_clip_rect update_area = {0}; int ret; - /* - * Temporarily don't support event == NULL. We need the - * @file_priv pointer! - */ - if (event == NULL) - return -EINVAL; - if (crtc == NULL) return -EINVAL; @@ -939,9 +658,6 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, stdu->content_fb = new_fb; if (stdu->display_srf) { - update_area.x2 = stdu->display_srf->base_size.width; - update_area.y2 = stdu->display_srf->base_size.height; - /* * If the display surface is the same as the content surface * then remove the reference @@ -961,7 +677,7 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, if (!new_fb) { /* Blanks the display */ - (void) vmw_stdu_update_st(dev_priv, NULL, stdu, &update_area); + (void) vmw_stdu_update_st(dev_priv, stdu); return 0; } @@ -982,16 +698,13 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, } /* Update display surface: after this point everything is bound */ - update_area.x2 = stdu->display_srf->base_size.width; - update_area.y2 = stdu->display_srf->base_size.height; - - file_priv = event->base.file_priv; - ret = vmw_stdu_update_st(dev_priv, file_priv, stdu, &update_area); + ret = vmw_stdu_update_st(dev_priv, stdu); if (unlikely(ret != 0)) return ret; if (event) { struct vmw_fence_obj *fence = NULL; + struct drm_file *file_priv = event->base.file_priv; vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); if (!fence) @@ -1016,6 +729,310 @@ err_out: } +/** + * vmw_stdu_dmabuf_clip - Callback to encode a suface DMA command cliprect + * + * @dirty: The closure structure. + * + * Encodes a surface DMA command cliprect and updates the bounding box + * for the DMA. + */ +static void vmw_stdu_dmabuf_clip(struct vmw_kms_dirty *dirty) +{ + struct vmw_stdu_dirty *ddirty = + container_of(dirty, struct vmw_stdu_dirty, base); + struct vmw_stdu_dma *cmd = dirty->cmd; + struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; + + blit += dirty->num_hits; + blit->srcx = dirty->fb_x; + blit->srcy = dirty->fb_y; + blit->x = dirty->unit_x1; + blit->y = dirty->unit_y1; + blit->d = 1; + blit->w = dirty->unit_x2 - dirty->unit_x1; + blit->h = dirty->unit_y2 - dirty->unit_y1; + dirty->num_hits++; + + if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM) + return; + + /* Destination bounding box */ + ddirty->left = min_t(s32, ddirty->left, dirty->unit_x1); + ddirty->top = min_t(s32, ddirty->top, dirty->unit_y1); + ddirty->right = max_t(s32, ddirty->right, dirty->unit_x2); + ddirty->bottom = max_t(s32, ddirty->bottom, dirty->unit_y2); +} + +/** + * vmw_stdu_dmabuf_fifo_commit - Callback to fill in and submit a DMA command. + * + * @dirty: The closure structure. + * + * Fills in the missing fields in a DMA command, and optionally encodes + * a screen target update command, depending on transfer direction. + */ +static void vmw_stdu_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) +{ + struct vmw_stdu_dirty *ddirty = + container_of(dirty, struct vmw_stdu_dirty, base); + struct vmw_screen_target_display_unit *stdu = + container_of(dirty->unit, typeof(*stdu), base); + struct vmw_stdu_dma *cmd = dirty->cmd; + struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; + SVGA3dCmdSurfaceDMASuffix *suffix = + (SVGA3dCmdSurfaceDMASuffix *) &blit[dirty->num_hits]; + size_t blit_size = sizeof(*blit) * dirty->num_hits + sizeof(*suffix); + + if (!dirty->num_hits) { + vmw_fifo_commit(dirty->dev_priv, 0); + return; + } + + cmd->header.id = SVGA_3D_CMD_SURFACE_DMA; + cmd->header.size = size |
