1 /*
2 * Copyright (c) 2021 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 <errno.h>
18 #include <fcntl.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <xf86drm.h>
22 #include <xf86drmMode.h>
23 #include <drm_fourcc.h>
24 #include <securec.h>
25 #include "display_common.h"
26 #include "hi_gbm_internal.h"
27 #ifdef ROCKCHIP_CMA
28 #define ROCKCHIP_BO_CONTIG (1 << 0)
29 #endif
30
31 typedef struct {
32 uint32_t numPlanes;
33 uint32_t radio[MAX_PLANES];
34 } PlaneLayoutInfo;
35
36 typedef struct {
37 uint32_t format;
38 uint32_t bitsPerPixel; // bits per pixel for first plane
39 const PlaneLayoutInfo *planes;
40 } FormatInfo;
41
42 static const PlaneLayoutInfo g_yuv420SPLayout = {
43 .numPlanes = 2,
44 .radio = { 4, 2 },
45 };
46
47 static const PlaneLayoutInfo g_yuv420PLayout = {
48 .numPlanes = 3,
49 .radio = { 4, 1, 1 },
50 };
51
52 static const PlaneLayoutInfo g_yuv422SPLayout = {
53 .numPlanes = 2,
54 .radio = { 4, 4 },
55 };
56
57 static const PlaneLayoutInfo g_yuv422PLayout = {
58 .numPlanes = 3,
59 .radio = { 4, 2, 2 },
60 };
61
GetFormatInfo(uint32_t format)62 static const FormatInfo *GetFormatInfo(uint32_t format)
63 {
64 static const FormatInfo fmtInfos[] = {
65 {DRM_FORMAT_RGBX8888, 32, NULL}, {DRM_FORMAT_RGBA8888, 32, NULL},
66 {DRM_FORMAT_BGRX8888, 32, NULL}, {DRM_FORMAT_BGRA8888, 32, NULL},
67 {DRM_FORMAT_RGB888, 24, NULL}, {DRM_FORMAT_RGB565, 16, NULL},
68 {DRM_FORMAT_BGRX4444, 16, NULL}, {DRM_FORMAT_BGRA4444, 16, NULL},
69 {DRM_FORMAT_RGBA4444, 16, NULL}, {DRM_FORMAT_RGBX4444, 16, NULL},
70 {DRM_FORMAT_BGRX5551, 16, NULL}, {DRM_FORMAT_BGRA5551, 16, NULL},
71 {DRM_FORMAT_NV12, 8, &g_yuv420SPLayout}, {DRM_FORMAT_NV21, 8, &g_yuv420SPLayout},
72 {DRM_FORMAT_NV16, 8, &g_yuv422SPLayout}, {DRM_FORMAT_NV61, 8, &g_yuv422SPLayout},
73 {DRM_FORMAT_YUV420, 8, &g_yuv420PLayout}, {DRM_FORMAT_YVU420, 8, &g_yuv420PLayout},
74 {DRM_FORMAT_YUV422, 8, &g_yuv422PLayout}, {DRM_FORMAT_YVU422, 8, &g_yuv422PLayout},
75 };
76
77 for (uint32_t i = 0; i < sizeof(fmtInfos) / sizeof(FormatInfo); i++) {
78 if (fmtInfos[i].format == format) {
79 return &fmtInfos[i];
80 }
81 }
82 DISPLAY_LOGE("the format can not support");
83 return NULL;
84 }
85
InitGbmBo(struct gbm_bo * bo,const struct drm_mode_create_dumb * dumb)86 void InitGbmBo(struct gbm_bo *bo, const struct drm_mode_create_dumb *dumb)
87 {
88 DISPLAY_CHK_RETURN_NOT_VALUE((dumb == NULL), DISPLAY_LOGE("dumb is null"));
89 DISPLAY_CHK_RETURN_NOT_VALUE((bo == NULL), DISPLAY_LOGE("bo is null"));
90 bo->stride = dumb->pitch;
91 bo->size = dumb->size;
92 bo->handle = dumb->handle;
93 }
94
AdjustStrideFromFormat(uint32_t format,uint32_t height)95 static uint32_t AdjustStrideFromFormat(uint32_t format, uint32_t height)
96 {
97 uint32_t tmpHeight = height;
98 const FormatInfo *fmtInfo = GetFormatInfo(format);
99 if ((fmtInfo != NULL) && (fmtInfo->planes != NULL)) {
100 uint32_t sum = fmtInfo->planes->radio[0];
101 for (uint32_t i = 1; (i < fmtInfo->planes->numPlanes) && (i < MAX_PLANES); i++) {
102 sum += fmtInfo->planes->radio[i];
103 }
104 if (sum > 0) {
105 tmpHeight = DIV_ROUND_UP((height * sum), fmtInfo->planes->radio[0]);
106 }
107 DISPLAY_DEBUGLOG("height adjust to : %{public}d", tmpHeight);
108 }
109 return tmpHeight;
110 }
111
hdi_gbm_bo_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t usage)112 struct gbm_bo *hdi_gbm_bo_create(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format,
113 uint32_t usage)
114 {
115 DISPLAY_UNUSED(usage);
116 int ret;
117 struct gbm_bo *bo;
118 struct drm_mode_create_dumb dumb = { 0 };
119 const FormatInfo *fmtInfo = GetFormatInfo(format);
120 DISPLAY_CHK_RETURN((fmtInfo == NULL), NULL, DISPLAY_LOGE("formt: 0x%{public}x can not get layout info", format));
121 bo = (struct gbm_bo *)calloc(1, sizeof(struct gbm_bo));
122 DISPLAY_CHK_RETURN((bo == NULL), NULL, DISPLAY_LOGE("gbm bo create fialed no memery"));
123 (void)memset_s(bo, sizeof(struct gbm_bo), 0, sizeof(struct gbm_bo));
124 bo->width = width;
125 bo->height = height;
126 bo->gbm = gbm;
127 bo->format = format;
128 // init create_dumb
129 dumb.height = ALIGN_UP(height, HEIGHT_ALIGN);
130 dumb.width = ALIGN_UP(AdjustStrideFromFormat(format, width), WIDTH_ALIGN);
131 dumb.flags = 0;
132 dumb.bpp = fmtInfo->bitsPerPixel;
133 ret = drmIoctl(gbm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &dumb);
134 DISPLAY_DEBUGLOG("fmt 0x%{public}x create dumb width: %{public}d height: %{public}d bpp: %{public}u pitch"
135 "%{public}d size %{public}llu",
136 format, dumb.width, dumb.height, dumb.bpp, dumb.pitch, dumb.size);
137 DISPLAY_CHK_RETURN((ret != 0), NULL, DISPLAY_LOGE("DRM_IOCTL_MODE_CREATE_DUMB failed errno %{public}d", errno));
138 InitGbmBo(bo, &dumb);
139 DISPLAY_DEBUGLOG(
140 "fmt 0x%{public}x create dumb width: %{public}d height: %{public}d stride %{public}d size %{public}u", format,
141 bo->width, bo->height, bo->stride, bo->size);
142 return bo;
143 }
144
hdi_gbm_create_device(int fd)145 struct gbm_device *hdi_gbm_create_device(int fd)
146 {
147 struct gbm_device *gbm;
148 gbm = (struct gbm_device *)calloc(1, sizeof(struct gbm_device));
149 DISPLAY_CHK_RETURN((gbm == NULL), NULL, DISPLAY_LOGE("memory calloc failed"));
150 gbm->fd = fd;
151 return gbm;
152 }
153
hdi_gbm_device_destroy(struct gbm_device * gbm)154 void hdi_gbm_device_destroy(struct gbm_device *gbm)
155 {
156 free(gbm);
157 }
158
hdi_gbm_bo_get_stride(struct gbm_bo * bo)159 uint32_t hdi_gbm_bo_get_stride(struct gbm_bo *bo)
160 {
161 DISPLAY_CHK_RETURN((bo == NULL), 0, DISPLAY_LOGE("the bo is null"));
162 return bo->stride;
163 }
164
hdi_gbm_bo_get_width(struct gbm_bo * bo)165 uint32_t hdi_gbm_bo_get_width(struct gbm_bo *bo)
166 {
167 DISPLAY_CHK_RETURN((bo == NULL), 0, DISPLAY_LOGE("the bo is null"));
168 return bo->width;
169 }
170
hdi_gbm_bo_get_height(struct gbm_bo * bo)171 uint32_t hdi_gbm_bo_get_height(struct gbm_bo *bo)
172 {
173 DISPLAY_CHK_RETURN((bo == NULL), 0, DISPLAY_LOGE("the bo is null"));
174 return bo->height;
175 }
176
hdi_gbm_bo_destroy(struct gbm_bo * bo)177 void hdi_gbm_bo_destroy(struct gbm_bo *bo)
178 {
179 int ret;
180 DISPLAY_CHK_RETURN_NOT_VALUE((bo == NULL), DISPLAY_LOGE("the bo is null"));
181 struct drm_mode_destroy_dumb dumb = { 0 };
182 dumb.handle = bo->handle;
183 ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dumb);
184 DISPLAY_CHK_RETURN_NOT_VALUE((ret), DISPLAY_LOGE("dumb buffer destroy failed errno %{public}d", errno));
185 free(bo);
186 }
187
hdi_gbm_bo_get_fd(struct gbm_bo * bo)188 int hdi_gbm_bo_get_fd(struct gbm_bo *bo)
189 {
190 int fd, ret;
191 ret = drmPrimeHandleToFD(bo->gbm->fd, bo->handle, DRM_CLOEXEC | DRM_RDWR, &fd);
192 DISPLAY_CHK_RETURN((ret), -1,
193 DISPLAY_LOGE("drmPrimeHandleToFD failed ret: %{public}d errno: %{public}d", ret, errno));
194 return fd;
195 }
196