summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2014-02-07 17:17:30 -0500
committerRob Clark <robdclark@gmail.com>2014-02-16 09:01:25 -0500
commit6d7c5ad9028bf4b0721159a2b919ebede0921dd7 (patch)
treef560017a8782efb82ba11f7ab7deae12985fe5d0
parent24c400713bc0bfbbe5520d44b4ca77b7685afc58 (diff)
xa: add XA state tracker based EXA
Currently just for solid fills and blits (no composite wired up yet), but this is enough to accelerate presentation blit (and avoid stalling for GPU to complete and memcpy), which is pretty important for performance of post-sub-buffer (gnome-shell and window managers), windowed GL apps (including gpu based video rendering), etc.
-rw-r--r--configure.ac9
-rw-r--r--src/Makefile.am17
-rw-r--r--src/drmmode_display.c2
-rw-r--r--src/msm-accel.c51
-rw-r--r--src/msm-dri2.c14
-rw-r--r--src/msm-driver.c2
-rw-r--r--src/msm-exa-xa.c647
-rw-r--r--src/msm-pixmap.c79
-rw-r--r--src/msm.h17
9 files changed, 822 insertions, 16 deletions
diff --git a/configure.ac b/configure.ac
index 1d400ff..5f957b4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,11 +63,14 @@ XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
PKG_CHECK_MODULES(XORG, [libdrm libdrm_freedreno xorg-server xproto libudev $REQUIRED_MODULES])
sdkdir=$(pkg-config --variable=sdkdir xorg-server)
PKG_CHECK_MODULES(XEXT, [xextproto >= 7.0.99.1],
-HAVE_XEXTPROTO_71="yes"; AC_DEFINE(HAVE_XEXTPROTO_71, 1, [xextproto 7.1 available]),
-HAVE_XEXTPROTO_71="no")
+ HAVE_XEXTPROTO_71="yes"; AC_DEFINE(HAVE_XEXTPROTO_71, 1, [xextproto 7.1 available]),
+ HAVE_XEXTPROTO_71="no")
AM_CONDITIONAL(HAVE_XEXTPROTO_71, [ test "$HAVE_XEXTPROTO_71" = "yes" ])
-# Checks for libraries.
+PKG_CHECK_MODULES([XATRACKER], [xatracker >= 2.2.0],
+ BUILD_XA=yes; AC_DEFINE(HAVE_XA, 1, [xa state tracker available]),
+ BUILD_XA=no)
+AM_CONDITIONAL(BUILD_XA, [test "$BUILD_XA" = "yes"])
# Checks for header files.
AC_HEADER_STDC
diff --git a/src/Makefile.am b/src/Makefile.am
index c490d5f..0e69d8a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,10 +1,14 @@
-freedreno_drv_la_LIBADD =
-
-AM_CFLAGS = @XORG_CFLAGS@ -Wall -Werror -I$(top_srcdir)/system-includes/ -I$(top_builddir)/
+AM_CFLAGS = \
+ @XORG_CFLAGS@ \
+ @XATRACKER_CFLAGS@ \
+ -Wall \
+ -Werror \
+ -I$(top_srcdir)/system-includes/ \
+ -I$(top_builddir)/
freedreno_drv_la_LTLIBRARIES = freedreno_drv.la
freedreno_drv_la_LDFLAGS = -module -avoid-version
-freedreno_drv_la_LIBADD = @XORG_LIBS@
+freedreno_drv_la_LIBADD = @XORG_LIBS@ @XATRACKER_LIBS@
freedreno_drv_ladir = @moduledir@/drivers
# Additional includes needed for msm fbdev + kgsl backend:
@@ -25,5 +29,10 @@ freedreno_drv_la_SOURCES = \
msm-dri2.c \
msm-pixmap.c
+if BUILD_XA
+freedreno_drv_la_SOURCES += \
+ msm-exa-xa.c
+endif
+
EXTRA_DIST = \
msm.h
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index cd205db..aa67a3e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1015,8 +1015,8 @@ drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
*/
ppix = screen->GetScreenPixmap(screen);
if (ppix) {
- msm_set_pixmap_bo(ppix, pMsm->scanout);
screen->ModifyPixmapHeader(ppix, width, height, -1, -1, pitch, ptr);
+ msm_set_pixmap_bo(ppix, pMsm->scanout);
#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 9
pScrn->pixmapPrivate.ptr = ppix->devPrivate.ptr;
#endif
diff --git a/src/msm-accel.c b/src/msm-accel.c
index b3b40a9..7cfb630 100644
--- a/src/msm-accel.c
+++ b/src/msm-accel.c
@@ -33,6 +33,10 @@
#include "msm.h"
#include "msm-accel.h"
+#ifdef HAVE_XA
+# include <xa_tracker.h>
+#endif
+
/* matching buffer info:
len: 00001000
gpuaddr: 66142000
@@ -192,8 +196,34 @@ MSMSetupAccel(ScreenPtr pScreen)
struct fd_ringbuffer *ring;
pMsm->pipe = fd_pipe_new(pMsm->dev, FD_PIPE_2D);
+#ifdef HAVE_XA
if (!pMsm->pipe) {
- ERROR_MSG("fail, no 2D pipe..!");
+ struct fd_pipe *p;
+
+ INFO_MSG("no 2D, trying 3D/XA");
+
+ p = fd_pipe_new(pMsm->dev, FD_PIPE_3D);
+ if (!p) {
+ ERROR_MSG("no 3D pipe");
+ goto no_xa;
+ }
+
+ pMsm->xa = xa_tracker_create(pMsm->drmFD);
+ if (!pMsm->xa) {
+ ERROR_MSG("could not setup XA");
+ goto no_xa;
+ }
+
+ pMsm->pipe = p;
+
+ INFO_MSG("using 3D/XA");
+
+ goto out;
+ }
+no_xa:
+#endif
+ if (!pMsm->pipe) {
+ INFO_MSG("no 2D pipe, falling back to software!");
if (pMsm->NoKMS) {
/* fbdev mode is lame.. we need a pipe, any pipe, to get a
* bo for the scanout/fbdev buffer. So just do this instead
@@ -229,9 +259,28 @@ MSMSetupAccel(ScreenPtr pScreen)
END_RING (pMsm);
out:
+#ifdef HAVE_XA
+ if (pMsm->xa)
+ ret = MSMSetupExaXA(pScreen);
+ else
+#endif
ret = MSMSetupExa(pScreen, softexa);
if (ret) {
pMsm->dri = MSMDRI2ScreenInit(pScreen);
}
return ret;
}
+
+void
+MSMFlushAccel(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+ MSMPtr pMsm = MSMPTR(pScrn);
+ if (pMsm->xa) {
+#ifdef HAVE_XA
+ MSMFlushXA(pMsm);
+#endif
+ } else {
+ FIRE_RING(pMsm);
+ }
+}
diff --git a/src/msm-dri2.c b/src/msm-dri2.c
index d9e041e..d9f6d0e 100644
--- a/src/msm-dri2.c
+++ b/src/msm-dri2.c
@@ -304,6 +304,18 @@ MSMDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
DEBUG_MSG("pDraw=%p, pDstBuffer=%p (%p), pSrcBuffer=%p (%p)",
pDraw, pDstBuffer, pSrcDraw, pSrcBuffer, pDstDraw);
+ /* hack.. since we don't have proper fencing / kernel synchronization
+ * we can get in a scenario where we get many frames ahead of the gpu,
+ * with queued up cmd sequence like: render -> blit -> render -> blit ..
+ * This hack makes sure the previous blit has completed.
+ */
+ {
+ MSMPtr pMsm = MSMPTR(pScrn);
+ MSMDRI2BufferPtr buf = MSMBUF(pDstBuffer);
+ pMsm->pExa->PrepareAccess(buf->pPixmap, 0);
+ pMsm->pExa->FinishAccess(buf->pPixmap, 0);
+ }
+
pGC = GetScratchGC(pDstDraw->depth, pScreen);
if (!pGC) {
return;
@@ -326,6 +338,8 @@ MSMDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
0, 0, pDraw->width, pDraw->height, 0, 0);
FreeScratchGC(pGC);
+
+ MSMFlushAccel(pScreen);
}
/**
diff --git a/src/msm-driver.c b/src/msm-driver.c
index a8cdbbf..88a60bd 100644
--- a/src/msm-driver.c
+++ b/src/msm-driver.c
@@ -100,7 +100,7 @@ MSMBlockHandler (BLOCKHANDLER_ARGS_DECL)
pScreen->BlockHandler = MSMBlockHandler;
if (pScrn->vtSema)
- FIRE_RING(pMsm);
+ MSMFlushAccel(pScreen);
}
/*
diff --git a/src/msm-exa-xa.c b/src/msm-exa-xa.c
new file mode 100644
index 0000000..dadfbad
--- /dev/null
+++ b/src/msm-exa-xa.c
@@ -0,0 +1,647 @@
+/* msm-exa-xa.c
+ *
+ * Copyright © 2013 Rob Clark <robclark@freedesktop.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+#include "exa.h"
+
+#include "msm.h"
+#include "msm-accel.h"
+
+#ifdef HAVE_XA
+# include <xa_tracker.h>
+# include <xa_context.h>
+# include <xa_composite.h>
+#endif
+
+#define xFixedtoDouble(_f) (double) ((_f)/(double) xFixed1)
+
+#define MSM_LOCALS(pDraw) \
+ ScrnInfoPtr pScrn = xf86ScreenToScrn(((DrawablePtr)(pDraw))->pScreen); \
+ MSMPtr pMsm = MSMPTR(pScrn); \
+ struct exa_state *exa = pMsm->exa; (void)exa
+ ;
+
+struct exa_state {
+ struct xa_context *ctx;
+ struct xa_composite comp;
+};
+
+/**
+ * PrepareSolid() sets up the driver for doing a solid fill.
+ * @param pPixmap Destination pixmap
+ * @param alu raster operation
+ * @param planemask write mask for the fill
+ * @param fg "foreground" color for the fill
+ *
+ * This call should set up the driver for doing a series of solid fills
+ * through the Solid() call. The alu raster op is one of the GX*
+ * graphics functions listed in X.h, and typically maps to a similar
+ * single-byte "ROP" setting in all hardware. The planemask controls
+ * which bits of the destination should be affected, and will only represent
+ * the bits up to the depth of pPixmap. The fg is the pixel value of the
+ * foreground color referred to in ROP descriptions.
+ *
+ * Note that many drivers will need to store some of the data in the driver
+ * private record, for sending to the hardware with each drawing command.
+ *
+ * The PrepareSolid() call is required of all drivers, but it may fail for any
+ * reason. Failure results in a fallback to software rendering.
+ */
+static Bool
+XAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg)
+{
+ MSM_LOCALS(pPixmap);
+ struct xa_surface *dst = msm_get_pixmap_surf(pPixmap);
+ if (!dst)
+ return FALSE;
+ return xa_solid_prepare(exa->ctx, dst, fg) == XA_ERR_NONE;
+}
+
+/**
+ * Solid() performs a solid fill set up in the last PrepareSolid() call.
+ *
+ * @param pPixmap destination pixmap
+ * @param x1 left coordinate
+ * @param y1 top coordinate
+ * @param x2 right coordinate
+ * @param y2 bottom coordinate
+ *
+ * Performs the fill set up by the last PrepareSolid() call, covering the
+ * area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are
+ * in the coordinate space of the destination pixmap, so the driver will
+ * need to set up the hardware's offset and pitch for the destination
+ * coordinates according to the pixmap's offset and pitch within
+ * framebuffer. This likely means using exaGetPixmapOffset() and
+ * exaGetPixmapPitch().
+ *
+ * This call is required if PrepareSolid() ever succeeds.
+ */
+static void
+XASolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
+{
+ MSM_LOCALS(pPixmap);
+ xa_solid(exa->ctx, x1, y1, x2 - x1, y2 - y1);
+}
+
+/**
+ * DoneSolid() finishes a set of solid fills.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The DoneSolid() call is called at the end of a series of consecutive
+ * Solid() calls following a successful PrepareSolid(). This allows drivers
+ * to finish up emitting drawing commands that were buffered, or clean up
+ * state from PrepareSolid().
+ *
+ * This call is required if PrepareSolid() ever succeeds.
+ */
+static void
+XADoneSolid(PixmapPtr pPixmap)
+{
+ MSM_LOCALS(pPixmap);
+ xa_solid_done(exa->ctx);
+}
+
+/**
+ * PrepareCopy() sets up the driver for doing a copy within video
+ * memory.
+ *
+ * @param pSrcPixmap source pixmap
+ * @param pDstPixmap destination pixmap
+ * @param dx X copy direction
+ * @param dy Y copy direction
+ * @param alu raster operation
+ * @param planemask write mask for the fill
+ *
+ * This call should set up the driver for doing a series of copies from the
+ * the pSrcPixmap to the pDstPixmap. The dx flag will be positive if the
+ * hardware should do the copy from the left to the right, and dy will be
+ * positive if the copy should be done from the top to the bottom. This
+ * is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap.
+ * If your hardware can only support blits that are (left to right, top to
+ * bottom) or (right to left, bottom to top), then you should set
+ * #EXA_TWO_BITBLT_DIRECTIONS, and EXA will break down Copy operations to
+ * ones that meet those requirements. The alu raster op is one of the GX*
+ * graphics functions listed in X.h, and typically maps to a similar
+ * single-byte "ROP" setting in all hardware. The planemask controls which
+ * bits of the destination should be affected, and will only represent the
+ * bits up to the depth of pPixmap.
+ *
+ * Note that many drivers will need to store some of the data in the driver
+ * private record, for sending to the hardware with each drawing command.
+ *
+ * The PrepareCopy() call is required of all drivers, but it may fail for any
+ * reason. Failure results in a fallback to software rendering.
+ */
+static Bool
+XAPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int dx, int dy,
+ int alu, Pixel planemask)
+{
+ MSM_LOCALS(pDstPixmap);
+ struct xa_surface *src = msm_get_pixmap_surf(pSrcPixmap);
+ struct xa_surface *dst = msm_get_pixmap_surf(pDstPixmap);
+ if (!(src && dst))
+ return FALSE;
+ return xa_copy_prepare(exa->ctx, dst, src) == XA_ERR_NONE;
+}
+
+/**
+ * Copy() performs a copy set up in the last PrepareCopy call.
+ *
+ * @param pDstPixmap destination pixmap
+ * @param srcX source X coordinate
+ * @param srcY source Y coordinate
+ * @param dstX destination X coordinate
+ * @param dstY destination Y coordinate
+ * @param width width of the rectangle to be copied
+ * @param height height of the rectangle to be copied.
+ *
+ * Performs the copy set up by the last PrepareCopy() call, copying the
+ * rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source
+ * pixmap to the same-sized rectangle at (dstX, dstY) in the destination
+ * pixmap. Those rectangles may overlap in memory, if
+ * pSrcPixmap == pDstPixmap. Note that this call does not receive the
+ * pSrcPixmap as an argument -- if it's needed in this function, it should
+ * be stored in the driver private during PrepareCopy(). As with Solid(),
+ * the coordinates are in the coordinate space of each pixmap, so the driver
+ * will need to set up source and destination pitches and offsets from those
+ * pixmaps, probably using exaGetPixmapOffset() and exaGetPixmapPitch().
+ *
+ * This call is required if PrepareCopy ever succeeds.
+ */
+static void
+XACopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY,
+ int width, int height)
+{
+ MSM_LOCALS(pDstPixmap);
+ xa_copy(exa->ctx, dstX, dstY, srcX, srcY, width, height);
+}
+
+/**
+ * DoneCopy() finishes a set of copies.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The DoneCopy() call is called at the end of a series of consecutive
+ * Copy() calls following a successful PrepareCopy(). This allows drivers
+ * to finish up emitting drawing commands that were buffered, or clean up
+ * state from PrepareCopy().
+ *
+ * This call is required if PrepareCopy() ever succeeds.
+ */
+static void
+XADoneCopy(PixmapPtr pDstPixmap)
+{
+ MSM_LOCALS(pDstPixmap);
+ xa_copy_done(exa->ctx);
+}
+
+static Bool
+xa_setup_composite(struct xa_composite *comp, int op, PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture, PicturePtr pDstPicture)
+{
+ // XXX
+ return FALSE;
+}
+
+/**
+ * CheckComposite() checks to see if a composite operation could be
+ * accelerated.
+ *
+ * @param op Render operation
+ * @param pSrcPicture source Picture
+ * @param pMaskPicture mask picture
+ * @param pDstPicture destination Picture
+ *
+ * The CheckComposite() call checks if the driver could handle acceleration
+ * of op with the given source, mask, and destination pictures. This allows
+ * drivers to check source and destination formats, supported operations,
+ * transformations, and component alpha state, and send operations it can't
+ * support to software rendering early on. This avoids costly pixmap
+ * migration to the wrong places when the driver can't accelerate
+ * operations. Note that because migration hasn't happened, the driver
+ * can't know during CheckComposite() what the offsets and pitches of the
+ * pixmaps are going to be.
+ *
+ * See PrepareComposite() for more details on likely issues that drivers
+ * will have in accelerating Composite operations.
+ *
+ * The CheckComposite() call is recommended if PrepareComposite() is
+ * implemented, but is not required.
+ */
+static Bool
+XACheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
+ PicturePtr pDstPicture)
+{
+ MSM_LOCALS(pDstPicture->pDrawable);
+ return xa_setup_composite(&exa->comp, op, pSrcPicture,
+ pMaskPicture, pDstPicture) &&
+ (xa_composite_check_accelerated(&exa->comp) == XA_ERR_NONE);
+}
+
+/**
+ * PrepareComposite() sets up the driver for doing a Composite operation
+ * described in the Render extension protocol spec.
+ *
+ * @param op Render operation
+ * @param pSrcPicture source Picture
+ * @param pMaskPicture mask picture
+ * @param pDstPicture destination Picture
+ * @param pSrc source pixmap
+ * @param pMask mask pixmap
+ * @param pDst destination pixmap
+ *
+ * This call should set up the driver for doing a series of Composite
+ * operations, as described in the Render protocol spec, with the given
+ * pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and
+ * pDst are the pixmaps containing the pixel data, and should be used for
+ * setting the offset and pitch used for the coordinate spaces for each of
+ * the Pictures.
+ *
+ * Notes on interpreting Picture structures:
+ * - The Picture structures will always have a valid pDrawable.
+ * - The Picture structures will never have alphaMap set.
+ * - The mask Picture (and therefore pMask) may be NULL, in which case the
+ * operation is simply src OP dst instead of src IN mask OP dst, and
+ * mask coordinates should be ignored.
+ * - pMarkPicture may have componentAlpha set, which greatly changes
+ * the behavior of the Composite operation. componentAlpha has no effect
+ * when set on pSrcPicture or pDstPicture.
+ * Note: componentAlpha means to treat each R/G/B channel as an independent
+ * alpha value for the corresponding channel in the src.
+ * - The source and mask Pictures may have a transformation set
+ * (Picture->transform != NULL), which means that the source coordinates
+ * should be transformed by that transformation, resulting in scaling,
+ * rotation, etc. The PictureTransformPoint() call can transform
+ * coordinates for you. Transforms have no effect on Pictures when used
+ * as a destination.
+ * - The source and mask pictures may have a filter set. PictFilterNearest
+ * and PictFilterBilinear are defined in the Render protocol, but others
+ * may be encountered, and must be handled correctly (usually by
+ * PrepareComposite failing, and falling back to software). Filters have
+ * no effect on Pictures when used as a destination.
+ * - The source and mask Pictures may have repeating set, which must be
+ * respected. Many chipsets will be unable to support repeating on
+ * pixmaps that have a width or height that is not a power of two.
+ *
+ * If your hardware can't support source pictures (textures) with
+ * non-power-of-two pitches, you should set #EXA_OFFSCREEN_ALIGN_POT.
+ *
+ * Note that many drivers will need to store some of the data in the driver
+ * private record, for sending to the hardware with each drawing command.
+ *
+ * The PrepareComposite() call is not required. However, it is highly
+ * recommended for performance of antialiased font rendering and performance
+ * of cairo applications. Failure results in a fallback to software
+ * rendering.
+ */
+static Bool
+XAPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
+ PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
+{
+ MSM_LOCALS(pDst);
+ return xa_composite_prepare(exa->ctx, &exa->comp) == XA_ERR_NONE;
+}
+
+/**
+ * Composite() performs a Composite operation set up in the last
+ * PrepareComposite() call.
+ *
+ * @param pDstPixmap destination pixmap
+ * @param srcX source X coordinate
+ * @param srcY source Y coordinate
+ * @param maskX source X coordinate
+ * @param maskY source Y coordinate
+ * @param dstX destination X coordinate
+ * @param dstY destination Y coordinate
+ * @param width destination rectangle width
+ * @param height destination rectangle height
+ *
+ * Performs the Composite operation set up by the last PrepareComposite()
+ * call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height)
+ * in the destination Pixmap. Note that if a transformation was set on
+ * the source or mask Pictures, the source rectangles may not be the same
+ * size as the destination rectangles and filtering. Getting the coordinate
+ * transformation right at the subpixel level can be tricky, and rendercheck
+ * can test this for you.
+ *
+ * This call is required if PrepareComposite() ever succeeds.
+ */
+static void
+XAComposite(PixmapPtr pDstPixmap, int srcX, int srcY, int maskX, int maskY,
+ int dstX, int dstY, int width, int height)
+{
+ MSM_LOCALS(pDstPixmap);
+ xa_composite_rect(exa->ctx, srcX, srcY, maskX, maskY,
+ dstX, dstY, width, height);
+}
+
+/**
+ * DoneComposite() finishes a set of Composite operations.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The DoneComposite() call is called at the end of a series of consecutive
+ * Composite() calls following a successful PrepareComposite(). This allows
+ * drivers to finish up emitting drawing commands that were buffered, or
+ * clean up state from PrepareComposite().
+ *
+ * This call is required if PrepareComposite() ever succeeds.
+ */
+static void
+XADoneComposite(PixmapPtr pDstPixmap)
+{
+ MSM_LOCALS(pDstPixmap);
+ xa_composite_done(exa->ctx);
+}
+
+/**
+ * MarkSync() requests that the driver mark a synchronization point,
+ * returning an driver-defined integer marker which could be requested for
+ * synchronization to later in WaitMarker(). This might be used in the
+ * future to avoid waiting for full hardware stalls before accessing pixmap
+ * data with the CPU, but is not important in the current incarnation of
+ * EXA.
+ *
+ * Note that drivers should call exaMarkSync() when they have done some
+ * acceleration, rather than their own MarkSync() handler, as otherwise EXA
+ * will be unaware of the driver's acceleration and not sync to it during
+ * fallbacks.
+ *
+ * MarkSync() is optional.
+ */
+static int
+XAMarkSync(ScreenPtr pScreen)
+{
+ return 1;
+}
+
+
+/**
+ * WaitMarker() waits for all rendering before the given marker to have
+ * completed. If the driver does not implement MarkSync(), marker is
+ * meaningless, and all rendering by the hardware should be completed before
+ * WaitMarker() returns.
+ *
+ * Note that drivers should call exaWaitSync() to wait for all acceleration
+ * to finish, as otherwise EXA will be unaware of the driver having
+ * synchronized, resulting in excessive WaitMarker() calls.
+ *
+ * WaitMarker() is required of all drivers.
+ */
+static void
+XAWaitMarker(ScreenPtr pScreen, int marker)
+{
+ /* nothing to do, handled by xa_surface_map() in PrepareAccess */
+}
+
+static Bool
+XAPixmapIsOffscreen(PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ struct xa_surface *surf = msm_get_pixmap_surf(pPixmap);
+
+ if ((pScreen->GetScreenPixmap(pScreen) == pPixmap)) {
+ return TRUE;
+ }
+
+ if (!surf) {
+ /* because we are pretending to handle unaccel (1bpp, etc)
+ * pixmaps too..
+ * this is pretty lame, revisit using EXA_MIXED_PIXMAPS
+ */
+ struct msm_pixmap_priv *priv =
+ exaGetPixmapDriverPrivate(pPixmap);
+
+ if (priv && priv->ptr) {
+ return TRUE;
+ }
+ }
+
+ if (surf)
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool
+XAPrepareAccess(PixmapPtr pPixmap, int index)
+{
+ static const unsigned int usage[EXA_NUM_PREPARE_INDICES] = {
+ [EXA_PREPARE_DEST] = XA_MAP_READ | XA_MAP_WRITE,
+ [EXA_PREPARE_SRC] = XA_MAP_READ,
+ [EXA_PREPARE_MASK] = XA_MAP_READ,
+ [EXA_PREPARE_AUX_DEST] = XA_MAP_READ | XA_MAP_WRITE,
+ [EXA_PREPARE_AUX_SRC] = XA_MAP_READ,
+ [EXA_PREPARE_AUX_MASK] = XA_MAP_READ,
+ };
+ MSM_LOCALS(pPixmap);
+
+ if (pPixmap->devPrivate.ptr == NULL) {
+ struct xa_surface *surf = msm_get_pixmap_surf(pPixmap);
+ void *ptr;
+ if (surf) {
+ xa_context_flush(exa->ctx);
+ ptr = xa_surface_map(exa->ctx, surf, usage[index]);
+ } else {
+ struct msm_pixmap_priv *priv =
+ exaGetPixmapDriverPrivate(pPixmap);
+ ptr = priv ? priv->ptr : NULL;
+ }
+ pPixmap->devPrivate.ptr = ptr;
+ }
+
+ if (!pPixmap->devPrivate.ptr) {
+ ERROR_MSG("PrepareAccess failed!!");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+XAFinishAccess(PixmapPtr pPixmap, int index)
+{
+ MSM_LOCALS(pPixmap);
+ struct xa_surface *surf = msm_get_pixmap_surf(pPixmap);
+ if (surf) {
+ pPixmap->devPrivate.ptr = NULL;
+ xa_surface_unmap(surf);
+ }
+}
+
+#define EXA_ALIGN(offset, align) (((offset) + (align) - 1) - \
+ (((offset) + (align) - 1) % (align)))
+
+static void *
+XACreatePixmap2(ScreenPtr pScreen, int width, int height,
+ int depth, int usage_hint, int bpp,
+ int *new_fb_pitch)
+{
+ struct msm_pixmap_priv *priv;
+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+ MSMPtr pMsm = MSMPTR(pScrn);
+ unsigned int flags = XA_FLAG_RENDER_TARGET;
+
+ priv = calloc(1, sizeof(struct msm_pixmap_priv));
+
+ if (priv == NULL)
+ return NULL;
+
+ if (usage_hint & CREATE_PIXMAP_USAGE_DRI2)
+ flags |= XA_FLAG_SHARED;
+
+ if ((width * height) > 0) {
+ enum xa_surface_type type =
+ (bpp > 8) ? xa_type_argb : xa_type_a;
+ priv->surf = xa_surface_create(pMsm->xa,
+ width, height, depth,
+ type, xa_format_unknown, flags);
+ }
+
+ if (priv->surf) {
+ uint32_t handle, stride;
+ xa_surface_handle(priv->surf, xa_handle_type_kms,
+ &handle, &stride);
+ *new_fb_pitch = stride;
+ return priv;
+ }
+
+ *new_fb_pitch = EXA_ALIGN(width * bpp,
+ pMsm->pExa->pixmapPitchAlign * 8) / 8;
+
+ /* 1bpp pixmaps aren't handled by XA.. probably everything
+ * else should be:
+ */
+ if (depth != 1) {
+ ERROR_MSG("cannot accel pixmap: %dx%d@%d (usage: %x)",
+ width, height, depth, usage_hint);
+ }
+ priv->ptr = calloc(1, *new_fb_pitch * height);
+
+ if (priv->ptr)
+ return priv;
+
+ free(priv);
+ return NULL;
+}
+
+static void
+XADestroyPixmap(ScreenPtr pScreen, void *dpriv)
+{
+ struct msm_pixmap_priv *priv = dpriv;
+
+ if (!priv)
+ return;
+
+ if (priv->surf)
+ xa_surface_unref(priv->surf);
+
+ free(priv);
+}
+
+/**
+ * Flush pending draw cmds
+ */
+void
+MSMFlushXA(MSMPtr pMsm)
+{
+ xa_context_flush(pMsm->exa->ctx);
+}
+
+Bool
+MSMSetupExaXA(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+ MSMPtr pMsm = MSMPTR(pScrn);
+ ExaDriverPtr pExa;
+
+ /* Set up EXA */
+ xf86LoadSubModule(pScrn, "exa");
+
+ if (pMsm->pExa == NULL) {
+ pMsm->pExa = exaDriverAlloc();
+ pMsm->exa = calloc(1, sizeof(*pMsm->exa));
+ pMsm->exa->ctx = xa_context_default(pMsm->xa);
+ }
+
+ if (pMsm->pExa == NULL)
+ return FALSE;
+
+ pExa = pMsm->pExa;
+
+ /* This is the current major/minor that we support */
+
+ pExa->exa_major = 2;
+ pExa->exa_minor = 2;
+
+ /* Max blit extents that hw supports */
+ pExa->maxX = 4096;
+ pExa->maxY = 4096;
+
+ pExa->flags = EXA_OFFSCREEN_PIXMAPS |
+ EXA_HANDLES_PIXMAPS |
+ EXA_SUPPORTS_PREPARE_AUX;
+
+ /* Align pixmap offsets along page boundaries */
+ pExa->pixmapOffsetAlign = 4096;
+
+ /* Align pixmap pitches to the maximum needed aligment for the
+ GPU - this ensures that we have enough room, and we adjust the
+ pitches down to the depth later */
+
+ pExa->pixmapPitchAlign = 128;
+
+ /* The maximum acceleratable pitch is 2048 pixels */
+ pExa->maxPitchPixels = 2048;
+
+ pExa->PrepareSolid = XAPrepareSolid;
+ pExa->Solid = XASolid;
+ pExa->DoneSolid = XADoneSolid;
+ pExa->PrepareCopy = XAPrepareCopy;
+ pExa->Copy = XACopy;
+ pExa->DoneCopy = XADoneCopy;
+ pExa->CheckComposite = XACheckComposite;
+ pExa->PrepareComposite = XAPrepareComposite;
+ pExa->Composite = XAComposite;
+ pExa->DoneComposite = XADoneComposite;
+ pExa->MarkSync = XAMarkSync;
+ pExa->WaitMarker = XAWaitMarker;
+ pExa->PixmapIsOffscreen = XAPixmapIsOffscreen;
+ pExa->CreatePixmap2 = XACreatePixmap2;
+ pExa->DestroyPixmap = XADestroyPixmap;
+ pExa->PrepareAccess = XAPrepareAccess;
+ pExa->FinishAccess = XAFinishAccess;
+
+ return exaDriverInit(pScreen, pMsm->pExa);
+}
diff --git a/src/msm-pixmap.c b/src/msm-pixmap.c
index 7d20208..22fc006 100644
--- a/src/msm-pixmap.c
+++ b/src/msm-pixmap.c
@@ -33,6 +33,9 @@
#include "msm.h"
+#ifdef HAVE_XA
+# include <xa_tracker.h>
+#endif
struct fd_bo *
msm_get_pixmap_bo(PixmapPtr pix)
@@ -42,6 +45,19 @@ msm_get_pixmap_bo(PixmapPtr pix)
if (priv && priv->bo)
return priv->bo;
+#ifdef HAVE_XA
+ /* we should only hit this path for pageflip/dri2 (in which case
+ * the buffer is already exported to an flink name):
+ */
+ if (priv && priv->surf) {
+ MSMPtr pMsm = MSMPTR_FROM_PIXMAP(pix);
+ uint32_t name, stride;
+ xa_surface_handle(priv->surf, xa_handle_type_shared, &name, &stride);
+ priv->bo = fd_bo_from_name(pMsm->dev, name);
+ return priv->bo;
+ }
+#endif
+
assert(!priv);
return NULL;
@@ -57,18 +73,67 @@ msm_set_pixmap_bo(PixmapPtr pix, struct fd_bo *bo)
priv->bo = bo ? fd_bo_ref(bo) : NULL;
if (old_bo)
fd_bo_del(old_bo);
+#ifdef HAVE_XA
+ if (priv->surf) {
+ xa_surface_unref(priv->surf);
+ priv->surf = NULL;
+ }
+ if (bo) {
+ MSMPtr pMsm = MSMPTR_FROM_PIXMAP(pix);
+ if (pMsm->xa) {
+ enum xa_surface_type type;
+ uint32_t name;
+
+ type = (pix->drawable.bitsPerPixel > 8) ?
+ xa_type_argb : xa_type_a;
+
+ fd_bo_get_name(bo, &name);
+
+ priv->surf = xa_surface_from_handle(pMsm->xa,
+ pix->drawable.width, pix->drawable.height,
+ pix->drawable.depth, type, xa_format_unknown,
+ XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET | XA_FLAG_SCANOUT,
+ name, exaGetPixmapPitch(pix));
+ }
+ }
+#endif
}
}
+#ifdef HAVE_XA
+struct xa_surface *
+msm_get_pixmap_surf(PixmapPtr pix)
+{
+ struct msm_pixmap_priv *priv = exaGetPixmapDriverPrivate(pix);
+
+ if (priv && priv->surf)
+ return priv->surf;
+
+ return NULL;
+}
+#endif
+
int
-msm_get_pixmap_name(PixmapPtr pix, unsigned int *name, unsigned int *pitch)
+msm_get_pixmap_name(PixmapPtr pix, unsigned int *name, unsigned int *stride)
{
+ MSMPtr pMsm = MSMPTR_FROM_PIXMAP(pix);
int ret = -1;
- struct fd_bo *bo = msm_get_pixmap_bo(pix);
- if (bo) {
- *pitch = exaGetPixmapPitch(pix);
- ret = fd_bo_get_name(bo, name);
+
+ if (pMsm->xa) {
+#ifdef HAVE_XA
+ struct xa_surface *surf = msm_get_pixmap_surf(pix);
+ if (surf) {
+ ret = xa_surface_handle(surf, xa_handle_type_shared, name, stride);
+ }
+#endif
+ } else {
+ struct fd_bo *bo = msm_get_pixmap_bo(pix);
+ if (bo) {
+ *stride = exaGetPixmapPitch(pix);
+ ret = fd_bo_get_name(bo, name);
+ }
}
+
return ret;
}
@@ -78,4 +143,8 @@ msm_pixmap_exchange(PixmapPtr a, PixmapPtr b)
struct msm_pixmap_priv *apriv = exaGetPixmapDriverPrivate(a);
struct msm_pixmap_priv *bpriv = exaGetPixmapDriverPrivate(b);
exchange(apriv->bo, bpriv->bo);
+ exchange(apriv->ptr, bpriv->ptr);
+#ifdef HAVE_XA
+ exchange(apriv->surf, bpriv->surf);
+#endif
}
diff --git a/src/msm.h b/src/msm.h
index 1e97692..196c37a 100644
--- a/src/msm.h
+++ b/src/msm.h
@@ -38,6 +38,9 @@
#include <freedreno_drmif.h>
#include <freedreno_ringbuffer.h>
+struct xa_tracker;
+struct xa_surface;
+
#define CREATE_PIXMAP_USAGE_DRI2 0x10000000
#ifndef ARRAY_SIZE
@@ -93,16 +96,22 @@ typedef struct _MSMRec
} ring;
struct fd_pipe *pipe;
+ /* for XA state tracker EXA: */
+ struct xa_tracker *xa;
+
/* EXA state: */
struct exa_state *exa;
struct fd_bo *scanout;
+ struct xa_surface *scanout_surf;
OptionInfoPtr options;
} MSMRec, *MSMPtr;
struct msm_pixmap_priv {
- struct fd_bo *bo;
+ struct fd_bo *bo; /* for traditional 2d EXA */
+ struct xa_surface *surf; /* for XA state tracker EXA */
+ void *ptr; /* for unacceleratable pixmaps */
};
/* Macro to get the private record from the ScreenInfo structure */
@@ -115,7 +124,10 @@ struct msm_pixmap_priv {
MSMPTR_FROM_SCREEN((_x)->drawable.pScreen)
Bool MSMSetupAccel(ScreenPtr pScreen);
+void MSMFlushAccel(ScreenPtr pScreen);
Bool MSMSetupExa(ScreenPtr, Bool softexa);
+Bool MSMSetupExaXA(ScreenPtr);
+void MSMFlushXA(MSMPtr pMsm);
typedef struct _MSMDRISwapCmd MSMDRISwapCmd;
void MSMDRI2SwapComplete(MSMDRISwapCmd *cmd, uint32_t frame,
@@ -148,6 +160,9 @@ void fbmode_screen_fini(ScreenPtr pScreen);
}
struct fd_bo *msm_get_pixmap_bo(PixmapPtr);
+#ifdef HAVE_XA
+struct xa_surface *msm_get_pixmap_surf(PixmapPtr pix);
+#endif
void msm_set_pixmap_bo(PixmapPtr pix, struct fd_bo *bo);
int msm_get_pixmap_name(PixmapPtr pix, unsigned int *name, unsigned int *pitch);
void msm_pixmap_exchange(PixmapPtr a, PixmapPtr b);