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 "display_gralloc.h"
17 #include <errno.h>
18 #include <inttypes.h>
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <sys/mman.h>
22 #include <sys/shm.h>
23 #include <securec.h>
24 #include "buffer_handle.h"
25 #include "display_type.h"
26 #include "disp_common.h"
27 #include "hdf_log.h"
28 #include "osal_mem.h"
29
30 #define DEFAULT_READ_WRITE_PERMISSIONS 0666
31 #define MAX_MALLOC_SIZE 0x10000000L
32 #define SHM_MAX_KEY 10000
33 #define SHM_START_KEY 1
34 #define INVALID_SHMID -1
35 #define BITS_PER_BYTE 8
36
37 #define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
38 #define ALIGN_UP(x, a) ((((x) + ((a)-1)) / (a)) * (a))
39 #define HEIGHT_ALIGN 2U
40 #define WIDTH_ALIGN 8U
41 #define MAX_PLANES 3
42
43 #undef HDF_LOG_TAG
44 #define HDF_LOG_TAG display_gralloc_c
45
46 typedef struct {
47 BufferHandle hdl;
48 int32_t shmid;
49 } PriBufferHandle;
50
51 typedef struct {
52 uint32_t numPlanes;
53 uint32_t radio[MAX_PLANES];
54 } PlaneLayoutInfo;
55
56 typedef struct {
57 uint32_t format;
58 uint32_t bitsPerPixel; // bits per pixel for first plane
59 const PlaneLayoutInfo *planes;
60 } FormatInfo;
61
62 struct GrallocManager {
63 pthread_mutex_t mutex;
64 pthread_mutexattr_t mutexattr;
65 int32_t count;
66 };
67
68 static struct GrallocManager g_grallocManager;
69
70 static const PlaneLayoutInfo g_yuv420SPLayout = {
71 .numPlanes = 2,
72 .radio = { 4, 2 },
73 };
74
75 static const PlaneLayoutInfo g_yuv420PLayout = {
76 .numPlanes = 3,
77 .radio = { 4, 1, 1 },
78 };
79
GetGrallocMgr(void)80 static void GetGrallocMgr(void)
81 {
82 g_grallocManager.count++;
83 }
84
PutGrallocMgr(void)85 static int32_t PutGrallocMgr(void)
86 {
87 g_grallocManager.count--;
88 return g_grallocManager.count;
89 }
90
LockGrallocMgr(void)91 static void LockGrallocMgr(void)
92 {
93 pthread_mutex_lock(&g_grallocManager.mutex);
94 }
95
UnlockGrallocMgr(void)96 static void UnlockGrallocMgr(void)
97 {
98 pthread_mutex_unlock(&g_grallocManager.mutex);
99 }
100
GetFormatInfo(uint32_t format)101 static const FormatInfo *GetFormatInfo(uint32_t format)
102 {
103 static const FormatInfo fmtInfos[] = {
104 {PIXEL_FMT_RGBX_8888, 32, NULL}, {PIXEL_FMT_RGBA_8888, 32, NULL},
105 {PIXEL_FMT_BGRX_8888, 32, NULL}, {PIXEL_FMT_BGRA_8888, 32, NULL},
106 {PIXEL_FMT_RGB_888, 24, NULL}, {PIXEL_FMT_BGR_565, 16, NULL},
107 {PIXEL_FMT_RGBA_5551, 16, NULL}, {PIXEL_FMT_RGB_565, 16, NULL},
108 {PIXEL_FMT_BGRX_4444, 16, NULL}, {PIXEL_FMT_BGRA_4444, 16, NULL},
109 {PIXEL_FMT_RGBA_4444, 16, NULL}, {PIXEL_FMT_RGBX_4444, 16, NULL},
110 {PIXEL_FMT_BGRX_5551, 16, NULL}, {PIXEL_FMT_BGRA_5551, 16, NULL},
111 {PIXEL_FMT_YCBCR_420_SP, 8, &g_yuv420SPLayout}, {PIXEL_FMT_YCRCB_420_SP, 8, &g_yuv420SPLayout},
112 {PIXEL_FMT_YCBCR_420_P, 8, &g_yuv420PLayout}, {PIXEL_FMT_YCRCB_420_P, 8, &g_yuv420PLayout},
113 };
114
115 for (uint32_t i = 0; i < sizeof(fmtInfos) / sizeof(FormatInfo); i++) {
116 if (fmtInfos[i].format == format) {
117 return &fmtInfos[i];
118 }
119 }
120 HDF_LOGE("the format can not support %d %d", format, PIXEL_FMT_RGBA_8888);
121 return NULL;
122 }
123
AdjustStrideFromFormat(uint32_t format,uint32_t width)124 static uint32_t AdjustStrideFromFormat(uint32_t format, uint32_t width)
125 {
126 const FormatInfo *fmtInfo = GetFormatInfo(format);
127 if ((fmtInfo != NULL) && (fmtInfo->planes != NULL)) {
128 uint32_t sum = fmtInfo->planes->radio[0];
129 for (uint32_t i = 1; (i < fmtInfo->planes->numPlanes) && (i < MAX_PLANES); i++) {
130 sum += fmtInfo->planes->radio[i];
131 }
132 if (sum > 0) {
133 width = DIV_ROUND_UP((width * sum), fmtInfo->planes->radio[0]);
134 }
135 }
136 return width;
137 }
138
InitBufferHandle(PriBufferHandle * buffer,const AllocInfo * info)139 static int32_t InitBufferHandle(PriBufferHandle* buffer, const AllocInfo* info)
140 {
141 int32_t size;
142 int32_t stride;
143 int32_t h = ALIGN_UP(info->height, HEIGHT_ALIGN);
144 const FormatInfo *fmtInfo = GetFormatInfo(info->format);
145 if (fmtInfo == NULL) {
146 HDF_LOGE("can not get format information : %d", buffer->hdl.format);
147 return DISPLAY_FAILURE;
148 }
149
150 stride = ALIGN_UP(AdjustStrideFromFormat(info->format, info->width), WIDTH_ALIGN) *
151 fmtInfo->bitsPerPixel / BITS_PER_BYTE;
152 size = h * stride;
153 buffer->hdl.width = info->width;
154 buffer->hdl.stride = stride;
155 buffer->hdl.height = info->height;
156 buffer->hdl.size = size;
157 buffer->hdl.usage = info->usage;
158 buffer->hdl.fd = -1;
159 buffer->shmid = INVALID_SHMID;
160 buffer->hdl.format = info->format;
161 buffer->hdl.reserveInts = (sizeof(PriBufferHandle) - sizeof(BufferHandle) -
162 buffer->hdl.reserveFds * sizeof(uint32_t)) / sizeof(uint32_t);
163 return DISPLAY_SUCCESS;
164 }
165
AllocShm(BufferHandle * buffer)166 static int32_t AllocShm(BufferHandle *buffer)
167 {
168 static int32_t key = SHM_START_KEY;
169 int32_t shmid;
170
171 while ((shmid = shmget(key, buffer->size, IPC_CREAT | IPC_EXCL | DEFAULT_READ_WRITE_PERMISSIONS)) < 0) {
172 if (errno != EEXIST) {
173 HDF_LOGE("%s: fail to alloc the shared memory, errno = %d", __func__, errno);
174 return DISPLAY_FAILURE;
175 }
176 key++;
177 if (key >= SHM_MAX_KEY) {
178 key = SHM_START_KEY;
179 }
180 }
181 void *pBase = shmat(shmid, NULL, 0);
182 if (pBase == ((void *)-1)) {
183 HDF_LOGE("%s: Fail to attach the shared memory, errno = %d", __func__, errno);
184 if (shmctl(shmid, IPC_RMID, 0) == -1) {
185 HDF_LOGE("%s: Fail to free shmid, errno = %d", __func__, errno);
186 }
187 return DISPLAY_FAILURE;
188 }
189 buffer->virAddr = pBase;
190 buffer->fd = key;
191 ((PriBufferHandle*)buffer)->shmid = shmid;
192 key++;
193 if (memset_s(pBase, buffer->size, 0x0, buffer->size) != EOK) {
194 HDF_LOGE("memset_s failure");
195 if (shmctl(shmid, IPC_RMID, 0) == -1) {
196 HDF_LOGE("%s: Fail to free shmid, errno = %d", __func__, errno);
197 }
198 return DISPLAY_FAILURE;
199 }
200 if (key >= SHM_MAX_KEY) {
201 key = SHM_START_KEY;
202 }
203 return DISPLAY_SUCCESS;
204 }
205
AllocMem(const AllocInfo * info,BufferHandle ** buffer)206 static int32_t AllocMem(const AllocInfo* info, BufferHandle **buffer)
207 {
208 int32_t ret;
209
210 DISPLAY_CHK_RETURN((buffer == NULL), DISPLAY_NULL_PTR, HDF_LOGE("%s: in buffer is null", __func__));
211 DISPLAY_CHK_RETURN((info == NULL), DISPLAY_NULL_PTR, HDF_LOGE("%s: in info is null", __func__));
212 PriBufferHandle* priBuffer = calloc(1, sizeof(PriBufferHandle));
213 DISPLAY_CHK_RETURN((priBuffer == NULL), DISPLAY_NULL_PTR, HDF_LOGE("%s: can not calloc errno : %d",
214 __func__, errno));
215 ret = InitBufferHandle(priBuffer, info);
216 DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, HDF_LOGE("%s: can not init buffe handle",
217 __func__); goto OUT);
218
219 BufferHandle *bufferHdl = &priBuffer->hdl;
220 DISPLAY_CHK_RETURN(((bufferHdl->size > MAX_MALLOC_SIZE) || (bufferHdl->size == 0)),
221 DISPLAY_FAILURE, HDF_LOGE("%s: size is invalid %d ", __func__, bufferHdl->size); goto OUT);
222 LockGrallocMgr();
223
224 ret = AllocShm(bufferHdl);
225
226
227 OUT:
228 if ((ret != DISPLAY_SUCCESS) && (bufferHdl != NULL)) {
229 free(bufferHdl);
230 bufferHdl = NULL;
231 }
232 *buffer = bufferHdl;
233 UnlockGrallocMgr();
234 return ret;
235 }
236
FreeShm(BufferHandle * buffer)237 static void FreeShm(BufferHandle *buffer)
238 {
239 CHECK_NULLPOINTER_RETURN(buffer->virAddr);
240 if (shmdt(buffer->virAddr) == -1) {
241 HDF_LOGE("%s: Fail to free shared memory, errno = %d", __func__, errno);
242 }
243 if (shmctl(((PriBufferHandle*)buffer)->shmid, IPC_RMID, 0) == -1) {
244 HDF_LOGE("%s: Fail to free shmid, errno = %d", __func__, errno);
245 }
246 }
247
FreeMem(BufferHandle * buffer)248 static void FreeMem(BufferHandle *buffer)
249 {
250 CHECK_NULLPOINTER_RETURN(buffer);
251 if ((buffer->size > MAX_MALLOC_SIZE) || (buffer->size == 0)) {
252 HDF_LOGE("%s: size is invalid, buffer->size = %d", __func__, buffer->size);
253 return;
254 }
255
256 LockGrallocMgr();
257
258 FreeShm(buffer);
259
260 UnlockGrallocMgr();
261 }
262
MmapShm(BufferHandle * buffer)263 static void *MmapShm(BufferHandle *buffer)
264 {
265 int32_t shmid;
266
267 shmid = shmget(buffer->fd, buffer->size, IPC_EXCL | DEFAULT_READ_WRITE_PERMISSIONS);
268 if (shmid < 0) {
269 HDF_LOGE("%s: Fail to mmap the shared memory, errno = %d", __func__, errno);
270 return NULL;
271 }
272 void *pBase = shmat(shmid, NULL, 0);
273 if (pBase == ((void *)-1)) {
274 HDF_LOGE("%s: Fail to attach the shared memory, errno = %d", __func__, errno);
275 return NULL;
276 }
277 ((PriBufferHandle*)buffer)->shmid = shmid;
278 return pBase;
279 }
280
Mmap(BufferHandle * buffer)281 static void *Mmap(BufferHandle *buffer)
282 {
283 void *temp = NULL;
284
285 CHECK_NULLPOINTER_RETURN_VALUE(buffer, NULL);
286 if ((buffer->size > MAX_MALLOC_SIZE) || (buffer->size == 0)) {
287 HDF_LOGE("%s: size is invalid, buffer->size = %d", __func__, buffer->size);
288 return NULL;
289 }
290
291 LockGrallocMgr();
292
293 temp = MmapShm(buffer);
294
295 UnlockGrallocMgr();
296 return temp;
297 }
298
UnmapShm(BufferHandle * buffer)299 static int32_t UnmapShm(BufferHandle *buffer)
300 {
301 if (shmdt(buffer->virAddr) == -1) {
302 HDF_LOGE("%s: Fail to unmap shared memory errno = %d", __func__, errno);
303 return DISPLAY_FAILURE;
304 }
305 int32_t shmid = ((PriBufferHandle*)buffer)->shmid;
306 if ((shmid != INVALID_SHMID) && (shmctl(shmid, IPC_RMID, 0) == -1)) {
307
308 }
309 return DISPLAY_SUCCESS;
310 }
311
Unmap(BufferHandle * buffer)312 static int32_t Unmap(BufferHandle *buffer)
313 {
314 int32_t ret;
315
316 CHECK_NULLPOINTER_RETURN_VALUE(buffer, DISPLAY_NULL_PTR);
317 CHECK_NULLPOINTER_RETURN_VALUE(buffer->virAddr, DISPLAY_NULL_PTR);
318 if ((buffer->size > MAX_MALLOC_SIZE) || (buffer->size == 0)) {
319 HDF_LOGE("%s: size is invalid, buffer->size = %d", __func__, buffer->size);
320 return DISPLAY_FAILURE;
321 }
322 LockGrallocMgr();
323
324 ret = UnmapShm(buffer);
325
326 UnlockGrallocMgr();
327 return ret;
328 }
329
GrallocInitialize(GrallocFuncs ** funcs)330 int32_t GrallocInitialize(GrallocFuncs **funcs)
331 {
332 static GrallocFuncs *gFuncs = NULL;
333
334 if (funcs == NULL) {
335 HDF_LOGE("%s: funcs is null", __func__);
336 return DISPLAY_NULL_PTR;
337 }
338 if (gFuncs == NULL) {
339 gFuncs = (GrallocFuncs *)OsalMemCalloc(sizeof(GrallocFuncs));
340 if (gFuncs == NULL) {
341 HDF_LOGE("%s: gFuncs is null", __func__);
342 return DISPLAY_NULL_PTR;
343 }
344 pthread_mutexattr_init(&g_grallocManager.mutexattr);
345 pthread_mutexattr_setpshared(&g_grallocManager.mutexattr, PTHREAD_PROCESS_SHARED);
346 pthread_mutex_init(&g_grallocManager.mutex, &g_grallocManager.mutexattr);
347 gFuncs->AllocMem = AllocMem;
348 gFuncs->FreeMem = FreeMem;
349 gFuncs->Mmap = Mmap;
350 gFuncs->Unmap = Unmap;
351 }
352 *funcs = gFuncs;
353 GetGrallocMgr();
354 HDF_LOGI("%s: gralloc initialize success", __func__);
355 return DISPLAY_SUCCESS;
356 }
357
GrallocUninitialize(GrallocFuncs * funcs)358 int32_t GrallocUninitialize(GrallocFuncs *funcs)
359 {
360 if (funcs == NULL) {
361 HDF_LOGE("%s: funcs is null", __func__);
362 return DISPLAY_NULL_PTR;
363 }
364 if (PutGrallocMgr() == 0) {
365 pthread_mutexattr_destroy(&g_grallocManager.mutexattr);
366 pthread_mutex_destroy(&g_grallocManager.mutex);
367 OsalMemFree(funcs);
368 }
369 HDF_LOGI("%s: gralloc uninitialize success", __func__);
370 return DISPLAY_SUCCESS;
371 }
372