diff options
author | David Garbett <David.Garbett@arm.com> | 2012-07-02 10:15:47 +0100 |
---|---|---|
committer | David Garbett <David.Garbett@arm.com> | 2012-10-04 10:52:35 +0100 |
commit | ae5a636895f5cebeba6c844c68ca78588fee70c2 (patch) | |
tree | dc4690734dbceacf45d660bf64aacef3939d0565 | |
parent | cd68442d022632b5058b084cf068e4b0cfc9753e (diff) |
select() on dma_buf fd in cpu_prep (so PrepareAccess).
Only attach dma_buf to dumb buffers that back DRI2 Buffers, so the fd limit is
not reached.
If poll() is not implemented on the dma_buf file then the select() does
nothing. A warning is printed if select() takes longer than 10s.
Reference counts the number of DRI2 buffers that wrap a Pixmap, so the
dma_buf fd is only kept open while it is wrapped and to enable additional
asserts.
-rw-r--r-- | src/drmmode_display.c | 23 | ||||
-rw-r--r-- | src/omap_dri2.c | 12 | ||||
-rw-r--r-- | src/omap_drmif_fb.h | 5 | ||||
-rw-r--r-- | src/omap_dumb.c | 66 | ||||
-rw-r--r-- | src/omap_exa.c | 58 | ||||
-rw-r--r-- | src/omap_exa.h | 9 |
6 files changed, 167 insertions, 6 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c index e960645..a4802f9 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -1041,8 +1041,6 @@ drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height) || (height != omap_bo_height(pOMAP->scanout)) || (pScrn->bitsPerPixel != omap_bo_bpp(pOMAP->scanout)) ) { - /* delete old scanout buffer */ - omap_bo_unreference(pOMAP->scanout); pOMAP->has_resized = TRUE; DEBUG_MSG("allocating new scanout buffer: %dx%d", width, height); @@ -1059,8 +1057,27 @@ drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height) } pitch = omap_bo_pitch(new_scanout); - if (omap_bo_add_fb(new_scanout)) + if (omap_bo_add_fb(new_scanout)) { + omap_bo_unreference(new_scanout); return FALSE; + } + + /* Handle dma_buf fd that may be attached to bo */ + if(omap_bo_has_dmabuf(pOMAP->scanout)) + { + omap_bo_clear_dmabuf(pOMAP->scanout); + res = omap_bo_set_dmabuf(new_scanout); + if(res) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unable to attach dma_buf fd to new scanout buffer. " + "Error: %d (%s)\n", res, strerror(res)); + omap_bo_unreference(new_scanout); + return FALSE; + } + } + + /* delete old scanout buffer */ + omap_bo_unreference(pOMAP->scanout); set_scanout_bo(pScrn, new_scanout); diff --git a/src/omap_dri2.c b/src/omap_dri2.c index 8e0f39f..4c65caf 100644 --- a/src/omap_dri2.c +++ b/src/omap_dri2.c @@ -101,8 +101,10 @@ canflip(DrawablePtr pDraw) static inline Bool exchangebufs(DrawablePtr pDraw, DRI2BufferPtr a, DRI2BufferPtr b) { - OMAPPixmapExchange(draw2pix(dri2draw(pDraw, a)), - draw2pix(dri2draw(pDraw, b))); + PixmapPtr aPix = draw2pix(dri2draw(pDraw, a)); + PixmapPtr bPix = draw2pix(dri2draw(pDraw, b)); + + OMAPPixmapExchange(aPix,bPix); exchange(a->name, b->name); return TRUE; } @@ -215,6 +217,10 @@ OMAPDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment, } } + /* Register Pixmap as having a buffer that can be accessed externally, + * so needs synchronised access */ + OMAPRegisterExternalAccess(pPixmap); + return DRIBUF(buf); } @@ -240,6 +246,8 @@ OMAPDRI2DestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer) DEBUG_MSG("pDraw=%p, buffer=%p", pDraw, buffer); + OMAPDeregisterExternalAccess(buf->pPixmap); + pScreen->DestroyPixmap(buf->pPixmap); free(buf); diff --git a/src/omap_drmif_fb.h b/src/omap_drmif_fb.h index 3972e25..9599411 100644 --- a/src/omap_drmif_fb.h +++ b/src/omap_drmif_fb.h @@ -49,5 +49,10 @@ uint32_t omap_bo_pitch(struct omap_bo *bo); void omap_bo_reference(struct omap_bo *bo); void omap_bo_unreference(struct omap_bo *bo); +/* When dmabuf is set on a bo, omap_bo_cpu_prep() waits for KDS shared access */ +int omap_bo_set_dmabuf(struct omap_bo *bo); +void omap_bo_clear_dmabuf(struct omap_bo *bo); +int omap_bo_has_dmabuf(struct omap_bo *bo); + #endif /* OMAP_DRMIF_FB_H_ */ diff --git a/src/omap_dumb.c b/src/omap_dumb.c index 84d63da..2ab5eb1 100644 --- a/src/omap_dumb.c +++ b/src/omap_dumb.c @@ -25,6 +25,7 @@ #include <sys/mman.h> #include <assert.h> #include <errno.h> +#include <unistd.h> #include <xf86.h> #include <xf86drm.h> @@ -49,6 +50,7 @@ struct omap_bo { uint8_t bpp; uint32_t pitch; int refcnt; + int dmabuf; }; /* device related functions: @@ -72,6 +74,41 @@ void omap_device_del(struct omap_device *dev) /* buffer-object related functions: */ +int omap_bo_set_dmabuf(struct omap_bo *bo) +{ + int res; + struct drm_prime_handle prime_handle; + + assert(!omap_bo_has_dmabuf(bo)); + + /* Try to get dma_buf fd */ + prime_handle.handle = bo->handle; + prime_handle.flags = 0; + res = drmIoctl(bo->dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle); + if (res) + { + res = errno; + } + else + { + bo->dmabuf = prime_handle.fd; + } + return res; +} + +void omap_bo_clear_dmabuf(struct omap_bo *bo) +{ + assert(omap_bo_has_dmabuf(bo)); + + close(bo->dmabuf); + bo->dmabuf = -1; +} + +int omap_bo_has_dmabuf(struct omap_bo *bo) +{ + return bo->dmabuf >= 0; +} + struct omap_bo *omap_bo_new_with_dim(struct omap_device *dev, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t flags) @@ -111,6 +148,7 @@ struct omap_bo *omap_bo_new_with_dim(struct omap_device *dev, new_buf->depth = depth; new_buf->bpp = create_dumb.bpp; new_buf->refcnt = 1; + new_buf->dmabuf = -1; return new_buf; } @@ -141,6 +179,7 @@ struct omap_bo *omap_bo_from_name(struct omap_device *dev, uint32_t name) new_buf->map_addr = NULL; new_buf->fb_id = 0; new_buf->refcnt = 1; + new_buf->dmabuf = -1; return new_buf; } @@ -153,6 +192,8 @@ void omap_bo_del(struct omap_bo *bo) if (!bo) return; + assert(!omap_bo_has_dmabuf(bo)); + if (bo->map_addr) { munmap(bo->map_addr, bo->size); @@ -253,7 +294,30 @@ void *omap_bo_map(struct omap_bo *bo) int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op) { - return 0; + int ret = 0; + + if(omap_bo_has_dmabuf(bo)) + { + fd_set fds; + const struct timeval timeout = {10,0}; /* 10s before printing a msg */ + struct timeval t; + FD_ZERO(&fds); + FD_SET(bo->dmabuf, &fds); + + do + { + t = timeout; + ret = select(bo->dmabuf+1, &fds, NULL, NULL, &t); + if (ret == 0) + { + xf86DrvMsg(-1, X_ERROR, "select() on dma_buf fd has timed-out"); + } + }while ( (ret == -1 && errno == EINTR) || ret == 0 ); + + if (ret > 0) + ret = 0; + } + return ret; } int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op) diff --git a/src/omap_exa.c b/src/omap_exa.c index cf2e294..c178f5f 100644 --- a/src/omap_exa.c +++ b/src/omap_exa.c @@ -57,6 +57,23 @@ OMAPPixmapExchange(PixmapPtr a, PixmapPtr b) OMAPPixmapPrivPtr bpriv = exaGetPixmapDriverPrivate(b); exchange(apriv->priv, bpriv->priv); exchange(apriv->bo, bpriv->bo); + + /* Ensure neither pixmap has a dmabuf fd attached to the bo if the + * ext_access_cnt refcount is 0, as it will never be cleared. */ + if (omap_bo_has_dmabuf(apriv->bo) && !apriv->ext_access_cnt) + { + omap_bo_clear_dmabuf(apriv->bo); + + /* Should only have to clear one dmabuf fd, otherwise the + * refcount is broken */ + assert(!omap_bo_has_dmabuf(bpriv->bo)); + } + else if (omap_bo_has_dmabuf(bpriv->bo) && !bpriv->ext_access_cnt) + { + omap_bo_clear_dmabuf(bpriv->bo); + + assert(!omap_bo_has_dmabuf(apriv->bo)); + } } _X_EXPORT void * @@ -76,6 +93,9 @@ OMAPDestroyPixmap(ScreenPtr pScreen, void *driverPriv) { OMAPPixmapPrivPtr priv = driverPriv; + assert(!priv->ext_access_cnt); + assert(!omap_bo_has_dmabuf(priv->bo)); + omap_bo_unreference(priv->bo); free(priv); @@ -229,9 +249,20 @@ OMAPPrepareAccess(PixmapPtr pPixmap, int index) pPixmap->devPrivate.ptr = omap_bo_map(priv->bo); if (!pPixmap->devPrivate.ptr) { + xf86DrvMsg(-1, X_ERROR, "%s: Failed to map buffer\n", __FUNCTION__); return FALSE; } + /* Attach dmabuf fd to bo to synchronise access if pixmap wrapped by DRI2 */ + if (priv->ext_access_cnt && !omap_bo_has_dmabuf(priv->bo)) + { + if(omap_bo_set_dmabuf(priv->bo)) { + xf86DrvMsg(-1, X_ERROR, "%s: Unable to get dma_buf fd for bo, " + "to enable synchronised CPU access.\n", __FUNCTION__); + return FALSE; + } + } + /* wait for blits complete.. note we could be a bit more clever here * for non-DRI2 buffers and use separate OMAP{Prepare,Finish}GPUAccess() * fxns wrapping accelerated GPU operations.. this way we don't have @@ -241,6 +272,8 @@ OMAPPrepareAccess(PixmapPtr pPixmap, int index) */ if (omap_bo_cpu_prep(priv->bo, idx2op(index))) { + xf86DrvMsg(-1, X_ERROR, "%s: omap_bo_cpu_prep failed - " + "unable to synchronise access.\n", __FUNCTION__); return FALSE; } @@ -296,3 +329,28 @@ OMAPPixmapIsOffscreen(PixmapPtr pPixmap) OMAPPixmapPrivPtr priv = exaGetPixmapDriverPrivate(pPixmap); return priv && priv->bo; } + +void OMAPRegisterExternalAccess(PixmapPtr pPixmap) +{ + OMAPPixmapPrivPtr priv = exaGetPixmapDriverPrivate(pPixmap); + + priv->ext_access_cnt++; +} + +void OMAPDeregisterExternalAccess(PixmapPtr pPixmap) +{ + OMAPPixmapPrivPtr priv = exaGetPixmapDriverPrivate(pPixmap); + + assert(priv->ext_access_cnt > 0); + priv->ext_access_cnt--; + + if (priv->ext_access_cnt == 0) + { + /* No DRI2 buffers wrapping the pixmap, so no need for synchronisation + * with dma_buf */ + if(omap_bo_has_dmabuf(priv->bo)) + { + omap_bo_clear_dmabuf(priv->bo); + } + } +} diff --git a/src/omap_exa.h b/src/omap_exa.h index b1d4c64..288387e 100644 --- a/src/omap_exa.h +++ b/src/omap_exa.h @@ -123,6 +123,9 @@ draw2pix(DrawablePtr pDraw) typedef struct { void *priv; /* EXA submodule private data */ + int ext_access_cnt; /* Ref-count of DRI2Buffers that wrap the Pixmap, + that allow external access to the underlying + buffer. When >0 CPU access must be synchronised. */ struct omap_bo *bo; } OMAPPixmapPrivRec, *OMAPPixmapPrivPtr; @@ -151,4 +154,10 @@ OMAPPixmapBo(PixmapPtr pPixmap) void OMAPPixmapExchange(PixmapPtr a, PixmapPtr b); +/* Register that the pixmap can be accessed externally, so + * CPU access must be synchronised. */ +void OMAPRegisterExternalAccess(PixmapPtr pPixmap); +void OMAPDeregisterExternalAccess(PixmapPtr pPixmap); + + #endif /* OMAP_EXA_COMMON_H_ */ |