Merge "Merge remote-tracking branch 'aosp/upstream-main' into 'aosp/master'"
diff --git a/Android.bp b/Android.bp
index c39b756..9d8a567 100644
--- a/Android.bp
+++ b/Android.bp
@@ -38,10 +38,9 @@
     srcs: [
         "amdgpu.c",
         "drv.c",
+        "drv_array_helpers.c",
+        "drv_helpers.c",
         "dumb_driver.c",
-        "exynos.c",
-        "helpers_array.c",
-        "helpers.c",
         "i915.c",
         "mediatek.c",
         "msm.c",
diff --git a/OWNERS b/OWNERS
index 6a69a37..1facc15 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,10 +1,20 @@
+basni@chromium.org
+dbehr@chromium.org
+ddavenport@chromium.org
 gurchetansingh@chromium.org
+hiroh@chromium.org
 hoegsberg@chromium.org
 marcheu@chromium.org
+olv@google.com
+robdclark@chromium.org
 stevensd@chromium.org
 tfiga@chromium.org
+zzyiwei@chromium.org
 
-# Also natsu@google.com is great for gralloc/Android stuff but doesn't have a
-# chromium account.
-# So any team members can +2
-*
+# just reference for backend specific reviews
+per-file amdgpu.c = basni@chromium.org, ddavenport@chromium.org
+per-file i915.c = chadversary@chromium.org, hoegsberg@chromium.org
+per-file mediatek.c = fshao@chromium.org, tzungbi@chromium.org
+per-file msm.c = robdclark@chromium.org, hoegsberg@chromium.org
+per-file rockchip.c = tfiga@chromium.org
+per-file virtgpu* = jbates@chromium.org, natsu@google.com, olv@google.com, zzyiwei@chromium.org
diff --git a/amdgpu.c b/amdgpu.c
index da211ca..3ebf1ab 100644
--- a/amdgpu.c
+++ b/amdgpu.c
@@ -19,8 +19,8 @@
 #include <xf86drmMode.h>
 
 #include "dri.h"
+#include "drv_helpers.h"
 #include "drv_priv.h"
-#include "helpers.h"
 #include "util.h"
 
 // clang-format off
@@ -785,8 +785,7 @@
 	.bo_map = amdgpu_map_bo,
 	.bo_unmap = amdgpu_unmap_bo,
 	.bo_invalidate = amdgpu_bo_invalidate,
-	.resolve_format = drv_resolve_format_helper,
-	.resolve_use_flags = drv_resolve_use_flags_helper,
+	.resolve_format_and_use_flags = drv_resolve_format_and_use_flags_helper,
 	.num_planes_from_modifier = dri_num_planes_from_modifier,
 };
 
diff --git a/cros_gralloc/OWNERS b/cros_gralloc/OWNERS
new file mode 100644
index 0000000..cd8d003
--- /dev/null
+++ b/cros_gralloc/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+natsu@google.com
+zzyiwei@chromium.org
diff --git a/cros_gralloc/cros_gralloc_buffer.h b/cros_gralloc/cros_gralloc_buffer.h
index 9bc0ef0..3158454 100644
--- a/cros_gralloc/cros_gralloc_buffer.h
+++ b/cros_gralloc/cros_gralloc_buffer.h
@@ -7,7 +7,6 @@
 #ifndef CROS_GRALLOC_BUFFER_H
 #define CROS_GRALLOC_BUFFER_H
 
-#include "../drv.h"
 #include "cros_gralloc_helpers.h"
 
 class cros_gralloc_buffer
diff --git a/cros_gralloc/cros_gralloc_driver.cc b/cros_gralloc/cros_gralloc_driver.cc
index 70f261c..1381ff5 100644
--- a/cros_gralloc/cros_gralloc_driver.cc
+++ b/cros_gralloc/cros_gralloc_driver.cc
@@ -13,8 +13,6 @@
 #include <syscall.h>
 #include <xf86drm.h>
 
-#include "../drv_priv.h"
-#include "../helpers.h"
 #include "../util.h"
 
 // Constants taken from pipe_loader_drm.c in Mesa
@@ -138,19 +136,8 @@
 	uint64_t resolved_use_flags;
 	struct combination *combo;
 
-	resolved_format = drv_resolve_format(drv_, descriptor->drm_format, descriptor->use_flags);
-	if (resolved_format == DRM_FORMAT_NONE)
-		return false;
-
-	resolved_use_flags = drv_resolve_use_flags(drv_, resolved_format, descriptor->use_flags);
-	/*
-	 * This unmask is a backup in the case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED is resolved
-	 * to non-YUV formats.
-	 */
-	if (descriptor->drm_format == DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED &&
-	    (resolved_format == DRM_FORMAT_XBGR8888 || resolved_format == DRM_FORMAT_ABGR8888)) {
-		resolved_use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
-	}
+	drv_resolve_format_and_use_flags(drv_, descriptor->drm_format, descriptor->use_flags,
+					 &resolved_format, &resolved_use_flags);
 
 	combo = drv_get_combination(drv_, resolved_format, resolved_use_flags);
 	if (!combo && (descriptor->droid_usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) &&
@@ -187,8 +174,7 @@
 	if (descriptor->droid_format == HAL_PIXEL_FORMAT_BLOB)
 		return true;
 
-	return descriptor->width <= max_texture_size &&
-	       descriptor->height <= max_texture_size;
+	return descriptor->width <= max_texture_size && descriptor->height <= max_texture_size;
 }
 
 int32_t create_reserved_region(const std::string &buffer_name, uint64_t reserved_region_size)
