xref: /qemu/ui/qemu-pixman.c (revision d0fb9657)
1 /*
2  * This work is licensed under the terms of the GNU GPL, version 2 or later.
3  * See the COPYING file in the top-level directory.
4  */
5 
6 #include "qemu/osdep.h"
7 #include "ui/console.h"
8 #include "standard-headers/drm/drm_fourcc.h"
9 
10 PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format)
11 {
12     PixelFormat pf;
13     uint8_t bpp;
14 
15     bpp = pf.bits_per_pixel = PIXMAN_FORMAT_BPP(format);
16     pf.bytes_per_pixel = PIXMAN_FORMAT_BPP(format) / 8;
17     pf.depth = PIXMAN_FORMAT_DEPTH(format);
18 
19     pf.abits = PIXMAN_FORMAT_A(format);
20     pf.rbits = PIXMAN_FORMAT_R(format);
21     pf.gbits = PIXMAN_FORMAT_G(format);
22     pf.bbits = PIXMAN_FORMAT_B(format);
23 
24     switch (PIXMAN_FORMAT_TYPE(format)) {
25     case PIXMAN_TYPE_ARGB:
26         pf.ashift = pf.bbits + pf.gbits + pf.rbits;
27         pf.rshift = pf.bbits + pf.gbits;
28         pf.gshift = pf.bbits;
29         pf.bshift = 0;
30         break;
31     case PIXMAN_TYPE_ABGR:
32         pf.ashift = pf.rbits + pf.gbits + pf.bbits;
33         pf.bshift = pf.rbits + pf.gbits;
34         pf.gshift = pf.rbits;
35         pf.rshift = 0;
36         break;
37     case PIXMAN_TYPE_BGRA:
38         pf.bshift = bpp - pf.bbits;
39         pf.gshift = bpp - (pf.bbits + pf.gbits);
40         pf.rshift = bpp - (pf.bbits + pf.gbits + pf.rbits);
41         pf.ashift = 0;
42         break;
43     case PIXMAN_TYPE_RGBA:
44         pf.rshift = bpp - pf.rbits;
45         pf.gshift = bpp - (pf.rbits + pf.gbits);
46         pf.bshift = bpp - (pf.rbits + pf.gbits + pf.bbits);
47         pf.ashift = 0;
48         break;
49     default:
50         g_assert_not_reached();
51         break;
52     }
53 
54     pf.amax = (1 << pf.abits) - 1;
55     pf.rmax = (1 << pf.rbits) - 1;
56     pf.gmax = (1 << pf.gbits) - 1;
57     pf.bmax = (1 << pf.bbits) - 1;
58     pf.amask = pf.amax << pf.ashift;
59     pf.rmask = pf.rmax << pf.rshift;
60     pf.gmask = pf.gmax << pf.gshift;
61     pf.bmask = pf.bmax << pf.bshift;
62 
63     return pf;
64 }
65 
66 pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian)
67 {
68     if (native_endian) {
69         switch (bpp) {
70         case 15:
71             return PIXMAN_x1r5g5b5;
72         case 16:
73             return PIXMAN_r5g6b5;
74         case 24:
75             return PIXMAN_r8g8b8;
76         case 32:
77             return PIXMAN_x8r8g8b8;
78         }
79     } else {
80         switch (bpp) {
81         case 24:
82             return PIXMAN_b8g8r8;
83         case 32:
84             return PIXMAN_b8g8r8x8;
85         break;
86         }
87     }
88     return 0;
89 }
90 
91 /* Note: drm is little endian, pixman is native endian */
92 static const struct {
93     uint32_t drm_format;
94     pixman_format_code_t pixman_format;
95 } drm_format_pixman_map[] = {
96     { DRM_FORMAT_RGB888,   PIXMAN_LE_r8g8b8   },
97     { DRM_FORMAT_ARGB8888, PIXMAN_LE_a8r8g8b8 },
98     { DRM_FORMAT_XRGB8888, PIXMAN_LE_x8r8g8b8 }
99 };
100 
101 pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format)
102 {
103     int i;
104 
105     for (i = 0; i < ARRAY_SIZE(drm_format_pixman_map); i++) {
106         if (drm_format == drm_format_pixman_map[i].drm_format) {
107             return drm_format_pixman_map[i].pixman_format;
108         }
109     }
110     return 0;
111 }
112 
113 uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman_format)
114 {
115     int i;
116 
117     for (i = 0; i < ARRAY_SIZE(drm_format_pixman_map); i++) {
118         if (pixman_format == drm_format_pixman_map[i].pixman_format) {
119             return drm_format_pixman_map[i].drm_format;
120         }
121     }
122     return 0;
123 }
124 
125 int qemu_pixman_get_type(int rshift, int gshift, int bshift)
126 {
127     int type = PIXMAN_TYPE_OTHER;
128 
129     if (rshift > gshift && gshift > bshift) {
130         if (bshift == 0) {
131             type = PIXMAN_TYPE_ARGB;
132         } else {
133             type = PIXMAN_TYPE_RGBA;
134         }
135     } else if (rshift < gshift && gshift < bshift) {
136         if (rshift == 0) {
137             type = PIXMAN_TYPE_ABGR;
138         } else {
139             type = PIXMAN_TYPE_BGRA;
140         }
141     }
142     return type;
143 }
144 
145 pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf)
146 {
147     pixman_format_code_t format;
148     int type;
149 
150     type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift);
151     format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
152                            pf->abits, pf->rbits, pf->gbits, pf->bbits);
153     if (!pixman_format_supported_source(format)) {
154         return 0;
155     }
156     return format;
157 }
158 
159 /*
160  * Return true for known-good pixman conversions.
161  *
162  * UIs using pixman for format conversion can hook this into
163  * DisplayChangeListenerOps->dpy_gfx_check_format
164  */
165 bool qemu_pixman_check_format(DisplayChangeListener *dcl,
166                               pixman_format_code_t format)
167 {
168     switch (format) {
169     /* 32 bpp */
170     case PIXMAN_x8r8g8b8:
171     case PIXMAN_a8r8g8b8:
172     case PIXMAN_b8g8r8x8:
173     case PIXMAN_b8g8r8a8:
174     /* 24 bpp */
175     case PIXMAN_r8g8b8:
176     case PIXMAN_b8g8r8:
177     /* 16 bpp */
178     case PIXMAN_x1r5g5b5:
179     case PIXMAN_r5g6b5:
180         return true;
181     default:
182         return false;
183     }
184 }
185 
186 pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format,
187                                            int width)
188 {
189     pixman_image_t *image = pixman_image_create_bits(format, width, 1, NULL, 0);
190     assert(image != NULL);
191     return image;
192 }
193 
194 /* fill linebuf from framebuffer */
195 void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb,
196                               int width, int x, int y)
197 {
198     pixman_image_composite(PIXMAN_OP_SRC, fb, NULL, linebuf,
199                            x, y, 0, 0, 0, 0, width, 1);
200 }
201 
202 /* copy linebuf to framebuffer */
203 void qemu_pixman_linebuf_copy(pixman_image_t *fb, int width, int x, int y,
204                               pixman_image_t *linebuf)
205 {
206     pixman_image_composite(PIXMAN_OP_SRC, linebuf, NULL, fb,
207                            0, 0, 0, 0, x, y, width, 1);
208 }
209 
210 pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format,
211                                           pixman_image_t *image)
212 {
213     return pixman_image_create_bits(format,
214                                     pixman_image_get_width(image),
215                                     pixman_image_get_height(image),
216                                     NULL,
217                                     pixman_image_get_stride(image));
218 }
219 
220 void qemu_pixman_image_unref(pixman_image_t *image)
221 {
222     if (image == NULL) {
223         return;
224     }
225     pixman_image_unref(image);
226 }
227 
228 pixman_color_t qemu_pixman_color(PixelFormat *pf, uint32_t color)
229 {
230     pixman_color_t c;
231 
232     c.red   = ((color & pf->rmask) >> pf->rshift) << (16 - pf->rbits);
233     c.green = ((color & pf->gmask) >> pf->gshift) << (16 - pf->gbits);
234     c.blue  = ((color & pf->bmask) >> pf->bshift) << (16 - pf->bbits);
235     c.alpha = ((color & pf->amask) >> pf->ashift) << (16 - pf->abits);
236     return c;
237 }
238 
239 pixman_image_t *qemu_pixman_glyph_from_vgafont(int height, const uint8_t *font,
240                                                unsigned int ch)
241 {
242     pixman_image_t *glyph;
243     uint8_t *data;
244     bool bit;
245     int x, y;
246 
247     glyph = pixman_image_create_bits(PIXMAN_a8, 8, height,
248                                      NULL, 0);
249     data = (uint8_t *)pixman_image_get_data(glyph);
250 
251     font += height * ch;
252     for (y = 0; y < height; y++, font++) {
253         for (x = 0; x < 8; x++, data++) {
254             bit = (*font) & (1 << (7-x));
255             *data = bit ? 0xff : 0x00;
256         }
257     }
258     return glyph;
259 }
260 
261 void qemu_pixman_glyph_render(pixman_image_t *glyph,
262                               pixman_image_t *surface,
263                               pixman_color_t *fgcol,
264                               pixman_color_t *bgcol,
265                               int x, int y, int cw, int ch)
266 {
267     pixman_image_t *ifg = pixman_image_create_solid_fill(fgcol);
268     pixman_image_t *ibg = pixman_image_create_solid_fill(bgcol);
269 
270     pixman_image_composite(PIXMAN_OP_SRC, ibg, NULL, surface,
271                            0, 0, 0, 0,
272                            cw * x, ch * y,
273                            cw, ch);
274     pixman_image_composite(PIXMAN_OP_OVER, ifg, glyph, surface,
275                            0, 0, 0, 0,
276                            cw * x, ch * y,
277                            cw, ch);
278     pixman_image_unref(ifg);
279     pixman_image_unref(ibg);
280 }
281