summaryrefslogtreecommitdiff
path: root/src/lx_exa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lx_exa.c')
-rw-r--r--src/lx_exa.c337
1 files changed, 220 insertions, 117 deletions
diff --git a/src/lx_exa.c b/src/lx_exa.c
index e686cec..c85b322 100644
--- a/src/lx_exa.c
+++ b/src/lx_exa.c
@@ -43,6 +43,9 @@
#include "geode_blend.h"
+#define F(x) IntToxFixed(x)
+#define I(x) xFixedToInt(x)
+
static const struct exa_format_t
{
int exa;
@@ -68,6 +71,7 @@ static const struct exa_format_t
#define COMP_TYPE_MASK 0
#define COMP_TYPE_ONEPASS 1
#define COMP_TYPE_TWOPASS 3
+#define COMP_TYPE_ROTATE 5
static struct
{
@@ -86,6 +90,10 @@ static struct
unsigned int bufferOffset;
struct exa_format_t *srcFormat;
struct exa_format_t *dstFormat;
+
+ int rotate;
+ PictTransform *transform;
+
} exaScratch;
static const int SDfn[16] = {
@@ -346,8 +354,8 @@ lx_do_copy(PixmapPtr pxDst, int srcX, int srcY,
srcOffset = exaScratch.srcOffset + (exaScratch.srcPitch * srcY) +
(exaScratch.srcBpp) * srcX;
- dstOffset = exaGetPixmapOffset(pxDst) + (dstPitch * dstY) +
- (dstBpp * dstX);
+ dstOffset = exaGetPixmapOffset(pxDst) +
+ (dstPitch * dstY) + (dstBpp * dstX);
flags = 0;
@@ -462,19 +470,71 @@ lx_get_format(PicturePtr p)
return (&lx_exa_formats[i]);
}
-#if 0
- ErrorF("Couldn't match on format %x\n", format);
- ErrorF("BPP = %d, type = %d, ARGB(%d,%d,%d,%d)n",
- PICT_FORMAT_BPP(format),
- PICT_FORMAT_TYPE(format),
- PICT_FORMAT_A(format),
- PICT_FORMAT_R(format), PICT_FORMAT_G(format), PICT_FORMAT_B(format));
-#endif
-
return NULL;
}
static Bool
+lx_process_transform(PicturePtr pSrc)
+{
+ PictTransformPtr t = pSrc->transform;
+ xFixed c0 = t->matrix[0][0];
+ xFixed s0 = t->matrix[0][1];
+ xFixed s1 = t->matrix[1][0];
+ xFixed c1 = t->matrix[1][1];
+
+ /* If the transform doesn't have any rotation
+ * or scaling components, then just grab the
+ * translate coordinates */
+
+ if (t->matrix[0][0] == 0 &&
+ t->matrix[0][1] == 0 &&
+ t->matrix[1][0] == 0 && t->matrix[1][1] == 0) {
+ exaScratch.transform = pSrc->transform;
+ return TRUE;
+ }
+
+ /* Otherwise, see if this is a simple
+ * rotate transform - if it isn't, then
+ * we have to punt back to software */
+
+ if (t->matrix[2][2] != F(1))
+ return FALSE;
+
+ /* The rotate matrix looks like this:
+ * [ cos X -sin x
+ * sin X cos X ]
+ *
+ * Where X is the angle. We do a simple
+ * check first - if [0,0] != [1,1], then
+ * scaling was specified too, and we can
+ * bail, and if [0,1] != -[1,1] then this
+ * isn't scaling that we can handle.
+ */
+
+ if ((c0 != c1) || (s0 != -s1))
+ return FALSE;
+
+ /* Now, figure out what angle we want - we
+ * can only accelerate right angle rotations,
+ * so this turns into an easy set of if statements */
+
+ if (c0 == F(1) && s1 == F(0))
+ exaScratch.rotate = RR_Rotate_0;
+ else if (c0 == F(0) && s1 == F(1))
+ exaScratch.rotate = RR_Rotate_90;
+ else if (c0 == F(-1) && s1 == F(0))
+ exaScratch.rotate = RR_Rotate_180;
+ else if (c0 == F(0) && s1 == F(-1))
+ exaScratch.rotate = RR_Rotate_270;
+ else
+ return FALSE;
+
+ exaScratch.transform = pSrc->transform;
+
+ return TRUE;
+}
+
+static Bool
lx_check_composite(int op, PicturePtr pSrc, PicturePtr pMsk, PicturePtr pDst)
{
GeodeRec *pGeode = GEODEPTR_FROM_PICTURE(pDst);
@@ -503,9 +563,13 @@ lx_check_composite(int op, PicturePtr pSrc, PicturePtr pMsk, PicturePtr pDst)
return FALSE;
}
- /* We don't handle transforms */
+ /* Keep an eye out for rotation transforms - those we can
+ * do something about */
+
+ exaScratch.rotate = RR_Rotate_0;
+ exaScratch.transform = NULL;
- if (pSrc->transform)
+ if (pSrc->transform && !lx_process_transform(pSrc))
return FALSE;
/* XXX - I don't understand PICT_a8 enough - so I'm punting */
@@ -550,8 +614,18 @@ lx_prepare_composite(int op, PicturePtr pSrc, PicturePtr pMsk,
/* FIXME: See a way around this! */
- if (srcFmt->alphabits == 0 && dstFmt->alphabits != 0)
+ if (srcFmt->alphabits == 0 && dstFmt->alphabits != 0) {
+ ErrorF("EXA: no src alpha bits\n");
+ return FALSE;
+ }
+
+ /* If this is a rotate operation, then make sure the src and dst
+ * formats are the same */
+
+ if (exaScratch.rotate != RR_Rotate_0 && srcFmt != dstFmt) {
+ ErrorF("EXA: Can't rotate and convert formats at the same time\n");
return FALSE;
+ }
/* Set up the scratch buffer with the information we need */
@@ -613,6 +687,8 @@ lx_prepare_composite(int op, PicturePtr pSrc, PicturePtr pMsk,
} else {
if (usesPasses(op))
exaScratch.type = COMP_TYPE_TWOPASS;
+ else if (exaScratch.rotate != RR_Rotate_0)
+ exaScratch.type = COMP_TYPE_ROTATE;
else
exaScratch.type = COMP_TYPE_ONEPASS;
@@ -686,8 +762,6 @@ get_op_type(struct exa_format_t *src, struct exa_format_t *dst, int type)
* ifdefed out until such time that we are sure its not needed
*/
-#if 1
-
static void
lx_composite_onepass(PixmapPtr pxDst, unsigned long dstOffset,
unsigned long srcOffset, int width, int height)
@@ -716,99 +790,6 @@ lx_composite_onepass(PixmapPtr pxDst, unsigned long dstOffset,
gp_screen_to_screen_convert(dstOffset, srcOffset, width, height, 0);
}
-#else
-
-/* XXX - For now, we assume that the conversion will fit */
-
-static void
-lx_composite_onepass(PixmapPtr pxDst, unsigned long dstOffset,
- unsigned long srcOffset, int width, int height)
-{
- struct blend_ops_t *opPtr;
- int apply, type;
- int sbpp = lx_get_bpp_from_format(exaScratch.srcFormat->fmt);
-
- /* Copy the destination into the scratch buffer */
-
- gp_declare_blt(0);
-
- gp_set_bpp(sbpp);
-
- gp_set_source_format(exaScratch.dstFormat->fmt);
-
- gp_set_raster_operation(0xCC);
- gp_set_strides(exaScratch.srcPitch, exaGetPixmapPitch(pxDst));
- gp_screen_to_screen_convert(exaScratch.bufferOffset, dstOffset, width,
- height, 0);
-
- /* Do the blend */
-
- opPtr = &lx_alpha_ops[exaScratch.op * 2];
- apply = (exaScratch.srcFormat->alphabits == 0) ?
- CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
-
- gp_declare_blt(0);
- gp_set_bpp(sbpp);
-
- type =
- get_op_type(exaScratch.srcFormat, exaScrach.dstFormat, opPtr->type);
-
- gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
-
- gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch);
- gp_screen_to_screen_blt(exaScratch.bufferOffset, srcOffset,
- width, height, 0);
-
- /* And copy back */
-
- gp_declare_blt(0);
- gp_set_bpp(pxDst->drawable.bitsPerPixel);
- gp_set_source_format(exaScratch.srcFormat->fmt);
- gp_set_raster_operation(0xCC);
- gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
- gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
- width, height, 0);
-}
-
-#endif
-
-#if 0
-
-lx_composite_convert(PixmapPtr pxDst, unsigned long dstOffset,
- unsigned long srcOffset, int width, int height)
-{
- /* Step 1 - copy the destination into the scratch buffer */
-
- gp_declare_blt(0);
- gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
-
- gp_set_raster_operation(0xCC);
- gp_set_strides(exaGetPixmapPitch(pxDst), exaGetPixmapPitch(pxDst));
-
- gp_screen_to_screen_blt(exaScratch.bufferOffset, dstOffset, width, height,
- 0);
-
- /* Step 2 - Do the original blend */
-
- lx_composite_onepass(pxDst, exaScratch.bufferOffset, srcOffset, width,
- height);
-
- /* Step 3 - copy back and fixup the alpha */
- gp_declare_blt(0);
- gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
- gp_set_strides(exaGetPixmapPitch(pxDst), exaGetPixmapPitch(pxDst));
-
- /* FIXME: Does this alpha value need to be changed for the mode? */
-
- gp_set_alpha_operation(CIMGP_ALPHA_TIMES_A, CIMGP_CONSTANT_ALPHA,
- CIMGP_CHANNEL_A_SOURCE, CIMGP_APPLY_BLEND_TO_ALPHA, 1);
-
- gp_screen_to_screen_blt(dstOffset, exaScratch.bufferOffset, width, height,
- 0);
-}
-
-#endif
-
/* This function handles the multipass blend functions */
static void
@@ -878,6 +859,41 @@ lx_composite_multipass(PixmapPtr pxDst, unsigned long dstOffset,
}
static void
+lx_composite_rotate(PixmapPtr pxDst, unsigned long dstOffset,
+ unsigned int srcOffset, int width, int height)
+{
+ int degrees = 0;
+
+ gp_wait_until_idle();
+
+ gp_declare_blt(0);
+ gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
+ gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
+
+ lx_set_source_format(exaScratch.srcFormat->fmt,
+ exaScratch.dstFormat->fmt);
+
+ gp_set_raster_operation(0xCC);
+
+ /* RandR rotation is counter-clockwise, our rotation
+ * is clockwise, so adjust the numbers accordingly */
+
+ switch (exaScratch.rotate) {
+ case RR_Rotate_90:
+ degrees = 270;
+ break;
+ case RR_Rotate_180:
+ degrees = 180;
+ break;
+ case RR_Rotate_270:
+ degrees = 90;
+ break;
+ }
+
+ gp_rotate_blt(dstOffset, srcOffset, width, height, degrees);
+}
+
+static void
lx_do_composite_mask(PixmapPtr pxDst, unsigned long dstOffset,
unsigned int maskOffset, int width, int height)
{
@@ -902,29 +918,87 @@ static void
lx_do_composite(PixmapPtr pxDst, int srcX, int srcY, int maskX,
int maskY, int dstX, int dstY, int width, int height)
{
-
struct blend_ops_t *opPtr = &lx_alpha_ops[exaScratch.op * 2];
- unsigned int dstOffset, srcOffset;
+ unsigned int dstOffset, srcOffset = 0;
unsigned int opX = dstX;
unsigned int opY = dstY;
unsigned int opWidth = width;
unsigned int opHeight = height;
+ unsigned int sX = srcX;
+ unsigned int sY = srcY;
+
+ /* Transform the source coordinates */
+
+ /* srcX, srcY point to the upper right side of the bounding box
+ * in the unrotated coordinate space. Depending on the orientation,
+ * we have to translate the coordinates to point to the origin of
+ * the rectangle in the source pixmap */
+
+ if (exaScratch.transform) {
+
+ switch (exaScratch.rotate) {
+ case RR_Rotate_270:
+ /* srcX,srcY starts at the lower right side of the original rect */
+ srcX += width;
+ break;
+
+ case RR_Rotate_180:
+
+ /* srcX,srcY starts at the lower left side of the original rect */
+ srcX += width;
+ srcY += height;
+ break;
+
+ case RR_Rotate_90:
+ srcY += height;
+ break;
+ }
+
+ /* Now, transform the unrotated coordinates to the original rect in the
+ * src pixmap */
+
+ sX = (I(exaScratch.transform->matrix[0][0]) * srcX) +
+ (I(exaScratch.transform->matrix[0][1]) * srcY) +
+ (I(exaScratch.transform->matrix[0][2]) * 1);
+
+ sY = (I(exaScratch.transform->matrix[1][0]) * srcX) +
+ (I(exaScratch.transform->matrix[1][1]) * srcY) +
+ (I(exaScratch.transform->matrix[1][2]) * 1);
+ }
+
+ /* If we are rotated, flip the operational width and the height */
+
+ if (exaScratch.rotate == RR_Rotate_90
+ || exaScratch.rotate == RR_Rotate_270) {
+ opWidth = height;
+ opHeight = width;
+ }
+
+ /* Make sure the source is in bounds */
+
+ if (sX < 0) {
+ opWidth += sX;
+ sX = 0;
+ }
+ if (sY < 0) {
+ opHeight += sY;
+ sY = 0;
+ }
+
if (exaScratch.type == COMP_TYPE_MASK)
srcOffset = exaScratch.srcOffset + (maskY * exaScratch.srcPitch) +
(maskX * exaScratch.srcBpp);
else
- srcOffset = exaScratch.srcOffset + (srcY * exaScratch.srcPitch) +
- (srcX * exaScratch.srcBpp);
+ srcOffset = exaScratch.srcOffset + (sY * exaScratch.srcPitch) +
+ (sX * exaScratch.srcBpp);
- /* Adjust the width / height of the operation the size of the source */
-
- if (exaScratch.srcWidth < width)
+ if (exaScratch.srcWidth < opWidth)
opWidth = exaScratch.srcWidth;
- if (exaScratch.srcHeight < height)
+ if (exaScratch.srcHeight < opHeight)
opHeight = exaScratch.srcHeight;
while (1) {
@@ -955,6 +1029,10 @@ lx_do_composite(PixmapPtr pxDst, int srcX, int srcY, int maskX,
case COMP_TYPE_TWOPASS:
lx_composite_multipass(pxDst, dstOffset, srcOffset, opWidth,
opHeight);
+
+ case COMP_TYPE_ROTATE:
+ lx_composite_rotate(pxDst, dstOffset, srcOffset, opWidth,
+ opHeight);
break;
}
@@ -989,6 +1067,27 @@ lx_done(PixmapPtr ptr)
{
}
+#if EXA_VERSION_MINOR >= 2
+
+static Bool
+lx_exa_pixmap_is_offscreen(PixmapPtr pPixmap)
+{
+ ScrnInfoPtr pScrni = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+ void *start = (void *)(pGeode->FBBase);
+ void *end =
+ (void *)(pGeode->FBBase + pGeode->offscreenStart +
+ pGeode->offscreenSize);
+
+ if ((void *)pPixmap->devPrivate.ptr >= start &&
+ (void *)pPixmap->devPrivate.ptr < end)
+ return TRUE;
+
+ return FALSE;
+}
+
+#endif
+
Bool
LXExaInit(ScreenPtr pScreen)
{
@@ -1015,5 +1114,9 @@ LXExaInit(ScreenPtr pScreen)
pExa->Composite = lx_do_composite;
pExa->DoneComposite = lx_done;
+#if EXA_VERSION_MINOR >= 2
+ pExa->PixmapIsOffscreen = lx_exa_pixmap_is_offscreen;
+#endif
+
return exaDriverInit(pScreen, pGeode->pExa);
}