@@ -564,9 +550,15 @@
 	return buffer->get_reserved_region(reserved_region_addr, reserved_region_size);
 }
 
-uint32_t cros_gralloc_driver::get_resolved_drm_format(uint32_t drm_format, uint64_t usage)
+uint32_t cros_gralloc_driver::get_resolved_drm_format(uint32_t drm_format, uint64_t use_flags)
 {
-	return drv_resolve_format(drv_, drm_format, usage);
+	uint32_t resolved_format;
+	uint64_t resolved_use_flags;
+
+	drv_resolve_format_and_use_flags(drv_, drm_format, use_flags, &resolved_format,
+					 &resolved_use_flags);
+
+	return resolved_format;
 }
 
 cros_gralloc_buffer *cros_gralloc_driver::get_buffer(cros_gralloc_handle_t hnd)
diff --git a/cros_gralloc/cros_gralloc_driver.h b/cros_gralloc/cros_gralloc_driver.h
index 8403ff6..d1456a8 100644
--- a/cros_gralloc/cros_gralloc_driver.h
+++ b/cros_gralloc/cros_gralloc_driver.h
@@ -39,7 +39,7 @@
 	int32_t get_reserved_region(buffer_handle_t handle, void **reserved_region_addr,
 				    uint64_t *reserved_region_size);
 
-	uint32_t get_resolved_drm_format(uint32_t drm_format, uint64_t usage);
+	uint32_t get_resolved_drm_format(uint32_t drm_format, uint64_t use_flags);
 
 	void for_each_handle(const std::function<void(cros_gralloc_handle_t)> &function);
 
diff --git a/cros_gralloc/gralloc0/gralloc0.cc b/cros_gralloc/gralloc0/gralloc0.cc
index 6bc7ee4..53c89fd 100644
--- a/cros_gralloc/gralloc0/gralloc0.cc
+++ b/cros_gralloc/gralloc0/gralloc0.cc
@@ -4,7 +4,6 @@
  * found in the LICENSE file.
  */
 
-#include "../../helpers.h"
 #include "../../util.h"
 #include "../cros_gralloc_driver.h"
 
diff --git a/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc b/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc
index 327c8ca..8f952e1 100644
--- a/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc
+++ b/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc
@@ -16,8 +16,6 @@
 #include "cros_gralloc/cros_gralloc_helpers.h"
 #include "cros_gralloc/gralloc4/CrosGralloc4Utils.h"
 
-#include "helpers.h"
-
 using aidl::android::hardware::graphics::common::BlendMode;
 using aidl::android::hardware::graphics::common::Dataspace;
 using aidl::android::hardware::graphics::common::PlaneLayout;
diff --git a/dri.c b/dri.c
index f89bbed..8b55c32 100644
--- a/dri.c
+++ b/dri.c
@@ -18,8 +18,8 @@
 #include <xf86drm.h>
 
 #include "dri.h"
+#include "drv_helpers.h"
 #include "drv_priv.h"
