xserver-multidpi/hw/kdrive/src/kaapict.c
2007-06-29 14:06:52 -04:00

720 lines
18 KiB
C

/*
* Copyright © 2001 Keith Packard
*
* Partly based on code that is Copyright © The XFree86 Project Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif
#include "kdrive.h"
#include "kaa.h"
#ifdef RENDER
#include "mipict.h"
#define KAA_DEBUG_FALLBACKS 0
#if KAA_DEBUG_FALLBACKS
static void kaaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
{
char format[20];
char size[20];
char loc;
int temp;
if (!pict) {
snprintf(string, n, "None");
return;
}
switch (pict->format)
{
case PICT_a8r8g8b8:
snprintf(format, 20, "ARGB8888");
break;
case PICT_r5g6b5:
snprintf(format, 20, "RGB565 ");
break;
case PICT_x1r5g5b5:
snprintf(format, 20, "RGB555 ");
break;
case PICT_a8:
snprintf(format, 20, "A8 ");
break;
case PICT_a1:
snprintf(format, 20, "A1 ");
break;
default:
snprintf(format, 20, "0x%x", (int)pict->format);
break;
}
loc = kaaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
pict->pDrawable->height, pict->repeat ?
" R" : "");
snprintf(string, n, "0x%lx:%c fmt %s (%s)", (long)pict, loc, format, size);
}
static void
kaaPrintCompositeFallback(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst)
{
char sop[20];
char srcdesc[40], maskdesc[40], dstdesc[40];
switch(op)
{
case PictOpSrc:
sprintf(sop, "Src");
break;
case PictOpOver:
sprintf(sop, "Over");
break;
default:
sprintf(sop, "0x%x", (int)op);
break;
}
kaaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
kaaCompositeFallbackPictDesc(pMask, maskdesc, 40);
kaaCompositeFallbackPictDesc(pDst, dstdesc, 40);
ErrorF("Composite fallback: op %s, \n"
" src %s, \n"
" mask %s, \n"
" dst %s, \n",
sop, srcdesc, maskdesc, dstdesc);
}
static void
kaaPrintTrapezoidFallback(PicturePtr pDst)
{
char dstdesc[40];
kaaCompositeFallbackPictDesc(pDst, dstdesc, 40);
ErrorF("Trapezoid fallback: dst %s, %c/%s\n",
dstdesc,
(pDst->polyMode == PolyModePrecise) ? 'p' : 'i',
(pDst->polyEdge == PolyEdgeSharp) ? "a" : "aa");
}
#endif
static Bool
kaaGetPixelFromRGBA(CARD32 *pixel,
CARD16 red,
CARD16 green,
CARD16 blue,
CARD16 alpha,
CARD32 format)
{
int rbits, bbits, gbits, abits;
int rshift, bshift, gshift, ashift;
*pixel = 0;
if (!PICT_FORMAT_COLOR(format))
return FALSE;
rbits = PICT_FORMAT_R(format);
gbits = PICT_FORMAT_G(format);
bbits = PICT_FORMAT_B(format);
abits = PICT_FORMAT_A(format);
if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
bshift = 0;
gshift = bbits;
rshift = gshift + gbits;
ashift = rshift + rbits;
} else { /* PICT_TYPE_ABGR */
rshift = 0;
gshift = rbits;
bshift = gshift + gbits;
ashift = bshift + bbits;
}
*pixel |= ( blue >> (16 - bbits)) << bshift;
*pixel |= ( red >> (16 - rbits)) << rshift;
*pixel |= (green >> (16 - gbits)) << gshift;
*pixel |= (alpha >> (16 - abits)) << ashift;
return TRUE;
}
static Bool
kaaGetRGBAFromPixel(CARD32 pixel,
CARD16 *red,
CARD16 *green,
CARD16 *blue,
CARD16 *alpha,
CARD32 format)
{
int rbits, bbits, gbits, abits;
int rshift, bshift, gshift, ashift;
if (!PICT_FORMAT_COLOR(format))
return FALSE;
rbits = PICT_FORMAT_R(format);
gbits = PICT_FORMAT_G(format);
bbits = PICT_FORMAT_B(format);
abits = PICT_FORMAT_A(format);
if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
bshift = 0;
gshift = bbits;
rshift = gshift + gbits;
ashift = rshift + rbits;
} else { /* PICT_TYPE_ABGR */
rshift = 0;
gshift = rbits;
bshift = gshift + gbits;
ashift = bshift + bbits;
}
*red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits);
while (rbits < 16) {
*red |= *red >> rbits;
rbits <<= 1;
}
*green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits);
while (gbits < 16) {
*green |= *green >> gbits;
gbits <<= 1;
}
*blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits);
while (bbits < 16) {
*blue |= *blue >> bbits;
bbits <<= 1;
}
if (abits) {
*alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits);
while (abits < 16) {
*alpha |= *alpha >> abits;
abits <<= 1;
}
} else
*alpha = 0xffff;
return TRUE;
}
static int
kaaTryDriverSolidFill(PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height)
{
KaaScreenPriv (pDst->pDrawable->pScreen);
RegionRec region;
BoxPtr pbox;
int nbox;
int dst_off_x, dst_off_y;
PixmapPtr pSrcPix, pDstPix;
CARD32 pixel;
CARD16 red, green, blue, alpha;
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
xSrc, ySrc, 0, 0, xDst, yDst,
width, height))
return 1;
if (pSrc->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseMemory ((PixmapPtr) pSrc->pDrawable);
if (pDst->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseScreen ((PixmapPtr) pDst->pDrawable);
pDstPix = kaaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
if (!pDstPix) {
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return 0;
}
if (pSrc->pDrawable->type == DRAWABLE_WINDOW)
pSrcPix = (*pSrc->pDrawable->pScreen->GetWindowPixmap)(
(WindowPtr) (pSrc->pDrawable));
else
pSrcPix = (PixmapPtr) (pSrc->pDrawable);
/* If source is offscreen, we need to sync the accelerator
* before accessing it. We'd prefer for it to be in memory.
*/
if (kaaPixmapIsOffscreen(pSrcPix)) {
kaaWaitSync(pDst->pDrawable->pScreen);
}
pixel = *(CARD32 *)(pSrcPix->devPrivate.ptr);
if (!kaaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
pSrc->format))
{
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return -1;
}
kaaGetPixelFromRGBA(&pixel, red, green, blue, alpha,
pDst->format);
if (!(*pKaaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
{
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return -1;
}
nbox = REGION_NUM_RECTS(&region);
pbox = REGION_RECTS(&region);
while (nbox--)
{
(*pKaaScr->info->Solid) (pbox->x1 + dst_off_x,
pbox->y1 + dst_off_y,
pbox->x2 + dst_off_x,
pbox->y2 + dst_off_y);
pbox++;
}
(*pKaaScr->info->DoneSolid) ();
kaaMarkSync (pDst->pDrawable->pScreen);
kaaDrawableDirty (pDst->pDrawable);
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return 1;
}
static int
kaaTryDriverBlend(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height)
{
KaaScreenPriv (pDst->pDrawable->pScreen);
RegionRec region;
BoxPtr pbox;
int nbox;
int src_off_x, src_off_y, dst_off_x, dst_off_y;
PixmapPtr pSrcPix, pDstPix;
struct _Pixmap srcScratch;
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
xSrc, ySrc, 0, 0, xDst, yDst,
width, height))
return 1;
if (pSrc->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseScreen ((PixmapPtr) pSrc->pDrawable);
if (pDst->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseScreen ((PixmapPtr) pDst->pDrawable);
pSrcPix = kaaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
pDstPix = kaaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
if (!pDstPix) {
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return 0;
}
if (!pSrcPix && pKaaScr->info->UploadToScratch) {
if ((*pKaaScr->info->UploadToScratch) ((PixmapPtr) pSrc->pDrawable,
&srcScratch))
pSrcPix = &srcScratch;
}
if (!pSrcPix) {
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return 0;
}
if (!(*pKaaScr->info->PrepareBlend) (op, pSrc, pDst, pSrcPix,
pDstPix))
{
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return -1;
}
nbox = REGION_NUM_RECTS(&region);
pbox = REGION_RECTS(&region);
xSrc -= xDst;
ySrc -= yDst;
while (nbox--)
{
(*pKaaScr->info->Blend) (pbox->x1 + xSrc + src_off_x,
pbox->y1 + ySrc + src_off_y,
pbox->x1 + dst_off_x,
pbox->y1 + dst_off_y,
pbox->x2 - pbox->x1,
pbox->y2 - pbox->y1);
pbox++;
}
(*pKaaScr->info->DoneBlend) ();
kaaMarkSync (pDst->pDrawable->pScreen);
kaaDrawableDirty (pDst->pDrawable);
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return 1;
}
static int
kaaTryDriverComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height)
{
KaaScreenPriv (pDst->pDrawable->pScreen);
RegionRec region;
BoxPtr pbox;
int nbox;
int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
struct _Pixmap scratch;
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
if (pMask) {
xMask += pMask->pDrawable->x;
yMask += pMask->pDrawable->y;
}
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst, yDst,
width, height))
return 1;
if (pKaaScr->info->CheckComposite &&
!(*pKaaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
{
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return -1;
}
if (pSrc->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseScreen ((PixmapPtr) pSrc->pDrawable);
if (pMask && pMask->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseScreen ((PixmapPtr) pMask->pDrawable);
if (pDst->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseScreen ((PixmapPtr) pDst->pDrawable);
pSrcPix = kaaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
if (pMask)
pMaskPix = kaaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
&mask_off_y);
pDstPix = kaaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
if (!pDstPix) {
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return 0;
}
if (!pSrcPix && (!pMask || pMaskPix) && pKaaScr->info->UploadToScratch) {
if (pSrc->pDrawable->type == DRAWABLE_WINDOW)
pSrcPix = (*pSrc->pDrawable->pScreen->GetWindowPixmap) (
(WindowPtr) pSrc->pDrawable);
else
pSrcPix = (PixmapPtr) pSrc->pDrawable;
if ((*pKaaScr->info->UploadToScratch) (pSrcPix, &scratch))
pSrcPix = &scratch;
} else if (pSrcPix && pMask && !pMaskPix && pKaaScr->info->UploadToScratch) {
if (pMask->pDrawable->type == DRAWABLE_WINDOW)
pMaskPix = (*pMask->pDrawable->pScreen->GetWindowPixmap) (
(WindowPtr) pMask->pDrawable);
else
pMaskPix = (PixmapPtr) pMask->pDrawable;
if ((*pKaaScr->info->UploadToScratch) (pMaskPix, &scratch))
pMaskPix = &scratch;
}
if (!pSrcPix || (pMask && !pMaskPix)) {
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return 0;
}
if (!(*pKaaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
pMaskPix, pDstPix))
{
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return -1;
}
nbox = REGION_NUM_RECTS(&region);
pbox = REGION_RECTS(&region);
xMask -= xDst;
yMask -= yDst;
xSrc -= xDst;
ySrc -= yDst;
while (nbox--)
{
(*pKaaScr->info->Composite) (pbox->x1 + xSrc + src_off_x,
pbox->y1 + ySrc + src_off_y,
pbox->x1 + xMask + mask_off_x,
pbox->y1 + yMask + mask_off_y,
pbox->x1 + dst_off_x,
pbox->y1 + dst_off_y,
pbox->x2 - pbox->x1,
pbox->y2 - pbox->y1);
pbox++;
}
(*pKaaScr->info->DoneComposite) ();
kaaMarkSync (pDst->pDrawable->pScreen);
kaaDrawableDirty (pDst->pDrawable);
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return 1;
}
void
kaaComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height)
{
KdScreenPriv (pDst->pDrawable->pScreen);
KaaScreenPriv (pDst->pDrawable->pScreen);
int ret = -1;
if (!pMask && pSrc->pDrawable)
{
if (op == PictOpSrc)
{
if (pScreenPriv->enabled && pSrc->pDrawable && pSrc->pDrawable->width == 1 &&
pSrc->pDrawable->height == 1 && pSrc->repeat)
{
ret = kaaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
width, height);
if (ret == 1)
return;
}
else if (!pSrc->repeat && !pSrc->transform &&
pSrc->format == pDst->format)
{
RegionRec region;
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst,
yDst, width, height))
return;
kaaCopyNtoN (pSrc->pDrawable, pDst->pDrawable, 0,
REGION_RECTS(&region), REGION_NUM_RECTS(&region),
xSrc - xDst, ySrc - yDst,
FALSE, FALSE, 0, 0);
return;
}
}
if (pScreenPriv->enabled && pKaaScr->info->PrepareBlend &&
!pSrc->alphaMap && !pDst->alphaMap)
{
ret = kaaTryDriverBlend(op, pSrc, pDst, xSrc, ySrc, xDst, yDst,
width, height);
if (ret == 1)
return;
}
}
if (pSrc->pDrawable && (!pMask || pMask->pDrawable) &&
pScreenPriv->enabled && pKaaScr->info->PrepareComposite &&
!pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
{
ret = kaaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
yMask, xDst, yDst, width, height);
if (ret == 1)
return;
}
if (ret != 0) {
/* failure to accelerate was not due to pixmaps being in the wrong
* locations.
*/
if (pSrc->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseMemory ((PixmapPtr) pSrc->pDrawable);
if (pMask && pMask->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseMemory ((PixmapPtr) pMask->pDrawable);
if (pDst->pDrawable->type == DRAWABLE_PIXMAP)
kaaPixmapUseMemory ((PixmapPtr) pDst->pDrawable);
}
#if KAA_DEBUG_FALLBACKS
kaaPrintCompositeFallback (op, pSrc, pMask, pDst);
#endif
KdCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc,
xMask, yMask, xDst, yDst, width, height);
}
#endif
static xFixed
miLineFixedX (xLineFixed *l, xFixed y, Bool ceil)
{
xFixed dx = l->p2.x - l->p1.x;
xFixed_32_32 ex = (xFixed_32_32) (y - l->p1.y) * dx;
xFixed dy = l->p2.y - l->p1.y;
if (ceil)
ex += (dy - 1);
return l->p1.x + (xFixed) (ex / dy);
}
/* Need to decide just how much to trim, to maintain translation independence
* when converted to floating point.
*/
#define XFIXED_TO_FLOAT(x) (((float)((x) & 0xffffff00)) / 65536.0)
/* This is just to allow us to work on the hardware side of the problem while
* waiting for cairo to get a new tesselator. We may not be able to support
* RasterizeTrapezoid at all due to the abutting edges requirement, but it might
* be technically legal if we widened the trap by some epsilon, so that alpha
* values at abutting edges were a little too big and capped at one, rather than
* a little too small and looked bad.
*/
void kaaRasterizeTrapezoid(PicturePtr pDst,
xTrapezoid *trap,
int xoff,
int yoff)
{
KdScreenPriv (pDst->pDrawable->pScreen);
KaaScreenPriv (pDst->pDrawable->pScreen);
KaaTrapezoid ktrap;
PixmapPtr pPix;
xFixed x1, x2;
if (!pScreenPriv->enabled ||
!pKaaScr->info->PrepareTrapezoids ||
pDst->pDrawable->type != DRAWABLE_PIXMAP ||
pDst->alphaMap || pDst->format != PICT_a8)
{
KdCheckRasterizeTrapezoid (pDst, trap, xoff, yoff);
#if KAA_DEBUG_FALLBACKS
kaaPrintTrapezoidFallback (pDst);
#endif
return;
}
pPix = (PixmapPtr)pDst->pDrawable;
kaaPixmapUseScreen (pPix);
if (!kaaPixmapIsOffscreen (pPix) ||
!(*pKaaScr->info->PrepareTrapezoids) (pDst, pPix))
{
#if KAA_DEBUG_FALLBACKS
kaaPrintTrapezoidFallback (pDst);
#endif
KdCheckRasterizeTrapezoid (pDst, trap, xoff, yoff);
return;
}
ktrap.ty = XFIXED_TO_FLOAT(trap->top) + yoff;
x1 = miLineFixedX (&trap->left, trap->top, FALSE);
x2 = miLineFixedX (&trap->right, trap->top, TRUE);
ktrap.tl = XFIXED_TO_FLOAT(x1) + xoff;
ktrap.tr = XFIXED_TO_FLOAT(x2) + xoff;
ktrap.by = XFIXED_TO_FLOAT(trap->bottom) + yoff;
x1 = miLineFixedX (&trap->left, trap->bottom, FALSE);
x2 = miLineFixedX (&trap->right, trap->bottom, TRUE);
ktrap.bl = XFIXED_TO_FLOAT(x1) + xoff;
ktrap.br = XFIXED_TO_FLOAT(x2) + xoff;
(*pKaaScr->info->Trapezoids) (&ktrap, 1);
(*pKaaScr->info->DoneTrapezoids) ();
}
void
kaaInitTrapOffsets(int grid_order, float *x_offsets, float *y_offsets,
float x_offset, float y_offset)
{
int i = 0;
float x, y, x_count, y_count;
x_count = (1 << (grid_order / 2)) + 1;
y_count = (1 << (grid_order / 2)) - 1;
x_offset += 1.0 / x_count / 2.0;
y_offset += 1.0 / y_count / 2.0;
for (x = 0; x < x_count; x++) {
for (y = 0; y < y_count; y++) {
x_offsets[i] = x / x_count + x_offset;
y_offsets[i] = y / y_count + y_offset;
i++;
}
}
}