diff options
Diffstat (limited to 'src/lx_exa.c')
-rw-r--r-- | src/lx_exa.c | 337 |
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); } |