diff --git a/gbm_wrapper.c b/gbm_wrapper.c new file mode 100644 index 0000000..da054c3 --- /dev/null +++ b/gbm_wrapper.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2020, Rockchip Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#include +#include +#include +#include +#include +#include + +#include "gbm.h" + +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1) +#endif + +#ifndef HAS_gbm_bo_get_offset +uint32_t +gbm_bo_get_offset(struct gbm_bo *bo, int plane) +{ + return 0; +} +#endif + +#ifndef HAS_gbm_bo_get_modifier +uint64_t +gbm_bo_get_modifier(struct gbm_bo *bo) +{ + return DRM_FORMAT_MOD_INVALID; +} +#endif + +#ifndef HAS_gbm_bo_get_plane_count +int +gbm_bo_get_plane_count(struct gbm_bo *bo) +{ + return 1; +} +#endif + +#ifndef HAS_gbm_device_get_format_modifier_plane_count +int +gbm_device_get_format_modifier_plane_count(struct gbm_device *gbm, + uint32_t format, + uint64_t modifier) +{ + return 1; +} +#endif + +#ifndef HAS_gbm_bo_get_stride_for_plane +uint32_t +gbm_bo_get_stride_for_plane(struct gbm_bo *bo, int plane) +{ + if (plane) + return 0; + + return gbm_bo_get_stride(bo); +} +#endif + +#ifndef HAS_gbm_bo_get_handle_for_plane +union gbm_bo_handle +gbm_bo_get_handle_for_plane(struct gbm_bo *bo, int plane) +{ + union gbm_bo_handle ret; + ret.s32 = -1; + + if (plane) + return ret; + + return gbm_bo_get_handle(bo); +} +#endif + +#ifndef HAS_gbm_bo_create_with_modifiers +struct gbm_bo * +gbm_bo_create_with_modifiers(struct gbm_device *gbm, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, + const unsigned int count) +{ + return gbm_bo_create(gbm, width, height, format, GBM_BO_USE_LINEAR); +} +#endif + +#ifndef HAS_gbm_surface_create_with_modifiers +struct gbm_surface * +gbm_surface_create_with_modifiers(struct gbm_device *gbm, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, + const unsigned int count) +{ + return gbm_surface_create(gbm, width, height, format, 0); +} +#endif + +#ifndef HAS_gbm_bo_map +void * +gbm_bo_map(struct gbm_bo *bo, + uint32_t x, uint32_t y, uint32_t width, uint32_t height, + uint32_t flags, uint32_t *stride, void **map_data) +{ + struct drm_mode_map_dumb arg; + struct gbm_device *gbm_dev; + void *map; + int fd, ret; + + if (!bo || !map_data || width <= 0 || width > gbm_bo_get_width(bo) || + height <= 0 || height > gbm_bo_get_height(bo)) { + errno = EINVAL; + return MAP_FAILED; + } + + gbm_dev = gbm_bo_get_device(bo); + if (!gbm_dev) + return MAP_FAILED; + + fd = gbm_device_get_fd(gbm_dev); + if (fd < 0) + return MAP_FAILED; + + memset(&arg, 0, sizeof(arg)); + arg.handle = gbm_bo_get_handle(bo).u32; + ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &arg); + if (ret) + return MAP_FAILED; + + map = mmap(NULL, gbm_bo_get_stride(bo) * gbm_bo_get_height(bo), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, arg.offset); + if (map == MAP_FAILED) + return map; + + *map_data = map; + + if (stride) + *stride = gbm_bo_get_stride(bo); + + return map + y * gbm_bo_get_stride(bo) + x * (gbm_bo_get_bpp(bo) >> 3); +} +#endif + +#ifndef HAS_gbm_bo_unmap +void +gbm_bo_unmap(struct gbm_bo *bo, void *map_data) +{ + if (map_data) + munmap(map_data, gbm_bo_get_stride(bo) * gbm_bo_get_height(bo)); +} +#endif + +/* Wrappers for unsupported flags */ +struct gbm_surface * +gbm_surface_create(struct gbm_device *gbm, + uint32_t width, uint32_t height, + uint32_t format, uint32_t flags) +{ + struct gbm_surface *surface; + + static struct gbm_surface * (*surface_create)(); + if(!surface_create) + surface_create = + (struct gbm_surface *(*)()) dlsym(RTLD_NEXT, "gbm_surface_create"); + + surface = surface_create(gbm, width, height, format, flags); + if (!surface) + surface = surface_create(gbm, width, height, format, 0); + + return surface; +} + +/* Wrappers for unsupported usage */ +struct gbm_bo * +gbm_bo_create(struct gbm_device *gbm, + uint32_t width, uint32_t height, + uint32_t format, uint32_t usage) +{ + struct gbm_bo *bo; + + static struct gbm_bo * (*bo_create)(); + if(!bo_create) + bo_create = + (struct gbm_bo *(*)()) dlsym(RTLD_NEXT, "gbm_bo_create"); + + bo = bo_create(gbm, width, height, format, usage); + if (!bo) + bo = bo_create(gbm, width, height, format, 0); + + return bo; +} + +/* From mesa3d 20.1.5 : src/gbm/main/gbm.c */ +#ifndef HAS_gbm_bo_get_bpp +uint32_t +gbm_bo_get_bpp(struct gbm_bo *bo) +{ + switch (gbm_bo_get_format(bo)) { + default: + return 0; + case GBM_FORMAT_C8: + case GBM_FORMAT_R8: + case GBM_FORMAT_RGB332: + case GBM_FORMAT_BGR233: + return 8; + case GBM_FORMAT_GR88: + case GBM_FORMAT_XRGB4444: + case GBM_FORMAT_XBGR4444: + case GBM_FORMAT_RGBX4444: + case GBM_FORMAT_BGRX4444: + case GBM_FORMAT_ARGB4444: + case GBM_FORMAT_ABGR4444: + case GBM_FORMAT_RGBA4444: + case GBM_FORMAT_BGRA4444: + case GBM_FORMAT_XRGB1555: + case GBM_FORMAT_XBGR1555: + case GBM_FORMAT_RGBX5551: + case GBM_FORMAT_BGRX5551: + case GBM_FORMAT_ARGB1555: + case GBM_FORMAT_ABGR1555: + case GBM_FORMAT_RGBA5551: + case GBM_FORMAT_BGRA5551: + case GBM_FORMAT_RGB565: + case GBM_FORMAT_BGR565: + return 16; + case GBM_FORMAT_RGB888: + case GBM_FORMAT_BGR888: + return 24; + case GBM_FORMAT_XRGB8888: + case GBM_FORMAT_XBGR8888: + case GBM_FORMAT_RGBX8888: + case GBM_FORMAT_BGRX8888: + case GBM_FORMAT_ARGB8888: + case GBM_FORMAT_ABGR8888: + case GBM_FORMAT_RGBA8888: + case GBM_FORMAT_BGRA8888: + case GBM_FORMAT_XRGB2101010: + case GBM_FORMAT_XBGR2101010: + case GBM_FORMAT_RGBX1010102: + case GBM_FORMAT_BGRX1010102: + case GBM_FORMAT_ARGB2101010: + case GBM_FORMAT_ABGR2101010: + case GBM_FORMAT_RGBA1010102: + case GBM_FORMAT_BGRA1010102: + return 32; + case GBM_FORMAT_XBGR16161616F: + case GBM_FORMAT_ABGR16161616F: + return 64; + } +} +#endif + +/* From mesa3d 20.1.5 : src/gbm/main/gbm.c */ +#ifndef HAS_gbm_format_get_name +static uint32_t +gbm_format_canonicalize(uint32_t gbm_format) +{ + switch (gbm_format) { + case GBM_BO_FORMAT_XRGB8888: + return GBM_FORMAT_XRGB8888; + case GBM_BO_FORMAT_ARGB8888: + return GBM_FORMAT_ARGB8888; + default: + return gbm_format; + } +} + +char * +gbm_format_get_name(uint32_t gbm_format, struct gbm_format_name_desc *desc) +{ + gbm_format = gbm_format_canonicalize(gbm_format); + + desc->name[0] = gbm_format; + desc->name[1] = gbm_format >> 8; + desc->name[2] = gbm_format >> 16; + desc->name[3] = gbm_format >> 24; + desc->name[4] = 0; + + return desc->name; +} +#endif diff --git a/include/gbm.h b/include/gbm.h index bf4257f..d8523f1 100644 --- a/include/gbm.h +++ b/include/gbm.h @@ -28,16 +28,16 @@ #ifndef _GBM_H_ #define _GBM_H_ -#ifdef __cplusplus -extern "C" { -#endif - - #define __GBM__ 1 #include #include +#ifdef __cplusplus +extern "C" { +#endif + + /** * \file gbm.h * \brief Generic Buffer Manager @@ -77,6 +77,12 @@ enum gbm_bo_format { GBM_BO_FORMAT_ARGB8888 }; + +/** + * The FourCC format codes are taken from the drm_fourcc.h definition, and + * re-namespaced. New GBM formats must not be added, unless they are + * identical ports from drm_fourcc. + */ #define __gbm_fourcc_code(a,b,c,d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \ ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) @@ -84,8 +90,13 @@ enum gbm_bo_format { /* color index */ #define GBM_FORMAT_C8 __gbm_fourcc_code('C', '8', ' ', ' ') /* [7:0] C */ + +/* 8 bpp Red */ #define GBM_FORMAT_R8 __gbm_fourcc_code('R', '8', ' ', ' ') /* [7:0] R */ +/* 16 bpp RG */ +#define GBM_FORMAT_GR88 __gbm_fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */ + /* 8 bpp RGB */ #define GBM_FORMAT_RGB332 __gbm_fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */ #define GBM_FORMAT_BGR233 __gbm_fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */ @@ -139,6 +150,15 @@ enum gbm_bo_format { #define GBM_FORMAT_RGBA1010102 __gbm_fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */ #define GBM_FORMAT_BGRA1010102 __gbm_fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */ +/* + * Floating point 64bpp RGB + * IEEE 754-2008 binary16 half-precision float + * [15:0] sign:exponent:mantissa 1:5:10 + */ +#define GBM_FORMAT_XBGR16161616F __gbm_fourcc_code('X', 'B', '4', 'H') /* [63:0] x:B:G:R 16:16:16:16 little endian */ + +#define GBM_FORMAT_ABGR16161616F __gbm_fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */ + /* packed YCbCr */ #define GBM_FORMAT_YUYV __gbm_fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ #define GBM_FORMAT_YVYU __gbm_fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ @@ -179,6 +199,9 @@ enum gbm_bo_format { #define GBM_FORMAT_YUV444 __gbm_fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define GBM_FORMAT_YVU444 __gbm_fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ +struct gbm_format_name_desc { + char name[5]; +}; /** * Flags to indicate the intended use for the buffer - these are passed into @@ -189,21 +212,16 @@ enum gbm_bo_format { * and use flags are supported */ enum gbm_bo_flags { - /** - * Mali doesn't use or support this flag - */ - GBM_BO_USE_LINEAR = (0), /** * Buffer is going to be presented to the screen using an API such as KMS */ GBM_BO_USE_SCANOUT = (1 << 0), - /** - * Buffer is going to be used as cursor - */ + /** + * Buffer is going to be used as cursor + */ GBM_BO_USE_CURSOR = (1 << 1), /** - * Buffer is going to be used as cursor - the dimensions for the buffer - * must be 64x64 if this flag is passed. + * Deprecated */ GBM_BO_USE_CURSOR_64X64 = GBM_BO_USE_CURSOR, /** @@ -213,12 +231,18 @@ enum gbm_bo_flags { GBM_BO_USE_RENDERING = (1 << 2), /** * Buffer can be used for gbm_bo_write. This is guaranteed to work - * with GBM_BO_USE_CURSOR_64X64. but may not work for other - * combinations. + * with GBM_BO_USE_CURSOR, but may not work for other combinations. */ GBM_BO_USE_WRITE = (1 << 3), + /** + * Buffer is linear, i.e. not tiled. + */ + GBM_BO_USE_LINEAR = (1 << 4), }; +/* HACK: Mali doesn't support this flag */ +#define GBM_BO_USE_LINEAR 0 + int gbm_device_get_fd(struct gbm_device *gbm); @@ -229,6 +253,11 @@ int gbm_device_is_format_supported(struct gbm_device *gbm, uint32_t format, uint32_t usage); +int +gbm_device_get_format_modifier_plane_count(struct gbm_device *gbm, + uint32_t format, + uint64_t modifier); + void gbm_device_destroy(struct gbm_device *gbm); @@ -240,9 +269,16 @@ gbm_bo_create(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags); +struct gbm_bo * +gbm_bo_create_with_modifiers(struct gbm_device *gbm, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, + const unsigned int count); #define GBM_BO_IMPORT_WL_BUFFER 0x5501 #define GBM_BO_IMPORT_EGL_IMAGE 0x5502 #define GBM_BO_IMPORT_FD 0x5503 +#define GBM_BO_IMPORT_FD_MODIFIER 0x5504 struct gbm_import_fd_data { int fd; @@ -252,34 +288,54 @@ struct gbm_import_fd_data { uint32_t format; }; +#define GBM_MAX_PLANES 4 + +struct gbm_import_fd_modifier_data { + uint32_t width; + uint32_t height; + uint32_t format; + uint32_t num_fds; + int fds[GBM_MAX_PLANES]; + int strides[GBM_MAX_PLANES]; + int offsets[GBM_MAX_PLANES]; + uint64_t modifier; +}; + struct gbm_bo * gbm_bo_import(struct gbm_device *gbm, uint32_t type, void *buffer, uint32_t usage); /** - * Mali doesn't support those flags + * Flags to indicate the type of mapping for the buffer - these are + * passed into gbm_bo_map(). The caller must set the union of all the + * flags that are appropriate. + * + * These flags are independent of the GBM_BO_USE_* creation flags. However, + * mapping the buffer may require copying to/from a staging buffer. + * + * See also: pipe_transfer_usage */ enum gbm_bo_transfer_flags { /** * Buffer contents read back (or accessed directly) at transfer * create time. */ - GBM_BO_TRANSFER_READ = (0), + GBM_BO_TRANSFER_READ = (1 << 0), /** * Buffer contents will be written back at unmap time * (or modified as a result of being accessed directly). */ - GBM_BO_TRANSFER_WRITE = (0), + GBM_BO_TRANSFER_WRITE = (1 << 1), /** * Read/modify/write */ - GBM_BO_TRANSFER_READ_WRITE = (0), + GBM_BO_TRANSFER_READ_WRITE = (GBM_BO_TRANSFER_READ | GBM_BO_TRANSFER_WRITE), }; void * gbm_bo_map(struct gbm_bo *bo, uint32_t x, uint32_t y, uint32_t width, uint32_t height, - uint32_t flags, uint32_t *stride, void **mp_data); + uint32_t flags, uint32_t *stride, void **map_data); void gbm_bo_unmap(struct gbm_bo *bo, void *map_data); @@ -293,9 +349,18 @@ gbm_bo_get_height(struct gbm_bo *bo); uint32_t gbm_bo_get_stride(struct gbm_bo *bo); +uint32_t +gbm_bo_get_stride_for_plane(struct gbm_bo *bo, int plane); + uint32_t gbm_bo_get_format(struct gbm_bo *bo); +uint32_t +gbm_bo_get_bpp(struct gbm_bo *bo); + +uint32_t +gbm_bo_get_offset(struct gbm_bo *bo, int plane); + struct gbm_device * gbm_bo_get_device(struct gbm_bo *bo); @@ -305,6 +370,15 @@ gbm_bo_get_handle(struct gbm_bo *bo); int gbm_bo_get_fd(struct gbm_bo *bo); +uint64_t +gbm_bo_get_modifier(struct gbm_bo *bo); + +int +gbm_bo_get_plane_count(struct gbm_bo *bo); + +union gbm_bo_handle +gbm_bo_get_handle_for_plane(struct gbm_bo *bo, int plane); + int gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count); @@ -325,6 +399,13 @@ gbm_surface_create(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags); +struct gbm_surface * +gbm_surface_create_with_modifiers(struct gbm_device *gbm, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, + const unsigned int count); + int gbm_surface_needs_lock_front_buffer(struct gbm_surface *surface); @@ -340,6 +421,9 @@ gbm_surface_has_free_buffers(struct gbm_surface *surface); void gbm_surface_destroy(struct gbm_surface *surface); +char * +gbm_format_get_name(uint32_t gbm_format, struct gbm_format_name_desc *desc); + #ifdef __cplusplus } #endif diff --git a/meson.build b/meson.build index 7e9c0b5..7864972 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project( 'libmali', 'c', version : '1.9.0', meson_version : '>=0.49.0', - default_options: ['b_asneeded=false'], + default_options: ['b_asneeded=false', 'b_lundef=false'], ) pkgconfig = import('pkgconfig') @@ -92,7 +92,7 @@ cl_headers = { # Package name : required symbol, wrappers, headers, package version map = { 'mali' : ['', mali_wrappers, mali_headers, meson.project_version()], - 'gbm' : ['gbm_create_device', gbm_wrappers, {'' : 'include/gbm.h'}, '10.4.0'], + 'gbm' : ['gbm_create_device', gbm_wrappers, {'' : 'include/gbm.h'}, '20.1.5'], 'egl' : ['eglCreateContext', egl_wrappers, egl_headers, '7.10'], 'glesv1_cm' : ['eglCreateContext', glesv1_wrappers, glesv1_headers, '7.10'], 'glesv2' : ['eglCreateContext', glesv2_wrappers, glesv2_headers, '7.10'], @@ -101,21 +101,68 @@ map = { } # Create dummy source for building libraries -run_command('touch', join_paths(meson.current_build_dir(), 'dummy.c')) +dummy_source = join_paths(meson.current_build_dir(), 'dummy.c') +run_command('touch', dummy_source) # Create a dummy library for building wrappers libmali = shared_library( 'mali', - join_paths(meson.current_build_dir(), 'dummy.c'), + dummy_source, install : true, version : meson.project_version()) +# The gbm functions might be missing +gbm_check_funcs = [ + 'gbm_bo_map', + 'gbm_bo_unmap', + 'gbm_bo_get_offset', + 'gbm_bo_get_plane_count', + 'gbm_device_get_format_modifier_plane_count', + 'gbm_bo_get_handle_for_plane', + 'gbm_bo_get_stride_for_plane', + 'gbm_bo_get_modifier', + 'gbm_bo_create_with_modifiers', + 'gbm_surface_create_with_modifiers', + 'gbm_bo_get_bpp', + 'gbm_format_get_name', +] + +# Create libgbm wrapper for missing functions +libgbm = [] +gbm_symbol = map['gbm'][0] +if run_command('grep', '-q', gbm_symbol, default_lib).returncode() == 0 + libgbm_version = gbm_wrappers['gbm'] + libgbm_cflags = [] + + libdrm_dep = dependency('libdrm', version : '>= 2.4.0') + if not libdrm_dep.found() + error('libdrm not found.') + endif + + foreach symbol : gbm_check_funcs + if run_command('grep', '-q', symbol, default_lib).returncode() == 0 + libgbm_cflags += '-DHAS_' + symbol + endif + endforeach + + libgbm = shared_library( + 'gbm', + 'gbm_wrapper.c', + c_args : libgbm_cflags, + include_directories : include_directories('include'), + dependencies : libdrm_dep, + link_with : libmali, + install : true, + version : libgbm_version) +endif + foreach name, values : map symbol = values[0] wrappers = values[1] headers = values[2] pkg_version = values[3] mali_cflags = [] + wrapper_ldflags = [] # TODO: Use readelf -s ? if run_command('grep', '-q', symbol, default_lib).returncode() != 0 @@ -127,12 +174,16 @@ foreach name, values : map endif foreach wrapper, version : wrappers - shared_library( - wrapper, - join_paths(meson.current_build_dir(), 'dummy.c'), - link_with : libmali, - install : true, - version : version) + wrapper_ldflags += '-l' + wrapper + + if wrapper != 'gbm' + shared_library( + wrapper, + dummy_source, + link_with : [libgbm, libmali], + install : true, + version : version) + endif endforeach foreach dir, files : headers @@ -140,7 +191,7 @@ foreach name, values : map endforeach pkgconfig.generate( - libraries : ['-L${libdir} -lmali'], + libraries : ['-L${libdir} -lmali', wrapper_ldflags], extra_cflags : mali_cflags, version : pkg_version, name : name,