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