diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2019-01-09 08:00:00 +0100 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2019-01-28 14:47:55 +0100 |
commit | ba4ef498fd1f66f81aaffc3dac504044b2ad7cc3 (patch) | |
tree | 43bf0021026a441d22c33396e08c40ad4d9165a0 | |
parent | d31e8e77e1453c26a02f24b26d96b4660d29e1df (diff) |
vmwgfx: Don't exceed the device command size limit v3
With a huge number of DMA clip rects we could exceed the device command
buffer command size limit. Fix this by sending multiple DMA commands
when we exceed the limit.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Deepak Rawat <drawat@vmware.com> #v1
-rw-r--r-- | src/svga_reg.h | 1 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_drmi.c | 147 |
2 files changed, 79 insertions, 69 deletions
diff --git a/src/svga_reg.h b/src/svga_reg.h index 0e1aa17..4aee52f 100644 --- a/src/svga_reg.h +++ b/src/svga_reg.h @@ -302,6 +302,7 @@ struct SVGAGuestPtr { uint32 offset; } SVGAGuestPtr; +#define SVGA_CB_MAX_COMMAND_SIZE (32 * 1024) /* 32 KB */ /* * SVGAGMRImageFormat -- diff --git a/vmwgfx/vmwgfx_drmi.c b/vmwgfx/vmwgfx_drmi.c index b6fb56d..82bf5f5 100644 --- a/vmwgfx/vmwgfx_drmi.c +++ b/vmwgfx/vmwgfx_drmi.c @@ -293,93 +293,102 @@ vmwgfx_dma(int host_x, int host_y, struct drm_vmw_execbuf_arg arg; struct drm_vmw_fence_rep rep; int ret; - unsigned int size; unsigned i; SVGA3dCopyBox *cb; SVGA3dCmdSurfaceDMASuffix *suffix; SVGA3dCmdSurfaceDMA *body; struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf); - struct { SVGA3dCmdHeader header; SVGA3dCmdSurfaceDMA body; SVGA3dCopyBox cb; } *cmd; - - if (num_clips == 0) - return 0; - - size = sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cb) + - sizeof(*suffix); - cmd = malloc(size); - if (!cmd) - return -1; - - cmd->header.id = SVGA_3D_CMD_SURFACE_DMA; - cmd->header.size = sizeof(cmd->body) + num_clips * sizeof(cmd->cb) + - sizeof(*suffix); - cb = &cmd->cb; - - suffix = (SVGA3dCmdSurfaceDMASuffix *) &cb[num_clips]; - suffix->suffixSize = sizeof(*suffix); - suffix->maximumOffset = (uint32_t) -1; - suffix->flags.discard = 0; - suffix->flags.unsynchronized = 0; - suffix->flags.reserved = 0; - - body = &cmd->body; - body->guest.ptr.gmrId = buf->gmr_id; - body->guest.ptr.offset = buf->gmr_offset; - body->guest.pitch = buf_pitch; - body->host.sid = surface_handle; - body->host.face = 0; - body->host.mipmap = 0; - - body->transfer = (to_surface ? SVGA3D_WRITE_HOST_VRAM : - SVGA3D_READ_HOST_VRAM); - - - for (i=0; i < num_clips; i++, cb++, clips++) { - cb->x = (uint16_t) clips->x1 + host_x; - cb->y = (uint16_t) clips->y1 + host_y; - cb->z = 0; - cb->srcx = (uint16_t) clips->x1; - cb->srcy = (uint16_t) clips->y1; - cb->srcz = 0; - cb->w = (uint16_t) (clips->x2 - clips->x1); - cb->h = (uint16_t) (clips->y2 - clips->y1); - cb->d = 1; + static unsigned int max_clips = + (SVGA_CB_MAX_COMMAND_SIZE - sizeof(*cmd) - sizeof(*suffix)) / + sizeof(cmd->cb) + 1; + + while (num_clips > 0) { + unsigned int size; + unsigned int cur_clips; + + cur_clips = min(num_clips, max_clips); + size = sizeof(*cmd) + (cur_clips - 1) * sizeof(cmd->cb) + + sizeof(*suffix); + + cmd = calloc(1, size); + if (!cmd) + return -1; + + cmd->header.id = SVGA_3D_CMD_SURFACE_DMA; + cmd->header.size = sizeof(cmd->body) + cur_clips * sizeof(cmd->cb) + + sizeof(*suffix); + cb = &cmd->cb; + + suffix = (SVGA3dCmdSurfaceDMASuffix *) &cb[cur_clips]; + suffix->suffixSize = sizeof(*suffix); + suffix->maximumOffset = (uint32_t) -1; + suffix->flags.discard = 0; + suffix->flags.unsynchronized = 0; + suffix->flags.reserved = 0; + + body = &cmd->body; + body->guest.ptr.gmrId = buf->gmr_id; + body->guest.ptr.offset = buf->gmr_offset; + body->guest.pitch = buf_pitch; + body->host.sid = surface_handle; + body->host.face = 0; + body->host.mipmap = 0; + + body->transfer = (to_surface ? SVGA3D_WRITE_HOST_VRAM : + SVGA3D_READ_HOST_VRAM); + + for (i = 0; i < cur_clips; i++, cb++, clips++) { + cb->x = (uint16_t) clips->x1 + host_x; + cb->y = (uint16_t) clips->y1 + host_y; + cb->z = 0; + cb->srcx = (uint16_t) clips->x1; + cb->srcy = (uint16_t) clips->y1; + cb->srcz = 0; + cb->w = (uint16_t) (clips->x2 - clips->x1); + cb->h = (uint16_t) (clips->y2 - clips->y1); + cb->d = 1; #if 0 - LogMessage(X_INFO, "DMA! x: %u y: %u srcx: %u srcy: %u w: %u h: %u %s\n", - cb->x, cb->y, cb->srcx, cb->srcy, cb->w, cb->h, - to_surface ? "to" : "from"); + LogMessage(X_INFO, "DMA! x: %u y: %u srcx: %u srcy: %u w: %u h: %u %s\n", + cb->x, cb->y, cb->srcx, cb->srcy, cb->w, cb->h, + to_surface ? "to" : "from"); #endif - } - - memset(&arg, 0, sizeof(arg)); - memset(&rep, 0, sizeof(rep)); + } - rep.error = -EFAULT; - arg.fence_rep = ((to_surface) ? 0UL : (unsigned long)&rep); - arg.commands = (unsigned long)cmd; - arg.command_size = size; - arg.throttle_us = 0; - arg.version = DRM_VMW_EXECBUF_VERSION; + memset(&arg, 0, sizeof(arg)); + memset(&rep, 0, sizeof(rep)); - ret = drmCommandWrite(ibuf->drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg)); - if (ret) { - LogMessage(X_ERROR, "DMA error %s.\n", strerror(-ret)); - } + rep.error = -EFAULT; - free(cmd); + /* Only require a fence if readback and last batch of cliprects. */ + arg.fence_rep = ((to_surface && (cur_clips == num_clips)) ? + 0UL : (unsigned long) &rep); + arg.commands = (unsigned long)cmd; + arg.command_size = size; + arg.throttle_us = 0; + arg.version = DRM_VMW_EXECBUF_VERSION; - if (rep.error == 0) { - ret = vmwgfx_fence_wait(ibuf->drm_fd, rep.handle, TRUE); + ret = drmCommandWrite(ibuf->drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg)); if (ret) { - LogMessage(X_ERROR, "DMA from host fence wait error %s.\n", - strerror(-ret)); - vmwgfx_fence_unref(ibuf->drm_fd, rep.handle); + LogMessage(X_ERROR, "DMA error %s.\n", strerror(-ret)); + } + + free(cmd); + num_clips -= cur_clips; + + if (rep.error == 0) { + ret = vmwgfx_fence_wait(ibuf->drm_fd, rep.handle, TRUE); + if (ret) { + LogMessage(X_ERROR, "DMA from host fence wait error %s.\n", + strerror(-ret)); + /* vmwgfx_fence_wait() takes care of this if ret == 0. */ + vmwgfx_fence_unref(ibuf->drm_fd, rep.handle); + } } } |