diff options
Diffstat (limited to 'vmwgfx')
-rw-r--r-- | vmwgfx/vmwgfx_drmi.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/vmwgfx/vmwgfx_drmi.c b/vmwgfx/vmwgfx_drmi.c index a420bd9..a602103 100644 --- a/vmwgfx/vmwgfx_drmi.c +++ b/vmwgfx/vmwgfx_drmi.c @@ -82,53 +82,66 @@ vmwgfx_present_readback(int drm_fd, uint32_t fb_id, RegionPtr region) { BoxPtr clips = REGION_RECTS(region); unsigned int num_clips = REGION_NUM_RECTS(region); + unsigned int alloc_clips = min(num_clips, DRM_MODE_FB_DIRTY_MAX_CLIPS); struct drm_vmw_fence_rep rep; struct drm_vmw_present_readback_arg arg; int ret; unsigned i; struct drm_vmw_rect *rects, *r; - rects = calloc(num_clips, sizeof(*rects)); + if (num_clips == 0) + return 0; + + rects = malloc(alloc_clips * sizeof(*rects)); if (!rects) { LogMessage(X_ERROR, "Failed to alloc cliprects for " "present readback.\n"); return -1; } - memset(&arg, 0, sizeof(arg)); - memset(&rep, 0, sizeof(rep)); - - arg.fb_id = fb_id; - arg.num_clips = num_clips; - arg.clips_ptr = (unsigned long) rects; - arg.fence_rep = (unsigned long) &rep; - rep.error = -EFAULT; - - for (i = 0, r = rects; i < num_clips; ++i, ++r, ++clips) { - r->x = clips->x1; - r->y = clips->y1; - r->w = clips->x2 - clips->x1; - r->h = clips->y2 - clips->y1; - } + while (num_clips > 0) { + unsigned int cur_clips = min(num_clips, DRM_MODE_FB_DIRTY_MAX_CLIPS); - ret = drmCommandWrite(drm_fd, DRM_VMW_PRESENT_READBACK, &arg, sizeof(arg)); - if (ret) - LogMessage(X_ERROR, "Present readback error %s.\n", strerror(-ret)); - free(rects); + memset(&arg, 0, sizeof(arg)); + memset(&rep, 0, sizeof(rep)); + memset(rects, 0, alloc_clips * sizeof(*rects)); - /* - * Sync to avoid racing with Xorg SW rendering. - */ + arg.fb_id = fb_id; + arg.num_clips = cur_clips; + arg.clips_ptr = (unsigned long) rects; - if (rep.error == 0) { - ret = vmwgfx_fence_wait(drm_fd, rep.handle, TRUE); - if (ret) { - LogMessage(X_ERROR, "Present readback fence wait error %s.\n", - strerror(-ret)); - vmwgfx_fence_unref(drm_fd, rep.handle); + /* Only request a fence on the last clip batch */ + arg.fence_rep = (cur_clips == num_clips) ? (unsigned long) &rep : 0UL; + rep.error = -EFAULT; + + for (i = 0, r = rects; i < cur_clips; ++i, ++r, ++clips) { + r->x = clips->x1; + r->y = clips->y1; + r->w = clips->x2 - clips->x1; + r->h = clips->y2 - clips->y1; + } + + ret = drmCommandWrite(drm_fd, DRM_VMW_PRESENT_READBACK, &arg, + sizeof(arg)); + if (ret) + LogMessage(X_ERROR, "Present readback error %s.\n", strerror(-ret)); + + /* Sync if we have a fence to avoid racing with Xorg SW rendering. */ + if (rep.error == 0) { + ret = vmwgfx_fence_wait(drm_fd, rep.handle, TRUE); + if (ret) { + LogMessage(X_ERROR, "Present readback fence wait error %s.\n", + strerror(-ret)); + /* vmwgfx_fence_wait() takes care of this if ret == 0. */ + vmwgfx_fence_unref(drm_fd, rep.handle); + } } + + num_clips -= cur_clips; } + free(rects); + return 0; } |