Add patch that contain Mali fixes.
[deb_xorg-server.git] / render / mipict.c
CommitLineData
a09e091a
JB
1/*
2 *
3 * Copyright © 1999 Keith Packard
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission. Keith Packard makes no
12 * representations about the suitability of this software for any purpose. It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#ifdef HAVE_DIX_CONFIG_H
25#include <dix-config.h>
26#endif
27
28#include "scrnintstr.h"
29#include "gcstruct.h"
30#include "pixmapstr.h"
31#include "windowstr.h"
32#include "mi.h"
33#include "picturestr.h"
34#include "mipict.h"
35
36int
37miCreatePicture(PicturePtr pPicture)
38{
39 return Success;
40}
41
42void
43miDestroyPicture(PicturePtr pPicture)
44{
45 if (pPicture->freeCompClip)
46 RegionDestroy(pPicture->pCompositeClip);
47}
48
49void
50miDestroyPictureClip(PicturePtr pPicture)
51{
52 switch (pPicture->clientClipType) {
53 case CT_NONE:
54 return;
55 case CT_PIXMAP:
56 (*pPicture->pDrawable->pScreen->
57 DestroyPixmap) ((PixmapPtr) (pPicture->clientClip));
58 break;
59 default:
60 /*
61 * we know we'll never have a list of rectangles, since ChangeClip
62 * immediately turns them into a region
63 */
64 RegionDestroy(pPicture->clientClip);
65 break;
66 }
67 pPicture->clientClip = NULL;
68 pPicture->clientClipType = CT_NONE;
69}
70
71int
72miChangePictureClip(PicturePtr pPicture, int type, pointer value, int n)
73{
74 ScreenPtr pScreen = pPicture->pDrawable->pScreen;
75 PictureScreenPtr ps = GetPictureScreen(pScreen);
76 pointer clientClip;
77 int clientClipType;
78
79 switch (type) {
80 case CT_PIXMAP:
81 /* convert the pixmap to a region */
82 clientClip = (pointer) BitmapToRegion(pScreen, (PixmapPtr) value);
83 if (!clientClip)
84 return BadAlloc;
85 clientClipType = CT_REGION;
86 (*pScreen->DestroyPixmap) ((PixmapPtr) value);
87 break;
88 case CT_REGION:
89 clientClip = value;
90 clientClipType = CT_REGION;
91 break;
92 case CT_NONE:
93 clientClip = 0;
94 clientClipType = CT_NONE;
95 break;
96 default:
97 clientClip = (pointer) RegionFromRects(n, (xRectangle *) value, type);
98 if (!clientClip)
99 return BadAlloc;
100 clientClipType = CT_REGION;
101 free(value);
102 break;
103 }
104 (*ps->DestroyPictureClip) (pPicture);
105 pPicture->clientClip = clientClip;
106 pPicture->clientClipType = clientClipType;
107 pPicture->stateChanges |= CPClipMask;
108 return Success;
109}
110
111void
112miChangePicture(PicturePtr pPicture, Mask mask)
113{
114 return;
115}
116
117void
118miValidatePicture(PicturePtr pPicture, Mask mask)
119{
120 DrawablePtr pDrawable = pPicture->pDrawable;
121
122 if ((mask & (CPClipXOrigin | CPClipYOrigin | CPClipMask | CPSubwindowMode))
123 || (pDrawable->serialNumber !=
124 (pPicture->serialNumber & DRAWABLE_SERIAL_BITS))) {
125 if (pDrawable->type == DRAWABLE_WINDOW) {
126 WindowPtr pWin = (WindowPtr) pDrawable;
127 RegionPtr pregWin;
128 Bool freeTmpClip, freeCompClip;
129
130 if (pPicture->subWindowMode == IncludeInferiors) {
131 pregWin = NotClippedByChildren(pWin);
132 freeTmpClip = TRUE;
133 }
134 else {
135 pregWin = &pWin->clipList;
136 freeTmpClip = FALSE;
137 }
138 freeCompClip = pPicture->freeCompClip;
139
140 /*
141 * if there is no client clip, we can get by with just keeping the
142 * pointer we got, and remembering whether or not should destroy
143 * (or maybe re-use) it later. this way, we avoid unnecessary
144 * copying of regions. (this wins especially if many clients clip
145 * by children and have no client clip.)
146 */
147 if (pPicture->clientClipType == CT_NONE) {
148 if (freeCompClip)
149 RegionDestroy(pPicture->pCompositeClip);
150 pPicture->pCompositeClip = pregWin;
151 pPicture->freeCompClip = freeTmpClip;
152 }
153 else {
154 /*
155 * we need one 'real' region to put into the composite clip. if
156 * pregWin the current composite clip are real, we can get rid of
157 * one. if pregWin is real and the current composite clip isn't,
158 * use pregWin for the composite clip. if the current composite
159 * clip is real and pregWin isn't, use the current composite
160 * clip. if neither is real, create a new region.
161 */
162
163 RegionTranslate(pPicture->clientClip,
164 pDrawable->x + pPicture->clipOrigin.x,
165 pDrawable->y + pPicture->clipOrigin.y);
166
167 if (freeCompClip) {
168 RegionIntersect(pPicture->pCompositeClip,
169 pregWin, pPicture->clientClip);
170 if (freeTmpClip)
171 RegionDestroy(pregWin);
172 }
173 else if (freeTmpClip) {
174 RegionIntersect(pregWin, pregWin, pPicture->clientClip);
175 pPicture->pCompositeClip = pregWin;
176 }
177 else {
178 pPicture->pCompositeClip = RegionCreate(NullBox, 0);
179 RegionIntersect(pPicture->pCompositeClip,
180 pregWin, pPicture->clientClip);
181 }
182 pPicture->freeCompClip = TRUE;
183 RegionTranslate(pPicture->clientClip,
184 -(pDrawable->x + pPicture->clipOrigin.x),
185 -(pDrawable->y + pPicture->clipOrigin.y));
186 }
187 } /* end of composite clip for a window */
188 else {
189 BoxRec pixbounds;
190
191 /* XXX should we translate by drawable.x/y here ? */
192 /* If you want pixmaps in offscreen memory, yes */
193 pixbounds.x1 = pDrawable->x;
194 pixbounds.y1 = pDrawable->y;
195 pixbounds.x2 = pDrawable->x + pDrawable->width;
196 pixbounds.y2 = pDrawable->y + pDrawable->height;
197
198 if (pPicture->freeCompClip) {
199 RegionReset(pPicture->pCompositeClip, &pixbounds);
200 }
201 else {
202 pPicture->freeCompClip = TRUE;
203 pPicture->pCompositeClip = RegionCreate(&pixbounds, 1);
204 }
205
206 if (pPicture->clientClipType == CT_REGION) {
207 if (pDrawable->x || pDrawable->y) {
208 RegionTranslate(pPicture->clientClip,
209 pDrawable->x + pPicture->clipOrigin.x,
210 pDrawable->y + pPicture->clipOrigin.y);
211 RegionIntersect(pPicture->pCompositeClip,
212 pPicture->pCompositeClip,
213 pPicture->clientClip);
214 RegionTranslate(pPicture->clientClip,
215 -(pDrawable->x + pPicture->clipOrigin.x),
216 -(pDrawable->y + pPicture->clipOrigin.y));
217 }
218 else {
219 RegionTranslate(pPicture->pCompositeClip,
220 -pPicture->clipOrigin.x,
221 -pPicture->clipOrigin.y);
222 RegionIntersect(pPicture->pCompositeClip,
223 pPicture->pCompositeClip,
224 pPicture->clientClip);
225 RegionTranslate(pPicture->pCompositeClip,
226 pPicture->clipOrigin.x,
227 pPicture->clipOrigin.y);
228 }
229 }
230 } /* end of composite clip for pixmap */
231 }
232}
233
234int
235miChangePictureTransform(PicturePtr pPicture, PictTransform * transform)
236{
237 return Success;
238}
239
240int
241miChangePictureFilter(PicturePtr pPicture,
242 int filter, xFixed * params, int nparams)
243{
244 return Success;
245}
246
247#define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v))
248
249static inline pixman_bool_t
250miClipPictureReg(pixman_region16_t * pRegion,
251 pixman_region16_t * pClip, int dx, int dy)
252{
253 if (pixman_region_n_rects(pRegion) == 1 &&
254 pixman_region_n_rects(pClip) == 1) {
255 pixman_box16_t *pRbox = pixman_region_rectangles(pRegion, NULL);
256 pixman_box16_t *pCbox = pixman_region_rectangles(pClip, NULL);
257 int v;
258
259 if (pRbox->x1 < (v = pCbox->x1 + dx))
260 pRbox->x1 = BOUND(v);
261 if (pRbox->x2 > (v = pCbox->x2 + dx))
262 pRbox->x2 = BOUND(v);
263 if (pRbox->y1 < (v = pCbox->y1 + dy))
264 pRbox->y1 = BOUND(v);
265 if (pRbox->y2 > (v = pCbox->y2 + dy))
266 pRbox->y2 = BOUND(v);
267 if (pRbox->x1 >= pRbox->x2 || pRbox->y1 >= pRbox->y2) {
268 pixman_region_init(pRegion);
269 }
270 }
271 else if (!pixman_region_not_empty(pClip))
272 return FALSE;
273 else {
274 if (dx || dy)
275 pixman_region_translate(pRegion, -dx, -dy);
276 if (!pixman_region_intersect(pRegion, pRegion, pClip))
277 return FALSE;
278 if (dx || dy)
279 pixman_region_translate(pRegion, dx, dy);
280 }
281 return pixman_region_not_empty(pRegion);
282}
283
284static inline Bool
285miClipPictureSrc(RegionPtr pRegion, PicturePtr pPicture, int dx, int dy)
286{
287 if (pPicture->clientClipType != CT_NONE) {
288 Bool result;
289
290 pixman_region_translate(pPicture->clientClip,
291 pPicture->clipOrigin.x + dx,
292 pPicture->clipOrigin.y + dy);
293
294 result = RegionIntersect(pRegion, pRegion, pPicture->clientClip);
295
296 pixman_region_translate(pPicture->clientClip,
297 -(pPicture->clipOrigin.x + dx),
298 -(pPicture->clipOrigin.y + dy));
299
300 if (!result)
301 return FALSE;
302 }
303 return TRUE;
304}
305
306static void
307SourceValidateOnePicture(PicturePtr pPicture)
308{
309 DrawablePtr pDrawable = pPicture->pDrawable;
310 ScreenPtr pScreen;
311
312 if (!pDrawable)
313 return;
314
315 pScreen = pDrawable->pScreen;
316
317 if (pScreen->SourceValidate) {
318 pScreen->SourceValidate(pDrawable, 0, 0, pDrawable->width,
319 pDrawable->height, pPicture->subWindowMode);
320 }
321}
322
323void
324miCompositeSourceValidate(PicturePtr pPicture)
325{
326 SourceValidateOnePicture(pPicture);
327 if (pPicture->alphaMap)
328 SourceValidateOnePicture(pPicture->alphaMap);
329}
330
331/*
332 * returns FALSE if the final region is empty. Indistinguishable from
333 * an allocation failure, but rendering ignores those anyways.
334 */
335
336Bool
337miComputeCompositeRegion(RegionPtr pRegion,
338 PicturePtr pSrc,
339 PicturePtr pMask,
340 PicturePtr pDst,
341 INT16 xSrc,
342 INT16 ySrc,
343 INT16 xMask,
344 INT16 yMask,
345 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
346{
347
348 int v;
349
350 pRegion->extents.x1 = xDst;
351 v = xDst + width;
352 pRegion->extents.x2 = BOUND(v);
353 pRegion->extents.y1 = yDst;
354 v = yDst + height;
355 pRegion->extents.y2 = BOUND(v);
356 pRegion->data = 0;
357 /* Check for empty operation */
358 if (pRegion->extents.x1 >= pRegion->extents.x2 ||
359 pRegion->extents.y1 >= pRegion->extents.y2) {
360 pixman_region_init(pRegion);
361 return FALSE;
362 }
363 /* clip against dst */
364 if (!miClipPictureReg(pRegion, pDst->pCompositeClip, 0, 0)) {
365 pixman_region_fini(pRegion);
366 return FALSE;
367 }
368 if (pDst->alphaMap) {
369 if (!miClipPictureReg(pRegion, pDst->alphaMap->pCompositeClip,
370 -pDst->alphaOrigin.x, -pDst->alphaOrigin.y)) {
371 pixman_region_fini(pRegion);
372 return FALSE;
373 }
374 }
375 /* clip against src */
376 if (!miClipPictureSrc(pRegion, pSrc, xDst - xSrc, yDst - ySrc)) {
377 pixman_region_fini(pRegion);
378 return FALSE;
379 }
380 if (pSrc->alphaMap) {
381 if (!miClipPictureSrc(pRegion, pSrc->alphaMap,
382 xDst - (xSrc - pSrc->alphaOrigin.x),
383 yDst - (ySrc - pSrc->alphaOrigin.y))) {
384 pixman_region_fini(pRegion);
385 return FALSE;
386 }
387 }
388 /* clip against mask */
389 if (pMask) {
390 if (!miClipPictureSrc(pRegion, pMask, xDst - xMask, yDst - yMask)) {
391 pixman_region_fini(pRegion);
392 return FALSE;
393 }
394 if (pMask->alphaMap) {
395 if (!miClipPictureSrc(pRegion, pMask->alphaMap,
396 xDst - (xMask - pMask->alphaOrigin.x),
397 yDst - (yMask - pMask->alphaOrigin.y))) {
398 pixman_region_fini(pRegion);
399 return FALSE;
400 }
401 }
402 }
403
404 miCompositeSourceValidate(pSrc);
405 if (pMask)
406 miCompositeSourceValidate(pMask);
407
408 return TRUE;
409}
410
411void
412miRenderColorToPixel(PictFormatPtr format, xRenderColor * color, CARD32 *pixel)
413{
414 CARD32 r, g, b, a;
415 miIndexedPtr pIndexed;
416
417 switch (format->type) {
418 case PictTypeDirect:
419 r = color->red >> (16 - Ones(format->direct.redMask));
420 g = color->green >> (16 - Ones(format->direct.greenMask));
421 b = color->blue >> (16 - Ones(format->direct.blueMask));
422 a = color->alpha >> (16 - Ones(format->direct.alphaMask));
423 r = r << format->direct.red;
424 g = g << format->direct.green;
425 b = b << format->direct.blue;
426 a = a << format->direct.alpha;
427 *pixel = r | g | b | a;
428 break;
429 case PictTypeIndexed:
430 pIndexed = (miIndexedPtr) (format->index.devPrivate);
431 if (pIndexed->color) {
432 r = color->red >> 11;
433 g = color->green >> 11;
434 b = color->blue >> 11;
435 *pixel = miIndexToEnt15(pIndexed, (r << 10) | (g << 5) | b);
436 }
437 else {
438 r = color->red >> 8;
439 g = color->green >> 8;
440 b = color->blue >> 8;
441 *pixel = miIndexToEntY24(pIndexed, (r << 16) | (g << 8) | b);
442 }
443 break;
444 }
445}
446
447static CARD16
448miFillColor(CARD32 pixel, int bits)
449{
450 while (bits < 16) {
451 pixel |= pixel << bits;
452 bits <<= 1;
453 }
454 return (CARD16) pixel;
455}
456
457Bool
458miIsSolidAlpha(PicturePtr pSrc)
459{
460 ScreenPtr pScreen;
461 char line[1];
462
463 if (!pSrc->pDrawable)
464 return FALSE;
465
466 pScreen = pSrc->pDrawable->pScreen;
467
468 /* Alpha-only */
469 if (PICT_FORMAT_TYPE(pSrc->format) != PICT_TYPE_A)
470 return FALSE;
471 /* repeat */
472 if (!pSrc->repeat)
473 return FALSE;
474 /* 1x1 */
475 if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1)
476 return FALSE;
477 line[0] = 1;
478 (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line);
479 switch (pSrc->pDrawable->bitsPerPixel) {
480 case 1:
481 return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80;
482 case 4:
483 return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0;
484 case 8:
485 return (CARD8) line[0] == 0xff;
486 default:
487 return FALSE;
488 }
489}
490
491void
492miRenderPixelToColor(PictFormatPtr format, CARD32 pixel, xRenderColor * color)
493{
494 CARD32 r, g, b, a;
495 miIndexedPtr pIndexed;
496
497 switch (format->type) {
498 case PictTypeDirect:
499 r = (pixel >> format->direct.red) & format->direct.redMask;
500 g = (pixel >> format->direct.green) & format->direct.greenMask;
501 b = (pixel >> format->direct.blue) & format->direct.blueMask;
502 a = (pixel >> format->direct.alpha) & format->direct.alphaMask;
503 color->red = miFillColor(r, Ones(format->direct.redMask));
504 color->green = miFillColor(g, Ones(format->direct.greenMask));
505 color->blue = miFillColor(b, Ones(format->direct.blueMask));
506 color->alpha = miFillColor(a, Ones(format->direct.alphaMask));
507 break;
508 case PictTypeIndexed:
509 pIndexed = (miIndexedPtr) (format->index.devPrivate);
510 pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED - 1)];
511 r = (pixel >> 16) & 0xff;
512 g = (pixel >> 8) & 0xff;
513 b = (pixel) & 0xff;
514 color->red = miFillColor(r, 8);
515 color->green = miFillColor(g, 8);
516 color->blue = miFillColor(b, 8);
517 color->alpha = 0xffff;
518 break;
519 }
520}
521
522void
523miTriStrip(CARD8 op,
524 PicturePtr pSrc,
525 PicturePtr pDst,
526 PictFormatPtr maskFormat,
527 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
528{
529 xTriangle *tris, *tri;
530 int ntri;
531
532 ntri = npoints - 2;
533 tris = malloc(ntri * sizeof(xTriangle));
534 if (!tris)
535 return;
536
537 for (tri = tris; npoints >= 3; npoints--, points++, tri++) {
538 tri->p1 = points[0];
539 tri->p2 = points[1];
540 tri->p3 = points[2];
541 }
542 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris);
543 free(tris);
544}
545
546void
547miTriFan(CARD8 op,
548 PicturePtr pSrc,
549 PicturePtr pDst,
550 PictFormatPtr maskFormat,
551 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
552{
553 xTriangle *tris, *tri;
554 xPointFixed *first;
555 int ntri;
556
557 ntri = npoints - 2;
558 tris = malloc(ntri * sizeof(xTriangle));
559 if (!tris)
560 return;
561
562 first = points++;
563 for (tri = tris; npoints >= 3; npoints--, points++, tri++) {
564 tri->p1 = *first;
565 tri->p2 = points[0];
566 tri->p3 = points[1];
567 }
568 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris);
569 free(tris);
570}
571
572Bool
573miPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
574{
575 PictureScreenPtr ps;
576
577 if (!PictureInit(pScreen, formats, nformats))
578 return FALSE;
579 ps = GetPictureScreen(pScreen);
580 ps->CreatePicture = miCreatePicture;
581 ps->DestroyPicture = miDestroyPicture;
582 ps->ChangePictureClip = miChangePictureClip;
583 ps->DestroyPictureClip = miDestroyPictureClip;
584 ps->ChangePicture = miChangePicture;
585 ps->ValidatePicture = miValidatePicture;
586 ps->InitIndexed = miInitIndexed;
587 ps->CloseIndexed = miCloseIndexed;
588 ps->UpdateIndexed = miUpdateIndexed;
589 ps->ChangePictureTransform = miChangePictureTransform;
590 ps->ChangePictureFilter = miChangePictureFilter;
591 ps->RealizeGlyph = miRealizeGlyph;
592 ps->UnrealizeGlyph = miUnrealizeGlyph;
593
594 /* MI rendering routines */
595 ps->Composite = 0; /* requires DDX support */
596 ps->Glyphs = miGlyphs;
597 ps->CompositeRects = miCompositeRects;
598 ps->Trapezoids = 0;
599 ps->Triangles = 0;
600
601 ps->RasterizeTrapezoid = 0; /* requires DDX support */
602 ps->AddTraps = 0; /* requires DDX support */
603 ps->AddTriangles = 0; /* requires DDX support */
604
605 ps->TriStrip = miTriStrip; /* converts call to CompositeTriangles */
606 ps->TriFan = miTriFan;
607
608 return TRUE;
609}