From 903721a6215f474787b5daf02761fbcb1d3a0bb5 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 4 Apr 2017 17:54:20 +0100 Subject: [PATCH] libweston: Add pixel-format helpers Rather than duplicating knowledge of pixel formats across several components, create a custom central repository. Signed-off-by: Daniel Stone [Pekka: fix include paths and two copy-pastas] Reviewed-by: Pekka Paalanen --- Makefile.am | 5 +- libweston/pixel-formats.c | 430 ++++++++++++++++++++++++++++++++++++++ libweston/pixel-formats.h | 194 +++++++++++++++++ 3 files changed, 628 insertions(+), 1 deletion(-) create mode 100644 libweston/pixel-formats.c create mode 100644 libweston/pixel-formats.h diff --git a/Makefile.am b/Makefile.am index 8ecc90cd..94b1c143 100644 --- a/Makefile.am +++ b/Makefile.am @@ -71,7 +71,8 @@ install-libweston_moduleLTLIBRARIES install-moduleLTLIBRARIES: install-libLTLIBR lib_LTLIBRARIES = libweston-@LIBWESTON_MAJOR@.la libweston_@LIBWESTON_MAJOR@_la_CPPFLAGS = $(AM_CPPFLAGS) -DIN_WESTON -libweston_@LIBWESTON_MAJOR@_la_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS) +libweston_@LIBWESTON_MAJOR@_la_CFLAGS = $(AM_CFLAGS) \ + $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS) $(LIBDRM_CFLAGS) libweston_@LIBWESTON_MAJOR@_la_LIBADD = $(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \ $(DLOPEN_LIBS) -lm $(CLOCK_GETTIME_LIBS) \ $(LIBINPUT_BACKEND_LIBS) libshared.la @@ -105,6 +106,8 @@ libweston_@LIBWESTON_MAJOR@_la_SOURCES = \ libweston/timeline-object.h \ libweston/linux-dmabuf.c \ libweston/linux-dmabuf.h \ + libweston/pixel-formats.c \ + libweston/pixel-formats.h \ shared/helpers.h \ shared/matrix.c \ shared/matrix.h \ diff --git a/libweston/pixel-formats.c b/libweston/pixel-formats.c new file mode 100644 index 00000000..df84a9f3 --- /dev/null +++ b/libweston/pixel-formats.c @@ -0,0 +1,430 @@ +/* + * Copyright © 2016 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Daniel Stone + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "helpers.h" +#include "wayland-util.h" +#include "pixel-formats.h" + +#if ENABLE_EGL +#include +#include +#include +#include +#define GL_FORMAT(fmt) .gl_format = (fmt) +#define GL_TYPE(type) .gl_type = (type) +#define SAMPLER_TYPE(type) .sampler_type = (type) +#else +#define GL_FORMAT(fmt) .gl_format = 0 +#define GL_TYPE(type) .gl_type = 0 +#define SAMPLER_TYPE(type) .sampler_type = 0 +#endif + +#include "weston-egl-ext.h" + +/** + * Table of DRM formats supported by Weston; RGB, ARGB and YUV formats are + * supported. Indexed/greyscale formats, and formats not containing complete + * colour channels, are not supported. + */ +static const struct pixel_format_info pixel_format_table[] = { + { + .format = DRM_FORMAT_XRGB4444, + }, + { + .format = DRM_FORMAT_ARGB4444, + .opaque_substitute = DRM_FORMAT_XRGB4444, + }, + { + .format = DRM_FORMAT_XBGR4444, + }, + { + .format = DRM_FORMAT_ABGR4444, + .opaque_substitute = DRM_FORMAT_XBGR4444, + }, + { + .format = DRM_FORMAT_RGBX4444, +# if __BYTE_ORDER == __LITTLE_ENDIAN + GL_FORMAT(GL_RGBA), + GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4), +#endif + }, + { + .format = DRM_FORMAT_RGBA4444, + .opaque_substitute = DRM_FORMAT_RGBX4444, +# if __BYTE_ORDER == __LITTLE_ENDIAN + GL_FORMAT(GL_RGBA), + GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4), +#endif + }, + { + .format = DRM_FORMAT_BGRX4444, + }, + { + .format = DRM_FORMAT_BGRA4444, + .opaque_substitute = DRM_FORMAT_BGRX4444, + }, + { + .format = DRM_FORMAT_XRGB1555, + .depth = 15, + .bpp = 16, + }, + { + .format = DRM_FORMAT_ARGB1555, + .opaque_substitute = DRM_FORMAT_XRGB1555, + }, + { + .format = DRM_FORMAT_XBGR1555, + }, + { + .format = DRM_FORMAT_ABGR1555, + .opaque_substitute = DRM_FORMAT_XBGR1555, + }, + { + .format = DRM_FORMAT_RGBX5551, +# if __BYTE_ORDER == __LITTLE_ENDIAN + GL_FORMAT(GL_RGBA), + GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1), +#endif + }, + { + .format = DRM_FORMAT_RGBA5551, + .opaque_substitute = DRM_FORMAT_RGBX5551, +# if __BYTE_ORDER == __LITTLE_ENDIAN + GL_FORMAT(GL_RGBA), + GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1), +#endif + }, + { + .format = DRM_FORMAT_BGRX5551, + }, + { + .format = DRM_FORMAT_BGRA5551, + .opaque_substitute = DRM_FORMAT_BGRX5551, + }, + { + .format = DRM_FORMAT_RGB565, + .depth = 16, + .bpp = 16, +# if __BYTE_ORDER == __LITTLE_ENDIAN + GL_FORMAT(GL_RGB), + GL_TYPE(GL_UNSIGNED_SHORT_5_6_5), +#endif + }, + { + .format = DRM_FORMAT_BGR565, + }, + { + .format = DRM_FORMAT_RGB888, + }, + { + .format = DRM_FORMAT_BGR888, + GL_FORMAT(GL_RGB), + GL_TYPE(GL_UNSIGNED_BYTE), + }, + { + .format = DRM_FORMAT_XRGB8888, + .depth = 24, + .bpp = 32, + GL_FORMAT(GL_BGRA_EXT), + GL_TYPE(GL_UNSIGNED_BYTE), + }, + { + .format = DRM_FORMAT_ARGB8888, + .opaque_substitute = DRM_FORMAT_XRGB8888, + .depth = 32, + .bpp = 32, + GL_FORMAT(GL_BGRA_EXT), + GL_TYPE(GL_UNSIGNED_BYTE), + }, + { + .format = DRM_FORMAT_XBGR8888, + GL_FORMAT(GL_RGBA), + GL_TYPE(GL_UNSIGNED_BYTE), + }, + { + .format = DRM_FORMAT_ABGR8888, + .opaque_substitute = DRM_FORMAT_XBGR8888, + GL_FORMAT(GL_RGBA), + GL_TYPE(GL_UNSIGNED_BYTE), + }, + { + .format = DRM_FORMAT_RGBX8888, + }, + { + .format = DRM_FORMAT_RGBA8888, + .opaque_substitute = DRM_FORMAT_RGBX8888, + }, + { + .format = DRM_FORMAT_BGRX8888, + }, + { + .format = DRM_FORMAT_BGRA8888, + .opaque_substitute = DRM_FORMAT_BGRX8888, + }, + { + .format = DRM_FORMAT_XRGB2101010, + .depth = 30, + .bpp = 32, + }, + { + .format = DRM_FORMAT_ARGB2101010, + .opaque_substitute = DRM_FORMAT_XRGB2101010, + }, + { + .format = DRM_FORMAT_XBGR2101010, +# if __BYTE_ORDER == __LITTLE_ENDIAN + GL_FORMAT(GL_RGBA), + GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT), +#endif + }, + { + .format = DRM_FORMAT_ABGR2101010, + .opaque_substitute = DRM_FORMAT_XBGR2101010, +# if __BYTE_ORDER == __LITTLE_ENDIAN + GL_FORMAT(GL_RGBA), + GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT), +#endif + }, + { + .format = DRM_FORMAT_RGBX1010102, + }, + { + .format = DRM_FORMAT_RGBA1010102, + .opaque_substitute = DRM_FORMAT_RGBX1010102, + }, + { + .format = DRM_FORMAT_BGRX1010102, + }, + { + .format = DRM_FORMAT_BGRA1010102, + .opaque_substitute = DRM_FORMAT_BGRX1010102, + }, + { + .format = DRM_FORMAT_YUYV, + SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL), + .num_planes = 1, + .hsub = 2, + }, + { + .format = DRM_FORMAT_YVYU, + SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL), + .num_planes = 1, + .chroma_order = ORDER_VU, + .hsub = 2, + }, + { + .format = DRM_FORMAT_UYVY, + SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL), + .num_planes = 1, + .luma_chroma_order = ORDER_CHROMA_LUMA, + .hsub = 2, + }, + { + .format = DRM_FORMAT_VYUY, + SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL), + .num_planes = 1, + .luma_chroma_order = ORDER_CHROMA_LUMA, + .chroma_order = ORDER_VU, + .hsub = 2, + }, + { + .format = DRM_FORMAT_NV12, + SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), + .num_planes = 2, + .hsub = 2, + .vsub = 2, + }, + { + .format = DRM_FORMAT_NV21, + SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), + .num_planes = 2, + .chroma_order = ORDER_VU, + .hsub = 2, + .vsub = 2, + }, + { + .format = DRM_FORMAT_NV16, + SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), + .num_planes = 2, + .hsub = 2, + .vsub = 1, + }, + { + .format = DRM_FORMAT_NV61, + SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), + .num_planes = 2, + .chroma_order = ORDER_VU, + .hsub = 2, + .vsub = 1, + }, + { + .format = DRM_FORMAT_NV24, + SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), + .num_planes = 2, + }, + { + .format = DRM_FORMAT_NV42, + SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), + .num_planes = 2, + .chroma_order = ORDER_VU, + }, + { + .format = DRM_FORMAT_YUV410, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + .hsub = 4, + .vsub = 4, + }, + { + .format = DRM_FORMAT_YVU410, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + .chroma_order = ORDER_VU, + .hsub = 4, + .vsub = 4, + }, + { + .format = DRM_FORMAT_YUV411, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + .hsub = 4, + .vsub = 1, + }, + { + .format = DRM_FORMAT_YVU411, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + .chroma_order = ORDER_VU, + .hsub = 4, + .vsub = 1, + }, + { + .format = DRM_FORMAT_YUV420, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + .hsub = 2, + .vsub = 2, + }, + { + .format = DRM_FORMAT_YVU420, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + .chroma_order = ORDER_VU, + .hsub = 2, + .vsub = 2, + }, + { + .format = DRM_FORMAT_YUV422, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + .hsub = 2, + .vsub = 1, + }, + { + .format = DRM_FORMAT_YVU422, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + .chroma_order = ORDER_VU, + .hsub = 2, + .vsub = 1, + }, + { + .format = DRM_FORMAT_YUV444, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + }, + { + .format = DRM_FORMAT_YVU444, + SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), + .num_planes = 3, + .chroma_order = ORDER_VU, + }, +}; + +WL_EXPORT const struct pixel_format_info * +pixel_format_get_info(uint32_t format) +{ + unsigned int i; + + for (i = 0; i < ARRAY_LENGTH(pixel_format_table); i++) { + if (pixel_format_table[i].format == format) + return &pixel_format_table[i]; + } + + return NULL; +} + +WL_EXPORT unsigned int +pixel_format_get_plane_count(const struct pixel_format_info *info) +{ + return info->num_planes ? info->num_planes : 1; +} + +WL_EXPORT bool +pixel_format_is_opaque(const struct pixel_format_info *info) +{ + return !info->opaque_substitute; +} + +WL_EXPORT const struct pixel_format_info * +pixel_format_get_opaque_substitute(const struct pixel_format_info *info) +{ + if (!info->opaque_substitute) + return info; + else + return pixel_format_get_info(info->opaque_substitute); +} + +WL_EXPORT unsigned int +pixel_format_width_for_plane(const struct pixel_format_info *info, + unsigned int plane, + unsigned int width) +{ + /* We don't support any formats where the first plane is subsampled. */ + if (plane == 0 || !info->hsub) + return width; + + return width / info->hsub; +} + +WL_EXPORT unsigned int +pixel_format_height_for_plane(const struct pixel_format_info *info, + unsigned int plane, + unsigned int height) +{ + /* We don't support any formats where the first plane is subsampled. */ + if (plane == 0 || !info->vsub) + return height; + + return height / info->vsub; +} diff --git a/libweston/pixel-formats.h b/libweston/pixel-formats.h new file mode 100644 index 00000000..b16aae32 --- /dev/null +++ b/libweston/pixel-formats.h @@ -0,0 +1,194 @@ +/* + * Copyright © 2016 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Daniel Stone + */ + +#include +#include + +/** + * Contains information about pixel formats, mapping format codes from + * wl_shm and drm_fourcc.h (which are deliberately identical, but for the + * special cases of WL_SHM_ARGB8888 and WL_SHM_XRGB8888) into various + * sets of information. Helper functions are provided for dealing with these + * raw structures. + */ +struct pixel_format_info { + /** DRM/wl_shm format code */ + uint32_t format; + + /** If non-zero, number of planes in base (non-modified) format. */ + int num_planes; + + /** If format contains alpha channel, opaque equivalent of format, + * i.e. alpha channel replaced with X. */ + uint32_t opaque_substitute; + + /** How the format should be sampled, expressed in terms of tokens + * from the EGL_WL_bind_wayland_display extension. If not set, + * assumed to be either RGB or RGBA, depending on whether or not + * the format contains an alpha channel. The samplers may still + * return alpha even for opaque formats; users must manually set + * the alpha channel to 1.0 (or ignore it) if the format is + * opaque. */ + uint32_t sampler_type; + + /** GL format, if data can be natively/directly uploaded. Note that + * whilst DRM formats are little-endian unless explicitly specified, + * (i.e. DRM_FORMAT_ARGB8888 is stored BGRA as sequential bytes in + * memory), GL uses the sequential byte order, so that format maps to + * GL_BGRA_EXT plus GL_UNSIGNED_BYTE. To add to the confusion, the + * explicitly-sized types (e.g. GL_UNSIGNED_SHORT_5_5_5_1) read in + * machine-endian order, so for these types, the correspondence + * depends on endianness. */ + int gl_format; + + /** GL data type, if data can be natively/directly uploaded. */ + int gl_type; + + /** If set, this format can be used with the legacy drmModeAddFB() + * function (not AddFB2), using this and the bpp member. */ + int depth; + + /** See 'depth' member above. */ + int bpp; + + /** Horizontal subsampling; if non-zero, divide the width by this + * member to obtain the number of columns in the source buffer for + * secondary planes only. Stride is not affected by horizontal + * subsampling. */ + int hsub; + + /** Vertical subsampling; if non-zero, divide the height by this + * member to obtain the number of rows in the source buffer for + * secondary planes only. */ + int vsub; + + /* Ordering of chroma components. */ + enum { + ORDER_UV = 0, + ORDER_VU, + } chroma_order; + + /* If packed YUV (num_planes == 1), ordering of luma/chroma + * components. */ + enum { + ORDER_LUMA_CHROMA = 0, + ORDER_CHROMA_LUMA, + } luma_chroma_order; +}; + +/** + * Get pixel format information for a DRM format code + * + * Given a DRM format code, return a pixel format info structure describing + * the properties of that format. + * + * @param format DRM format code to get info for + * @returns A pixel format structure (must not be freed), or NULL if the + * format could not be found + */ +const struct pixel_format_info *pixel_format_get_info(uint32_t format); + +/** + * Get number of planes used by a pixel format + * + * Given a pixel format info structure, return the number of planes + * required for a buffer. Note that this is not necessarily identical to + * the number of samplers required to be bound, as two views into a single + * plane are sometimes required. + * + * @param format Pixel format info structure + * @returns Number of planes required for the format + */ +unsigned int +pixel_format_get_plane_count(const struct pixel_format_info *format); + +/** + * Determine if a pixel format is opaque or contains alpha + * + * Returns whether or not the pixel format is opaque, or contains a + * significant alpha channel. Note that the suggested EGL sampler type may + * still sample undefined data into the alpha channel; users must consider + * alpha as 1.0 if the format is opaque, and not rely on the sampler to + * return this when sampling from the alpha channel. + * + * @param format Pixel format info structure + * @returns True if the format is opaque, or false if it has significant alpha + */ +bool pixel_format_is_opaque(const struct pixel_format_info *format); + +/** + * Get compatible opaque equivalent for a format + * + * Given a pixel format info structure, return a format which is wholly + * compatible with the input format, but opaque, ignoring the alpha channel. + * If an alpha format is provided, but the content is known to all be opaque, + * then this can be used as a substitute to avoid blending. + * + * If the input format is opaque, this function will return the input format. + * + * @param format Pixel format info structure + * @returns A pixel format info structure for the compatible opaque substitute + */ +const struct pixel_format_info * +pixel_format_get_opaque_substitute(const struct pixel_format_info *format); + +/** + * Return the effective sampling width for a given plane + * + * When horizontal subsampling is effective, a sampler bound to a secondary + * plane must bind the sampler with a smaller effective width. This function + * returns the effective width to use for the sampler, i.e. dividing by hsub. + * + * If horizontal subsampling is not in effect, this will be equal to the + * width. + * + * @param format Pixel format info structure + * @param plane Zero-indexed plane number + * @param width Width of the buffer + * @returns Effective width for sampling + */ +unsigned int +pixel_format_width_for_plane(const struct pixel_format_info *format, + unsigned int plane, + unsigned int width); + +/** + * Return the effective sampling height for a given plane + * + * When vertical subsampling is in effect, a sampler bound to a secondary + * plane must bind the sampler with a smaller effective height. This function + * returns the effective height to use for the sampler, i.e. dividing by vsub. + * + * If vertical subsampling is not in effect, this will be equal to the height. + * + * @param format Pixel format info structure + * @param plane Zero-indexed plane number + * @param height Height of the buffer + * @returns Effective width for sampling + */ +unsigned int +pixel_format_height_for_plane(const struct pixel_format_info *format, + unsigned int plane, + unsigned int height);