summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2019-01-09 08:00:00 +0100
committerThomas Hellstrom <thellstrom@vmware.com>2019-01-28 14:47:55 +0100
commitba4ef498fd1f66f81aaffc3dac504044b2ad7cc3 (patch)
tree43bf0021026a441d22c33396e08c40ad4d9165a0
parentd31e8e77e1453c26a02f24b26d96b4660d29e1df (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.h1
-rw-r--r--vmwgfx/vmwgfx_drmi.c147
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);
+ }
}
}