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 <cerrno>
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
46typedef struct {
47    BufferHandle hdl;
48    int32_t shmid;
49} PriBufferHandle;
50
51typedef struct {
52    uint32_t numPlanes;
53    uint32_t radio[MAX_PLANES];
54} PlaneLayoutInfo;
55
56typedef struct {
57    uint32_t format;
58    uint32_t bitsPerPixel; // bits per pixel for first plane
59    const PlaneLayoutInfo *planes;
60} FormatInfo;
61
62struct GrallocManager {
63    pthread_mutex_t mutex;
64    pthread_mutexattr_t mutexattr;
65    int32_t count;
66};
67
68static struct GrallocManager g_grallocManager;
69
70static const PlaneLayoutInfo g_yuv420SPLayout = {
71    .numPlanes = 2,
72    .radio = { 4, 2 },
73};
74
75static const PlaneLayoutInfo g_yuv420PLayout = {
76    .numPlanes = 3,
77    .radio = { 4, 1, 1 },
78};
79
80static void GetGrallocMgr(void)
81{
82    g_grallocManager.count++;
83}
84
85static int32_t PutGrallocMgr(void)
86{
87    g_grallocManager.count--;
88    return g_grallocManager.count;
89}
90
91static void LockGrallocMgr(void)
92{
93    pthread_mutex_lock(&g_grallocManager.mutex);
94}
95
96static void UnlockGrallocMgr(void)
97{
98    pthread_mutex_unlock(&g_grallocManager.mutex);
99}
100
101static 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
124static 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
139static 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
166static 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
206static int32_t AllocMem(const AllocInfo* info, BufferHandle **buffer)
207{
208    int32_t ret;
209    DISPLAY_CHK_RETURN((buffer == NULL), DISPLAY_NULL_PTR, HDF_LOGE("%s: in buffer is null", __func__));
210    DISPLAY_CHK_RETURN((info == NULL), DISPLAY_NULL_PTR, HDF_LOGE("%s: in info is null", __func__));
211    PriBufferHandle* priBuffer = (PriBufferHandle*)calloc(1, sizeof(PriBufferHandle));
212    DISPLAY_CHK_RETURN((priBuffer == NULL), DISPLAY_NULL_PTR, HDF_LOGE("%s: can not calloc errno : %d",
213        __func__, errno));
214    ret = InitBufferHandle(priBuffer, info);
215    DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, HDF_LOGE("%s: can not init buffe handle",
216        __func__); goto OUT);
217
218    BufferHandle *bufferHdl = &priBuffer->hdl;
219    DISPLAY_CHK_RETURN(((bufferHdl->size > MAX_MALLOC_SIZE) || (bufferHdl->size == 0)),
220        DISPLAY_FAILURE, HDF_LOGE("%s: size is invalid %d ", __func__, bufferHdl->size); goto OUT);
221    LockGrallocMgr();
222    if (bufferHdl->usage == HBM_USE_MEM_SHARE) {
223        ret = AllocShm(bufferHdl);
224    } else {
225        HDF_LOGE("%s: not support memory usage: 0x%" PRIx64 "", __func__, bufferHdl->usage);
226        ret = DISPLAY_NOT_SUPPORT;
227    }
228
229OUT:
230    if ((ret != DISPLAY_SUCCESS) && (bufferHdl != NULL)) {
231        free(bufferHdl);
232        bufferHdl = NULL;
233    }
234    *buffer = bufferHdl;
235    UnlockGrallocMgr();
236    return ret;
237}
238
239static void FreeShm(BufferHandle *buffer)
240{
241    CHECK_NULLPOINTER_RETURN(buffer->virAddr);
242    if (shmdt(buffer->virAddr) == -1) {
243        HDF_LOGE("%s: Fail to free shared memory, errno = %d", __func__, errno);
244    }
245    if (shmctl(((PriBufferHandle*)buffer)->shmid, IPC_RMID, 0) == -1) {
246        HDF_LOGE("%s: Fail to free shmid, errno = %d", __func__, errno);
247    }
248}
249
250static void FreeMem(BufferHandle *buffer)
251{
252    CHECK_NULLPOINTER_RETURN(buffer);
253    if ((buffer->size > MAX_MALLOC_SIZE) || (buffer->size == 0)) {
254        HDF_LOGE("%s: size is invalid, buffer->size = %d", __func__, buffer->size);
255        return;
256    }
257
258    LockGrallocMgr();
259    if (buffer->usage == HBM_USE_MEM_SHARE) {
260        FreeShm(buffer);
261    } else {
262        HDF_LOGE("%s: not support memory usage: 0x%" PRIx64 "", __func__, buffer->usage);
263    }
264    UnlockGrallocMgr();
265}
266
267static void *MmapShm(BufferHandle *buffer)
268{
269    int32_t shmid;
270
271    shmid = shmget(buffer->fd, buffer->size, IPC_EXCL | DEFAULT_READ_WRITE_PERMISSIONS);
272    if (shmid < 0) {
273        HDF_LOGE("%s: Fail to mmap the shared memory, errno = %d", __func__, errno);
274        return NULL;
275    }
276    void *pBase = shmat(shmid, NULL, 0);
277    if (pBase == ((void *)-1)) {
278        HDF_LOGE("%s: Fail to attach the shared memory, errno = %d", __func__, errno);
279        return NULL;
280    }
281    ((PriBufferHandle*)buffer)->shmid = shmid;
282    HDF_LOGI("%s: Mmap shared memory succeed", __func__);
283    return pBase;
284}
285
286static void *Mmap(BufferHandle *buffer)
287{
288    void *temp = NULL;
289
290    CHECK_NULLPOINTER_RETURN_VALUE(buffer, NULL);
291    if ((buffer->size > MAX_MALLOC_SIZE) || (buffer->size == 0)) {
292        HDF_LOGE("%s: size is invalid, buffer->size = %d", __func__, buffer->size);
293        return NULL;
294    }
295
296    LockGrallocMgr();
297    if (buffer->usage == HBM_USE_MEM_SHARE) {
298        temp = MmapShm(buffer);
299    } else {
300        HDF_LOGE("%s: not support memory usage: 0x%" PRIx64 "", __func__, buffer->usage);
301    }
302    UnlockGrallocMgr();
303    return temp;
304}
305
306static int32_t UnmapShm(BufferHandle *buffer)
307{
308    if (shmdt(buffer->virAddr) == -1) {
309        HDF_LOGE("%s: Fail to unmap shared memory errno =  %d", __func__, errno);
310        return DISPLAY_FAILURE;
311    }
312    int32_t shmid = ((PriBufferHandle*)buffer)->shmid;
313    if ((shmid != INVALID_SHMID) && (shmctl(shmid, IPC_RMID, 0) == -1)) {
314        HDF_LOGE("%s: Fail to free shmid, errno = %d", __func__, errno);
315    }
316    return DISPLAY_SUCCESS;
317}
318
319static int32_t Unmap(BufferHandle *buffer)
320{
321    int32_t ret;
322
323    CHECK_NULLPOINTER_RETURN_VALUE(buffer, DISPLAY_NULL_PTR);
324    CHECK_NULLPOINTER_RETURN_VALUE(buffer->virAddr, DISPLAY_NULL_PTR);
325    if ((buffer->size > MAX_MALLOC_SIZE) || (buffer->size == 0)) {
326        HDF_LOGE("%s: size is invalid, buffer->size = %d", __func__, buffer->size);
327        return DISPLAY_FAILURE;
328    }
329    LockGrallocMgr();
330    if (buffer->usage == HBM_USE_MEM_SHARE) {
331        ret = UnmapShm(buffer);
332    } else {
333        HDF_LOGE("%s: not support memory usage: 0x%" PRIx64 "", __func__, buffer->usage);
334        ret = DISPLAY_FAILURE;
335    }
336    UnlockGrallocMgr();
337    return ret;
338}
339
340int32_t GrallocInitialize(GrallocFuncs **funcs)
341{
342    static GrallocFuncs *gFuncs = NULL;
343
344    if (funcs == NULL) {
345        HDF_LOGE("%s: funcs is null", __func__);
346        return DISPLAY_NULL_PTR;
347    }
348    if (gFuncs == NULL) {
349        gFuncs = (GrallocFuncs *)OsalMemCalloc(sizeof(GrallocFuncs));
350        if (gFuncs == NULL) {
351            HDF_LOGE("%s: gFuncs is null", __func__);
352            return DISPLAY_NULL_PTR;
353        }
354        pthread_mutexattr_init(&g_grallocManager.mutexattr);
355        pthread_mutexattr_setpshared(&g_grallocManager.mutexattr, PTHREAD_PROCESS_SHARED);
356        pthread_mutex_init(&g_grallocManager.mutex, &g_grallocManager.mutexattr);
357        gFuncs->AllocMem = AllocMem;
358        gFuncs->FreeMem = FreeMem;
359        gFuncs->Mmap = Mmap;
360        gFuncs->Unmap = Unmap;
361    }
362    *funcs = gFuncs;
363    GetGrallocMgr();
364    HDF_LOGI("%s: gralloc initialize success", __func__);
365    return DISPLAY_SUCCESS;
366}
367
368int32_t GrallocUninitialize(GrallocFuncs *funcs)
369{
370    if (funcs == NULL) {
371        HDF_LOGE("%s: funcs is null", __func__);
372        return DISPLAY_NULL_PTR;
373    }
374    if (PutGrallocMgr() == 0) {
375        pthread_mutexattr_destroy(&g_grallocManager.mutexattr);
376        pthread_mutex_destroy(&g_grallocManager.mutex);
377        OsalMemFree(funcs);
378    }
379    HDF_LOGI("%s: gralloc uninitialize success", __func__);
380    return DISPLAY_SUCCESS;
381}
382