/* * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * 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. */ #include "hi_gbm.h" #include #include #include #include #include #include #include #include #include "display_log.h" #include "hi_gbm_internal.h" namespace OHOS { namespace HDI { namespace DISPLAY { #ifdef ROCKCHIP_CMA #define ROCKCHIP_BO_CONTIG (1 << 0) #endif using PlaneLayoutInfo = struct { uint32_t numPlanes; uint32_t radio[MAX_PLANES]; }; using FormatInfo = struct { uint32_t format; uint32_t bitsPerPixel; // bits per pixel for first plane const PlaneLayoutInfo *planes; }; static const PlaneLayoutInfo YUV_420SP_LAYOUT = { .numPlanes = 2, .radio = { 4, 2 }, }; static const PlaneLayoutInfo YUV_420P_LAYOUT = { .numPlanes = 3, .radio = { 4, 1, 1 }, }; static const PlaneLayoutInfo YUV_422SP_LAYOUT = { .numPlanes = 2, .radio = { 4, 4 }, }; static const PlaneLayoutInfo YUV_422P_LAYOUT = { .numPlanes = 3, .radio = { 4, 2, 2 }, }; static const FormatInfo *GetFormatInfo(uint32_t format) { static const FormatInfo FMT_INFOS[] = { {DRM_FORMAT_RGBX8888, 32, nullptr}, {DRM_FORMAT_RGBA8888, 32, nullptr}, {DRM_FORMAT_BGRX8888, 32, nullptr}, {DRM_FORMAT_BGRA8888, 32, nullptr}, {DRM_FORMAT_RGB888, 24, nullptr}, {DRM_FORMAT_RGB565, 16, nullptr}, {DRM_FORMAT_BGRX4444, 16, nullptr}, {DRM_FORMAT_BGRA4444, 16, nullptr}, {DRM_FORMAT_RGBA4444, 16, nullptr}, {DRM_FORMAT_RGBX4444, 16, nullptr}, {DRM_FORMAT_BGRX5551, 16, nullptr}, {DRM_FORMAT_BGRA5551, 16, nullptr}, {DRM_FORMAT_NV12, 8, &YUV_420SP_LAYOUT}, {DRM_FORMAT_NV21, 8, &YUV_420SP_LAYOUT}, {DRM_FORMAT_NV16, 8, &YUV_422SP_LAYOUT}, {DRM_FORMAT_NV61, 8, &YUV_422SP_LAYOUT}, {DRM_FORMAT_YUV420, 8, &YUV_420P_LAYOUT}, {DRM_FORMAT_YVU420, 8, &YUV_420P_LAYOUT}, {DRM_FORMAT_YUV422, 8, &YUV_422P_LAYOUT}, {DRM_FORMAT_YVU422, 8, &YUV_422P_LAYOUT}, }; for (uint32_t i = 0; i < sizeof(FMT_INFOS) / sizeof(FormatInfo); i++) { if (FMT_INFOS[i].format == format) { return &FMT_INFOS[i]; } } DISPLAY_LOGE("the format can not support"); return nullptr; } void InitGbmBo(struct gbm_bo *bo, const struct drm_mode_create_dumb *dumb) { DISPLAY_CHK_RETURN_NOT_VALUE((dumb == nullptr), DISPLAY_LOGE("dumb is null")); DISPLAY_CHK_RETURN_NOT_VALUE((bo == nullptr), DISPLAY_LOGE("bo is null")); bo->stride = dumb->pitch; bo->size = dumb->size; bo->handle = dumb->handle; } static uint32_t AdjustStrideFromFormat(uint32_t format, uint32_t height) { uint32_t tmpHeight = height; const FormatInfo *fmtInfo = GetFormatInfo(format); if ((fmtInfo != nullptr) && (fmtInfo->planes != nullptr)) { uint32_t sum = fmtInfo->planes->radio[0]; for (uint32_t i = 1; (i < fmtInfo->planes->numPlanes) && (i < MAX_PLANES); i++) { sum += fmtInfo->planes->radio[i]; } if (sum > 0) { tmpHeight = DIV_ROUND_UP((height * sum), fmtInfo->planes->radio[0]); } DISPLAY_LOGD("height adjust to : %{public}d", tmpHeight); } return tmpHeight; } struct gbm_bo *HdiGbmBoCreate(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { DISPLAY_UNUSED(usage); int ret; struct gbm_bo *bo; struct drm_mode_create_dumb dumb = { 0 }; const FormatInfo *fmtInfo = GetFormatInfo(format); DISPLAY_CHK_RETURN((fmtInfo == nullptr), nullptr, DISPLAY_LOGE("formt: 0x%{public}x can not get layout info", format)); bo = (struct gbm_bo *)calloc(1, sizeof(struct gbm_bo)); DISPLAY_CHK_RETURN((bo == nullptr), nullptr, DISPLAY_LOGE("gbm bo create fialed no memery")); (void)memset_s(bo, sizeof(struct gbm_bo), 0, sizeof(struct gbm_bo)); bo->width = width; bo->height = height; bo->gbm = gbm; bo->format = format; // init create_dumb dumb.height = ALIGN_UP(AdjustStrideFromFormat(format, height), HEIGHT_ALIGN); dumb.width = ALIGN_UP(width, WIDTH_ALIGN); dumb.flags = 0; dumb.bpp = fmtInfo->bitsPerPixel; ret = drmIoctl(gbm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &dumb); DISPLAY_LOGD("fmt 0x%{public}x create dumb width: %{public}d height: %{public}d bpp: %{public}u pitch" "%{public}d size %{public}llu", format, dumb.width, dumb.height, dumb.bpp, dumb.pitch, dumb.size); DISPLAY_CHK_RETURN((ret != 0), nullptr, DISPLAY_LOGE("DRM_IOCTL_MODE_CREATE_DUMB failed errno %{public}d", errno)); InitGbmBo(bo, &dumb); DISPLAY_LOGD( "fmt 0x%{public}x create dumb width: %{public}d height: %{public}d stride %{public}d size %{public}u", format, bo->width, bo->height, bo->stride, bo->size); return bo; } struct gbm_device *HdiGbmCreateDevice(int fd) { struct gbm_device *gbm = (struct gbm_device *)calloc(1, sizeof(struct gbm_device)); DISPLAY_CHK_RETURN((gbm == nullptr), nullptr, DISPLAY_LOGE("memory calloc failed")); gbm->fd = fd; return gbm; } void HdiGbmDeviceDestroy(struct gbm_device *gbm) { free(gbm); } uint32_t HdiGbmBoGetStride(struct gbm_bo *bo) { DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null")); return bo->stride; } uint32_t HdiGbmBoGetWidth(struct gbm_bo *bo) { DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null")); return bo->width; } uint32_t HdiGbmBoGetHeight(struct gbm_bo *bo) { DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null")); return bo->height; } uint32_t HdiGbmBoGetSize(struct gbm_bo *bo) { DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null")); return bo->size; } void HdiGbmBoDestroy(struct gbm_bo *bo) { int ret; DISPLAY_CHK_RETURN_NOT_VALUE((bo == nullptr), DISPLAY_LOGE("the bo is null")); struct drm_mode_destroy_dumb dumb = { 0 }; dumb.handle = bo->handle; ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dumb); DISPLAY_CHK_RETURN_NOT_VALUE((ret), DISPLAY_LOGE("dumb buffer destroy failed errno %{public}d", errno)); free(bo); } int HdiGbmBoGetFd(struct gbm_bo *bo) { int fd; int ret = drmPrimeHandleToFD(bo->gbm->fd, bo->handle, DRM_CLOEXEC | DRM_RDWR, &fd); DISPLAY_CHK_RETURN((ret), -1, DISPLAY_LOGE("drmPrimeHandleToFD failed ret: %{public}d errno: %{public}d", ret, errno)); return fd; } } // namespace DISPLAY } // namespace HDI } // namespace OHOS