1  /*
2   * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3   * Licensed under the Apache License, Version 2.0 (the "License");
4   * you may not use this file except in compliance with the License.
5   * You may obtain a copy of the License at
6   *
7   *     http://www.apache.org/licenses/LICENSE-2.0
8   *
9   * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  #include "hi_gbm.h"
17  #include <cerrno>
18  #include <cstring>
19  #include <cstdlib>
20  #include <fcntl.h>
21  #include <xf86drm.h>
22  #include <xf86drmMode.h>
23  #include <drm_fourcc.h>
24  #include <securec.h>
25  #include "display_log.h"
26  #include "hi_gbm_internal.h"
27  
28  namespace OHOS {
29  namespace HDI {
30  namespace DISPLAY {
31  #ifdef ROCKCHIP_CMA
32  #define ROCKCHIP_BO_CONTIG (1 << 0)
33  #endif
34  
35  using PlaneLayoutInfo = struct {
36      uint32_t numPlanes;
37      uint32_t radio[MAX_PLANES];
38  };
39  
40  using FormatInfo = struct {
41      uint32_t format;
42      uint32_t bitsPerPixel; // bits per pixel for first plane
43      const PlaneLayoutInfo *planes;
44  };
45  
46  static const PlaneLayoutInfo YUV_420SP_LAYOUT = {
47      .numPlanes = 2,
48      .radio = { 4, 2 },
49  };
50  
51  static const PlaneLayoutInfo YUV_420P_LAYOUT = {
52      .numPlanes = 3,
53      .radio = { 4, 1, 1 },
54  };
55  
56  static const PlaneLayoutInfo YUV_422SP_LAYOUT = {
57      .numPlanes = 2,
58      .radio = { 4, 4 },
59  };
60  
61  static const PlaneLayoutInfo YUV_422P_LAYOUT = {
62      .numPlanes = 3,
63      .radio = { 4, 2, 2 },
64  };
65  
GetFormatInfo(uint32_t format)66  static const FormatInfo *GetFormatInfo(uint32_t format)
67  {
68      static const FormatInfo FMT_INFOS[] = {
69          {DRM_FORMAT_RGBX8888,  32, nullptr},  {DRM_FORMAT_RGBA8888, 32,  nullptr},
70          {DRM_FORMAT_BGRX8888,  32, nullptr},  {DRM_FORMAT_BGRA8888, 32,  nullptr},
71          {DRM_FORMAT_RGB888,    24, nullptr},  {DRM_FORMAT_RGB565,   16,  nullptr},
72          {DRM_FORMAT_BGRX4444,  16, nullptr},  {DRM_FORMAT_BGRA4444, 16,  nullptr},
73          {DRM_FORMAT_RGBA4444,  16, nullptr},  {DRM_FORMAT_RGBX4444, 16,  nullptr},
74          {DRM_FORMAT_BGRX5551,  16, nullptr},  {DRM_FORMAT_BGRA5551, 16,  nullptr},
75          {DRM_FORMAT_NV12, 8, &YUV_420SP_LAYOUT}, {DRM_FORMAT_NV21, 8, &YUV_420SP_LAYOUT},
76          {DRM_FORMAT_NV16, 8, &YUV_422SP_LAYOUT},  {DRM_FORMAT_NV61, 8, &YUV_422SP_LAYOUT},
77          {DRM_FORMAT_YUV420, 8, &YUV_420P_LAYOUT}, {DRM_FORMAT_YVU420, 8, &YUV_420P_LAYOUT},
78          {DRM_FORMAT_YUV422, 8, &YUV_422P_LAYOUT}, {DRM_FORMAT_YVU422, 8, &YUV_422P_LAYOUT},
79      };
80  
81      for (uint32_t i = 0; i < sizeof(FMT_INFOS) / sizeof(FormatInfo); i++) {
82          if (FMT_INFOS[i].format == format) {
83              return &FMT_INFOS[i];
84          }
85      }
86      DISPLAY_LOGE("the format can not support");
87      return nullptr;
88  }
89  
InitGbmBo(struct gbm_bo * bo,const struct drm_mode_create_dumb * dumb)90  void InitGbmBo(struct gbm_bo *bo, const struct drm_mode_create_dumb *dumb)
91  {
92      DISPLAY_CHK_RETURN_NOT_VALUE((dumb == nullptr), DISPLAY_LOGE("dumb is null"));
93      DISPLAY_CHK_RETURN_NOT_VALUE((bo == nullptr), DISPLAY_LOGE("bo is null"));
94      bo->stride = dumb->pitch;
95      bo->size = dumb->size;
96      bo->handle = dumb->handle;
97  }
98  
AdjustStrideFromFormat(uint32_t format,uint32_t height)99  static uint32_t AdjustStrideFromFormat(uint32_t format, uint32_t height)
100  {
101      uint32_t tmpHeight = height;
102      const FormatInfo *fmtInfo = GetFormatInfo(format);
103      if ((fmtInfo != nullptr) && (fmtInfo->planes != nullptr)) {
104          uint32_t sum = fmtInfo->planes->radio[0];
105          for (uint32_t i = 1; (i < fmtInfo->planes->numPlanes) && (i < MAX_PLANES); i++) {
106              sum += fmtInfo->planes->radio[i];
107          }
108          if (sum > 0) {
109              tmpHeight = DIV_ROUND_UP((height * sum), fmtInfo->planes->radio[0]);
110          }
111          DISPLAY_LOGD("height adjust to : %{public}d", tmpHeight);
112      }
113      return tmpHeight;
114  }
115  
HdiGbmBoCreate(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t usage)116  struct gbm_bo *HdiGbmBoCreate(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format,
117      uint32_t usage)
118  {
119      DISPLAY_UNUSED(usage);
120      int ret;
121      struct gbm_bo *bo;
122      struct drm_mode_create_dumb dumb = { 0 };
123      const FormatInfo *fmtInfo = GetFormatInfo(format);
124      DISPLAY_CHK_RETURN((fmtInfo == nullptr), nullptr,
125          DISPLAY_LOGE("formt: 0x%{public}x can not get layout info", format));
126      bo = (struct gbm_bo *)calloc(1, sizeof(struct gbm_bo));
127      DISPLAY_CHK_RETURN((bo == nullptr), nullptr, DISPLAY_LOGE("gbm bo create fialed no memery"));
128      (void)memset_s(bo, sizeof(struct gbm_bo), 0, sizeof(struct gbm_bo));
129      bo->width = width;
130      bo->height = height;
131      bo->gbm = gbm;
132      bo->format = format;
133      // init create_dumb
134      dumb.height = ALIGN_UP(AdjustStrideFromFormat(format, height), HEIGHT_ALIGN);
135      dumb.width = ALIGN_UP(width, WIDTH_ALIGN);
136      dumb.flags = 0;
137      dumb.bpp = fmtInfo->bitsPerPixel;
138      ret = drmIoctl(gbm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &dumb);
139      DISPLAY_LOGD("fmt 0x%{public}x create dumb width: %{public}d  height: %{public}d bpp: %{public}u pitch"
140          "%{public}d size %{public}llu",
141          format, dumb.width, dumb.height, dumb.bpp, dumb.pitch, dumb.size);
142      DISPLAY_CHK_RETURN((ret != 0), nullptr, DISPLAY_LOGE("DRM_IOCTL_MODE_CREATE_DUMB failed errno %{public}d", errno));
143      InitGbmBo(bo, &dumb);
144      DISPLAY_LOGD(
145          "fmt 0x%{public}x create dumb width: %{public}d  height: %{public}d  stride %{public}d size %{public}u", format,
146          bo->width, bo->height, bo->stride, bo->size);
147      return bo;
148  }
149  
HdiGbmCreateDevice(int fd)150  struct gbm_device *HdiGbmCreateDevice(int fd)
151  {
152      struct gbm_device *gbm = (struct gbm_device *)calloc(1, sizeof(struct gbm_device));
153      DISPLAY_CHK_RETURN((gbm == nullptr), nullptr, DISPLAY_LOGE("memory calloc failed"));
154      gbm->fd = fd;
155      return gbm;
156  }
157  
HdiGbmDeviceDestroy(struct gbm_device * gbm)158  void HdiGbmDeviceDestroy(struct gbm_device *gbm)
159  {
160      free(gbm);
161  }
162  
HdiGbmBoGetStride(struct gbm_bo * bo)163  uint32_t HdiGbmBoGetStride(struct gbm_bo *bo)
164  {
165      DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null"));
166      return bo->stride;
167  }
168  
HdiGbmBoGetWidth(struct gbm_bo * bo)169  uint32_t HdiGbmBoGetWidth(struct gbm_bo *bo)
170  {
171      DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null"));
172      return bo->width;
173  }
174  
HdiGbmBoGetHeight(struct gbm_bo * bo)175  uint32_t HdiGbmBoGetHeight(struct gbm_bo *bo)
176  {
177      DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null"));
178      return bo->height;
179  }
180  
HdiGbmBoGetSize(struct gbm_bo * bo)181  uint32_t HdiGbmBoGetSize(struct gbm_bo *bo)
182  {
183      DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null"));
184      return bo->size;
185  }
186  
HdiGbmBoDestroy(struct gbm_bo * bo)187  void HdiGbmBoDestroy(struct gbm_bo *bo)
188  {
189      int ret;
190      DISPLAY_CHK_RETURN_NOT_VALUE((bo == nullptr), DISPLAY_LOGE("the bo is null"));
191      struct drm_mode_destroy_dumb dumb = { 0 };
192      dumb.handle = bo->handle;
193      ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dumb);
194      DISPLAY_CHK_RETURN_NOT_VALUE((ret), DISPLAY_LOGE("dumb buffer destroy failed errno %{public}d", errno));
195      free(bo);
196  }
197  
HdiGbmBoGetFd(struct gbm_bo * bo)198  int HdiGbmBoGetFd(struct gbm_bo *bo)
199  {
200      int fd;
201      int ret = drmPrimeHandleToFD(bo->gbm->fd, bo->handle, DRM_CLOEXEC | DRM_RDWR, &fd);
202      DISPLAY_CHK_RETURN((ret), -1,
203          DISPLAY_LOGE("drmPrimeHandleToFD  failed ret: %{public}d  errno: %{public}d", ret, errno));
204      return fd;
205  }
206  } // namespace DISPLAY
207  } // namespace HDI
208  } // namespace OHOS
209