minigbm: More sophisticated gbm_bo_map/gbm_bo_unmap
We previously added the gbm_bo_map/gbm_bo_unmap (see CL:393927)
entry points since we wanted to do driver-specific detiling during
screenshot capture tests. We ignored most the parameters and mapped
the entire buffer. This CL adds the ability to:
1) Return the starting address within a byte given a specific x, y
in the buffer.
2) Handle the case where there are more than one kernel buffers
per buffer object. Currently, only the Exynos driver would use
this capability.
BUG=chromium:653284
TEST=Ran cros_gralloc with modified code
CQ-DEPEND=CL:393927
Change-Id: I19d75d2f16489c0184e96305fb643f18477e1cdb
Reviewed-on: https://chromium-review.googlesource.com/395066
Commit-Ready: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Gurchetan Singh <gurchetansingh@chromium.org>
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
diff --git a/drv.c b/drv.c
index f2376a2..fdae850 100644
--- a/drv.c
+++ b/drv.c
@@ -106,31 +106,37 @@
drv->fd = fd;
drv->backend = drv_get_backend(fd);
- if (!drv->backend) {
- free(drv);
- return NULL;
- }
+ if (!drv->backend)
+ goto free_driver;
- if (pthread_mutex_init(&drv->table_lock, NULL)) {
- free(drv);
- return NULL;
- }
+ if (pthread_mutex_init(&drv->table_lock, NULL))
+ goto free_driver;
drv->buffer_table = drmHashCreate();
- if (!drv->buffer_table) {
- free(drv);
- return NULL;
- }
+ if (!drv->buffer_table)
+ goto free_lock;
+
+ drv->map_table = drmHashCreate();
+ if (!drv->map_table)
+ goto free_buffer_table;
if (drv->backend->init) {
ret = drv->backend->init(drv);
- if (ret) {
- free(drv);
- return NULL;
- }
+ if (ret)
+ goto free_map_table;
}
return drv;
+
+free_map_table:
+ drmHashDestroy(drv->map_table);
+free_buffer_table:
+ drmHashDestroy(drv->buffer_table);
+free_lock:
+ pthread_mutex_destroy(&drv->table_lock);
+free_driver:
+ free(drv);
+ return NULL;
}
void drv_destroy(struct driver *drv)
@@ -140,6 +146,7 @@
pthread_mutex_destroy(&drv->table_lock);
drmHashDestroy(drv->buffer_table);
+ drmHashDestroy(drv->map_table);
free(drv);
}
@@ -251,32 +258,6 @@
free(bo);
}
-void *
-drv_bo_map(struct bo *bo)
-{
- assert(drv_num_buffers_per_bo(bo) == 1);
-
- if (!bo->map_data || bo->map_data == MAP_FAILED)
- bo->map_data = bo->drv->backend->bo_map(bo);
-
- return bo->map_data;
-}
-
-int
-drv_bo_unmap(struct bo *bo)
-{
- int ret = -1;
-
- assert(drv_num_buffers_per_bo(bo) == 1);
-
- if (bo->map_data && bo->map_data != MAP_FAILED)
- ret = munmap(bo->map_data, bo->total_size);
-
- bo->map_data = NULL;
-
- return ret;
-}
-
struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data)
{
int ret;
@@ -324,6 +305,74 @@
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 *ptr;
+ uint8_t *addr;
+ size_t offset;
+ struct map_info *data;
+
+ assert(width > 0);
+ assert(height > 0);
+ assert(x + width <= drv_bo_get_width(bo));
+ assert(y + height <= drv_bo_get_height(bo));
+
+ pthread_mutex_lock(&bo->drv->table_lock);
+
+ if (!drmHashLookup(bo->drv->map_table, bo->handles[plane].u32, &ptr)) {
+ data = (struct map_info *) ptr;
+ data->refcount++;
+ goto success;
+ }
+
+ data = calloc(1, sizeof(*data));
+ addr = bo->drv->backend->bo_map(bo, data, plane);
+ if (addr == MAP_FAILED) {
+ *map_data = NULL;
+ free(data);
+ pthread_mutex_unlock(&bo->drv->table_lock);
+ return MAP_FAILED;
+ }
+
+ data->refcount = 1;
+ data->addr = addr;
+ data->handle = bo->handles[plane].u32;
+ drmHashInsert(bo->drv->buffer_table, bo->handles[plane].u32,
+ (void *) data);
+
+success:
+ *map_data = (void *) 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 += drv_bo_get_plane_offset(bo, plane) + offset;
+ pthread_mutex_unlock(&bo->drv->table_lock);
+
+ return (void *) addr;
+}
+
+int drv_bo_unmap(struct bo *bo, void *map_data)
+{
+ struct map_info *data = map_data;
+ int ret = 0;
+
+ assert(data);
+ assert(data->refcount >= 0);
+
+ pthread_mutex_lock(&bo->drv->table_lock);
+
+ if (!--data->refcount) {
+ ret = munmap(data->addr, data->length);
+ drmHashDelete(bo->drv->map_table, data->handle);
+ free(data);
+ }
+
+ pthread_mutex_unlock(&bo->drv->table_lock);
+
+ return ret;
+}
+
uint32_t drv_bo_get_width(struct bo *bo)
{
return bo->width;