The multi-planar formats are being allocated into a single plane, and the minigbm exynos backend is dropped. So we can use `handle` instead of handles as of now. Remove some of the helper functions that calculate the number of planes. There is no need to check if there is more than one kernel buffer per buffer object. Added a new function `drv_gem_close` in `drv_helpers` that can be used by `drv_gem_bo_destroy` and `drv_prime_bo_import`. It can be used to clean the unused gem_handle. Bug=b:266776512 TEST=camera and screenshot work fine after deploying the change #strongbad TEST=camera and screenshot work fine after deploying the change #kukui-arc-r TEST=camera and screenshot work fine after deploying the change, tested a couple of apps in the Google Play Store, and checked file `dma_buf/bufinfo` to see there's no object leaking. #guybrush Change-Id: Ib63559504e4cb8f1a32ae90170925146613d694f Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/4297873 Commit-Queue: Dawn Han <dawnhan@google.com> Reviewed-by: Yiwei Zhang <zzyiwei@chromium.org> Tested-by: Dawn Han <dawnhan@google.com>
785 lines
18 KiB
C
785 lines
18 KiB
C
/*
|
|
* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <pthread.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <xf86drm.h>
|
|
|
|
#ifdef __ANDROID__
|
|
#include <cutils/log.h>
|
|
#include <libgen.h>
|
|
#endif
|
|
|
|
#include "drv_helpers.h"
|
|
#include "drv_priv.h"
|
|
#include "util.h"
|
|
|
|
#ifdef DRV_AMDGPU
|
|
extern const struct backend backend_amdgpu;
|
|
#endif
|
|
#ifdef DRV_I915
|
|
extern const struct backend backend_i915;
|
|
#endif
|
|
#ifdef DRV_MSM
|
|
extern const struct backend backend_msm;
|
|
#endif
|
|
#ifdef DRV_VC4
|
|
extern const struct backend backend_vc4;
|
|
#endif
|
|
|
|
// Dumb / generic drivers
|
|
extern const struct backend backend_evdi;
|
|
extern const struct backend backend_marvell;
|
|
extern const struct backend backend_mediatek;
|
|
extern const struct backend backend_meson;
|
|
extern const struct backend backend_nouveau;
|
|
extern const struct backend backend_komeda;
|
|
extern const struct backend backend_radeon;
|
|
extern const struct backend backend_rockchip;
|
|
extern const struct backend backend_sun4i_drm;
|
|
extern const struct backend backend_synaptics;
|
|
extern const struct backend backend_virtgpu;
|
|
extern const struct backend backend_udl;
|
|
extern const struct backend backend_vkms;
|
|
|
|
static const struct backend *drv_backend_list[] = {
|
|
#ifdef DRV_AMDGPU
|
|
&backend_amdgpu,
|
|
#endif
|
|
#ifdef DRV_I915
|
|
&backend_i915,
|
|
#endif
|
|
#ifdef DRV_MSM
|
|
&backend_msm,
|
|
#endif
|
|
#ifdef DRV_VC4
|
|
&backend_vc4,
|
|
#endif
|
|
&backend_evdi, &backend_komeda, &backend_marvell, &backend_mediatek,
|
|
&backend_meson, &backend_nouveau, &backend_radeon, &backend_rockchip,
|
|
&backend_sun4i_drm, &backend_synaptics, &backend_udl, &backend_virtgpu,
|
|
&backend_vkms
|
|
};
|
|
|
|
void drv_preload(bool load)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < ARRAY_SIZE(drv_backend_list); i++) {
|
|
const struct backend *b = drv_backend_list[i];
|
|
if (b->preload)
|
|
b->preload(load);
|
|
}
|
|
}
|
|
|
|
static const struct backend *drv_get_backend(int fd)
|
|
{
|
|
drmVersionPtr drm_version;
|
|
unsigned int i;
|
|
|
|
drm_version = drmGetVersion(fd);
|
|
|
|
if (!drm_version)
|
|
return NULL;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(drv_backend_list); i++) {
|
|
const struct backend *b = drv_backend_list[i];
|
|
if (!strcmp(drm_version->name, b->name)) {
|
|
drmFreeVersion(drm_version);
|
|
return b;
|
|
}
|
|
}
|
|
|
|
drmFreeVersion(drm_version);
|
|
return NULL;
|
|
}
|
|
|
|
struct driver *drv_create(int fd)
|
|
{
|
|
struct driver *drv;
|
|
int ret;
|
|
|
|
drv = (struct driver *)calloc(1, sizeof(*drv));
|
|
|
|
if (!drv)
|
|
return NULL;
|
|
|
|
char *minigbm_debug;
|
|
minigbm_debug = getenv("MINIGBM_DEBUG");
|
|
drv->compression = (minigbm_debug == NULL) || (strcmp(minigbm_debug, "nocompression") != 0);
|
|
|
|
drv->fd = fd;
|
|
drv->backend = drv_get_backend(fd);
|
|
|
|
if (!drv->backend)
|
|
goto free_driver;
|
|
|
|
if (pthread_mutex_init(&drv->buffer_table_lock, NULL))
|
|
goto free_driver;
|
|
|
|
drv->buffer_table = drmHashCreate();
|
|
if (!drv->buffer_table)
|
|
goto free_buffer_table_lock;
|
|
|
|
if (pthread_mutex_init(&drv->mappings_lock, NULL))
|
|
goto free_buffer_table;
|
|
|
|
drv->mappings = drv_array_init(sizeof(struct mapping));
|
|
if (!drv->mappings)
|
|
goto free_mappings_lock;
|
|
|
|
drv->combos = drv_array_init(sizeof(struct combination));
|
|
if (!drv->combos)
|
|
goto free_mappings;
|
|
|
|
if (drv->backend->init) {
|
|
ret = drv->backend->init(drv);
|
|
if (ret) {
|
|
drv_array_destroy(drv->combos);
|
|
goto free_mappings;
|
|
}
|
|
}
|
|
|
|
return drv;
|
|
|
|
free_mappings:
|
|
drv_array_destroy(drv->mappings);
|
|
free_mappings_lock:
|
|
pthread_mutex_destroy(&drv->mappings_lock);
|
|
free_buffer_table:
|
|
drmHashDestroy(drv->buffer_table);
|
|
free_buffer_table_lock:
|
|
pthread_mutex_destroy(&drv->buffer_table_lock);
|
|
free_driver:
|
|
free(drv);
|
|
return NULL;
|
|
}
|
|
|
|
void drv_destroy(struct driver *drv)
|
|
{
|
|
if (drv->backend->close)
|
|
drv->backend->close(drv);
|
|
|
|
drv_array_destroy(drv->combos);
|
|
|
|
drv_array_destroy(drv->mappings);
|
|
pthread_mutex_destroy(&drv->mappings_lock);
|
|
|
|
drmHashDestroy(drv->buffer_table);
|
|
pthread_mutex_destroy(&drv->buffer_table_lock);
|
|
|
|
free(drv);
|
|
}
|
|
|
|
int drv_get_fd(struct driver *drv)
|
|
{
|
|
return drv->fd;
|
|
}
|
|
|
|
const char *drv_get_name(struct driver *drv)
|
|
{
|
|
return drv->backend->name;
|
|
}
|
|
|
|
struct combination *drv_get_combination(struct driver *drv, uint32_t format, uint64_t use_flags)
|
|
{
|
|
struct combination *curr, *best;
|
|
|
|
if (format == DRM_FORMAT_NONE || use_flags == BO_USE_NONE)
|
|
return 0;
|
|
|
|
best = NULL;
|
|
uint32_t i;
|
|
for (i = 0; i < drv_array_size(drv->combos); i++) {
|
|
curr = drv_array_at_idx(drv->combos, i);
|
|
if ((format == curr->format) && use_flags == (curr->use_flags & use_flags))
|
|
if (!best || best->metadata.priority < curr->metadata.priority)
|
|
best = curr;
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
struct bo *drv_bo_new(struct driver *drv, uint32_t width, uint32_t height, uint32_t format,
|
|
uint64_t use_flags, bool is_test_buffer)
|
|
{
|
|
|
|
struct bo *bo;
|
|
bo = (struct bo *)calloc(1, sizeof(*bo));
|
|
|
|
if (!bo)
|
|
return NULL;
|
|
|
|
bo->drv = drv;
|
|
bo->meta.width = width;
|
|
bo->meta.height = height;
|
|
bo->meta.format = format;
|
|
bo->meta.use_flags = use_flags;
|
|
bo->meta.num_planes = drv_num_planes_from_format(format);
|
|
bo->is_test_buffer = is_test_buffer;
|
|
|
|
if (!bo->meta.num_planes) {
|
|
free(bo);
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
return bo;
|
|
}
|
|
|
|
static void drv_bo_mapping_destroy(struct bo *bo)
|
|
{
|
|
struct driver *drv = bo->drv;
|
|
uint32_t idx = 0;
|
|
|
|
/*
|
|
* This function is called right before the buffer is destroyed. It will free any mappings
|
|
* associated with the buffer.
|
|
*/
|
|
pthread_mutex_lock(&drv->mappings_lock);
|
|
for (size_t plane = 0; plane < bo->meta.num_planes; plane++) {
|
|
while (idx < drv_array_size(drv->mappings)) {
|
|
struct mapping *mapping =
|
|
(struct mapping *)drv_array_at_idx(drv->mappings, idx);
|
|
if (mapping->vma->handle != bo->handle.u32) {
|
|
idx++;
|
|
continue;
|
|
}
|
|
|
|
if (!--mapping->vma->refcount) {
|
|
int ret = drv->backend->bo_unmap(bo, mapping->vma);
|
|
if (ret) {
|
|
pthread_mutex_unlock(&drv->mappings_lock);
|
|
assert(ret);
|
|
drv_loge("munmap failed\n");
|
|
return;
|
|
}
|
|
|
|
free(mapping->vma);
|
|
}
|
|
|
|
/* This shrinks and shifts the array, so don't increment idx. */
|
|
drv_array_remove(drv->mappings, idx);
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&drv->mappings_lock);
|
|
}
|
|
|
|
/*
|
|
* Acquire a reference on plane buffers of the bo.
|
|
*/
|
|
static void drv_bo_acquire(struct bo *bo)
|
|
{
|
|
struct driver *drv = bo->drv;
|
|
|
|
pthread_mutex_lock(&drv->buffer_table_lock);
|
|
for (size_t plane = 0; plane < bo->meta.num_planes; plane++) {
|
|
uintptr_t num = 0;
|
|
|
|
if (!drmHashLookup(drv->buffer_table, bo->handle.u32, (void **)&num))
|
|
drmHashDelete(drv->buffer_table, bo->handle.u32);
|
|
|
|
drmHashInsert(drv->buffer_table, bo->handle.u32, (void *)(num + 1));
|
|
}
|
|
pthread_mutex_unlock(&drv->buffer_table_lock);
|
|
}
|
|
|
|
/*
|
|
* Release a reference on plane buffers of the bo. Return true when the bo has lost all its
|
|
* references. Otherwise, return false.
|
|
*/
|
|
static bool drv_bo_release(struct bo *bo)
|
|
{
|
|
struct driver *drv = bo->drv;
|
|
uintptr_t num;
|
|
|
|
if (drv->backend->bo_release)
|
|
drv->backend->bo_release(bo);
|
|
|
|
pthread_mutex_lock(&drv->buffer_table_lock);
|
|
for (size_t plane = 0; plane < bo->meta.num_planes; plane++) {
|
|
if (!drmHashLookup(drv->buffer_table, bo->handle.u32, (void **)&num)) {
|
|
drmHashDelete(drv->buffer_table, bo->handle.u32);
|
|
|
|
if (num > 1) {
|
|
drmHashInsert(drv->buffer_table, bo->handle.u32, (void *)(num - 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* The same buffer can back multiple planes with different offsets. */
|
|
for (size_t plane = 0; plane < bo->meta.num_planes; plane++) {
|
|
if (!drmHashLookup(drv->buffer_table, bo->handle.u32, (void **)&num)) {
|
|
/* num is positive if found in the hashmap. */
|
|
pthread_mutex_unlock(&drv->buffer_table_lock);
|
|
return false;
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&drv->buffer_table_lock);
|
|
|
|
return true;
|
|
}
|
|
|
|
struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height, uint32_t format,
|
|
uint64_t use_flags)
|
|
{
|
|
int ret;
|
|
struct bo *bo;
|
|
bool is_test_alloc;
|
|
|
|
is_test_alloc = use_flags & BO_USE_TEST_ALLOC;
|
|
use_flags &= ~BO_USE_TEST_ALLOC;
|
|
|
|
bo = drv_bo_new(drv, width, height, format, use_flags, is_test_alloc);
|
|
|
|
if (!bo)
|
|
return NULL;
|
|
|
|
ret = -EINVAL;
|
|
if (drv->backend->bo_compute_metadata) {
|
|
ret = drv->backend->bo_compute_metadata(bo, width, height, format, use_flags, NULL,
|
|
0);
|
|
if (!is_test_alloc && ret == 0)
|
|
ret = drv->backend->bo_create_from_metadata(bo);
|
|
} else if (!is_test_alloc) {
|
|
ret = drv->backend->bo_create(bo, width, height, format, use_flags);
|
|
}
|
|
|
|
if (ret) {
|
|
errno = -ret;
|
|
free(bo);
|
|
return NULL;
|
|
}
|
|
|
|
drv_bo_acquire(bo);
|
|
|
|
return bo;
|
|
}
|
|
|
|
struct bo *drv_bo_create_with_modifiers(struct driver *drv, uint32_t width, uint32_t height,
|
|
uint32_t format, const uint64_t *modifiers, uint32_t count)
|
|
{
|
|
int ret;
|
|
struct bo *bo;
|
|
|
|
if (!drv->backend->bo_create_with_modifiers && !drv->backend->bo_compute_metadata) {
|
|
errno = ENOENT;
|
|
return NULL;
|
|
}
|
|
|
|
bo = drv_bo_new(drv, width, height, format, BO_USE_NONE, false);
|
|
|
|
if (!bo)
|
|
return NULL;
|
|
|
|
ret = -EINVAL;
|
|
if (drv->backend->bo_compute_metadata) {
|
|
ret = drv->backend->bo_compute_metadata(bo, width, height, format, BO_USE_NONE,
|
|
modifiers, count);
|
|
if (ret == 0)
|
|
ret = drv->backend->bo_create_from_metadata(bo);
|
|
} else {
|
|
ret = drv->backend->bo_create_with_modifiers(bo, width, height, format, modifiers,
|
|
count);
|
|
}
|
|
|
|
if (ret) {
|
|
free(bo);
|
|
return NULL;
|
|
}
|
|
|
|
drv_bo_acquire(bo);
|
|
|
|
return bo;
|
|
}
|
|
|
|
void drv_bo_destroy(struct bo *bo)
|
|
{
|
|
if (!bo->is_test_buffer && drv_bo_release(bo)) {
|
|
drv_bo_mapping_destroy(bo);
|
|
bo->drv->backend->bo_destroy(bo);
|
|
}
|
|
|
|
free(bo);
|
|
}
|
|
|
|
struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data)
|
|
{
|
|
int ret;
|
|
size_t plane;
|
|
struct bo *bo;
|
|
off_t seek_end;
|
|
|
|
bo = drv_bo_new(drv, data->width, data->height, data->format, data->use_flags, false);
|
|
|
|
if (!bo)
|
|
return NULL;
|
|
|
|
ret = drv->backend->bo_import(bo, data);
|
|
if (ret) {
|
|
free(bo);
|
|
return NULL;
|
|
}
|
|
|
|
drv_bo_acquire(bo);
|
|
|
|
bo->meta.format_modifier = data->format_modifier;
|
|
for (plane = 0; plane < bo->meta.num_planes; plane++) {
|
|
bo->meta.strides[plane] = data->strides[plane];
|
|
bo->meta.offsets[plane] = data->offsets[plane];
|
|
|
|
seek_end = lseek(data->fds[plane], 0, SEEK_END);
|
|
if (seek_end == (off_t)(-1)) {
|
|
drv_loge("lseek() failed with %s\n", strerror(errno));
|
|
goto destroy_bo;
|
|
}
|
|
|
|
lseek(data->fds[plane], 0, SEEK_SET);
|
|
if (plane == bo->meta.num_planes - 1 || data->offsets[plane + 1] == 0)
|
|
bo->meta.sizes[plane] = seek_end - data->offsets[plane];
|
|
else
|
|
bo->meta.sizes[plane] = data->offsets[plane + 1] - data->offsets[plane];
|
|
|
|
if ((int64_t)bo->meta.offsets[plane] + bo->meta.sizes[plane] > seek_end) {
|
|
drv_loge("buffer size is too large.\n");
|
|
goto destroy_bo;
|
|
}
|
|
|
|
bo->meta.total_size += bo->meta.sizes[plane];
|
|
}
|
|
|
|
return bo;
|
|
|
|
destroy_bo:
|
|
drv_bo_destroy(bo);
|
|
return NULL;
|
|
}
|
|
|
|
void *drv_bo_map(struct bo *bo, const struct rectangle *rect, uint32_t map_flags,
|
|
struct mapping **map_data, size_t plane)
|
|
{
|
|
struct driver *drv = bo->drv;
|
|
uint32_t i;
|
|
uint8_t *addr;
|
|
struct mapping mapping = { 0 };
|
|
|
|
assert(rect->width >= 0);
|
|
assert(rect->height >= 0);
|
|
assert(rect->x + rect->width <= drv_bo_get_width(bo));
|
|
assert(rect->y + rect->height <= drv_bo_get_height(bo));
|
|
assert(BO_MAP_READ_WRITE & map_flags);
|
|
/* No CPU access for protected buffers. */
|
|
assert(!(bo->meta.use_flags & BO_USE_PROTECTED));
|
|
|
|
if (bo->is_test_buffer)
|
|
return MAP_FAILED;
|
|
|
|
mapping.rect = *rect;
|
|
mapping.refcount = 1;
|
|
|
|
pthread_mutex_lock(&drv->mappings_lock);
|
|
|
|
for (i = 0; i < drv_array_size(drv->mappings); i++) {
|
|
struct mapping *prior = (struct mapping *)drv_array_at_idx(drv->mappings, i);
|
|
if (prior->vma->handle != bo->handle.u32 || prior->vma->map_flags != map_flags)
|
|
continue;
|
|
|
|
if (rect->x != prior->rect.x || rect->y != prior->rect.y ||
|
|
rect->width != prior->rect.width || rect->height != prior->rect.height)
|
|
continue;
|
|
|
|
prior->refcount++;
|
|
*map_data = prior;
|
|
goto exact_match;
|
|
}
|
|
|
|
for (i = 0; i < drv_array_size(drv->mappings); i++) {
|
|
struct mapping *prior = (struct mapping *)drv_array_at_idx(drv->mappings, i);
|
|
if (prior->vma->handle != bo->handle.u32 || prior->vma->map_flags != map_flags)
|
|
continue;
|
|
|
|
prior->vma->refcount++;
|
|
mapping.vma = prior->vma;
|
|
goto success;
|
|
}
|
|
|
|
mapping.vma = calloc(1, sizeof(*mapping.vma));
|
|
if (!mapping.vma) {
|
|
*map_data = NULL;
|
|
pthread_mutex_unlock(&drv->mappings_lock);
|
|
return MAP_FAILED;
|
|
}
|
|
|
|
memcpy(mapping.vma->map_strides, bo->meta.strides, sizeof(mapping.vma->map_strides));
|
|
addr = drv->backend->bo_map(bo, mapping.vma, map_flags);
|
|
if (addr == MAP_FAILED) {
|
|
*map_data = NULL;
|
|
free(mapping.vma);
|
|
pthread_mutex_unlock(&drv->mappings_lock);
|
|
return MAP_FAILED;
|
|
}
|
|
|
|
mapping.vma->refcount = 1;
|
|
mapping.vma->addr = addr;
|
|
mapping.vma->handle = bo->handle.u32;
|
|
mapping.vma->map_flags = map_flags;
|
|
|
|
success:
|
|
*map_data = drv_array_append(drv->mappings, &mapping);
|
|
exact_match:
|
|
drv_bo_invalidate(bo, *map_data);
|
|
addr = (uint8_t *)((*map_data)->vma->addr);
|
|
addr += drv_bo_get_plane_offset(bo, plane);
|
|
pthread_mutex_unlock(&drv->mappings_lock);
|
|
return (void *)addr;
|
|
}
|
|
|
|
int drv_bo_unmap(struct bo *bo, struct mapping *mapping)
|
|
{
|
|
struct driver *drv = bo->drv;
|
|
uint32_t i;
|
|
int ret = 0;
|
|
|
|
pthread_mutex_lock(&drv->mappings_lock);
|
|
|
|
if (--mapping->refcount)
|
|
goto out;
|
|
|
|
if (!--mapping->vma->refcount) {
|
|
ret = drv->backend->bo_unmap(bo, mapping->vma);
|
|
free(mapping->vma);
|
|
}
|
|
|
|
for (i = 0; i < drv_array_size(drv->mappings); i++) {
|
|
if (mapping == (struct mapping *)drv_array_at_idx(drv->mappings, i)) {
|
|
drv_array_remove(drv->mappings, i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
pthread_mutex_unlock(&drv->mappings_lock);
|
|
return ret;
|
|
}
|
|
|
|
int drv_bo_invalidate(struct bo *bo, struct mapping *mapping)
|
|
{
|
|
int ret = 0;
|
|
|
|
assert(mapping);
|
|
assert(mapping->vma);
|
|
assert(mapping->refcount > 0);
|
|
assert(mapping->vma->refcount > 0);
|
|
|
|
if (bo->drv->backend->bo_invalidate)
|
|
ret = bo->drv->backend->bo_invalidate(bo, mapping);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int drv_bo_flush(struct bo *bo, struct mapping *mapping)
|
|
{
|
|
int ret = 0;
|
|
|
|
assert(mapping);
|
|
assert(mapping->vma);
|
|
assert(mapping->refcount > 0);
|
|
assert(mapping->vma->refcount > 0);
|
|
|
|
if (bo->drv->backend->bo_flush)
|
|
ret = bo->drv->backend->bo_flush(bo, mapping);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int drv_bo_flush_or_unmap(struct bo *bo, struct mapping *mapping)
|
|
{
|
|
int ret = 0;
|
|
|
|
assert(mapping);
|
|
assert(mapping->vma);
|
|
assert(mapping->refcount > 0);
|
|
assert(mapping->vma->refcount > 0);
|
|
assert(!(bo->meta.use_flags & BO_USE_PROTECTED));
|
|
|
|
if (bo->drv->backend->bo_flush)
|
|
ret = bo->drv->backend->bo_flush(bo, mapping);
|
|
else
|
|
ret = drv_bo_unmap(bo, mapping);
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t drv_bo_get_width(struct bo *bo)
|
|
{
|
|
return bo->meta.width;
|
|
}
|
|
|
|
uint32_t drv_bo_get_height(struct bo *bo)
|
|
{
|
|
return bo->meta.height;
|
|
}
|
|
|
|
size_t drv_bo_get_num_planes(struct bo *bo)
|
|
{
|
|
return bo->meta.num_planes;
|
|
}
|
|
|
|
union bo_handle drv_bo_get_plane_handle(struct bo *bo, size_t plane)
|
|
{
|
|
return bo->handle;
|
|
}
|
|
|
|
#ifndef DRM_RDWR
|
|
#define DRM_RDWR O_RDWR
|
|
#endif
|
|
|
|
int drv_bo_get_plane_fd(struct bo *bo, size_t plane)
|
|
{
|
|
|
|
int ret, fd;
|
|
assert(plane < bo->meta.num_planes);
|
|
|
|
if (bo->is_test_buffer)
|
|
return -EINVAL;
|
|
|
|
ret = drmPrimeHandleToFD(bo->drv->fd, bo->handle.u32, DRM_CLOEXEC | DRM_RDWR, &fd);
|
|
|
|
// Older DRM implementations blocked DRM_RDWR, but gave a read/write mapping anyways
|
|
if (ret)
|
|
ret = drmPrimeHandleToFD(bo->drv->fd, bo->handle.u32, DRM_CLOEXEC, &fd);
|
|
|
|
if (ret)
|
|
drv_loge("Failed to get plane fd: %s\n", strerror(errno));
|
|
|
|
return (ret) ? ret : fd;
|
|
}
|
|
|
|
uint32_t drv_bo_get_plane_offset(struct bo *bo, size_t plane)
|
|
{
|
|
assert(plane < bo->meta.num_planes);
|
|
return bo->meta.offsets[plane];
|
|
}
|
|
|
|
uint32_t drv_bo_get_plane_size(struct bo *bo, size_t plane)
|
|
{
|
|
assert(plane < bo->meta.num_planes);
|
|
return bo->meta.sizes[plane];
|
|
}
|
|
|
|
uint32_t drv_bo_get_plane_stride(struct bo *bo, size_t plane)
|
|
{
|
|
assert(plane < bo->meta.num_planes);
|
|
return bo->meta.strides[plane];
|
|
}
|
|
|
|
uint64_t drv_bo_get_format_modifier(struct bo *bo)
|
|
{
|
|
return bo->meta.format_modifier;
|
|
}
|
|
|
|
uint32_t drv_bo_get_format(struct bo *bo)
|
|
{
|
|
return bo->meta.format;
|
|
}
|
|
|
|
uint32_t drv_bo_get_tiling(struct bo *bo)
|
|
{
|
|
return bo->meta.tiling;
|
|
}
|
|
|
|
uint64_t drv_bo_get_use_flags(struct bo *bo)
|
|
{
|
|
return bo->meta.use_flags;
|
|
}
|
|
|
|
size_t drv_bo_get_total_size(struct bo *bo)
|
|
{
|
|
return bo->meta.total_size;
|
|
}
|
|
|
|
/*
|
|
* Map internal fourcc codes back to standard fourcc codes.
|
|
*/
|
|
uint32_t drv_get_standard_fourcc(uint32_t fourcc_internal)
|
|
{
|
|
return (fourcc_internal == DRM_FORMAT_YVU420_ANDROID) ? DRM_FORMAT_YVU420 : fourcc_internal;
|
|
}
|
|
|
|
void drv_resolve_format_and_use_flags(struct driver *drv, uint32_t format, uint64_t use_flags,
|
|
uint32_t *out_format, uint64_t *out_use_flags)
|
|
{
|
|
assert(drv->backend->resolve_format_and_use_flags);
|
|
|
|
drv->backend->resolve_format_and_use_flags(drv, format, use_flags, out_format,
|
|
out_use_flags);
|
|
}
|
|
|
|
void drv_log_prefix(enum drv_log_level level, const char *prefix, const char *file, int line,
|
|
const char *format, ...)
|
|
{
|
|
char buf[50];
|
|
snprintf(buf, sizeof(buf), "[%s:%s(%d)]", prefix, basename(file), line);
|
|
|
|
va_list args;
|
|
va_start(args, format);
|
|
#ifdef __ANDROID__
|
|
int prio = ANDROID_LOG_ERROR;
|
|
switch (level) {
|
|
case DRV_LOGV:
|
|
prio = ANDROID_LOG_VERBOSE;
|
|
break;
|
|
case DRV_LOGD:
|
|
prio = ANDROID_LOG_DEBUG;
|
|
break;
|
|
case DRV_LOGI:
|
|
prio = ANDROID_LOG_INFO;
|
|
break;
|
|
case DRV_LOGE:
|
|
default:
|
|
break;
|
|
};
|
|
__android_log_vprint(prio, buf, format, args);
|
|
#else
|
|
if (level == DRV_LOGE) {
|
|
fprintf(stderr, "%s ", buf);
|
|
vfprintf(stderr, format, args);
|
|
} else {
|
|
fprintf(stdout, "%s ", buf);
|
|
vfprintf(stdout, format, args);
|
|
}
|
|
#endif
|
|
va_end(args);
|
|
}
|
|
|
|
int drv_resource_info(struct bo *bo, uint32_t strides[DRV_MAX_PLANES],
|
|
uint32_t offsets[DRV_MAX_PLANES], uint64_t *format_modifier)
|
|
{
|
|
for (uint32_t plane = 0; plane < bo->meta.num_planes; plane++) {
|
|
strides[plane] = bo->meta.strides[plane];
|
|
offsets[plane] = bo->meta.offsets[plane];
|
|
}
|
|
*format_modifier = bo->meta.format_modifier;
|
|
|
|
if (bo->drv->backend->resource_info)
|
|
return bo->drv->backend->resource_info(bo, strides, offsets, format_modifier);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t drv_get_max_texture_2d_size(struct driver *drv)
|
|
{
|
|
if (drv->backend->get_max_texture_2d_size)
|
|
return drv->backend->get_max_texture_2d_size(drv);
|
|
|
|
return UINT32_MAX;
|
|
}
|