-#include "helpers.h"
 #include "util.h"
 
 static const struct {
diff --git a/drv.c b/drv.c
index b50eea6..ea979d3 100644
--- a/drv.c
+++ b/drv.c
@@ -9,7 +9,6 @@
 #include <pthread.h>
 #include <stdint.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/types.h>
@@ -21,8 +20,8 @@
 #include <libgen.h>
 #endif
 
+#include "drv_helpers.h"
 #include "drv_priv.h"
-#include "helpers.h"
 #include "util.h"
 
 #ifdef DRV_AMDGPU
@@ -263,6 +262,8 @@
 			if (!--mapping->vma->refcount) {
 				int ret = drv->backend->bo_unmap(bo, mapping->vma);
 				if (ret) {
+					pthread_mutex_unlock(&drv->mappings_lock);
+					assert(ret);
 					drv_log("munmap failed\n");
 					return;
 				}
@@ -303,24 +304,31 @@
 static bool drv_bo_release(struct bo *bo)
 {
 	struct driver *drv = bo->drv;
-	bool unreferenced = true;
+	uintptr_t num;
 
 	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->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;
+			if (num > 1) {
+				drmHashInsert(drv->buffer_table, bo->handles[plane].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->handles[plane].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 unreferenced;
+	return true;
 }
 
 struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height, uint32_t format,
@@ -703,20 +711,21 @@
 	return bo->meta.total_size;
 }
 
-uint32_t drv_resolve_format(struct driver *drv, uint32_t format, uint64_t use_flags)
+/*
+ * Map internal fourcc codes back to standard fourcc codes.
+ */
+uint32_t drv_get_standard_fourcc(uint32_t fourcc_internal)
 {
-	if (drv->backend->resolve_format)
-		return drv->backend->resolve_format(format, use_flags);
-
-	return format;
+	return (fourcc_internal == DRM_FORMAT_YVU420_ANDROID) ? DRM_FORMAT_YVU420 : fourcc_internal;
 }
 
-uint64_t drv_resolve_use_flags(struct driver *drv, uint32_t format, uint64_t use_flags)
+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)
 {
-	if (drv->backend->resolve_use_flags)
-		return drv->backend->resolve_use_flags(drv, format, use_flags);
+	assert(drv->backend->resolve_format_and_use_flags);
 
-	return use_flags;
+	drv->backend->resolve_format_and_use_flags(drv, format, use_flags, out_format,
+						   out_use_flags);
 }
 
 uint32_t drv_num_buffers_per_bo(struct bo *bo)
diff --git a/drv.h b/drv.h
index 99b4afd..9687025 100644
--- a/drv.h
+++ b/drv.h
@@ -14,6 +14,7 @@
 #include <drm_fourcc.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 #define DRV_MAX_PLANES 4
 
@@ -178,11 +179,14 @@
 
 size_t drv_bo_get_total_size(struct bo *bo);
 
+uint32_t drv_get_standard_fourcc(uint32_t fourcc_internal);
+
 uint32_t drv_bytes_per_pixel_from_format(uint32_t format, size_t plane);
 
 uint32_t drv_stride_from_format(uint32_t format, uint32_t width, size_t plane);
 
-uint32_t drv_resolve_format(struct driver *drv, uint32_t format, uint64_t use_flags);
+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);
 
 uint64_t drv_resolve_use_flags(struct driver *drv, uint32_t format, uint64_t use_flags);
 
diff --git a/helpers_array.c b/drv_array_helpers.c
similarity index 98%
rename from helpers_array.c
rename to drv_array_helpers.c
index 2ec9063..b4e7750 100644
--- a/helpers_array.c
+++ b/drv_array_helpers.c
@@ -3,6 +3,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+#include "drv_array_helpers.h"
 
 #include <assert.h>
 #include <stdint.h>
diff --git a/helpers_array.h b/drv_array_helpers.h
similarity index 89%
rename from helpers_array.h
rename to drv_array_helpers.h
index 2893976..77544d3 100644
--- a/helpers_array.h
+++ b/drv_array_helpers.h
@@ -4,6 +4,11 @@
  * found in the LICENSE file.
  */
 
+#ifndef DRV_ARRAY_HELPERS_H
+#define DRV_ARRAY_HELPERS_H
+
+#include <stdint.h>
+
 struct drv_array;
 
 struct drv_array *drv_array_init(uint32_t item_size);
@@ -20,3 +25,5 @@
 
 /* The array and all associated data will be freed. */
 void drv_array_destroy(struct drv_array *array);
+
+#endif
diff --git a/helpers.c b/drv_helpers.c
similarity index 95%
rename from helpers.c
rename to drv_helpers.c
index fc67bbf..6ea4b8e 100644
--- a/helpers.c
+++ b/drv_helpers.c
@@ -4,6 +4,8 @@
  * found in the LICENSE file.
  */
 
+#include "drv_helpers.h"
+
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
@@ -15,7 +17,6 @@
 #include <xf86drm.h>
 
 #include "drv_priv.h"
-#include "helpers.h"
 #include "util.h"
 
 struct planar_layout {
@@ -572,35 +573,31 @@
 	return false;
 }
 
-/*
- * Map internal fourcc codes back to standard fourcc codes.
- */
-uint32_t drv_get_standard_fourcc(uint32_t fourcc_internal)
+void drv_resolve_format_and_use_flags_helper(struct driver *drv, uint32_t format,
+					     uint64_t use_flags, uint32_t *out_format,
+					     uint64_t *out_use_flags)
 {
-	return (fourcc_internal == DRM_FORMAT_YVU420_ANDROID) ? DRM_FORMAT_YVU420 : fourcc_internal;
-}
-
-uint32_t drv_resolve_format_helper(uint32_t format, uint64_t use_flags)
-{
+	*out_format = format;
+	*out_use_flags = use_flags;
 	switch (format) {
 	case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
 		/* Common camera implementation defined format. */
-		if (use_flags & (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE))
-			return DRM_FORMAT_NV12;
-		/* A common hack: See b/28671744 */
-		return DRM_FORMAT_XBGR8888;
+		if (use_flags & (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE)) {
+			*out_format = DRM_FORMAT_NV12;
+		} else {
+			/* HACK: See b/28671744 */
+			*out_format = DRM_FORMAT_XBGR8888;
+			*out_use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
+		}
+		break;
 	case DRM_FORMAT_FLEX_YCbCr_420_888:
 		/* Common flexible video format. */
-		return DRM_FORMAT_NV12;
+		*out_format = DRM_FORMAT_NV12;
+		break;
+	case DRM_FORMAT_YVU420_ANDROID:
+		*out_use_flags &= ~BO_USE_SCANOUT;
+		break;
 	default:
-		return format;
+		break;
 	}
 }
-
-uint64_t drv_resolve_use_flags_helper(struct driver *drv, uint32_t format, uint64_t use_flags)
-{
-	if (format == DRM_FORMAT_YVU420_ANDROID)
-		return use_flags & ~BO_USE_SCANOUT;
-
-	return use_flags;
-}
diff --git a/helpers.h b/drv_helpers.h
similarity index 84%
rename from helpers.h
rename to drv_helpers.h
index f40432b..edb69bf 100644
--- a/helpers.h
+++ b/drv_helpers.h
@@ -4,22 +4,20 @@
  * found in the LICENSE file.
  */
 
-#ifndef HELPERS_H
-#define HELPERS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#ifndef DRV_HELPERS_H
+#define DRV_HELPERS_H
 
 #include <stdbool.h>
 
 #include "drv.h"
-#include "helpers_array.h"
+#include "drv_array_helpers.h"
 
 #ifndef PAGE_SIZE
 #define PAGE_SIZE 0x1000
 #endif
 
+struct format_metadata;
+
 uint32_t drv_height_from_format(uint32_t format, uint32_t height, size_t plane);
 uint32_t drv_vertical_subsampling_from_format(uint32_t format, size_t plane);
 uint32_t drv_size_from_format(uint32_t format, uint32_t stride, uint32_t height, size_t plane);
@@ -46,12 +44,8 @@
 uint64_t drv_pick_modifier(const uint64_t *modifiers, uint32_t count,
 			   const uint64_t *modifier_order, uint32_t order_count);
 bool drv_has_modifier(const uint64_t *list, uint32_t count, uint64_t modifier);
-uint32_t drv_get_standard_fourcc(uint32_t fourcc_internal);
-uint32_t drv_resolve_format_helper(uint32_t format, uint64_t use_flags);
-uint64_t drv_resolve_use_flags_helper(struct driver *drv, uint32_t format, uint64_t use_flags);
-
-#ifdef __cplusplus
-}
-#endif
+void drv_resolve_format_and_use_flags_helper(struct driver *drv, uint32_t format,
+					     uint64_t use_flags, uint32_t *out_format,
+					     uint64_t *out_use_flags);
 
 #endif
