#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <xf86drm.h>
#include "drv_priv.h"
extern struct backend backend_mediatek;
#endif
extern struct backend backend_nouveau;
+#ifdef DRV_RADEON
+extern struct backend backend_radeon;
+#endif
#ifdef DRV_ROCKCHIP
extern struct backend backend_rockchip;
#endif
#ifdef DRV_AMDGPU
&backend_amdgpu,
#endif
- &backend_cirrus,
- &backend_evdi,
+ &backend_cirrus, &backend_evdi,
#ifdef DRV_EXYNOS
&backend_exynos,
#endif
&backend_mediatek,
#endif
&backend_nouveau,
+#ifdef DRV_RADEON
+ &backend_radeon,
+#endif
#ifdef DRV_ROCKCHIP
&backend_rockchip,
#endif
#ifdef DRV_VC4
&backend_vc4,
#endif
- &backend_vgem,
- &backend_virtio_gpu,
+ &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;
goto free_buffer_table;
/* 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)
+ drv->combos.allocations = 2;
+ drv->combos.size = 0;
+
+ drv->combos.data = calloc(drv->combos.allocations, sizeof(struct combination));
+ if (!drv->combos.data)
goto free_map_table;
if (drv->backend->init) {
ret = drv->backend->init(drv);
if (ret) {
- free(drv->backend->combos.data);
+ free(drv->combos.data);
goto free_map_table;
}
}
drmHashDestroy(drv->buffer_table);
drmHashDestroy(drv->map_table);
- free(drv->backend->combos.data);
+ free(drv->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;
}
-struct combination *drv_get_combination(struct driver *drv, uint32_t format,
- uint64_t usage)
+struct combination *drv_get_combination(struct driver *drv, uint32_t format, uint64_t use_flags)
{
struct combination *curr, *best;
- if (format == DRM_FORMAT_NONE || usage == BO_USE_NONE)
+ if (format == DRM_FORMAT_NONE || use_flags == BO_USE_NONE)
return 0;
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)
+ for (i = 0; i < drv->combos.size; i++) {
+ curr = &drv->combos.data[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)
+struct bo *drv_bo_new(struct driver *drv, uint32_t width, uint32_t height, uint32_t format,
+ uint64_t use_flags)
{
struct bo *bo;
- bo = (struct bo *) calloc(1, sizeof(*bo));
+ bo = (struct bo *)calloc(1, sizeof(*bo));
if (!bo)
return NULL;
bo->width = width;
bo->height = height;
bo->format = format;
+ bo->use_flags = use_flags;
bo->num_planes = drv_num_planes_from_format(format);
if (!bo->num_planes) {
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 use_flags)
{
int ret;
size_t plane;
struct bo *bo;
- bo = drv_bo_new(drv, width, height, format);
+ bo = drv_bo_new(drv, width, height, format, use_flags);
if (!bo)
return NULL;
- ret = drv->backend->bo_create(bo, width, height, format, flags);
+ ret = drv->backend->bo_create(bo, width, height, format, use_flags);
if (ret) {
free(bo);
pthread_mutex_lock(&drv->driver_lock);
- for (plane = 0; plane < bo->num_planes; plane++)
+ for (plane = 0; plane < bo->num_planes; plane++) {
+ if (plane > 0)
+ assert(bo->offsets[plane] >= bo->offsets[plane - 1]);
+
drv_increment_reference_count(drv, bo, plane);
+ }
pthread_mutex_unlock(&drv->driver_lock);
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)
+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;
return NULL;
}
- bo = drv_bo_new(drv, width, height, format);
+ bo = drv_bo_new(drv, width, height, format, BO_USE_NONE);
if (!bo)
return NULL;
- ret = drv->backend->bo_create_with_modifiers(bo, width, height,
- format, modifiers, count);
+ ret = drv->backend->bo_create_with_modifiers(bo, width, height, format, modifiers, count);
if (ret) {
free(bo);
pthread_mutex_lock(&drv->driver_lock);
- for (plane = 0; plane < bo->num_planes; plane++)
+ for (plane = 0; plane < bo->num_planes; plane++) {
+ if (plane > 0)
+ assert(bo->offsets[plane] >= bo->offsets[plane - 1]);
+
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;
pthread_mutex_unlock(&drv->driver_lock);
- if (total == 0)
+ if (total == 0) {
+ assert(drv_map_info_destroy(bo) == 0);
bo->drv->backend->bo_destroy(bo);
+ }
free(bo);
}
int ret;
size_t plane;
struct bo *bo;
+ off_t seek_end;
- bo = drv_bo_new(drv, data->width, data->height, data->format);
+ bo = drv_bo_new(drv, data->width, data->height, data->format, data->use_flags);
if (!bo)
return NULL;
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];
+
+ seek_end = lseek(data->fds[plane], 0, SEEK_END);
+ if (seek_end == (off_t)(-1)) {
+ fprintf(stderr, "drv: lseek() failed with %s\n", strerror(errno));
+ goto destroy_bo;
+ }
+
+ lseek(data->fds[plane], 0, SEEK_SET);
+ if (plane == bo->num_planes - 1 || data->offsets[plane + 1] == 0)
+ bo->sizes[plane] = seek_end - data->offsets[plane];
+ else
+ bo->sizes[plane] = data->offsets[plane + 1] - data->offsets[plane];
+
+ if ((int64_t)bo->offsets[plane] + bo->sizes[plane] > seek_end) {
+ fprintf(stderr, "drv: buffer size is too large.\n");
+ goto destroy_bo;
+ }
+
+ bo->total_size += bo->sizes[plane];
}
return bo;
+
+destroy_bo:
+ drv_bo_destroy(bo);
+ return NULL;
}
-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 *drv_bo_map(struct bo *bo, uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+ uint32_t map_flags, struct map_info **map_data, size_t plane)
{
void *ptr;
uint8_t *addr;
assert(height > 0);
assert(x + width <= drv_bo_get_width(bo));
assert(y + height <= drv_bo_get_height(bo));
+ assert(BO_MAP_READ_WRITE & map_flags);
+ /* No CPU access for protected buffers. */
+ assert(!(bo->use_flags & BO_USE_PROTECTED));
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;
+ /* TODO(gsingh): support mapping same buffer with different flags. */
+ assert(data->map_flags == map_flags);
data->refcount++;
goto success;
}
data = calloc(1, sizeof(*data));
- addr = bo->drv->backend->bo_map(bo, data, plane);
+ addr = bo->drv->backend->bo_map(bo, data, plane, map_flags);
if (addr == MAP_FAILED) {
*map_data = NULL;
free(data);
data->refcount = 1;
data->addr = addr;
data->handle = bo->handles[plane].u32;
- drmHashInsert(bo->drv->map_table, bo->handles[plane].u32,
- (void *) data);
+ data->map_flags = map_flags;
+ drmHashInsert(bo->drv->map_table, bo->handles[plane].u32, (void *)data);
success:
+ drv_bo_invalidate(bo, 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, struct map_info *data)
{
- int ret = 0;
-
- assert(data);
- assert(data->refcount >= 0);
+ int ret = drv_bo_flush(bo, data);
+ if (ret)
+ return ret;
pthread_mutex_lock(&bo->drv->driver_lock);
if (!--data->refcount) {
- if (bo->drv->backend->bo_unmap)
- ret = bo->drv->backend->bo_unmap(bo, data);
- else
- ret = munmap(data->addr, data->length);
+ ret = bo->drv->backend->bo_unmap(bo, data);
drmHashDelete(bo->drv->map_table, data->handle);
free(data);
}
return ret;
}
+int drv_bo_invalidate(struct bo *bo, struct map_info *data)
+{
+ int ret = 0;
+ assert(data);
+ assert(data->refcount >= 0);
+
+ if (bo->drv->backend->bo_invalidate)
+ ret = bo->drv->backend->bo_invalidate(bo, data);
+
+ return ret;
+}
+
+int drv_bo_flush(struct bo *bo, struct map_info *data)
+{
+ int ret = 0;
+ assert(data);
+ assert(data->refcount >= 0);
+ assert(!(bo->use_flags & BO_USE_PROTECTED));
+
+ if (bo->drv->backend->bo_flush)
+ ret = bo->drv->backend->bo_flush(bo, data);
+
+ return ret;
+}
+
uint32_t drv_bo_get_width(struct bo *bo)
{
return bo->width;
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 use_flags)
{
if (drv->backend->resolve_format)
- return drv->backend->resolve_format(format);
+ return drv->backend->resolve_format(format, use_flags);
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 = DIV_ROUND_UP(width * 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:
- case DRM_FORMAT_YVU420_ANDROID:
- stride = DIV_ROUND_UP(stride, 2);
- break;
- }
- }
-
- /*
- * The stride of Android YV12 buffers is required to be aligned to 16 bytes
- * (see <system/graphics.h>).
- */
- if (format == DRM_FORMAT_YVU420_ANDROID)
- stride = ALIGN(stride, 16);
-
- 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 0;
}
-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:
- vertical_subsampling = 1;
- }
-
- return stride * DIV_ROUND_UP(height, vertical_subsampling);
-}
-
uint32_t drv_num_buffers_per_bo(struct bo *bo)
{
uint32_t count = 0;