@@ -79,10 +79,12 @@ static inline uint32_t swap32(uint32_t x)
#define cpu_to_be16(x) (x)
#define cpu_to_le16(x) swap16(x)
#define cpu_to_le32(x) swap32(x)
+#define fb_foreign_endian(format) (!((format) & DRM_FORMAT_BIG_ENDIAN))
#else
#define cpu_to_be16(x) swap16(x)
#define cpu_to_le16(x) (x)
#define cpu_to_le32(x) (x)
+#define fb_foreign_endian(format) ((format) & DRM_FORMAT_BIG_ENDIAN)
#endif
#define cpu_to_fb16(x) (fb_be ? cpu_to_be16(x) : cpu_to_le16(x))
@@ -1141,6 +1143,32 @@ static void fill_smpte(const struct util_format_info *info, void *planes[3],
}
}
+#if HAVE_CAIRO
+static void byteswap_buffer16(void *mem, unsigned int width, unsigned int height,
+ unsigned int stride)
+{
+ unsigned int x, y;
+
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x)
+ ((uint16_t *)mem)[x] = swap16(((uint16_t *)mem)[x]);
+ mem += stride;
+ }
+}
+
+static void byteswap_buffer32(void *mem, unsigned int width, unsigned int height,
+ unsigned int stride)
+{
+ unsigned int x, y;
+
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x)
+ ((uint32_t *)mem)[x] = swap32(((uint32_t *)mem)[x]);
+ mem += stride;
+ }
+}
+#endif
+
static void make_pwetty(void *data, unsigned int width, unsigned int height,
unsigned int stride, uint32_t format)
{
@@ -1148,6 +1176,8 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height,
cairo_surface_t *surface;
cairo_t *cr;
cairo_format_t cairo_format;
+ bool swap16 = false;
+ bool swap32 = false;
/* we can ignore the order of R,G,B channels */
switch (format) {
@@ -1160,6 +1190,7 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height,
case DRM_FORMAT_RGB565:
case DRM_FORMAT_BGR565:
cairo_format = CAIRO_FORMAT_RGB16_565;
+ swap16 = fb_foreign_endian(format);
break;
#if CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 12)
case DRM_FORMAT_ARGB2101010:
@@ -1167,12 +1198,19 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height,
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_XBGR2101010:
cairo_format = CAIRO_FORMAT_RGB30;
+ swap32 = fb_foreign_endian(format);
break;
#endif
default:
return;
}
+ /* Cairo uses native byte order, so we may have to byteswap before... */
+ if (swap16)
+ byteswap_buffer16(data, width, height, stride);
+ if (swap32)
+ byteswap_buffer32(data, width, height, stride);
+
surface = cairo_image_surface_create_for_data(data,
cairo_format,
width, height,
@@ -1208,6 +1246,12 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height,
}
cairo_destroy(cr);
+
+ /* ... and after */
+ if (swap16)
+ byteswap_buffer16(data, width, height, stride);
+ if (swap32)
+ byteswap_buffer32(data, width, height, stride);
#endif
}