diff --git a/drv_priv.h b/drv_priv.h
index 791fc56..63f7804 100644
--- a/drv_priv.h
+++ b/drv_priv.h
@@ -91,8 +91,9 @@
 	int (*bo_unmap)(struct bo *bo, struct vma *vma);
 	int (*bo_invalidate)(struct bo *bo, struct mapping *mapping);
 	int (*bo_flush)(struct bo *bo, struct mapping *mapping);
-	uint32_t (*resolve_format)(uint32_t format, uint64_t use_flags);
-	uint64_t (*resolve_use_flags)(struct driver *drv, uint32_t format, uint64_t use_flags);
+	void (*resolve_format_and_use_flags)(struct driver *drv, uint32_t format,
+					     uint64_t use_flags, uint32_t *out_format,
+					     uint64_t *out_use_flags);
 	size_t (*num_planes_from_modifier)(struct driver *drv, uint32_t format, uint64_t modifier);
 	int (*resource_info)(struct bo *bo, uint32_t strides[DRV_MAX_PLANES],
 			     uint32_t offsets[DRV_MAX_PLANES], uint64_t *format_modifier);
diff --git a/dumb_driver.c b/dumb_driver.c
index f5a62aa..baceca1 100644
--- a/dumb_driver.c
+++ b/dumb_driver.c
@@ -4,8 +4,8 @@
  * found in the LICENSE file.
  */
 
+#include "drv_helpers.h"
 #include "drv_priv.h"
-#include "helpers.h"
 #include "util.h"
 
 #define INIT_DUMB_DRIVER(driver)                                                                   \
@@ -17,6 +17,7 @@
 		.bo_import = drv_prime_bo_import,                                                  \
 		.bo_map = drv_dumb_bo_map,                                                         \
 		.bo_unmap = drv_bo_munmap,                                                         \
+		.resolve_format_and_use_flags = drv_resolve_format_and_use_flags_helper,           \
 	};
 
 static const uint32_t scanout_render_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888,
