Add patch that contain Mali fixes.
[deb_xorg-server.git] / fb / fbpict.c
1 /*
2 *
3 * Copyright © 2000 SuSE, Inc.
4 * Copyright © 2007 Red Hat, Inc.
5 *
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 SuSE not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. SuSE makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
15 *
16 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author: Keith Packard, SuSE, Inc.
24 */
25
26 #ifdef HAVE_DIX_CONFIG_H
27 #include <dix-config.h>
28 #endif
29
30 #include <string.h>
31
32 #include "fb.h"
33
34 #include "picturestr.h"
35 #include "mipict.h"
36 #include "fbpict.h"
37
38 void
39 fbComposite(CARD8 op,
40 PicturePtr pSrc,
41 PicturePtr pMask,
42 PicturePtr pDst,
43 INT16 xSrc,
44 INT16 ySrc,
45 INT16 xMask,
46 INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
47 {
48 pixman_image_t *src, *mask, *dest;
49 int src_xoff, src_yoff;
50 int msk_xoff, msk_yoff;
51 int dst_xoff, dst_yoff;
52
53 miCompositeSourceValidate(pSrc);
54 if (pMask)
55 miCompositeSourceValidate(pMask);
56
57 src = image_from_pict(pSrc, FALSE, &src_xoff, &src_yoff);
58 mask = image_from_pict(pMask, FALSE, &msk_xoff, &msk_yoff);
59 dest = image_from_pict(pDst, TRUE, &dst_xoff, &dst_yoff);
60
61 if (src && dest && !(pMask && !mask)) {
62 pixman_image_composite(op, src, mask, dest,
63 xSrc + src_xoff, ySrc + src_yoff,
64 xMask + msk_xoff, yMask + msk_yoff,
65 xDst + dst_xoff, yDst + dst_yoff, width, height);
66 }
67
68 free_pixman_pict(pSrc, src);
69 free_pixman_pict(pMask, mask);
70 free_pixman_pict(pDst, dest);
71 }
72
73 static pixman_glyph_cache_t *glyphCache;
74
75 void
76 fbDestroyGlyphCache(void)
77 {
78 if (glyphCache)
79 {
80 pixman_glyph_cache_destroy (glyphCache);
81 glyphCache = NULL;
82 }
83 }
84
85 static void
86 fbUnrealizeGlyph(ScreenPtr pScreen,
87 GlyphPtr pGlyph)
88 {
89 if (glyphCache)
90 pixman_glyph_cache_remove (glyphCache, pGlyph, NULL);
91 }
92
93 static void
94 fbGlyphs(CARD8 op,
95 PicturePtr pSrc,
96 PicturePtr pDst,
97 PictFormatPtr maskFormat,
98 INT16 xSrc,
99 INT16 ySrc, int nlist,
100 GlyphListPtr list,
101 GlyphPtr *glyphs)
102 {
103 #define N_STACK_GLYPHS 512
104 ScreenPtr pScreen = pDst->pDrawable->pScreen;
105 pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
106 pixman_glyph_t *pglyphs = stack_glyphs;
107 pixman_image_t *srcImage, *dstImage;
108 int srcXoff, srcYoff, dstXoff, dstYoff;
109 GlyphPtr glyph;
110 int n_glyphs;
111 int x, y;
112 int i, n;
113 int xDst = list->xOff, yDst = list->yOff;
114
115 miCompositeSourceValidate(pSrc);
116
117 n_glyphs = 0;
118 for (i = 0; i < nlist; ++i)
119 n_glyphs += list[i].len;
120
121 if (!glyphCache)
122 glyphCache = pixman_glyph_cache_create();
123
124 pixman_glyph_cache_freeze (glyphCache);
125
126 if (n_glyphs > N_STACK_GLYPHS) {
127 if (!(pglyphs = malloc (n_glyphs * sizeof (pixman_glyph_t))))
128 goto out;
129 }
130
131 i = 0;
132 x = y = 0;
133 while (nlist--) {
134 x += list->xOff;
135 y += list->yOff;
136 n = list->len;
137 while (n--) {
138 const void *g;
139
140 glyph = *glyphs++;
141
142 if (!(g = pixman_glyph_cache_lookup (glyphCache, glyph, NULL))) {
143 pixman_image_t *glyphImage;
144 PicturePtr pPicture;
145 int xoff, yoff;
146
147 pPicture = GetGlyphPicture(glyph, pScreen);
148 if (!pPicture) {
149 n_glyphs--;
150 goto next;
151 }
152
153 if (!(glyphImage = image_from_pict(pPicture, FALSE, &xoff, &yoff)))
154 goto out;
155
156 g = pixman_glyph_cache_insert(glyphCache, glyph, NULL,
157 glyph->info.x,
158 glyph->info.y,
159 glyphImage);
160
161 free_pixman_pict(pPicture, glyphImage);
162
163 if (!g)
164 goto out;
165 }
166
167 pglyphs[i].x = x;
168 pglyphs[i].y = y;
169 pglyphs[i].glyph = g;
170 i++;
171
172 next:
173 x += glyph->info.xOff;
174 y += glyph->info.yOff;
175 }
176 list++;
177 }
178
179 if (!(srcImage = image_from_pict(pSrc, FALSE, &srcXoff, &srcYoff)))
180 goto out;
181
182 if (!(dstImage = image_from_pict(pDst, TRUE, &dstXoff, &dstYoff)))
183 goto out_free_src;
184
185 if (maskFormat) {
186 pixman_format_code_t format;
187 pixman_box32_t extents;
188
189 format = maskFormat->format | (maskFormat->depth << 24);
190
191 pixman_glyph_get_extents(glyphCache, n_glyphs, pglyphs, &extents);
192
193 pixman_composite_glyphs(op, srcImage, dstImage, format,
194 xSrc + srcXoff + xDst, ySrc + srcYoff + yDst,
195 extents.x1, extents.y1,
196 extents.x1 + dstXoff, extents.y1 + dstYoff,
197 extents.x2 - extents.x1,
198 extents.y2 - extents.y1,
199 glyphCache, n_glyphs, pglyphs);
200 }
201 else {
202 pixman_composite_glyphs_no_mask(op, srcImage, dstImage,
203 xSrc + srcXoff - xDst, ySrc + srcYoff - yDst,
204 dstXoff, dstYoff,
205 glyphCache, n_glyphs, pglyphs);
206 }
207
208 free_pixman_pict(pDst, dstImage);
209
210 out_free_src:
211 free_pixman_pict(pSrc, srcImage);
212
213 out:
214 pixman_glyph_cache_thaw(glyphCache);
215 if (pglyphs != stack_glyphs)
216 free(pglyphs);
217 }
218
219 static pixman_image_t *
220 create_solid_fill_image(PicturePtr pict)
221 {
222 PictSolidFill *solid = &pict->pSourcePict->solidFill;
223 pixman_color_t color;
224 CARD32 a, r, g, b;
225
226 a = (solid->color & 0xff000000) >> 24;
227 r = (solid->color & 0x00ff0000) >> 16;
228 g = (solid->color & 0x0000ff00) >> 8;
229 b = (solid->color & 0x000000ff) >> 0;
230
231 color.alpha = (a << 8) | a;
232 color.red = (r << 8) | r;
233 color.green = (g << 8) | g;
234 color.blue = (b << 8) | b;
235
236 return pixman_image_create_solid_fill(&color);
237 }
238
239 static pixman_image_t *
240 create_linear_gradient_image(PictGradient * gradient)
241 {
242 PictLinearGradient *linear = (PictLinearGradient *) gradient;
243 pixman_point_fixed_t p1;
244 pixman_point_fixed_t p2;
245
246 p1.x = linear->p1.x;
247 p1.y = linear->p1.y;
248 p2.x = linear->p2.x;
249 p2.y = linear->p2.y;
250
251 return pixman_image_create_linear_gradient(&p1, &p2,
252 (pixman_gradient_stop_t *)
253 gradient->stops,
254 gradient->nstops);
255 }
256
257 static pixman_image_t *
258 create_radial_gradient_image(PictGradient * gradient)
259 {
260 PictRadialGradient *radial = (PictRadialGradient *) gradient;
261 pixman_point_fixed_t c1;
262 pixman_point_fixed_t c2;
263
264 c1.x = radial->c1.x;
265 c1.y = radial->c1.y;
266 c2.x = radial->c2.x;
267 c2.y = radial->c2.y;
268
269 return pixman_image_create_radial_gradient(&c1, &c2, radial->c1.radius,
270 radial->c2.radius,
271 (pixman_gradient_stop_t *)
272 gradient->stops,
273 gradient->nstops);
274 }
275
276 static pixman_image_t *
277 create_conical_gradient_image(PictGradient * gradient)
278 {
279 PictConicalGradient *conical = (PictConicalGradient *) gradient;
280 pixman_point_fixed_t center;
281
282 center.x = conical->center.x;
283 center.y = conical->center.y;
284
285 return pixman_image_create_conical_gradient(&center, conical->angle,
286 (pixman_gradient_stop_t *)
287 gradient->stops,
288 gradient->nstops);
289 }
290
291 static pixman_image_t *
292 create_bits_picture(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
293 {
294 PixmapPtr pixmap;
295 FbBits *bits;
296 FbStride stride;
297 int bpp;
298 pixman_image_t *image;
299
300 fbGetDrawablePixmap(pict->pDrawable, pixmap, *xoff, *yoff);
301 fbGetPixmapBitsData(pixmap, bits, stride, bpp);
302
303 image = pixman_image_create_bits((pixman_format_code_t) pict->format,
304 pixmap->drawable.width,
305 pixmap->drawable.height, (uint32_t *) bits,
306 stride * sizeof(FbStride));
307
308 if (!image)
309 return NULL;
310
311 #ifdef FB_ACCESS_WRAPPER
312 #if FB_SHIFT==5
313
314 pixman_image_set_accessors(image,
315 (pixman_read_memory_func_t) wfbReadMemory,
316 (pixman_write_memory_func_t) wfbWriteMemory);
317
318 #else
319
320 #error The pixman library only works when FbBits is 32 bits wide
321
322 #endif
323 #endif
324
325 /* pCompositeClip is undefined for source pictures, so
326 * only set the clip region for pictures with drawables
327 */
328 if (has_clip) {
329 if (pict->clientClipType != CT_NONE)
330 pixman_image_set_has_client_clip(image, TRUE);
331
332 if (*xoff || *yoff)
333 pixman_region_translate(pict->pCompositeClip, *xoff, *yoff);
334
335 pixman_image_set_clip_region(image, pict->pCompositeClip);
336
337 if (*xoff || *yoff)
338 pixman_region_translate(pict->pCompositeClip, -*xoff, -*yoff);
339 }
340
341 /* Indexed table */
342 if (pict->pFormat->index.devPrivate)
343 pixman_image_set_indexed(image, pict->pFormat->index.devPrivate);
344
345 /* Add in drawable origin to position within the image */
346 *xoff += pict->pDrawable->x;
347 *yoff += pict->pDrawable->y;
348
349 return image;
350 }
351
352 static pixman_image_t *image_from_pict_internal(PicturePtr pict, Bool has_clip,
353 int *xoff, int *yoff,
354 Bool is_alpha_map);
355
356 static void
357 set_image_properties(pixman_image_t * image, PicturePtr pict, Bool has_clip,
358 int *xoff, int *yoff, Bool is_alpha_map)
359 {
360 pixman_repeat_t repeat;
361 pixman_filter_t filter;
362
363 if (pict->transform) {
364 /* For source images, adjust the transform to account
365 * for the drawable offset within the pixman image,
366 * then set the offset to 0 as it will be used
367 * to compute positions within the transformed image.
368 */
369 if (!has_clip) {
370 struct pixman_transform adjusted;
371
372 adjusted = *pict->transform;
373 pixman_transform_translate(&adjusted,
374 NULL,
375 pixman_int_to_fixed(*xoff),
376 pixman_int_to_fixed(*yoff));
377 pixman_image_set_transform(image, &adjusted);
378 *xoff = 0;
379 *yoff = 0;
380 }
381 else
382 pixman_image_set_transform(image, pict->transform);
383 }
384
385 switch (pict->repeatType) {
386 default:
387 case RepeatNone:
388 repeat = PIXMAN_REPEAT_NONE;
389 break;
390
391 case RepeatPad:
392 repeat = PIXMAN_REPEAT_PAD;
393 break;
394
395 case RepeatNormal:
396 repeat = PIXMAN_REPEAT_NORMAL;
397 break;
398
399 case RepeatReflect:
400 repeat = PIXMAN_REPEAT_REFLECT;
401 break;
402 }
403
404 pixman_image_set_repeat(image, repeat);
405
406 /* Fetch alpha map unless 'pict' is being used
407 * as the alpha map for this operation
408 */
409 if (pict->alphaMap && !is_alpha_map) {
410 int alpha_xoff, alpha_yoff;
411 pixman_image_t *alpha_map =
412 image_from_pict_internal(pict->alphaMap, FALSE, &alpha_xoff,
413 &alpha_yoff, TRUE);
414
415 pixman_image_set_alpha_map(image, alpha_map, pict->alphaOrigin.x,
416 pict->alphaOrigin.y);
417
418 free_pixman_pict(pict->alphaMap, alpha_map);
419 }
420
421 pixman_image_set_component_alpha(image, pict->componentAlpha);
422
423 switch (pict->filter) {
424 default:
425 case PictFilterNearest:
426 case PictFilterFast:
427 filter = PIXMAN_FILTER_NEAREST;
428 break;
429
430 case PictFilterBilinear:
431 case PictFilterGood:
432 filter = PIXMAN_FILTER_BILINEAR;
433 break;
434
435 case PictFilterConvolution:
436 filter = PIXMAN_FILTER_CONVOLUTION;
437 break;
438 }
439
440 pixman_image_set_filter(image, filter,
441 (pixman_fixed_t *) pict->filter_params,
442 pict->filter_nparams);
443 pixman_image_set_source_clipping(image, TRUE);
444 }
445
446 static pixman_image_t *
447 image_from_pict_internal(PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
448 Bool is_alpha_map)
449 {
450 pixman_image_t *image = NULL;
451
452 if (!pict)
453 return NULL;
454
455 if (pict->pDrawable) {
456 image = create_bits_picture(pict, has_clip, xoff, yoff);
457 }
458 else if (pict->pSourcePict) {
459 SourcePict *sp = pict->pSourcePict;
460
461 if (sp->type == SourcePictTypeSolidFill) {
462 image = create_solid_fill_image(pict);
463 }
464 else {
465 PictGradient *gradient = &pict->pSourcePict->gradient;
466
467 if (sp->type == SourcePictTypeLinear)
468 image = create_linear_gradient_image(gradient);
469 else if (sp->type == SourcePictTypeRadial)
470 image = create_radial_gradient_image(gradient);
471 else if (sp->type == SourcePictTypeConical)
472 image = create_conical_gradient_image(gradient);
473 }
474 *xoff = *yoff = 0;
475 }
476
477 if (image)
478 set_image_properties(image, pict, has_clip, xoff, yoff, is_alpha_map);
479
480 return image;
481 }
482
483 pixman_image_t *
484 image_from_pict(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
485 {
486 return image_from_pict_internal(pict, has_clip, xoff, yoff, FALSE);
487 }
488
489 void
490 free_pixman_pict(PicturePtr pict, pixman_image_t * image)
491 {
492 if (image && pixman_image_unref(image) && pict->pDrawable)
493 fbFinishAccess(pict->pDrawable);
494 }
495
496 Bool
497 fbPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
498 {
499
500 PictureScreenPtr ps;
501
502 if (!miPictureInit(pScreen, formats, nformats))
503 return FALSE;
504 ps = GetPictureScreen(pScreen);
505 ps->Composite = fbComposite;
506 ps->Glyphs = fbGlyphs;
507 ps->UnrealizeGlyph = fbUnrealizeGlyph;
508 ps->CompositeRects = miCompositeRects;
509 ps->RasterizeTrapezoid = fbRasterizeTrapezoid;
510 ps->Trapezoids = fbTrapezoids;
511 ps->AddTraps = fbAddTraps;
512 ps->AddTriangles = fbAddTriangles;
513 ps->Triangles = fbTriangles;
514
515 return TRUE;
516 }