/* * Mesa 3-D graphics library * * Copyright © 2021, Google Inc. * SPDX-License-Identifier: MIT */ #include "u_gralloc_internal.h" #include #include "drm-uapi/drm_fourcc.h" #include "util/log.h" #include "util/macros.h" #include "util/u_memory.h" #include #include #include struct fallback_gralloc { struct u_gralloc base; gralloc_module_t *gralloc_module; }; /* 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; struct android_ycbcr ycbcr; 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); ret = bufferinfo_from_ycbcr(&ycbcr, hnd, out); if (ret) return ret; /* * 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; if (hnd->handle->numFds == 0) return -EINVAL; if (is_hal_format_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 = 1; drm_fourcc = get_fourcc_from_hal_format(hnd->hal_format); if (drm_fourcc == -1) { mesa_loge("Failed to get drm_fourcc"); return -EINVAL; } stride = hnd->pixel_stride * get_hal_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] = hnd->handle->data[0]; out->strides[0] = stride; #ifdef HAS_FREEDRENO uint32_t gmsm = ('g' << 24) | ('m' << 16) | ('s' << 8) | 'm'; if (hnd->handle->numInts >= 2 && hnd->handle->data[hnd->handle->numFds] == gmsm) { /* This UBWC flag was introduced in a5xx. */ bool ubwc = hnd->handle->data[hnd->handle->numFds + 1] & 0x08000000; out->modifier = ubwc ? DRM_FORMAT_MOD_QCOM_COMPRESSED : DRM_FORMAT_MOD_LINEAR; } #endif 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; }