diff --git a/exynos.c b/exynos.c
deleted file mode 100644
index 5862643..0000000
--- a/exynos.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2014 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.
- */
-
-#ifdef DRV_EXYNOS
-
-// clang-format off
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <xf86drm.h>
-#include <exynos_drm.h>
-// clang-format on
-
-#include "drv_priv.h"
-#include "helpers.h"
-#include "util.h"
-
-static const uint32_t render_target_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888 };
-
-static const uint32_t texture_source_formats[] = { DRM_FORMAT_NV12 };
-
-static int exynos_init(struct driver *drv)
-{
-	drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
-			     &LINEAR_METADATA, BO_USE_RENDER_MASK);
-
-	drv_add_combinations(drv, texture_source_formats, ARRAY_SIZE(texture_source_formats),
-			     &LINEAR_METADATA, BO_USE_TEXTURE_MASK);
-
-	return drv_modify_linear_combinations(drv);
-}
-
-static int exynos_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
-			    uint64_t use_flags)
-{
-	size_t plane;
-
-	if (format == DRM_FORMAT_NV12) {
-		uint32_t chroma_height;
-		/* V4L2 s5p-mfc requires width to be 16 byte aligned and height 32. */
-		width = ALIGN(width, 16);
-		height = ALIGN(height, 32);
-		chroma_height = ALIGN(height / 2, 32);
-		bo->meta.strides[0] = bo->meta.strides[1] = width;
-		/* MFC v8+ requires 64 byte padding in the end of luma and chroma buffers. */
-		bo->meta.sizes[0] = bo->meta.strides[0] * height + 64;
-		bo->meta.sizes[1] = bo->meta.strides[1] * chroma_height + 64;
-		bo->meta.offsets[0] = bo->meta.offsets[1] = 0;
-		bo->meta.total_size = bo->meta.sizes[0] + bo->meta.sizes[1];
-	} else if (format == DRM_FORMAT_XRGB8888 || format == DRM_FORMAT_ARGB8888) {
-		bo->meta.strides[0] = drv_stride_from_format(format, width, 0);
-		bo->meta.total_size = bo->meta.sizes[0] = height * bo->meta.strides[0];
-		bo->meta.offsets[0] = 0;
-	} else {
-		drv_log("unsupported format %X\n", format);
-		assert(0);
-		return -EINVAL;
-	}
-
-	int ret;
-	for (plane = 0; plane < bo->meta.num_planes; plane++) {
-		size_t size = bo->meta.sizes[plane];
-		struct drm_exynos_gem_create gem_create = { 0 };
-
-		gem_create.size = size;
-		gem_create.flags = EXYNOS_BO_NONCONTIG;
-
-		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &gem_create);
-		if (ret) {
-			drv_log("DRM_IOCTL_EXYNOS_GEM_CREATE failed (size=%zu)\n", size);
-			ret = -errno;
-			goto cleanup_planes;
-		}
-
-		bo->handles[plane].u32 = gem_create.handle;
-	}
-
-	return 0;
-
-cleanup_planes:
-	for (; plane != 0; plane--) {
-		struct drm_gem_close gem_close = { 0 };
-
-		gem_close.handle = bo->handles[plane - 1].u32;
-		int gem_close_ret = drmIoctl(bo->drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
-		if (gem_close_ret) {
-			drv_log("DRM_IOCTL_GEM_CLOSE failed: %d\n", gem_close_ret);
-		}
-	}
-
-	return ret;
-}
-
-/*
- * Use dumb mapping with exynos even though a GEM buffer is created.
- * libdrm does the same thing in exynos_drm.c
- */
-const struct backend backend_exynos = {
-	.name = "exynos",
-	.init = exynos_init,
-	.bo_create = exynos_bo_create,
-	.bo_destroy = drv_gem_bo_destroy,
-	.bo_import = drv_prime_bo_import,
-	.bo_map = drv_dumb_bo_map,
-	.bo_unmap = drv_bo_munmap,
-};
-
-#endif
diff --git a/i915.c b/i915.c
index 0cd0a89..10a1ec2 100644
--- a/i915.c
+++ b/i915.c
@@ -15,9 +15,9 @@
 #include <unistd.h>
 #include <xf86drm.h>
 
+#include "drv_helpers.h"
 #include "drv_priv.h"
 #include "external/i915_drm.h"
-#include "helpers.h"
 #include "util.h"
 
 #define I915_CACHELINE_SIZE 64
@@ -684,8 +684,7 @@
 	.bo_unmap = drv_bo_munmap,
 	.bo_invalidate = i915_bo_invalidate,
 	.bo_flush = i915_bo_flush,
-	.resolve_format = drv_resolve_format_helper,
-	.resolve_use_flags = drv_resolve_use_flags_helper,
+	.resolve_format_and_use_flags = drv_resolve_format_and_use_flags_helper,
 };
 
 #endif
diff --git a/mediatek.c b/mediatek.c
index b25fa00..a95ed46 100644
--- a/mediatek.c
+++ b/mediatek.c
@@ -19,8 +19,8 @@
 #include <mediatek_drm.h>
 // clang-format on
 
+#include "drv_helpers.h"
 #include "drv_priv.h"
-#include "helpers.h"
 #include "util.h"
 
 #define TILE_TYPE_LINEAR 0
@@ -275,36 +275,55 @@
 	return 0;
 }
 
