# util is self contained.
inc_util = [inc_include, include_directories('..')]
+if with_platform_android
+subdir('u_gralloc')
+endif
+
subdir('blake3')
files_mesa_util = files(
--- /dev/null
+# Mesa 3-D graphics library
+#
+# Copyright (C) 2022 Roman Stratiienko (r.stratiienko@gmail.com)
+# SPDX-License-Identifier: MIT
+
+c_args_for_u_gralloc = []
+cpp_args_for_u_gralloc = []
+options_for_u_gralloc = []
+
+files_u_gralloc = files(
+ 'u_gralloc.c',
+ 'u_gralloc_fallback.c',
+ 'u_gralloc_cros_api.c',
+)
+
+if dep_android_mapper4.found()
+ files_u_gralloc += files('u_gralloc_imapper4_api.cpp')
+ c_args_for_u_gralloc += '-DUSE_IMAPPER4_METADATA_API'
+ cpp_args_for_u_gralloc += '-DUSE_IMAPPER4_METADATA_API'
+ options_for_u_gralloc += 'cpp_std=c++17'
+endif
+
+_libmesa_u_gralloc = static_library(
+ '_mesa_u_gralloc',
+ [files_u_gralloc],
+ include_directories : [inc_include, inc_util],
+ c_args : c_args_for_u_gralloc,
+ cpp_args : cpp_args_for_u_gralloc,
+ override_options : options_for_u_gralloc,
+ gnu_symbol_visibility : 'hidden',
+ build_by_default : false,
+ dependencies: dep_android,
+)
+
+idep_u_gralloc = declare_dependency(link_with: _libmesa_u_gralloc)
--- /dev/null
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2022 Roman Stratiienko (r.stratiienko@gmail.com)
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "u_gralloc_internal.h"
+
+#include <assert.h>
+#include <errno.h>
+
+#include "drm-uapi/drm_fourcc.h"
+#include "util/log.h"
+#include "util/macros.h"
+#include "util/simple_mtx.h"
+#include "util/u_atomic.h"
+#include "util/u_memory.h"
+
+static simple_mtx_t u_gralloc_mutex = SIMPLE_MTX_INITIALIZER;
+
+static const struct u_grallocs {
+ enum u_gralloc_type type;
+ struct u_gralloc *(*create)();
+} u_grallocs[] = {
+ {.type = U_GRALLOC_TYPE_CROS, .create = u_gralloc_cros_api_create},
+#ifdef USE_IMAPPER4_METADATA_API
+ {.type = U_GRALLOC_TYPE_GRALLOC4, .create = u_gralloc_imapper_api_create},
+#endif /* USE_IMAPPER4_METADATA_API */
+ {.type = U_GRALLOC_TYPE_FALLBACK, .create = u_gralloc_fallback_create},
+};
+
+static struct u_gralloc_cache {
+ struct u_gralloc *u_gralloc;
+ int refcount;
+} u_gralloc_cache[U_GRALLOC_TYPE_COUNT] = {0};
+
+struct u_gralloc *
+u_gralloc_create(enum u_gralloc_type type)
+{
+ struct u_gralloc *out_gralloc = NULL;
+
+ simple_mtx_lock(&u_gralloc_mutex);
+
+ if (u_gralloc_cache[type].u_gralloc != NULL) {
+ u_gralloc_cache[type].refcount++;
+ out_gralloc = u_gralloc_cache[type].u_gralloc;
+ goto out;
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(u_grallocs); i++) {
+ if (u_grallocs[i].type != type && type != U_GRALLOC_TYPE_AUTO)
+ continue;
+
+ u_gralloc_cache[type].u_gralloc = u_grallocs[i].create();
+ if (u_gralloc_cache[type].u_gralloc) {
+ assert(u_gralloc_cache[type].u_gralloc->ops.get_buffer_basic_info);
+ assert(u_gralloc_cache[type].u_gralloc->ops.destroy);
+
+ u_gralloc_cache[type].refcount = 1;
+
+ out_gralloc = u_gralloc_cache[type].u_gralloc;
+ goto out;
+ }
+ }
+
+out:
+ simple_mtx_unlock(&u_gralloc_mutex);
+
+ return out_gralloc;
+}
+
+void
+u_gralloc_destroy(struct u_gralloc **gralloc NONNULL)
+{
+ int i;
+
+ if (*gralloc == NULL)
+ return;
+
+ simple_mtx_lock(&u_gralloc_mutex);
+
+ for (i = 0; i < ARRAY_SIZE(u_gralloc_cache); i++) {
+ if (u_gralloc_cache[i].u_gralloc == *gralloc) {
+ u_gralloc_cache[i].refcount--;
+ if (u_gralloc_cache[i].refcount == 0) {
+ u_gralloc_cache[i].u_gralloc->ops.destroy(
+ u_gralloc_cache[i].u_gralloc);
+ u_gralloc_cache[i].u_gralloc = NULL;
+ }
+ break;
+ }
+ }
+
+ simple_mtx_unlock(&u_gralloc_mutex);
+
+ assert(i < ARRAY_SIZE(u_grallocs));
+
+ *gralloc = NULL;
+}
+
+inline int
+u_gralloc_get_buffer_basic_info(struct u_gralloc *gralloc NONNULL,
+ struct u_gralloc_buffer_handle *hnd NONNULL,
+ struct u_gralloc_buffer_basic_info *out
+ NONNULL)
+{
+ struct u_gralloc_buffer_basic_info info = {0};
+ int ret;
+
+ ret = gralloc->ops.get_buffer_basic_info(gralloc, hnd, &info);
+
+ if (ret)
+ return ret;
+
+ *out = info;
+
+ return 0;
+}
+
+inline int
+u_gralloc_get_buffer_color_info(struct u_gralloc *gralloc NONNULL,
+ struct u_gralloc_buffer_handle *hnd NONNULL,
+ struct u_gralloc_buffer_color_info *out
+ NONNULL)
+{
+ struct u_gralloc_buffer_color_info info = {0};
+ int ret;
+
+ if (!gralloc->ops.get_buffer_color_info)
+ return -ENOTSUP;
+
+ ret = gralloc->ops.get_buffer_color_info(gralloc, hnd, &info);
+
+ if (ret)
+ return ret;
+
+ *out = info;
+
+ return 0;
+}
+
+inline int
+u_gralloc_get_front_rendering_usage(struct u_gralloc *gralloc NONNULL,
+ uint64_t *out_usage NONNULL)
+{
+ if (!gralloc->ops.get_front_rendering_usage)
+ return -ENOTSUP;
+
+ return gralloc->ops.get_front_rendering_usage(gralloc, out_usage);
+}
--- /dev/null
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2022 Roman Stratiienko (r.stratiienko@gmail.com)
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef U_GRALLOC_H
+#define U_GRALLOC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cutils/native_handle.h>
+
+#include <stdbool.h>
+
+#include "util/macros.h"
+#include "GL/internal/dri_interface.h"
+
+struct u_gralloc;
+
+/* Both Vulkan and EGL API exposes HAL format / pixel stride which is required
+ * by the fallback implementation.
+ */
+struct u_gralloc_buffer_handle {
+ const native_handle_t *handle;
+ int hal_format;
+ int pixel_stride;
+};
+
+struct u_gralloc_buffer_basic_info {
+ uint32_t drm_fourcc;
+ uint64_t modifier;
+
+ int num_planes;
+ int fds[4];
+ int offsets[4];
+ int strides[4];
+};
+
+struct u_gralloc_buffer_color_info {
+ enum __DRIYUVColorSpace yuv_color_space;
+ enum __DRISampleRange sample_range;
+ enum __DRIChromaSiting horizontal_siting;
+ enum __DRIChromaSiting vertical_siting;
+};
+
+enum u_gralloc_type {
+ U_GRALLOC_TYPE_AUTO,
+#ifdef USE_IMAPPER4_METADATA_API
+ U_GRALLOC_TYPE_GRALLOC4,
+#endif
+ U_GRALLOC_TYPE_CROS,
+ U_GRALLOC_TYPE_FALLBACK,
+ U_GRALLOC_TYPE_COUNT,
+};
+
+struct u_gralloc *u_gralloc_create(enum u_gralloc_type type);
+
+void u_gralloc_destroy(struct u_gralloc **gralloc NONNULL);
+
+int u_gralloc_get_buffer_basic_info(
+ struct u_gralloc *gralloc NONNULL,
+ struct u_gralloc_buffer_handle *hnd NONNULL,
+ struct u_gralloc_buffer_basic_info *out NONNULL);
+
+int u_gralloc_get_buffer_color_info(
+ struct u_gralloc *gralloc NONNULL,
+ struct u_gralloc_buffer_handle *hnd NONNULL,
+ struct u_gralloc_buffer_color_info *out NONNULL);
+
+int u_gralloc_get_front_rendering_usage(struct u_gralloc *gralloc NONNULL,
+ uint64_t *out_usage NONNULL);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* U_GRALLOC_H */
--- /dev/null
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright © 2021, Google Inc.
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include <hardware/gralloc.h>
+
+#include "util/log.h"
+#include "util/u_memory.h"
+
+#include "u_gralloc_internal.h"
+
+/* More recent CrOS gralloc has a perform op that fills out the struct below
+ * with canonical information about the buffer and its modifier, planes,
+ * offsets and strides. If we have this, we can skip straight to
+ * createImageFromDmaBufs2() and avoid all the guessing and recalculations.
+ * This also gives us the modifier and plane offsets/strides for multiplanar
+ * compressed buffers (eg Intel CCS buffers) in order to make that work in
+ * Android.
+ */
+
+struct cros_gralloc {
+ struct u_gralloc base;
+ gralloc_module_t *gralloc_module;
+};
+
+static const char cros_gralloc_module_name[] = "CrOS Gralloc";
+
+#define CROS_GRALLOC_DRM_GET_BUFFER_INFO 4
+#define CROS_GRALLOC_DRM_GET_USAGE 5
+#define CROS_GRALLOC_DRM_GET_USAGE_FRONT_RENDERING_BIT 0x1
+
+struct cros_gralloc0_buffer_info {
+ uint32_t drm_fourcc;
+ int num_fds;
+ int fds[4];
+ uint64_t modifier;
+ int offset[4];
+ int stride[4];
+};
+
+static int
+cros_get_buffer_info(struct u_gralloc *gralloc,
+ struct u_gralloc_buffer_handle *hnd,
+ struct u_gralloc_buffer_basic_info *out)
+{
+ struct cros_gralloc0_buffer_info info;
+ struct cros_gralloc *gr = (struct cros_gralloc *)gralloc;
+ gralloc_module_t *gr_mod = gr->gralloc_module;
+
+ if (gr_mod->perform(gr_mod, CROS_GRALLOC_DRM_GET_BUFFER_INFO, hnd->handle,
+ &info) == 0) {
+ out->drm_fourcc = info.drm_fourcc;
+ out->modifier = info.modifier;
+ out->num_planes = info.num_fds;
+ for (int i = 0; i < out->num_planes; i++) {
+ out->fds[i] = info.fds[i];
+ out->offsets[i] = info.offset[i];
+ out->strides[i] = info.stride[i];
+ }
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int
+cros_get_front_rendering_usage(struct u_gralloc *gralloc, uint64_t *out_usage)
+{
+ struct cros_gralloc *gr = (struct cros_gralloc *)gralloc;
+ uint32_t front_rendering_usage = 0;
+
+ if (gr->gralloc_module->perform(
+ gr->gralloc_module, CROS_GRALLOC_DRM_GET_USAGE,
+ CROS_GRALLOC_DRM_GET_USAGE_FRONT_RENDERING_BIT,
+ &front_rendering_usage) == 0) {
+ *out_usage = front_rendering_usage;
+ return 0;
+ }
+
+ return -ENOTSUP;
+}
+
+static int
+destroy(struct u_gralloc *gralloc)
+{
+ struct cros_gralloc *gr = (struct cros_gralloc *)gralloc;
+ if (gr->gralloc_module)
+ dlclose(gr->gralloc_module->common.dso);
+
+ FREE(gr);
+
+ return 0;
+}
+
+struct u_gralloc *
+u_gralloc_cros_api_create()
+{
+ struct cros_gralloc *gr = CALLOC_STRUCT(cros_gralloc);
+ int err = 0;
+
+ err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+ (const hw_module_t **)&gr->gralloc_module);
+
+ if (err)
+ goto fail;
+
+ if (strcmp(gr->gralloc_module->common.name, cros_gralloc_module_name) != 0)
+ goto fail;
+
+ if (!gr->gralloc_module->perform) {
+ mesa_logw("Oops. CrOS gralloc doesn't have perform callback");
+ goto fail;
+ }
+
+ gr->base.ops.get_buffer_basic_info = cros_get_buffer_info;
+ gr->base.ops.get_front_rendering_usage = cros_get_front_rendering_usage;
+ gr->base.ops.destroy = destroy;
+
+ mesa_logi("Using gralloc0 CrOS API");
+
+ return &gr->base;
+
+fail:
+ destroy(&gr->base);
+
+ return NULL;
+}
--- /dev/null
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright © 2021, Google Inc.
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "u_gralloc_internal.h"
+
+#include <hardware/gralloc.h>
+
+#include "drm-uapi/drm_fourcc.h"
+#include "util/log.h"
+#include "util/macros.h"
+#include "util/u_memory.h"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+struct fallback_gralloc {
+ struct u_gralloc base;
+ gralloc_module_t *gralloc_module;
+};
+
+enum chroma_order {
+ YCbCr,
+ YCrCb,
+};
+
+struct droid_yuv_format {
+ /* Lookup keys */
+ int native; /* HAL_PIXEL_FORMAT_ */
+ enum chroma_order chroma_order; /* chroma order is {Cb, Cr} or {Cr, Cb} */
+ int chroma_step; /* Distance in bytes between subsequent chroma pixels. */
+
+ /* Result */
+ int fourcc; /* DRM_FORMAT_ */
+};
+
+/* The following table is used to look up a DRI image FourCC based
+ * on native format and information contained in android_ycbcr struct. */
+static const struct droid_yuv_format droid_yuv_formats[] = {
+ /* Native format, YCrCb, Chroma step, DRI image FourCC */
+ {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 2, DRM_FORMAT_NV12},
+ {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 1, DRM_FORMAT_YUV420},
+ {HAL_PIXEL_FORMAT_YCbCr_420_888, YCrCb, 1, DRM_FORMAT_YVU420},
+ {HAL_PIXEL_FORMAT_YV12, YCrCb, 1, DRM_FORMAT_YVU420},
+ /* HACK: See droid_create_image_from_prime_fds() and
+ * https://issuetracker.google.com/32077885. */
+ {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 2, DRM_FORMAT_NV12},
+ {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 1, DRM_FORMAT_YUV420},
+ {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_YVU420},
+ {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_AYUV},
+ {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_XYUV8888},
+};
+
+static int
+get_fourcc_yuv(int native, enum chroma_order chroma_order, int chroma_step)
+{
+ for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
+ if (droid_yuv_formats[i].native == native &&
+ droid_yuv_formats[i].chroma_order == chroma_order &&
+ droid_yuv_formats[i].chroma_step == chroma_step)
+ return droid_yuv_formats[i].fourcc;
+
+ return -1;
+}
+
+static bool
+is_yuv(int native)
+{
+ for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
+ if (droid_yuv_formats[i].native == native)
+ return true;
+
+ return false;
+}
+
+static int
+get_format_bpp(int native)
+{
+ int bpp;
+
+ switch (native) {
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ bpp = 8;
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ /*
+ * HACK: Hardcode this to RGBX_8888 as per cros_gralloc hack.
+ * TODO: Remove this once https://issuetracker.google.com/32077885 is
+ * fixed.
+ */
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ bpp = 4;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ bpp = 2;
+ break;
+ default:
+ bpp = 0;
+ break;
+ }
+
+ return bpp;
+}
+
+/* createImageFromFds requires fourcc format */
+static int
+get_fourcc(int native)
+{
+ switch (native) {
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return DRM_FORMAT_RGB565;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return DRM_FORMAT_ARGB8888;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return DRM_FORMAT_ABGR8888;
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ /*
+ * HACK: Hardcode this to RGBX_8888 as per cros_gralloc hack.
+ * TODO: Remove this once https://issuetracker.google.com/32077885 is
+ * fixed.
+ */
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return DRM_FORMAT_XBGR8888;
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ return DRM_FORMAT_ABGR16161616F;
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ return DRM_FORMAT_ABGR2101010;
+ default:
+ mesa_logw("unsupported native buffer format 0x%x", native);
+ }
+ return -1;
+}
+
+/* returns # of fds, and by reference the actual fds */
+static unsigned
+get_native_buffer_fds(const native_handle_t *handle, int fds[3])
+{
+ if (!handle)
+ return 0;
+
+ /*
+ * Various gralloc implementations exist, but the dma-buf fd tends
+ * to be first. Access it directly to avoid a dependency on specific
+ * gralloc versions.
+ */
+ for (int i = 0; i < handle->numFds; i++)
+ fds[i] = handle->data[i];
+
+ return handle->numFds;
+}
+
+static int
+fallback_gralloc_get_yuv_info(struct u_gralloc *gralloc,
+ struct u_gralloc_buffer_handle *hnd,
+ struct u_gralloc_buffer_basic_info *out)
+{
+ struct fallback_gralloc *gr = (struct fallback_gralloc *)gralloc;
+ gralloc_module_t *gr_mod = gr->gralloc_module;
+ enum chroma_order chroma_order;
+ struct android_ycbcr ycbcr;
+ int drm_fourcc = 0;
+ int num_planes = 0;
+ int num_fds = 0;
+ int fds[3];
+ int ret;
+
+ num_fds = get_native_buffer_fds(hnd->handle, fds);
+ if (num_fds == 0)
+ return -EINVAL;
+
+ if (!gr_mod || !gr_mod->lock_ycbcr) {
+ return -EINVAL;
+ }
+
+ memset(&ycbcr, 0, sizeof(ycbcr));
+ ret = gr_mod->lock_ycbcr(gr_mod, hnd->handle, 0, 0, 0, 0, 0, &ycbcr);
+ if (ret) {
+ /* HACK: See native_window_buffer_get_buffer_info() and
+ * https://issuetracker.google.com/32077885.*/
+ if (hnd->hal_format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)
+ return -EAGAIN;
+
+ mesa_logw("gralloc->lock_ycbcr failed: %d", ret);
+ return -EINVAL;
+ }
+ gr_mod->unlock(gr_mod, hnd->handle);
+
+ chroma_order = ((size_t)ycbcr.cr < (size_t)ycbcr.cb) ? YCrCb : YCbCr;
+
+ /* .chroma_step is the byte distance between the same chroma channel
+ * values of subsequent pixels, assumed to be the same for Cb and Cr. */
+ drm_fourcc =
+ get_fourcc_yuv(hnd->hal_format, chroma_order, ycbcr.chroma_step);
+ if (drm_fourcc == -1) {
+ mesa_logw("unsupported YUV format, native = %x, chroma_order = %s, "
+ "chroma_step = %zu",
+ hnd->hal_format, chroma_order == YCbCr ? "YCbCr" : "YCrCb",
+ ycbcr.chroma_step);
+ return -EINVAL;
+ }
+
+ out->drm_fourcc = drm_fourcc;
+ out->modifier = DRM_FORMAT_MOD_INVALID;
+
+ num_planes = ycbcr.chroma_step == 2 ? 2 : 3;
+ /* When lock_ycbcr's usage argument contains no SW_READ/WRITE flags
+ * it will return the .y/.cb/.cr pointers based on a NULL pointer,
+ * so they can be interpreted as offsets. */
+ out->offsets[0] = (size_t)ycbcr.y;
+ /* We assume here that all the planes are located in one DMA-buf. */
+ if (chroma_order == YCrCb) {
+ out->offsets[1] = (size_t)ycbcr.cr;
+ out->offsets[2] = (size_t)ycbcr.cb;
+ } else {
+ out->offsets[1] = (size_t)ycbcr.cb;
+ out->offsets[2] = (size_t)ycbcr.cr;
+ }
+
+ /* .ystride is the line length (in bytes) of the Y plane,
+ * .cstride is the line length (in bytes) of any of the remaining
+ * Cb/Cr/CbCr planes, assumed to be the same for Cb and Cr for fully
+ * planar formats. */
+ out->strides[0] = ycbcr.ystride;
+ out->strides[1] = out->strides[2] = ycbcr.cstride;
+
+ /*
+ * Since this is EGL_NATIVE_BUFFER_ANDROID don't assume that
+ * the single-fd case cannot happen. So handle eithe single
+ * fd or fd-per-plane case:
+ */
+ if (num_fds == 1) {
+ out->fds[1] = out->fds[0] = fds[0];
+ if (out->num_planes == 3)
+ out->fds[2] = fds[0];
+ } else {
+ assert(num_fds == out->num_planes);
+ out->fds[0] = fds[0];
+ out->fds[1] = fds[1];
+ out->fds[2] = fds[2];
+ }
+
+ return 0;
+}
+
+static int
+fallback_gralloc_get_buffer_info(struct u_gralloc *gralloc,
+ struct u_gralloc_buffer_handle *hnd,
+ struct u_gralloc_buffer_basic_info *out)
+{
+ int num_planes = 0;
+ int drm_fourcc = 0;
+ int stride = 0;
+ int fds[3];
+
+ if (is_yuv(hnd->hal_format)) {
+ int ret = fallback_gralloc_get_yuv_info(gralloc, hnd, out);
+ /*
+ * HACK: https://issuetracker.google.com/32077885
+ * There is no API available to properly query the
+ * IMPLEMENTATION_DEFINED format. As a workaround we rely here on
+ * gralloc allocating either an arbitrary YCbCr 4:2:0 or RGBX_8888, with
+ * the latter being recognized by lock_ycbcr failing.
+ */
+ if (ret != -EAGAIN)
+ return ret;
+ }
+
+ /*
+ * Non-YUV formats could *also* have multiple planes, such as ancillary
+ * color compression state buffer, but the rest of the code isn't ready
+ * yet to deal with modifiers:
+ */
+ num_planes = get_native_buffer_fds(hnd->handle, fds);
+ if (num_planes == 0)
+ return -EINVAL;
+
+ assert(num_planes == 1);
+
+ drm_fourcc = get_fourcc(hnd->hal_format);
+ if (drm_fourcc == -1) {
+ mesa_loge("Failed to get drm_fourcc");
+ return -EINVAL;
+ }
+
+ stride = hnd->pixel_stride * get_format_bpp(hnd->hal_format);
+ if (stride == 0) {
+ mesa_loge("Failed to calcuulate stride");
+ return -EINVAL;
+ }
+
+ out->drm_fourcc = drm_fourcc;
+ out->modifier = DRM_FORMAT_MOD_INVALID;
+ out->num_planes = num_planes;
+ out->fds[0] = fds[0];
+ out->strides[0] = stride;
+
+ return 0;
+}
+
+static int
+destroy(struct u_gralloc *gralloc)
+{
+ struct fallback_gralloc *gr = (struct fallback_gralloc *)gralloc;
+ if (gr->gralloc_module) {
+ dlclose(gr->gralloc_module->common.dso);
+ }
+
+ FREE(gr);
+
+ return 0;
+}
+
+struct u_gralloc *
+u_gralloc_fallback_create()
+{
+ struct fallback_gralloc *gr = CALLOC_STRUCT(fallback_gralloc);
+ int err = 0;
+
+ err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+ (const hw_module_t **)&gr->gralloc_module);
+
+ if (err) {
+ mesa_logw(
+ "No gralloc hwmodule detected (video buffers won't be supported)");
+ } else if (!gr->gralloc_module->lock_ycbcr) {
+ mesa_logw("Gralloc doesn't support lock_ycbcr (video buffers won't be "
+ "supported)");
+ }
+
+ gr->base.ops.get_buffer_basic_info = fallback_gralloc_get_buffer_info;
+ gr->base.ops.destroy = destroy;
+
+ mesa_logi("Using fallback gralloc implementation");
+
+ return &gr->base;
+}
--- /dev/null
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2021 GlobalLogic Ukraine
+ * Copyright (C) 2021-2022 Roman Stratiienko (r.stratiienko@gmail.com)
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/ChromaSiting.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <aidl/android/hardware/graphics/common/ExtendableType.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
+#include <gralloctypes/Gralloc4.h>
+#include <system/window.h>
+
+#include "util/log.h"
+#include "u_gralloc_internal.h"
+
+using aidl::android::hardware::graphics::common::BufferUsage;
+using aidl::android::hardware::graphics::common::ChromaSiting;
+using aidl::android::hardware::graphics::common::Dataspace;
+using aidl::android::hardware::graphics::common::ExtendableType;
+using aidl::android::hardware::graphics::common::PlaneLayout;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::graphics::mapper::V4_0::Error;
+using android::hardware::graphics::mapper::V4_0::IMapper;
+
+using MetadataType =
+ android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
+
+Error
+GetMetadata(android::sp<IMapper> mapper, const native_handle_t *buffer,
+ MetadataType type, hidl_vec<uint8_t> *metadata)
+{
+ Error error = Error::NONE;
+
+ auto native_handle = const_cast<native_handle_t *>(buffer);
+
+ auto ret =
+ mapper->get(native_handle, type,
+ [&](const auto &get_error, const auto &get_metadata) {
+ error = get_error;
+ *metadata = get_metadata;
+ });
+
+ if (!ret.isOk())
+ error = Error::NO_RESOURCES;
+
+ return error;
+}
+
+std::optional<std::vector<PlaneLayout>>
+GetPlaneLayouts(android::sp<IMapper> mapper, const native_handle_t *buffer)
+{
+ hidl_vec<uint8_t> encoded_layouts;
+
+ Error error = GetMetadata(mapper, buffer,
+ android::gralloc4::MetadataType_PlaneLayouts,
+ &encoded_layouts);
+
+ if (error != Error::NONE)
+ return std::nullopt;
+
+ std::vector<PlaneLayout> plane_layouts;
+
+ auto status =
+ android::gralloc4::decodePlaneLayouts(encoded_layouts, &plane_layouts);
+
+ if (status != android::OK)
+ return std::nullopt;
+
+ return plane_layouts;
+}
+
+struct gralloc4 {
+ struct u_gralloc base;
+ android::sp<IMapper> mapper;
+};
+
+extern "C" {
+
+static int
+mapper4_get_buffer_basic_info(struct u_gralloc *gralloc,
+ struct u_gralloc_buffer_handle *hnd,
+ struct u_gralloc_buffer_basic_info *out)
+{
+ gralloc4 *gr4 = (gralloc4 *)gralloc;
+
+ if (gr4->mapper == nullptr)
+ return -EINVAL;
+
+ if (!hnd->handle)
+ return -EINVAL;
+
+ hidl_vec<uint8_t> encoded_format;
+ auto err = GetMetadata(gr4->mapper, hnd->handle,
+ android::gralloc4::MetadataType_PixelFormatFourCC,
+ &encoded_format);
+ if (err != Error::NONE)
+ return -EINVAL;
+
+ uint32_t drm_fourcc;
+
+ auto status =
+ android::gralloc4::decodePixelFormatFourCC(encoded_format, &drm_fourcc);
+ if (status != android::OK)
+ return -EINVAL;
+
+ uint64_t drm_modifier;
+
+ hidl_vec<uint8_t> encoded_modifier;
+ err = GetMetadata(gr4->mapper, hnd->handle,
+ android::gralloc4::MetadataType_PixelFormatModifier,
+ &encoded_modifier);
+ if (err != Error::NONE)
+ return -EINVAL;
+
+ status = android::gralloc4::decodePixelFormatModifier(encoded_modifier,
+ &drm_modifier);
+ if (status != android::OK)
+ return -EINVAL;
+
+ out->drm_fourcc = drm_fourcc;
+ out->modifier = drm_modifier;
+
+ auto layouts_opt = GetPlaneLayouts(gr4->mapper, hnd->handle);
+
+ if (!layouts_opt)
+ return -EINVAL;
+
+ std::vector<PlaneLayout> &layouts = *layouts_opt;
+
+ out->num_planes = layouts.size();
+
+ int fd_index = 0;
+
+ for (uint32_t i = 0; i < layouts.size(); i++) {
+ out->strides[i] = layouts[i].strideInBytes;
+ out->offsets[i] = layouts[i].offsetInBytes;
+
+ /* offset == 0 means layer is located in different dma-buf */
+ if (out->offsets[i] == 0 && i > 0)
+ fd_index++;
+
+ if (fd_index >= hnd->handle->numFds)
+ return -EINVAL;
+
+ out->fds[i] = hnd->handle->data[fd_index];
+ }
+
+ return 0;
+}
+
+static int
+mapper4_get_buffer_color_info(struct u_gralloc *gralloc,
+ struct u_gralloc_buffer_handle *hnd,
+ struct u_gralloc_buffer_color_info *out)
+{
+ gralloc4 *gr4 = (gralloc4 *)gralloc;
+
+ if (gr4->mapper == nullptr)
+ return -EINVAL;
+
+ if (!hnd->handle)
+ return -EINVAL;
+
+ /* optional attributes */
+ hidl_vec<uint8_t> encoded_chroma_siting;
+ std::optional<ChromaSiting> chroma_siting;
+ auto err = GetMetadata(gr4->mapper, hnd->handle,
+ android::gralloc4::MetadataType_ChromaSiting,
+ &encoded_chroma_siting);
+ if (err == Error::NONE) {
+ ExtendableType chroma_siting_ext;
+ auto status = android::gralloc4::decodeChromaSiting(
+ encoded_chroma_siting, &chroma_siting_ext);
+ if (status != android::OK)
+ return -EINVAL;
+
+ chroma_siting =
+ android::gralloc4::getStandardChromaSitingValue(chroma_siting_ext);
+ }
+
+ hidl_vec<uint8_t> encoded_dataspace;
+ err = GetMetadata(gr4->mapper, hnd->handle,
+ android::gralloc4::MetadataType_Dataspace,
+ &encoded_dataspace);
+ if (err == Error::NONE) {
+ Dataspace dataspace;
+ auto status =
+ android::gralloc4::decodeDataspace(encoded_dataspace, &dataspace);
+ if (status != android::OK)
+ return -EINVAL;
+
+ Dataspace standard =
+ (Dataspace)((int)dataspace & (uint32_t)Dataspace::STANDARD_MASK);
+ switch (standard) {
+ case Dataspace::STANDARD_BT709:
+ out->yuv_color_space = __DRI_YUV_COLOR_SPACE_ITU_REC709;
+ break;
+ case Dataspace::STANDARD_BT601_625:
+ case Dataspace::STANDARD_BT601_625_UNADJUSTED:
+ case Dataspace::STANDARD_BT601_525:
+ case Dataspace::STANDARD_BT601_525_UNADJUSTED:
+ out->yuv_color_space = __DRI_YUV_COLOR_SPACE_ITU_REC601;
+ break;
+ case Dataspace::STANDARD_BT2020:
+ case Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE:
+ out->yuv_color_space = __DRI_YUV_COLOR_SPACE_ITU_REC2020;
+ break;
+ default:
+ break;
+ }
+
+ Dataspace range =
+ (Dataspace)((int)dataspace & (uint32_t)Dataspace::RANGE_MASK);
+ switch (range) {
+ case Dataspace::RANGE_FULL:
+ out->sample_range = __DRI_YUV_FULL_RANGE;
+ break;
+ case Dataspace::RANGE_LIMITED:
+ out->sample_range = __DRI_YUV_NARROW_RANGE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (chroma_siting) {
+ switch (*chroma_siting) {
+ case ChromaSiting::SITED_INTERSTITIAL:
+ out->horizontal_siting = __DRI_YUV_CHROMA_SITING_0_5;
+ out->vertical_siting = __DRI_YUV_CHROMA_SITING_0_5;
+ break;
+ case ChromaSiting::COSITED_HORIZONTAL:
+ out->horizontal_siting = __DRI_YUV_CHROMA_SITING_0;
+ out->vertical_siting = __DRI_YUV_CHROMA_SITING_0_5;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+mapper4_get_front_rendering_usage(struct u_gralloc *gralloc,
+ uint64_t *out_usage)
+{
+ assert(out_usage);
+#if ANDROID_API_LEVEL >= 33
+ *out_usage = static_cast<uint64_t>(BufferUsage::FRONT_BUFFER);
+
+ return 0;
+#else
+ return -ENOTSUP;
+#endif
+}
+
+static int
+destroy(struct u_gralloc *gralloc)
+{
+ gralloc4 *gr = (struct gralloc4 *)gralloc;
+ delete gr;
+
+ return 0;
+}
+
+struct u_gralloc *
+u_gralloc_imapper_api_create()
+{
+ auto mapper = IMapper::getService();
+ if (!mapper)
+ return NULL;
+
+ auto gr = new gralloc4;
+ gr->mapper = mapper;
+ gr->base.ops.get_buffer_basic_info = mapper4_get_buffer_basic_info;
+ gr->base.ops.get_buffer_color_info = mapper4_get_buffer_color_info;
+ gr->base.ops.get_front_rendering_usage = mapper4_get_front_rendering_usage;
+ gr->base.ops.destroy = destroy;
+
+ mesa_logi("Using IMapper v4 API");
+
+ return &gr->base;
+}
+
+} // extern "C"
--- /dev/null
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2023 Roman Stratiienko (r.stratiienko@gmail.com)
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef U_GRALLOC_INTERNAL_H
+#define U_GRALLOC_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "u_gralloc.h"
+
+struct u_gralloc_ops {
+ int (*get_buffer_basic_info)(struct u_gralloc *gralloc,
+ struct u_gralloc_buffer_handle *hnd,
+ struct u_gralloc_buffer_basic_info *out);
+ int (*get_buffer_color_info)(struct u_gralloc *gralloc,
+ struct u_gralloc_buffer_handle *hnd,
+ struct u_gralloc_buffer_color_info *out);
+ int (*get_front_rendering_usage)(struct u_gralloc *gralloc,
+ uint64_t *out_usage);
+ int (*destroy)(struct u_gralloc *gralloc);
+};
+
+struct u_gralloc {
+ struct u_gralloc_ops ops;
+};
+
+extern struct u_gralloc *u_gralloc_cros_api_create(void);
+#ifdef USE_IMAPPER4_METADATA_API
+extern struct u_gralloc *u_gralloc_imapper_api_create(void);
+#endif
+extern struct u_gralloc *u_gralloc_fallback_create(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* U_GRALLOC_INTERNAL_H */