aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Garbett <david.garbett@arm.com>2013-04-04 09:04:29 +0100
committerDavid Garbett <david.garbett@arm.com>2013-07-09 10:48:57 +0100
commit4d37be3492bb1d3af52b550fdb233f411b004d70 (patch)
tree4e62ef52a63641f9ce78b96b641132349c032c52
parent119001b1eff83fdb9232f96c031b9b0353eb5aa1 (diff)
DRI2 N-Buffering
Adds an xorg.conf option to specify the number of buffers to use with DRI2. This will only apply when page flipping (i.e. full screen windows). Change-Id: I2e59a5fa521837bb24462d445897699486ba3874 Signed-off-by: David Garbett <david.garbett@arm.com>
-rw-r--r--src/armsoc_dri2.c220
-rw-r--r--src/armsoc_driver.c18
-rw-r--r--src/armsoc_driver.h1
3 files changed, 210 insertions, 29 deletions
diff --git a/src/armsoc_dri2.c b/src/armsoc_dri2.c
index e06c77f..a2e71ca 100644
--- a/src/armsoc_dri2.c
+++ b/src/armsoc_dri2.c
@@ -46,13 +46,32 @@ struct ARMSOCDRI2BufferRec {
DRI2BufferRec base;
/**
- * Pixmap that is backing the buffer
+ * Pixmap(s) that are backing the buffer
*
* NOTE: don't track the pixmap ptr for the front buffer if it is
* a window.. this could get reallocated from beneath us, so we should
* always use draw2pix to be sure to have the correct one
*/
- PixmapPtr pPixmap;
+ PixmapPtr *pPixmaps;
+
+ /**
+ * Pixmap that corresponds to the DRI2BufferRec.name, so wraps
+ * the buffer that will be used for DRI2GetBuffers calls and the
+ * next DRI2SwapBuffers call.
+ *
+ * When using more than double buffering this (and the name) are updated
+ * after a swap, before the next DRI2GetBuffers call.
+ */
+ unsigned currentPixmap;
+
+ /**
+ * Number of Pixmaps to use.
+ *
+ * This allows the number of back buffers used to be reduced, for
+ * example when allocation fails. It cannot be changed to increase the
+ * number of buffers as we would overflow the pPixmaps array.
+ */
+ unsigned numPixmaps;
/**
* The DRI2 buffers are reference counted to avoid crashyness when the
@@ -62,8 +81,8 @@ struct ARMSOCDRI2BufferRec {
int refcnt;
/**
- * The value of canflip() for the previous frame. Used so that we can tell
- * whether the buffer should be re-allocated, e.g into scanout-able
+ * The value of canflip() for the previous frame. Used so that we can
+ * tell whether the buffer should be re-allocated, e.g into scanout-able
* memory if the buffer can now be flipped.
*
* We don't want to re-allocate every frame because it is unnecessary
@@ -87,8 +106,10 @@ dri2draw(DrawablePtr pDraw, DRI2BufferPtr buf)
{
if (buf->attachment == DRI2BufferFrontLeft)
return pDraw;
- else
- return &(ARMSOCBUF(buf)->pPixmap->drawable);
+ else {
+ const unsigned curPix = ARMSOCBUF(buf)->currentPixmap;
+ return &(ARMSOCBUF(buf)->pPixmaps[curPix]->drawable);
+ }
}
static Bool
@@ -144,6 +165,7 @@ ARMSOCDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
struct ARMSOCDRI2BufferRec *buf = calloc(1, sizeof(*buf));
+ struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
PixmapPtr pPixmap = NULL;
struct armsoc_bo *bo;
int ret;
@@ -169,6 +191,23 @@ ARMSOCDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
goto fail;
}
+ if (attachment == DRI2BufferBackLeft && pARMSOC->driNumBufs > 2) {
+ buf->pPixmaps = calloc(pARMSOC->driNumBufs-1,
+ sizeof(PixmapPtr));
+ buf->numPixmaps = pARMSOC->driNumBufs-1;
+ } else {
+ buf->pPixmaps = malloc(sizeof(PixmapPtr));
+ buf->numPixmaps = 1;
+ }
+
+ if (!buf->pPixmaps) {
+ ERROR_MSG("Failed to allocate PixmapPtr array for DRI2Buffer");
+ goto fail;
+ }
+
+ buf->pPixmaps[0] = pPixmap;
+ assert(buf->currentPixmap == 0);
+
bo = ARMSOCPixmapBo(pPixmap);
if (!bo) {
ERROR_MSG(
@@ -182,7 +221,6 @@ ARMSOCDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
DRIBUF(buf)->format = format;
DRIBUF(buf)->flags = 0;
buf->refcnt = 1;
- buf->pPixmap = pPixmap;
buf->previous_canflip = -1;
ret = armsoc_bo_get_name(bo, &DRIBUF(buf)->name);
@@ -217,6 +255,7 @@ fail:
else
pPixmap->refcnt--;
}
+ free(buf->pPixmaps);
free(buf);
return NULL;
@@ -232,18 +271,28 @@ ARMSOCDRI2DestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer)
/* Note: pDraw may already be deleted, so use the pPixmap here
* instead (since it is at least refcntd)
*/
- ScreenPtr pScreen = buf->pPixmap->drawable.pScreen;
+ ScreenPtr pScreen = buf->pPixmaps[0]->drawable.pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
+ int numBuffers, i;
if (--buf->refcnt > 0)
return;
DEBUG_MSG("pDraw=%p, buffer=%p", pDraw, buffer);
- ARMSOCDeregisterExternalAccess(buf->pPixmap);
+ if (buffer->attachment == DRI2BufferBackLeft) {
+ assert(pARMSOC->driNumBufs > 1);
+ numBuffers = pARMSOC->driNumBufs-1;
+ } else
+ numBuffers = 1;
- pScreen->DestroyPixmap(buf->pPixmap);
+ for (i = 0; i < numBuffers && buf->pPixmaps[i] != NULL; i++) {
+ ARMSOCDeregisterExternalAccess(buf->pPixmaps[i]);
+ pScreen->DestroyPixmap(buf->pPixmaps[i]);
+ }
+ free(buf->pPixmaps);
free(buf);
}
@@ -356,6 +405,120 @@ static const char * const swap_names[] = {
[DRI2_FLIP_COMPLETE] = "flip,"
};
+static Bool allocNextBuffer(DrawablePtr pDraw, PixmapPtr *ppPixmap,
+ uint32_t *name) {
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ struct armsoc_bo *bo;
+ PixmapPtr pPixmap;
+ int ret;
+ uint32_t new_name;
+ Bool extRegistered = FALSE;
+
+ pPixmap = createpix(pDraw);
+
+ if (!pPixmap)
+ goto error;
+
+ bo = ARMSOCPixmapBo(pPixmap);
+ if (!bo) {
+ WARNING_MSG(
+ "Attempting to DRI2 wrap a pixmap with no DRM buffer object backing");
+ goto error;
+ }
+
+ ARMSOCRegisterExternalAccess(pPixmap);
+ extRegistered = TRUE;
+
+ ret = armsoc_bo_get_name(bo, &new_name);
+ if (ret) {
+ ERROR_MSG("Could not get buffer name: %d", ret);
+ goto error;
+ }
+
+ if (!armsoc_bo_get_fb(bo)) {
+ ret = armsoc_bo_add_fb(bo);
+ /* Should always be able to add fb, as we only add more buffers
+ * when flipping*/
+ if (ret) {
+ ERROR_MSG(
+ "Could not add framebuffer to additional back buffer");
+ goto error;
+ }
+ }
+
+ /* No errors, update pixmap and name */
+ *ppPixmap = pPixmap;
+ *name = new_name;
+
+ return TRUE;
+
+error:
+ /* revert to existing pixmap */
+ if (pPixmap) {
+ if (extRegistered)
+ ARMSOCDeregisterExternalAccess(pPixmap);
+ pScreen->DestroyPixmap(pPixmap);
+ }
+
+ return FALSE;
+}
+
+static void nextBuffer(DrawablePtr pDraw, struct ARMSOCDRI2BufferRec *backBuf)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
+
+ if (pARMSOC->driNumBufs <= 2) {
+ /*Only using double buffering, leave the pixmap as-is */
+ return;
+ }
+
+ backBuf->currentPixmap++;
+ backBuf->currentPixmap %= backBuf->numPixmaps;
+
+ if (backBuf->pPixmaps[backBuf->currentPixmap]) {
+ /* Already allocated the next buffer - get the name and
+ * early-out */
+ struct armsoc_bo *bo;
+ int ret;
+
+ bo = ARMSOCPixmapBo(backBuf->pPixmaps[backBuf->currentPixmap]);
+ assert(bo);
+ ret = armsoc_bo_get_name(bo, &DRIBUF(backBuf)->name);
+ assert(!ret);
+ } else {
+ Bool ret;
+ PixmapPtr * const curBackPix =
+ &backBuf->pPixmaps[backBuf->currentPixmap];
+ ret = allocNextBuffer(pDraw, curBackPix,
+ &DRIBUF(backBuf)->name);
+ if (!ret) {
+ /* can't have failed on the first buffer */
+ assert(backBuf->currentPixmap > 0);
+ /* Fall back to last buffer */
+ backBuf->currentPixmap--;
+ WARNING_MSG(
+ "Failed to use the requested %d-buffering due to an allocation failure.\n"
+ "Falling back to %d-buffering for this DRI2Drawable",
+ backBuf->numPixmaps+1,
+ backBuf->currentPixmap+2);
+ backBuf->numPixmaps = backBuf->currentPixmap+1;
+ }
+ }
+}
+
+static struct armsoc_bo *boFromBuffer(DRI2BufferPtr buf)
+{
+ PixmapPtr pPixmap;
+ struct ARMSOCPixmapPrivRec *priv;
+
+ pPixmap = ARMSOCBUF(buf)->pPixmaps[ARMSOCBUF(buf)->currentPixmap];
+ priv = exaGetPixmapDriverPrivate(pPixmap);
+ return priv->bo;
+}
+
void
ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd)
{
@@ -364,19 +527,14 @@ ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd)
struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
DrawablePtr pDraw = NULL;
int status;
- struct ARMSOCPixmapPrivRec *src_priv, *dst_priv;
struct armsoc_bo *old_src_bo, *old_dst_bo;
if (--cmd->swapCount > 0)
return;
/* Save the old source bo for unreference below */
- src_priv = exaGetPixmapDriverPrivate(
- ARMSOCBUF(cmd->pSrcBuffer)->pPixmap);
- dst_priv = exaGetPixmapDriverPrivate(
- ARMSOCBUF(cmd->pDstBuffer)->pPixmap);
- old_src_bo = src_priv->bo;
- old_dst_bo = dst_priv->bo;
+ old_src_bo = boFromBuffer(cmd->pSrcBuffer);
+ old_dst_bo = boFromBuffer(cmd->pDstBuffer);
if ((cmd->flags & ARMSOC_SWAP_FAIL) == 0) {
DEBUG_MSG("%s complete: %d -> %d", swap_names[cmd->type],
@@ -392,6 +550,11 @@ ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd)
assert(cmd->type == DRI2_FLIP_COMPLETE);
exchangebufs(pDraw, cmd->pSrcBuffer,
cmd->pDstBuffer);
+
+ if (cmd->pSrcBuffer->attachment ==
+ DRI2BufferBackLeft)
+ nextBuffer(pDraw,
+ ARMSOCBUF(cmd->pSrcBuffer));
}
DRI2SwapComplete(cmd->client, pDraw, 0, 0, 0, cmd->type,
@@ -399,10 +562,9 @@ ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd)
if (cmd->type != DRI2_BLIT_COMPLETE &&
(cmd->flags & ARMSOC_SWAP_FAKE_FLIP) == 0) {
- dst_priv = exaGetPixmapDriverPrivate(draw2pix(
- dri2draw(pDraw, cmd->pDstBuffer)));
assert(cmd->type == DRI2_FLIP_COMPLETE);
- set_scanout_bo(pScrn, dst_priv->bo);
+ set_scanout_bo(pScrn,
+ boFromBuffer(cmd->pDstBuffer));
}
}
}
@@ -442,8 +604,8 @@ ARMSOCDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw,
struct ARMSOCDRI2BufferRec *src = ARMSOCBUF(pSrcBuffer);
struct ARMSOCDRI2BufferRec *dst = ARMSOCBUF(pDstBuffer);
struct ARMSOCDRISwapCmd *cmd = calloc(1, sizeof(*cmd));
+ struct armsoc_bo *src_bo, *dst_bo;
int src_fb_id, dst_fb_id;
- struct ARMSOCPixmapPrivRec *src_priv, *dst_priv;
int new_canflip, ret, do_flip;
if (!cmd)
@@ -468,11 +630,11 @@ ARMSOCDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw,
ARMSOCDRI2ReferenceBuffer(pDstBuffer);
pARMSOC->pending_flips++;
- src_priv = exaGetPixmapDriverPrivate(src->pPixmap);
- dst_priv = exaGetPixmapDriverPrivate(dst->pPixmap);
+ src_bo = boFromBuffer(pSrcBuffer);
+ dst_bo = boFromBuffer(pDstBuffer);
- src_fb_id = armsoc_bo_get_fb(src_priv->bo);
- dst_fb_id = armsoc_bo_get_fb(dst_priv->bo);
+ src_fb_id = armsoc_bo_get_fb(src_bo);
+ dst_fb_id = armsoc_bo_get_fb(dst_bo);
new_canflip = canflip(pDraw);
if ((src->previous_canflip != -1 &&
@@ -496,8 +658,8 @@ ARMSOCDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw,
src->previous_canflip = new_canflip;
dst->previous_canflip = new_canflip;
- armsoc_bo_reference(src_priv->bo);
- armsoc_bo_reference(dst_priv->bo);
+ armsoc_bo_reference(src_bo);
+ armsoc_bo_reference(dst_bo);
do_flip = src_fb_id && dst_fb_id && canflip(pDraw);
@@ -509,8 +671,8 @@ ARMSOCDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw,
* Once the client calls DRI2GetBuffers again, it will receive a new back buffer of the
* same size as the new resolution, and subsequent DRI2SwapBuffers will result in a flip.
*/
- do_flip = do_flip && (armsoc_bo_width(src_priv->bo) == armsoc_bo_width(dst_priv->bo));
- do_flip = do_flip && (armsoc_bo_height(src_priv->bo) == armsoc_bo_height(dst_priv->bo));
+ do_flip = do_flip && (armsoc_bo_width(src_bo) == armsoc_bo_width(dst_bo));
+ do_flip = do_flip && (armsoc_bo_height(src_bo) == armsoc_bo_height(dst_bo));
if (do_flip) {
DEBUG_MSG("can flip: %d -> %d", src_fb_id, dst_fb_id);
diff --git a/src/armsoc_driver.c b/src/armsoc_driver.c
index 7e9f8b9..c5208ee 100644
--- a/src/armsoc_driver.c
+++ b/src/armsoc_driver.c
@@ -110,6 +110,7 @@ enum {
OPTION_CARD_NUM,
OPTION_BUSID,
OPTION_DRIVERNAME,
+ OPTION_DRI_NUM_BUF,
};
/** Supported options. */
@@ -119,6 +120,7 @@ static const OptionInfoRec ARMSOCOptions[] = {
{ OPTION_CARD_NUM, "DRICard", OPTV_INTEGER, {0}, FALSE },
{ OPTION_BUSID, "BusID", OPTV_STRING, {0}, FALSE },
{ OPTION_DRIVERNAME, "DriverName", OPTV_STRING, {0}, FALSE },
+ { OPTION_DRI_NUM_BUF, "DRI2MaxBuffers", OPTV_INTEGER, {-1}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
@@ -599,6 +601,7 @@ ARMSOCPreInit(ScrnInfoPtr pScrn, int flags)
rgb defaultMask = { 0, 0, 0 };
Gamma defaultGamma = { 0.0, 0.0, 0.0 };
int i;
+ int driNumBufs;
TRACE_ENTER();
@@ -705,6 +708,21 @@ ARMSOCPreInit(ScrnInfoPtr pScrn, int flags)
armsocDebug = xf86ReturnOptValBool(pARMSOC->pOptionInfo,
OPTION_DEBUG, FALSE);
+ if (!xf86GetOptValInteger(pARMSOC->pOptionInfo, OPTION_DRI_NUM_BUF,
+ &driNumBufs)) {
+ /* Default to double buffering */
+ driNumBufs = 2;
+ }
+
+ if (driNumBufs < 2) {
+ ERROR_MSG(
+ "Invalid option for %s: %d. Must be greater than or equal to 2",
+ xf86TokenToOptName(pARMSOC->pOptionInfo,
+ OPTION_DRI_NUM_BUF),
+ driNumBufs);
+ return FALSE;
+ }
+ pARMSOC->driNumBufs = driNumBufs;
/* Determine if user wants to disable buffer flipping: */
pARMSOC->NoFlip = xf86ReturnOptValBool(pARMSOC->pOptionInfo,
OPTION_NO_FLIP, FALSE);
diff --git a/src/armsoc_driver.h b/src/armsoc_driver.h
index 9bb6532..8835e66 100644
--- a/src/armsoc_driver.h
+++ b/src/armsoc_driver.h
@@ -118,6 +118,7 @@ struct ARMSOCRec {
/** user-configurable option: */
Bool NoFlip;
+ unsigned driNumBufs;
/** File descriptor of the connection with the DRM. */
int drmFD;