-static uint32_t mediatek_resolve_format(uint32_t format, uint64_t use_flags)
+static void mediatek_resolve_format_and_use_flags(struct driver *drv, uint32_t format,
+						  uint64_t use_flags, uint32_t *out_format,
+						  uint64_t *out_use_flags)
 {
+	*out_format = format;
+	*out_use_flags = use_flags;
 	switch (format) {
 	case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
 #ifdef MTK_MT8183
 		/* Only MT8183 Camera subsystem offers private reprocessing
 		 * capability. CAMERA_READ indicates the buffer is intended for
 		 * reprocessing and hence given the private format for MTK. */
-		if (use_flags & BO_USE_CAMERA_READ)
-			return DRM_FORMAT_MTISP_SXYZW10;
+		if (use_flags & BO_USE_CAMERA_READ) {
+			*out_format = DRM_FORMAT_MTISP_SXYZW10;
+			break;
+		}
 #endif
-		if (use_flags & BO_USE_CAMERA_WRITE)
-			return DRM_FORMAT_NV12;
+		if (use_flags & BO_USE_CAMERA_WRITE) {
+			*out_format = DRM_FORMAT_NV12;
+			break;
+		}
 
-		/*HACK: See b/28671744 */
-		return DRM_FORMAT_XBGR8888;
+		/* HACK: See b/28671744 */
+		*out_format = DRM_FORMAT_XBGR8888;
+		*out_use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
+		break;
 	case DRM_FORMAT_FLEX_YCbCr_420_888:
 #if defined(MTK_MT8183) || defined(MTK_MT8192) || defined(MTK_MT8195)
 		// TODO(hiroh): Switch to use NV12 for video decoder on MT8173 as well.
 		if (use_flags & (BO_USE_HW_VIDEO_DECODER)) {
-			return DRM_FORMAT_NV12;
+			*out_format = DRM_FORMAT_NV12;
+			break;
 		}
 #endif
 		if (use_flags &
 		    (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_ENCODER)) {
-			return DRM_FORMAT_NV12;
+			*out_format = DRM_FORMAT_NV12;
+			break;
 		}
-		return DRM_FORMAT_YVU420;
+
+		/* HACK: See b/139714614 */
+		*out_format = DRM_FORMAT_YVU420;
+		*out_use_flags &= ~BO_USE_SCANOUT;
+		break;
+	case DRM_FORMAT_YVU420_ANDROID:
+		*out_use_flags &= ~BO_USE_SCANOUT;
+		break;
 	default:
-		return format;
+		break;
 	}
 }
 
@@ -319,8 +338,7 @@
 	.bo_unmap = mediatek_bo_unmap,
 	.bo_invalidate = mediatek_bo_invalidate,
 	.bo_flush = mediatek_bo_flush,
-	.resolve_format = mediatek_resolve_format,
-	.resolve_use_flags = drv_resolve_use_flags_helper,
+	.resolve_format_and_use_flags = mediatek_resolve_format_and_use_flags,
 };
 
 #endif
diff --git a/msm.c b/msm.c
index 694fd58..a07c1c4 100644
--- a/msm.c
+++ b/msm.c
@@ -18,8 +18,8 @@
 #include <sys/mman.h>
 #include <xf86drm.h>
 
+#include "drv_helpers.h"
 #include "drv_priv.h"
-#include "helpers.h"
 #include "util.h"
 
 /* Alignment values are based on SDM845 Gfx IP */
@@ -260,12 +260,10 @@
 
 	/*
 	 * Android also frequently requests YV12 formats for some camera implementations
-	 * (including the external provider implmenetation). So mark it as well as valid
-	 * for camera display and encoding.
+	 * (including the external provider implmenetation).
 	 */
 	drv_modify_combination(drv, DRM_FORMAT_YVU420_ANDROID, &LINEAR_METADATA,
-			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_SCANOUT |
-				   BO_USE_HW_VIDEO_ENCODER);
+			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
 
 	/* Android CTS tests require this. */
 	drv_add_combination(drv, DRM_FORMAT_BGR888, &LINEAR_METADATA, BO_USE_SW_MASK);
@@ -386,6 +384,6 @@
 	.bo_import = drv_prime_bo_import,
 	.bo_map = msm_bo_map,
 	.bo_unmap = drv_bo_munmap,
-	.resolve_format = drv_resolve_format_helper,
+	.resolve_format_and_use_flags = drv_resolve_format_and_use_flags_helper,
 };
 #endif /* DRV_MSM */
diff --git a/rockchip.c b/rockchip.c
index 960023a..89063ee 100644
--- a/rockchip.c
+++ b/rockchip.c
@@ -14,8 +14,8 @@
 #include <sys/mman.h>
 #include <xf86drm.h>
 
+#include "drv_helpers.h"
 #include "drv_priv.h"
-#include "helpers.h"
 #include "util.h"
 
 struct rockchip_private_map_data {
@@ -271,8 +271,7 @@
 	.bo_unmap = rockchip_bo_unmap,
 	.bo_invalidate = rockchip_bo_invalidate,
 	.bo_flush = rockchip_bo_flush,
-	.resolve_format = drv_resolve_format_helper,
-	.resolve_use_flags = drv_resolve_use_flags_helper,
+	.resolve_format_and_use_flags = drv_resolve_format_and_use_flags_helper,
 };
 
 #endif
diff --git a/vc4.c b/vc4.c
index 5ea4bc3..820e4fe 100644
--- a/vc4.c
+++ b/vc4.c
@@ -13,8 +13,8 @@
 #include <vc4_drm.h>
 #include <xf86drm.h>
 
+#include "drv_helpers.h"
 #include "drv_priv.h"
-#include "helpers.h"
 #include "util.h"
 
 static const uint32_t render_target_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB565,
@@ -131,6 +131,7 @@
 	.bo_destroy = drv_gem_bo_destroy,
 	.bo_map = vc4_bo_map,
 	.bo_unmap = drv_bo_munmap,
+	.resolve_format_and_use_flags = drv_resolve_format_and_use_flags_helper,
 };
 
 #endif
diff --git a/virtgpu.c b/virtgpu.c
index 802749b..db50b46 100644
--- a/virtgpu.c
+++ b/virtgpu.c
@@ -13,7 +13,6 @@
 
 #include "drv_priv.h"
 #include "external/virtgpu_drm.h"
