1 /*
2  * Support for RENDER extension with rootless
3  */
4 /*
5  * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved.
6  * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Except as contained in this notice, the name(s) of the above copyright
27  * holders shall not be used in advertising or otherwise to promote the sale,
28  * use or other dealings in this Software without prior written authorization.
29  */
30 /* This file is largely based on fbcompose.c and fbpict.c, which contain
31  * the following copyright:
32  *
33  * Copyright � 2000 Keith Packard, member of The XFree86 Project, Inc.
34  */
35  /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/aquaPicture.c,v 1.3 2002/09/28 00:00:03 torrey Exp $ */
36 
37 #define DEFAULT_LOG_FORMATS 0
38 
39 #ifdef RENDER
40 
41 #include "fb.h"
42 #include "picturestr.h"
43 #include "mipict.h"
44 #include "fbpict.h"
45 #include "rootless.h"
46 
47 # define mod(a,b)	((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
48 
49 
50 // Replacement for fbStore_x8r8g8b8 that sets the alpha channel
51 void
RootlessStore_x8r8g8b8(FbCompositeOperand * op,CARD32 value)52 RootlessStore_x8r8g8b8 (FbCompositeOperand *op, CARD32 value)
53 {
54     FbBits  *line = op->u.drawable.line; CARD32 offset = op->u.drawable.offset;
55     ((CARD32 *)line)[offset >> 5] = (value & 0xffffff) | 0xff000000;
56 }
57 
58 
59 // Defined in fbcompose.c
60 extern FbCombineFunc fbCombineFuncU[];
61 extern FbCombineFunc fbCombineFuncC[];
62 
63 void
RootlessCompositeGeneral(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)64 RootlessCompositeGeneral(
65     CARD8               op,
66     PicturePtr          pSrc,
67     PicturePtr          pMask,
68     PicturePtr          pDst,
69     INT16               xSrc,
70     INT16               ySrc,
71     INT16               xMask,
72     INT16               yMask,
73     INT16               xDst,
74     INT16               yDst,
75     CARD16              width,
76     CARD16              height)
77 {
78     FbCompositeOperand	src[4],msk[4],dst[4],*pmsk;
79     FbCompositeOperand	*srcPict, *srcAlpha;
80     FbCompositeOperand	*dstPict, *dstAlpha;
81     FbCompositeOperand	*mskPict = 0, *mskAlpha = 0;
82     FbCombineFunc	f;
83     int			w;
84 
85     if (!fbBuildCompositeOperand (pSrc, src, xSrc, ySrc, TRUE, TRUE))
86 	return;
87     if (!fbBuildCompositeOperand (pDst, dst, xDst, yDst, FALSE, TRUE))
88 	return;
89 
90     // Use Rootless operands for on screen picture formats
91     if (pDst->format == PICT_x8r8g8b8) {
92         dst[0].store = RootlessStore_x8r8g8b8;
93     }
94 
95     if (pSrc->alphaMap)
96     {
97 	srcPict = &src[1];
98 	srcAlpha = &src[2];
99     }
100     else
101     {
102 	srcPict = &src[0];
103 	srcAlpha = 0;
104     }
105     if (pDst->alphaMap)
106     {
107 	dstPict = &dst[1];
108 	dstAlpha = &dst[2];
109     }
110     else
111     {
112 	dstPict = &dst[0];
113 	dstAlpha = 0;
114     }
115     f = fbCombineFuncU[op];
116     if (pMask)
117     {
118 	if (!fbBuildCompositeOperand (pMask, msk, xMask, yMask, TRUE, TRUE))
119 	    return;
120 	pmsk = msk;
121 	if (pMask->componentAlpha)
122 	    f = fbCombineFuncC[op];
123 	if (pMask->alphaMap)
124 	{
125 	    mskPict = &msk[1];
126 	    mskAlpha = &msk[2];
127 	}
128 	else
129 	{
130 	    mskPict = &msk[0];
131 	    mskAlpha = 0;
132 	}
133     }
134     else
135 	pmsk = 0;
136     while (height--)
137     {
138 	w = width;
139 
140 	while (w--)
141 	{
142 	    (*f) (src, pmsk, dst);
143 	    (*src->over) (src);
144 	    (*dst->over) (dst);
145 	    if (pmsk)
146 		(*pmsk->over) (pmsk);
147 	}
148 	(*src->down) (src);
149 	(*dst->down) (dst);
150 	if (pmsk)
151 	    (*pmsk->down) (pmsk);
152     }
153 }
154 
155 static int rootless_log_pict_formats = DEFAULT_LOG_FORMATS;
156 
op_name(int op)157 static const char *op_name (int op)
158 {
159     static const char *ops[] = {
160 	"Clear", "Src", "Dst", "Over", "OverReverse", "In", "InReverse",
161 	"Out", "OutReverse", "Atop", "AtopReverse", "Xor", "Add",
162 	"Saturate", "Maximum",
163 
164 	"DisjointClear", "DisjointSrc", "DisjointDst", "DisjointOver",
165 	"DisjointOverReverse", "DisjointIn", "DisjointInReverse",
166 	"DisjointOut", "DisjointOutReverse", "DisjointAtop",
167 	"DisjointAtopReverse", "DisjointXor", "DisjointMaximum",
168 
169 	"ConjointClear", "ConjointSrc", "ConjointDst", "ConjointOver",
170 	"ConjointOverReverse", "ConjointIn", "ConjointInReverse",
171 	"ConjointOut", "ConjointOutReverse", "ConjointAtop",
172 	"ConjointAtopReverse", "ConjointXor", "ConjointMaximum",
173     };
174 
175     if (op >= 0 && op < (int) (sizeof (ops) / sizeof (ops[0])))
176 	return ops[op];
177     else
178 	return "Unknown";
179 }
180 
type_name(int type)181 static const char *type_name (int type)
182 {
183     switch (type)
184     {
185     case PICT_TYPE_OTHER:
186 	return "Other";
187     case PICT_TYPE_A:
188 	return "A";
189     case PICT_TYPE_ARGB:
190 	return "ARGB";
191     case PICT_TYPE_ABGR:
192 	return "ABGR";
193     case PICT_TYPE_COLOR:
194 	return "Color";
195     case PICT_TYPE_GRAY:
196 	return "Gray";
197     default:
198 	return "Unknown";
199     }
200 }
201 
log_format(int op,unsigned int src,unsigned int dst,unsigned int mask)202 static void log_format (int op, unsigned int src,
203 			unsigned int dst, unsigned int mask)
204 {
205     struct op {
206 	int op;
207 	unsigned int src, dst, mask;
208     };
209 
210     static struct op *ops;
211     static int n_ops, allocated_ops;
212 
213     int i;
214 
215     for (i = 0; i < n_ops; i++)
216     {
217 	if (ops[i].op == op && ops[i].src == src
218 	    && ops[i].dst == dst && ops[i].mask == mask)
219 	{
220 	    return;
221 	}
222     }
223 
224     if (n_ops == allocated_ops)
225     {
226 	allocated_ops *= 2;
227 	ops = realloc (ops, allocated_ops * sizeof (struct op));
228     }
229 
230     ops[n_ops].op = op;
231     ops[n_ops].src = src;
232     ops[n_ops].dst = dst;
233     ops[n_ops].mask = mask;
234     n_ops++;
235 
236     fprintf (stderr,
237 	     "op: %s src (%dbpp %s %04x) dst (%dbpp %s %04x) mask (%dbpp %s %04x)\n",
238 	     op_name (op), PICT_FORMAT_BPP (src),
239 	     type_name (PICT_FORMAT_TYPE (src)),
240 	     src & 0xffff, PICT_FORMAT_BPP (dst),
241 	     type_name (PICT_FORMAT_TYPE (dst)),
242 	     dst & 0xffff, PICT_FORMAT_BPP (mask),
243 	     type_name (PICT_FORMAT_TYPE (mask)),
244 	     mask & 0xffff);
245 }
246 
247 void
RootlessComposite(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)248 RootlessComposite(
249     CARD8           op,
250     PicturePtr      pSrc,
251     PicturePtr      pMask,
252     PicturePtr      pDst,
253     INT16           xSrc,
254     INT16           ySrc,
255     INT16           xMask,
256     INT16           yMask,
257     INT16           xDst,
258     INT16           yDst,
259     CARD16          width,
260     CARD16          height)
261 {
262     RegionRec	    region;
263     int		    n;
264     BoxPtr	    pbox;
265     CompositeFunc   func;
266     Bool	    srcRepeat = pSrc->repeat;
267     Bool	    maskRepeat = FALSE;
268     Bool	    srcAlphaMap = pSrc->alphaMap != 0;
269     Bool	    maskAlphaMap = FALSE;
270     Bool	    dstAlphaMap = pDst->alphaMap != 0;
271     int		    x_msk, y_msk, x_src, y_src, x_dst, y_dst;
272     int		    w, h, w_this, h_this;
273     int		    dstDepth = pDst->pDrawable->depth;
274 
275     xDst += pDst->pDrawable->x;
276     yDst += pDst->pDrawable->y;
277     xSrc += pSrc->pDrawable->x;
278     ySrc += pSrc->pDrawable->y;
279     if (pMask)
280     {
281 	xMask += pMask->pDrawable->x;
282 	yMask += pMask->pDrawable->y;
283 	maskRepeat = pMask->repeat;
284 	maskAlphaMap = pMask->alphaMap != 0;
285     }
286 
287     if (rootless_log_pict_formats)
288     {
289 	log_format (op, pSrc->format, pDst->format,
290 		    pMask != 0 ? pMask->format : 0);
291     }
292 
293     if (!miComputeCompositeRegion (&region,
294 				   pSrc,
295 				   pMask,
296 				   pDst,
297 				   xSrc,
298 				   ySrc,
299 				   xMask,
300 				   yMask,
301 				   xDst,
302 				   yDst,
303 				   width,
304 				   height))
305 	return;
306 
307     if (pDst->pDrawable->type == DRAWABLE_WINDOW
308 	&& pDst->pDrawable->depth == 24
309 	&& pDst->pDrawable->bitsPerPixel == 32)
310     {
311 	/* fbpict code sets bits above depth to zero. We don't want that! */
312 
313 	pDst->pDrawable->depth = 32;
314     }
315 
316     func = RootlessCompositeGeneral;
317 
318     if (!maskAlphaMap && !srcAlphaMap && !dstAlphaMap)
319     switch (op) {
320     case PictOpOver:
321 	if (pMask)
322 	{
323 	    if (srcRepeat &&
324 		pSrc->pDrawable->width == 1 &&
325 		pSrc->pDrawable->height == 1)
326 	    {
327 		srcRepeat = FALSE;
328 		if (PICT_FORMAT_COLOR(pSrc->format)) {
329 		    switch (pMask->format) {
330 		    case PICT_a8:
331 			switch (pDst->format) {
332 			case PICT_r5g6b5:
333 			case PICT_b5g6r5:
334 			    func = fbCompositeSolidMask_nx8x0565;
335 			    break;
336 			case PICT_r8g8b8:
337 			case PICT_b8g8r8:
338 			    func = fbCompositeSolidMask_nx8x0888;
339 			    break;
340 			case PICT_a8r8g8b8:
341 			case PICT_x8r8g8b8:
342 			case PICT_a8b8g8r8:
343 			case PICT_x8b8g8r8:
344 			    func = fbCompositeSolidMask_nx8x8888;
345 			    break;
346 			}
347 			break;
348 		    case PICT_a8r8g8b8:
349 			if (pMask->componentAlpha) {
350 			    switch (pDst->format) {
351 			    case PICT_a8r8g8b8:
352 			    case PICT_x8r8g8b8:
353 				func = fbCompositeSolidMask_nx8888x8888C;
354 				break;
355 			    case PICT_r5g6b5:
356 				func = fbCompositeSolidMask_nx8888x0565C;
357 				break;
358 			    }
359 			}
360 			break;
361 		    case PICT_a8b8g8r8:
362 			if (pMask->componentAlpha) {
363 			    switch (pDst->format) {
364 			    case PICT_a8b8g8r8:
365 			    case PICT_x8b8g8r8:
366 				func = fbCompositeSolidMask_nx8888x8888C;
367 				break;
368 			    case PICT_b5g6r5:
369 				func = fbCompositeSolidMask_nx8888x0565C;
370 				break;
371 			    }
372 			}
373 			break;
374 		    case PICT_a1:
375 			switch (pDst->format) {
376 			case PICT_r5g6b5:
377 			case PICT_b5g6r5:
378 			case PICT_r8g8b8:
379 			case PICT_b8g8r8:
380 			case PICT_a8r8g8b8:
381 			case PICT_x8r8g8b8:
382 			case PICT_a8b8g8r8:
383 			case PICT_x8b8g8r8:
384 			    func = fbCompositeSolidMask_nx1xn;
385 			    break;
386 			}
387 		    }
388 		}
389 	    }
390 	}
391 	else
392 	{
393 	    switch (pSrc->format) {
394 	    case PICT_a8r8g8b8:
395 	    case PICT_x8r8g8b8:
396 		switch (pDst->format) {
397 		case PICT_a8r8g8b8:
398 		case PICT_x8r8g8b8:
399 		    func = fbCompositeSrc_8888x8888;
400 		    break;
401 		case PICT_r8g8b8:
402 		    func = fbCompositeSrc_8888x0888;
403 		    break;
404 		case PICT_r5g6b5:
405 		    func = fbCompositeSrc_8888x0565;
406 		    break;
407 		}
408 		break;
409 	    case PICT_a8b8g8r8:
410 	    case PICT_x8b8g8r8:
411 		switch (pDst->format) {
412 		case PICT_a8b8g8r8:
413 		case PICT_x8b8g8r8:
414 		    func = fbCompositeSrc_8888x8888;
415 		    break;
416 		case PICT_b8g8r8:
417 		    func = fbCompositeSrc_8888x0888;
418 		    break;
419 		case PICT_b5g6r5:
420 		    func = fbCompositeSrc_8888x0565;
421 		    break;
422 		}
423 		break;
424 	    case PICT_r5g6b5:
425 		switch (pDst->format) {
426 		case PICT_r5g6b5:
427 		    func = fbCompositeSrc_0565x0565;
428 		    break;
429 		}
430 		break;
431 	    case PICT_b5g6r5:
432 		switch (pDst->format) {
433 		case PICT_b5g6r5:
434 		    func = fbCompositeSrc_0565x0565;
435 		    break;
436 		}
437 		break;
438 	    }
439 	}
440 	break;
441     case PictOpAdd:
442 	if (pMask == 0)
443 	{
444 	    switch (pSrc->format) {
445 	    case PICT_a8r8g8b8:
446 		switch (pDst->format) {
447 		case PICT_a8r8g8b8:
448 		    func = fbCompositeSrcAdd_8888x8888;
449 		    break;
450 		}
451 		break;
452 	    case PICT_a8b8g8r8:
453 		switch (pDst->format) {
454 		case PICT_a8b8g8r8:
455 		    func = fbCompositeSrcAdd_8888x8888;
456 		    break;
457 		}
458 		break;
459 	    case PICT_a8:
460 		switch (pDst->format) {
461 		case PICT_a8:
462 		    func = fbCompositeSrcAdd_8000x8000;
463 		    break;
464 		}
465 		break;
466 	    case PICT_a1:
467 		switch (pDst->format) {
468 		case PICT_a1:
469 		    func = fbCompositeSrcAdd_1000x1000;
470 		    break;
471 		}
472 		break;
473 	    }
474 	}
475 	break;
476     }
477 
478     n = REGION_NUM_RECTS (&region);
479     pbox = REGION_RECTS (&region);
480     while (n--)
481     {
482 	h = pbox->y2 - pbox->y1;
483 	y_src = pbox->y1 - yDst + ySrc;
484 	y_msk = pbox->y1 - yDst + yMask;
485 	y_dst = pbox->y1;
486 	while (h)
487 	{
488 	    h_this = h;
489 	    w = pbox->x2 - pbox->x1;
490 	    x_src = pbox->x1 - xDst + xSrc;
491 	    x_msk = pbox->x1 - xDst + xMask;
492 	    x_dst = pbox->x1;
493 	    if (maskRepeat)
494 	    {
495 		y_msk = mod (y_msk, pMask->pDrawable->height);
496 		if (h_this > pMask->pDrawable->height - y_msk)
497 		    h_this = pMask->pDrawable->height - y_msk;
498 	    }
499 	    if (srcRepeat)
500 	    {
501 		y_src = mod (y_src, pSrc->pDrawable->height);
502 		if (h_this > pSrc->pDrawable->height - y_src)
503 		    h_this = pSrc->pDrawable->height - y_src;
504 	    }
505 	    while (w)
506 	    {
507 		w_this = w;
508 		if (maskRepeat)
509 		{
510 		    x_msk = mod (x_msk, pMask->pDrawable->width);
511 		    if (w_this > pMask->pDrawable->width - x_msk)
512 			w_this = pMask->pDrawable->width - x_msk;
513 		}
514 		if (srcRepeat)
515 		{
516 		    x_src = mod (x_src, pSrc->pDrawable->width);
517 		    if (w_this > pSrc->pDrawable->width - x_src)
518 			w_this = pSrc->pDrawable->width - x_src;
519 		}
520 		(*func) (op, pSrc, pMask, pDst,
521 			 x_src, y_src, x_msk, y_msk, x_dst, y_dst,
522 			 w_this, h_this);
523 		w -= w_this;
524 		x_src += w_this;
525 		x_msk += w_this;
526 		x_dst += w_this;
527 	    }
528 	    h -= h_this;
529 	    y_src += h_this;
530 	    y_msk += h_this;
531 	    y_dst += h_this;
532 	}
533 	pbox++;
534     }
535     REGION_UNINIT (pDst->pDrawable->pScreen, &region);
536 
537     pDst->pDrawable->depth = dstDepth;
538 }
539 
540 #endif /* RENDER */
541