[Xf86-video-armsoc] [PATCH 2/3] Allocate framebuffer on unflippable-to-flippable transition
Daniel Drake
drake at endlessm.com
Fri Nov 14 10:31:04 PST 2014
The previous_canflip system that was in place no longer works,
because DRI2 on the X side no longer checks serial numbers,
as of xserver commit 77e51d5bbb97eb5c9d9dbff9a7c44d7e53620e68.
We need a new way to detect the situation where a framebuffer was
not created at CreateBuffer time (because the window wasn't mapped)
but then later becomes mapped and flippable.
After some experimentation I have settled on the assumption that Mali
always sends a GetBuffers request when such a transition happens,
which means we can hook into ReuseBufferNotify to be called at that time
and create the framebuffer.
This fixes a test case of running `glmark2-es2 --fullscreen` under
metacity with a modern X server. Previously it was falling back to
CopyRegion (fb never allocated), now we allocate the fb once the window
gets mapped shortly after launch.
---
src/armsoc_dri2.c | 103 +++++++++++++++++++++++++++++++++---------------------
1 file changed, 64 insertions(+), 39 deletions(-)
diff --git a/src/armsoc_dri2.c b/src/armsoc_dri2.c
index 2e8571a..e548f67 100644
--- a/src/armsoc_dri2.c
+++ b/src/armsoc_dri2.c
@@ -80,19 +80,12 @@ 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
- * memory if the buffer can now be flipped.
- *
- * We don't want to re-allocate every frame because it is unnecessary
- * overhead most of the time apart from when we switch from flipping
- * to blitting or vice versa.
- *
- * We should bump the serial number of the drawable if canflip() returns
- * something different to what is stored here, so that the DRI2 buffers
- * will get re-allocated.
- */
- int previous_canflip;
+ * We don't want to overdo attempting fb allocation for mapped
+ * scanout buffers, to behave nice under low memory conditions.
+ * Instead we use this flag to attempt the allocation just once
+ * every time the window is mapped.
+ */
+ int attempted_fb_alloc;
};
@@ -249,7 +242,6 @@ ARMSOCDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
DRIBUF(buf)->format = format;
DRIBUF(buf)->flags = 0;
buf->refcnt = 1;
- buf->previous_canflip = canflip(pDraw);
ret = armsoc_bo_get_name(bo, &DRIBUF(buf)->name);
if (ret) {
@@ -262,8 +254,13 @@ ARMSOCDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
* fall back to blitting if the display controller hardware
* cannot scan out this buffer (for example, if it doesn't
* support the format or there was insufficient scanout memory
- * at buffer creation time). */
+ * at buffer creation time).
+ *
+ * If the window is not mapped at this time, we will not hit
+ * this codepath, but ARMSOCDRI2ReuseBufferNotify will create
+ * a framebuffer if it gets mapped later on. */
int ret = armsoc_bo_add_fb(bo);
+ buf->attempted_fb_alloc = TRUE;
if (ret) {
WARNING_MSG(
"Falling back to blitting a flippable window");
@@ -296,6 +293,56 @@ fail:
return NULL;
}
+/* Called when DRI2 is handling a GetBuffers request and is going to
+ * reuse a buffer that we created earlier.
+ * Our interest in this situation is that we might have omitted creating
+ * a framebuffer for a backbuffer due to it not being flippable at creation
+ * time (e.g. because the window wasn't mapped yet).
+ * But if GetBuffers has been called because the window is now mapped,
+ * we are going to need a framebuffer so that we can page flip it later.
+ * We avoid creating a framebuffer when it is not necessary in order to save
+ * on scanout memory which is potentially scarce.
+ *
+ * Mali r4p0 is generally light on calling GetBuffers (e.g. it doesn't do it
+ * in response to an InvalidateBuffers event) but we have determined
+ * experimentally that it does always seem to call GetBuffers upon a
+ * unmapped-to-mapped transition.
+ */
+static void
+ARMSOCDRI2ReuseBufferNotify(DrawablePtr pDraw, DRI2BufferPtr buffer)
+{
+ struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(buffer);
+ struct armsoc_bo *bo;
+ Bool flippable;
+ int fb_id;
+
+ if (buffer->attachment == DRI2BufferFrontLeft)
+ return;
+
+ bo = ARMSOCPixmapBo(buf->pPixmaps[0]);
+ fb_id = armsoc_bo_get_fb(bo);
+ flippable = canflip(pDraw);
+
+ /* Detect unflippable-to-flippable transition:
+ * Window is flippable, but we haven't yet tried to allocate a
+ * framebuffer for it, and it doesn't already have a framebuffer.
+ * This can happen when CreateBuffer was called before the window
+ * was mapped, and we have now been mapped. */
+ if (flippable && !buf->attempted_fb_alloc && fb_id == 0) {
+ armsoc_bo_add_fb(bo);
+ buf->attempted_fb_alloc = TRUE;
+ }
+
+ /* Detect flippable-to-unflippable transition:
+ * Window is now unflippable, but we have a framebuffer allocated for
+ * it. Now we can free the framebuffer to save on scanout memory, and
+ * reset state in case it gets mapped again later. */
+ if (!flippable && fb_id != 0) {
+ buf->attempted_fb_alloc = FALSE;
+ armsoc_bo_rm_fb(bo);
+ }
+}
+
/**
* Destroy Buffer
*/
@@ -355,7 +402,6 @@ ARMSOCDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
DEBUG_MSG("pDraw=%p, pDstBuffer=%p (%p), pSrcBuffer=%p (%p)",
pDraw, pDstBuffer, pSrcDraw, pSrcBuffer, pDstDraw);
-
pGC = GetScratchGC(pDstDraw->depth, pScreen);
if (!pGC)
return;
@@ -716,12 +762,10 @@ ARMSOCDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw,
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
- struct ARMSOCDRI2BufferRec *src = ARMSOCBUF(pSrcBuffer);
- struct ARMSOCDRI2BufferRec *dst = ARMSOCBUF(pDstBuffer);
struct ARMSOCDRISwapCmd *cmd;
struct armsoc_bo *src_bo, *dst_bo;
int src_fb_id, dst_fb_id;
- int new_canflip, ret, do_flip;
+ int ret, do_flip;
unsigned int idx;
RegionRec region;
PixmapPtr pDstPixmap = draw2pix(dri2draw(pDraw, pDstBuffer));
@@ -773,26 +817,6 @@ ARMSOCDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw,
DEBUG_MSG("SWAP %d SCHEDULED : %d -> %d ", cmd->swap_id,
pSrcBuffer->attachment, pDstBuffer->attachment);
- new_canflip = canflip(pDraw);
- if ((src->previous_canflip != new_canflip) ||
- (dst->previous_canflip != new_canflip)) {
- /* The drawable has transitioned between being flippable and
- * non-flippable or vice versa. Bump the serial number to force
- * the DRI2 buffers to be re-allocated during the next frame so
- * that:
- * - It is able to be scanned out
- * (if drawable is now flippable), or
- * - It is not taking up possibly scarce scanout-able memory
- * (if drawable is now not flippable)
- */
-
- PixmapPtr pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw);
- pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER;
- }
-
- src->previous_canflip = new_canflip;
- dst->previous_canflip = new_canflip;
-
do_flip = src_fb_id && dst_fb_id && canflip(pDraw);
/* After a resolution change the back buffer (src) will still be
@@ -947,6 +971,7 @@ ARMSOCDRI2ScreenInit(ScreenPtr pScreen)
.AuthMagic = drmAuthMagic,
#if DRI2INFOREC_VERSION >= 6
.SwapLimitValidate = ARMSOCDRI2SwapLimitValidate,
+ .ReuseBufferNotify = ARMSOCDRI2ReuseBufferNotify,
#endif
};
int minor = 1, major = 0;
--
1.8.1.2
More information about the Xf86-video-armsoc
mailing list