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 g_yuv420SPLayout = {
47 .numPlanes = 2,
48 .radio = { 4, 2 },
49 };
50
51 static const PlaneLayoutInfo g_yuv420PLayout = {
52 .numPlanes = 3,
53 .radio = { 4, 1, 1 },
54 };
55
56 static const PlaneLayoutInfo g_yuv422SPLayout = {
57 .numPlanes = 2,
58 .radio = { 4, 4 },
59 };
60
61 static const PlaneLayoutInfo g_yuv422PLayout = {
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 fmtInfos[] = {
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, &g_yuv420SPLayout}, {DRM_FORMAT_NV21, 8, &g_yuv420SPLayout},
76 {DRM_FORMAT_NV16, 8, &g_yuv422SPLayout}, {DRM_FORMAT_NV61, 8, &g_yuv422SPLayout},
77 {DRM_FORMAT_YUV420, 8, &g_yuv420PLayout}, {DRM_FORMAT_YVU420, 8, &g_yuv420PLayout},
78 {DRM_FORMAT_YUV422, 8, &g_yuv422PLayout}, {DRM_FORMAT_YVU422, 8, &g_yuv422PLayout},
79 };
80
81 for (uint32_t i = 0; i < sizeof(fmtInfos) / sizeof(FormatInfo); i++) {
82 if (fmtInfos[i].format == format) {
83 return &fmtInfos[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
AlignUp(uint32_t x,uint32_t a)99 static uint32_t AlignUp(uint32_t x, uint32_t a)
100 {
101 return ((((x) + ((a)-1)) / (a)) * (a));
102 }
103
DivRoundUp(uint32_t n,uint32_t d)104 static uint32_t DivRoundUp(uint32_t n, uint32_t d)
105 {
106 return (((n) + (d)-1) / (d));
107 }
108
AdjustStrideFromFormat(uint32_t format,uint32_t height)109 static uint32_t AdjustStrideFromFormat(uint32_t format, uint32_t height)
110 {
111 const FormatInfo *fmtInfo = GetFormatInfo(format);
112 uint32_t adjustheight = height;
113 if ((fmtInfo != nullptr) && (fmtInfo->planes != nullptr)) {
114 uint32_t sum = fmtInfo->planes->radio[0];
115 for (uint32_t i = 1; (i < fmtInfo->planes->numPlanes) && (i < MAX_PLANES); i++) {
116 sum += fmtInfo->planes->radio[i];
117 }
118 if (sum > 0) {
119 adjustheight = DivRoundUp((height * sum), fmtInfo->planes->radio[0]);
120 }
121 DISPLAY_LOGD("height adjust to : %{public}d", adjustheight);
122 }
123 return adjustheight;
124 }
125
hdi_gbm_bo_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t usage)126 struct gbm_bo *hdi_gbm_bo_create(struct gbm_device *gbm, uint32_t width, uint32_t height,
127 uint32_t format, uint32_t usage)
128 {
129 int ret;
130 struct gbm_bo *bo = nullptr;
131 struct drm_mode_create_dumb dumb = { 0 };
132 const FormatInfo *fmtInfo = GetFormatInfo(format);
133 DISPLAY_CHK_RETURN((fmtInfo == nullptr), NULL, DISPLAY_LOGE("formt: 0x%{public}x can not get layout info", format));
134 bo = (struct gbm_bo *)calloc(1, sizeof(struct gbm_bo));
135 DISPLAY_CHK_RETURN((bo == nullptr), nullptr, DISPLAY_LOGE("gbm bo create fialed no memery %{public}d", usage));
136 (void)memset_s(bo, sizeof(struct gbm_bo), 0, sizeof(struct gbm_bo));
137 bo->width = width;
138 bo->height = height;
139 bo->gbm = gbm;
140 bo->format = format;
141 // init create_dumb
142 dumb.height = AlignUp(AdjustStrideFromFormat(format, height), HEIGHT_ALIGN);
143 dumb.width = AlignUp(width, WIDTH_ALIGN);
144 dumb.flags = 0;
145 dumb.bpp = fmtInfo->bitsPerPixel;
146 ret = drmIoctl(gbm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &dumb);
147 DISPLAY_LOGI("fmt 0x%{public}x create dumb width: %{public}d height: %{public}d bpp: %{public}u pitch %{public}d "
148 "size %{public}llu",
149 format, dumb.width, dumb.height, dumb.bpp, dumb.pitch, dumb.size);
150 DISPLAY_CHK_RETURN((ret != 0), nullptr, DISPLAY_LOGE("DRM_IOCTL_MODE_CREATE_DUMB failed errno %{public}d", errno));
151 InitGbmBo(bo, &dumb);
152 DISPLAY_LOGI(
153 "fmt 0x%{public}x create dumb width: %{public}d height: %{public}d stride %{public}d size %{public}u", format,
154 bo->width, bo->height, bo->stride, bo->size);
155 return bo;
156 }
157
hdi_gbm_create_device(int fd)158 struct gbm_device *hdi_gbm_create_device(int fd)
159 {
160 struct gbm_device *gbm;
161 gbm = (struct gbm_device *)calloc(1, sizeof(struct gbm_device));
162 DISPLAY_CHK_RETURN((gbm == nullptr), nullptr, DISPLAY_LOGE("memory calloc failed"));
163 gbm->fd = fd;
164 return gbm;
165 }
166
hdi_gbm_device_destroy(struct gbm_device * gbm)167 void hdi_gbm_device_destroy(struct gbm_device *gbm)
168 {
169 free(gbm);
170 }
171
hdi_gbm_bo_get_stride(struct gbm_bo * bo)172 uint32_t hdi_gbm_bo_get_stride(struct gbm_bo *bo)
173 {
174 DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null"));
175 return bo->stride;
176 }
177
hdi_gbm_bo_get_width(struct gbm_bo * bo)178 uint32_t hdi_gbm_bo_get_width(struct gbm_bo *bo)
179 {
180 DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null"));
181 return bo->width;
182 }
183
hdi_gbm_bo_get_height(struct gbm_bo * bo)184 uint32_t hdi_gbm_bo_get_height(struct gbm_bo *bo)
185 {
186 DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null"));
187 return bo->height;
188 }
189
hdi_gbm_bo_get_size(struct gbm_bo * bo)190 uint32_t hdi_gbm_bo_get_size(struct gbm_bo *bo)
191 {
192 DISPLAY_CHK_RETURN((bo == nullptr), 0, DISPLAY_LOGE("the bo is null"));
193 return bo->size;
194 }
195
hdi_gbm_bo_destroy(struct gbm_bo * bo)196 void hdi_gbm_bo_destroy(struct gbm_bo *bo)
197 {
198 int ret;
199 DISPLAY_CHK_RETURN_NOT_VALUE((bo == nullptr), DISPLAY_LOGE("the bo is null"));
200 struct drm_mode_destroy_dumb dumb = { 0 };
201 dumb.handle = bo->handle;
202 ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dumb);
203 DISPLAY_CHK_RETURN_NOT_VALUE((ret), DISPLAY_LOGE("dumb buffer destroy failed errno %{public}d", errno));
204 free(bo);
205 }
206
hdi_gbm_bo_get_fd(struct gbm_bo * bo)207 int hdi_gbm_bo_get_fd(struct gbm_bo *bo)
208 {
209 int fd;
210 int ret;
211 ret = drmPrimeHandleToFD(bo->gbm->fd, bo->handle, DRM_CLOEXEC | DRM_RDWR, &fd);
212 DISPLAY_CHK_RETURN((ret), -1, \
213 DISPLAY_LOGE("drmPrimeHandleToFD failed ret: %{public}d errno: %{public}d", ret, errno));
214 return fd;
215 }
216 } // namespace DISPLAY
217 } // namespace HDI
218 } // namespace OHOS
219