/* * Copyright (c) Hisilicon Technologies Co., Ltd.. 2018-2019. All rights reserved. * Description: Gralloc * Author: Hisilicon * Created: 2019.11.07 */ #include "gralloc_framebuffer.h" #include #ifdef GRALLOC_NEED_SMMU_MAP #include #endif #include #include #include #include #include "gfbg.h" #include "gralloc_descriptor.h" #include "gralloc_attribute.h" #include "gralloc_format.h" #include "mali_gralloc_formats.h" #include "gralloc_debug.h" #define GRALLOC_PROPERTY_FB_RESOLUTION "persist.vendor.display.resolution" #define GRALLOC_PROPERTY_MASTER_DISPLAY "persist.vendor.display.master" #define GRALLOC_PROPERTY_DISPLAY1_ATTACH_FB "persist.vendor.disp1.attach.fb" #define GRALLOC_MAX_FB_RESOLUTION 8192 #define DEV_NAME_MAX_LEN 64 struct fb_dmabuf_export { __u32 fd; __u32 flags; }; #define FBIOGET_DMABUF _IOR('F', 0x21, struct fb_dmabuf_export) static int gralloc_framebuffer_get_dmabuf(const private_module_t *m) { int ret = 0; struct fb_dmabuf_export fb_dma_buf; fb_dma_buf.fd = 0; fb_dma_buf.flags = 0; unsigned int id = ((hw_module_t *)m)->reserved[0]; if (id >= NUM_FB_DEVICES) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } ret = ioctl(m->framebuffer[id]->fd, FBIOGET_DMABUF, &fb_dma_buf); if (ret != 0) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } return fb_dma_buf.fd; } static int gralloc_framebuffer_open_fb(unsigned int id) { int ret; int device_fd; char device_name[DEV_NAME_MAX_LEN]; if (id >= NUM_FB_DEVICES) { GRALLOC_ERROR_INFO(); return -1; } /* open framebuffer device */ ret = snprintf_s(device_name, sizeof(device_name), sizeof(device_name) - 1, "/dev/graphics/fb%u", id); if (ret < 0) { GRALLOC_ERROR_INFO(); return -1; } device_fd = open(device_name, O_RDWR, 0); if (device_fd < 0) { GRALLOC_ERROR_INFO(); return -1; } ALOGI("gralloc open fb id:%d", id); return device_fd; } static bool gralloc_get_fb_afbc_capability(const private_module_t *m, unsigned int id) { int ret = 0; gfbg_capability_info fb_capability_info; if (id >= NUM_FB_DEVICES) { ALOGE("gralloc fb id is more than NUM_FB_DEVICES."); return false; } ret = ioctl(m->framebuffer[id]->fd, GFBGIOGET_CAPABILITY, &fb_capability_info); if (ret != 0) { ALOGE("gralloc ioctl GFBGIOGET_CAPABILITY failed."); return false; } return fb_capability_info.compression.is_support_afbc; } static int gralloc_framebuffer_get_fb_info(int device_fd, const struct fb_fix_screeninfo *fix_info, const struct fb_var_screeninfo *var_info) { int ret; if ((fix_info == nullptr) || (var_info == nullptr)) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } /* get framebuffer fix/vary info */ ret = ioctl(device_fd, FBIOGET_FSCREENINFO, fix_info); if (ret < 0) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } ret = ioctl(device_fd, FBIOGET_VSCREENINFO, var_info); if (ret < 0) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } return GRALLOC_SUCCESS; } static int gralloc_framebuffer_set_fb_info(int device_fd, struct fb_var_screeninfo *var_info) { int ret; unsigned int base = 10; char custom_value[PROPERTY_VALUE_MAX] = {0}; char *str_save = nullptr; if (var_info == nullptr) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } /* get fb resolution from the property. use default resolution from FBIOGET_VSCREENINFO if the property is not set */ property_get(GRALLOC_PROPERTY_FB_RESOLUTION, custom_value, ""); if (strlen(custom_value) != 0) { var_info->xres = (unsigned int)strtol(strtok_r(custom_value, "x", &str_save), nullptr, base); var_info->yres = (unsigned int)strtol(strtok_r(nullptr, "x", &str_save), nullptr, base); } if ((var_info->xres > GRALLOC_MAX_FB_RESOLUTION) || (var_info->yres > GRALLOC_MAX_FB_RESOLUTION)) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } var_info->reserved[0] = 0; var_info->reserved[1] = 0; var_info->reserved[2] = 0; /* init reserved[2] is 0 */ var_info->xoffset = 0; var_info->yoffset = 0; var_info->activate = FB_ACTIVATE_NOW; /* set framebuffer format */ var_info->bits_per_pixel = 32; /* 32bit */ var_info->transp.offset = 24; /* offset 24 of a channel */ var_info->transp.length = 8; /* 8 bit */ var_info->red.offset = 16; /* offset 16 of red channel */ var_info->red.length = 8; /* 8 bit */ var_info->green.offset = 8; /* offset 8 of green channel */ var_info->green.length = 8; /* 8 bits */ var_info->blue.offset = 0; /* offset 0 of blue channel */ var_info->blue.length = 8; /* 8 bits */ var_info->xres_virtual = var_info->xres; var_info->yres_virtual = var_info->yres * NUM_FB_BUFFERS; /* set framebuffer vary info */ ret = ioctl(device_fd, FBIOPUT_VSCREENINFO, var_info); if (ret < 0) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } return GRALLOC_SUCCESS; } static int gralloc_framebuffer_get_fb_dpi_and_fps(struct fb_var_screeninfo *var_info, float *xdpi, float *ydpi, float *fps) { int refresh_rate; if ((var_info == nullptr) || (xdpi == nullptr) || (ydpi == nullptr) || (fps == nullptr)) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } /* compute refresh rate */ if (static_cast(var_info->pixclock) > 0) { refresh_rate = static_cast(1000000000000000LLU / ((var_info->upper_margin + var_info->lower_margin + var_info->yres + var_info->hsync_len) * (var_info->left_margin + var_info->right_margin + var_info->xres + var_info->vsync_len) * var_info->pixclock)); } else { /* 60 Hz, fps = refresh_rate / 1000 , var_info.pixclock may be 0 when android run in Emulator */ refresh_rate = 60 * 1000; } if ((var_info->width == 0) || (var_info->height == 0)) { var_info->width = ((var_info->xres * 25.4f) / 160.0f + 0.5f); /* (var_info.xres * 25.4f) / 160.0f + 0.5f) */ var_info->height = ((var_info->yres * 25.4f) / 160.0f + 0.5f); /* (var_info.yres * 25.4f) / 160.0f + 0.5f) */ } *xdpi = (var_info->xres * 25.4f) / var_info->width; /* (var_info.xres * 25.4f) / 160.0f + 0.5f) */ *ydpi = (var_info->yres * 25.4f) / var_info->height; /* (var_info.yres * 25.4f) / 160.0f + 0.5f) */ *fps = refresh_rate / 1000.0f; /* 60 Hz, fps = refresh_rate / 1000.0f */ return GRALLOC_SUCCESS; } static int gralloc_framebuffer_create_private_handle(unsigned int line_length, unsigned int yres_virtual, int device_fd, struct private_handle_t **handle) { size_t framebuffer_size; void *framebuffer_viraddr; framebuffer_size = line_length * yres_virtual; framebuffer_viraddr = mmap(nullptr, framebuffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, 0); if (framebuffer_viraddr == MAP_FAILED) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } *handle = new private_internal_handle_t(private_internal_handle_t::PRIV_FLAGS_FRAMEBUFFER, framebuffer_size, framebuffer_viraddr, GRALLOC_USAGE_HW_FB, GRALLOC_USAGE_HW_FB, dup(device_fd), 0); return GRALLOC_SUCCESS; } static int gralloc_framebuffer_init_locked(struct private_module_t *module) { int device_fd; unsigned int id = ((hw_module_t *)module)->reserved[0]; struct fb_fix_screeninfo fix_info; struct fb_var_screeninfo var_info; float xdpi = 0.0f; float ydpi = 0.0f; float fps = 0.0f; /* Nothing to do, already initialized */ if (module->framebuffer[id]) { return GRALLOC_SUCCESS; } device_fd = gralloc_framebuffer_open_fb(id); if (device_fd < 0) { return GRALLOC_FAILURE; } /* get default fb info */ if (gralloc_framebuffer_get_fb_info(device_fd, &fix_info, &var_info) != GRALLOC_SUCCESS) { close(device_fd); return GRALLOC_FAILURE; } /* set fb info */ if (gralloc_framebuffer_set_fb_info(device_fd, &var_info) != GRALLOC_SUCCESS) { close(device_fd); return GRALLOC_FAILURE; } /* get set fb info */ if (gralloc_framebuffer_get_fb_info(device_fd, &fix_info, &var_info) != GRALLOC_SUCCESS) { close(device_fd); return GRALLOC_FAILURE; } /* get dpi and fps */ if (gralloc_framebuffer_get_fb_dpi_and_fps(&var_info, &xdpi, &ydpi, &fps) != GRALLOC_SUCCESS) { close(device_fd); GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } module->xdpi[id] = xdpi; module->ydpi[id] = ydpi; module->fps[id] = fps; module->vinfo[id] = var_info; module->finfo[id] = fix_info; module->swapInterval[id] = 0x1; if (gralloc_framebuffer_create_private_handle(fix_info.line_length, var_info.yres_virtual, device_fd, &(module->framebuffer[id])) != GRALLOC_SUCCESS) { close(device_fd); return GRALLOC_FAILURE; } module->numBuffers[id] = var_info.yres_virtual / var_info.yres; module->bufferMask[id] = 0; close(device_fd); return GRALLOC_SUCCESS; } static int gralloc_framebuffer_init(struct private_module_t *module) { int ret; pthread_mutex_lock(&module->lock); ret = gralloc_framebuffer_init_locked(module); pthread_mutex_unlock(&module->lock); return ret; } static int gralloc_framebuffer_swap_interval(struct framebuffer_device_t *dev, int interval) { private_module_t *m = nullptr; unsigned int id; if (dev == nullptr) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } m = reinterpret_cast(dev->common.module); if (m == nullptr) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } id = ((hw_module_t *)m)->reserved[0]; if (interval < dev->minSwapInterval) { interval = dev->minSwapInterval; } else if (interval > dev->maxSwapInterval) { interval = dev->maxSwapInterval; } m->swapInterval[id] = interval; return GRALLOC_SUCCESS; } static int gralloc_framebuffer_post(struct framebuffer_device_t *dev, buffer_handle_t buffer) { GRALLOC_IGNORE(dev); GRALLOC_IGNORE(buffer); return GRALLOC_SUCCESS; } static int gralloc_framebuffer_composition_complete(struct framebuffer_device_t *dev) { GRALLOC_IGNORE(dev); glFinish(); return GRALLOC_SUCCESS; } static int gralloc_framebuffer_device_close(struct hw_device_t *device) { framebuffer_device_t *dev = reinterpret_cast(device); if (dev != nullptr) { free(dev); } return GRALLOC_SUCCESS; } static unsigned int gralloc_framebuffer_get_id(unsigned long long usage) { unsigned int id; char display1_fb_value[PROPERTY_VALUE_MAX] = {0}; unsigned int diaplay0_attach_fb_id; unsigned int diaplay1_attach_fb_id; char master_display[PROPERTY_VALUE_MAX] = {0}; unsigned int master_fb_id; unsigned int external_fb_id; diaplay0_attach_fb_id = 0; /* fb[0, 1, 2, 3], attach fb0 to display0 by default. */ property_get(GRALLOC_PROPERTY_DISPLAY1_ATTACH_FB, display1_fb_value, "3"); if (strncmp(display1_fb_value, "1", strlen("1")) == 0) { diaplay1_attach_fb_id = 1; /* fb[0, 1, 2, 3], attach fb1 to display1 */ } else if (strncmp(display1_fb_value, "2", strlen("2")) == 0) { diaplay1_attach_fb_id = 2; /* fb[0, 1, 2, 3], attach fb2 to display1 */ } else { diaplay1_attach_fb_id = 3; /* fb[0, 1, 2, 3], attach fb3 to display1 by default */ } /* bind master display to fb device */ property_get(GRALLOC_PROPERTY_MASTER_DISPLAY, master_display, "0"); if (strncmp(master_display, "1", strlen("1")) == 0) { /* use display1 as master display */ master_fb_id = diaplay1_attach_fb_id; external_fb_id = diaplay0_attach_fb_id; } else { /* use display0 as master display by default */ master_fb_id = diaplay0_attach_fb_id; external_fb_id = diaplay1_attach_fb_id; } #ifdef GRALLOC_SUPPORT_MUTIPLE_DISPLAY /* use external_fb_id if GRALLOC1_CONSUMER_USAGE_PRIVATE_19 is set, use master_fb_id by default */ id = ((usage & GRALLOC1_CONSUMER_USAGE_PRIVATE_19) != 0) ? external_fb_id : master_fb_id; #else GRALLOC_IGNORE(usage); id = master_display_id; #endif return id; } static unsigned int gralloc_framebuffer_get_size(const private_module_t *m, unsigned int id, bool fb_support_afbc) { size_t framebuffer_size; char afbc_property[PROPERTY_VALUE_MAX]; /* use AFBC as default format */ property_get(GRALLOC_PROPERTY_ENBALE_AFBC, afbc_property, "false"); if ((strcmp(afbc_property, "true") == 0) && fb_support_afbc) { int w_align = GRALLOC_ALIGN(m->vinfo[id].xres, AFBC_ARGB_WIDEBLK_WIDTH_ALIGN); int h_align = GRALLOC_ALIGN(m->vinfo[id].yres, AFBC_ARGB_WIDEBLK_HEIGHT_ALIGN); int header_size = GRALLOC_ALIGN((w_align / AFBC_PIXELS_PER_BLOCK) * (h_align / AFBC_PIXELS_PER_BLOCK) * AFBC_HEADER_BUFFER_BYTES_PER_BLOCKENTRY, 1024); /* 1024: 1k align */ /* 8: 8bit == 1byte */ int payload_size = w_align * h_align * (m->vinfo[id].bits_per_pixel / 8); framebuffer_size = header_size + payload_size; /* 4096: 4k align */ framebuffer_size = GRALLOC_ALIGN(framebuffer_size, 4096); ALOGI("gralloc get afbc property true in gralloc_framebuffer_get_size"); } else { framebuffer_size = m->finfo[id].line_length * m->vinfo[id].yres; ALOGI("gralloc get afbc property false in gralloc_framebuffer_get_size"); } return framebuffer_size; } static int gralloc_framebuffer_get_offset(private_module_t *m, unsigned int id, size_t framebuffer_size, off_t *offset) { uintptr_t framebuffer_viraddr; unsigned int buffer_mask, buffer_nums; buffer_mask = m->bufferMask[id]; buffer_nums = m->numBuffers[id]; if (buffer_nums > NUM_FB_BUFFERS) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } framebuffer_viraddr = (uintptr_t)m->framebuffer[id]->base; if (buffer_mask >= ((1LU << buffer_nums) - 1)) { buffer_mask = 0; m->bufferMask[id] = 0; } /* find a free slot */ for (unsigned int i = 0; i < buffer_nums; i++) { if (((buffer_mask & (unsigned int)(1LU << i)) == 0) && (id < NUM_FB_DEVICES)) { m->bufferMask[id] |= (unsigned int)(1LU << i); break; } framebuffer_viraddr += framebuffer_size; } *offset = framebuffer_viraddr - (uintptr_t)m->framebuffer[id]->base; return GRALLOC_SUCCESS; } static unsigned long long gralloc_framebuffer_get_internal_format(unsigned long long format, bool fb_support_afbc) { unsigned long long internal_format; char afbc_property[PROPERTY_VALUE_MAX]; /* use AFBC as default format */ property_get(GRALLOC_PROPERTY_ENBALE_AFBC, afbc_property, "false"); if ((strcmp(afbc_property, "true") == 0) && fb_support_afbc) { internal_format = format | (MALI_GRALLOC_INTFMT_AFBC_BASIC | MALI_GRALLOC_INTFMT_AFBC_WIDEBLK | MALI_GRALLOC_INTFMT_AFBC_SPLITBLK | MALI_GRALLOC_INTFMT_AFBC_SPARSE | MALI_GRALLOC_INTFMT_AFBC_YUV_TRANSFORM); ALOGI("gralloc get afbc property true in gralloc_framebuffer_get_internal_format"); } else { internal_format = format; ALOGI("gralloc get afbc property false in gralloc_framebuffer_get_internal_format"); } return internal_format; } static int gralloc_framebuffer_allocate_locked(private_module_t *m, buffer_descriptor_t *descriptors, buffer_handle_t *out_buffers, const bool *shared_backend) { int ret; size_t framebuffer_size; unsigned int id; off_t offset; bool fb_support_afbc; GRALLOC_IGNORE(shared_backend); pthread_mutex_lock(&m->lock); id = gralloc_framebuffer_get_id(descriptors->producer_usage | descriptors->consumer_usage); if (id >= NUM_FB_DEVICES) { pthread_mutex_unlock(&m->lock); return GRALLOC_FAILURE; } /* (hw_module_t *)m)->reserved[0] will be covered by the last initialized fb id, so it should be reinitialized when surfaceflinger allocates FrameBufferSurface again */ ((hw_module_t *)m)->reserved[0] = id; if (m->framebuffer[id] == nullptr) { /* SurfaceFlinger process need init framebuffer by itself, becasue framebuffer open is not in SF process */ ret = gralloc_framebuffer_init_locked(m); if (ret != GRALLOC_SUCCESS) { pthread_mutex_unlock(&m->lock); return ret; } } fb_support_afbc = gralloc_get_fb_afbc_capability(m, id); ALOGI("gralloc id:%d, fb_support_afbc:%d", id, fb_support_afbc); framebuffer_size = gralloc_framebuffer_get_size(m, id, fb_support_afbc); gralloc_framebuffer_get_offset(m, id, framebuffer_size, &offset); private_internal_handle_t *handle = new private_internal_handle_t(private_internal_handle_t::PRIV_FLAGS_FRAMEBUFFER, framebuffer_size, reinterpret_cast((uintptr_t)m->framebuffer[id]->base + offset), descriptors->consumer_usage, descriptors->producer_usage, -1, offset); handle->fd = gralloc_framebuffer_get_dmabuf(m); handle->addr = (uintptr_t)m->finfo[id].smem_start + offset; descriptors->format = HAL_PIXEL_FORMAT_BGRA_8888; /* fb use HAL_PIXEL_FORMAT_BGRA_8888 by default */ handle->format = descriptors->format; handle->internal_format = gralloc_framebuffer_get_internal_format(descriptors->format, fb_support_afbc); handle->width = descriptors->width; handle->height = descriptors->height; handle->internal_width = descriptors->width; handle->internal_height = descriptors->height; handle->pixel_stride = m->finfo[id].line_length / 4; /* ARGB pixel_stride is 4 * bytes_stride */ handle->bytes_stride = m->finfo[id].line_length; handle->yuv_info = PRI_YUV_BT601_NARROW; /* use PRI_YUV_BT601_NARROW by default */ *out_buffers = handle; pthread_mutex_unlock(&m->lock); ALOGI("gralloc fb id:%d, usage:0x%llx, dma buf fd:%d, width:%d, height:%d, addr:0x%x", id, descriptors->producer_usage | descriptors->consumer_usage, handle->fd, handle->width, handle->height, handle->addr); return GRALLOC_SUCCESS; } int gralloc_framebuffer_allocate(private_module_t *m, buffer_descriptor_t *descriptors, buffer_handle_t *out_buffers, const bool *shared_backend) { int ret; gralloc_debug_update_config(); if (out_buffers == nullptr) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } ret = gralloc_framebuffer_allocate_locked(m, descriptors, out_buffers, shared_backend); if (ret < 0) { GRALLOC_ERROR_INFO(); return GRALLOC_FAILURE; } private_internal_handle_t *handle = (private_internal_handle_t*)(*out_buffers); gralloc_buffer_attr_allocate(m, handle); if (gralloc_init_attribute_buffer(m, handle) != GRALLOC_SUCCESS) { return GRALLOC_FAILURE; } if (gralloc_debug_dump_is_enabled()) { gralloc_debug_dump_framebuffer(handle, m); } return GRALLOC_SUCCESS; } void gralloc_framebuffer_free(const private_module_t *m, buffer_handle_t buffer) { GRALLOC_IGNORE(m); private_internal_handle_t *handle = (private_internal_handle_t*)buffer; if (handle == nullptr) { GRALLOC_ERROR_INFO(); return; } if (handle->fd > 0) { close(handle->fd); } } int gralloc_framebuffer_device_open(const hw_module_t *module, hw_device_t **device) { private_module_t *m = (private_module_t *)module; gralloc1_device_t *gralloc_device = nullptr; framebuffer_device_t *dev = nullptr; unsigned int id; if (device == nullptr || module == nullptr) { return GRALLOC_FAILURE; } id = ((hw_module_t *)module)->reserved[0]; dev = reinterpret_cast(malloc(sizeof(framebuffer_device_t))); if (dev == nullptr) { return GRALLOC_FAILURE; } if (memset_s(dev, sizeof(*dev), 0, sizeof(*dev)) != EOK) { free(dev); return GRALLOC_FAILURE; } /* open gralloc device */ if (gralloc1_open(module, &gralloc_device) != GRALLOC_SUCCESS) { GRALLOC_ERROR_INFO(); free(dev); return GRALLOC_FAILURE; } /* init framebuffer */ if (gralloc_framebuffer_init(m) != GRALLOC_SUCCESS) { GRALLOC_ERROR_INFO(); gralloc1_close(gralloc_device); free(dev); return GRALLOC_FAILURE; } /* configure parameters */ dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = const_cast(module); dev->common.close = gralloc_framebuffer_device_close; dev->setSwapInterval = gralloc_framebuffer_swap_interval; dev->post = gralloc_framebuffer_post; dev->setUpdateRect = nullptr; dev->compositionComplete = &gralloc_framebuffer_composition_complete; const_cast(dev->flags) = 0; const_cast(dev->width) = m->vinfo[id].xres; const_cast(dev->height) = m->vinfo[id].yres; /* stride : pixel num of each line */ /* bits_per_pixel >> 3: bytes of per_pixel */ const_cast(dev->stride) = m->finfo[id].line_length / (m->vinfo[0].bits_per_pixel >> 3); const_cast(dev->format) = HAL_PIXEL_FORMAT_BGRA_8888; const_cast(dev->xdpi) = m->xdpi[id]; const_cast(dev->ydpi) = m->ydpi[id]; const_cast(dev->fps) = m->fps[id]; const_cast(dev->minSwapInterval) = 0; const_cast(dev->maxSwapInterval) = 1; *device = &dev->common; return GRALLOC_SUCCESS; }