-#include "helpers.h"
 #include "util.h"
 #include "virtgpu.h"
 
diff --git a/virtgpu_cross_domain.c b/virtgpu_cross_domain.c
index c999a4f..85ea1a3 100644
--- a/virtgpu_cross_domain.c
+++ b/virtgpu_cross_domain.c
@@ -9,10 +9,10 @@
 #include <sys/mman.h>
 #include <xf86drm.h>
 
+#include "drv_helpers.h"
 #include "drv_priv.h"
 #include "external/virtgpu_cross_domain_protocol.h"
 #include "external/virtgpu_drm.h"
-#include "helpers.h"
 #include "util.h"
 #include "virtgpu.h"
 
@@ -252,7 +252,7 @@
 		return -ENOMEM;
 
 	ret = pthread_mutex_init(&priv->metadata_cache_lock, NULL);
-	if (!ret) {
+	if (ret) {
 		free(priv);
 		return ret;
 	}
@@ -422,6 +422,5 @@
 	.bo_destroy = drv_gem_bo_destroy,
 	.bo_map = cross_domain_bo_map,
 	.bo_unmap = drv_bo_munmap,
-	.resolve_format = drv_resolve_format_helper,
-	.resolve_use_flags = drv_resolve_use_flags_helper,
+	.resolve_format_and_use_flags = drv_resolve_format_and_use_flags_helper,
 };
diff --git a/virtgpu_virgl.c b/virtgpu_virgl.c
index 82a39d9..c159c21 100644
--- a/virtgpu_virgl.c
+++ b/virtgpu_virgl.c
@@ -12,11 +12,11 @@
 #include <sys/mman.h>
 #include <xf86drm.h>
 
+#include "drv_helpers.h"
 #include "drv_priv.h"
 #include "external/virgl_hw.h"
 #include "external/virgl_protocol.h"
 #include "external/virtgpu_drm.h"
-#include "helpers.h"
 #include "util.h"
 #include "virtgpu.h"
 
@@ -27,6 +27,16 @@
 #define MESA_LLVMPIPE_TILE_ORDER 6
 #define MESA_LLVMPIPE_TILE_SIZE (1 << MESA_LLVMPIPE_TILE_ORDER)
 
+// This comes from a combination of SwiftShader's VkPhysicalDeviceLimits::maxFramebufferWidth and
+// VkPhysicalDeviceLimits::maxImageDimension2D (see https://crrev.com/c/1917130).
+#define ANGLE_ON_SWIFTSHADER_MAX_TEXTURE_2D_SIZE 8192
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#define VIRGL_2D_MAX_TEXTURE_2D_SIZE                                                               \
+	MIN(ANGLE_ON_SWIFTSHADER_MAX_TEXTURE_2D_SIZE, MESA_LLVMPIPE_MAX_TEXTURE_2D_SIZE)
+
 static const uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888,
 						  DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888,
 						  DRM_FORMAT_XRGB8888 };
@@ -365,8 +375,8 @@
 		virgl_add_combination(drv, drm_formats[i], metadata, use_flags);
 }
 
-static int virtio_dumb_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
-				 uint64_t use_flags)
+static int virgl_2d_dumb_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
+				   uint64_t use_flags)
 {
 	if (bo->meta.format != DRM_FORMAT_R8) {
 		width = ALIGN(width, MESA_LLVMPIPE_TILE_SIZE);
@@ -754,7 +764,7 @@
 	if (params[param_3d].value)
 		return virgl_3d_bo_create(bo, width, height, format, use_flags);
 	else
-		return virtio_dumb_bo_create(bo, width, height, format, use_flags);
+		return virgl_2d_dumb_bo_create(bo, width, height, format, use_flags);
 }
 
 static int virgl_bo_destroy(struct bo *bo)
@@ -945,66 +955,95 @@
 	return 0;
 }
 
-static uint32_t virgl_resolve_format(uint32_t format, uint64_t use_flags)
+static void virgl_3d_resolve_format_and_use_flags(struct driver *drv, uint32_t format,
+						  uint64_t use_flags, uint32_t *out_format,
+						  uint64_t *out_use_flags)
 {
+	*out_format = format;
+	*out_use_flags = use_flags;
 	switch (format) {
 	case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
 		/* Camera subsystem requires NV12. */
-		if (use_flags & (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE))
-			return DRM_FORMAT_NV12;
-		/*HACK: See b/28671744 */
-		return DRM_FORMAT_XBGR8888;
+		if (use_flags & (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE)) {
+			*out_format = DRM_FORMAT_NV12;
+		} else {
+			/* HACK: See b/28671744 */
+			*out_format = DRM_FORMAT_XBGR8888;
+			*out_use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
+		}
+		break;
 	case DRM_FORMAT_FLEX_YCbCr_420_888:
-		/*
-		 * All of our host drivers prefer NV12 as their flexible media format.
-		 * If that changes, this will need to be modified.
-		 */
-		if (params[param_3d].value)
-			return DRM_FORMAT_NV12;
-		else
-			return DRM_FORMAT_YVU420_ANDROID;
+		/* All of our host drivers prefer NV12 as their flexible media format.
+		 * If that changes, this will need to be modified. */
+		*out_format = DRM_FORMAT_NV12;
+		/* fallthrough */
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_XRGB8888:
+		/* These are the scanout capable formats to the guest. Strip scanout use_flag if the
+		 * host does not natively support scanout on the requested format. */
+		if ((use_flags & BO_USE_SCANOUT) &&
+		    !virgl_supports_combination_natively(drv, format, BO_USE_SCANOUT))
+			*out_use_flags &= ~BO_USE_SCANOUT;
+		break;
+	case DRM_FORMAT_YVU420_ANDROID:
+		*out_use_flags &= ~BO_USE_SCANOUT;
+		/* HACK: See b/172389166. Also see gbm_bo_create. */
+		*out_use_flags |= BO_USE_LINEAR;
+		break;
 	default:
-		return format;
+		break;
 	}
 }
 
