static int realloc_buffer(struct exynos_data *pdata, enum exynos_buffer_type type, unsigned size) { struct exynos_bo *buf = pdata->buf[type]; unsigned i; if (size > buf->size) { #if (EXYNOS_GFX_DEBUG_LOG == 1) RARCH_LOG("video_exynos: reallocating %s buffer (%u -> %u bytes)\n", buffer_name(type), buf->size, size); #endif exynos_bo_destroy(buf); buf = create_mapped_buffer(pdata->device, size); if (buf == NULL) { RARCH_ERR("video_exynos: reallocation failed\n"); return -1; } pdata->buf[type] = buf; /* Map new GEM buffer to the G2D images backed by it. */ for (i = 0; i < exynos_image_count; ++i) { if (defaults[i].buf_type == type) pdata->src[i]->bo[0] = buf->handle; } } return 0; }
static void clean_up_pages(struct exynos_page *p, unsigned cnt) { unsigned i; for (i = 0; i < cnt; ++i) { if (p[i].bo != NULL) { if (p[i].buf_id != 0) drmModeRmFB(p[i].buf_id, p[i].bo->handle); exynos_bo_destroy(p[i].bo); } } }
static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev, unsigned long size, unsigned int flags) { struct exynos_bo *bo; bo = exynos_bo_create(dev, size, flags); if (!bo) return bo; if (!exynos_bo_map(bo)) { exynos_bo_destroy(bo); return NULL; } return bo; }
/* Create a GEM buffer with userspace mapping. Buffer is cleared after creation. */ static struct exynos_bo *create_mapped_buffer(struct exynos_device *dev, unsigned size) { struct exynos_bo *buf; const unsigned flags = 0; buf = exynos_bo_create(dev, size, flags); if (buf == NULL) { RARCH_ERR("video_exynos: failed to create temp buffer object\n"); return NULL; } if (exynos_bo_map(buf) == NULL) { RARCH_ERR("video_exynos: failed to map temp buffer object\n"); exynos_bo_destroy(buf); return NULL; } memset(buf->vaddr, 0, size); return buf; }
static void exynos_destroy_buffer(struct exynos_bo *bo) { exynos_bo_destroy(bo); }
static int exynos_alloc(struct hook_data *data) { struct exynos_device *device; struct exynos_bo *bo; struct exynos_page *pages; struct drm_prime_handle req = { 0 }; unsigned i; const unsigned flags = 0; device = exynos_device_create(data->drm_fd); if (device == NULL) { fprintf(stderr, "[exynos_init] error: failed to create device from fd\n"); return -1; } pages = calloc(data->num_pages, sizeof(struct exynos_page)); if (pages == NULL) { fprintf(stderr, "[exynos_init] error: failed to allocate pages\n"); goto fail_alloc; } for (i = 0; i < data->num_pages; ++i) { bo = exynos_bo_create(device, data->size, flags); if (bo == NULL) { fprintf(stderr, "[exynos_init] error: failed to create buffer object\n"); goto fail; } req.handle = bo->handle; if (drmIoctl(data->drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &req) < 0) { fprintf(stderr, "[exynos_init] error: failed to get fd from bo\n"); exynos_bo_destroy(bo); goto fail; } /* Don't map the BO, since we don't access it through userspace. */ pages[i].bo = bo; pages[i].fd = req.fd; pages[i].base = data; pages[i].used = false; pages[i].clear = true; } if (vconf.use_screen == 1) { const uint32_t pixel_format = (data->bpp == 2) ? DRM_FORMAT_RGB565 : DRM_FORMAT_XRGB8888; uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; pitches[0] = data->pitch; offsets[0] = 0; for (i = 0; i < data->num_pages; ++i) { handles[0] = pages[i].bo->handle; if (drmModeAddFB2(data->drm_fd, data->width, data->height, pixel_format, handles, pitches, offsets, &pages[i].buf_id, flags)) { fprintf(stderr, "[exynos_init] error: failed to add bo %u to fb\n", i); goto fail; } } } if (vconf.use_screen == 1) { /* Setup CRTC: display the last allocated page. */ if (drmModeSetCrtc(data->drm_fd, data->drm->crtc_id, pages[data->num_pages - 1].buf_id, 0, 0, &data->drm->connector_id, 1, data->drm->mode)) { fprintf(stderr, "[exynos_init] error: drmModeSetCrtc failed\n"); goto fail; } } data->pages = pages; data->device = device; return 0; fail: clean_up_pages(pages, data->num_pages); fail_alloc: exynos_device_destroy(device); return -1; }