2
* Copyright Ā© 2001 Keith Packard
4
* Partly based on code that is Copyright Ā© The XFree86 Project Inc.
6
* Permission to use, copy, modify, distribute, and sell this software and its
7
* documentation for any purpose is hereby granted without fee, provided that
8
* the above copyright notice appear in all copies and that both that
9
* copyright notice and this permission notice appear in supporting
10
* documentation, and that the name of Keith Packard not be used in
11
* advertising or publicity pertaining to distribution of the software without
12
* specific, written prior permission. Keith Packard makes no
13
* representations about the suitability of this software for any purpose. It
14
* is provided "as is" without express or implied warranty.
16
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22
* PERFORMANCE OF THIS SOFTWARE.
26
#include <xorg-config.h>
38
static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
46
snprintf(string, n, "None");
53
snprintf(format, 20, "ARGB8888");
56
snprintf(format, 20, "RGB565 ");
59
snprintf(format, 20, "RGB555 ");
62
snprintf(format, 20, "A8 ");
65
snprintf(format, 20, "A1 ");
68
snprintf(format, 20, "0x%x", (int)pict->format);
72
loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
74
snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
75
pict->pDrawable->height, pict->repeat ?
78
snprintf(string, n, "0x%lx:%c fmt %s (%s)", (long)pict->pDrawable, loc, format, size);
82
exaPrintCompositeFallback(CARD8 op,
88
char srcdesc[40], maskdesc[40], dstdesc[40];
99
sprintf(sop, "0x%x", (int)op);
103
exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
104
exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
105
exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
107
ErrorF("Composite fallback: op %s, \n"
111
sop, srcdesc, maskdesc, dstdesc);
116
exaGetPixelFromRGBA(CARD32 *pixel,
123
int rbits, bbits, gbits, abits;
124
int rshift, bshift, gshift, ashift;
128
if (!PICT_FORMAT_COLOR(format))
131
rbits = PICT_FORMAT_R(format);
132
gbits = PICT_FORMAT_G(format);
133
bbits = PICT_FORMAT_B(format);
134
abits = PICT_FORMAT_A(format);
136
if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
139
rshift = gshift + gbits;
140
ashift = rshift + rbits;
141
} else { /* PICT_TYPE_ABGR */
144
bshift = gshift + gbits;
145
ashift = bshift + bbits;
148
*pixel |= ( blue >> (16 - bbits)) << bshift;
149
*pixel |= ( red >> (16 - rbits)) << rshift;
150
*pixel |= (green >> (16 - gbits)) << gshift;
151
*pixel |= (alpha >> (16 - abits)) << ashift;
158
exaGetRGBAFromPixel(CARD32 pixel,
165
int rbits, bbits, gbits, abits;
166
int rshift, bshift, gshift, ashift;
168
if (!PICT_FORMAT_COLOR(format))
171
rbits = PICT_FORMAT_R(format);
172
gbits = PICT_FORMAT_G(format);
173
bbits = PICT_FORMAT_B(format);
174
abits = PICT_FORMAT_A(format);
176
if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
179
rshift = gshift + gbits;
180
ashift = rshift + rbits;
181
} else { /* PICT_TYPE_ABGR */
184
bshift = gshift + gbits;
185
ashift = bshift + bbits;
188
*red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits);
190
*red |= *red >> rbits;
194
*green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits);
196
*green |= *green >> gbits;
200
*blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits);
202
*blue |= *blue >> bbits;
207
*alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits);
209
*alpha |= *alpha >> abits;
219
exaTryDriverSolidFill(PicturePtr pSrc,
228
ExaScreenPriv (pDst->pDrawable->pScreen);
232
int dst_off_x, dst_off_y;
233
PixmapPtr pSrcPix, pDstPix;
235
CARD16 red, green, blue, alpha;
237
xDst += pDst->pDrawable->x;
238
yDst += pDst->pDrawable->y;
239
xSrc += pSrc->pDrawable->x;
240
ySrc += pSrc->pDrawable->y;
242
if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst,
243
xSrc, ySrc, 0, 0, xDst, yDst,
247
exaDrawableUseMemory(pSrc->pDrawable);
248
exaDrawableUseScreen(pDst->pDrawable);
250
pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
252
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
256
if (pSrc->pDrawable->type == DRAWABLE_WINDOW)
257
pSrcPix = (*pSrc->pDrawable->pScreen->GetWindowPixmap)(
258
(WindowPtr) (pSrc->pDrawable));
260
pSrcPix = (PixmapPtr) (pSrc->pDrawable);
263
exaPrepareAccess(&pSrcPix->drawable, EXA_PREPARE_SRC);
264
switch (pSrcPix->drawable.bitsPerPixel) {
266
pixel = *(CARD32 *)(pSrcPix->devPrivate.ptr);
269
pixel = *(CARD16 *)(pSrcPix->devPrivate.ptr);
272
pixel = *(CARD8 *)(pSrcPix->devPrivate.ptr);
275
if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
278
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
281
exaFinishAccess(&pSrcPix->drawable, EXA_PREPARE_SRC);
283
exaGetPixelFromRGBA(&pixel, red, green, blue, alpha,
286
if (!(*pExaScr->info->accel.PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
288
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
292
nbox = REGION_NUM_RECTS(®ion);
293
pbox = REGION_RECTS(®ion);
296
(*pExaScr->info->accel.Solid) (pDstPix,
297
pbox->x1 + dst_off_x,
298
pbox->y1 + dst_off_y,
299
pbox->x2 + dst_off_x,
300
pbox->y2 + dst_off_y);
304
(*pExaScr->info->accel.DoneSolid) (pDstPix);
305
exaMarkSync(pDst->pDrawable->pScreen);
306
exaDrawableDirty (pDst->pDrawable);
308
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
313
exaTryDriverComposite(CARD8 op,
326
ExaScreenPriv (pDst->pDrawable->pScreen);
330
int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
331
PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
332
struct _Pixmap scratch;
334
/* Bail if we might exceed coord limits by rendering from/to these. We
335
* should really be making some scratch pixmaps with offsets and coords
336
* adjusted to deal with this, but it hasn't been done yet.
338
if (pSrc->pDrawable->width > pExaScr->info->card.maxX ||
339
pSrc->pDrawable->height > pExaScr->info->card.maxY ||
340
pDst->pDrawable->width > pExaScr->info->card.maxX ||
341
pDst->pDrawable->height > pExaScr->info->card.maxY ||
342
(pMask && (pMask->pDrawable->width > pExaScr->info->card.maxX ||
343
pMask->pDrawable->height > pExaScr->info->card.maxY)))
348
xDst += pDst->pDrawable->x;
349
yDst += pDst->pDrawable->y;
352
xMask += pMask->pDrawable->x;
353
yMask += pMask->pDrawable->y;
356
xSrc += pSrc->pDrawable->x;
357
ySrc += pSrc->pDrawable->y;
359
if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst,
360
xSrc, ySrc, xMask, yMask, xDst, yDst,
364
if (pExaScr->info->accel.CheckComposite &&
365
!(*pExaScr->info->accel.CheckComposite) (op, pSrc, pMask, pDst))
367
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
371
exaDrawableUseScreen(pSrc->pDrawable);
373
exaDrawableUseScreen(pMask->pDrawable);
374
exaDrawableUseScreen(pDst->pDrawable);
376
pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
378
pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
380
pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
383
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
387
if (!pSrcPix && (!pMask || pMaskPix) && pExaScr->info->accel.UploadToScratch) {
388
if (pSrc->pDrawable->type == DRAWABLE_WINDOW)
389
pSrcPix = (*pSrc->pDrawable->pScreen->GetWindowPixmap) (
390
(WindowPtr) pSrc->pDrawable);
392
pSrcPix = (PixmapPtr) pSrc->pDrawable;
393
if ((*pExaScr->info->accel.UploadToScratch) (pSrcPix, &scratch))
395
} else if (pSrcPix && pMask && !pMaskPix && pExaScr->info->accel.UploadToScratch) {
396
if (pMask->pDrawable->type == DRAWABLE_WINDOW)
397
pMaskPix = (*pMask->pDrawable->pScreen->GetWindowPixmap) (
398
(WindowPtr) pMask->pDrawable);
400
pMaskPix = (PixmapPtr) pMask->pDrawable;
401
if ((*pExaScr->info->accel.UploadToScratch) (pMaskPix, &scratch))
405
if (!pSrcPix || (pMask && !pMaskPix)) {
406
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
410
if (!(*pExaScr->info->accel.PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
413
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
417
nbox = REGION_NUM_RECTS(®ion);
418
pbox = REGION_RECTS(®ion);
428
(*pExaScr->info->accel.Composite) (pDstPix,
429
pbox->x1 + xSrc + src_off_x,
430
pbox->y1 + ySrc + src_off_y,
431
pbox->x1 + xMask + mask_off_x,
432
pbox->y1 + yMask + mask_off_y,
433
pbox->x1 + dst_off_x,
434
pbox->y1 + dst_off_y,
436
pbox->y2 - pbox->y1);
440
(*pExaScr->info->accel.DoneComposite) (pDstPix);
441
exaMarkSync(pDst->pDrawable->pScreen);
442
exaDrawableDirty (pDst->pDrawable);
444
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
450
exaComposite(CARD8 op,
463
ExaScreenPriv (pDst->pDrawable->pScreen);
465
ScrnInfoPtr pScrn = XF86SCRNINFO(pDst->pDrawable->pScreen);
466
Bool saveSrcRepeat = pSrc->repeat;
467
Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
469
if (!pScrn->vtSema) {
470
exaDrawableDirty(pDst->pDrawable);
471
pExaScr->SavedComposite(op, pSrc, pMask, pDst, xSrc, ySrc,
472
xMask, yMask, xDst, yDst, width, height);
476
/* simplify the drivers by reducing here */
478
case PictOpDisjointClear:
479
case PictOpConjointClear:
482
case PictOpDisjointSrc:
483
case PictOpConjointSrc:
486
case PictOpDisjointDst:
487
case PictOpConjointDst:
494
/* Remove repeat in source if useless */
495
if (pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
496
(xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
497
(ySrc + height) <= pSrc->pDrawable->height)
500
if (!pMask && pSrc->pDrawable)
504
if (pSrc->pDrawable->width == 1 &&
505
pSrc->pDrawable->height == 1 && pSrc->repeat)
507
ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
512
else if (!pSrc->repeat && !pSrc->transform &&
513
pSrc->format == pDst->format)
517
xDst += pDst->pDrawable->x;
518
yDst += pDst->pDrawable->y;
519
xSrc += pSrc->pDrawable->x;
520
ySrc += pSrc->pDrawable->y;
522
if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst,
523
xSrc, ySrc, xMask, yMask, xDst,
524
yDst, width, height))
528
exaCopyNtoN (pSrc->pDrawable, pDst->pDrawable, NULL,
529
REGION_RECTS(®ion), REGION_NUM_RECTS(®ion),
530
xSrc - xDst, ySrc - yDst,
531
FALSE, FALSE, 0, NULL);
532
REGION_UNINIT(pDst->pDrawable->pScreen, ®ion);
538
/* Remove repeat in mask if useless */
539
if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 &&
540
(xMask + width) <= pMask->pDrawable->width && yMask >= 0 &&
541
(yMask + height) <= pMask->pDrawable->height)
545
if (pSrc->pDrawable && (!pMask || pMask->pDrawable) &&
546
pExaScr->info->accel.PrepareComposite &&
547
!pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
549
ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
550
yMask, xDst, yDst, width, height);
556
/* failure to accelerate was not due to pixmaps being in the wrong
559
exaDrawableUseMemory(pSrc->pDrawable);
561
exaDrawableUseMemory(pMask->pDrawable);
562
exaDrawableUseMemory(pDst->pDrawable);
566
exaPrintCompositeFallback (op, pSrc, pMask, pDst);
569
ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc,
570
xMask, yMask, xDst, yDst, width, height);
573
pSrc->repeat = saveSrcRepeat;
575
pMask->repeat = saveMaskRepeat;
579
#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
581
/* exaGlyphs is a slight variation on miGlyphs, to support acceleration. The
582
* issue is that miGlyphs' use of ModifyPixmapHeader makes it impossible to
583
* migrate these pixmaps. So, instead we create a pixmap at the beginning of
584
* the loop and upload each glyph into the pixmap before compositing.
590
PictFormatPtr maskFormat,
597
ExaScreenPriv (pDst->pDrawable->pScreen);
598
PixmapPtr pPixmap = NULL, pScratchPixmap = NULL;
600
PixmapPtr pMaskPixmap = NULL;
602
ScreenPtr pScreen = pDst->pDrawable->pScreen;
603
int width = 0, height = 0;
605
int xDst = list->xOff, yDst = list->yOff;
610
CARD32 component_alpha;
612
/* If the driver doesn't support accelerated composite, there's no point in
613
* going to this extra work. Assume that no driver will be able to do
614
* component-alpha, which is likely accurate (at least until we make a CA
617
if (!pExaScr->info->accel.PrepareComposite ||
618
(maskFormat && NeedsComponent(maskFormat->format))) {
619
miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
628
miGlyphExtents (nlist, list, glyphs, &extents);
630
if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
632
width = extents.x2 - extents.x1;
633
height = extents.y2 - extents.y1;
634
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
638
component_alpha = NeedsComponent(maskFormat->format);
639
pMask = CreatePicture (0, &pMaskPixmap->drawable,
640
maskFormat, CPComponentAlpha, &component_alpha,
641
serverClient, &error);
644
(*pScreen->DestroyPixmap) (pMaskPixmap);
647
pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
648
ValidateGC (&pMaskPixmap->drawable, pGC);
652
rect.height = height;
653
(*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
668
int maxwidth = 0, maxheight = 0, i;
673
for (i = 0; i < n; i++) {
674
if (glyphs[i]->info.width > maxwidth)
675
maxwidth = glyphs[i]->info.width;
676
if (glyphs[i]->info.height > maxheight)
677
maxheight = glyphs[i]->info.height;
679
if (maxwidth == 0 || maxheight == 0) {
683
x += glyph->info.xOff;
684
y += glyph->info.yOff;
690
/* Get a scratch pixmap to wrap the original glyph data */
691
pScratchPixmap = GetScratchPixmapHeader (pScreen, glyphs[0]->info.width,
692
glyphs[0]->info.height,
695
0, (pointer) (glyphs[0] + 1));
699
/* Create the (real) temporary pixmap to store the current glyph in */
700
pPixmap = (*pScreen->CreatePixmap) (pScreen, maxwidth, maxheight,
701
list->format->depth);
703
FreeScratchPixmapHeader (pScratchPixmap);
707
/* Create a temporary picture to wrap the temporary pixmap, so it can be
708
* used as a source for Composite.
710
component_alpha = NeedsComponent(list->format->format);
711
pPicture = CreatePicture (0, &pPixmap->drawable, list->format,
712
CPComponentAlpha, &component_alpha,
713
serverClient, &error);
715
(*pScreen->DestroyPixmap) (pPixmap);
716
FreeScratchPixmapHeader (pScratchPixmap);
720
/* Get a scratch GC with which to copy the glyph data from scratch to
723
pGC = GetScratchGC (list->format->depth, pScreen);
724
ValidateGC (&pPixmap->drawable, pGC);
726
/* Give the temporary pixmap an initial kick towards the screen, so
729
exaPixmapUseScreen (pPixmap);
735
(*pScreen->ModifyPixmapHeader) (pScratchPixmap,
738
0, 0, -1, (pointer) (glyph + 1));
739
pScratchPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
741
/* Copy the glyph data into the proper pixmap instead of a fake.
742
* First we try to use UploadToScreen, if we can, then we fall back
743
* to a plain exaCopyArea in case of failure.
745
if (!pExaScr->info->accel.UploadToScreen ||
746
!exaPixmapIsOffscreen(pPixmap) ||
747
!(*pExaScr->info->accel.UploadToScreen) (pPixmap, 0, 0,
750
pScratchPixmap->devPrivate.ptr,
751
pScratchPixmap->devKind))
753
exaCopyArea (&pScratchPixmap->drawable, &pPixmap->drawable, pGC,
754
0, 0, glyph->info.width, glyph->info.height, 0, 0);
756
exaDrawableDirty (&pPixmap->drawable);
761
CompositePicture (PictOpAdd,
774
CompositePicture (op,
778
xSrc + (x - glyph->info.x) - xDst,
779
ySrc + (y - glyph->info.y) - yDst,
786
x += glyph->info.xOff;
787
y += glyph->info.yOff;
791
FreePicture ((pointer) pPicture, 0);
792
(*pScreen->DestroyPixmap) (pPixmap);
793
FreeScratchPixmapHeader (pScratchPixmap);
799
CompositePicture (op,
808
FreePicture ((pointer) pMask, (XID) 0);
809
(*pScreen->DestroyPixmap) (pMaskPixmap);