-static uint64_t virgl_resolve_use_flags(struct driver *drv, uint32_t format, uint64_t use_flags)
+static void virgl_2d_resolve_format_and_use_flags(uint32_t format, uint64_t use_flags,
+						  uint32_t *out_format, uint64_t *out_use_flags)
 {
-	if (format == DRM_FORMAT_YVU420_ANDROID) {
-		use_flags &= ~BO_USE_SCANOUT;
-		/*
-		 * HACK: See b/172389166. This is for HAL_PIXEL_FORMAT_YV12 buffers allocated by
-		 * arcvm. None of our platforms can display YV12, so we can treat as a SW buffer.
-		 * Remove once this can be intelligently resolved in the guest. Also see
-		 * gbm_bo_create.
-		 */
-		use_flags |= BO_USE_LINEAR;
-		return use_flags;
-	}
+	*out_format = format;
+	*out_use_flags = use_flags;
 
-	if (params[param_3d].value) {
-		switch (format) {
-		/* formats need to support scanout */
-		case DRM_FORMAT_ABGR8888:
-		case DRM_FORMAT_ARGB8888:
-		case DRM_FORMAT_RGB565:
-		case DRM_FORMAT_XBGR8888:
-		case DRM_FORMAT_XRGB8888:
-		case DRM_FORMAT_NV12:
-			/* strip scanout use_flag if necessary */
-			if ((use_flags & BO_USE_SCANOUT) &&
-			    !virgl_supports_combination_natively(drv, format, BO_USE_SCANOUT))
-				return use_flags & ~BO_USE_SCANOUT;
-			break;
-		default:
-			break;
+	/* HACK: See crrev/c/1849773 */
+	if (format != DRM_FORMAT_XRGB8888)
+		*out_use_flags &= ~BO_USE_SCANOUT;
+
+	switch (format) {
+	case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
+		/* Camera subsystem requires NV12. */
+		if (use_flags & (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE)) {
+			*out_format = DRM_FORMAT_NV12;
+		} else {
+			/* HACK: See b/28671744 */
+			*out_format = DRM_FORMAT_XBGR8888;
+			*out_use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
 		}
-	} else {
-		if (format != DRM_FORMAT_XRGB8888)
-			return use_flags & ~BO_USE_SCANOUT;
+		break;
+	case DRM_FORMAT_FLEX_YCbCr_420_888:
+		*out_format = DRM_FORMAT_YVU420_ANDROID;
+		/* fallthrough */
+	case DRM_FORMAT_YVU420_ANDROID:
+		*out_use_flags &= ~BO_USE_SCANOUT;
+		/* HACK: See b/172389166. Also see gbm_bo_create. */
+		*out_use_flags |= BO_USE_LINEAR;
+		break;
+	default:
+		break;
 	}
+}
 
-	return use_flags;
+static void virgl_resolve_format_and_use_flags(struct driver *drv, uint32_t format,
+					       uint64_t use_flags, uint32_t *out_format,
+					       uint64_t *out_use_flags)
+{
+	if (params[param_3d].value) {
+		return virgl_3d_resolve_format_and_use_flags(drv, format, use_flags, out_format,
+							     out_use_flags);
+	} else {
+		return virgl_2d_resolve_format_and_use_flags(format, use_flags, out_format,
+							     out_use_flags);
+	}
 }
 
 static int virgl_resource_info(struct bo *bo, uint32_t strides[DRV_MAX_PLANES],
@@ -1045,7 +1084,7 @@
 	if (params[param_3d].value)
 		return virgl_3d_get_max_texture_2d_size(drv);
 	else
-		return MESA_LLVMPIPE_MAX_TEXTURE_2D_SIZE;
+		return VIRGL_2D_MAX_TEXTURE_2D_SIZE;
 }
 
 const struct backend virtgpu_virgl = { .name = "virtgpu_virgl",
@@ -1058,7 +1097,7 @@
 				       .bo_unmap = drv_bo_munmap,
 				       .bo_invalidate = virgl_bo_invalidate,
 				       .bo_flush = virgl_bo_flush,
-				       .resolve_format = virgl_resolve_format,
-				       .resolve_use_flags = virgl_resolve_use_flags,
+				       .resolve_format_and_use_flags =
+					   virgl_resolve_format_and_use_flags,
 				       .resource_info = virgl_resource_info,
 				       .get_max_texture_2d_size = virgl_get_max_texture_2d_size };