/* * Copyright © 2016 Collabora, Ltd. * Copyright (c) 2018 DisplayLink (UK) 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 #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 #define DRM_FORMAT(f) .format = DRM_FORMAT_ ## f, .drm_format_name = #f #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[] = { { DRM_FORMAT(XRGB4444), }, { DRM_FORMAT(ARGB4444), .opaque_substitute = DRM_FORMAT_XRGB4444, }, { DRM_FORMAT(XBGR4444), }, { DRM_FORMAT(ABGR4444), .opaque_substitute = DRM_FORMAT_XBGR4444, }, { DRM_FORMAT(RGBX4444), # if __BYTE_ORDER == __LITTLE_ENDIAN GL_FORMAT(GL_RGBA), GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4), #endif }, { 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 }, { DRM_FORMAT(BGRX4444), }, { DRM_FORMAT(BGRA4444), .opaque_substitute = DRM_FORMAT_BGRX4444, }, { DRM_FORMAT(XRGB1555), .depth = 15, .bpp = 16, }, { DRM_FORMAT(ARGB1555), .opaque_substitute = DRM_FORMAT_XRGB1555, }, { DRM_FORMAT(XBGR1555), }, { DRM_FORMAT(ABGR1555), .opaque_substitute = DRM_FORMAT_XBGR1555, }, { DRM_FORMAT(RGBX5551), # if __BYTE_ORDER == __LITTLE_ENDIAN GL_FORMAT(GL_RGBA), GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1), #endif }, { 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 }, { DRM_FORMAT(BGRX5551), }, { DRM_FORMAT(BGRA5551), .opaque_substitute = DRM_FORMAT_BGRX5551, }, { 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 }, { DRM_FORMAT(BGR565), }, { DRM_FORMAT(RGB888), }, { DRM_FORMAT(BGR888), GL_FORMAT(GL_RGB), GL_TYPE(GL_UNSIGNED_BYTE), }, { DRM_FORMAT(XRGB8888), .depth = 24, .bpp = 32, GL_FORMAT(GL_BGRA_EXT), GL_TYPE(GL_UNSIGNED_BYTE), }, { DRM_FORMAT(ARGB8888), .opaque_substitute = DRM_FORMAT_XRGB8888, .depth = 32, .bpp = 32, GL_FORMAT(GL_BGRA_EXT), GL_TYPE(GL_UNSIGNED_BYTE), }, { DRM_FORMAT(XBGR8888), GL_FORMAT(GL_RGBA), GL_TYPE(GL_UNSIGNED_BYTE), }, { DRM_FORMAT(ABGR8888), .opaque_substitute = DRM_FORMAT_XBGR8888, GL_FORMAT(GL_RGBA), GL_TYPE(GL_UNSIGNED_BYTE), }, { DRM_FORMAT(RGBX8888), }, { DRM_FORMAT(RGBA8888), .opaque_substitute = DRM_FORMAT_RGBX8888, }, { DRM_FORMAT(BGRX8888), }, { DRM_FORMAT(BGRA8888), .opaque_substitute = DRM_FORMAT_BGRX8888, }, { DRM_FORMAT(XRGB2101010), .depth = 30, .bpp = 32, }, { DRM_FORMAT(ARGB2101010), .opaque_substitute = DRM_FORMAT_XRGB2101010, }, { DRM_FORMAT(XBGR2101010), # if __BYTE_ORDER == __LITTLE_ENDIAN GL_FORMAT(GL_RGBA), GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT), #endif }, { 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 }, { DRM_FORMAT(RGBX1010102), }, { DRM_FORMAT(RGBA1010102), .opaque_substitute = DRM_FORMAT_RGBX1010102, }, { DRM_FORMAT(BGRX1010102), }, { DRM_FORMAT(BGRA1010102), .opaque_substitute = DRM_FORMAT_BGRX1010102, }, { DRM_FORMAT(YUYV), SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL), .num_planes = 1, .hsub = 2, }, { DRM_FORMAT(YVYU), SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL), .num_planes = 1, .chroma_order = ORDER_VU, .hsub = 2, }, { DRM_FORMAT(UYVY), SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL), .num_planes = 1, .luma_chroma_order = ORDER_CHROMA_LUMA, .hsub = 2, }, { 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, }, { DRM_FORMAT(NV12), SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), .num_planes = 2, .hsub = 2, .vsub = 2, }, { DRM_FORMAT(NV21), SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), .num_planes = 2, .chroma_order = ORDER_VU, .hsub = 2, .vsub = 2, }, { DRM_FORMAT(NV16), SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), .num_planes = 2, .hsub = 2, .vsub = 1, }, { DRM_FORMAT(NV61), SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), .num_planes = 2, .chroma_order = ORDER_VU, .hsub = 2, .vsub = 1, }, { DRM_FORMAT(NV24), SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), .num_planes = 2, }, { DRM_FORMAT(NV42), SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL), .num_planes = 2, .chroma_order = ORDER_VU, }, { DRM_FORMAT(YUV410), SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), .num_planes = 3, .hsub = 4, .vsub = 4, }, { DRM_FORMAT(YVU410), SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), .num_planes = 3, .chroma_order = ORDER_VU, .hsub = 4, .vsub = 4, }, { DRM_FORMAT(YUV411), SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), .num_planes = 3, .hsub = 4, .vsub = 1, }, { DRM_FORMAT(YVU411), SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), .num_planes = 3, .chroma_order = ORDER_VU, .hsub = 4, .vsub = 1, }, { DRM_FORMAT(YUV420), SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), .num_planes = 3, .hsub = 2, .vsub = 2, }, { DRM_FORMAT(YVU420), SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), .num_planes = 3, .chroma_order = ORDER_VU, .hsub = 2, .vsub = 2, }, { DRM_FORMAT(YUV422), SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), .num_planes = 3, .hsub = 2, .vsub = 1, }, { DRM_FORMAT(YVU422), SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), .num_planes = 3, .chroma_order = ORDER_VU, .hsub = 2, .vsub = 1, }, { DRM_FORMAT(YUV444), SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL), .num_planes = 3, }, { 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_shm(uint32_t format) { if (format == WL_SHM_FORMAT_XRGB8888) return pixel_format_get_info(DRM_FORMAT_XRGB8888); else if (format == WL_SHM_FORMAT_ARGB8888) return pixel_format_get_info(DRM_FORMAT_ARGB8888); else return pixel_format_get_info(format); } /** Retrieve a pixel format information structure from a DRM FOURCC format * * \param format a DRM FOURCC format */ 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 const struct pixel_format_info * pixel_format_get_info_by_drm_name(const char *drm_format_name) { const struct pixel_format_info *info; unsigned int i; for (i = 0; i < ARRAY_LENGTH(pixel_format_table); i++) { info = &pixel_format_table[i]; if (strcasecmp(info->drm_format_name, drm_format_name) == 0) return info; } 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; } /** Retrieve the opaque substitute for a pixel format * * If the given pixel format contains an alpha channel, look up an identical * pixel format except where the alpha channel is ignored, if such format * exists. Otherwise returns the passed in format as is. * * \param info a pixel_format_info already retrieved using pixel_format_get_info() * */ 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; }