/*
- * Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * 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>
#ifdef DRV_MEDIATEK
extern struct backend backend_mediatek;
#endif
+extern struct backend backend_nouveau;
#ifdef DRV_ROCKCHIP
extern struct backend backend_rockchip;
#endif
extern struct backend backend_tegra;
#endif
extern struct backend backend_udl;
+#ifdef DRV_VC4
+extern struct backend backend_vc4;
+#endif
extern struct backend backend_vgem;
extern struct backend backend_virtio_gpu;
#ifdef DRV_AMDGPU
&backend_amdgpu,
#endif
- &backend_cirrus,
- &backend_evdi,
+ &backend_cirrus, &backend_evdi,
#ifdef DRV_EXYNOS
&backend_exynos,
#endif
#ifdef DRV_MEDIATEK
&backend_mediatek,
#endif
+ &backend_nouveau,
#ifdef DRV_ROCKCHIP
&backend_rockchip,
#endif
&backend_tegra,
#endif
&backend_udl,
- &backend_vgem,
- &backend_virtio_gpu,
+#ifdef DRV_VC4
+ &backend_vc4,
+#endif
+ &backend_vgem, &backend_virtio_gpu,
};
- for(i = 0; i < ARRAY_SIZE(backend_list); i++)
+ for (i = 0; i < ARRAY_SIZE(backend_list); i++)
if (!strcmp(drm_version->name, backend_list[i]->name)) {
drmFreeVersion(drm_version);
return backend_list[i];
struct driver *drv;
int ret;
- drv = (struct driver *) calloc(1, sizeof(*drv));
+ drv = (struct driver *)calloc(1, sizeof(*drv));
if (!drv)
return NULL;
if (!drv->map_table)
goto free_buffer_table;
- LIST_INITHEAD(&drv->backend->combinations);
+ /* Start with a power of 2 number of allocations. */
+ drv->backend->combos.allocations = 2;
+ drv->backend->combos.size = 0;
+ drv->backend->combos.data =
+ calloc(drv->backend->combos.allocations, sizeof(struct combination));
+ if (!drv->backend->combos.data)
+ goto free_map_table;
if (drv->backend->init) {
ret = drv->backend->init(drv);
- if (ret)
+ if (ret) {
+ free(drv->backend->combos.data);
goto free_map_table;
+ }
}
return drv;
drmHashDestroy(drv->buffer_table);
drmHashDestroy(drv->map_table);
- list_for_each_entry_safe(struct combination_list_element, elem,
- &drv->backend->combinations, link) {
- LIST_DEL(&elem->link);
- free(elem);
- }
+ free(drv->backend->combos.data);
pthread_mutex_unlock(&drv->driver_lock);
pthread_mutex_destroy(&drv->driver_lock);
return drv->fd;
}
-const char *
-drv_get_name(struct driver *drv)
+const char *drv_get_name(struct driver *drv)
{
return drv->backend->name;
}
-int drv_is_combination_supported(struct driver *drv, uint32_t format,
- uint64_t usage, uint64_t modifier)
+struct combination *drv_get_combination(struct driver *drv, uint32_t format, uint64_t usage)
{
+ struct combination *curr, *best;
if (format == DRM_FORMAT_NONE || usage == BO_USE_NONE)
return 0;
- list_for_each_entry(struct combination_list_element, elem,
- &drv->backend->combinations, link) {
- if (format == elem->combination.format &&
- usage == (elem->combination.usage & usage) &&
- modifier == elem->combination.modifier)
- return 1;
+ best = NULL;
+ uint32_t i;
+ for (i = 0; i < drv->backend->combos.size; i++) {
+ curr = &drv->backend->combos.data[i];
+ if ((format == curr->format) && usage == (curr->usage & usage))
+ if (!best || best->metadata.priority < curr->metadata.priority)
+ best = curr;
}
- return 0;
+ return best;
}
-struct bo *drv_bo_new(struct driver *drv, uint32_t width, uint32_t height,
- uint32_t format)
+struct bo *drv_bo_new(struct driver *drv, uint32_t width, uint32_t height, uint32_t format)
{
struct bo *bo;
- bo = (struct bo *) calloc(1, sizeof(*bo));
+ bo = (struct bo *)calloc(1, sizeof(*bo));
if (!bo)
return NULL;
return bo;
}
-struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height,
- uint32_t format, uint64_t flags)
+struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height, uint32_t format,
+ uint64_t flags)
{
int ret;
size_t plane;
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;
+ size_t plane;
+ struct bo *bo;
+
+ if (!drv->backend->bo_create_with_modifiers) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ bo = drv_bo_new(drv, width, height, format);
+
+ if (!bo)
+ return NULL;
+
+ ret = drv->backend->bo_create_with_modifiers(bo, width, height, format, modifiers, count);
+
+ if (ret) {
+ free(bo);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&drv->driver_lock);
+
+ for (plane = 0; plane < bo->num_planes; plane++)
+ drv_increment_reference_count(drv, bo, plane);
+
+ pthread_mutex_unlock(&drv->driver_lock);
+
+ return bo;
+}
+
void drv_bo_destroy(struct bo *bo)
{
size_t plane;
int ret;
size_t plane;
struct bo *bo;
- struct drm_prime_handle prime_handle;
bo = drv_bo_new(drv, data->width, data->height, data->format);
if (!bo)
return NULL;
- for (plane = 0; plane < bo->num_planes; plane++) {
-
- memset(&prime_handle, 0, sizeof(prime_handle));
- prime_handle.fd = data->fds[plane];
-
- ret = drmIoctl(drv->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE,
- &prime_handle);
-
- if (ret) {
- fprintf(stderr, "drv: DRM_IOCTL_PRIME_FD_TO_HANDLE failed "
- "(fd=%u)\n", prime_handle.fd);
-
- if (plane > 0) {
- bo->num_planes = plane;
- drv_bo_destroy(bo);
- } else {
- free(bo);
- }
-
- return NULL;
- }
+ ret = drv->backend->bo_import(bo, data);
+ if (ret) {
+ free(bo);
+ return NULL;
+ }
- bo->handles[plane].u32 = prime_handle.handle;
+ for (plane = 0; plane < bo->num_planes; plane++) {
bo->strides[plane] = data->strides[plane];
bo->offsets[plane] = data->offsets[plane];
bo->sizes[plane] = data->sizes[plane];
bo->format_modifiers[plane] = data->format_modifiers[plane];
bo->total_size += data->sizes[plane];
-
- pthread_mutex_lock(&drv->driver_lock);
- drv_increment_reference_count(drv, bo, plane);
- pthread_mutex_unlock(&drv->driver_lock);
}
return bo;
}
-void *drv_bo_map(struct bo *bo, uint32_t x, uint32_t y, uint32_t width,
- uint32_t height, uint32_t flags, void **map_data, size_t plane)
+void *drv_bo_map(struct bo *bo, uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+ uint32_t flags, struct map_info **map_data, size_t plane)
{
void *ptr;
uint8_t *addr;
size_t offset;
struct map_info *data;
+ int prot;
assert(width > 0);
assert(height > 0);
assert(x + width <= drv_bo_get_width(bo));
assert(y + height <= drv_bo_get_height(bo));
+ assert(BO_TRANSFER_READ_WRITE & flags);
pthread_mutex_lock(&bo->drv->driver_lock);
if (!drmHashLookup(bo->drv->map_table, bo->handles[plane].u32, &ptr)) {
- data = (struct map_info *) ptr;
+ data = (struct map_info *)ptr;
data->refcount++;
goto success;
}
data = calloc(1, sizeof(*data));
- addr = bo->drv->backend->bo_map(bo, data, plane);
+ prot = BO_TRANSFER_WRITE & flags ? PROT_WRITE | PROT_READ : PROT_READ;
+ addr = bo->drv->backend->bo_map(bo, data, plane, prot);
if (addr == MAP_FAILED) {
*map_data = NULL;
free(data);
data->refcount = 1;
data->addr = addr;
data->handle = bo->handles[plane].u32;
- drmHashInsert(bo->drv->buffer_table, bo->handles[plane].u32,
- (void *) data);
+ drmHashInsert(bo->drv->map_table, bo->handles[plane].u32, (void *)data);
success:
- *map_data = (void *) data;
+ *map_data = data;
offset = drv_bo_get_plane_stride(bo, plane) * y;
offset += drv_stride_from_format(bo->format, x, plane);
- addr = (uint8_t *) data->addr;
+ addr = (uint8_t *)data->addr;
addr += drv_bo_get_plane_offset(bo, plane) + offset;
pthread_mutex_unlock(&bo->drv->driver_lock);
- return (void *) addr;
+ return (void *)addr;
}
-int drv_bo_unmap(struct bo *bo, void *map_data)
+int drv_bo_unmap(struct bo *bo, struct map_info *data)
{
- struct map_info *data = map_data;
int ret = 0;
assert(data);
pthread_mutex_lock(&bo->drv->driver_lock);
if (!--data->refcount) {
- ret = munmap(data->addr, data->length);
+ if (bo->drv->backend->bo_unmap)
+ ret = bo->drv->backend->bo_unmap(bo, data);
+ else
+ ret = munmap(data->addr, data->length);
drmHashDelete(bo->drv->map_table, data->handle);
free(data);
}
int ret, fd;
assert(plane < bo->num_planes);
- ret = drmPrimeHandleToFD(bo->drv->fd, bo->handles[plane].u32,
- DRM_CLOEXEC | DRM_RDWR, &fd);
+ ret = drmPrimeHandleToFD(bo->drv->fd, bo->handles[plane].u32, DRM_CLOEXEC | DRM_RDWR, &fd);
return (ret) ? ret : fd;
-
}
uint32_t drv_bo_get_plane_offset(struct bo *bo, size_t plane)
uint64_t drv_bo_get_plane_format_modifier(struct bo *bo, size_t plane)
{
- assert(plane < bo->num_planes);
+ assert(plane < bo->num_planes);
return bo->format_modifiers[plane];
}
return bo->format;
}
-uint32_t drv_resolve_format(struct driver *drv, uint32_t format)
+uint32_t drv_resolve_format(struct driver *drv, uint32_t format, uint64_t usage)
{
if (drv->backend->resolve_format)
- return drv->backend->resolve_format(format);
+ return drv->backend->resolve_format(format, usage);
return format;
}
-/*
- * This function returns the stride for a given format, width and plane.
- */
-int drv_stride_from_format(uint32_t format, uint32_t width, size_t plane)
-{
- int stride = width * DIV_ROUND_UP(drv_bpp_from_format(format, plane),
- 8);
-
- /*
- * Only downsample for certain multiplanar formats which have horizontal
- * subsampling for chroma planes. Only formats supported by our drivers
- * are listed here -- add more as needed.
- */
- if (plane != 0) {
- switch (format) {
- case DRM_FORMAT_NV12:
- case DRM_FORMAT_YVU420:
- stride = stride / 2;
- break;
- }
- }
-
- return stride;
-}
-
size_t drv_num_planes_from_format(uint32_t format)
{
switch (format) {
case DRM_FORMAT_YVYU:
return 1;
case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
return 2;
case DRM_FORMAT_YVU420:
+ case DRM_FORMAT_YVU420_ANDROID:
return 3;
}
return 0;
}
-uint32_t drv_size_from_format(uint32_t format, uint32_t stride,
- uint32_t height, size_t plane)
+uint32_t drv_size_from_format(uint32_t format, uint32_t stride, uint32_t height, size_t plane)
{
assert(plane < drv_num_planes_from_format(format));
uint32_t vertical_subsampling;
switch (format) {
case DRM_FORMAT_NV12:
case DRM_FORMAT_YVU420:
+ case DRM_FORMAT_YVU420_ANDROID:
vertical_subsampling = (plane == 0) ? 1 : 2;
break;
default: