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