/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "hwc-bufferinfo-libdrm" #include "BufferInfoLibdrm.h" #include #include #include #include #include #include "utils/log.h" #include "utils/properties.h" namespace android { LEGACY_BUFFER_INFO_GETTER(BufferInfoLibdrm); enum chroma_order { kYCbCr, kYCrCb, }; struct DroidYuvFormat { /* Lookup keys */ uint32_t native; /* HAL_PIXEL_FORMAT_ */ enum chroma_order chroma_order; /* chroma order is {Cb, Cr} or {Cr, Cb} */ size_t chroma_step; /* Distance in bytes between subsequent chroma pixels. */ /* Result */ int fourcc; /* DRM_FORMAT_ */ }; #ifndef DRM_FORMAT_XYUV8888 #define DRM_FORMAT_XYUV8888 \ fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */ #endif /* 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 DroidYuvFormat kDroidYuvFormats[] = { /* Native format, YCrCb, Chroma step, DRI image FourCC */ {HAL_PIXEL_FORMAT_YCbCr_420_888, kYCbCr, 2, DRM_FORMAT_NV12}, {HAL_PIXEL_FORMAT_YCbCr_420_888, kYCbCr, 1, DRM_FORMAT_YUV420}, {HAL_PIXEL_FORMAT_YCbCr_420_888, kYCrCb, 1, DRM_FORMAT_YVU420}, {HAL_PIXEL_FORMAT_YV12, kYCrCb, 1, DRM_FORMAT_YVU420}, /* HACK: See droid_create_image_from_prime_fds() and * https://issuetracker.google.com/32077885. */ {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCbCr, 2, DRM_FORMAT_NV12}, {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCbCr, 1, DRM_FORMAT_YUV420}, {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCrCb, 1, DRM_FORMAT_YVU420}, {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCrCb, 1, DRM_FORMAT_AYUV}, {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, kYCrCb, 1, DRM_FORMAT_XYUV8888}, }; #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static uint32_t get_fourcc_yuv(uint32_t native, enum chroma_order chroma_order, size_t chroma_step) { for (auto droid_yuv_format : kDroidYuvFormats) if (droid_yuv_format.native == native && droid_yuv_format.chroma_order == chroma_order && droid_yuv_format.chroma_step == chroma_step) return droid_yuv_format.fourcc; return UINT32_MAX; } static bool is_yuv(uint32_t native) { // NOLINTNEXTLINE(readability-use-anyofallof) for (auto droid_yuv_format : kDroidYuvFormats) if (droid_yuv_format.native == native) return true; return false; } bool BufferInfoLibdrm::GetYuvPlaneInfo(int num_fds, buffer_handle_t handle, hwc_drm_bo_t *bo) { struct android_ycbcr ycbcr {}; enum chroma_order chroma_order {}; int ret = 0; if (!gralloc_->lock_ycbcr) { static std::once_flag once; std::call_once(once, []() { ALOGW("Gralloc does not support lock_ycbcr()"); }); return false; } memset(&ycbcr, 0, sizeof(ycbcr)); ret = gralloc_->lock_ycbcr(gralloc_, handle, 0, 0, 0, 0, 0, &ycbcr); if (ret) { ALOGW("gralloc->lock_ycbcr failed: %d", ret); return false; } gralloc_->unlock(gralloc_, handle); /* 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. */ bo->offsets[0] = (size_t)ycbcr.y; /* We assume here that all the planes are located in one DMA-buf. */ if ((size_t)ycbcr.cr < (size_t)ycbcr.cb) { chroma_order = kYCrCb; bo->offsets[1] = (size_t)ycbcr.cr; bo->offsets[2] = (size_t)ycbcr.cb; } else { chroma_order = kYCbCr; bo->offsets[1] = (size_t)ycbcr.cb; bo->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. */ bo->pitches[0] = ycbcr.ystride; bo->pitches[1] = bo->pitches[2] = ycbcr.cstride; /* .chroma_step is the byte distance between the same chroma channel * values of subsequent pixels, assumed to be the same for Cb and Cr. */ bo->format = get_fourcc_yuv(bo->hal_format, chroma_order, ycbcr.chroma_step); if (bo->format == UINT32_MAX) { ALOGW( "unsupported YUV format, native = %x, chroma_order = %s, chroma_step = " "%d", bo->hal_format, chroma_order == kYCbCr ? "YCbCr" : "YCrCb", (int)ycbcr.chroma_step); return false; } /* * 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) { bo->prime_fds[2] = bo->prime_fds[1] = bo->prime_fds[0]; } else { int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3; if (num_fds != expected_planes) return false; } return true; } int BufferInfoLibdrm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) { gralloc_handle_t *gr_handle = gralloc_handle(handle); if (!gr_handle) return -EINVAL; bo->width = gr_handle->width; bo->height = gr_handle->height; bo->hal_format = gr_handle->format; #if GRALLOC_HANDLE_VERSION < 4 static std::once_flag once; std::call_once(once, []() { ALOGE( "libdrm < v2.4.97 has broken gralloc_handle structure. Please update."); }); #endif #if GRALLOC_HANDLE_VERSION == 4 bo->modifiers[0] = gr_handle->modifier; #endif bo->usage = gr_handle->usage; bo->prime_fds[0] = gr_handle->prime_fd; if (is_yuv(gr_handle->format)) { if (!GetYuvPlaneInfo(handle->numFds, handle, bo)) return -EINVAL; } else { bo->pitches[0] = gr_handle->stride; bo->offsets[0] = 0; /* FOSS graphic components (gbm_gralloc, mesa3d) are translating * HAL_PIXEL_FORMAT_RGB_565 to DRM_FORMAT_RGB565 without swapping * the R and B components. Same must be done here. */ switch (bo->hal_format) { case HAL_PIXEL_FORMAT_RGB_565: bo->format = DRM_FORMAT_RGB565; break; default: bo->format = ConvertHalFormatToDrm(gr_handle->format); } if (bo->format == DRM_FORMAT_INVALID) return -EINVAL; } return 0; } constexpr char gbm_gralloc_module_name[] = "GBM Memory Allocator"; constexpr char drm_gralloc_module_name[] = "DRM Memory Allocator"; int BufferInfoLibdrm::ValidateGralloc() { if (strcmp(gralloc_->common.name, drm_gralloc_module_name) != 0 && strcmp(gralloc_->common.name, gbm_gralloc_module_name) != 0) { ALOGE( "Gralloc name isn't valid: Expected: \"%s\" or \"%s\", Actual: \"%s\"", gbm_gralloc_module_name, drm_gralloc_module_name, gralloc_->common.name); return -EINVAL; } return 0; } } // namespace android