07f2f0a5ae
A recent kernel with kernel modesetting support is required. Thanks to jsg@ and kettenis@ for their work.
2075 lines
52 KiB
C
2075 lines
52 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_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "uxa-priv.h"
|
|
#include "uxa-glamor.h"
|
|
#include <xorgVersion.h>
|
|
|
|
#ifdef RENDER
|
|
#include "mipict.h"
|
|
|
|
/* Note: when using glamor we can not fail through to the ordinary UXA
|
|
* code paths, as glamor keeps an internal texture which will become
|
|
* inconsistent with the original bo. (The texture is replaced whenever
|
|
* the format changes, e.g. switching between xRGB and ARGB, for which mesa
|
|
* will allocate its own bo.)
|
|
*
|
|
* Ergo it is unsafe to fall through to the original backend operations if
|
|
* glamor is enabled.
|
|
*
|
|
* XXX This has some serious implications for mixing Render, DRI, scanout...
|
|
*/
|
|
|
|
static void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string,
|
|
int n)
|
|
{
|
|
char format[20];
|
|
char size[20];
|
|
char loc;
|
|
|
|
if (!pict) {
|
|
snprintf(string, n, "None");
|
|
return;
|
|
}
|
|
|
|
if (pict->pDrawable == NULL) {
|
|
snprintf(string, n, "source-only");
|
|
return;
|
|
}
|
|
|
|
switch (pict->format) {
|
|
case PICT_a8r8g8b8:
|
|
snprintf(format, 20, "ARGB8888");
|
|
break;
|
|
case PICT_x8r8g8b8:
|
|
snprintf(format, 20, "XRGB8888");
|
|
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 = uxa_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm';
|
|
|
|
snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
|
|
pict->pDrawable->height, pict->repeat ? " R" : "");
|
|
|
|
snprintf(string, n, "%p:%c fmt %s (%s)%s",
|
|
pict->pDrawable, loc, format, size,
|
|
pict->alphaMap ? " with alpha map" :"");
|
|
}
|
|
|
|
static const char *
|
|
op_to_string(CARD8 op)
|
|
{
|
|
switch (op) {
|
|
#define C(x) case PictOp##x: return #x
|
|
C(Clear);
|
|
C(Src);
|
|
C(Dst);
|
|
C(Over);
|
|
C(OverReverse);
|
|
C(In);
|
|
C(InReverse);
|
|
C(Out);
|
|
C(OutReverse);
|
|
C(Atop);
|
|
C(AtopReverse);
|
|
C(Xor);
|
|
C(Add);
|
|
C(Saturate);
|
|
|
|
/*
|
|
* Operators only available in version 0.2
|
|
*/
|
|
#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 2
|
|
C(DisjointClear);
|
|
C(DisjointSrc);
|
|
C(DisjointDst);
|
|
C(DisjointOver);
|
|
C(DisjointOverReverse);
|
|
C(DisjointIn);
|
|
C(DisjointInReverse);
|
|
C(DisjointOut);
|
|
C(DisjointOutReverse);
|
|
C(DisjointAtop);
|
|
C(DisjointAtopReverse);
|
|
C(DisjointXor);
|
|
|
|
C(ConjointClear);
|
|
C(ConjointSrc);
|
|
C(ConjointDst);
|
|
C(ConjointOver);
|
|
C(ConjointOverReverse);
|
|
C(ConjointIn);
|
|
C(ConjointInReverse);
|
|
C(ConjointOut);
|
|
C(ConjointOutReverse);
|
|
C(ConjointAtop);
|
|
C(ConjointAtopReverse);
|
|
C(ConjointXor);
|
|
#endif
|
|
|
|
/*
|
|
* Operators only available in version 0.11
|
|
*/
|
|
#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 11
|
|
C(Multiply);
|
|
C(Screen);
|
|
C(Overlay);
|
|
C(Darken);
|
|
C(Lighten);
|
|
C(ColorDodge);
|
|
C(ColorBurn);
|
|
C(HardLight);
|
|
C(SoftLight);
|
|
C(Difference);
|
|
C(Exclusion);
|
|
C(HSLHue);
|
|
C(HSLSaturation);
|
|
C(HSLColor);
|
|
C(HSLLuminosity);
|
|
#endif
|
|
default: return "garbage";
|
|
#undef C
|
|
}
|
|
}
|
|
|
|
static void
|
|
uxa_print_composite_fallback(const char *func, CARD8 op,
|
|
PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
|
|
{
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
|
|
char srcdesc[40], maskdesc[40], dstdesc[40];
|
|
|
|
if (! uxa_screen->fallback_debug)
|
|
return;
|
|
|
|
/* Limit the noise if fallbacks are expected. */
|
|
if (uxa_screen->force_fallback)
|
|
return;
|
|
|
|
uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40);
|
|
uxa_composite_fallback_pict_desc(pMask, maskdesc, 40);
|
|
uxa_composite_fallback_pict_desc(pDst, dstdesc, 40);
|
|
|
|
ErrorF("Composite fallback at %s:\n"
|
|
" op %s, \n"
|
|
" src %s, \n"
|
|
" mask %s, \n"
|
|
" dst %s, \n",
|
|
func, op_to_string (op), srcdesc, maskdesc, dstdesc);
|
|
}
|
|
|
|
Bool uxa_op_reads_destination(CARD8 op)
|
|
{
|
|
/* FALSE (does not read destination) is the list of ops in the protocol
|
|
* document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
|
|
* That's just Clear and Src. ReduceCompositeOp() will already have
|
|
* converted con/disjoint clear/src to Clear or Src.
|
|
*/
|
|
switch (op) {
|
|
case PictOpClear:
|
|
case PictOpSrc:
|
|
return FALSE;
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
uxa_get_pixel_from_rgba(CARD32 * pixel,
|
|
CARD16 red,
|
|
CARD16 green,
|
|
CARD16 blue,
|
|
CARD16 alpha,
|
|
CARD32 format)
|
|
{
|
|
int rbits, bbits, gbits, abits;
|
|
int rshift, bshift, gshift, ashift;
|
|
|
|
rbits = PICT_FORMAT_R(format);
|
|
gbits = PICT_FORMAT_G(format);
|
|
bbits = PICT_FORMAT_B(format);
|
|
abits = PICT_FORMAT_A(format);
|
|
if (abits == 0)
|
|
abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
|
|
|
|
if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
|
|
*pixel = alpha >> (16 - abits);
|
|
return TRUE;
|
|
}
|
|
|
|
if (!PICT_FORMAT_COLOR(format))
|
|
return FALSE;
|
|
|
|
if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
|
|
bshift = 0;
|
|
gshift = bbits;
|
|
rshift = gshift + gbits;
|
|
ashift = rshift + rbits;
|
|
} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
|
|
rshift = 0;
|
|
gshift = rbits;
|
|
bshift = gshift + gbits;
|
|
ashift = bshift + bbits;
|
|
#if XORG_VERSION_CURRENT >= 10699900
|
|
} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
|
|
ashift = 0;
|
|
rshift = abits;
|
|
gshift = rshift + rbits;
|
|
bshift = gshift + gbits;
|
|
#endif
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
*pixel = 0;
|
|
*pixel |= (blue >> (16 - bbits)) << bshift;
|
|
*pixel |= (green >> (16 - gbits)) << gshift;
|
|
*pixel |= (red >> (16 - rbits)) << rshift;
|
|
*pixel |= (alpha >> (16 - abits)) << ashift;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
uxa_get_rgba_from_pixel(CARD32 pixel,
|
|
CARD16 * red,
|
|
CARD16 * green,
|
|
CARD16 * blue,
|
|
CARD16 * alpha,
|
|
CARD32 format)
|
|
{
|
|
int rbits, bbits, gbits, abits;
|
|
int rshift, bshift, gshift, ashift;
|
|
|
|
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_A) {
|
|
rshift = gshift = bshift = ashift = 0;
|
|
} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
|
|
bshift = 0;
|
|
gshift = bbits;
|
|
rshift = gshift + gbits;
|
|
ashift = rshift + rbits;
|
|
} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
|
|
rshift = 0;
|
|
gshift = rbits;
|
|
bshift = gshift + gbits;
|
|
ashift = bshift + bbits;
|
|
#if XORG_VERSION_CURRENT >= 10699900
|
|
} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
|
|
ashift = 0;
|
|
rshift = abits;
|
|
if (abits == 0)
|
|
rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
|
|
gshift = rshift + rbits;
|
|
bshift = gshift + gbits;
|
|
#endif
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
if (rbits) {
|
|
*red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
|
|
while (rbits < 16) {
|
|
*red |= *red >> rbits;
|
|
rbits <<= 1;
|
|
}
|
|
} else
|
|
*red = 0;
|
|
|
|
if (gbits) {
|
|
*green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
|
|
while (gbits < 16) {
|
|
*green |= *green >> gbits;
|
|
gbits <<= 1;
|
|
}
|
|
} else
|
|
*green = 0;
|
|
|
|
if (bbits) {
|
|
*blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
|
|
while (bbits < 16) {
|
|
*blue |= *blue >> bbits;
|
|
bbits <<= 1;
|
|
}
|
|
} else
|
|
*blue = 0;
|
|
|
|
if (abits) {
|
|
*alpha =
|
|
((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
|
|
while (abits < 16) {
|
|
*alpha |= *alpha >> abits;
|
|
abits <<= 1;
|
|
}
|
|
} else
|
|
*alpha = 0xffff;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
uxa_get_color_for_pixmap (PixmapPtr pixmap,
|
|
CARD32 src_format,
|
|
CARD32 dst_format,
|
|
CARD32 *pixel)
|
|
{
|
|
CARD16 red, green, blue, alpha;
|
|
|
|
*pixel = uxa_get_pixmap_first_pixel(pixmap);
|
|
|
|
if (src_format != dst_format) {
|
|
if (!uxa_get_rgba_from_pixel(*pixel,
|
|
&red, &green, &blue, &alpha,
|
|
src_format))
|
|
return FALSE;
|
|
|
|
if (!uxa_get_pixel_from_rgba(pixel,
|
|
red, green, blue, alpha,
|
|
dst_format))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
uxa_try_driver_solid_fill(PicturePtr pSrc,
|
|
PicturePtr pDst,
|
|
INT16 xSrc,
|
|
INT16 ySrc,
|
|
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
|
|
{
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
|
|
RegionRec region;
|
|
BoxPtr pbox;
|
|
int nbox;
|
|
int dst_off_x, dst_off_y;
|
|
PixmapPtr pSrcPix = NULL, pDstPix;
|
|
CARD32 pixel;
|
|
|
|
if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES))
|
|
return -1;
|
|
|
|
pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
|
|
if (!pDstPix)
|
|
return -1;
|
|
|
|
xDst += pDst->pDrawable->x;
|
|
yDst += pDst->pDrawable->y;
|
|
|
|
if (pSrc->pDrawable) {
|
|
pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
|
|
xSrc += pSrc->pDrawable->x;
|
|
ySrc += pSrc->pDrawable->y;
|
|
}
|
|
|
|
if (!miComputeCompositeRegion(®ion, pSrc, NULL, pDst,
|
|
xSrc, ySrc, 0, 0, xDst, yDst,
|
|
width, height))
|
|
return 1;
|
|
|
|
if (pSrcPix) {
|
|
if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) {
|
|
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
|
|
return -1;
|
|
}
|
|
} else {
|
|
SourcePict *source = pSrc->pSourcePict;
|
|
PictSolidFill *solid = &source->solidFill;
|
|
|
|
if (source == NULL || source->type != SourcePictTypeSolidFill) {
|
|
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
|
|
return -1;
|
|
}
|
|
|
|
if (pDst->format == PICT_a8r8g8b8) {
|
|
pixel = solid->color;
|
|
} else if (pDst->format == PICT_x8r8g8b8) {
|
|
pixel = solid->color | 0xff000000;
|
|
} else {
|
|
CARD16 red, green, blue, alpha;
|
|
|
|
if (!uxa_get_rgba_from_pixel(solid->color,
|
|
&red, &green, &blue, &alpha,
|
|
PICT_a8r8g8b8) ||
|
|
!uxa_get_pixel_from_rgba(&pixel,
|
|
red, green, blue, alpha,
|
|
pDst->format)) {
|
|
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(*uxa_screen->info->prepare_solid)
|
|
(pDstPix, GXcopy, FB_ALLONES, pixel)) {
|
|
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
|
|
return -1;
|
|
}
|
|
|
|
REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y);
|
|
|
|
nbox = REGION_NUM_RECTS(®ion);
|
|
pbox = REGION_RECTS(®ion);
|
|
|
|
while (nbox--) {
|
|
(*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1,
|
|
pbox->x2, pbox->y2);
|
|
pbox++;
|
|
}
|
|
|
|
(*uxa_screen->info->done_solid) (pDstPix);
|
|
|
|
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
|
|
return 1;
|
|
}
|
|
|
|
static PicturePtr
|
|
uxa_picture_for_pixman_format(ScreenPtr screen,
|
|
pixman_format_code_t format,
|
|
int width, int height)
|
|
{
|
|
PicturePtr picture;
|
|
PixmapPtr pixmap;
|
|
int error;
|
|
|
|
if (format == PIXMAN_a1)
|
|
format = PIXMAN_a8;
|
|
|
|
/* fill alpha if unset */
|
|
if (PIXMAN_FORMAT_A(format) == 0)
|
|
format = PIXMAN_a8r8g8b8;
|
|
|
|
pixmap = screen->CreatePixmap(screen, width, height,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
UXA_CREATE_PIXMAP_FOR_MAP);
|
|
if (!pixmap)
|
|
return 0;
|
|
|
|
if (!uxa_pixmap_is_offscreen(pixmap)) {
|
|
screen->DestroyPixmap(pixmap);
|
|
return 0;
|
|
}
|
|
|
|
picture = CreatePicture(0, &pixmap->drawable,
|
|
PictureMatchFormat(screen,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
format),
|
|
0, 0, serverClient, &error);
|
|
screen->DestroyPixmap(pixmap);
|
|
if (!picture)
|
|
return 0;
|
|
|
|
ValidatePicture(picture);
|
|
|
|
return picture;
|
|
}
|
|
|
|
static PicturePtr
|
|
uxa_picture_from_pixman_image(ScreenPtr screen,
|
|
pixman_image_t * image,
|
|
pixman_format_code_t format)
|
|
{
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(screen);
|
|
PicturePtr picture;
|
|
PixmapPtr pixmap;
|
|
int width, height;
|
|
|
|
width = pixman_image_get_width(image);
|
|
height = pixman_image_get_height(image);
|
|
|
|
picture = uxa_picture_for_pixman_format(screen, format,
|
|
width, height);
|
|
if (!picture)
|
|
return 0;
|
|
|
|
if (uxa_screen->info->put_image &&
|
|
((picture->pDrawable->depth << 24) | picture->format) == format &&
|
|
uxa_screen->info->put_image((PixmapPtr)picture->pDrawable,
|
|
0, 0,
|
|
width, height,
|
|
(char *)pixman_image_get_data(image),
|
|
pixman_image_get_stride(image)))
|
|
return picture;
|
|
|
|
pixmap = GetScratchPixmapHeader(screen, width, height,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
PIXMAN_FORMAT_BPP(format),
|
|
pixman_image_get_stride(image),
|
|
pixman_image_get_data(image));
|
|
if (!pixmap) {
|
|
FreePicture(picture, 0);
|
|
return 0;
|
|
}
|
|
|
|
if (((picture->pDrawable->depth << 24) | picture->format) == format) {
|
|
GCPtr gc;
|
|
|
|
gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen);
|
|
if (!gc) {
|
|
FreeScratchPixmapHeader(pixmap);
|
|
FreePicture(picture, 0);
|
|
return 0;
|
|
}
|
|
ValidateGC(picture->pDrawable, gc);
|
|
|
|
(*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable,
|
|
gc, 0, 0, width, height, 0, 0);
|
|
|
|
FreeScratchGC(gc);
|
|
} else {
|
|
PicturePtr src;
|
|
int error;
|
|
|
|
src = CreatePicture(0, &pixmap->drawable,
|
|
PictureMatchFormat(screen,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
format),
|
|
0, 0, serverClient, &error);
|
|
if (!src) {
|
|
FreeScratchPixmapHeader(pixmap);
|
|
FreePicture(picture, 0);
|
|
return 0;
|
|
}
|
|
ValidatePicture(src);
|
|
|
|
if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) {
|
|
fbComposite(PictOpSrc, src, NULL, picture,
|
|
0, 0, 0, 0, 0, 0, width, height);
|
|
uxa_picture_finish_access(picture, UXA_ACCESS_RW);
|
|
}
|
|
|
|
FreePicture(src, 0);
|
|
}
|
|
FreeScratchPixmapHeader(pixmap);
|
|
|
|
return picture;
|
|
}
|
|
|
|
static PicturePtr
|
|
uxa_create_solid(ScreenPtr screen, uint32_t color)
|
|
{
|
|
PixmapPtr pixmap;
|
|
PicturePtr picture;
|
|
XID repeat = RepeatNormal;
|
|
int error = 0;
|
|
|
|
pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32,
|
|
UXA_CREATE_PIXMAP_FOR_MAP);
|
|
if (!pixmap)
|
|
return 0;
|
|
|
|
if (!uxa_prepare_access((DrawablePtr)pixmap, UXA_ACCESS_RW)) {
|
|
(*screen->DestroyPixmap)(pixmap);
|
|
return 0;
|
|
}
|
|
*((uint32_t *)pixmap->devPrivate.ptr) = color;
|
|
uxa_finish_access((DrawablePtr)pixmap, UXA_ACCESS_RW);
|
|
|
|
picture = CreatePicture(0, &pixmap->drawable,
|
|
PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
|
|
CPRepeat, &repeat, serverClient, &error);
|
|
(*screen->DestroyPixmap)(pixmap);
|
|
|
|
return picture;
|
|
}
|
|
|
|
static PicturePtr
|
|
uxa_solid_clear(ScreenPtr screen)
|
|
{
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(screen);
|
|
PicturePtr picture;
|
|
|
|
if (!uxa_screen->solid_clear) {
|
|
uxa_screen->solid_clear = uxa_create_solid(screen, 0);
|
|
if (!uxa_screen->solid_clear)
|
|
return 0;
|
|
}
|
|
picture = uxa_screen->solid_clear;
|
|
return picture;
|
|
}
|
|
|
|
PicturePtr
|
|
uxa_acquire_solid(ScreenPtr screen, SourcePict *source)
|
|
{
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(screen);
|
|
PictSolidFill *solid = &source->solidFill;
|
|
PicturePtr picture;
|
|
int i;
|
|
|
|
if ((solid->color >> 24) == 0) {
|
|
picture = uxa_solid_clear(screen);
|
|
if (!picture)
|
|
return 0;
|
|
|
|
goto DONE;
|
|
} else if (solid->color == 0xff000000) {
|
|
if (!uxa_screen->solid_black) {
|
|
uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000);
|
|
if (!uxa_screen->solid_black)
|
|
return 0;
|
|
}
|
|
picture = uxa_screen->solid_black;
|
|
goto DONE;
|
|
} else if (solid->color == 0xffffffff) {
|
|
if (!uxa_screen->solid_white) {
|
|
uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff);
|
|
if (!uxa_screen->solid_white)
|
|
return 0;
|
|
}
|
|
picture = uxa_screen->solid_white;
|
|
goto DONE;
|
|
}
|
|
|
|
for (i = 0; i < uxa_screen->solid_cache_size; i++) {
|
|
if (uxa_screen->solid_cache[i].color == solid->color) {
|
|
picture = uxa_screen->solid_cache[i].picture;
|
|
goto DONE;
|
|
}
|
|
}
|
|
|
|
picture = uxa_create_solid(screen, solid->color);
|
|
if (!picture)
|
|
return 0;
|
|
|
|
if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) {
|
|
i = rand() % UXA_NUM_SOLID_CACHE;
|
|
FreePicture(uxa_screen->solid_cache[i].picture, 0);
|
|
} else
|
|
uxa_screen->solid_cache_size++;
|
|
|
|
uxa_screen->solid_cache[i].picture = picture;
|
|
uxa_screen->solid_cache[i].color = solid->color;
|
|
|
|
DONE:
|
|
picture->refcnt++;
|
|
return picture;
|
|
}
|
|
|
|
PicturePtr
|
|
uxa_acquire_pattern(ScreenPtr pScreen,
|
|
PicturePtr pSrc,
|
|
pixman_format_code_t format,
|
|
INT16 x, INT16 y, CARD16 width, CARD16 height)
|
|
{
|
|
PicturePtr pDst;
|
|
|
|
if (pSrc->pSourcePict) {
|
|
SourcePict *source = pSrc->pSourcePict;
|
|
if (source->type == SourcePictTypeSolidFill)
|
|
return uxa_acquire_solid (pScreen, source);
|
|
}
|
|
|
|
pDst = uxa_picture_for_pixman_format(pScreen, format, width, height);
|
|
if (!pDst)
|
|
return 0;
|
|
|
|
if (uxa_picture_prepare_access(pDst, UXA_ACCESS_RW)) {
|
|
fbComposite(PictOpSrc, pSrc, NULL, pDst,
|
|
x, y, 0, 0, 0, 0, width, height);
|
|
uxa_picture_finish_access(pDst, UXA_ACCESS_RW);
|
|
return pDst;
|
|
} else {
|
|
FreePicture(pDst, 0);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
transform_is_integer_translation(PictTransformPtr t, int *tx, int *ty)
|
|
{
|
|
if (t == NULL) {
|
|
*tx = *ty = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
if (t->matrix[0][0] != IntToxFixed(1) ||
|
|
t->matrix[0][1] != 0 ||
|
|
t->matrix[1][0] != 0 ||
|
|
t->matrix[1][1] != IntToxFixed(1) ||
|
|
t->matrix[2][0] != 0 ||
|
|
t->matrix[2][1] != 0 ||
|
|
t->matrix[2][2] != IntToxFixed(1))
|
|
return FALSE;
|
|
|
|
if (xFixedFrac(t->matrix[0][2]) != 0 ||
|
|
xFixedFrac(t->matrix[1][2]) != 0)
|
|
return FALSE;
|
|
|
|
*tx = xFixedToInt(t->matrix[0][2]);
|
|
*ty = xFixedToInt(t->matrix[1][2]);
|
|
return TRUE;
|
|
}
|
|
|
|
static PicturePtr
|
|
uxa_render_picture(ScreenPtr screen,
|
|
PicturePtr src,
|
|
pixman_format_code_t format,
|
|
INT16 x, INT16 y,
|
|
CARD16 width, CARD16 height)
|
|
{
|
|
PicturePtr picture;
|
|
int ret = 0;
|
|
|
|
/* XXX we need a mechanism for the card to choose the fallback format */
|
|
|
|
/* force alpha channel in case source does not entirely cover the extents */
|
|
if (PIXMAN_FORMAT_A(format) == 0)
|
|
format = PIXMAN_a8r8g8b8; /* available on all hardware */
|
|
|
|
picture = uxa_picture_for_pixman_format(screen, format, width, height);
|
|
if (!picture)
|
|
return 0;
|
|
|
|
if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) {
|
|
if (uxa_picture_prepare_access(src, UXA_ACCESS_RO)) {
|
|
ret = 1;
|
|
fbComposite(PictOpSrc, src, NULL, picture,
|
|
x, y, 0, 0, 0, 0, width, height);
|
|
uxa_picture_finish_access(src, UXA_ACCESS_RO);
|
|
}
|
|
uxa_picture_finish_access(picture, UXA_ACCESS_RW);
|
|
}
|
|
|
|
if (!ret) {
|
|
FreePicture(picture, 0);
|
|
return 0;
|
|
}
|
|
|
|
return picture;
|
|
}
|
|
|
|
static int
|
|
drawable_contains (DrawablePtr drawable, int x, int y, int w, int h)
|
|
{
|
|
if (x < 0 || y < 0)
|
|
return FALSE;
|
|
|
|
if (x + w > drawable->width)
|
|
return FALSE;
|
|
|
|
if (y + h > drawable->height)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PicturePtr
|
|
uxa_acquire_drawable(ScreenPtr pScreen,
|
|
PicturePtr pSrc,
|
|
INT16 x, INT16 y,
|
|
CARD16 width, CARD16 height,
|
|
INT16 * out_x, INT16 * out_y)
|
|
{
|
|
PixmapPtr pPixmap;
|
|
PicturePtr pDst;
|
|
int depth, error;
|
|
int tx, ty;
|
|
GCPtr pGC;
|
|
|
|
depth = pSrc->pDrawable->depth;
|
|
if (!transform_is_integer_translation(pSrc->transform, &tx, &ty) ||
|
|
!drawable_contains(pSrc->pDrawable, x + tx, y + ty, width, height) ||
|
|
depth == 1 ||
|
|
pSrc->filter == PictFilterConvolution) {
|
|
/* XXX extract the sample extents and do the transformation on the GPU */
|
|
pDst = uxa_render_picture(pScreen, pSrc,
|
|
pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24),
|
|
x, y, width, height);
|
|
if (!pDst)
|
|
return 0;
|
|
|
|
goto done;
|
|
} else {
|
|
if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->height) {
|
|
*out_x = x + pSrc->pDrawable->x;
|
|
*out_y = y + pSrc->pDrawable->y;
|
|
return pSrc;
|
|
}
|
|
}
|
|
|
|
pPixmap = pScreen->CreatePixmap(pScreen,
|
|
width, height, depth,
|
|
CREATE_PIXMAP_USAGE_SCRATCH);
|
|
if (!pPixmap)
|
|
return 0;
|
|
|
|
/* Skip the copy if the result remains in memory and not a bo */
|
|
if (!uxa_pixmap_is_offscreen(pPixmap)) {
|
|
pScreen->DestroyPixmap(pPixmap);
|
|
return 0;
|
|
}
|
|
|
|
pGC = GetScratchGC(depth, pScreen);
|
|
if (!pGC) {
|
|
pScreen->DestroyPixmap(pPixmap);
|
|
return 0;
|
|
}
|
|
|
|
ValidateGC(&pPixmap->drawable, pGC);
|
|
pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC,
|
|
x + tx, y + ty, width, height, 0, 0);
|
|
FreeScratchGC(pGC);
|
|
|
|
pDst = CreatePicture(0, &pPixmap->drawable,
|
|
PictureMatchFormat(pScreen, depth, pSrc->format),
|
|
0, 0, serverClient, &error);
|
|
pScreen->DestroyPixmap(pPixmap);
|
|
if (!pDst)
|
|
return 0;
|
|
|
|
ValidatePicture(pDst);
|
|
done:
|
|
pDst->componentAlpha = pSrc->componentAlpha;
|
|
*out_x = 0;
|
|
*out_y = 0;
|
|
return pDst;
|
|
}
|
|
|
|
static PicturePtr
|
|
uxa_acquire_picture(ScreenPtr screen,
|
|
PicturePtr src,
|
|
pixman_format_code_t format,
|
|
INT16 x, INT16 y,
|
|
CARD16 width, CARD16 height,
|
|
INT16 * out_x, INT16 * out_y)
|
|
{
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(screen);
|
|
|
|
if (uxa_screen->info->check_composite_texture &&
|
|
uxa_screen->info->check_composite_texture(screen, src)) {
|
|
if (src->pDrawable) {
|
|
*out_x = x + src->pDrawable->x;
|
|
*out_y = y + src->pDrawable->y;
|
|
} else {
|
|
*out_x = x;
|
|
*out_y = y;
|
|
}
|
|
return src;
|
|
}
|
|
|
|
if (src->pDrawable) {
|
|
PicturePtr dst;
|
|
|
|
dst = uxa_acquire_drawable(screen, src,
|
|
x, y, width, height,
|
|
out_x, out_y);
|
|
if (!dst)
|
|
return 0;
|
|
|
|
if (uxa_screen->info->check_composite_texture &&
|
|
!uxa_screen->info->check_composite_texture(screen, dst)) {
|
|
if (dst != src)
|
|
FreePicture(dst, 0);
|
|
return 0;
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
*out_x = 0;
|
|
*out_y = 0;
|
|
return uxa_acquire_pattern(screen, src,
|
|
format, x, y, width, height);
|
|
}
|
|
|
|
static PicturePtr
|
|
uxa_acquire_source(ScreenPtr screen,
|
|
PicturePtr pict,
|
|
INT16 x, INT16 y,
|
|
CARD16 width, CARD16 height,
|
|
INT16 * out_x, INT16 * out_y)
|
|
{
|
|
return uxa_acquire_picture (screen, pict,
|
|
PICT_a8r8g8b8,
|
|
x, y,
|
|
width, height,
|
|
out_x, out_y);
|
|
}
|
|
|
|
static PicturePtr
|
|
uxa_acquire_mask(ScreenPtr screen,
|
|
PicturePtr pict,
|
|
INT16 x, INT16 y,
|
|
INT16 width, INT16 height,
|
|
INT16 * out_x, INT16 * out_y)
|
|
{
|
|
return uxa_acquire_picture (screen, pict,
|
|
PICT_a8,
|
|
x, y,
|
|
width, height,
|
|
out_x, out_y);
|
|
}
|
|
|
|
static int
|
|
uxa_try_driver_composite(CARD8 op,
|
|
PicturePtr pSrc,
|
|
PicturePtr pMask,
|
|
PicturePtr pDst,
|
|
INT16 xSrc, INT16 ySrc,
|
|
INT16 xMask, INT16 yMask,
|
|
INT16 xDst, INT16 yDst,
|
|
CARD16 width, CARD16 height)
|
|
{
|
|
ScreenPtr screen = pDst->pDrawable->pScreen;
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(screen);
|
|
RegionRec region;
|
|
BoxPtr pbox;
|
|
int nbox;
|
|
int xDst_copy = 0, yDst_copy = 0;
|
|
int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
|
|
PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
|
|
PicturePtr localSrc, localMask = NULL;
|
|
PicturePtr localDst = pDst;
|
|
|
|
if (uxa_screen->info->check_composite &&
|
|
!(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height))
|
|
return -1;
|
|
|
|
if (uxa_screen->info->check_composite_target &&
|
|
!uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
|
|
int depth = pDst->pDrawable->depth;
|
|
PixmapPtr pixmap;
|
|
int error;
|
|
GCPtr gc;
|
|
|
|
pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
|
|
if (uxa_screen->info->check_copy &&
|
|
!uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
|
|
return -1;
|
|
|
|
pixmap = screen->CreatePixmap(screen,
|
|
width, height, depth,
|
|
CREATE_PIXMAP_USAGE_SCRATCH);
|
|
if (!pixmap)
|
|
return 0;
|
|
|
|
gc = GetScratchGC(depth, screen);
|
|
if (!gc) {
|
|
screen->DestroyPixmap(pixmap);
|
|
return 0;
|
|
}
|
|
|
|
ValidateGC(&pixmap->drawable, gc);
|
|
gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
|
|
xDst, yDst, width, height, 0, 0);
|
|
FreeScratchGC(gc);
|
|
|
|
xDst_copy = xDst; xDst = 0;
|
|
yDst_copy = yDst; yDst = 0;
|
|
|
|
localDst = CreatePicture(0, &pixmap->drawable,
|
|
PictureMatchFormat(screen, depth, pDst->format),
|
|
0, 0, serverClient, &error);
|
|
screen->DestroyPixmap(pixmap);
|
|
|
|
if (!localDst)
|
|
return 0;
|
|
|
|
ValidatePicture(localDst);
|
|
}
|
|
|
|
pDstPix =
|
|
uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y);
|
|
if (!pDstPix) {
|
|
if (localDst != pDst)
|
|
FreePicture(localDst, 0);
|
|
return -1;
|
|
}
|
|
|
|
xDst += localDst->pDrawable->x;
|
|
yDst += localDst->pDrawable->y;
|
|
|
|
localSrc = uxa_acquire_source(screen, pSrc,
|
|
xSrc, ySrc,
|
|
width, height,
|
|
&xSrc, &ySrc);
|
|
if (!localSrc) {
|
|
if (localDst != pDst)
|
|
FreePicture(localDst, 0);
|
|
return 0;
|
|
}
|
|
|
|
if (pMask) {
|
|
localMask = uxa_acquire_mask(screen, pMask,
|
|
xMask, yMask,
|
|
width, height,
|
|
&xMask, &yMask);
|
|
if (!localMask) {
|
|
if (localSrc != pSrc)
|
|
FreePicture(localSrc, 0);
|
|
if (localDst != pDst)
|
|
FreePicture(localDst, 0);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (!miComputeCompositeRegion(®ion, localSrc, localMask, localDst,
|
|
xSrc, ySrc, xMask, yMask, xDst, yDst,
|
|
width, height)) {
|
|
if (localSrc != pSrc)
|
|
FreePicture(localSrc, 0);
|
|
if (localMask && localMask != pMask)
|
|
FreePicture(localMask, 0);
|
|
if (localDst != pDst)
|
|
FreePicture(localDst, 0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable,
|
|
&src_off_x, &src_off_y);
|
|
if (!pSrcPix) {
|
|
REGION_UNINIT(screen, ®ion);
|
|
|
|
if (localSrc != pSrc)
|
|
FreePicture(localSrc, 0);
|
|
if (localMask && localMask != pMask)
|
|
FreePicture(localMask, 0);
|
|
if (localDst != pDst)
|
|
FreePicture(localDst, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (localMask) {
|
|
pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable,
|
|
&mask_off_x, &mask_off_y);
|
|
if (!pMaskPix) {
|
|
REGION_UNINIT(screen, ®ion);
|
|
|
|
if (localSrc != pSrc)
|
|
FreePicture(localSrc, 0);
|
|
if (localMask && localMask != pMask)
|
|
FreePicture(localMask, 0);
|
|
if (localDst != pDst)
|
|
FreePicture(localDst, 0);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (!(*uxa_screen->info->prepare_composite)
|
|
(op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) {
|
|
REGION_UNINIT(screen, ®ion);
|
|
|
|
if (localSrc != pSrc)
|
|
FreePicture(localSrc, 0);
|
|
if (localMask && localMask != pMask)
|
|
FreePicture(localMask, 0);
|
|
if (localDst != pDst)
|
|
FreePicture(localDst, 0);
|
|
|
|
return -1;
|
|
}
|
|
|
|
if (pMask) {
|
|
xMask = xMask + mask_off_x - xDst;
|
|
yMask = yMask + mask_off_y - yDst;
|
|
}
|
|
|
|
xSrc = xSrc + src_off_x - xDst;
|
|
ySrc = ySrc + src_off_y - yDst;
|
|
|
|
nbox = REGION_NUM_RECTS(®ion);
|
|
pbox = REGION_RECTS(®ion);
|
|
while (nbox--) {
|
|
(*uxa_screen->info->composite) (pDstPix,
|
|
pbox->x1 + xSrc,
|
|
pbox->y1 + ySrc,
|
|
pbox->x1 + xMask,
|
|
pbox->y1 + yMask,
|
|
pbox->x1 + dst_off_x,
|
|
pbox->y1 + dst_off_y,
|
|
pbox->x2 - pbox->x1,
|
|
pbox->y2 - pbox->y1);
|
|
pbox++;
|
|
}
|
|
(*uxa_screen->info->done_composite) (pDstPix);
|
|
|
|
REGION_UNINIT(screen, ®ion);
|
|
|
|
if (localSrc != pSrc)
|
|
FreePicture(localSrc, 0);
|
|
if (localMask && localMask != pMask)
|
|
FreePicture(localMask, 0);
|
|
|
|
if (localDst != pDst) {
|
|
GCPtr gc;
|
|
|
|
gc = GetScratchGC(pDst->pDrawable->depth, screen);
|
|
if (gc) {
|
|
ValidateGC(pDst->pDrawable, gc);
|
|
gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
|
|
0, 0, width, height, xDst_copy, yDst_copy);
|
|
FreeScratchGC(gc);
|
|
}
|
|
|
|
FreePicture(localDst, 0);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of
|
|
* simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
|
|
* alpha and limited 1-tmu cards.
|
|
*
|
|
* From http://anholt.livejournal.com/32058.html:
|
|
*
|
|
* The trouble is that component-alpha rendering requires two different sources
|
|
* for blending: one for the source value to the blender, which is the
|
|
* per-channel multiplication of source and mask, and one for the source alpha
|
|
* for multiplying with the destination channels, which is the multiplication
|
|
* of the source channels by the mask alpha. So the equation for Over is:
|
|
*
|
|
* dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
|
|
* dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
|
|
* dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
|
|
* dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
|
|
*
|
|
* But we can do some simpler operations, right? How about PictOpOutReverse,
|
|
* which has a source factor of 0 and dest factor of (1 - source alpha). We
|
|
* can get the source alpha value (srca.X = src.A * mask.X) out of the texture
|
|
* blenders pretty easily. So we can do a component-alpha OutReverse, which
|
|
* gets us:
|
|
*
|
|
* dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
|
|
* dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
|
|
* dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
|
|
* dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
|
|
*
|
|
* OK. And if an op doesn't use the source alpha value for the destination
|
|
* factor, then we can do the channel multiplication in the texture blenders
|
|
* to get the source value, and ignore the source alpha that we wouldn't use.
|
|
* We've supported this in the Radeon driver for a long time. An example would
|
|
* be PictOpAdd, which does:
|
|
*
|
|
* dst.A = src.A * mask.A + dst.A
|
|
* dst.R = src.R * mask.R + dst.R
|
|
* dst.G = src.G * mask.G + dst.G
|
|
* dst.B = src.B * mask.B + dst.B
|
|
*
|
|
* Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
|
|
* after it, we get:
|
|
*
|
|
* dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
|
|
* dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
|
|
* dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
|
|
* dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
|
|
*/
|
|
|
|
static int
|
|
uxa_try_magic_two_pass_composite_helper(CARD8 op,
|
|
PicturePtr pSrc,
|
|
PicturePtr pMask,
|
|
PicturePtr pDst,
|
|
INT16 xSrc, INT16 ySrc,
|
|
INT16 xMask, INT16 yMask,
|
|
INT16 xDst, INT16 yDst,
|
|
CARD16 width, CARD16 height)
|
|
{
|
|
ScreenPtr screen = pDst->pDrawable->pScreen;
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(screen);
|
|
PicturePtr localDst = pDst;
|
|
int xDst_copy, yDst_copy;
|
|
|
|
assert(op == PictOpOver);
|
|
|
|
if (uxa_screen->info->check_composite &&
|
|
(!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc,
|
|
pMask, pDst, width, height)
|
|
|| !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask,
|
|
pDst, width, height))) {
|
|
return -1;
|
|
}
|
|
|
|
if (uxa_screen->info->check_composite_target &&
|
|
!uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
|
|
int depth = pDst->pDrawable->depth;
|
|
PixmapPtr pixmap;
|
|
int error;
|
|
GCPtr gc;
|
|
|
|
pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
|
|
if (uxa_screen->info->check_copy &&
|
|
!uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
|
|
return -1;
|
|
|
|
pixmap = screen->CreatePixmap(screen,
|
|
width, height, depth,
|
|
CREATE_PIXMAP_USAGE_SCRATCH);
|
|
if (!pixmap)
|
|
return 0;
|
|
|
|
gc = GetScratchGC(depth, screen);
|
|
if (!gc) {
|
|
screen->DestroyPixmap(pixmap);
|
|
return 0;
|
|
}
|
|
|
|
ValidateGC(&pixmap->drawable, gc);
|
|
gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
|
|
xDst, yDst, width, height, 0, 0);
|
|
FreeScratchGC(gc);
|
|
|
|
xDst_copy = xDst; xDst = 0;
|
|
yDst_copy = yDst; yDst = 0;
|
|
|
|
localDst = CreatePicture(0, &pixmap->drawable,
|
|
PictureMatchFormat(screen, depth, pDst->format),
|
|
0, 0, serverClient, &error);
|
|
screen->DestroyPixmap(pixmap);
|
|
|
|
if (!localDst)
|
|
return 0;
|
|
|
|
ValidatePicture(localDst);
|
|
}
|
|
|
|
/* Now, we think we should be able to accelerate this operation. First,
|
|
* composite the destination to be the destination times the source alpha
|
|
* factors.
|
|
*/
|
|
uxa_composite(PictOpOutReverse, pSrc, pMask, localDst,
|
|
xSrc, ySrc,
|
|
xMask, yMask,
|
|
xDst, yDst,
|
|
width, height);
|
|
|
|
/* Then, add in the source value times the destination alpha factors (1.0).
|
|
*/
|
|
uxa_composite(PictOpAdd, pSrc, pMask, localDst,
|
|
xSrc, ySrc,
|
|
xMask, yMask,
|
|
xDst, yDst,
|
|
width, height);
|
|
|
|
if (localDst != pDst) {
|
|
GCPtr gc;
|
|
|
|
gc = GetScratchGC(pDst->pDrawable->depth, screen);
|
|
if (gc) {
|
|
ValidateGC(pDst->pDrawable, gc);
|
|
gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
|
|
0, 0, width, height, xDst_copy, yDst_copy);
|
|
FreeScratchGC(gc);
|
|
}
|
|
|
|
FreePicture(localDst, 0);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
compatible_formats (CARD8 op, PicturePtr dst, PicturePtr src)
|
|
{
|
|
if (op == PictOpSrc) {
|
|
if (src->format == dst->format)
|
|
return 1;
|
|
|
|
/* Is the destination an alpha-less version of source? */
|
|
if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format),
|
|
PICT_FORMAT_TYPE(src->format),
|
|
0,
|
|
PICT_FORMAT_R(src->format),
|
|
PICT_FORMAT_G(src->format),
|
|
PICT_FORMAT_B(src->format)))
|
|
return 1;
|
|
|
|
/* XXX xrgb is promoted to argb during image upload... */
|
|
#if 0
|
|
if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8)
|
|
return 1;
|
|
#endif
|
|
} else if (op == PictOpOver) {
|
|
if (PICT_FORMAT_A(src->format))
|
|
return 0;
|
|
|
|
return src->format == dst->format;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
uxa_composite(CARD8 op,
|
|
PicturePtr pSrc,
|
|
PicturePtr pMask,
|
|
PicturePtr pDst,
|
|
INT16 xSrc, INT16 ySrc,
|
|
INT16 xMask, INT16 yMask,
|
|
INT16 xDst, INT16 yDst,
|
|
CARD16 width, CARD16 height)
|
|
{
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
|
|
int ret = -1;
|
|
Bool saveSrcRepeat = pSrc->repeat;
|
|
Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
|
|
RegionRec region;
|
|
int tx, ty;
|
|
|
|
if (uxa_screen->info->flags & UXA_USE_GLAMOR) {
|
|
int ok;
|
|
|
|
uxa_picture_prepare_access(pDst, UXA_GLAMOR_ACCESS_RW);
|
|
uxa_picture_prepare_access(pSrc, UXA_GLAMOR_ACCESS_RO);
|
|
if (pMask)
|
|
uxa_picture_prepare_access(pMask, UXA_GLAMOR_ACCESS_RO);
|
|
|
|
ok = glamor_composite_nf(op,
|
|
pSrc, pMask, pDst, xSrc, ySrc,
|
|
xMask, yMask, xDst, yDst,
|
|
width, height);
|
|
|
|
if (pMask)
|
|
uxa_picture_finish_access(pMask, UXA_GLAMOR_ACCESS_RO);
|
|
uxa_picture_finish_access(pSrc, UXA_GLAMOR_ACCESS_RO);
|
|
uxa_picture_finish_access(pDst, UXA_GLAMOR_ACCESS_RW);
|
|
|
|
if (!ok)
|
|
goto fallback;
|
|
|
|
return;
|
|
}
|
|
|
|
if (uxa_screen->force_fallback)
|
|
goto fallback;
|
|
|
|
if (!uxa_drawable_is_offscreen(pDst->pDrawable))
|
|
goto fallback;
|
|
|
|
if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap))
|
|
goto fallback;
|
|
|
|
/* Remove repeat in source if useless */
|
|
if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution &&
|
|
transform_is_integer_translation(pSrc->transform, &tx, &ty) &&
|
|
(pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) &&
|
|
drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height))
|
|
pSrc->repeat = 0;
|
|
|
|
if (!pMask) {
|
|
if (op == PictOpClear) {
|
|
PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen);
|
|
if (clear &&
|
|
uxa_try_driver_solid_fill(clear, pDst,
|
|
xSrc, ySrc,
|
|
xDst, yDst,
|
|
width, height) == 1)
|
|
goto done;
|
|
}
|
|
|
|
if (pSrc->pDrawable == NULL) {
|
|
if (pSrc->pSourcePict) {
|
|
SourcePict *source = pSrc->pSourcePict;
|
|
if (source->type == SourcePictTypeSolidFill) {
|
|
if (op == PictOpSrc ||
|
|
(op == PictOpOver &&
|
|
(source->solidFill.color & 0xff000000) == 0xff000000)) {
|
|
ret = uxa_try_driver_solid_fill(pSrc, pDst,
|
|
xSrc, ySrc,
|
|
xDst, yDst,
|
|
width, height);
|
|
if (ret == 1)
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
} else if (pSrc->pDrawable->width == 1 &&
|
|
pSrc->pDrawable->height == 1 &&
|
|
pSrc->repeat &&
|
|
(op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) {
|
|
ret = uxa_try_driver_solid_fill(pSrc, pDst,
|
|
xSrc, ySrc,
|
|
xDst, yDst,
|
|
width, height);
|
|
if (ret == 1)
|
|
goto done;
|
|
} else if (compatible_formats (op, pDst, pSrc) &&
|
|
pSrc->filter != PictFilterConvolution &&
|
|
transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
|
|
if (!pSrc->repeat &&
|
|
drawable_contains(pSrc->pDrawable,
|
|
xSrc + tx, ySrc + ty,
|
|
width, height)) {
|
|
xDst += pDst->pDrawable->x;
|
|
yDst += pDst->pDrawable->y;
|
|
xSrc += pSrc->pDrawable->x + tx;
|
|
ySrc += pSrc->pDrawable->y + ty;
|
|
|
|
if (!miComputeCompositeRegion
|
|
(®ion, pSrc, pMask, pDst, xSrc, ySrc,
|
|
xMask, yMask, xDst, yDst, width, height))
|
|
goto done;
|
|
|
|
uxa_copy_n_to_n(pSrc->pDrawable,
|
|
pDst->pDrawable, NULL,
|
|
REGION_RECTS(®ion),
|
|
REGION_NUM_RECTS(®ion),
|
|
xSrc - xDst, ySrc - yDst, FALSE,
|
|
FALSE, 0, NULL);
|
|
REGION_UNINIT(pDst->pDrawable->pScreen,
|
|
®ion);
|
|
goto done;
|
|
} else if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
|
|
pSrc->pDrawable->type == DRAWABLE_PIXMAP) {
|
|
DDXPointRec patOrg;
|
|
|
|
/* Let's see if the driver can do the repeat
|
|
* in one go
|
|
*/
|
|
if (uxa_screen->info->prepare_composite) {
|
|
ret = uxa_try_driver_composite(op, pSrc,
|
|
pMask, pDst,
|
|
xSrc, ySrc,
|
|
xMask, yMask,
|
|
xDst, yDst,
|
|
width, height);
|
|
if (ret == 1)
|
|
goto done;
|
|
}
|
|
|
|
/* Now see if we can use
|
|
* uxa_fill_region_tiled()
|
|
*/
|
|
xDst += pDst->pDrawable->x;
|
|
yDst += pDst->pDrawable->y;
|
|
xSrc += pSrc->pDrawable->x + tx;
|
|
ySrc += pSrc->pDrawable->y + ty;
|
|
|
|
if (!miComputeCompositeRegion
|
|
(®ion, pSrc, pMask, pDst, xSrc, ySrc,
|
|
xMask, yMask, xDst, yDst, width, height))
|
|
goto done;
|
|
|
|
/* pattern origin is the point in the
|
|
* destination drawable
|
|
* corresponding to (0,0) in the source */
|
|
patOrg.x = xDst - xSrc;
|
|
patOrg.y = yDst - ySrc;
|
|
|
|
ret = uxa_fill_region_tiled(pDst->pDrawable,
|
|
®ion,
|
|
(PixmapPtr) pSrc->
|
|
pDrawable, &patOrg,
|
|
FB_ALLONES, GXcopy);
|
|
|
|
REGION_UNINIT(pDst->pDrawable->pScreen,
|
|
®ion);
|
|
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Remove repeat in mask if useless */
|
|
if (pMask && pMask->pDrawable && pMask->repeat &&
|
|
pMask->filter != PictFilterConvolution &&
|
|
transform_is_integer_translation(pMask->transform, &tx, &ty) &&
|
|
(pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) &&
|
|
drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height))
|
|
pMask->repeat = 0;
|
|
|
|
if (uxa_screen->info->prepare_composite) {
|
|
Bool isSrcSolid;
|
|
|
|
ret =
|
|
uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
|
|
xMask, yMask, xDst, yDst, width,
|
|
height);
|
|
if (ret == 1)
|
|
goto done;
|
|
|
|
/* For generic masks and solid src pictures, mach64 can do
|
|
* Over in two passes, similar to the component-alpha case.
|
|
*/
|
|
|
|
isSrcSolid =
|
|
pSrc->pDrawable ?
|
|
pSrc->pDrawable->width == 1 &&
|
|
pSrc->pDrawable->height == 1 &&
|
|
pSrc->repeat :
|
|
pSrc->pSourcePict ?
|
|
pSrc->pSourcePict->type == SourcePictTypeSolidFill :
|
|
0;
|
|
|
|
/* If we couldn't do the Composite in a single pass, and it
|
|
* was a component-alpha Over, see if we can do it in two
|
|
* passes with an OutReverse and then an Add.
|
|
*/
|
|
if (ret == -1 && op == PictOpOver && pMask &&
|
|
(pMask->componentAlpha || isSrcSolid)) {
|
|
ret =
|
|
uxa_try_magic_two_pass_composite_helper(op, pSrc,
|
|
pMask, pDst,
|
|
xSrc, ySrc,
|
|
xMask, yMask,
|
|
xDst, yDst,
|
|
width, height);
|
|
if (ret == 1)
|
|
goto done;
|
|
}
|
|
|
|
}
|
|
|
|
fallback:
|
|
uxa_print_composite_fallback("uxa_composite",
|
|
op, pSrc, pMask, pDst);
|
|
|
|
uxa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
|
|
xMask, yMask, xDst, yDst, width, height);
|
|
|
|
done:
|
|
pSrc->repeat = saveSrcRepeat;
|
|
if (pMask)
|
|
pMask->repeat = saveMaskRepeat;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead
|
|
* of PolyFillRect to initialize the pixmap after creating it, to prevent
|
|
* the pixmap from being migrated.
|
|
*
|
|
* See the comments about uxa_trapezoids and uxa_triangles.
|
|
*/
|
|
static PicturePtr
|
|
uxa_create_alpha_picture(ScreenPtr pScreen,
|
|
PicturePtr pDst,
|
|
PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
|
|
{
|
|
PixmapPtr pPixmap;
|
|
PicturePtr pPicture;
|
|
int error;
|
|
|
|
if (width > 32767 || height > 32767)
|
|
return 0;
|
|
|
|
if (!pPictFormat) {
|
|
if (pDst->polyEdge == PolyEdgeSharp)
|
|
pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
|
|
else
|
|
pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
|
|
if (!pPictFormat)
|
|
return 0;
|
|
}
|
|
|
|
pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
|
|
pPictFormat->depth,
|
|
UXA_CREATE_PIXMAP_FOR_MAP);
|
|
if (!pPixmap)
|
|
return 0;
|
|
pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
|
|
0, 0, serverClient, &error);
|
|
(*pScreen->DestroyPixmap) (pPixmap);
|
|
return pPicture;
|
|
}
|
|
|
|
static void
|
|
uxa_check_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
|
|
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
|
int ntrap, xTrapezoid * traps)
|
|
{
|
|
ScreenPtr screen = dst->pDrawable->pScreen;
|
|
|
|
if (maskFormat) {
|
|
PixmapPtr scratch = NULL;
|
|
PicturePtr mask;
|
|
INT16 xDst, yDst;
|
|
INT16 xRel, yRel;
|
|
BoxRec bounds;
|
|
int width, height;
|
|
pixman_image_t *image;
|
|
pixman_format_code_t format;
|
|
int error;
|
|
|
|
xDst = traps[0].left.p1.x >> 16;
|
|
yDst = traps[0].left.p1.y >> 16;
|
|
|
|
miTrapezoidBounds (ntrap, traps, &bounds);
|
|
if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
|
|
return;
|
|
|
|
width = bounds.x2 - bounds.x1;
|
|
height = bounds.y2 - bounds.y1;
|
|
|
|
format = maskFormat->format |
|
|
(BitsPerPixel(maskFormat->depth) << 24);
|
|
image =
|
|
pixman_image_create_bits(format, width, height, NULL, 0);
|
|
if (!image)
|
|
return;
|
|
|
|
for (; ntrap; ntrap--, traps++)
|
|
pixman_rasterize_trapezoid(image,
|
|
(pixman_trapezoid_t *) traps,
|
|
-bounds.x1, -bounds.y1);
|
|
|
|
|
|
scratch = GetScratchPixmapHeader(screen, width, height,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
PIXMAN_FORMAT_BPP(format),
|
|
pixman_image_get_stride(image),
|
|
pixman_image_get_data(image));
|
|
if (!scratch) {
|
|
pixman_image_unref(image);
|
|
return;
|
|
}
|
|
|
|
mask = CreatePicture(0, &scratch->drawable,
|
|
PictureMatchFormat(screen,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
format),
|
|
0, 0, serverClient, &error);
|
|
if (!mask) {
|
|
FreeScratchPixmapHeader(scratch);
|
|
pixman_image_unref(image);
|
|
return;
|
|
}
|
|
|
|
xRel = bounds.x1 + xSrc - xDst;
|
|
yRel = bounds.y1 + ySrc - yDst;
|
|
CompositePicture(op, src, mask, dst,
|
|
xRel, yRel,
|
|
0, 0,
|
|
bounds.x1, bounds.y1,
|
|
width, height);
|
|
FreePicture(mask, 0);
|
|
|
|
FreeScratchPixmapHeader(scratch);
|
|
pixman_image_unref(image);
|
|
} else {
|
|
if (dst->polyEdge == PolyEdgeSharp)
|
|
maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
|
|
else
|
|
maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
|
|
|
|
for (; ntrap; ntrap--, traps++)
|
|
uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1, traps);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* uxa_trapezoids is essentially a copy of miTrapezoids that uses
|
|
* uxa_create_alpha_picture instead of miCreateAlphaPicture.
|
|
*
|
|
* The problem with miCreateAlphaPicture is that it calls PolyFillRect
|
|
* to initialize the contents after creating the pixmap, which
|
|
* causes the pixmap to be moved in for acceleration. The subsequent
|
|
* call to RasterizeTrapezoid won't be accelerated however, which
|
|
* forces the pixmap to be moved out again.
|
|
*
|
|
* uxa_create_alpha_picture avoids this roundtrip by using
|
|
* uxa_check_poly_fill_rect to initialize the contents.
|
|
*/
|
|
void
|
|
uxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
|
|
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
|
int ntrap, xTrapezoid * traps)
|
|
{
|
|
ScreenPtr screen = dst->pDrawable->pScreen;
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(screen);
|
|
BoxRec bounds;
|
|
Bool direct;
|
|
|
|
if (uxa_screen->info->flags & UXA_USE_GLAMOR) {
|
|
int ok;
|
|
|
|
uxa_picture_prepare_access(dst, UXA_GLAMOR_ACCESS_RW);
|
|
uxa_picture_prepare_access(src, UXA_GLAMOR_ACCESS_RO);
|
|
ok = glamor_trapezoids_nf(op,
|
|
src, dst, maskFormat, xSrc,
|
|
ySrc, ntrap, traps);
|
|
uxa_picture_finish_access(src, UXA_GLAMOR_ACCESS_RO);
|
|
uxa_picture_finish_access(dst, UXA_GLAMOR_ACCESS_RW);
|
|
|
|
if (!ok)
|
|
goto fallback;
|
|
|
|
return;
|
|
}
|
|
|
|
if (uxa_screen->force_fallback) {
|
|
fallback:
|
|
uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, ntrap, traps);
|
|
return;
|
|
}
|
|
|
|
direct = op == PictOpAdd && miIsSolidAlpha(src);
|
|
if (maskFormat || direct) {
|
|
miTrapezoidBounds(ntrap, traps, &bounds);
|
|
|
|
if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Check for solid alpha add
|
|
*/
|
|
if (direct) {
|
|
DrawablePtr pDraw = dst->pDrawable;
|
|
PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw);
|
|
int xoff, yoff;
|
|
|
|
uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff);
|
|
|
|
xoff += pDraw->x;
|
|
yoff += pDraw->y;
|
|
|
|
if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) {
|
|
PictureScreenPtr ps = GetPictureScreen(screen);
|
|
|
|
for (; ntrap; ntrap--, traps++)
|
|
(*ps->RasterizeTrapezoid) (dst, traps, 0, 0);
|
|
uxa_finish_access(pDraw, UXA_ACCESS_RW);
|
|
}
|
|
} else if (maskFormat) {
|
|
PixmapPtr scratch = NULL;
|
|
PicturePtr mask;
|
|
INT16 xDst, yDst;
|
|
INT16 xRel, yRel;
|
|
int width, height;
|
|
pixman_image_t *image;
|
|
pixman_format_code_t format;
|
|
|
|
xDst = traps[0].left.p1.x >> 16;
|
|
yDst = traps[0].left.p1.y >> 16;
|
|
|
|
width = bounds.x2 - bounds.x1;
|
|
height = bounds.y2 - bounds.y1;
|
|
|
|
format = maskFormat->format |
|
|
(BitsPerPixel(maskFormat->depth) << 24);
|
|
image =
|
|
pixman_image_create_bits(format, width, height, NULL, 0);
|
|
if (!image)
|
|
return;
|
|
|
|
for (; ntrap; ntrap--, traps++)
|
|
pixman_rasterize_trapezoid(image,
|
|
(pixman_trapezoid_t *) traps,
|
|
-bounds.x1, -bounds.y1);
|
|
if (uxa_drawable_is_offscreen(dst->pDrawable)) {
|
|
mask = uxa_picture_from_pixman_image(screen, image, format);
|
|
} else {
|
|
int error;
|
|
|
|
scratch = GetScratchPixmapHeader(screen, width, height,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
PIXMAN_FORMAT_BPP(format),
|
|
pixman_image_get_stride(image),
|
|
pixman_image_get_data(image));
|
|
mask = CreatePicture(0, &scratch->drawable,
|
|
PictureMatchFormat(screen,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
format),
|
|
0, 0, serverClient, &error);
|
|
}
|
|
if (!mask) {
|
|
if (scratch)
|
|
FreeScratchPixmapHeader(scratch);
|
|
pixman_image_unref(image);
|
|
return;
|
|
}
|
|
|
|
xRel = bounds.x1 + xSrc - xDst;
|
|
yRel = bounds.y1 + ySrc - yDst;
|
|
CompositePicture(op, src, mask, dst,
|
|
xRel, yRel,
|
|
0, 0,
|
|
bounds.x1, bounds.y1,
|
|
width, height);
|
|
FreePicture(mask, 0);
|
|
|
|
if (scratch)
|
|
FreeScratchPixmapHeader(scratch);
|
|
pixman_image_unref(image);
|
|
} else {
|
|
if (dst->polyEdge == PolyEdgeSharp)
|
|
maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
|
|
else
|
|
maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
|
|
for (; ntrap; ntrap--, traps++)
|
|
uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc,
|
|
1, traps);
|
|
}
|
|
}
|
|
|
|
static void
|
|
uxa_check_triangles(CARD8 op, PicturePtr src, PicturePtr dst,
|
|
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
|
int ntri, xTriangle *tri)
|
|
{
|
|
ScreenPtr screen = dst->pDrawable->pScreen;
|
|
|
|
if (maskFormat) {
|
|
PixmapPtr scratch = NULL;
|
|
PicturePtr mask;
|
|
INT16 xDst, yDst;
|
|
INT16 xRel, yRel;
|
|
BoxRec bounds;
|
|
int width, height;
|
|
pixman_image_t *image;
|
|
pixman_format_code_t format;
|
|
int error;
|
|
|
|
xDst = pixman_fixed_to_int(tri[0].p1.x);
|
|
yDst = pixman_fixed_to_int(tri[0].p1.y);
|
|
|
|
miTriangleBounds (ntri, tri, &bounds);
|
|
if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
|
|
return;
|
|
|
|
width = bounds.x2 - bounds.x1;
|
|
height = bounds.y2 - bounds.y1;
|
|
|
|
format = maskFormat->format |
|
|
(BitsPerPixel(maskFormat->depth) << 24);
|
|
image =
|
|
pixman_image_create_bits(format, width, height, NULL, 0);
|
|
if (!image)
|
|
return;
|
|
|
|
pixman_add_triangles(image,
|
|
-bounds.x1, -bounds.y1,
|
|
ntri, (pixman_triangle_t *)tri);
|
|
|
|
scratch = GetScratchPixmapHeader(screen, width, height,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
PIXMAN_FORMAT_BPP(format),
|
|
pixman_image_get_stride(image),
|
|
pixman_image_get_data(image));
|
|
if (!scratch) {
|
|
pixman_image_unref(image);
|
|
return;
|
|
}
|
|
|
|
mask = CreatePicture(0, &scratch->drawable,
|
|
PictureMatchFormat(screen,
|
|
PIXMAN_FORMAT_DEPTH(format),
|
|
format),
|
|
0, 0, serverClient, &error);
|
|
if (!mask) {
|
|
FreeScratchPixmapHeader(scratch);
|
|
pixman_image_unref(image);
|
|
return;
|
|
}
|
|
|
|
xRel = bounds.x1 + xSrc - xDst;
|
|
yRel = bounds.y1 + ySrc - yDst;
|
|
CompositePicture(op, src, mask, dst,
|
|
xRel, yRel,
|
|
0, 0,
|
|
bounds.x1, bounds.y1,
|
|
width, height);
|
|
FreePicture(mask, 0);
|
|
|
|
FreeScratchPixmapHeader(scratch);
|
|
pixman_image_unref(image);
|
|
} else {
|
|
if (dst->polyEdge == PolyEdgeSharp)
|
|
maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
|
|
else
|
|
maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
|
|
|
|
for (; ntri; ntri--, tri++)
|
|
uxa_check_triangles(op, src, dst, maskFormat, xSrc, ySrc, 1, tri);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* uxa_triangles is essentially a copy of miTriangles that uses
|
|
* uxa_create_alpha_picture instead of miCreateAlphaPicture.
|
|
*
|
|
* The problem with miCreateAlphaPicture is that it calls PolyFillRect
|
|
* to initialize the contents after creating the pixmap, which
|
|
* causes the pixmap to be moved in for acceleration. The subsequent
|
|
* call to AddTriangles won't be accelerated however, which forces the pixmap
|
|
* to be moved out again.
|
|
*
|
|
* uxa_create_alpha_picture avoids this roundtrip by using
|
|
* uxa_check_poly_fill_rect to initialize the contents.
|
|
*/
|
|
void
|
|
uxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
|
|
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
|
int ntri, xTriangle * tris)
|
|
{
|
|
ScreenPtr pScreen = pDst->pDrawable->pScreen;
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
|
|
PictureScreenPtr ps = GetPictureScreen(pScreen);
|
|
BoxRec bounds;
|
|
Bool direct;
|
|
|
|
if (uxa_screen->info->flags & UXA_USE_GLAMOR) {
|
|
int ok;
|
|
|
|
uxa_picture_prepare_access(pDst, UXA_GLAMOR_ACCESS_RW);
|
|
uxa_picture_prepare_access(pSrc, UXA_GLAMOR_ACCESS_RO);
|
|
ok = glamor_triangles_nf(op,
|
|
pSrc, pDst, maskFormat, xSrc,
|
|
ySrc, ntri, tris);
|
|
uxa_picture_finish_access(pSrc, UXA_GLAMOR_ACCESS_RO);
|
|
uxa_picture_finish_access(pDst, UXA_GLAMOR_ACCESS_RW);
|
|
|
|
if (!ok)
|
|
goto fallback;
|
|
|
|
return;
|
|
}
|
|
|
|
if (uxa_screen->force_fallback) {
|
|
fallback:
|
|
uxa_check_triangles(op, pSrc, pDst, maskFormat,
|
|
xSrc, ySrc, ntri, tris);
|
|
return;
|
|
}
|
|
|
|
direct = op == PictOpAdd && miIsSolidAlpha(pSrc);
|
|
if (maskFormat || direct) {
|
|
miTriangleBounds(ntri, tris, &bounds);
|
|
|
|
if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Check for solid alpha add
|
|
*/
|
|
if (direct) {
|
|
DrawablePtr pDraw = pDst->pDrawable;
|
|
if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) {
|
|
(*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
|
|
uxa_finish_access(pDraw, UXA_ACCESS_RW);
|
|
}
|
|
} else if (maskFormat) {
|
|
PicturePtr pPicture;
|
|
INT16 xDst, yDst;
|
|
INT16 xRel, yRel;
|
|
int width = bounds.x2 - bounds.x1;
|
|
int height = bounds.y2 - bounds.y1;
|
|
GCPtr pGC;
|
|
xRectangle rect;
|
|
|
|
xDst = tris[0].p1.x >> 16;
|
|
yDst = tris[0].p1.y >> 16;
|
|
|
|
pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat,
|
|
width, height);
|
|
if (!pPicture)
|
|
return;
|
|
|
|
/* Clear the alpha picture to 0. */
|
|
pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen);
|
|
if (!pGC) {
|
|
FreePicture(pPicture, 0);
|
|
return;
|
|
}
|
|
ValidateGC(pPicture->pDrawable, pGC);
|
|
rect.x = 0;
|
|
rect.y = 0;
|
|
rect.width = width;
|
|
rect.height = height;
|
|
uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect);
|
|
FreeScratchGC(pGC);
|
|
|
|
if (uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW)) {
|
|
(*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1,
|
|
ntri, tris);
|
|
uxa_finish_access(pPicture->pDrawable, UXA_ACCESS_RW);
|
|
}
|
|
|
|
xRel = bounds.x1 + xSrc - xDst;
|
|
yRel = bounds.y1 + ySrc - yDst;
|
|
CompositePicture(op, pSrc, pPicture, pDst,
|
|
xRel, yRel, 0, 0, bounds.x1, bounds.y1,
|
|
bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
|
|
FreePicture(pPicture, 0);
|
|
} else {
|
|
if (pDst->polyEdge == PolyEdgeSharp)
|
|
maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
|
|
else
|
|
maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
|
|
|
|
for (; ntri; ntri--, tris++)
|
|
uxa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1,
|
|
tris);
|
|
}
|
|
}
|
|
|
|
void
|
|
uxa_add_traps(PicturePtr pPicture,
|
|
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
|
|
{
|
|
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
|
|
uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
|
|
|
|
if (uxa_screen->info->flags & UXA_USE_GLAMOR) {
|
|
int ok;
|
|
|
|
uxa_picture_prepare_access(pPicture, UXA_GLAMOR_ACCESS_RW);
|
|
ok = glamor_add_traps_nf(pPicture,
|
|
x_off, y_off, ntrap, traps);
|
|
uxa_picture_finish_access(pPicture, UXA_GLAMOR_ACCESS_RW);
|
|
|
|
if (!ok)
|
|
goto fallback;
|
|
|
|
return;
|
|
}
|
|
|
|
fallback:
|
|
uxa_check_add_traps(pPicture, x_off, y_off, ntrap, traps);
|
|
}
|