minigbm: refactor bo refcount and mapping destruction

1. internalize drv specific helpers into drv.c
2. simplify bo ref counting and clean up
3. refactor drv_bo_mapping_destroy

BUG=b:201110412
TEST=CQ

Change-Id: If297ef7007c1d14a69ae467b6d1c67c4edf5b177
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/3188470
Tested-by: Yiwei Zhang <zzyiwei@chromium.org>
Reviewed-by: Chia-I Wu <olv@google.com>
Commit-Queue: Yiwei Zhang <zzyiwei@chromium.org>
diff --git a/drv.c b/drv.c
index 7963aa4..22eabdd 100644
--- a/drv.c
+++ b/drv.c
@@ -237,11 +237,94 @@
 	return bo;
 }
 
+static int 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->driver_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->handles[plane].u32) {
+				idx++;
+				continue;
+			}
+
+			if (!--mapping->vma->refcount) {
+				int ret = drv->backend->bo_unmap(bo, mapping->vma);
+				if (ret) {
+					drv_log("munmap failed\n");
+					return ret;
+				}
+
+				free(mapping->vma);
+			}
+
+			/* This shrinks and shifts the array, so don't increment idx. */
+			drv_array_remove(drv->mappings, idx);
+		}
+	}
+	pthread_mutex_unlock(&drv->driver_lock);
+
+	return 0;
+}
+
+/*
+ * 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->driver_lock);
+	for (size_t plane = 0; plane < bo->meta.num_planes; plane++) {
+		uintptr_t num = 0;
+
+		if (!drmHashLookup(drv->buffer_table, bo->handles[plane].u32, (void **)&num))
+			drmHashDelete(drv->buffer_table, bo->handles[plane].u32);
+
+		drmHashInsert(drv->buffer_table, bo->handles[plane].u32, (void *)(num + 1));
+	}
+	pthread_mutex_unlock(&drv->driver_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;
+	bool unreferenced = true;
+
+	pthread_mutex_lock(&drv->driver_lock);
+	for (size_t plane = 0; plane < bo->meta.num_planes; plane++) {
+		uintptr_t num = 0;
+
+		if (!drmHashLookup(drv->buffer_table, bo->handles[plane].u32, (void **)&num)) {
+			drmHashDelete(drv->buffer_table, bo->handles[plane].u32);
+		}
+
+		if (num > 1) {
+			drmHashInsert(drv->buffer_table, bo->handles[plane].u32, (void *)(num - 1));
+			unreferenced = false;
+		}
+	}
+	pthread_mutex_unlock(&drv->driver_lock);
+
+	return unreferenced;
+}
+
 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;
 	bool is_test_alloc;
 
@@ -269,16 +352,7 @@
 		return NULL;
 	}
 
-	pthread_mutex_lock(&drv->driver_lock);
-
-	for (plane = 0; plane < bo->meta.num_planes; plane++) {
-		if (plane > 0)
-			assert(bo->meta.offsets[plane] >= bo->meta.offsets[plane - 1]);
-
-		drv_increment_reference_count(drv, bo, plane);
-	}
-
-	pthread_mutex_unlock(&drv->driver_lock);
+	drv_bo_acquire(bo);
 
 	return bo;
 }
@@ -287,7 +361,6 @@
 					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 && !drv->backend->bo_compute_metadata) {
@@ -316,43 +389,18 @@
 		return NULL;
 	}
 
-	pthread_mutex_lock(&drv->driver_lock);
-
-	for (plane = 0; plane < bo->meta.num_planes; plane++) {
-		if (plane > 0)
-			assert(bo->meta.offsets[plane] >= bo->meta.offsets[plane - 1]);
-
-		drv_increment_reference_count(drv, bo, plane);
-	}
-
-	pthread_mutex_unlock(&drv->driver_lock);
+	drv_bo_acquire(bo);
 
 	return bo;
 }
 
 void drv_bo_destroy(struct bo *bo)
 {
-	int ret;
-	size_t plane;
-	uintptr_t total = 0;
-	struct driver *drv = bo->drv;
+	if (!bo->is_test_buffer && drv_bo_release(bo)) {
+		int ret = drv_bo_mapping_destroy(bo);
+		assert(ret == 0);
 
-	if (!bo->is_test_buffer) {
-		pthread_mutex_lock(&drv->driver_lock);
-
-		for (plane = 0; plane < bo->meta.num_planes; plane++)
-			drv_decrement_reference_count(drv, bo, plane);
-
-		for (plane = 0; plane < bo->meta.num_planes; plane++)
-			total += drv_get_reference_count(drv, bo, plane);
-
-		pthread_mutex_unlock(&drv->driver_lock);
-
-		if (total == 0) {
-			ret = drv_mapping_destroy(bo);
-			assert(ret == 0);
-			bo->drv->backend->bo_destroy(bo);
-		}
+		bo->drv->backend->bo_destroy(bo);
 	}
 
 	free(bo);
@@ -376,11 +424,7 @@
 		return NULL;
 	}
 
-	for (plane = 0; plane < bo->meta.num_planes; plane++) {
-		pthread_mutex_lock(&bo->drv->driver_lock);
-		drv_increment_reference_count(bo->drv, bo, plane);
-		pthread_mutex_unlock(&bo->drv->driver_lock);
-	}
+	drv_bo_acquire(bo);
 
 	bo->meta.format_modifier = data->format_modifier;
 	for (plane = 0; plane < bo->meta.num_planes; plane++) {