summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Garbett <David.Garbett@arm.com>2012-07-02 10:15:47 +0100
committerDavid Garbett <David.Garbett@arm.com>2012-10-04 10:52:35 +0100
commitae5a636895f5cebeba6c844c68ca78588fee70c2 (patch)
treedc4690734dbceacf45d660bf64aacef3939d0565
parentcd68442d022632b5058b084cf068e4b0cfc9753e (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.c23
-rw-r--r--src/omap_dri2.c12
-rw-r--r--src/omap_drmif_fb.h5
-rw-r--r--src/omap_dumb.c66
-rw-r--r--src/omap_exa.c58
-rw-r--r--src/omap_exa.h9
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_ */