xref: /qemu/ui/qemu-pixman.c (revision efd3dda312129b91986f85976afbda58d40f757f)
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 "qapi/error.h"
8  #include "ui/console.h"
9  #include "qemu/memfd.h"
10  #include "standard-headers/drm/drm_fourcc.h"
11  #include "trace.h"
12  
13  PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format)
14  {
15      PixelFormat pf;
16      uint8_t bpp;
17  
18      bpp = pf.bits_per_pixel = PIXMAN_FORMAT_BPP(format);
19      pf.bytes_per_pixel = PIXMAN_FORMAT_BPP(format) / 8;
20      pf.depth = PIXMAN_FORMAT_DEPTH(format);
21  
22      pf.abits = PIXMAN_FORMAT_A(format);
23      pf.rbits = PIXMAN_FORMAT_R(format);
24      pf.gbits = PIXMAN_FORMAT_G(format);
25      pf.bbits = PIXMAN_FORMAT_B(format);
26  
27      switch (PIXMAN_FORMAT_TYPE(format)) {
28      case PIXMAN_TYPE_ARGB:
29          pf.ashift = pf.bbits + pf.gbits + pf.rbits;
30          pf.rshift = pf.bbits + pf.gbits;
31          pf.gshift = pf.bbits;
32          pf.bshift = 0;
33          break;
34      case PIXMAN_TYPE_ABGR:
35          pf.ashift = pf.rbits + pf.gbits + pf.bbits;
36          pf.bshift = pf.rbits + pf.gbits;
37          pf.gshift = pf.rbits;
38          pf.rshift = 0;
39          break;
40      case PIXMAN_TYPE_BGRA:
41          pf.bshift = bpp - pf.bbits;
42          pf.gshift = bpp - (pf.bbits + pf.gbits);
43          pf.rshift = bpp - (pf.bbits + pf.gbits + pf.rbits);
44          pf.ashift = 0;
45          break;
46      case PIXMAN_TYPE_RGBA:
47          pf.rshift = bpp - pf.rbits;
48          pf.gshift = bpp - (pf.rbits + pf.gbits);
49          pf.bshift = bpp - (pf.rbits + pf.gbits + pf.bbits);
50          pf.ashift = 0;
51          break;
52      default:
53          g_assert_not_reached();
54      }
55  
56      pf.amax = (1 << pf.abits) - 1;
57      pf.rmax = (1 << pf.rbits) - 1;
58      pf.gmax = (1 << pf.gbits) - 1;
59      pf.bmax = (1 << pf.bbits) - 1;
60      pf.amask = pf.amax << pf.ashift;
61      pf.rmask = pf.rmax << pf.rshift;
62      pf.gmask = pf.gmax << pf.gshift;
63      pf.bmask = pf.bmax << pf.bshift;
64  
65      return pf;
66  }
67  
68  pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian)
69  {
70      if (native_endian) {
71          switch (bpp) {
72          case 15:
73              return PIXMAN_x1r5g5b5;
74          case 16:
75              return PIXMAN_r5g6b5;
76          case 24:
77              return PIXMAN_r8g8b8;
78          case 32:
79              return PIXMAN_x8r8g8b8;
80          }
81      } else {
82          switch (bpp) {
83          case 24:
84              return PIXMAN_b8g8r8;
85          case 32:
86              return PIXMAN_b8g8r8x8;
87          break;
88          }
89      }
90      return 0;
91  }
92  
93  /* Note: drm is little endian, pixman is native endian */
94  static const struct {
95      uint32_t drm_format;
96      pixman_format_code_t pixman_format;
97  } drm_format_pixman_map[] = {
98      { DRM_FORMAT_RGB888,   PIXMAN_LE_r8g8b8   },
99      { DRM_FORMAT_ARGB8888, PIXMAN_LE_a8r8g8b8 },
100      { DRM_FORMAT_XRGB8888, PIXMAN_LE_x8r8g8b8 },
101      { DRM_FORMAT_XBGR8888, PIXMAN_LE_x8b8g8r8 },
102      { DRM_FORMAT_ABGR8888, PIXMAN_LE_a8b8g8r8 },
103  };
104  
105  pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format)
106  {
107      int i;
108  
109      for (i = 0; i < ARRAY_SIZE(drm_format_pixman_map); i++) {
110          if (drm_format == drm_format_pixman_map[i].drm_format) {
111              return drm_format_pixman_map[i].pixman_format;
112          }
113      }
114      return 0;
115  }
116  
117  uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman_format)
118  {
119      int i;
120  
121      for (i = 0; i < ARRAY_SIZE(drm_format_pixman_map); i++) {
122          if (pixman_format == drm_format_pixman_map[i].pixman_format) {
123              return drm_format_pixman_map[i].drm_format;
124          }
125      }
126      return 0;
127  }
128  
129  int qemu_pixman_get_type(int rshift, int gshift, int bshift)
130  {
131      int type = PIXMAN_TYPE_OTHER;
132  
133      if (rshift > gshift && gshift > bshift) {
134          if (bshift == 0) {
135              type = PIXMAN_TYPE_ARGB;
136          } else {
137              type = PIXMAN_TYPE_RGBA;
138          }
139      } else if (rshift < gshift && gshift < bshift) {
140          if (rshift == 0) {
141              type = PIXMAN_TYPE_ABGR;
142          } else {
143              type = PIXMAN_TYPE_BGRA;
144          }
145      }
146      return type;
147  }
148  
149  #ifdef CONFIG_PIXMAN
150  pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf)
151  {
152      pixman_format_code_t format;
153      int type;
154  
155      type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift);
156      format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
157                             pf->abits, pf->rbits, pf->gbits, pf->bbits);
158      if (!pixman_format_supported_source(format)) {
159          return 0;
160      }
161      return format;
162  }
163  #endif
164  
165  /*
166   * Return true for known-good pixman conversions.
167   *
168   * UIs using pixman for format conversion can hook this into
169   * DisplayChangeListenerOps->dpy_gfx_check_format
170   */
171  bool qemu_pixman_check_format(DisplayChangeListener *dcl,
172                                pixman_format_code_t format)
173  {
174      switch (format) {
175      /* 32 bpp */
176      case PIXMAN_x8r8g8b8:
177      case PIXMAN_a8r8g8b8:
178      case PIXMAN_b8g8r8x8:
179      case PIXMAN_b8g8r8a8:
180      /* 24 bpp */
181      case PIXMAN_r8g8b8:
182      case PIXMAN_b8g8r8:
183      /* 16 bpp */
184      case PIXMAN_x1r5g5b5:
185      case PIXMAN_r5g6b5:
186          return true;
187      default:
188          return false;
189      }
190  }
191  
192  #ifdef CONFIG_PIXMAN
193  pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format,
194                                             int width)
195  {
196      pixman_image_t *image = pixman_image_create_bits(format, width, 1, NULL, 0);
197      assert(image != NULL);
198      return image;
199  }
200  
201  /* fill linebuf from framebuffer */
202  void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb,
203                                int width, int x, int y)
204  {
205      pixman_image_composite(PIXMAN_OP_SRC, fb, NULL, linebuf,
206                             x, y, 0, 0, 0, 0, width, 1);
207  }
208  
209  pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format,
210                                            pixman_image_t *image)
211  {
212      return pixman_image_create_bits(format,
213                                      pixman_image_get_width(image),
214                                      pixman_image_get_height(image),
215                                      NULL,
216                                      pixman_image_get_stride(image));
217  }
218  #endif
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  #ifdef CONFIG_PIXMAN
229  pixman_image_t *qemu_pixman_glyph_from_vgafont(int height, const uint8_t *font,
230                                                 unsigned int ch)
231  {
232      pixman_image_t *glyph;
233      uint8_t *data;
234      bool bit;
235      int x, y;
236  
237      glyph = pixman_image_create_bits(PIXMAN_a8, 8, height,
238                                       NULL, 0);
239      data = (uint8_t *)pixman_image_get_data(glyph);
240  
241      font += height * ch;
242      for (y = 0; y < height; y++, font++) {
243          for (x = 0; x < 8; x++, data++) {
244              bit = (*font) & (1 << (7-x));
245              *data = bit ? 0xff : 0x00;
246          }
247      }
248      return glyph;
249  }
250  
251  void qemu_pixman_glyph_render(pixman_image_t *glyph,
252                                pixman_image_t *surface,
253                                pixman_color_t *fgcol,
254                                pixman_color_t *bgcol,
255                                int x, int y, int cw, int ch)
256  {
257      pixman_image_t *ifg = pixman_image_create_solid_fill(fgcol);
258      pixman_image_t *ibg = pixman_image_create_solid_fill(bgcol);
259  
260      pixman_image_composite(PIXMAN_OP_SRC, ibg, NULL, surface,
261                             0, 0, 0, 0,
262                             cw * x, ch * y,
263                             cw, ch);
264      pixman_image_composite(PIXMAN_OP_OVER, ifg, glyph, surface,
265                             0, 0, 0, 0,
266                             cw * x, ch * y,
267                             cw, ch);
268      pixman_image_unref(ifg);
269      pixman_image_unref(ibg);
270  }
271  #endif /* CONFIG_PIXMAN */
272  
273  static void *
274  qemu_pixman_shareable_alloc(const char *name, size_t size,
275                              qemu_pixman_shareable *handle,
276                              Error **errp)
277  {
278  #ifdef WIN32
279      return qemu_win32_map_alloc(size, handle, errp);
280  #else
281      return qemu_memfd_alloc(name, size, 0, handle, errp);
282  #endif
283  }
284  
285  static void
286  qemu_pixman_shareable_free(qemu_pixman_shareable handle,
287                             void *ptr, size_t size)
288  {
289  #ifdef WIN32
290      qemu_win32_map_free(ptr, handle, &error_warn);
291  #else
292      qemu_memfd_free(ptr, size, handle);
293  #endif
294  }
295  
296  static void
297  qemu_pixman_shared_image_destroy(pixman_image_t *image, void *data)
298  {
299      qemu_pixman_shareable handle = PTR_TO_SHAREABLE(data);
300      void *ptr = pixman_image_get_data(image);
301      size_t size = pixman_image_get_height(image) * pixman_image_get_stride(image);
302  
303      qemu_pixman_shareable_free(handle, ptr, size);
304  }
305  
306  bool
307  qemu_pixman_image_new_shareable(pixman_image_t **image,
308                                  qemu_pixman_shareable *handle,
309                                  const char *name,
310                                  pixman_format_code_t format,
311                                  int width,
312                                  int height,
313                                  int rowstride_bytes,
314                                  Error **errp)
315  {
316      ERRP_GUARD();
317      size_t size = height * rowstride_bytes;
318      void *bits = NULL;
319  
320      g_return_val_if_fail(image != NULL, false);
321      g_return_val_if_fail(handle != NULL, false);
322  
323      bits = qemu_pixman_shareable_alloc(name, size, handle, errp);
324      if (!bits) {
325          return false;
326      }
327  
328      *image = pixman_image_create_bits(format, width, height, bits, rowstride_bytes);
329      if (!*image) {
330          error_setg(errp, "Failed to allocate image");
331          qemu_pixman_shareable_free(*handle, bits, size);
332          return false;
333      }
334  
335      pixman_image_set_destroy_function(*image,
336                                        qemu_pixman_shared_image_destroy,
337                                        SHAREABLE_TO_PTR(*handle));
338  
339      return true;
340  }
341