Snap for 10453563 from 9b05077bc12b7b13ad680bfaec35ddd3cff5dd93 to mainline-adservices-release

Change-Id: I0886f55b4b1f759fb7c0f70fac9e959938c77c42
diff --git a/DIR_METADATA b/DIR_METADATA
new file mode 100644
index 0000000..55fd9f0
--- /dev/null
+++ b/DIR_METADATA
@@ -0,0 +1,34 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+buganizer {
+  # ChromeOS > Platform > Graphics > Graphics Virtualization
+  component_id: 964076
+}
+
+chromeos {
+  cq {
+    source_test_plans {
+      test_plan_starlark_files {
+        host: "chrome-internal.googlesource.com"
+        project: "chromeos/config-internal"
+        path: "test/plans/v2/ctpv1_compatible/legacy_default_tast_hw.star"
+      }
+      test_plan_starlark_files {
+        host: "chrome-internal.googlesource.com"
+        project: "chromeos/config-internal"
+        path: "test/plans/v2/ctpv1_compatible/legacy_default_autotest_hw.star"
+      }
+      test_plan_starlark_files {
+        host: "chrome-internal.googlesource.com"
+        project: "chromeos/config-internal"
+        path: "test/plans/v2/ctpv1_compatible/legacy_default_vm.star"
+      }
+    }
+  }
+}
diff --git a/Makefile b/Makefile
index 987708f..b45226d 100644
--- a/Makefile
+++ b/Makefile
@@ -59,3 +59,4 @@
 	ln -sf $(MINIGBM_FILENAME) $(DESTDIR)/$(LIBDIR)/libgbm.so.$(GBM_VERSION_MAJOR)
 	install -D -m 0644 $(SRC)/gbm.pc $(DESTDIR)$(LIBDIR)/pkgconfig/gbm.pc
 	install -D -m 0644 $(SRC)/gbm.h $(DESTDIR)/usr/include/gbm.h
+	install -D -m 0644 $(SRC)/minigbm_helpers.h $(DESTDIR)/usr/include/minigbm/minigbm_helpers.h
diff --git a/amdgpu.c b/amdgpu.c
index 7ff61a4..a3f5e45 100644
--- a/amdgpu.c
+++ b/amdgpu.c
@@ -10,6 +10,7 @@
 #include <drm_fourcc.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -278,7 +279,7 @@
 
 	ret = drmCommandWriteRead(fd, DRM_AMDGPU_CS, &cs, sizeof(cs));
 	if (ret) {
-		drv_log("SDMA copy command buffer submission failed %d\n", ret);
+		drv_loge("SDMA copy command buffer submission failed %d\n", ret);
 		goto unmap_dst;
 	}
 
@@ -289,9 +290,9 @@
 
 	ret = drmCommandWriteRead(fd, DRM_AMDGPU_WAIT_CS, &wait_cs, sizeof(wait_cs));
 	if (ret) {
-		drv_log("Could not wait for CS to finish\n");
+		drv_loge("Could not wait for CS to finish\n");
 	} else if (wait_cs.out.status) {
-		drv_log("Infinite wait timed out, likely GPU hang.\n");
+		drv_loge("Infinite wait timed out, likely GPU hang.\n");
 		ret = -ENODEV;
 	}
 
@@ -345,6 +346,18 @@
 	return true;
 }
 
+static void amdgpu_preload(bool load)
+{
+	static void *handle;
+
+	if (load && !handle)
+		handle = dri_dlopen(DRI_PATH);
+	else if (!load && handle) {
+		dri_dlclose(handle);
+		handle = NULL;
+	}
+}
+
 static int amdgpu_init(struct driver *drv)
 {
 	struct amdgpu_priv *priv;
@@ -380,7 +393,7 @@
 
 	/* Continue on failure, as we can still succesfully map things without SDMA. */
 	if (sdma_init(priv, drv_get_fd(drv)))
-		drv_log("SDMA init failed\n");
+		drv_loge("SDMA init failed\n");
 
 	metadata.tiling = TILE_TYPE_LINEAR;
 	metadata.priority = 1;
@@ -425,7 +438,8 @@
 	 */
 	drv_modify_combination(drv, DRM_FORMAT_R8, &metadata,
 			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
-				   BO_USE_HW_VIDEO_ENCODER);
+				   BO_USE_HW_VIDEO_ENCODER | BO_USE_GPU_DATA_BUFFER |
+				   BO_USE_SENSOR_DIRECT_DATA);
 
 	/*
 	 * The following formats will be allocated by the DRI backend and may be potentially tiled.
@@ -504,26 +518,44 @@
 				   uint64_t use_flags)
 {
 	int ret;
-	size_t num_planes;
+	uint32_t stride_align = 1;
 	uint32_t plane, stride;
 	union drm_amdgpu_gem_create gem_create = { { 0 } };
 	struct amdgpu_priv *priv = bo->drv->priv;
 
 	stride = drv_stride_from_format(format, width, 0);
-	num_planes = drv_num_planes_from_format(format);
 
-	/*
-	 * For multiplane formats, align the stride to 512 to ensure that subsample strides are 256
-	 * aligned. This uses more memory than necessary since the first plane only needs to be
-	 * 256 aligned, but it's acceptable for a short-term fix. It's probably safe for other gpu
-	 * families, but let's restrict it to Raven and Stoney for now (b/171013552, b/190484589).
-	 * This only applies to the Android YUV (multiplane) format.
-	 * */
-	if (format == DRM_FORMAT_YVU420_ANDROID &&
-	    (priv->dev_info.family == AMDGPU_FAMILY_RV || priv->dev_info.family == AMDGPU_FAMILY_CZ))
-		stride = ALIGN(stride, 512);
-	else
-		stride = ALIGN(stride, 256);
+	if (use_flags & BO_USE_HW_MASK) {
+		/* GFX9+ requires the stride to be aligned to 256 bytes */
+		stride_align = 256;
+		stride = ALIGN(stride, stride_align);
+
+		/* Android YV12 requires the UV stride to be half of the Y
+		 * stride.  Before GFX10, we can double the alignment for the
+		 * Y stride, which makes sure the UV stride is still aligned
+		 * to 256 bytes after halving.
+		 *
+		 * GFX10+ additionally requires the stride to be as small as
+		 * possible.  It is impossible to support the format in some
+		 * cases.  Instead, we force DRM_FORMAT_YVU420 and knowingly
+		 * vioate Android YV12 stride requirement.  This is done
+		 * because
+		 *
+		 *  - we would like to know what breaks, and
+		 *  - when used as a classic resource by virglrenderer, the
+		 *    requirement hopefully does not matter
+		 */
+		bool double_align = format == DRM_FORMAT_YVU420_ANDROID;
+		if (double_align && priv->dev_info.family >= AMDGPU_FAMILY_NV &&
+		    (use_flags & BO_USE_GPU_HW) && ((stride / stride_align) & 1)) {
+			drv_loge("allocating %dx%d YV12 bo (usage 0x%" PRIx64 ") with bad strides",
+				 width, height, use_flags);
+			format = DRM_FORMAT_YVU420;
+			double_align = false;
+		}
+		if (double_align)
+			stride = ALIGN(stride, stride_align * 2);
+	}
 
 	/*
 	 * Currently, allocator used by chrome aligns the height for Encoder/
@@ -535,7 +567,7 @@
 	if (use_flags & (BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER))
 		height = ALIGN(height, CHROME_HEIGHT_ALIGN);
 
-	drv_bo_from_format(bo, stride, height, format);
+	drv_bo_from_format(bo, stride, stride_align, height, format);
 
 	gem_create.in.bo_size =
 	    ALIGN(bo->meta.total_size, priv->dev_info.virtual_address_alignment);
@@ -625,8 +657,8 @@
 		dri_tiling = combo->metadata.tiling != TILE_TYPE_LINEAR;
 	}
 
-	bo->meta.num_planes = dri_num_planes_from_modifier(bo->drv, data->format,
-		data->format_modifier);
+	bo->meta.num_planes =
+	    dri_num_planes_from_modifier(bo->drv, data->format, data->format_modifier);
 
 	if (dri_tiling)
 		return dri_bo_import(bo, data);
@@ -650,19 +682,19 @@
 		return drv_gem_bo_destroy(bo);
 }
 
-static void *amdgpu_map_bo(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+static void *amdgpu_map_bo(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	void *addr = MAP_FAILED;
 	int ret;
 	union drm_amdgpu_gem_mmap gem_map = { { 0 } };
 	struct drm_amdgpu_gem_create_in bo_info = { 0 };
 	struct drm_amdgpu_gem_op gem_op = { 0 };
-	uint32_t handle = bo->handles[plane].u32;
+	uint32_t handle = bo->handles[0].u32;
 	struct amdgpu_linear_vma_priv *priv = NULL;
 	struct amdgpu_priv *drv_priv;
 
 	if (bo->priv)
-		return dri_bo_map(bo, vma, plane, map_flags);
+		return dri_bo_map(bo, vma, 0, map_flags);
 
 	drv_priv = bo->drv->priv;
 	gem_op.handle = handle;
@@ -691,7 +723,7 @@
 		ret = drmCommandWriteRead(bo->drv->fd, DRM_AMDGPU_GEM_CREATE, &gem_create,
 					  sizeof(gem_create));
 		if (ret < 0) {
-			drv_log("GEM create failed\n");
+			drv_loge("GEM create failed\n");
 			free(priv);
 			return MAP_FAILED;
 		}
@@ -702,7 +734,7 @@
 		ret = sdma_copy(bo->drv->priv, bo->drv->fd, bo->handles[0].u32, priv->handle,
 				bo_info.bo_size);
 		if (ret) {
-			drv_log("SDMA copy for read failed\n");
+			drv_loge("SDMA copy for read failed\n");
 			goto fail;
 		}
 	}
@@ -710,7 +742,7 @@
 	gem_map.in.handle = handle;
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_AMDGPU_GEM_MMAP, &gem_map);
 	if (ret) {
-		drv_log("DRM_IOCTL_AMDGPU_GEM_MMAP failed\n");
+		drv_loge("DRM_IOCTL_AMDGPU_GEM_MMAP failed\n");
 		goto fail;
 	}
 
@@ -775,18 +807,19 @@
 				  sizeof(wait_idle));
 
 	if (ret < 0) {
-		drv_log("DRM_AMDGPU_GEM_WAIT_IDLE failed with %d\n", ret);
+		drv_loge("DRM_AMDGPU_GEM_WAIT_IDLE failed with %d\n", ret);
 		return ret;
 	}
 
 	if (ret == 0 && wait_idle.out.status)
-		drv_log("DRM_AMDGPU_GEM_WAIT_IDLE BO is busy\n");
+		drv_loge("DRM_AMDGPU_GEM_WAIT_IDLE BO is busy\n");
 
 	return 0;
 }
 
 const struct backend backend_amdgpu = {
 	.name = "amdgpu",
+	.preload = amdgpu_preload,
 	.init = amdgpu_init,
 	.close = amdgpu_close,
 	.bo_create = amdgpu_create_bo,
diff --git a/cros_gralloc/Makefile b/cros_gralloc/Makefile
index c95ad2c..b0d62d7 100644
--- a/cros_gralloc/Makefile
+++ b/cros_gralloc/Makefile
@@ -9,7 +9,7 @@
 
 SRCS   += $(wildcard gralloc0/*.cc)
 
-SOURCES = $(filter-out ../gbm%, $(SRCS))
+SOURCES = $(filter-out ../gbm% ../minigbm%, $(SRCS))
 PKG_CONFIG ?= pkg-config
 
 VPATH = $(dir $(SOURCES))
diff --git a/cros_gralloc/aidl/Allocator.cpp b/cros_gralloc/aidl/Allocator.cpp
index 0d81d5c..2ea5a0d 100644
--- a/cros_gralloc/aidl/Allocator.cpp
+++ b/cros_gralloc/aidl/Allocator.cpp
@@ -16,7 +16,7 @@
 #include "cros_gralloc/gralloc4/CrosGralloc4Utils.h"
 
 using aidl::android::hardware::common::NativeHandle;
-using BufferDescriptorInfo =
+using BufferDescriptorInfoV4 =
         android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo;
 
 namespace aidl::android::hardware::graphics::allocator::impl {
@@ -78,7 +78,7 @@
         return ToBinderStatus(AllocationError::NO_RESOURCES);
     }
 
-    BufferDescriptorInfo description;
+    BufferDescriptorInfoV4 description;
 
     int ret = ::android::gralloc4::decodeBufferDescriptorInfo(descriptor, &description);
     if (ret) {
@@ -109,7 +109,7 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Allocator::allocate(const BufferDescriptorInfo& descriptor, int32_t* outStride,
+ndk::ScopedAStatus Allocator::allocate(const BufferDescriptorInfoV4& descriptor, int32_t* outStride,
                                        native_handle_t** outHandle) {
     if (!mDriver) {
         ALOGE("Failed to allocate. Driver is uninitialized.\n");
@@ -154,6 +154,85 @@
     return ndk::ScopedAStatus::ok();
 }
 
+static BufferDescriptorInfoV4 convertAidlToIMapperV4Descriptor(const BufferDescriptorInfo& info) {
+    return BufferDescriptorInfoV4 {
+        .name{reinterpret_cast<const char*>(info.name.data())},
+        .width = static_cast<uint32_t>(info.width),
+        .height = static_cast<uint32_t>(info.height),
+        .layerCount = static_cast<uint32_t>(info.layerCount),
+        .format = static_cast<::android::hardware::graphics::common::V1_2::PixelFormat>(info.format),
+        .usage = static_cast<uint64_t>(info.usage),
+        .reservedSize = 0,
+    };
+}
+
+ndk::ScopedAStatus Allocator::allocate2(const BufferDescriptorInfo& descriptor, int32_t count,
+                            allocator::AllocationResult* outResult) {
+    if (!mDriver) {
+        ALOGE("Failed to allocate. Driver is uninitialized.\n");
+        return ToBinderStatus(AllocationError::NO_RESOURCES);
+    }
+
+    if (!descriptor.additionalOptions.empty()) {
+        return ToBinderStatus(AllocationError::UNSUPPORTED);
+    }
+
+    BufferDescriptorInfoV4 descriptionV4 = convertAidlToIMapperV4Descriptor(descriptor);
+
+    std::vector<native_handle_t*> handles;
+    handles.resize(count, nullptr);
+
+    for (int32_t i = 0; i < count; i++) {
+        ndk::ScopedAStatus status = allocate(descriptionV4, &outResult->stride, &handles[i]);
+        if (!status.isOk()) {
+            for (int32_t j = 0; j < i; j++) {
+                releaseBufferAndHandle(handles[j]);
+            }
+            return status;
+        }
+    }
+
+    outResult->buffers.resize(count);
+    for (int32_t i = 0; i < count; i++) {
+        auto handle = handles[i];
+        outResult->buffers[i] = ::android::dupToAidl(handle);
+        releaseBufferAndHandle(handle);
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Allocator::isSupported(const BufferDescriptorInfo& descriptor,
+                            bool* outResult) {
+    if (!mDriver) {
+        ALOGE("Failed to allocate. Driver is uninitialized.\n");
+        return ToBinderStatus(AllocationError::NO_RESOURCES);
+    }
+
+    if (!descriptor.additionalOptions.empty()) {
+        *outResult = false;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    struct cros_gralloc_buffer_descriptor crosDescriptor;
+    if (convertToCrosDescriptor(convertAidlToIMapperV4Descriptor(descriptor), &crosDescriptor)) {
+        // Failing to convert the descriptor means the layer count, pixel format, or usage is
+        // unsupported, thus isSupported() = false
+        *outResult = false;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    crosDescriptor.reserved_region_size += sizeof(CrosGralloc4Metadata);
+
+    *outResult = mDriver->is_supported(&crosDescriptor);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Allocator::getIMapperLibrarySuffix(std::string* outResult) {
+    *outResult = "minigbm";
+    return ndk::ScopedAStatus::ok();
+}
+
 ::ndk::SpAIBinder Allocator::createBinder() {
     auto binder = BnAllocator::createBinder();
     AIBinder_setInheritRt(binder.get(), true);
diff --git a/cros_gralloc/aidl/Allocator.h b/cros_gralloc/aidl/Allocator.h
index 801c852..5c12308 100644
--- a/cros_gralloc/aidl/Allocator.h
+++ b/cros_gralloc/aidl/Allocator.h
@@ -26,6 +26,14 @@
     ndk::ScopedAStatus allocate(const std::vector<uint8_t>& descriptor, int32_t count,
                                 allocator::AllocationResult* outResult) override;
 
+    ndk::ScopedAStatus allocate2(const BufferDescriptorInfo& descriptor, int32_t count,
+                                allocator::AllocationResult* outResult) override;
+
+    ndk::ScopedAStatus isSupported(const BufferDescriptorInfo& descriptor,
+                                bool* outResult) override;
+
+    ndk::ScopedAStatus getIMapperLibrarySuffix(std::string* outResult) override;
+
   protected:
     ndk::SpAIBinder createBinder() override;
 
diff --git a/cros_gralloc/aidl/Android.bp b/cros_gralloc/aidl/Android.bp
index 71e2ae7..da8f670 100644
--- a/cros_gralloc/aidl/Android.bp
+++ b/cros_gralloc/aidl/Android.bp
@@ -24,14 +24,14 @@
 }
 
 cc_binary {
-    name: "android.hardware.graphics.allocator-V1-service.minigbm",
+    name: "android.hardware.graphics.allocator-service.minigbm",
     defaults: ["minigbm_cros_gralloc_defaults"],
     relative_install_path: "hw",
-    init_rc: [":allocator_rc"],
-    vintf_fragments: [":allocator_xml"],
+    init_rc: ["allocator.rc"],
+    vintf_fragments: ["allocator.xml"],
     vendor: true,
     shared_libs: [
-        "android.hardware.graphics.allocator-V1-ndk",
+        "android.hardware.graphics.allocator-V2-ndk",
         "android.hardware.graphics.mapper@4.0",
         "libbase",
         "libbinder_ndk",
@@ -49,13 +49,3 @@
         "Main.cpp",
     ],
 }
-
-filegroup {
-    name: "allocator_rc",
-    srcs: ["allocator.rc"],
-}
-
-filegroup {
-    name: "allocator_xml",
-    srcs: ["allocator.xml"],
-}
\ No newline at end of file
diff --git a/cros_gralloc/aidl/allocator.rc b/cros_gralloc/aidl/allocator.rc
index 5859384..24a7c45 100644
--- a/cros_gralloc/aidl/allocator.rc
+++ b/cros_gralloc/aidl/allocator.rc
@@ -1,4 +1,4 @@
-service vendor.graphics.allocator /vendor/bin/hw/android.hardware.graphics.allocator-V1-service.minigbm
+service vendor.graphics.allocator /vendor/bin/hw/android.hardware.graphics.allocator-service.minigbm
     class hal animation
     user system
     group graphics drmrpc
diff --git a/cros_gralloc/aidl/allocator.xml b/cros_gralloc/aidl/allocator.xml
index 74fd4cd..4d375b3 100644
--- a/cros_gralloc/aidl/allocator.xml
+++ b/cros_gralloc/aidl/allocator.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.graphics.allocator</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IAllocator</name>
             <instance>default</instance>
diff --git a/cros_gralloc/cros_gralloc_buffer.cc b/cros_gralloc/cros_gralloc_buffer.cc
index e1af7a4..0cac133 100644
--- a/cros_gralloc/cros_gralloc_buffer.cc
+++ b/cros_gralloc/cros_gralloc_buffer.cc
@@ -19,14 +19,14 @@
 	auto acquire_hnd =
 	    reinterpret_cast<struct cros_gralloc_handle *>(native_handle_clone(borrowed_handle));
 	if (!acquire_hnd) {
-		drv_log("Failed to create cros_gralloc_buffer: failed to clone handle.\n");
+		ALOGE("Failed to create cros_gralloc_buffer: failed to clone handle.");
 		return {};
 	}
 
 	std::unique_ptr<cros_gralloc_buffer> buffer(
 	    new cros_gralloc_buffer(acquire_bo, acquire_hnd));
 	if (!buffer) {
-		drv_log("Failed to create cros_gralloc_buffer: failed to allocate.\n");
+		ALOGE("Failed to create cros_gralloc_buffer: failed to allocate.");
 		native_handle_close(acquire_hnd);
 		native_handle_delete(acquire_hnd);
 		return {};
@@ -65,6 +65,11 @@
 	return hnd_->width;
 }
 
+uint32_t cros_gralloc_buffer::get_pixel_stride() const
+{
+	return hnd_->pixel_stride;
+}
+
 uint32_t cros_gralloc_buffer::get_height() const
 {
 	return hnd_->height;
@@ -138,7 +143,7 @@
 	 * just use the first kernel buffer.
 	 */
 	if (drv_num_buffers_per_bo(bo_) != 1) {
-		drv_log("Can only support one buffer per bo.\n");
+		ALOGE("Can only support one buffer per bo.");
 		return -EINVAL;
 	}
 
@@ -162,7 +167,7 @@
 		}
 
 		if (vaddr == MAP_FAILED) {
-			drv_log("Mapping failed.\n");
+			ALOGE("Mapping failed.");
 			return -EFAULT;
 		}
 	}
@@ -177,7 +182,7 @@
 int32_t cros_gralloc_buffer::unlock()
 {
 	if (lockcount_ <= 0) {
-		drv_log("Buffer was not locked.\n");
+		ALOGE("Buffer was not locked.");
 		return -EINVAL;
 	}
 
@@ -201,7 +206,7 @@
 int32_t cros_gralloc_buffer::invalidate()
 {
 	if (lockcount_ <= 0) {
-		drv_log("Buffer was not locked.\n");
+		ALOGE("Buffer was not locked.");
 		return -EINVAL;
 	}
 
@@ -214,7 +219,7 @@
 int32_t cros_gralloc_buffer::flush()
 {
 	if (lockcount_ <= 0) {
-		drv_log("Buffer was not locked.\n");
+		ALOGE("Buffer was not locked.");
 		return -EINVAL;
 	}
 
@@ -228,7 +233,7 @@
 {
 	int32_t reserved_region_fd = hnd_->fds[hnd_->num_planes];
 	if (reserved_region_fd < 0) {
-		drv_log("Buffer does not have reserved region.\n");
+		ALOGE("Buffer does not have reserved region.");
 		return -EINVAL;
 	}
 
@@ -237,7 +242,7 @@
 		    mmap(nullptr, hnd_->reserved_region_size, PROT_WRITE | PROT_READ, MAP_SHARED,
 			 reserved_region_fd, 0);
 		if (reserved_region_addr_ == MAP_FAILED) {
-			drv_log("Failed to mmap reserved region: %s.\n", strerror(errno));
+			ALOGE("Failed to mmap reserved region: %s.", strerror(errno));
 			return -errno;
 		}
 	}
diff --git a/cros_gralloc/cros_gralloc_buffer.h b/cros_gralloc/cros_gralloc_buffer.h
index 21f8306..71947d9 100644
--- a/cros_gralloc/cros_gralloc_buffer.h
+++ b/cros_gralloc/cros_gralloc_buffer.h
@@ -21,6 +21,7 @@
 
 	uint32_t get_id() const;
 	uint32_t get_width() const;
+	uint32_t get_pixel_stride() const;
 	uint32_t get_height() const;
 	uint32_t get_format() const;
 	uint64_t get_format_modifier() const;
diff --git a/cros_gralloc/cros_gralloc_driver.cc b/cros_gralloc/cros_gralloc_driver.cc
index 46de30d..a714798 100644
--- a/cros_gralloc/cros_gralloc_driver.cc
+++ b/cros_gralloc/cros_gralloc_driver.cc
@@ -7,6 +7,7 @@
 #include "cros_gralloc_driver.h"
 
 #include <cstdlib>
+#include <cutils/properties.h>
 #include <fcntl.h>
 #include <hardware/gralloc.h>
 #include <sys/mman.h>
@@ -25,6 +26,22 @@
 // DRM Card nodes start at 0
 #define DRM_CARD_NODE_START 0
 
+class cros_gralloc_driver_preloader
+{
+      public:
+	cros_gralloc_driver_preloader()
+	{
+		drv_preload(true);
+	}
+
+	~cros_gralloc_driver_preloader()
+	{
+		drv_preload(false);
+	}
+};
+
+static class cros_gralloc_driver_preloader cros_gralloc_driver_preloader;
+
 int memfd_create_wrapper(const char *name, unsigned int flags)
 {
 	int fd;
@@ -34,12 +51,12 @@
 #elif defined(__NR_memfd_create)
 	fd = syscall(__NR_memfd_create, name, flags);
 #else
-	drv_log("Failed to create memfd '%s': memfd_create not available.", name);
+	ALOGE("Failed to create memfd '%s': memfd_create not available.", name);
 	return -1;
 #endif
 
 	if (fd == -1)
-		drv_log("Failed to create memfd '%s': %s.\n", name, strerror(errno));
+		ALOGE("Failed to create memfd '%s': %s.", name, strerror(errno));
 
 	return fd;
 }
@@ -53,7 +70,7 @@
 		return -errno;
 
 	if (ftruncate(reserved_region_fd, reserved_region_size)) {
-		drv_log("Failed to set reserved region size: %s.\n", strerror(errno));
+		ALOGE("Failed to set reserved region size: %s.", strerror(errno));
 		return -errno;
 	}
 
@@ -65,7 +82,7 @@
 	static cros_gralloc_driver s_instance;
 
 	if (!s_instance.is_initialized()) {
-		drv_log("Failed to initialize driver.\n");
+		ALOGE("Failed to initialize driver.");
 		return nullptr;
 	}
 
@@ -138,6 +155,9 @@
 
 cros_gralloc_driver::cros_gralloc_driver() : drv_(init_try_nodes(), drv_destroy_and_close)
 {
+	char buf[PROP_VALUE_MAX];
+	property_get("ro.product.device", buf, "unknown");
+	mt8183_camera_quirk_ = !strncmp(buf, "kukui", strlen("kukui"));
 }
 
 cros_gralloc_driver::~cros_gralloc_driver()
@@ -159,6 +179,14 @@
 	uint64_t resolved_use_flags;
 	struct combination *combo;
 
+	if (mt8183_camera_quirk_ && (descriptor->use_flags & BO_USE_CAMERA_READ) &&
+	    !(descriptor->use_flags & BO_USE_SCANOUT) &&
+	    descriptor->drm_format == DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED) {
+		*out_use_flags = descriptor->use_flags;
+		*out_format = DRM_FORMAT_MTISP_SXYZW10;
+		return true;
+	}
+
 	drv_resolve_format_and_use_flags(drv_.get(), descriptor->drm_format, descriptor->use_flags,
 					 &resolved_format, &resolved_use_flags);
 
@@ -172,7 +200,7 @@
 		resolved_use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
 		combo = drv_get_combination(drv_.get(), resolved_format, resolved_use_flags);
 	}
-	if (!combo && (descriptor->droid_usage & BUFFER_USAGE_FRONT_RENDERING)) {
+	if (!combo && (descriptor->droid_usage & BUFFER_USAGE_FRONT_RENDERING_MASK)) {
 		resolved_use_flags &= ~BO_USE_FRONT_RENDERING;
 		resolved_use_flags |= BO_USE_LINEAR;
 		combo = drv_get_combination(drv_.get(), resolved_format, resolved_use_flags);
@@ -215,7 +243,7 @@
 	if (ret >= 0)
 		return ret;
 
-	drv_log("Failed to create_reserved_region.\n");
+	ALOGE("Failed to create_reserved_region.");
 	return -1;
 }
 
@@ -234,14 +262,14 @@
 	std::unique_ptr<cros_gralloc_buffer> buffer;
 
 	if (!get_resolved_format_and_use_flags(descriptor, &resolved_format, &resolved_use_flags)) {
-		drv_log("Failed to resolve format and use_flags.\n");
+		ALOGE("Failed to resolve format and use_flags.");
 		return -EINVAL;
 	}
 
 	bo = drv_bo_create(drv_.get(), descriptor->width, descriptor->height, resolved_format,
 			   resolved_use_flags);
 	if (!bo) {
-		drv_log("Failed to create bo.\n");
+		ALOGE("Failed to create bo.");
 		return -errno;
 	}
 
@@ -251,7 +279,7 @@
 	 * send more than one fd. GL/Vulkan drivers may also have to modified.
 	 */
 	if (drv_num_buffers_per_bo(bo) != 1) {
-		drv_log("Can only support one buffer per bo.\n");
+		ALOGE("Can only support one buffer per bo.");
 		goto destroy_bo;
 	}
 
@@ -308,7 +336,7 @@
 
 	buffer = cros_gralloc_buffer::create(bo, hnd);
 	if (!buffer) {
-		drv_log("Failed to allocate: failed to create cros_gralloc_buffer.\n");
+		ALOGE("Failed to allocate: failed to create cros_gralloc_buffer.");
 		ret = -1;
 		goto destroy_hnd;
 	}
@@ -342,7 +370,7 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
@@ -393,7 +421,7 @@
 
 		auto scoped_buffer = cros_gralloc_buffer::create(bo, hnd);
 		if (!scoped_buffer) {
-			drv_log("Failed to import: failed to create cros_gralloc_buffer.\n");
+			ALOGE("Failed to import: failed to create cros_gralloc_buffer.");
 			return -1;
 		}
 		buffer = scoped_buffer.get();
@@ -414,13 +442,13 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	auto buffer = get_buffer(hnd);
 	if (!buffer) {
-		drv_log("Invalid reference (release() called on unregistered handle).\n");
+		ALOGE("Invalid reference (release() called on unregistered handle).");
 		return -EINVAL;
 	}
 
@@ -446,13 +474,13 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	auto buffer = get_buffer(hnd);
 	if (!buffer) {
-		drv_log("Invalid reference (lock() called on unregistered handle).\n");
+		ALOGE("Invalid reference (lock() called on unregistered handle).");
 		return -EINVAL;
 	}
 
@@ -465,13 +493,13 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	auto buffer = get_buffer(hnd);
 	if (!buffer) {
-		drv_log("Invalid reference (unlock() called on unregistered handle).\n");
+		ALOGE("Invalid reference (unlock() called on unregistered handle).");
 		return -EINVAL;
 	}
 
@@ -491,42 +519,35 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	auto buffer = get_buffer(hnd);
 	if (!buffer) {
-		drv_log("Invalid reference (invalidate() called on unregistered handle).\n");
+		ALOGE("Invalid reference (invalidate() called on unregistered handle).");
 		return -EINVAL;
 	}
 
 	return buffer->invalidate();
 }
 
-int32_t cros_gralloc_driver::flush(buffer_handle_t handle, int32_t *release_fence)
+int32_t cros_gralloc_driver::flush(buffer_handle_t handle)
 {
 	std::lock_guard<std::mutex> lock(mutex_);
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	auto buffer = get_buffer(hnd);
 	if (!buffer) {
-		drv_log("Invalid reference (flush() called on unregistered handle).\n");
+		ALOGE("Invalid reference (flush() called on unregistered handle).");
 		return -EINVAL;
 	}
 
-	/*
-	 * From the ANativeWindow::dequeueBuffer documentation:
-	 *
-	 * "A value of -1 indicates that the caller may access the buffer immediately without
-	 * waiting on a fence."
-	 */
-	*release_fence = -1;
 	return buffer->flush();
 }
 
@@ -536,13 +557,13 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	auto buffer = get_buffer(hnd);
 	if (!buffer) {
-		drv_log("Invalid reference (get_backing_store() called on unregistered handle).\n");
+		ALOGE("Invalid reference (get_backing_store() called on unregistered handle).");
 		return -EINVAL;
 	}
 
@@ -558,13 +579,13 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	auto buffer = get_buffer(hnd);
 	if (!buffer) {
-		drv_log("Invalid reference (resource_info() called on unregistered handle).\n");
+		ALOGE("Invalid reference (resource_info() called on unregistered handle).");
 		return -EINVAL;
 	}
 
@@ -579,14 +600,13 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	auto buffer = get_buffer(hnd);
 	if (!buffer) {
-		drv_log(
-		    "Invalid reference (get_reserved_region() called on unregistered handle).\n");
+		ALOGE("Invalid reference (get_reserved_region() called on unregistered handle).");
 		return -EINVAL;
 	}
 
@@ -620,7 +640,7 @@
 
 	auto buffer = get_buffer(hnd);
 	if (!buffer) {
-		drv_log("Invalid reference (with_buffer() called on unregistered handle).\n");
+		ALOGE("Invalid reference (with_buffer() called on unregistered handle).");
 		return;
 	}
 
diff --git a/cros_gralloc/cros_gralloc_driver.h b/cros_gralloc/cros_gralloc_driver.h
index 5678b76..f35757c 100644
--- a/cros_gralloc/cros_gralloc_driver.h
+++ b/cros_gralloc/cros_gralloc_driver.h
@@ -36,7 +36,7 @@
 	int32_t unlock(buffer_handle_t handle, int32_t *release_fence);
 
 	int32_t invalidate(buffer_handle_t handle);
-	int32_t flush(buffer_handle_t handle, int32_t *release_fence);
+	int32_t flush(buffer_handle_t handle);
 
 	int32_t get_backing_store(buffer_handle_t handle, uint64_t *out_store);
 	int32_t resource_info(buffer_handle_t handle, uint32_t strides[DRV_MAX_PLANES],
@@ -83,6 +83,7 @@
 	std::mutex mutex_;
 	std::unordered_map<uint32_t, std::unique_ptr<cros_gralloc_buffer>> buffers_;
 	std::unordered_map<cros_gralloc_handle_t, cros_gralloc_imported_handle_info> handles_;
+	bool mt8183_camera_quirk_ = false;
 };
 
 #endif
diff --git a/cros_gralloc/cros_gralloc_helpers.cc b/cros_gralloc/cros_gralloc_helpers.cc
index 3301522..8c86c66 100644
--- a/cros_gralloc/cros_gralloc_helpers.cc
+++ b/cros_gralloc/cros_gralloc_helpers.cc
@@ -12,9 +12,15 @@
 /* Define to match AIDL BufferUsage::VIDEO_DECODER. */
 #define BUFFER_USAGE_VIDEO_DECODER (1 << 22)
 
+/* Define to match AIDL BufferUsage::SENSOR_DIRECT_DATA. */
+#define BUFFER_USAGE_SENSOR_DIRECT_DATA (1 << 23)
+
 /* Define to match AIDL BufferUsage::GPU_DATA_BUFFER. */
 #define BUFFER_USAGE_GPU_DATA_BUFFER (1 << 24)
 
+/* Define to match AIDL PixelFormat::R_8. */
+#define HAL_PIXEL_FORMAT_R8 0x38
+
 uint32_t cros_gralloc_convert_format(int format)
 {
 	/*
@@ -50,6 +56,7 @@
 	 * equal to their size in bytes.
 	 */
 	case HAL_PIXEL_FORMAT_BLOB:
+	case HAL_PIXEL_FORMAT_R8:
 		return DRM_FORMAT_R8;
 	case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
 		return DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED;
@@ -119,11 +126,13 @@
 	handle_usage(&usage, GRALLOC_USAGE_HW_CAMERA_READ, &use_flags, BO_USE_CAMERA_READ);
 	handle_usage(&usage, GRALLOC_USAGE_RENDERSCRIPT, &use_flags, BO_USE_RENDERSCRIPT);
 	handle_usage(&usage, BUFFER_USAGE_VIDEO_DECODER, &use_flags, BO_USE_HW_VIDEO_DECODER);
+	handle_usage(&usage, BUFFER_USAGE_SENSOR_DIRECT_DATA, &use_flags,
+		     BO_USE_SENSOR_DIRECT_DATA);
 	handle_usage(&usage, BUFFER_USAGE_GPU_DATA_BUFFER, &use_flags, BO_USE_GPU_DATA_BUFFER);
-	handle_usage(&usage, BUFFER_USAGE_FRONT_RENDERING, &use_flags, BO_USE_FRONT_RENDERING);
+	handle_usage(&usage, BUFFER_USAGE_FRONT_RENDERING_MASK, &use_flags, BO_USE_FRONT_RENDERING);
 
 	if (usage) {
-		drv_log("Unhandled gralloc usage: %llx\n", (unsigned long long)usage);
+		ALOGE("Unhandled gralloc usage: %llx", (unsigned long long)usage);
 		return BO_USE_NONE;
 	}
 
@@ -162,10 +171,10 @@
 	 */
 	int err = sync_wait(fence, 1000);
 	if (err < 0) {
-		drv_log("Timed out on sync wait, err = %s\n", strerror(errno));
+		ALOGE("Timed out on sync wait, err = %s", strerror(errno));
 		err = sync_wait(fence, -1);
 		if (err < 0) {
-			drv_log("sync wait error = %s\n", strerror(errno));
+			ALOGE("sync wait error = %s", strerror(errno));
 			return -errno;
 		}
 	}
@@ -173,7 +182,7 @@
 	if (close_fence) {
 		err = close(fence);
 		if (err) {
-			drv_log("Unable to close fence fd, err = %s\n", strerror(errno));
+			ALOGE("Unable to close fence fd, err = %s", strerror(errno));
 			return -errno;
 		}
 	}
diff --git a/cros_gralloc/cros_gralloc_helpers.h b/cros_gralloc/cros_gralloc_helpers.h
index 312d2f7..9fcb995 100644
--- a/cros_gralloc/cros_gralloc_helpers.h
+++ b/cros_gralloc/cros_gralloc_helpers.h
@@ -10,6 +10,7 @@
 #include "../drv.h"
 #include "cros_gralloc_handle.h"
 
+#include <log/log.h>
 #include <system/graphics.h>
 #include <system/window.h>
 
@@ -20,6 +21,9 @@
 // BO_USE_FRONT_RENDERING or BO_USE_LINEAR upon buffer allocaton.
 #define BUFFER_USAGE_FRONT_RENDERING (1U << 28)
 
+// Adopt BufferUsage::FRONT_BUFFER from api level 33
+#define BUFFER_USAGE_FRONT_RENDERING_MASK (BUFFER_USAGE_FRONT_RENDERING | (1ULL << 32))
+
 struct cros_gralloc_buffer_descriptor {
 	uint32_t width;
 	uint32_t height;
diff --git a/cros_gralloc/gralloc0/gralloc0.cc b/cros_gralloc/gralloc0/gralloc0.cc
index ce62521..3412e85 100644
--- a/cros_gralloc/gralloc0/gralloc0.cc
+++ b/cros_gralloc/gralloc0/gralloc0.cc
@@ -84,10 +84,10 @@
 	descriptor.reserved_region_size = 0;
 
 	if (!mod->driver->is_supported(&descriptor)) {
-		drv_log("Unsupported combination -- HAL format: %u, HAL usage: %u, "
-			"drv_format: %4.4s, use_flags: %llu\n",
-			format, usage, reinterpret_cast<char *>(&descriptor.drm_format),
-			static_cast<unsigned long long>(descriptor.use_flags));
+		ALOGE("Unsupported combination -- HAL format: %u, HAL usage: %u, "
+		      "drv_format: %4.4s, use_flags: %llu",
+		      format, usage, reinterpret_cast<char *>(&descriptor.drm_format),
+		      static_cast<unsigned long long>(descriptor.use_flags));
 		return -EINVAL;
 	}
 
@@ -160,7 +160,7 @@
 	}
 
 	if (strcmp(name, GRALLOC_HARDWARE_GPU0)) {
-		drv_log("Incorrect device name - %s.\n", name);
+		ALOGE("Incorrect device name - %s.", name);
 		return -EINVAL;
 	}
 
@@ -247,7 +247,7 @@
 		hnd = cros_gralloc_convert_handle(handle);
 		if (!hnd) {
 			va_end(args);
-			drv_log("Invalid handle.\n");
+			ALOGE("Invalid handle.");
 			return -EINVAL;
 		}
 		break;
@@ -351,12 +351,12 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	if (hnd->droid_format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-		drv_log("HAL_PIXEL_FORMAT_YCbCr_*_888 format not compatible.\n");
+		ALOGE("HAL_PIXEL_FORMAT_YCbCr_*_888 format not compatible.");
 		return -EINVAL;
 	}
 
@@ -402,13 +402,13 @@
 
 	auto hnd = cros_gralloc_convert_handle(handle);
 	if (!hnd) {
-		drv_log("Invalid handle.\n");
+		ALOGE("Invalid handle.");
 		return -EINVAL;
 	}
 
 	if (!gralloc0_droid_yuv_format(hnd->droid_format) &&
 	    hnd->droid_format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-		drv_log("Non-YUV format not compatible.\n");
+		ALOGE("Non-YUV format not compatible.");
 		return -EINVAL;
 	}
 
diff --git a/cros_gralloc/gralloc4/CrosGralloc4Allocator.cc b/cros_gralloc/gralloc4/CrosGralloc4Allocator.cc
index 43c0b0c..3166793 100644
--- a/cros_gralloc/gralloc4/CrosGralloc4Allocator.cc
+++ b/cros_gralloc/gralloc4/CrosGralloc4Allocator.cc
@@ -35,12 +35,12 @@
         cros_gralloc_handle_t crosHandle,
         const struct cros_gralloc_buffer_descriptor& crosDescriptor) {
     if (!mDriver) {
-        drv_log("Failed to initializeMetadata. Driver is uninitialized.\n");
+        ALOGE("Failed to initializeMetadata. Driver is uninitialized.");
         return Error::NO_RESOURCES;
     }
 
     if (!crosHandle) {
-        drv_log("Failed to initializeMetadata. Invalid handle.\n");
+        ALOGE("Failed to initializeMetadata. Invalid handle.");
         return Error::BAD_BUFFER;
     }
 
@@ -48,7 +48,7 @@
     uint64_t size;
     int ret = mDriver->get_reserved_region(crosHandle, &addr, &size);
     if (ret) {
-        drv_log("Failed to getReservedRegion.\n");
+        ALOGE("Failed to getReservedRegion.");
         return Error::NO_RESOURCES;
     }
 
@@ -65,7 +65,7 @@
 Error CrosGralloc4Allocator::allocate(const BufferDescriptorInfo& descriptor, uint32_t* outStride,
                                       hidl_handle* outHandle) {
     if (!mDriver) {
-        drv_log("Failed to allocate. Driver is uninitialized.\n");
+        ALOGE("Failed to allocate. Driver is uninitialized.");
         return Error::NO_RESOURCES;
     }
 
@@ -84,8 +84,8 @@
         std::string drmFormatString = get_drm_format_string(crosDescriptor.drm_format);
         std::string pixelFormatString = getPixelFormatString(descriptor.format);
         std::string usageString = getUsageString(descriptor.usage);
-        drv_log("Unsupported combination -- pixel format: %s, drm format:%s, usage: %s\n",
-                pixelFormatString.c_str(), drmFormatString.c_str(), usageString.c_str());
+        ALOGE("Unsupported combination -- pixel format: %s, drm format:%s, usage: %s",
+              pixelFormatString.c_str(), drmFormatString.c_str(), usageString.c_str());
         return Error::UNSUPPORTED;
     }
 
@@ -116,7 +116,7 @@
     hidl_vec<hidl_handle> handles;
 
     if (!mDriver) {
-        drv_log("Failed to allocate. Driver is uninitialized.\n");
+        ALOGE("Failed to allocate. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, 0, handles);
         return Void();
     }
@@ -125,7 +125,7 @@
 
     int ret = android::gralloc4::decodeBufferDescriptorInfo(descriptor, &description);
     if (ret) {
-        drv_log("Failed to allocate. Failed to decode buffer descriptor: %d.\n", ret);
+        ALOGE("Failed to allocate. Failed to decode buffer descriptor: %d.", ret);
         hidlCb(Error::BAD_DESCRIPTOR, 0, handles);
         return Void();
     }
diff --git a/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc b/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc
index cc2c4d5..a8a4f52 100644
--- a/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc
+++ b/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc
@@ -34,26 +34,26 @@
     hidl_vec<uint8_t> descriptor;
 
     if (description.width == 0) {
-        drv_log("Failed to createDescriptor. Bad width: %d.\n", description.width);
+        ALOGE("Failed to createDescriptor. Bad width: %d.", description.width);
         hidlCb(Error::BAD_VALUE, descriptor);
         return Void();
     }
 
     if (description.height == 0) {
-        drv_log("Failed to createDescriptor. Bad height: %d.\n", description.height);
+        ALOGE("Failed to createDescriptor. Bad height: %d.", description.height);
         hidlCb(Error::BAD_VALUE, descriptor);
         return Void();
     }
 
     if (description.layerCount == 0) {
-        drv_log("Failed to createDescriptor. Bad layer count: %d.\n", description.layerCount);
+        ALOGE("Failed to createDescriptor. Bad layer count: %d.", description.layerCount);
         hidlCb(Error::BAD_VALUE, descriptor);
         return Void();
     }
 
     int ret = android::gralloc4::encodeBufferDescriptorInfo(description, &descriptor);
     if (ret) {
-        drv_log("Failed to createDescriptor. Failed to encode: %d.\n", ret);
+        ALOGE("Failed to createDescriptor. Failed to encode: %d.", ret);
         hidlCb(Error::BAD_VALUE, descriptor);
         return Void();
     }
@@ -64,21 +64,21 @@
 
 Return<void> CrosGralloc4Mapper::importBuffer(const hidl_handle& handle, importBuffer_cb hidlCb) {
     if (!mDriver) {
-        drv_log("Failed to import buffer. Driver is uninitialized.\n");
+        ALOGE("Failed to import buffer. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, nullptr);
         return Void();
     }
 
     const native_handle_t* bufferHandle = handle.getNativeHandle();
     if (!bufferHandle || bufferHandle->numFds == 0) {
-        drv_log("Failed to importBuffer. Bad handle.\n");
+        ALOGE("Failed to importBuffer. Bad handle.");
         hidlCb(Error::BAD_BUFFER, nullptr);
         return Void();
     }
 
     native_handle_t* importedBufferHandle = native_handle_clone(bufferHandle);
     if (!importedBufferHandle) {
-        drv_log("Failed to importBuffer. Handle clone failed: %s.\n", strerror(errno));
+        ALOGE("Failed to importBuffer. Handle clone failed: %s.", strerror(errno));
         hidlCb(Error::NO_RESOURCES, nullptr);
         return Void();
     }
@@ -97,13 +97,13 @@
 
 Return<Error> CrosGralloc4Mapper::freeBuffer(void* rawHandle) {
     if (!mDriver) {
-        drv_log("Failed to freeBuffer. Driver is uninitialized.\n");
+        ALOGE("Failed to freeBuffer. Driver is uninitialized.");
         return Error::NO_RESOURCES;
     }
 
     native_handle_t* bufferHandle = reinterpret_cast<native_handle_t*>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to freeBuffer. Empty handle.\n");
+        ALOGE("Failed to freeBuffer. Empty handle.");
         return Error::BAD_BUFFER;
     }
 
@@ -121,43 +121,49 @@
                                                      const BufferDescriptorInfo& descriptor,
                                                      uint32_t stride) {
     if (!mDriver) {
-        drv_log("Failed to validateBufferSize. Driver is uninitialized.\n");
+        ALOGE("Failed to validateBufferSize. Driver is uninitialized.");
         return Error::NO_RESOURCES;
     }
 
     native_handle_t* bufferHandle = reinterpret_cast<native_handle_t*>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to validateBufferSize. Empty handle.\n");
+        ALOGE("Failed to validateBufferSize. Empty handle.");
         return Error::BAD_BUFFER;
     }
 
     cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
     if (!crosHandle) {
-        drv_log("Failed to validateBufferSize. Invalid handle.\n");
+        ALOGE("Failed to validateBufferSize. Invalid handle.");
         return Error::BAD_BUFFER;
     }
 
     PixelFormat crosHandleFormat = static_cast<PixelFormat>(crosHandle->droid_format);
     if (descriptor.format != crosHandleFormat) {
-        drv_log("Failed to validateBufferSize. Format mismatch.\n");
+        ALOGE("Failed to validateBufferSize. Format mismatch.");
         return Error::BAD_BUFFER;
     }
 
     if (descriptor.width != crosHandle->width) {
-        drv_log("Failed to validateBufferSize. Width mismatch (%d vs %d).\n", descriptor.width,
-                crosHandle->width);
+        ALOGE("Failed to validateBufferSize. Width mismatch (%d vs %d).", descriptor.width,
+              crosHandle->width);
         return Error::BAD_VALUE;
     }
 
     if (descriptor.height != crosHandle->height) {
-        drv_log("Failed to validateBufferSize. Height mismatch (%d vs %d).\n", descriptor.height,
-                crosHandle->height);
+        ALOGE("Failed to validateBufferSize. Height mismatch (%d vs %d).", descriptor.height,
+              crosHandle->height);
         return Error::BAD_VALUE;
     }
 
-    if (stride != crosHandle->pixel_stride) {
-        drv_log("Failed to validateBufferSize. Stride mismatch (%d vs %d).\n", stride,
-                crosHandle->pixel_stride);
+    if (crosHandle->droid_format == HAL_PIXEL_FORMAT_BLOB) {
+        if (stride > crosHandle->pixel_stride) {
+            ALOGE("Failed to validateBufferSize. Oversized stride (%d vs %d).", stride,
+                  crosHandle->pixel_stride);
+            return Error::BAD_VALUE;
+        }
+    } else if (stride != crosHandle->pixel_stride) {
+        ALOGE("Failed to validateBufferSize. Stride mismatch (%d vs %d).", stride,
+              crosHandle->pixel_stride);
         return Error::BAD_VALUE;
     }
 
@@ -166,14 +172,14 @@
 
 Return<void> CrosGralloc4Mapper::getTransportSize(void* rawHandle, getTransportSize_cb hidlCb) {
     if (!mDriver) {
-        drv_log("Failed to getTransportSize. Driver is uninitialized.\n");
+        ALOGE("Failed to getTransportSize. Driver is uninitialized.");
         hidlCb(Error::BAD_BUFFER, 0, 0);
         return Void();
     }
 
     native_handle_t* bufferHandle = reinterpret_cast<native_handle_t*>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to getTransportSize. Bad handle.\n");
+        ALOGE("Failed to getTransportSize. Bad handle.");
         hidlCb(Error::BAD_BUFFER, 0, 0);
         return Void();
     }
@@ -186,20 +192,20 @@
 Return<void> CrosGralloc4Mapper::lock(void* rawBuffer, uint64_t cpuUsage, const Rect& region,
                                       const hidl_handle& acquireFence, lock_cb hidlCb) {
     if (!mDriver) {
-        drv_log("Failed to lock. Driver is uninitialized.\n");
+        ALOGE("Failed to lock. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, nullptr);
         return Void();
     }
 
     buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawBuffer);
     if (!bufferHandle) {
-        drv_log("Failed to lock. Empty handle.\n");
+        ALOGE("Failed to lock. Empty handle.");
         hidlCb(Error::BAD_BUFFER, nullptr);
         return Void();
     }
 
     if (cpuUsage == 0) {
-        drv_log("Failed to lock. Bad cpu usage: %" PRIu64 ".\n", cpuUsage);
+        ALOGE("Failed to lock. Bad cpu usage: %" PRIu64 ".", cpuUsage);
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
@@ -207,52 +213,52 @@
     uint32_t mapUsage = 0;
     int ret = convertToMapUsage(cpuUsage, &mapUsage);
     if (ret) {
-        drv_log("Failed to lock. Convert usage failed.\n");
+        ALOGE("Failed to lock. Convert usage failed.");
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
 
     cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
     if (crosHandle == nullptr) {
-        drv_log("Failed to lock. Invalid handle.\n");
+        ALOGE("Failed to lock. Invalid handle.");
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
 
     if (region.left < 0) {
-        drv_log("Failed to lock. Invalid region: negative left value %d.\n", region.left);
+        ALOGE("Failed to lock. Invalid region: negative left value %d.", region.left);
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
 
     if (region.top < 0) {
-        drv_log("Failed to lock. Invalid region: negative top value %d.\n", region.top);
+        ALOGE("Failed to lock. Invalid region: negative top value %d.", region.top);
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
 
     if (region.width < 0) {
-        drv_log("Failed to lock. Invalid region: negative width value %d.\n", region.width);
+        ALOGE("Failed to lock. Invalid region: negative width value %d.", region.width);
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
 
     if (region.height < 0) {
-        drv_log("Failed to lock. Invalid region: negative height value %d.\n", region.height);
+        ALOGE("Failed to lock. Invalid region: negative height value %d.", region.height);
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
 
     if (region.width > crosHandle->width) {
-        drv_log("Failed to lock. Invalid region: width greater than buffer width (%d vs %d).\n",
-                region.width, crosHandle->width);
+        ALOGE("Failed to lock. Invalid region: width greater than buffer width (%d vs %d).",
+              region.width, crosHandle->width);
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
 
     if (region.height > crosHandle->height) {
-        drv_log("Failed to lock. Invalid region: height greater than buffer height (%d vs %d).\n",
-                region.height, crosHandle->height);
+        ALOGE("Failed to lock. Invalid region: height greater than buffer height (%d vs %d).",
+              region.height, crosHandle->height);
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
@@ -270,7 +276,7 @@
     int acquireFenceFd = -1;
     ret = convertToFenceFd(acquireFence, &acquireFenceFd);
     if (ret) {
-        drv_log("Failed to lock. Bad acquire fence.\n");
+        ALOGE("Failed to lock. Bad acquire fence.");
         hidlCb(Error::BAD_VALUE, nullptr);
         return Void();
     }
@@ -289,14 +295,14 @@
 
 Return<void> CrosGralloc4Mapper::unlock(void* rawHandle, unlock_cb hidlCb) {
     if (!mDriver) {
-        drv_log("Failed to unlock. Driver is uninitialized.\n");
+        ALOGE("Failed to unlock. Driver is uninitialized.");
         hidlCb(Error::BAD_BUFFER, nullptr);
         return Void();
     }
 
     buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to unlock. Empty handle.\n");
+        ALOGE("Failed to unlock. Empty handle.");
         hidlCb(Error::BAD_BUFFER, nullptr);
         return Void();
     }
@@ -304,7 +310,7 @@
     int releaseFenceFd = -1;
     int ret = mDriver->unlock(bufferHandle, &releaseFenceFd);
     if (ret) {
-        drv_log("Failed to unlock.\n");
+        ALOGE("Failed to unlock.");
         hidlCb(Error::BAD_BUFFER, nullptr);
         return Void();
     }
@@ -312,7 +318,7 @@
     hidl_handle releaseFenceHandle;
     ret = convertToFenceHandle(releaseFenceFd, &releaseFenceHandle);
     if (ret) {
-        drv_log("Failed to unlock. Failed to convert release fence to handle.\n");
+        ALOGE("Failed to unlock. Failed to convert release fence to handle.");
         hidlCb(Error::BAD_BUFFER, nullptr);
         return Void();
     }
@@ -323,22 +329,28 @@
 
 Return<void> CrosGralloc4Mapper::flushLockedBuffer(void* rawHandle, flushLockedBuffer_cb hidlCb) {
     if (!mDriver) {
-        drv_log("Failed to flushLockedBuffer. Driver is uninitialized.\n");
+        ALOGE("Failed to flushLockedBuffer. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, nullptr);
         return Void();
     }
 
     buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to flushLockedBuffer. Empty handle.\n");
+        ALOGE("Failed to flushLockedBuffer. Empty handle.");
         hidlCb(Error::BAD_BUFFER, nullptr);
         return Void();
     }
 
+    /*
+     * From the ANativeWindow::dequeueBuffer documentation:
+     *
+     * "A value of -1 indicates that the caller may access the buffer immediately without
+     * waiting on a fence."
+     */
     int releaseFenceFd = -1;
-    int ret = mDriver->flush(bufferHandle, &releaseFenceFd);
+    int ret = mDriver->flush(bufferHandle);
     if (ret) {
-        drv_log("Failed to flushLockedBuffer. Flush failed.\n");
+        ALOGE("Failed to flushLockedBuffer. Flush failed.");
         hidlCb(Error::BAD_BUFFER, nullptr);
         return Void();
     }
@@ -346,7 +358,7 @@
     hidl_handle releaseFenceHandle;
     ret = convertToFenceHandle(releaseFenceFd, &releaseFenceHandle);
     if (ret) {
-        drv_log("Failed to flushLockedBuffer. Failed to convert release fence to handle.\n");
+        ALOGE("Failed to flushLockedBuffer. Failed to convert release fence to handle.");
         hidlCb(Error::BAD_BUFFER, nullptr);
         return Void();
     }
@@ -357,19 +369,19 @@
 
 Return<Error> CrosGralloc4Mapper::rereadLockedBuffer(void* rawHandle) {
     if (!mDriver) {
-        drv_log("Failed to rereadLockedBuffer. Driver is uninitialized.\n");
+        ALOGE("Failed to rereadLockedBuffer. Driver is uninitialized.");
         return Error::NO_RESOURCES;
     }
 
     buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to rereadLockedBuffer. Empty handle.\n");
+        ALOGE("Failed to rereadLockedBuffer. Empty handle.");
         return Error::BAD_BUFFER;
     }
 
     int ret = mDriver->invalidate(bufferHandle);
     if (ret) {
-        drv_log("Failed to rereadLockedBuffer. Failed to invalidate.\n");
+        ALOGE("Failed to rereadLockedBuffer. Failed to invalidate.");
         return Error::BAD_BUFFER;
     }
 
@@ -379,7 +391,7 @@
 Return<void> CrosGralloc4Mapper::isSupported(const BufferDescriptorInfo& descriptor,
                                              isSupported_cb hidlCb) {
     if (!mDriver) {
-        drv_log("Failed to isSupported. Driver is uninitialized.\n");
+        ALOGE("Failed to isSupported. Driver is uninitialized.");
         hidlCb(Error::BAD_VALUE, false);
         return Void();
     }
@@ -399,21 +411,21 @@
     hidl_vec<uint8_t> encodedMetadata;
 
     if (!mDriver) {
-        drv_log("Failed to get. Driver is uninitialized.\n");
+        ALOGE("Failed to get. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, encodedMetadata);
         return Void();
     }
 
     buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to get. Empty handle.\n");
+        ALOGE("Failed to get. Empty handle.");
         hidlCb(Error::BAD_BUFFER, encodedMetadata);
         return Void();
     }
 
     cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
     if (!crosHandle) {
-        drv_log("Failed to get. Invalid handle.\n");
+        ALOGE("Failed to get. Invalid handle.");
         hidlCb(Error::BAD_BUFFER, encodedMetadata);
         return Void();
     }
@@ -429,13 +441,13 @@
     hidl_vec<uint8_t> encodedMetadata;
 
     if (!mDriver) {
-        drv_log("Failed to get. Driver is uninitialized.\n");
+        ALOGE("Failed to get. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, encodedMetadata);
         return Void();
     }
 
     if (!crosBuffer) {
-        drv_log("Failed to get. Invalid buffer.\n");
+        ALOGE("Failed to get. Invalid buffer.");
         hidlCb(Error::BAD_BUFFER, encodedMetadata);
         return Void();
     }
@@ -448,7 +460,7 @@
         metadataType == android::gralloc4::MetadataType_Smpte2086) {
         Error error = getMetadata(crosBuffer, &crosMetadata);
         if (error != Error::NONE) {
-            drv_log("Failed to get. Failed to get buffer metadata.\n");
+            ALOGE("Failed to get. Failed to get buffer metadata.");
             hidlCb(Error::NO_RESOURCES, encodedMetadata);
             return Void();
         }
@@ -540,7 +552,7 @@
 
     if (status != android::NO_ERROR) {
         hidlCb(Error::NO_RESOURCES, encodedMetadata);
-        drv_log("Failed to get. Failed to encode metadata.\n");
+        ALOGE("Failed to get. Failed to encode metadata.");
         return Void();
     }
 
@@ -551,19 +563,19 @@
 Return<Error> CrosGralloc4Mapper::set(void* rawHandle, const MetadataType& metadataType,
                                       const hidl_vec<uint8_t>& encodedMetadata) {
     if (!mDriver) {
-        drv_log("Failed to set. Driver is uninitialized.\n");
+        ALOGE("Failed to set. Driver is uninitialized.");
         return Error::NO_RESOURCES;
     }
 
     buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to set. Empty handle.\n");
+        ALOGE("Failed to set. Empty handle.");
         return Error::BAD_BUFFER;
     }
 
     cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
     if (!crosHandle) {
-        drv_log("Failed to set. Invalid handle.\n");
+        ALOGE("Failed to set. Invalid handle.");
         return Error::BAD_BUFFER;
     }
 
@@ -601,12 +613,12 @@
 Error CrosGralloc4Mapper::set(cros_gralloc_buffer* crosBuffer, const MetadataType& metadataType,
                               const android::hardware::hidl_vec<uint8_t>& encodedMetadata) {
     if (!mDriver) {
-        drv_log("Failed to set. Driver is uninitialized.\n");
+        ALOGE("Failed to set. Driver is uninitialized.");
         return Error::NO_RESOURCES;
     }
 
     if (!crosBuffer) {
-        drv_log("Failed to set. Invalid buffer.\n");
+        ALOGE("Failed to set. Invalid buffer.");
         return Error::BAD_BUFFER;
     }
 
@@ -614,32 +626,32 @@
 
     Error error = getMutableMetadata(crosBuffer, &crosMetadata);
     if (error != Error::NONE) {
-        drv_log("Failed to set. Failed to get buffer metadata.\n");
+        ALOGE("Failed to set. Failed to get buffer metadata.");
         return Error::UNSUPPORTED;
     }
 
     if (metadataType == android::gralloc4::MetadataType_BlendMode) {
         auto status = android::gralloc4::decodeBlendMode(encodedMetadata, &crosMetadata->blendMode);
         if (status != android::NO_ERROR) {
-            drv_log("Failed to set. Failed to decode blend mode.\n");
+            ALOGE("Failed to set. Failed to decode blend mode.");
             return Error::UNSUPPORTED;
         }
     } else if (metadataType == android::gralloc4::MetadataType_Cta861_3) {
         auto status = android::gralloc4::decodeCta861_3(encodedMetadata, &crosMetadata->cta861_3);
         if (status != android::NO_ERROR) {
-            drv_log("Failed to set. Failed to decode cta861_3.\n");
+            ALOGE("Failed to set. Failed to decode cta861_3.");
             return Error::UNSUPPORTED;
         }
     } else if (metadataType == android::gralloc4::MetadataType_Dataspace) {
         auto status = android::gralloc4::decodeDataspace(encodedMetadata, &crosMetadata->dataspace);
         if (status != android::NO_ERROR) {
-            drv_log("Failed to set. Failed to decode dataspace.\n");
+            ALOGE("Failed to set. Failed to decode dataspace.");
             return Error::UNSUPPORTED;
         }
     } else if (metadataType == android::gralloc4::MetadataType_Smpte2086) {
         auto status = android::gralloc4::decodeSmpte2086(encodedMetadata, &crosMetadata->smpte2086);
         if (status != android::NO_ERROR) {
-            drv_log("Failed to set. Failed to decode smpte2086.\n");
+            ALOGE("Failed to set. Failed to decode smpte2086.");
             return Error::UNSUPPORTED;
         }
     }
@@ -652,24 +664,23 @@
     uint32_t drmFormat;
     if (convertToDrmFormat(pixelFormat, &drmFormat)) {
         std::string pixelFormatString = getPixelFormatString(pixelFormat);
-        drv_log("Failed to getResolvedDrmFormat. Failed to convert format %s\n",
-                pixelFormatString.c_str());
+        ALOGE("Failed to getResolvedDrmFormat. Failed to convert format %s",
+              pixelFormatString.c_str());
         return -EINVAL;
     }
 
     uint64_t usage;
     if (convertToBufferUsage(bufferUsage, &usage)) {
         std::string usageString = getUsageString(bufferUsage);
-        drv_log("Failed to getResolvedDrmFormat. Failed to convert usage %s\n",
-                usageString.c_str());
+        ALOGE("Failed to getResolvedDrmFormat. Failed to convert usage %s", usageString.c_str());
         return -EINVAL;
     }
 
     uint32_t resolvedDrmFormat = mDriver->get_resolved_drm_format(drmFormat, usage);
     if (resolvedDrmFormat == DRM_FORMAT_INVALID) {
         std::string drmFormatString = get_drm_format_string(drmFormat);
-        drv_log("Failed to getResolvedDrmFormat. Failed to resolve drm format %s\n",
-                drmFormatString.c_str());
+        ALOGE("Failed to getResolvedDrmFormat. Failed to resolve drm format %s",
+              drmFormatString.c_str());
         return -EINVAL;
     }
 
@@ -684,7 +695,7 @@
     hidl_vec<uint8_t> encodedMetadata;
 
     if (!mDriver) {
-        drv_log("Failed to getFromBufferDescriptorInfo. Driver is uninitialized.\n");
+        ALOGE("Failed to getFromBufferDescriptorInfo. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, encodedMetadata);
         return Void();
     }
@@ -769,7 +780,7 @@
     hidl_vec<MetadataTypeDescription> supported;
 
     if (!mDriver) {
-        drv_log("Failed to listSupportedMetadataTypes. Driver is uninitialized.\n");
+        ALOGE("Failed to listSupportedMetadataTypes. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, supported);
         return Void();
     }
@@ -866,6 +877,12 @@
                     /*isSettable=*/false,
             },
             {
+                    android::gralloc4::MetadataType_Crop,
+                    "",
+                    /*isGettable=*/true,
+                    /*isSettable=*/false,
+            },
+            {
                     android::gralloc4::MetadataType_Dataspace,
                     "",
                     /*isGettable=*/true,
@@ -905,21 +922,21 @@
     BufferDump bufferDump;
 
     if (!mDriver) {
-        drv_log("Failed to dumpBuffer. Driver is uninitialized.\n");
+        ALOGE("Failed to dumpBuffer. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, bufferDump);
         return Void();
     }
 
     buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to dumpBuffer. Empty handle.\n");
+        ALOGE("Failed to dumpBuffer. Empty handle.");
         hidlCb(Error::BAD_BUFFER, bufferDump);
         return Void();
     }
 
     cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
     if (!crosHandle) {
-        drv_log("Failed to dumpBuffer. Invalid handle.\n");
+        ALOGE("Failed to dumpBuffer. Invalid handle.");
         hidlCb(Error::BAD_BUFFER, bufferDump);
         return Void();
     }
@@ -935,7 +952,7 @@
     BufferDump bufferDump;
 
     if (!mDriver) {
-        drv_log("Failed to dumpBuffer. Driver is uninitialized.\n");
+        ALOGE("Failed to dumpBuffer. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, bufferDump);
         return Void();
     }
@@ -1010,7 +1027,7 @@
     std::vector<BufferDump> bufferDumps;
 
     if (!mDriver) {
-        drv_log("Failed to dumpBuffers. Driver is uninitialized.\n");
+        ALOGE("Failed to dumpBuffers. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, bufferDumps);
         return Void();
     }
@@ -1035,18 +1052,18 @@
                                                 ReservedRegionArea area, void** outAddr,
                                                 uint64_t* outSize) {
     if (!mDriver) {
-        drv_log("Failed to getReservedRegionArea. Driver is uninitialized.\n");
+        ALOGE("Failed to getReservedRegionArea. Driver is uninitialized.");
         return Error::NO_RESOURCES;
     }
 
     if (!crosBuffer) {
-        drv_log("Failed to getReservedRegionArea. Invalid buffer.\n");
+        ALOGE("Failed to getReservedRegionArea. Invalid buffer.");
         return Error::BAD_BUFFER;
     }
 
     int ret = crosBuffer->get_reserved_region(outAddr, outSize);
     if (ret) {
-        drv_log("Failed to getReservedRegionArea.\n");
+        ALOGE("Failed to getReservedRegionArea.");
         *outAddr = nullptr;
         *outSize = 0;
         return Error::NO_RESOURCES;
@@ -1102,21 +1119,21 @@
 
 Return<void> CrosGralloc4Mapper::getReservedRegion(void* rawHandle, getReservedRegion_cb hidlCb) {
     if (!mDriver) {
-        drv_log("Failed to getReservedRegion. Driver is uninitialized.\n");
+        ALOGE("Failed to getReservedRegion. Driver is uninitialized.");
         hidlCb(Error::NO_RESOURCES, nullptr, 0);
         return Void();
     }
 
     buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
     if (!bufferHandle) {
-        drv_log("Failed to getReservedRegion. Empty handle.\n");
+        ALOGE("Failed to getReservedRegion. Empty handle.");
         hidlCb(Error::BAD_BUFFER, nullptr, 0);
         return Void();
     }
 
     cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
     if (!crosHandle) {
-        drv_log("Failed to getReservedRegion. Invalid handle.\n");
+        ALOGE("Failed to getReservedRegion. Invalid handle.");
         hidlCb(Error::BAD_BUFFER, nullptr, 0);
         return Void();
     }
@@ -1131,7 +1148,7 @@
     });
 
     if (error != Error::NONE) {
-        drv_log("Failed to getReservedRegion. Failed to getReservedRegionArea.\n");
+        ALOGE("Failed to getReservedRegion. Failed to getReservedRegionArea.");
         hidlCb(Error::BAD_BUFFER, nullptr, 0);
         return Void();
     }
diff --git a/cros_gralloc/gralloc4/CrosGralloc4Utils.cc b/cros_gralloc/gralloc4/CrosGralloc4Utils.cc
index 6c07189..515269a 100644
--- a/cros_gralloc/gralloc4/CrosGralloc4Utils.cc
+++ b/cros_gralloc/gralloc4/CrosGralloc4Utils.cc
@@ -64,18 +64,17 @@
     outCrosDescriptor->droid_usage = descriptor.usage;
     outCrosDescriptor->reserved_region_size = descriptor.reservedSize;
     if (descriptor.layerCount > 1) {
-        drv_log("Failed to convert descriptor. Unsupported layerCount: %d\n",
-                descriptor.layerCount);
+        ALOGE("Failed to convert descriptor. Unsupported layerCount: %d", descriptor.layerCount);
         return -EINVAL;
     }
     if (convertToDrmFormat(descriptor.format, &outCrosDescriptor->drm_format)) {
         std::string pixelFormatString = getPixelFormatString(descriptor.format);
-        drv_log("Failed to convert descriptor. Unsupported format %s\n", pixelFormatString.c_str());
+        ALOGE("Failed to convert descriptor. Unsupported format %s", pixelFormatString.c_str());
         return -EINVAL;
     }
     if (convertToBufferUsage(descriptor.usage, &outCrosDescriptor->use_flags)) {
         std::string usageString = getUsageString(descriptor.usage);
-        drv_log("Failed to convert descriptor. Unsupported usage flags %s\n", usageString.c_str());
+        ALOGE("Failed to convert descriptor. Unsupported usage flags %s", usageString.c_str());
         return -EINVAL;
     }
     return 0;
@@ -342,7 +341,7 @@
                              },
                              {
                                      .components = {{.type = android::gralloc4::
-                                                             PlaneLayoutComponentType_CB,
+                                                             PlaneLayoutComponentType_CR,
                                                      .offsetInBits = 0,
                                                      .sizeInBits = 8}},
                                      .sampleIncrementInBits = 8,
@@ -351,7 +350,7 @@
                              },
                              {
                                      .components = {{.type = android::gralloc4::
-                                                             PlaneLayoutComponentType_CR,
+                                                             PlaneLayoutComponentType_CB,
                                                      .offsetInBits = 0,
                                                      .sizeInBits = 8}},
                                      .sampleIncrementInBits = 8,
@@ -398,7 +397,7 @@
     const auto& planeLayoutsMap = GetPlaneLayoutsMap();
     const auto it = planeLayoutsMap.find(drmFormat);
     if (it == planeLayoutsMap.end()) {
-        drv_log("Unknown plane layout for format %d\n", drmFormat);
+        ALOGE("Unknown plane layout for format %d", drmFormat);
         return -EINVAL;
     }
 
diff --git a/cros_gralloc/mapper_stablec/.clang-format b/cros_gralloc/mapper_stablec/.clang-format
new file mode 100644
index 0000000..e5e7076
--- /dev/null
+++ b/cros_gralloc/mapper_stablec/.clang-format
@@ -0,0 +1,19 @@
+# Copyright 2022 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.
+#
+# This directory is formatted to match the format of the interfaces implemented.
+
+BasedOnStyle: Google
+Standard: Cpp11
+AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IncludeBlocks: Preserve
+IndentWidth: 4
+ContinuationIndentWidth: 8
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
\ No newline at end of file
diff --git a/cros_gralloc/mapper_stablec/Android.bp b/cros_gralloc/mapper_stablec/Android.bp
new file mode 100644
index 0000000..b25be17
--- /dev/null
+++ b/cros_gralloc/mapper_stablec/Android.bp
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "external_minigbm_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-BSD
+    default_applicable_licenses: ["external_minigbm_license"],
+}
+
+cc_library_shared {
+    name: "mapper.minigbm",
+    defaults: ["minigbm_gralloc4_common_defaults"],
+    vintf_fragments: ["mapper.minigbm.xml"],
+    shared_libs: [
+        "android.hardware.graphics.allocator-V2-ndk",
+        "libminigbm_gralloc",
+    ],
+    header_libs: [
+        "libbase_headers",
+        "libimapper_stablec",
+        "libimapper_providerutils",
+    ],
+    srcs: [
+        ":minigbm_gralloc4_mapper_files",
+        "Mapper.cpp",
+    ],
+    cpp_std: "c++20",
+}
diff --git a/cros_gralloc/mapper_stablec/Mapper.cpp b/cros_gralloc/mapper_stablec/Mapper.cpp
new file mode 100644
index 0000000..6c4ac86
--- /dev/null
+++ b/cros_gralloc/mapper_stablec/Mapper.cpp
@@ -0,0 +1,745 @@
+/*
+ * Copyright 2022 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 <aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.h>
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidl/android/hardware/graphics/common/StandardMetadataType.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+#include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
+#include <cutils/native_handle.h>
+#include <gralloctypes/Gralloc4.h>
+
+#include "cros_gralloc/cros_gralloc_driver.h"
+#include "cros_gralloc/cros_gralloc_handle.h"
+#include "cros_gralloc/gralloc4/CrosGralloc4Metadata.h"
+#include "cros_gralloc/gralloc4/CrosGralloc4Utils.h"
+
+using namespace ::aidl::android::hardware::graphics::common;
+using namespace ::android::hardware::graphics::mapper;
+using ::aidl::android::hardware::graphics::allocator::BufferDescriptorInfo;
+using ::android::base::unique_fd;
+
+#define REQUIRE_DRIVER()                                           \
+    if (!mDriver) {                                                \
+        ALOGE("Failed to %s. Driver is uninitialized.", __func__); \
+        return AIMAPPER_ERROR_NO_RESOURCES;                        \
+    }
+
+#define VALIDATE_BUFFER_HANDLE(bufferHandle)                    \
+    if (!(bufferHandle)) {                                      \
+        ALOGE("Failed to %s. Null buffer_handle_t.", __func__); \
+        return AIMAPPER_ERROR_BAD_BUFFER;                       \
+    }
+
+#define VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle) \
+    REQUIRE_DRIVER()                                    \
+    VALIDATE_BUFFER_HANDLE(bufferHandle)
+
+static_assert(CROS_GRALLOC4_METADATA_MAX_NAME_SIZE >=
+                      decltype(std::declval<BufferDescriptorInfo>().name){}.size(),
+              "Metadata name storage too small to fit a BufferDescriptorInfo::name");
+
+constexpr const char* STANDARD_METADATA_NAME =
+        "android.hardware.graphics.common.StandardMetadataType";
+
+static bool isStandardMetadata(AIMapper_MetadataType metadataType) {
+    return strcmp(STANDARD_METADATA_NAME, metadataType.name) == 0;
+}
+
+class CrosGrallocMapperV5 final : public vendor::mapper::IMapperV5Impl {
+  private:
+    cros_gralloc_driver* mDriver = cros_gralloc_driver::get_instance();
+
+  public:
+    explicit CrosGrallocMapperV5() = default;
+    ~CrosGrallocMapperV5() override = default;
+
+    AIMapper_Error importBuffer(const native_handle_t* _Nonnull handle,
+                                buffer_handle_t _Nullable* _Nonnull outBufferHandle) override;
+
+    AIMapper_Error freeBuffer(buffer_handle_t _Nonnull buffer) override;
+
+    AIMapper_Error getTransportSize(buffer_handle_t _Nonnull buffer, uint32_t* _Nonnull outNumFds,
+                                    uint32_t* _Nonnull outNumInts) override;
+
+    AIMapper_Error lock(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage, ARect accessRegion,
+                        int acquireFence, void* _Nullable* _Nonnull outData) override;
+
+    AIMapper_Error unlock(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence) override;
+
+    AIMapper_Error flushLockedBuffer(buffer_handle_t _Nonnull buffer) override;
+
+    AIMapper_Error rereadLockedBuffer(buffer_handle_t _Nonnull buffer) override;
+
+    int32_t getMetadata(buffer_handle_t _Nonnull buffer, AIMapper_MetadataType metadataType,
+                        void* _Nonnull outData, size_t outDataSize) override;
+
+    int32_t getStandardMetadata(buffer_handle_t _Nonnull buffer, int64_t standardMetadataType,
+                                void* _Nonnull outData, size_t outDataSize) override;
+
+    AIMapper_Error setMetadata(buffer_handle_t _Nonnull buffer, AIMapper_MetadataType metadataType,
+                               const void* _Nonnull metadata, size_t metadataSize) override;
+
+    AIMapper_Error setStandardMetadata(buffer_handle_t _Nonnull buffer,
+                                       int64_t standardMetadataType, const void* _Nonnull metadata,
+                                       size_t metadataSize) override;
+
+    AIMapper_Error listSupportedMetadataTypes(
+            const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+            size_t* _Nonnull outNumberOfDescriptions) override;
+
+    AIMapper_Error dumpBuffer(buffer_handle_t _Nonnull bufferHandle,
+                              AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+                              void* _Null_unspecified context) override;
+
+    AIMapper_Error dumpAllBuffers(AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
+                                  AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+                                  void* _Null_unspecified context) override;
+
+    AIMapper_Error getReservedRegion(buffer_handle_t _Nonnull buffer,
+                                     void* _Nullable* _Nonnull outReservedRegion,
+                                     uint64_t* _Nonnull outReservedSize) override;
+
+  private:
+    enum class ReservedRegionArea {
+        /* CrosGralloc4Metadata */
+        MAPPER4_METADATA,
+
+        /* External user metadata */
+        USER_METADATA,
+    };
+
+    AIMapper_Error getReservedRegionArea(const cros_gralloc_buffer* crosBuffer,
+                                         ReservedRegionArea area, void** outAddr,
+                                         uint64_t* outSize);
+
+    AIMapper_Error getCrosMetadata(const cros_gralloc_buffer* crosBuffer,
+                                   const CrosGralloc4Metadata** outMetadata);
+
+    AIMapper_Error getMutableCrosMetadata(cros_gralloc_buffer* crosBuffer,
+                                          CrosGralloc4Metadata** outMetadata);
+
+    template <typename F, StandardMetadataType TYPE>
+    int32_t getStandardMetadata(const cros_gralloc_buffer* crosBuffer, F&& provide,
+                                StandardMetadata<TYPE>);
+
+    template <StandardMetadataType TYPE>
+    AIMapper_Error setStandardMetadata(CrosGralloc4Metadata* crosMetadata,
+                                       typename StandardMetadata<TYPE>::value_type&& value);
+
+    void dumpBuffer(
+            const cros_gralloc_buffer* crosBuffer,
+            std::function<void(AIMapper_MetadataType, const std::vector<uint8_t>&)> callback);
+};
+
+AIMapper_Error CrosGrallocMapperV5::importBuffer(
+        const native_handle_t* _Nonnull bufferHandle,
+        buffer_handle_t _Nullable* _Nonnull outBufferHandle) {
+    REQUIRE_DRIVER()
+
+    if (!bufferHandle || bufferHandle->numFds == 0) {
+        ALOGE("Failed to importBuffer. Bad handle.");
+        return AIMAPPER_ERROR_BAD_BUFFER;
+    }
+
+    native_handle_t* importedBufferHandle = native_handle_clone(bufferHandle);
+    if (!importedBufferHandle) {
+        ALOGE("Failed to importBuffer. Handle clone failed: %s.", strerror(errno));
+        return AIMAPPER_ERROR_NO_RESOURCES;
+    }
+
+    int ret = mDriver->retain(importedBufferHandle);
+    if (ret) {
+        native_handle_close(importedBufferHandle);
+        native_handle_delete(importedBufferHandle);
+        return AIMAPPER_ERROR_NO_RESOURCES;
+    }
+
+    *outBufferHandle = importedBufferHandle;
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::freeBuffer(buffer_handle_t _Nonnull buffer) {
+    VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer)
+
+    int ret = mDriver->release(buffer);
+    if (ret) {
+        return AIMAPPER_ERROR_BAD_BUFFER;
+    }
+
+    native_handle_close(buffer);
+    native_handle_delete(const_cast<native_handle_t*>(buffer));
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::getTransportSize(buffer_handle_t _Nonnull bufferHandle,
+                                                     uint32_t* _Nonnull outNumFds,
+                                                     uint32_t* _Nonnull outNumInts) {
+    VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle)
+
+    // No local process data is currently stored on the native handle.
+    *outNumFds = bufferHandle->numFds;
+    *outNumInts = bufferHandle->numInts;
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::lock(buffer_handle_t _Nonnull bufferHandle, uint64_t cpuUsage,
+                                         ARect region, int acquireFenceRawFd,
+                                         void* _Nullable* _Nonnull outData) {
+    // We take ownership of the FD in all cases, even for errors
+    unique_fd acquireFence(acquireFenceRawFd);
+    VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle)
+    if (cpuUsage == 0) {
+        ALOGE("Failed to lock. Bad cpu usage: %" PRIu64 ".", cpuUsage);
+        return AIMAPPER_ERROR_BAD_VALUE;
+    }
+
+    uint32_t mapUsage = cros_gralloc_convert_map_usage(cpuUsage);
+
+    cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
+    if (crosHandle == nullptr) {
+        ALOGE("Failed to lock. Invalid handle.");
+        return AIMAPPER_ERROR_BAD_VALUE;
+    }
+
+    struct rectangle rect;
+
+    // An access region of all zeros means the entire buffer.
+    if (region.left == 0 && region.top == 0 && region.right == 0 && region.bottom == 0) {
+        rect = {0, 0, crosHandle->width, crosHandle->height};
+    } else {
+        if (region.left < 0 || region.top < 0 || region.right <= region.left ||
+            region.bottom <= region.top) {
+            ALOGE("Failed to lock. Invalid accessRegion: [%d, %d, %d, %d]", region.left, region.top,
+                  region.right, region.bottom);
+            return AIMAPPER_ERROR_BAD_VALUE;
+        }
+
+        if (region.right > crosHandle->width) {
+            ALOGE("Failed to lock. Invalid region: width greater than buffer width (%d vs %d).",
+                  region.right, crosHandle->width);
+            return AIMAPPER_ERROR_BAD_VALUE;
+        }
+
+        if (region.bottom > crosHandle->height) {
+            ALOGE("Failed to lock. Invalid region: height greater than buffer height (%d vs "
+                  "%d).",
+                  region.bottom, crosHandle->height);
+            return AIMAPPER_ERROR_BAD_VALUE;
+        }
+
+        rect = {static_cast<uint32_t>(region.left), static_cast<uint32_t>(region.top),
+                static_cast<uint32_t>(region.right - region.left),
+                static_cast<uint32_t>(region.bottom - region.top)};
+    }
+
+    uint8_t* addr[DRV_MAX_PLANES];
+    int32_t status = mDriver->lock(bufferHandle, acquireFence.get(),
+                                   /*close_acquire_fence=*/false, &rect, mapUsage, addr);
+    if (status) {
+        return AIMAPPER_ERROR_BAD_VALUE;
+    }
+
+    *outData = addr[0];
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::unlock(buffer_handle_t _Nonnull buffer,
+                                           int* _Nonnull releaseFence) {
+    VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer)
+    int ret = mDriver->unlock(buffer, releaseFence);
+    if (ret) {
+        ALOGE("Failed to unlock.");
+        return AIMAPPER_ERROR_BAD_BUFFER;
+    }
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::flushLockedBuffer(buffer_handle_t _Nonnull buffer) {
+    VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer)
+    int ret = mDriver->flush(buffer);
+    if (ret) {
+        ALOGE("Failed to flushLockedBuffer. Flush failed.");
+        return AIMAPPER_ERROR_BAD_BUFFER;
+    }
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::rereadLockedBuffer(buffer_handle_t _Nonnull buffer) {
+    VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer)
+    int ret = mDriver->invalidate(buffer);
+    if (ret) {
+        ALOGE("Failed to rereadLockedBuffer. Failed to invalidate.");
+        return AIMAPPER_ERROR_BAD_BUFFER;
+    }
+
+    return AIMAPPER_ERROR_NONE;
+}
+
+int32_t CrosGrallocMapperV5::getMetadata(buffer_handle_t _Nonnull buffer,
+                                         AIMapper_MetadataType metadataType, void* _Nonnull outData,
+                                         size_t outDataSize) {
+    // We don't have any vendor-specific metadata, so divert to getStandardMetadata after validating
+    // that this is a standard metadata request
+    if (isStandardMetadata(metadataType)) {
+        return getStandardMetadata(buffer, metadataType.value, outData, outDataSize);
+    }
+    return -AIMAPPER_ERROR_UNSUPPORTED;
+}
+
+int32_t CrosGrallocMapperV5::getStandardMetadata(buffer_handle_t _Nonnull bufferHandle,
+                                                 int64_t standardType, void* _Nonnull outData,
+                                                 size_t outDataSize) {
+    // Can't use VALIDATE_DRIVER_AND_BUFFER_HANDLE because we need to negate the error
+    // for this call
+    if (!mDriver) {
+        ALOGE("Failed to %s. Driver is uninitialized.", __func__);
+        return -AIMAPPER_ERROR_NO_RESOURCES;
+    }
+    if (!(bufferHandle)) {
+        ALOGE("Failed to %s. Null buffer_handle_t.", __func__);
+        return -AIMAPPER_ERROR_BAD_BUFFER;
+    }
+
+    cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
+    if (!crosHandle) {
+        ALOGE("Failed to get. Invalid handle.");
+        return -AIMAPPER_ERROR_BAD_BUFFER;
+    }
+
+    int32_t retValue = -AIMAPPER_ERROR_UNSUPPORTED;
+    mDriver->with_buffer(crosHandle, [&](cros_gralloc_buffer* crosBuffer) {
+        auto provider = [&]<StandardMetadataType T>(auto&& provide) -> int32_t {
+            return getStandardMetadata(crosBuffer, provide, StandardMetadata<T>{});
+        };
+        retValue = provideStandardMetadata(static_cast<StandardMetadataType>(standardType), outData,
+                                           outDataSize, provider);
+    });
+    return retValue;
+}
+
+template <typename F, StandardMetadataType metadataType>
+int32_t CrosGrallocMapperV5::getStandardMetadata(const cros_gralloc_buffer* crosBuffer, F&& provide,
+                                                 StandardMetadata<metadataType>) {
+    const CrosGralloc4Metadata* crosMetadata = nullptr;
+    if constexpr (metadataType == StandardMetadataType::BLEND_MODE ||
+                  metadataType == StandardMetadataType::CTA861_3 ||
+                  metadataType == StandardMetadataType::DATASPACE ||
+                  metadataType == StandardMetadataType::NAME ||
+                  metadataType == StandardMetadataType::SMPTE2086) {
+        AIMapper_Error error = getCrosMetadata(crosBuffer, &crosMetadata);
+        if (error != AIMAPPER_ERROR_NONE) {
+            ALOGE("Failed to get. Failed to get buffer metadata.");
+            return -AIMAPPER_ERROR_NO_RESOURCES;
+        }
+    }
+    if constexpr (metadataType == StandardMetadataType::BUFFER_ID) {
+        return provide(crosBuffer->get_id());
+    }
+    if constexpr (metadataType == StandardMetadataType::NAME) {
+        return provide(crosMetadata->name);
+    }
+    if constexpr (metadataType == StandardMetadataType::WIDTH) {
+        return provide(crosBuffer->get_width());
+    }
+    if constexpr (metadataType == StandardMetadataType::STRIDE) {
+        return provide(crosBuffer->get_pixel_stride());
+    }
+    if constexpr (metadataType == StandardMetadataType::HEIGHT) {
+        return provide(crosBuffer->get_height());
+    }
+    if constexpr (metadataType == StandardMetadataType::LAYER_COUNT) {
+        return provide(1);
+    }
+    if constexpr (metadataType == StandardMetadataType::PIXEL_FORMAT_REQUESTED) {
+        return provide(static_cast<PixelFormat>(crosBuffer->get_android_format()));
+    }
+    if constexpr (metadataType == StandardMetadataType::PIXEL_FORMAT_FOURCC) {
+        return provide(drv_get_standard_fourcc(crosBuffer->get_format()));
+    }
+    if constexpr (metadataType == StandardMetadataType::PIXEL_FORMAT_MODIFIER) {
+        return provide(crosBuffer->get_format_modifier());
+    }
+    if constexpr (metadataType == StandardMetadataType::USAGE) {
+        return provide(static_cast<BufferUsage>(crosBuffer->get_android_usage()));
+    }
+    if constexpr (metadataType == StandardMetadataType::ALLOCATION_SIZE) {
+        return provide(crosBuffer->get_total_size());
+    }
+    if constexpr (metadataType == StandardMetadataType::PROTECTED_CONTENT) {
+        uint64_t hasProtectedContent =
+                crosBuffer->get_android_usage() & static_cast<int64_t>(BufferUsage::PROTECTED) ? 1
+                                                                                               : 0;
+        return provide(hasProtectedContent);
+    }
+    if constexpr (metadataType == StandardMetadataType::COMPRESSION) {
+        return provide(android::gralloc4::Compression_None);
+    }
+    if constexpr (metadataType == StandardMetadataType::INTERLACED) {
+        return provide(android::gralloc4::Interlaced_None);
+    }
+    if constexpr (metadataType == StandardMetadataType::CHROMA_SITING) {
+        return provide(android::gralloc4::ChromaSiting_None);
+    }
+    if constexpr (metadataType == StandardMetadataType::PLANE_LAYOUTS) {
+        std::vector<PlaneLayout> planeLayouts;
+        getPlaneLayouts(crosBuffer->get_format(), &planeLayouts);
+
+        for (size_t plane = 0; plane < planeLayouts.size(); plane++) {
+            PlaneLayout& planeLayout = planeLayouts[plane];
+            planeLayout.offsetInBytes = crosBuffer->get_plane_offset(plane);
+            planeLayout.strideInBytes = crosBuffer->get_plane_stride(plane);
+            planeLayout.totalSizeInBytes = crosBuffer->get_plane_size(plane);
+            planeLayout.widthInSamples =
+                    crosBuffer->get_width() / planeLayout.horizontalSubsampling;
+            planeLayout.heightInSamples =
+                    crosBuffer->get_height() / planeLayout.verticalSubsampling;
+        }
+
+        return provide(planeLayouts);
+    }
+    if constexpr (metadataType == StandardMetadataType::CROP) {
+        const uint32_t numPlanes = crosBuffer->get_num_planes();
+        const uint32_t w = crosBuffer->get_width();
+        const uint32_t h = crosBuffer->get_height();
+        std::vector<aidl::android::hardware::graphics::common::Rect> crops;
+        for (uint32_t plane = 0; plane < numPlanes; plane++) {
+            aidl::android::hardware::graphics::common::Rect crop;
+            crop.left = 0;
+            crop.top = 0;
+            crop.right = w;
+            crop.bottom = h;
+            crops.push_back(crop);
+        }
+
+        return provide(crops);
+    }
+    if constexpr (metadataType == StandardMetadataType::DATASPACE) {
+        return provide(crosMetadata->dataspace);
+    }
+    if constexpr (metadataType == StandardMetadataType::BLEND_MODE) {
+        return provide(crosMetadata->blendMode);
+    }
+    if constexpr (metadataType == StandardMetadataType::SMPTE2086) {
+        return crosMetadata->smpte2086 ? provide(*crosMetadata->smpte2086) : 0;
+    }
+    if constexpr (metadataType == StandardMetadataType::CTA861_3) {
+        return crosMetadata->cta861_3 ? provide(*crosMetadata->cta861_3) : 0;
+    }
+    return -AIMAPPER_ERROR_UNSUPPORTED;
+}
+
+AIMapper_Error CrosGrallocMapperV5::setMetadata(buffer_handle_t _Nonnull buffer,
+                                                AIMapper_MetadataType metadataType,
+                                                const void* _Nonnull metadata,
+                                                size_t metadataSize) {
+    // We don't have any vendor-specific metadata, so divert to setStandardMetadata after validating
+    // that this is a standard metadata request
+    if (isStandardMetadata(metadataType)) {
+        return setStandardMetadata(buffer, metadataType.value, metadata, metadataSize);
+    }
+    return AIMAPPER_ERROR_UNSUPPORTED;
+}
+
+AIMapper_Error CrosGrallocMapperV5::setStandardMetadata(buffer_handle_t _Nonnull bufferHandle,
+                                                        int64_t standardTypeRaw,
+                                                        const void* _Nonnull metadata,
+                                                        size_t metadataSize) {
+    VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle)
+
+    cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
+    if (!crosHandle) {
+        ALOGE("Failed to get. Invalid handle.");
+        return AIMAPPER_ERROR_BAD_BUFFER;
+    }
+
+    auto standardType = static_cast<StandardMetadataType>(standardTypeRaw);
+
+    switch (standardType) {
+        // Read-only values
+        case StandardMetadataType::BUFFER_ID:
+        case StandardMetadataType::NAME:
+        case StandardMetadataType::WIDTH:
+        case StandardMetadataType::HEIGHT:
+        case StandardMetadataType::LAYER_COUNT:
+        case StandardMetadataType::PIXEL_FORMAT_REQUESTED:
+        case StandardMetadataType::USAGE:
+            return AIMAPPER_ERROR_BAD_VALUE;
+
+        // Supported to set
+        case StandardMetadataType::BLEND_MODE:
+        case StandardMetadataType::CTA861_3:
+        case StandardMetadataType::DATASPACE:
+        case StandardMetadataType::SMPTE2086:
+            break;
+
+        // Everything else unsupported
+        default:
+            return AIMAPPER_ERROR_UNSUPPORTED;
+    }
+
+    AIMapper_Error status = AIMAPPER_ERROR_UNSUPPORTED;
+    mDriver->with_buffer(crosHandle, [&](cros_gralloc_buffer* crosBuffer) {
+        CrosGralloc4Metadata* crosMetadata = nullptr;
+        status = getMutableCrosMetadata(crosBuffer, &crosMetadata);
+        if (status != AIMAPPER_ERROR_NONE) {
+            return;
+        }
+
+        auto applier = [&]<StandardMetadataType T>(auto&& value) -> AIMapper_Error {
+            return setStandardMetadata<T>(crosMetadata, std::forward<decltype(value)>(value));
+        };
+
+        status = applyStandardMetadata(standardType, metadata, metadataSize, applier);
+    });
+    return status;
+}
+
+template <StandardMetadataType TYPE>
+AIMapper_Error CrosGrallocMapperV5::setStandardMetadata(
+        CrosGralloc4Metadata* crosMetadata, typename StandardMetadata<TYPE>::value_type&& value) {
+    if constexpr (TYPE == StandardMetadataType::BLEND_MODE) {
+        crosMetadata->blendMode = value;
+    }
+    if constexpr (TYPE == StandardMetadataType::CTA861_3) {
+        crosMetadata->cta861_3 = value;
+    }
+    if constexpr (TYPE == StandardMetadataType::DATASPACE) {
+        crosMetadata->dataspace = value;
+    }
+    if constexpr (TYPE == StandardMetadataType::SMPTE2086) {
+        crosMetadata->smpte2086 = value;
+    }
+    // Unsupported metadatas were already filtered before we reached this point
+    return AIMAPPER_ERROR_NONE;
+}
+
+constexpr AIMapper_MetadataTypeDescription describeStandard(StandardMetadataType type,
+                                                            bool isGettable, bool isSettable) {
+    return {{STANDARD_METADATA_NAME, static_cast<int64_t>(type)},
+            nullptr,
+            isGettable,
+            isSettable,
+            {0}};
+}
+
+AIMapper_Error CrosGrallocMapperV5::listSupportedMetadataTypes(
+        const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+        size_t* _Nonnull outNumberOfDescriptions) {
+    static constexpr std::array<AIMapper_MetadataTypeDescription, 22> sSupportedMetadaTypes{
+            describeStandard(StandardMetadataType::BUFFER_ID, true, false),
+            describeStandard(StandardMetadataType::NAME, true, false),
+            describeStandard(StandardMetadataType::WIDTH, true, false),
+            describeStandard(StandardMetadataType::HEIGHT, true, false),
+            describeStandard(StandardMetadataType::LAYER_COUNT, true, false),
+            describeStandard(StandardMetadataType::PIXEL_FORMAT_REQUESTED, true, false),
+            describeStandard(StandardMetadataType::PIXEL_FORMAT_FOURCC, true, false),
+            describeStandard(StandardMetadataType::PIXEL_FORMAT_MODIFIER, true, false),
+            describeStandard(StandardMetadataType::USAGE, true, false),
+            describeStandard(StandardMetadataType::ALLOCATION_SIZE, true, false),
+            describeStandard(StandardMetadataType::PROTECTED_CONTENT, true, false),
+            describeStandard(StandardMetadataType::COMPRESSION, true, false),
+            describeStandard(StandardMetadataType::INTERLACED, true, false),
+            describeStandard(StandardMetadataType::CHROMA_SITING, true, false),
+            describeStandard(StandardMetadataType::PLANE_LAYOUTS, true, false),
+            describeStandard(StandardMetadataType::CROP, true, false),
+            describeStandard(StandardMetadataType::DATASPACE, true, true),
+            describeStandard(StandardMetadataType::COMPRESSION, true, false),
+            describeStandard(StandardMetadataType::BLEND_MODE, true, true),
+            describeStandard(StandardMetadataType::SMPTE2086, true, true),
+            describeStandard(StandardMetadataType::CTA861_3, true, true),
+            describeStandard(StandardMetadataType::STRIDE, true, false),
+    };
+    *outDescriptionList = sSupportedMetadaTypes.data();
+    *outNumberOfDescriptions = sSupportedMetadaTypes.size();
+    return AIMAPPER_ERROR_NONE;
+}
+
+void CrosGrallocMapperV5::dumpBuffer(
+        const cros_gralloc_buffer* crosBuffer,
+        std::function<void(AIMapper_MetadataType, const std::vector<uint8_t>&)> callback) {
+    // Temp buffer of ~10kb, should be large enough for any of the metadata we want to dump
+    std::vector<uint8_t> tempBuffer;
+    tempBuffer.resize(10000);
+    AIMapper_MetadataType metadataType;
+    metadataType.name = STANDARD_METADATA_NAME;
+
+    // Take an instance of the empty StandardMetadat<T> class just to allow auto-deduction
+    // to happen as explicit template invocation on lambdas is ugly
+    auto dump = [&]<StandardMetadataType T>(StandardMetadata<T>) {
+        // Nested templated lambdas! Woo! But the cleanness of the result is worth it
+        // The outer lambda exists basically just to capture the StandardMetadataType that's
+        // being dumped, as the `provider` parameter of getStandardMetadata only knows
+        // the value_type that the enum maps to but not the enum value itself, which we need to
+        // construct the `AIMapper_MetadataType` to pass to the dump callback
+        auto dumpInner = [&](const typename StandardMetadata<T>::value_type& value) -> int32_t {
+            int32_t size =
+                    StandardMetadata<T>::value::encode(value, tempBuffer.data(), tempBuffer.size());
+            // The initial size should always be large enough, but just in case...
+            if (size > tempBuffer.size()) {
+                tempBuffer.resize(size * 2);
+                size = StandardMetadata<T>::value::encode(value, tempBuffer.data(),
+                                                          tempBuffer.size());
+            }
+            // If the first resize failed _somehow_, just give up. Also don't notify if any
+            // errors occurred during encoding.
+            if (size >= 0 && size <= tempBuffer.size()) {
+                metadataType.value = static_cast<int64_t>(T);
+                callback(metadataType, tempBuffer);
+            }
+            // We don't actually care about the return value in this case, but why not use the
+            // real value anyway
+            return size;
+        };
+        getStandardMetadata(crosBuffer, dumpInner, StandardMetadata<T>{});
+    };
+
+    // So clean. So pretty.
+    dump(StandardMetadata<StandardMetadataType::BUFFER_ID>{});
+    dump(StandardMetadata<StandardMetadataType::NAME>{});
+    dump(StandardMetadata<StandardMetadataType::WIDTH>{});
+    dump(StandardMetadata<StandardMetadataType::HEIGHT>{});
+    dump(StandardMetadata<StandardMetadataType::LAYER_COUNT>{});
+    dump(StandardMetadata<StandardMetadataType::PIXEL_FORMAT_REQUESTED>{});
+    dump(StandardMetadata<StandardMetadataType::PIXEL_FORMAT_FOURCC>{});
+    dump(StandardMetadata<StandardMetadataType::PIXEL_FORMAT_MODIFIER>{});
+    dump(StandardMetadata<StandardMetadataType::USAGE>{});
+    dump(StandardMetadata<StandardMetadataType::ALLOCATION_SIZE>{});
+    dump(StandardMetadata<StandardMetadataType::PROTECTED_CONTENT>{});
+    dump(StandardMetadata<StandardMetadataType::COMPRESSION>{});
+    dump(StandardMetadata<StandardMetadataType::INTERLACED>{});
+    dump(StandardMetadata<StandardMetadataType::CHROMA_SITING>{});
+    dump(StandardMetadata<StandardMetadataType::PLANE_LAYOUTS>{});
+    dump(StandardMetadata<StandardMetadataType::DATASPACE>{});
+    dump(StandardMetadata<StandardMetadataType::BLEND_MODE>{});
+}
+
+AIMapper_Error CrosGrallocMapperV5::dumpBuffer(
+        buffer_handle_t _Nonnull bufferHandle,
+        AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback, void* _Null_unspecified context) {
+    VALIDATE_DRIVER_AND_BUFFER_HANDLE(bufferHandle)
+    cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
+    if (!crosHandle) {
+        ALOGE("Failed to get. Invalid handle.");
+        return AIMAPPER_ERROR_BAD_BUFFER;
+    }
+    auto callback = [&](AIMapper_MetadataType type, const std::vector<uint8_t>& buffer) {
+        dumpBufferCallback(context, type, buffer.data(), buffer.size());
+    };
+    mDriver->with_buffer(
+            crosHandle, [&](cros_gralloc_buffer* crosBuffer) { dumpBuffer(crosBuffer, callback); });
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::dumpAllBuffers(
+        AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
+        AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback, void* _Null_unspecified context) {
+    REQUIRE_DRIVER()
+    auto callback = [&](AIMapper_MetadataType type, const std::vector<uint8_t>& buffer) {
+        dumpBufferCallback(context, type, buffer.data(), buffer.size());
+    };
+    mDriver->with_each_buffer([&](cros_gralloc_buffer* crosBuffer) {
+        beginDumpBufferCallback(context);
+        dumpBuffer(crosBuffer, callback);
+    });
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::getReservedRegion(buffer_handle_t _Nonnull buffer,
+                                                      void* _Nullable* _Nonnull outReservedRegion,
+                                                      uint64_t* _Nonnull outReservedSize) {
+    VALIDATE_DRIVER_AND_BUFFER_HANDLE(buffer)
+    cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(buffer);
+    if (!crosHandle) {
+        ALOGE("Failed to getReservedRegion. Invalid handle.");
+        return AIMAPPER_ERROR_BAD_BUFFER;
+    }
+
+    void* reservedRegionAddr = nullptr;
+    uint64_t reservedRegionSize = 0;
+
+    AIMapper_Error error = AIMAPPER_ERROR_NONE;
+    mDriver->with_buffer(crosHandle, [&, this](cros_gralloc_buffer* crosBuffer) {
+        error = getReservedRegionArea(crosBuffer, ReservedRegionArea::USER_METADATA,
+                                      &reservedRegionAddr, &reservedRegionSize);
+    });
+
+    if (error != AIMAPPER_ERROR_NONE) {
+        ALOGE("Failed to getReservedRegion. Failed to getReservedRegionArea.");
+        return AIMAPPER_ERROR_BAD_BUFFER;
+    }
+
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::getReservedRegionArea(const cros_gralloc_buffer* crosBuffer,
+                                                          ReservedRegionArea area, void** outAddr,
+                                                          uint64_t* outSize) {
+    int ret = crosBuffer->get_reserved_region(outAddr, outSize);
+    if (ret) {
+        ALOGE("Failed to getReservedRegionArea.");
+        *outAddr = nullptr;
+        *outSize = 0;
+        return AIMAPPER_ERROR_NO_RESOURCES;
+    }
+
+    switch (area) {
+        case ReservedRegionArea::MAPPER4_METADATA: {
+            // CrosGralloc4Metadata resides at the beginning reserved region.
+            *outSize = sizeof(CrosGralloc4Metadata);
+            break;
+        }
+        case ReservedRegionArea::USER_METADATA: {
+            // User metadata resides after the CrosGralloc4Metadata.
+            *outAddr = reinterpret_cast<void*>(reinterpret_cast<char*>(*outAddr) +
+                                               sizeof(CrosGralloc4Metadata));
+            *outSize = *outSize - sizeof(CrosGralloc4Metadata);
+            break;
+        }
+    }
+
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::getCrosMetadata(const cros_gralloc_buffer* crosBuffer,
+                                                    const CrosGralloc4Metadata** outMetadata) {
+    void* addr = nullptr;
+    uint64_t size;
+
+    auto error =
+            getReservedRegionArea(crosBuffer, ReservedRegionArea::MAPPER4_METADATA, &addr, &size);
+    if (error != AIMAPPER_ERROR_NONE) {
+        return error;
+    }
+
+    *outMetadata = reinterpret_cast<const CrosGralloc4Metadata*>(addr);
+    return AIMAPPER_ERROR_NONE;
+}
+
+AIMapper_Error CrosGrallocMapperV5::getMutableCrosMetadata(cros_gralloc_buffer* crosBuffer,
+                                                           CrosGralloc4Metadata** outMetadata) {
+    void* addr = nullptr;
+    uint64_t size;
+
+    auto error =
+            getReservedRegionArea(crosBuffer, ReservedRegionArea::MAPPER4_METADATA, &addr, &size);
+    if (error != AIMAPPER_ERROR_NONE) {
+        return error;
+    }
+
+    *outMetadata = reinterpret_cast<CrosGralloc4Metadata*>(addr);
+    return AIMAPPER_ERROR_NONE;
+}
+
+extern "C" uint32_t ANDROID_HAL_MAPPER_VERSION = AIMAPPER_VERSION_5;
+
+extern "C" AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation) {
+    static vendor::mapper::IMapperProvider<CrosGrallocMapperV5> provider;
+    return provider.load(outImplementation);
+}
\ No newline at end of file
diff --git a/cros_gralloc/mapper_stablec/mapper.minigbm.xml b/cros_gralloc/mapper_stablec/mapper.minigbm.xml
new file mode 100644
index 0000000..282f7c8
--- /dev/null
+++ b/cros_gralloc/mapper_stablec/mapper.minigbm.xml
@@ -0,0 +1,9 @@
+<manifest version="1.0" type="device">
+    <hal format="native">
+        <name>mapper</name>
+        <version>5.0</version>
+        <interface>
+            <instance>minigbm</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/dri.c b/dri.c
index 7257c31..5a30a77 100644
--- a/dri.c
+++ b/dri.c
@@ -78,7 +78,7 @@
 	gem_close.handle = handle;
 	ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
 	if (ret)
-		drv_log("DRM_IOCTL_GEM_CLOSE failed (handle=%x) error %d\n", handle, ret);
+		drv_loge("DRM_IOCTL_GEM_CLOSE failed (handle=%x) error %d\n", handle, ret);
 }
 
 /*
@@ -135,7 +135,7 @@
 		close(prime_fd);
 
 		if (ret) {
-			drv_log("drmPrimeFDToHandle failed with %s\n", strerror(errno));
+			drv_loge("drmPrimeFDToHandle failed with %s\n", strerror(errno));
 			goto cleanup;
 		}
 
@@ -186,6 +186,20 @@
 	return ret;
 }
 
+const __DRIuseInvalidateExtension use_invalidate = {
+	.base = { __DRI_USE_INVALIDATE, 1 },
+};
+
+void *dri_dlopen(const char *dri_so_path)
+{
+	return dlopen(dri_so_path, RTLD_NOW | RTLD_GLOBAL);
+}
+
+void dri_dlclose(void *dri_so_handle)
+{
+	dlclose(dri_so_handle);
+}
+
 /*
  * The caller is responsible for setting drv->priv to a structure that derives from dri_driver.
  */
@@ -193,7 +207,7 @@
 {
 	char fname[128];
 	const __DRIextension **(*get_extensions)();
-	const __DRIextension *loader_extensions[] = { NULL };
+	const __DRIextension *loader_extensions[] = { &use_invalidate.base, NULL };
 
 	struct dri_driver *dri = drv->priv;
 	char *node_name = drmGetRenderDeviceNameFromFd(drv_get_fd(drv));
@@ -205,7 +219,7 @@
 	if (dri->fd < 0)
 		return -ENODEV;
 
-	dri->driver_handle = dlopen(dri_so_path, RTLD_NOW | RTLD_GLOBAL);
+	dri->driver_handle = dri_dlopen(dri_so_path);
 	if (!dri->driver_handle)
 		goto close_dri_fd;
 
@@ -253,7 +267,7 @@
 free_screen:
 	dri->core_extension->destroyScreen(dri->device);
 free_handle:
-	dlclose(dri->driver_handle);
+	dri_dlclose(dri->driver_handle);
 	dri->driver_handle = NULL;
 close_dri_fd:
 	close(dri->fd);
@@ -269,7 +283,7 @@
 
 	dri->core_extension->destroyContext(dri->context);
 	dri->core_extension->destroyScreen(dri->device);
-	dlclose(dri->driver_handle);
+	dri_dlclose(dri->driver_handle);
 	dri->driver_handle = NULL;
 	close(dri->fd);
 }
diff --git a/dri.h b/dri.h
index daadf30..8136f5c 100644
--- a/dri.h
+++ b/dri.h
@@ -26,6 +26,9 @@
 	const __DRIconfig **configs;
 };
 
+void *dri_dlopen(const char *dri_so_path);
+void dri_dlclose(void *dri_so_handle);
+
 int dri_init(struct driver *drv, const char *dri_so_path, const char *driver_suffix);
 void dri_close(struct driver *drv);
 int dri_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
diff --git a/drv.c b/drv.c
index ada02ba..cbd7b4b 100644
--- a/drv.c
+++ b/drv.c
@@ -30,15 +30,9 @@
 #ifdef DRV_I915
 extern const struct backend backend_i915;
 #endif
-#ifdef DRV_MEDIATEK
-extern const struct backend backend_mediatek;
-#endif
 #ifdef DRV_MSM
 extern const struct backend backend_msm;
 #endif
-#ifdef DRV_ROCKCHIP
-extern const struct backend backend_rockchip;
-#endif
 #ifdef DRV_VC4
 extern const struct backend backend_vc4;
 #endif
@@ -46,15 +40,47 @@
 // Dumb / generic drivers
 extern const struct backend backend_evdi;
 extern const struct backend backend_marvell;
+extern const struct backend backend_mediatek;
 extern const struct backend backend_meson;
 extern const struct backend backend_nouveau;
 extern const struct backend backend_komeda;
 extern const struct backend backend_radeon;
+extern const struct backend backend_rockchip;
+extern const struct backend backend_sun4i_drm;
 extern const struct backend backend_synaptics;
 extern const struct backend backend_virtgpu;
 extern const struct backend backend_udl;
 extern const struct backend backend_vkms;
 
+static const struct backend *drv_backend_list[] = {
+#ifdef DRV_AMDGPU
+	&backend_amdgpu,
+#endif
+#ifdef DRV_I915
+	&backend_i915,
+#endif
+#ifdef DRV_MSM
+	&backend_msm,
+#endif
+#ifdef DRV_VC4
+	&backend_vc4,
+#endif
+	&backend_evdi,	    &backend_komeda,	&backend_marvell, &backend_mediatek,
+	&backend_meson,	    &backend_nouveau,	&backend_radeon,  &backend_rockchip,
+	&backend_sun4i_drm, &backend_synaptics, &backend_udl,	  &backend_virtgpu,
+	&backend_vkms
+};
+
+void drv_preload(bool load)
+{
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(drv_backend_list); i++) {
+		const struct backend *b = drv_backend_list[i];
+		if (b->preload)
+			b->preload(load);
+	}
+}
+
 static const struct backend *drv_get_backend(int fd)
 {
 	drmVersionPtr drm_version;
@@ -65,32 +91,8 @@
 	if (!drm_version)
 		return NULL;
 
-	const struct backend *backend_list[] = {
-#ifdef DRV_AMDGPU
-		&backend_amdgpu,
-#endif
-#ifdef DRV_I915
-		&backend_i915,
-#endif
-#ifdef DRV_MEDIATEK
-		&backend_mediatek,
-#endif
-#ifdef DRV_MSM
-		&backend_msm,
-#endif
-#ifdef DRV_ROCKCHIP
-		&backend_rockchip,
-#endif
-#ifdef DRV_VC4
-		&backend_vc4,
-#endif
-		&backend_evdi,	   &backend_marvell, &backend_meson,	 &backend_nouveau,
-		&backend_komeda,   &backend_radeon,  &backend_synaptics, &backend_virtgpu,
-		&backend_udl,	   &backend_virtgpu, &backend_vkms
-	};
-
-	for (i = 0; i < ARRAY_SIZE(backend_list); i++) {
-		const struct backend *b = backend_list[i];
+	for (i = 0; i < ARRAY_SIZE(drv_backend_list); i++) {
+		const struct backend *b = drv_backend_list[i];
 		if (!strcmp(drm_version->name, b->name)) {
 			drmFreeVersion(drm_version);
 			return b;
@@ -258,7 +260,7 @@
 				if (ret) {
 					pthread_mutex_unlock(&drv->mappings_lock);
 					assert(ret);
-					drv_log("munmap failed\n");
+					drv_loge("munmap failed\n");
 					return;
 				}
 
@@ -438,7 +440,7 @@
 
 		seek_end = lseek(data->fds[plane], 0, SEEK_END);
 		if (seek_end == (off_t)(-1)) {
-			drv_log("lseek() failed with %s\n", strerror(errno));
+			drv_loge("lseek() failed with %s\n", strerror(errno));
 			goto destroy_bo;
 		}
 
@@ -449,7 +451,7 @@
 			bo->meta.sizes[plane] = data->offsets[plane + 1] - data->offsets[plane];
 
 		if ((int64_t)bo->meta.offsets[plane] + bo->meta.sizes[plane] > seek_end) {
-			drv_log("buffer size is too large.\n");
+			drv_loge("buffer size is too large.\n");
 			goto destroy_bo;
 		}
 
@@ -521,7 +523,7 @@
 	}
 
 	memcpy(mapping.vma->map_strides, bo->meta.strides, sizeof(mapping.vma->map_strides));
-	addr = drv->backend->bo_map(bo, mapping.vma, plane, map_flags);
+	addr = drv->backend->bo_map(bo, mapping.vma, map_flags);
 	if (addr == MAP_FAILED) {
 		*map_data = NULL;
 		free(mapping.vma);
@@ -660,7 +662,7 @@
 		ret = drmPrimeHandleToFD(bo->drv->fd, bo->handles[plane].u32, DRM_CLOEXEC, &fd);
 
 	if (ret)
-		drv_log("Failed to get plane fd: %s\n", strerror(errno));
+		drv_loge("Failed to get plane fd: %s\n", strerror(errno));
 
 	return (ret) ? ret : fd;
 }
@@ -744,7 +746,8 @@
 	return count;
 }
 
-void drv_log_prefix(const char *prefix, const char *file, int line, const char *format, ...)
+void drv_log_prefix(enum drv_log_level level, const char *prefix, const char *file, int line,
+		    const char *format, ...)
 {
 	char buf[50];
 	snprintf(buf, sizeof(buf), "[%s:%s(%d)]", prefix, basename(file), line);
@@ -752,10 +755,30 @@
 	va_list args;
 	va_start(args, format);
 #ifdef __ANDROID__
-	__android_log_vprint(ANDROID_LOG_ERROR, buf, format, args);
+	int prio = ANDROID_LOG_ERROR;
+	switch (level) {
+	case DRV_LOGV:
+		prio = ANDROID_LOG_VERBOSE;
+		break;
+	case DRV_LOGD:
+		prio = ANDROID_LOG_DEBUG;
+		break;
+	case DRV_LOGI:
+		prio = ANDROID_LOG_INFO;
+		break;
+	case DRV_LOGE:
+	default:
+		break;
+	};
+	__android_log_vprint(prio, buf, format, args);
 #else
-	fprintf(stderr, "%s ", buf);
-	vfprintf(stderr, format, args);
+	if (level == DRV_LOGE) {
+		fprintf(stderr, "%s ", buf);
+		vfprintf(stderr, format, args);
+	} else {
+		fprintf(stdout, "%s ", buf);
+		vfprintf(stdout, format, args);
+	}
 #endif
 	va_end(args);
 }
diff --git a/drv.h b/drv.h
index 3dffdff..b824fc5 100644
--- a/drv.h
+++ b/drv.h
@@ -41,6 +41,9 @@
 #define BO_USE_FRONT_RENDERING		(1ull << 16)
 #define BO_USE_RENDERSCRIPT		(1ull << 17)
 #define BO_USE_GPU_DATA_BUFFER		(1ull << 18)
+#define BO_USE_SENSOR_DIRECT_DATA	(1ull << 19)
+
+#define BO_USE_ARC_SCREEN_CAP_PROBED	(1ull << 63)
 
 /* Quirks for allocating a buffer. */
 #define BO_QUIRK_NONE			0
@@ -76,6 +79,10 @@
 #define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS fourcc_mod_code(INTEL, 6)
 #endif
 
+//TODO: remove this defination once drm_fourcc.h contains it.
+#ifndef I915_FORMAT_MOD_4_TILED
+#define I915_FORMAT_MOD_4_TILED         fourcc_mod_code(INTEL, 9)
+#endif
 // clang-format on
 struct driver;
 struct bo;
@@ -124,6 +131,8 @@
 	uint32_t refcount;
 };
 
+void drv_preload(bool load);
+
 struct driver *drv_create(int fd);
 
 void drv_destroy(struct driver *drv);
@@ -206,12 +215,25 @@
 
 uint32_t drv_get_max_texture_2d_size(struct driver *drv);
 
-#define drv_log(format, ...)                                                                       \
+enum drv_log_level {
+	DRV_LOGV,
+	DRV_LOGD,
+	DRV_LOGI,
+	DRV_LOGE,
+};
+
+#define _drv_log(level, format, ...)                                                               \
 	do {                                                                                       \
-		drv_log_prefix("minigbm", __FILE__, __LINE__, format, ##__VA_ARGS__);              \
+		drv_log_prefix(level, "minigbm", __FILE__, __LINE__, format, ##__VA_ARGS__);       \
 	} while (0)
 
-__attribute__((format(printf, 4, 5))) void drv_log_prefix(const char *prefix, const char *file,
+#define drv_loge(format, ...) _drv_log(DRV_LOGE, format, ##__VA_ARGS__)
+#define drv_logv(format, ...) _drv_log(DRV_LOGV, format, ##__VA_ARGS__)
+#define drv_logd(format, ...) _drv_log(DRV_LOGD, format, ##__VA_ARGS__)
+#define drv_logi(format, ...) _drv_log(DRV_LOGI, format, ##__VA_ARGS__)
+
+__attribute__((format(printf, 5, 6))) void drv_log_prefix(enum drv_log_level level,
+							  const char *prefix, const char *file,
 							  int line, const char *format, ...);
 
 #ifdef __cplusplus
diff --git a/drv_helpers.c b/drv_helpers.c
index 6ea4b8e..cd51881 100644
--- a/drv_helpers.c
+++ b/drv_helpers.c
@@ -163,7 +163,7 @@
 		return &packed_8bpp_layout;
 
 	default:
-		drv_log("UNKNOWN FORMAT %d\n", format);
+		drv_loge("UNKNOWN FORMAT %d\n", format);
 		return NULL;
 	}
 }
@@ -250,18 +250,30 @@
 	return stride * drv_height_from_format(format, height, plane);
 }
 
-static uint32_t subsample_stride(uint32_t stride, uint32_t format, size_t plane)
+static uint32_t subsample_stride(uint32_t stride, uint32_t stride_align, uint32_t format,
+				 size_t plane)
 {
+	uint32_t plane_stride = stride;
+
 	if (plane != 0) {
 		switch (format) {
 		case DRM_FORMAT_YVU420:
 		case DRM_FORMAT_YVU420_ANDROID:
-			stride = DIV_ROUND_UP(stride, 2);
+			plane_stride = DIV_ROUND_UP(plane_stride, 2);
 			break;
 		}
 	}
 
-	return stride;
+	plane_stride = ALIGN(plane_stride, stride_align);
+
+	if (format == DRM_FORMAT_YVU420_ANDROID) {
+		if (plane != 0)
+			assert(plane_stride == ALIGN(stride / 2, 16));
+		else
+			assert(plane_stride % 16 == 0);
+	}
+
+	return plane_stride;
 }
 
 /*
@@ -269,14 +281,17 @@
  * the first plane, height and a format. This function assumes there is just
  * one kernel buffer per buffer object.
  */
-int drv_bo_from_format(struct bo *bo, uint32_t stride, uint32_t aligned_height, uint32_t format)
+int drv_bo_from_format(struct bo *bo, uint32_t stride, uint32_t stride_align,
+		       uint32_t aligned_height, uint32_t format)
 {
 	uint32_t padding[DRV_MAX_PLANES] = { 0 };
-	return drv_bo_from_format_and_padding(bo, stride, aligned_height, format, padding);
+	return drv_bo_from_format_and_padding(bo, stride, stride_align, aligned_height, format,
+					      padding);
 }
 
-int drv_bo_from_format_and_padding(struct bo *bo, uint32_t stride, uint32_t aligned_height,
-				   uint32_t format, uint32_t padding[DRV_MAX_PLANES])
+int drv_bo_from_format_and_padding(struct bo *bo, uint32_t stride, uint32_t stride_align,
+				   uint32_t aligned_height, uint32_t format,
+				   uint32_t padding[DRV_MAX_PLANES])
 {
 	size_t p, num_planes;
 	uint32_t offset = 0;
@@ -287,16 +302,18 @@
 	/*
 	 * HAL_PIXEL_FORMAT_YV12 requires that (see <system/graphics.h>):
 	 *  - the aligned height is same as the buffer's height.
-	 *  - the chroma stride is 16 bytes aligned, i.e., the luma's strides
-	 *    is 32 bytes aligned.
+	 *  - the luma stride is 16 bytes aligned
+	 *  - the chroma stride is ALIGN(luma_stride / 2, 16)
 	 */
 	if (format == DRM_FORMAT_YVU420_ANDROID) {
 		assert(aligned_height == bo->meta.height);
-		assert(stride == ALIGN(stride, 32));
+		/* force 16 if the caller has no requirement */
+		if (stride_align <= 1)
+			stride_align = 16;
 	}
 
 	for (p = 0; p < num_planes; p++) {
-		bo->meta.strides[p] = subsample_stride(stride, format, p);
+		bo->meta.strides[p] = subsample_stride(stride, stride_align, format, p);
 		bo->meta.sizes[p] =
 		    drv_size_from_format(format, bo->meta.strides[p], aligned_height, p) +
 		    padding[p];
@@ -353,6 +370,9 @@
 		    DIV_ROUND_UP(aligned_width * layout_from_format(format)->bytes_per_pixel[0], 4);
 		create_dumb.bpp = 32;
 	} else {
+		/* Align for llvmpipe 64-byte tile size for dumb_driver */
+		aligned_width = ALIGN(aligned_width, MESA_LLVMPIPE_TILE_SIZE);
+		aligned_height = ALIGN(aligned_height, MESA_LLVMPIPE_TILE_SIZE);
 		create_dumb.bpp = layout_from_format(format)->bytes_per_pixel[0] * 8;
 	}
 	create_dumb.width = aligned_width;
@@ -361,11 +381,11 @@
 
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
 	if (ret) {
-		drv_log("DRM_IOCTL_MODE_CREATE_DUMB failed (%d, %d)\n", bo->drv->fd, errno);
+		drv_loge("DRM_IOCTL_MODE_CREATE_DUMB failed (%d, %d)\n", bo->drv->fd, errno);
 		return -errno;
 	}
 
-	drv_bo_from_format(bo, create_dumb.pitch, height, format);
+	drv_bo_from_format(bo, create_dumb.pitch, 1, height, format);
 
 	for (plane = 0; plane < bo->meta.num_planes; plane++)
 		bo->handles[plane].u32 = create_dumb.handle;
@@ -388,7 +408,7 @@
 	destroy_dumb.handle = bo->handles[0].u32;
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
 	if (ret) {
-		drv_log("DRM_IOCTL_MODE_DESTROY_DUMB failed (handle=%x)\n", bo->handles[0].u32);
+		drv_loge("DRM_IOCTL_MODE_DESTROY_DUMB failed (handle=%x)\n", bo->handles[0].u32);
 		return -errno;
 	}
 
@@ -414,8 +434,8 @@
 
 		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
 		if (ret) {
-			drv_log("DRM_IOCTL_GEM_CLOSE failed (handle=%x) error %d\n",
-				bo->handles[plane].u32, ret);
+			drv_loge("DRM_IOCTL_GEM_CLOSE failed (handle=%x) error %d\n",
+				 bo->handles[plane].u32, ret);
 			error = -errno;
 		}
 	}
@@ -436,7 +456,7 @@
 		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_handle);
 
 		if (ret) {
-			drv_log("DRM_IOCTL_PRIME_FD_TO_HANDLE failed (fd=%u)\n", prime_handle.fd);
+			drv_loge("DRM_IOCTL_PRIME_FD_TO_HANDLE failed (fd=%u)\n", prime_handle.fd);
 
 			/*
 			 * Need to call GEM close on planes that were opened,
@@ -456,24 +476,23 @@
 	return 0;
 }
 
-void *drv_dumb_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+void *drv_dumb_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	int ret;
 	size_t i;
 	struct drm_mode_map_dumb map_dumb;
 
 	memset(&map_dumb, 0, sizeof(map_dumb));
-	map_dumb.handle = bo->handles[plane].u32;
+	map_dumb.handle = bo->handles[0].u32;
 
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
 	if (ret) {
-		drv_log("DRM_IOCTL_MODE_MAP_DUMB failed\n");
+		drv_loge("DRM_IOCTL_MODE_MAP_DUMB failed\n");
 		return MAP_FAILED;
 	}
 
 	for (i = 0; i < bo->meta.num_planes; i++)
-		if (bo->handles[i].u32 == bo->handles[plane].u32)
-			vma->length += bo->meta.sizes[i];
+		vma->length += bo->meta.sizes[i];
 
 	return mmap(0, vma->length, drv_get_prot(map_flags), MAP_SHARED, bo->drv->fd,
 		    map_dumb.offset);
diff --git a/drv_helpers.h b/drv_helpers.h
index edb69bf..0ea9ba9 100644
--- a/drv_helpers.h
+++ b/drv_helpers.h
@@ -21,9 +21,11 @@
 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);
-int drv_bo_from_format(struct bo *bo, uint32_t stride, uint32_t aligned_height, uint32_t format);
-int drv_bo_from_format_and_padding(struct bo *bo, uint32_t stride, uint32_t aligned_height,
-				   uint32_t format, uint32_t padding[DRV_MAX_PLANES]);
+int drv_bo_from_format(struct bo *bo, uint32_t stride, uint32_t stride_align,
+		       uint32_t aligned_height, uint32_t format);
+int drv_bo_from_format_and_padding(struct bo *bo, uint32_t stride, uint32_t stride_align,
+				   uint32_t aligned_height, uint32_t format,
+				   uint32_t padding[DRV_MAX_PLANES]);
 int drv_dumb_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
 		       uint64_t use_flags);
 int drv_dumb_bo_create_ex(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
@@ -31,7 +33,7 @@
 int drv_dumb_bo_destroy(struct bo *bo);
 int drv_gem_bo_destroy(struct bo *bo);
 int drv_prime_bo_import(struct bo *bo, struct drv_import_fd_data *data);
-void *drv_dumb_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags);
+void *drv_dumb_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags);
 int drv_bo_munmap(struct bo *bo, struct vma *vma);
 int drv_get_prot(uint32_t map_flags);
 void drv_add_combination(struct driver *drv, uint32_t format, struct format_metadata *metadata,
diff --git a/drv_priv.h b/drv_priv.h
index d2da440..a2ccdda 100644
--- a/drv_priv.h
+++ b/drv_priv.h
@@ -74,6 +74,7 @@
 
 struct backend {
 	char *name;
+	void (*preload)(bool load);
 	int (*init)(struct driver *drv);
 	void (*close)(struct driver *drv);
 	int (*bo_create)(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
@@ -90,7 +91,7 @@
 	/* Called on free if this bo is the last object referencing the contained GEM BOs */
 	int (*bo_destroy)(struct bo *bo);
 	int (*bo_import)(struct bo *bo, struct drv_import_fd_data *data);
-	void *(*bo_map)(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags);
+	void *(*bo_map)(struct bo *bo, struct vma *vma, uint32_t map_flags);
 	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);
@@ -115,14 +116,24 @@
 #define BO_USE_SW_MASK (BO_USE_SW_READ_OFTEN | BO_USE_SW_WRITE_OFTEN | \
 			BO_USE_SW_READ_RARELY | BO_USE_SW_WRITE_RARELY | BO_USE_FRONT_RENDERING)
 
+#define BO_USE_GPU_HW (BO_USE_RENDERING | BO_USE_TEXTURE | BO_USE_GPU_DATA_BUFFER)
+
 #define BO_USE_NON_GPU_HW (BO_USE_SCANOUT | BO_USE_CAMERA_WRITE | BO_USE_CAMERA_READ | \
-			   BO_USE_HW_VIDEO_ENCODER | BO_USE_HW_VIDEO_DECODER)
+			   BO_USE_HW_VIDEO_ENCODER | BO_USE_HW_VIDEO_DECODER | BO_USE_SENSOR_DIRECT_DATA)
+
+#define BO_USE_HW_MASK	(BO_USE_GPU_HW | BO_USE_NON_GPU_HW)
 
 #ifndef DRM_FORMAT_MOD_LINEAR
 #define DRM_FORMAT_MOD_LINEAR DRM_FORMAT_MOD_NONE
 #endif
 
 #define LINEAR_METADATA (struct format_metadata) { 1, 0, DRM_FORMAT_MOD_LINEAR }
+
+#define MESA_LLVMPIPE_MAX_TEXTURE_2D_LEVELS 15
+#define MESA_LLVMPIPE_MAX_TEXTURE_2D_SIZE (1 << (MESA_LLVMPIPE_MAX_TEXTURE_2D_LEVELS - 1))
+#define MESA_LLVMPIPE_TILE_ORDER 6
+#define MESA_LLVMPIPE_TILE_SIZE (1 << MESA_LLVMPIPE_TILE_ORDER)
+
 // clang-format on
 
 #endif
diff --git a/dumb_driver.c b/dumb_driver.c
index c667a51..f74d237 100644
--- a/dumb_driver.c
+++ b/dumb_driver.c
@@ -10,9 +10,9 @@
 #include "drv_priv.h"
 #include "util.h"
 
-#define INIT_DUMB_DRIVER(driver)                                                                   \
+#define INIT_DUMB_DRIVER_WITH_NAME(driver, _name)                                                  \
 	const struct backend backend_##driver = {                                                  \
-		.name = #driver,                                                                   \
+		.name = _name,                                                                     \
 		.init = dumb_driver_init,                                                          \
 		.bo_create = drv_dumb_bo_create,                                                   \
 		.bo_create_with_modifiers = dumb_bo_create_with_modifiers,                         \
@@ -23,6 +23,8 @@
 		.resolve_format_and_use_flags = drv_resolve_format_and_use_flags_helper,           \
 	};
 
+#define INIT_DUMB_DRIVER(driver) INIT_DUMB_DRIVER_WITH_NAME(driver, #driver)
+
 static const uint32_t scanout_render_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888,
 						   DRM_FORMAT_ABGR8888, DRM_FORMAT_XBGR8888,
 						   DRM_FORMAT_BGR888,	DRM_FORMAT_RGB565 };
@@ -40,7 +42,8 @@
 
 	drv_modify_combination(drv, DRM_FORMAT_R8, &LINEAR_METADATA,
 			       BO_USE_HW_VIDEO_ENCODER | BO_USE_HW_VIDEO_DECODER |
-				   BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
+				   BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE |
+				   BO_USE_GPU_DATA_BUFFER | BO_USE_SENSOR_DIRECT_DATA);
 	drv_modify_combination(drv, DRM_FORMAT_NV12, &LINEAR_METADATA,
 			       BO_USE_HW_VIDEO_ENCODER | BO_USE_HW_VIDEO_DECODER |
 				   BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
@@ -67,6 +70,14 @@
 INIT_DUMB_DRIVER(meson)
 INIT_DUMB_DRIVER(nouveau)
 INIT_DUMB_DRIVER(radeon)
+INIT_DUMB_DRIVER_WITH_NAME(sun4i_drm, "sun4i-drm")
 INIT_DUMB_DRIVER(synaptics)
 INIT_DUMB_DRIVER(udl)
 INIT_DUMB_DRIVER(vkms)
+
+#ifndef DRV_ROCKCHIP
+INIT_DUMB_DRIVER(rockchip)
+#endif
+#ifndef DRV_MEDIATEK
+INIT_DUMB_DRIVER(mediatek)
+#endif
diff --git a/external/i915_drm.h b/external/i915_drm.h
index e301c5f..e009a9e 100644
--- a/external/i915_drm.h
+++ b/external/i915_drm.h
@@ -1306,7 +1306,8 @@
 #define I915_TILING_NONE	0
 #define I915_TILING_X		1
 #define I915_TILING_Y		2
-#define I915_TILING_LAST	I915_TILING_Y
+#define I915_TILING_4		9
+#define I915_TILING_LAST	I915_TILING_4
 
 #define I915_BIT_6_SWIZZLE_NONE		0
 #define I915_BIT_6_SWIZZLE_9		1
diff --git a/gbm.h b/gbm.h
index 9acfaa2..7fae11c 100644
--- a/gbm.h
+++ b/gbm.h
@@ -290,6 +290,21 @@
     * with pixel data.
     */
    GBM_BO_USE_FRONT_RENDERING = (1 << 16),
+
+   /**
+    * (1 << 17) is reserved for RenderScript (deprecated in Android 12).
+    */
+
+   /**
+    * The buffer will be used as a shader storage or uniform buffer
+    * object.
+    */
+   GBM_BO_USE_GPU_DATA_BUFFER = (1 << 18),
+
+   /**
+    * The buffer will be used as a sensor direct report output.
+    */
+   GBM_BO_USE_SENSOR_DIRECT_DATA = (1 << 19),
 };
 
 int
diff --git a/gbm_helpers.c b/gbm_helpers.c
index 17dcf1f..e5bcb40 100644
--- a/gbm_helpers.c
+++ b/gbm_helpers.c
@@ -46,6 +46,10 @@
 		use_flags |= BO_USE_HW_VIDEO_ENCODER;
 	if (usage & GBM_BO_USE_FRONT_RENDERING)
 		use_flags |= BO_USE_FRONT_RENDERING;
+	if (usage & GBM_BO_USE_GPU_DATA_BUFFER)
+		use_flags |= BO_USE_GPU_DATA_BUFFER;
+	if (usage & GBM_BO_USE_SENSOR_DIRECT_DATA)
+		use_flags |= BO_USE_SENSOR_DIRECT_DATA;
 
 	return use_flags;
 }
diff --git a/i915.c b/i915.c
index 35c45eb..8619580 100644
--- a/i915.c
+++ b/i915.c
@@ -44,18 +44,25 @@
 static const uint64_t gen11_modifier_order[] = { I915_FORMAT_MOD_Y_TILED, I915_FORMAT_MOD_X_TILED,
 						 DRM_FORMAT_MOD_LINEAR };
 
+static const uint64_t xe_lpdp_modifier_order[] = { I915_FORMAT_MOD_4_TILED, I915_FORMAT_MOD_X_TILED,
+						   DRM_FORMAT_MOD_LINEAR };
+
 struct modifier_support_t {
 	const uint64_t *order;
 	uint32_t count;
 };
 
 struct i915_device {
-	uint32_t gen;
+	uint32_t graphics_version;
 	int32_t has_llc;
 	int32_t has_hw_protection;
 	struct modifier_support_t modifier;
 	int device_id;
-	bool is_adlp;
+	bool is_xelpd;
+	/*TODO : cleanup is_mtl to avoid adding variables for every new platforms */
+	bool is_mtl;
+	int32_t num_fences_avail;
+	bool has_mmap_offset;
 };
 
 static void i915_info_from_device_id(struct i915_device *i915)
@@ -103,72 +110,91 @@
 		0x46b3, 0x46c0, 0x46c1, 0x46c2, 0x46c3, 0x9A40, 0x9A49, 0x9A59, 0x9A60, 0x9A68,
 		0x9A70, 0x9A78, 0x9AC0, 0x9AC9, 0x9AD9, 0x9AF8, 0x4905, 0x4906, 0x4907, 0x4908
 	};
-	const uint16_t adlp_ids[] = { 0x46A0, 0x46A1, 0x46A2, 0x46A3, 0x46A6, 0x46A8,
-				      0x46AA, 0x462A, 0x4626, 0x4628, 0x46B0, 0x46B1,
-				      0x46B2, 0x46B3, 0x46C0, 0x46C1, 0x46C2, 0x46C3,
-				      0x46D0, 0x46D1, 0x46D2 };
+	const uint16_t adlp_ids[] = { 0x46A0, 0x46A1, 0x46A2, 0x46A3, 0x46A6, 0x46A8, 0x46AA,
+				      0x462A, 0x4626, 0x4628, 0x46B0, 0x46B1, 0x46B2, 0x46B3,
+				      0x46C0, 0x46C1, 0x46C2, 0x46C3, 0x46D0, 0x46D1, 0x46D2 };
+
+	const uint16_t rplp_ids[] = { 0xA720, 0xA721, 0xA7A0, 0xA7A1, 0xA7A8, 0xA7A9 };
+
+	const uint16_t mtl_ids[] = { 0x7D40, 0x7D60, 0x7D45, 0x7D55, 0x7DD5 };
+
 	unsigned i;
-	i915->gen = 4;
-	i915->is_adlp = false;
+	i915->graphics_version = 4;
+	i915->is_xelpd = false;
+	i915->is_mtl = false;
 
 	for (i = 0; i < ARRAY_SIZE(gen3_ids); i++)
 		if (gen3_ids[i] == i915->device_id)
-			i915->gen = 3;
+			i915->graphics_version = 3;
 
 	/* Gen 4 */
 	for (i = 0; i < ARRAY_SIZE(gen4_ids); i++)
 		if (gen4_ids[i] == i915->device_id)
-			i915->gen = 4;
+			i915->graphics_version = 4;
 
 	/* Gen 5 */
 	for (i = 0; i < ARRAY_SIZE(gen5_ids); i++)
 		if (gen5_ids[i] == i915->device_id)
-			i915->gen = 5;
+			i915->graphics_version = 5;
 
 	/* Gen 6 */
 	for (i = 0; i < ARRAY_SIZE(gen6_ids); i++)
 		if (gen6_ids[i] == i915->device_id)
-			i915->gen = 6;
+			i915->graphics_version = 6;
 
 	/* Gen 7 */
 	for (i = 0; i < ARRAY_SIZE(gen7_ids); i++)
 		if (gen7_ids[i] == i915->device_id)
-			i915->gen = 7;
+			i915->graphics_version = 7;
 
 	/* Gen 8 */
 	for (i = 0; i < ARRAY_SIZE(gen8_ids); i++)
 		if (gen8_ids[i] == i915->device_id)
-			i915->gen = 8;
+			i915->graphics_version = 8;
 
 	/* Gen 9 */
 	for (i = 0; i < ARRAY_SIZE(gen9_ids); i++)
 		if (gen9_ids[i] == i915->device_id)
-			i915->gen = 9;
+			i915->graphics_version = 9;
 
 	/* Gen 11 */
 	for (i = 0; i < ARRAY_SIZE(gen11_ids); i++)
 		if (gen11_ids[i] == i915->device_id)
-			i915->gen = 11;
+			i915->graphics_version = 11;
 
 	/* Gen 12 */
 	for (i = 0; i < ARRAY_SIZE(gen12_ids); i++)
 		if (gen12_ids[i] == i915->device_id)
-			i915->gen = 12;
+			i915->graphics_version = 12;
 
 	for (i = 0; i < ARRAY_SIZE(adlp_ids); i++)
 		if (adlp_ids[i] == i915->device_id) {
-			i915->is_adlp = true;
-			i915->gen = 12;
+			i915->is_xelpd = true;
+			i915->graphics_version = 12;
+		}
+
+	for (i = 0; i < ARRAY_SIZE(rplp_ids); i++)
+		if (rplp_ids[i] == i915->device_id) {
+			i915->is_xelpd = true;
+			i915->graphics_version = 12;
+		}
+
+	for (i = 0; i < ARRAY_SIZE(mtl_ids); i++)
+		if (mtl_ids[i] == i915->device_id) {
+			i915->graphics_version = 12;
+			i915->is_mtl = true;
 		}
 }
 
 static void i915_get_modifier_order(struct i915_device *i915)
 {
-	if (i915->gen == 12) {
+	if (i915->is_mtl) {
+		i915->modifier.order = xe_lpdp_modifier_order;
+		i915->modifier.count = ARRAY_SIZE(xe_lpdp_modifier_order);
+	} else if (i915->graphics_version == 12) {
 		i915->modifier.order = gen12_modifier_order;
 		i915->modifier.count = ARRAY_SIZE(gen12_modifier_order);
-	}
-	else if (i915->gen == 11) {
+	} else if (i915->graphics_version == 11) {
 		i915->modifier.order = gen11_modifier_order;
 		i915->modifier.count = ARRAY_SIZE(gen11_modifier_order);
 	} else {
@@ -229,7 +255,8 @@
 	 */
 	drv_modify_combination(drv, DRM_FORMAT_R8, &metadata_linear,
 			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
-				   BO_USE_HW_VIDEO_ENCODER);
+				   BO_USE_HW_VIDEO_ENCODER | BO_USE_GPU_DATA_BUFFER |
+				   BO_USE_SENSOR_DIRECT_DATA);
 
 	const uint64_t render_not_linear = unset_flags(render, linear_mask);
 	const uint64_t scanout_and_render_not_linear = render_not_linear | BO_USE_SCANOUT;
@@ -243,34 +270,57 @@
 	drv_add_combinations(drv, scanout_render_formats, ARRAY_SIZE(scanout_render_formats),
 			     &metadata_x_tiled, scanout_and_render_not_linear);
 
-	struct format_metadata metadata_y_tiled = { .tiling = I915_TILING_Y,
-						    .priority = 3,
-						    .modifier = I915_FORMAT_MOD_Y_TILED };
-
+	if (i915->is_mtl) {
+		struct format_metadata metadata_4_tiled = { .tiling = I915_TILING_4,
+							    .priority = 3,
+							    .modifier = I915_FORMAT_MOD_4_TILED };
+/* Support tile4 NV12 and P010 for libva */
+#ifdef I915_SCANOUT_4_TILED
+		const uint64_t nv12_usage =
+		    BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER | BO_USE_SCANOUT | hw_protected;
+		const uint64_t p010_usage =
+		    BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER | hw_protected | BO_USE_SCANOUT;
+#else
+		const uint64_t nv12_usage = BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER;
+		const uint64_t p010_usage = nv12_usage;
+#endif
+		drv_add_combination(drv, DRM_FORMAT_NV12, &metadata_4_tiled, nv12_usage);
+		drv_add_combination(drv, DRM_FORMAT_P010, &metadata_4_tiled, p010_usage);
+		drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats),
+				     &metadata_4_tiled, render_not_linear);
+		drv_add_combinations(drv, scanout_render_formats,
+				     ARRAY_SIZE(scanout_render_formats), &metadata_4_tiled,
+				     render_not_linear);
+	} else {
+		struct format_metadata metadata_y_tiled = { .tiling = I915_TILING_Y,
+							    .priority = 3,
+							    .modifier = I915_FORMAT_MOD_Y_TILED };
 /* Support y-tiled NV12 and P010 for libva */
 #ifdef I915_SCANOUT_Y_TILED
-	const uint64_t nv12_usage =
-	    BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER | BO_USE_SCANOUT | hw_protected;
-	const uint64_t p010_usage = BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER | hw_protected |
-				    (i915->gen >= 11 ? BO_USE_SCANOUT : 0);
+		const uint64_t nv12_usage =
+		    BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER | BO_USE_SCANOUT | hw_protected;
+		const uint64_t p010_usage = BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER |
+					    hw_protected |
+					    (i915->graphics_version >= 11 ? BO_USE_SCANOUT : 0);
 #else
-	const uint64_t nv12_usage = BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER;
-	const uint64_t p010_usage = nv12_usage;
+		const uint64_t nv12_usage = BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER;
+		const uint64_t p010_usage = nv12_usage;
 #endif
-	drv_add_combination(drv, DRM_FORMAT_NV12, &metadata_y_tiled, nv12_usage);
-	drv_add_combination(drv, DRM_FORMAT_P010, &metadata_y_tiled, p010_usage);
-
-	drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats), &metadata_y_tiled,
-			     render_not_linear);
-
-	// Y-tiled scanout isn't available on old platforms so we add
-	// |scanout_render_formats| without that USE flag.
-	drv_add_combinations(drv, scanout_render_formats, ARRAY_SIZE(scanout_render_formats),
-			     &metadata_y_tiled, render_not_linear);
+		drv_add_combination(drv, DRM_FORMAT_NV12, &metadata_y_tiled, nv12_usage);
+		drv_add_combination(drv, DRM_FORMAT_P010, &metadata_y_tiled, p010_usage);
+		drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats),
+				     &metadata_y_tiled, render_not_linear);
+		/* Y-tiled scanout isn't available on old platforms so we add
+		 * |scanout_render_formats| without that USE flag.
+		 */
+		drv_add_combinations(drv, scanout_render_formats,
+				     ARRAY_SIZE(scanout_render_formats), &metadata_y_tiled,
+				     render_not_linear);
+	}
 	return 0;
 }
 
-static int i915_align_dimensions(struct bo *bo, uint32_t tiling, uint32_t *stride,
+static int i915_align_dimensions(struct bo *bo, uint32_t format, uint32_t tiling, uint32_t *stride,
 				 uint32_t *aligned_height)
 {
 	struct i915_device *i915 = bo->drv->priv;
@@ -296,7 +346,24 @@
 #else
 		horizontal_alignment = 64;
 #endif
-		vertical_alignment = 4;
+		/*
+		 * For R8 and height=1, we assume the surface will be used as a linear buffer blob
+		 * (such as VkBuffer). The hardware allows vertical_alignment=1 only for non-tiled
+		 * 1D surfaces, which covers the VkBuffer case. However, if the app uses the surface
+		 * as a 2D image with height=1, then this code is buggy. For 2D images, the hardware
+		 * requires a vertical_alignment >= 4, and underallocating with vertical_alignment=1
+		 * will cause the GPU to read out-of-bounds.
+		 *
+		 * TODO: add a new DRM_FORMAT_BLOB format for this case, or further tighten up the
+		 * constraints with GPU_DATA_BUFFER usage when the guest has migrated to use
+		 * virtgpu_cross_domain backend which passes that flag through.
+		 */
+		if (format == DRM_FORMAT_R8 && *aligned_height == 1) {
+			vertical_alignment = 1;
+		} else {
+			vertical_alignment = 4;
+		}
+
 		break;
 
 	case I915_TILING_X:
@@ -305,7 +372,8 @@
 		break;
 
 	case I915_TILING_Y:
-		if (i915->gen == 3) {
+	case I915_TILING_4:
+		if (i915->graphics_version == 3) {
 			horizontal_alignment = 512;
 			vertical_alignment = 8;
 		} else {
@@ -316,7 +384,7 @@
 	}
 
 	*aligned_height = ALIGN(*aligned_height, vertical_alignment);
-	if (i915->gen > 3) {
+	if (i915->graphics_version > 3) {
 		*stride = ALIGN(*stride, horizontal_alignment);
 	} else {
 		while (*stride > horizontal_alignment)
@@ -325,7 +393,7 @@
 		*stride = horizontal_alignment;
 	}
 
-	if (i915->gen <= 3 && *stride > 8192)
+	if (i915->graphics_version <= 3 && *stride > 8192)
 		return -EINVAL;
 
 	return 0;
@@ -345,7 +413,7 @@
 
 static int i915_init(struct driver *drv)
 {
-	int ret;
+	int ret, val;
 	struct i915_device *i915;
 	drm_i915_getparam_t get_param = { 0 };
 
@@ -357,11 +425,11 @@
 	get_param.value = &(i915->device_id);
 	ret = drmIoctl(drv->fd, DRM_IOCTL_I915_GETPARAM, &get_param);
 	if (ret) {
-		drv_log("Failed to get I915_PARAM_CHIPSET_ID\n");
+		drv_loge("Failed to get I915_PARAM_CHIPSET_ID\n");
 		free(i915);
 		return -EINVAL;
 	}
-	/* must call before i915->gen is used anywhere else */
+	/* must call before i915->graphics_version is used anywhere else */
 	i915_info_from_device_id(i915);
 
 	i915_get_modifier_order(i915);
@@ -371,12 +439,34 @@
 	get_param.value = &i915->has_llc;
 	ret = drmIoctl(drv->fd, DRM_IOCTL_I915_GETPARAM, &get_param);
 	if (ret) {
-		drv_log("Failed to get I915_PARAM_HAS_LLC\n");
+		drv_loge("Failed to get I915_PARAM_HAS_LLC\n");
 		free(i915);
 		return -EINVAL;
 	}
 
-	if (i915->gen >= 12)
+	memset(&get_param, 0, sizeof(get_param));
+	get_param.param = I915_PARAM_NUM_FENCES_AVAIL;
+	get_param.value = &i915->num_fences_avail;
+	ret = drmIoctl(drv->fd, DRM_IOCTL_I915_GETPARAM, &get_param);
+	if (ret) {
+		drv_loge("Failed to get I915_PARAM_NUM_FENCES_AVAIL\n");
+		free(i915);
+		return -EINVAL;
+	}
+
+	memset(&get_param, 0, sizeof(get_param));
+	get_param.param = I915_PARAM_MMAP_GTT_VERSION;
+	get_param.value = &val;
+
+	ret = drmIoctl(drv->fd, DRM_IOCTL_I915_GETPARAM, &get_param);
+	if (ret) {
+		drv_loge("Failed to get I915_PARAM_MMAP_GTT_VERSION\n");
+		free(i915);
+		return -EINVAL;
+	}
+	i915->has_mmap_offset = (val >= 4);
+
+	if (i915->graphics_version >= 12)
 		i915->has_hw_protection = 1;
 
 	drv->priv = i915;
@@ -395,7 +485,7 @@
 	case DRM_FORMAT_NV12:
 	case DRM_FORMAT_P010:
 	case DRM_FORMAT_P016:
-		return (i915->gen == 11 || i915->gen == 12) && plane == 1;
+		return (i915->graphics_version == 11 || i915->graphics_version == 12) && plane == 1;
 	}
 	return false;
 }
@@ -417,7 +507,7 @@
 		if (bo->meta.tiling != I915_TILING_NONE)
 			assert(IS_ALIGNED(offset, pagesize));
 
-		ret = i915_align_dimensions(bo, bo->meta.tiling, &stride, &plane_height);
+		ret = i915_align_dimensions(bo, format, bo->meta.tiling, &stride, &plane_height);
 		if (ret)
 			return ret;
 
@@ -441,8 +531,7 @@
 	return 0;
 }
 
-static size_t i915_num_planes_from_modifier(struct driver *drv, uint32_t format,
-					    uint64_t modifier)
+static size_t i915_num_planes_from_modifier(struct driver *drv, uint32_t format, uint64_t modifier)
 {
 	size_t num_planes = drv_num_planes_from_format(format);
 	if (modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
@@ -459,7 +548,7 @@
 {
 	uint64_t modifier;
 	struct i915_device *i915 = bo->drv->priv;
-	bool huge_bo = (i915->gen < 11) && (width > 4096);
+	bool huge_bo = (i915->graphics_version < 11) && (width > 4096);
 
 	if (modifiers) {
 		modifier =
@@ -505,7 +594,7 @@
 	}
 
 	/* Prevent gen 8 and earlier from trying to use a tiling modifier */
-	if (i915->gen <= 8 && format == DRM_FORMAT_ARGB8888) {
+	if (i915->graphics_version <= 8 && format == DRM_FORMAT_ARGB8888) {
 		modifier = DRM_FORMAT_MOD_LINEAR;
 	}
 
@@ -524,6 +613,9 @@
 	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
 		bo->meta.tiling = I915_TILING_Y;
 		break;
+	case I915_FORMAT_MOD_4_TILED:
+		bo->meta.tiling = I915_TILING_4;
+		break;
 	}
 
 	bo->meta.format_modifier = modifier;
@@ -538,7 +630,7 @@
 		 * aligning to 32 bytes here.
 		 */
 		uint32_t stride = ALIGN(width, 32);
-		drv_bo_from_format(bo, stride, height, format);
+		return drv_bo_from_format(bo, stride, 1, height, format);
 	} else if (modifier == I915_FORMAT_MOD_Y_TILED_CCS) {
 		/*
 		 * For compressed surfaces, we need a color control surface
@@ -593,7 +685,7 @@
 
 		height = ALIGN(drv_height_from_format(format, height, 0), 32);
 
-		if (i915->is_adlp && (stride > 1)) {
+		if (i915->is_xelpd && (stride > 1)) {
 			stride = 1 << (32 - __builtin_clz(stride - 1));
 			height = ALIGN(drv_height_from_format(format, height, 0), 128);
 		}
@@ -616,7 +708,7 @@
 		bo->meta.num_planes = i915_num_planes_from_modifier(bo->drv, format, modifier);
 		bo->meta.total_size = bo->meta.sizes[0] + bo->meta.sizes[1];
 	} else {
-		i915_bo_from_format(bo, width, height, format);
+		return i915_bo_from_format(bo, width, height, format);
 	}
 	return 0;
 }
@@ -642,8 +734,8 @@
 
 		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext);
 		if (ret) {
-			drv_log("DRM_IOCTL_I915_GEM_CREATE_EXT failed (size=%llu) (ret=%d) \n",
-				create_ext.size, ret);
+			drv_loge("DRM_IOCTL_I915_GEM_CREATE_EXT failed (size=%llu) (ret=%d) \n",
+				 create_ext.size, ret);
 			return -errno;
 		}
 
@@ -653,7 +745,7 @@
 		gem_create.size = bo->meta.total_size;
 		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create);
 		if (ret) {
-			drv_log("DRM_IOCTL_I915_GEM_CREATE failed (size=%llu)\n", gem_create.size);
+			drv_loge("DRM_IOCTL_I915_GEM_CREATE failed (size=%llu)\n", gem_create.size);
 			return -errno;
 		}
 
@@ -663,20 +755,24 @@
 	for (plane = 0; plane < bo->meta.num_planes; plane++)
 		bo->handles[plane].u32 = gem_handle;
 
-	gem_set_tiling.handle = bo->handles[0].u32;
-	gem_set_tiling.tiling_mode = bo->meta.tiling;
-	gem_set_tiling.stride = bo->meta.strides[0];
+	/* Set/Get tiling ioctl not supported  based on fence availability
+	   Refer : "https://patchwork.freedesktop.org/patch/325343/"
+	 */
+	if (i915->num_fences_avail) {
+		gem_set_tiling.handle = bo->handles[0].u32;
+		gem_set_tiling.tiling_mode = bo->meta.tiling;
+		gem_set_tiling.stride = bo->meta.strides[0];
 
-	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_SET_TILING, &gem_set_tiling);
-	if (ret) {
-		struct drm_gem_close gem_close = { 0 };
-		gem_close.handle = bo->handles[0].u32;
-		drmIoctl(bo->drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
+		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_SET_TILING, &gem_set_tiling);
+		if (ret) {
+			struct drm_gem_close gem_close = { 0 };
+			gem_close.handle = bo->handles[0].u32;
+			drmIoctl(bo->drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
 
-		drv_log("DRM_IOCTL_I915_GEM_SET_TILING failed with %d\n", errno);
-		return -errno;
+			drv_loge("DRM_IOCTL_I915_GEM_SET_TILING failed with %d\n", errno);
+			return -errno;
+		}
 	}
-
 	return 0;
 }
 
@@ -690,68 +786,85 @@
 {
 	int ret;
 	struct drm_i915_gem_get_tiling gem_get_tiling = { 0 };
+	struct i915_device *i915 = bo->drv->priv;
 
-	bo->meta.num_planes = i915_num_planes_from_modifier(bo->drv, data->format,
-		data->format_modifier);
+	bo->meta.num_planes =
+	    i915_num_planes_from_modifier(bo->drv, data->format, data->format_modifier);
 
 	ret = drv_prime_bo_import(bo, data);
 	if (ret)
 		return ret;
 
-	/* TODO(gsingh): export modifiers and get rid of backdoor tiling. */
-	gem_get_tiling.handle = bo->handles[0].u32;
+	/* Set/Get tiling ioctl not supported  based on fence availability
+	   Refer : "https://patchwork.freedesktop.org/patch/325343/"
+	 */
+	if (i915->num_fences_avail) {
+		/* TODO(gsingh): export modifiers and get rid of backdoor tiling. */
+		gem_get_tiling.handle = bo->handles[0].u32;
 
-	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_GET_TILING, &gem_get_tiling);
-	if (ret) {
-		drv_gem_bo_destroy(bo);
-		drv_log("DRM_IOCTL_I915_GEM_GET_TILING failed.\n");
-		return ret;
+		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_GET_TILING, &gem_get_tiling);
+		if (ret) {
+			drv_gem_bo_destroy(bo);
+			drv_loge("DRM_IOCTL_I915_GEM_GET_TILING failed.\n");
+			return ret;
+		}
+		bo->meta.tiling = gem_get_tiling.tiling_mode;
 	}
-
-	bo->meta.tiling = gem_get_tiling.tiling_mode;
 	return 0;
 }
 
-static void *i915_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+static void *i915_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	int ret;
 	void *addr = MAP_FAILED;
+	struct i915_device *i915 = bo->drv->priv;
 
-	if (bo->meta.format_modifier == I915_FORMAT_MOD_Y_TILED_CCS)
-		return MAP_FAILED;
-
-	if (bo->meta.format_modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS)
+	if ((bo->meta.format_modifier == I915_FORMAT_MOD_Y_TILED_CCS) ||
+	    (bo->meta.format_modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS) ||
+	    (bo->meta.format_modifier == I915_FORMAT_MOD_4_TILED))
 		return MAP_FAILED;
 
 	if (bo->meta.tiling == I915_TILING_NONE) {
-		struct drm_i915_gem_mmap gem_map = { 0 };
-		/* TODO(b/118799155): We don't seem to have a good way to
-		 * detect the use cases for which WC mapping is really needed.
-		 * The current heuristic seems overly coarse and may be slowing
-		 * down some other use cases unnecessarily.
-		 *
-		 * For now, care must be taken not to use WC mappings for
-		 * Renderscript and camera use cases, as they're
-		 * performance-sensitive. */
-		if ((bo->meta.use_flags & BO_USE_SCANOUT) &&
-		    !(bo->meta.use_flags &
-		      (BO_USE_RENDERSCRIPT | BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE)))
-			gem_map.flags = I915_MMAP_WC;
+		if (i915->has_mmap_offset) {
+			struct drm_i915_gem_mmap_offset gem_map = { 0 };
+			gem_map.handle = bo->handles[0].u32;
+			gem_map.flags = I915_MMAP_OFFSET_WB;
 
-		gem_map.handle = bo->handles[0].u32;
-		gem_map.offset = 0;
-		gem_map.size = bo->meta.total_size;
+			/* Get the fake offset back */
+			ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_MMAP_OFFSET, &gem_map);
+			if (ret == 0)
+				addr = mmap(0, bo->meta.total_size, drv_get_prot(map_flags),
+					    MAP_SHARED, bo->drv->fd, gem_map.offset);
+		} else {
+			struct drm_i915_gem_mmap gem_map = { 0 };
+			/* TODO(b/118799155): We don't seem to have a good way to
+			 * detect the use cases for which WC mapping is really needed.
+			 * The current heuristic seems overly coarse and may be slowing
+			 * down some other use cases unnecessarily.
+			 *
+			 * For now, care must be taken not to use WC mappings for
+			 * Renderscript and camera use cases, as they're
+			 * performance-sensitive. */
+			if ((bo->meta.use_flags & BO_USE_SCANOUT) &&
+			    !(bo->meta.use_flags &
+			      (BO_USE_RENDERSCRIPT | BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE)))
+				gem_map.flags = I915_MMAP_WC;
 
-		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_MMAP, &gem_map);
-		/* DRM_IOCTL_I915_GEM_MMAP mmaps the underlying shm
-		 * file and returns a user space address directly, ie,
-		 * doesn't go through mmap. If we try that on a
-		 * dma-buf that doesn't have a shm file, i915.ko
-		 * returns ENXIO.  Fall through to
-		 * DRM_IOCTL_I915_GEM_MMAP_GTT in that case, which
-		 * will mmap on the drm fd instead. */
-		if (ret == 0)
-			addr = (void *)(uintptr_t)gem_map.addr_ptr;
+			gem_map.handle = bo->handles[0].u32;
+			gem_map.offset = 0;
+			gem_map.size = bo->meta.total_size;
+
+			ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_MMAP, &gem_map);
+			/* DRM_IOCTL_I915_GEM_MMAP mmaps the underlying shm
+			 * file and returns a user space address directly, ie,
+			 * doesn't go through mmap. If we try that on a
+			 * dma-buf that doesn't have a shm file, i915.ko
+			 * returns ENXIO.  Fall through to
+			 * DRM_IOCTL_I915_GEM_MMAP_GTT in that case, which
+			 * will mmap on the drm fd instead. */
+			if (ret == 0)
+				addr = (void *)(uintptr_t)gem_map.addr_ptr;
+		}
 	}
 
 	if (addr == MAP_FAILED) {
@@ -760,7 +873,7 @@
 		gem_map.handle = bo->handles[0].u32;
 		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &gem_map);
 		if (ret) {
-			drv_log("DRM_IOCTL_I915_GEM_MMAP_GTT failed\n");
+			drv_loge("DRM_IOCTL_I915_GEM_MMAP_GTT failed\n");
 			return MAP_FAILED;
 		}
 
@@ -769,7 +882,7 @@
 	}
 
 	if (addr == MAP_FAILED) {
-		drv_log("i915 GEM mmap failed\n");
+		drv_loge("i915 GEM mmap failed\n");
 		return addr;
 	}
 
@@ -795,7 +908,7 @@
 
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
 	if (ret) {
-		drv_log("DRM_IOCTL_I915_GEM_SET_DOMAIN with %d\n", ret);
+		drv_loge("DRM_IOCTL_I915_GEM_SET_DOMAIN with %d\n", ret);
 		return ret;
 	}
 
diff --git a/mediatek.c b/mediatek.c
index 562b1d1..113273b 100644
--- a/mediatek.c
+++ b/mediatek.c
@@ -25,17 +25,34 @@
 
 #define TILE_TYPE_LINEAR 0
 
-#if defined(MTK_MT8183) || defined(MTK_MT8186)
-#define SUPPORTS_YUV422_AND_HIGH_BIT_DEPTH_TEXTURING
+// clang-format off
+#if defined(MTK_MT8183) || \
+    defined(MTK_MT8186)
+// clang-format on
+#define SUPPORTS_YUV422
 #endif
 
 // All platforms except MT8173 should USE_NV12_FOR_HW_VIDEO_DECODING.
-#if defined(MTK_MT8183) || defined(MTK_MT8186) || defined(MTK_MT8192) || defined(MTK_MT8195)
+// clang-format off
+#if defined(MTK_MT8183) || \
+    defined(MTK_MT8186) || \
+    defined(MTK_MT8188G) || \
+    defined(MTK_MT8192) || \
+    defined(MTK_MT8195)
+// clang-format on
 #define USE_NV12_FOR_HW_VIDEO_DECODING
 #else
 #define DONT_USE_64_ALIGNMENT_FOR_VIDEO_BUFFERS
 #endif
 
+// For Mali Sigurd based GPUs, the texture unit reads outside the specified texture dimensions.
+// Therefore, certain formats require extra memory padding to its allocated surface to prevent the
+// hardware from reading outside an allocation. For YVU420, we need additional padding for the last
+// chroma plane.
+#if defined(MTK_MT8186)
+#define USE_EXTRA_PADDING_FOR_YVU420
+#endif
+
 struct mediatek_private_map_data {
 	void *cached_addr;
 	void *gem_addr;
@@ -48,12 +65,12 @@
 
 // clang-format off
 static const uint32_t texture_source_formats[] = {
-#ifdef SUPPORTS_YUV422_AND_HIGH_BIT_DEPTH_TEXTURING
+#ifdef SUPPORTS_YUV422
 	DRM_FORMAT_NV21,
 	DRM_FORMAT_YUYV,
+#endif
 	DRM_FORMAT_ABGR2101010,
 	DRM_FORMAT_ABGR16161616F,
-#endif
 	DRM_FORMAT_NV12,
 	DRM_FORMAT_YVU420,
 	DRM_FORMAT_YVU420_ANDROID
@@ -62,6 +79,7 @@
 static const uint32_t video_yuv_formats[] = {
 	DRM_FORMAT_NV21,
 	DRM_FORMAT_NV12,
+	DRM_FORMAT_YUYV,
 	DRM_FORMAT_YVU420,
 	DRM_FORMAT_YVU420_ANDROID
 };
@@ -89,6 +107,11 @@
 
 	drv_add_combination(drv, DRM_FORMAT_R8, &LINEAR_METADATA, BO_USE_SW_MASK | BO_USE_LINEAR);
 
+	/* YUYV format for video overlay and camera subsystem. */
+	drv_add_combination(drv, DRM_FORMAT_YUYV, &LINEAR_METADATA,
+			    BO_USE_HW_VIDEO_DECODER | BO_USE_SCANOUT | BO_USE_LINEAR |
+				BO_USE_TEXTURE);
+
 	/* Android CTS tests require this. */
 	drv_add_combination(drv, DRM_FORMAT_BGR888, &LINEAR_METADATA, BO_USE_SW_MASK);
 
@@ -109,7 +132,8 @@
 	 */
 	drv_modify_combination(drv, DRM_FORMAT_R8, &metadata,
 			       BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER |
-				   BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
+				   BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE |
+				   BO_USE_GPU_DATA_BUFFER | BO_USE_SENSOR_DIRECT_DATA);
 
 	/* NV12 format for encoding and display. */
 	drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata,
@@ -149,7 +173,7 @@
 
 	if (!drv_has_modifier(modifiers, count, DRM_FORMAT_MOD_LINEAR)) {
 		errno = EINVAL;
-		drv_log("no usable modifier found\n");
+		drv_loge("no usable modifier found\n");
 		return -EINVAL;
 	}
 
@@ -177,9 +201,9 @@
 					 (32 / drv_vertical_subsampling_from_format(format, plane));
 		}
 
-		drv_bo_from_format_and_padding(bo, stride, aligned_height, format, padding);
+		drv_bo_from_format_and_padding(bo, stride, 1, aligned_height, format, padding);
 	} else {
-#ifdef SUPPORTS_YUV422_AND_HIGH_BIT_DEPTH_TEXTURING
+#ifdef SUPPORTS_YUV422
 		/*
 		 * JPEG Encoder Accelerator requires 16x16 alignment. We want the buffer
 		 * from camera can be put in JEA directly so align the height to 16
@@ -188,14 +212,43 @@
 		if (format == DRM_FORMAT_NV12)
 			height = ALIGN(height, 16);
 #endif
-		drv_bo_from_format(bo, stride, height, format);
+		drv_bo_from_format(bo, stride, 1, height, format);
+
+#ifdef USE_EXTRA_PADDING_FOR_YVU420
+		/*
+		 * Apply extra padding for YV12 if the height does not meet round up requirement and
+		 * the image is to be sampled by gpu.
+		 */
+		static const uint32_t required_round_up = 4;
+		const uint32_t height_mod = height % required_round_up;
+		if ((format == DRM_FORMAT_YVU420 || format == DRM_FORMAT_YVU420_ANDROID) &&
+		    (bo->meta.use_flags & BO_USE_TEXTURE) && height_mod) {
+			const uint32_t height_padding = required_round_up - height_mod;
+			const uint32_t u_padding =
+			    drv_size_from_format(format, bo->meta.strides[2], height_padding, 2);
+
+			bo->meta.total_size += u_padding;
+
+			/*
+			 * Since we are not aligning Y, we must make sure that its padding fits
+			 * inside the rest of the space allocated for the V/U planes.
+			 */
+			const uint32_t y_padding =
+			    drv_size_from_format(format, bo->meta.strides[0], height_padding, 0);
+			const uint32_t vu_size = drv_bo_get_plane_size(bo, 2) * 2;
+			if (y_padding > vu_size) {
+				/* Align with mali workaround to pad all 3 planes. */
+				bo->meta.total_size += y_padding + u_padding;
+			}
+		}
+#endif
 	}
 
 	gem_create.size = bo->meta.total_size;
 
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MTK_GEM_CREATE, &gem_create);
 	if (ret) {
-		drv_log("DRM_IOCTL_MTK_GEM_CREATE failed (size=%" PRIu64 ")\n", gem_create.size);
+		drv_loge("DRM_IOCTL_MTK_GEM_CREATE failed (size=%" PRIu64 ")\n", gem_create.size);
 		return -errno;
 	}
 
@@ -213,7 +266,7 @@
 						 ARRAY_SIZE(modifiers));
 }
 
-static void *mediatek_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+static void *mediatek_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	int ret, prime_fd;
 	struct drm_mtk_gem_map_off gem_map = { 0 };
@@ -224,13 +277,13 @@
 
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MTK_GEM_MAP_OFFSET, &gem_map);
 	if (ret) {
-		drv_log("DRM_IOCTL_MTK_GEM_MAP_OFFSET failed\n");
+		drv_loge("DRM_IOCTL_MTK_GEM_MAP_OFFSET failed\n");
 		return MAP_FAILED;
 	}
 
 	prime_fd = drv_bo_get_plane_fd(bo, 0);
 	if (prime_fd < 0) {
-		drv_log("Failed to get a prime fd\n");
+		drv_loge("Failed to get a prime fd\n");
 		return MAP_FAILED;
 	}
 
@@ -303,7 +356,7 @@
 
 		poll(&fds, 1, -1);
 		if (fds.revents != fds.events)
-			drv_log("poll prime_fd failed\n");
+			drv_loge("poll prime_fd failed\n");
 
 		if (priv->cached_addr)
 			memcpy(priv->cached_addr, priv->gem_addr, bo->meta.total_size);
diff --git a/minigbm_helpers.c b/minigbm_helpers.c
index cea0b48..d1da7c4 100644
--- a/minigbm_helpers.c
+++ b/minigbm_helpers.c
@@ -17,6 +17,7 @@
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
+#include "gbm.h"
 #include "minigbm_helpers.h"
 #include "util.h"
 
@@ -210,7 +211,7 @@
 	return 0;
 }
 
-PUBLIC int gbm_get_default_device_fd(void)
+static int gbm_get_default_device_fd(void)
 {
 	DIR *dir;
 	int ret, fd, dfd = -1;
@@ -312,3 +313,63 @@
 	close(fd);
 	return ret;
 }
+
+static struct gbm_device *try_drm_devices(drmDevicePtr *devs, int dev_count, int type, int *out_fd)
+{
+	int i;
+
+	for (i = 0; i < dev_count; i++) {
+		drmDevicePtr dev = devs[i];
+		int fd;
+
+		if (!(dev->available_nodes & (1 << type)))
+			continue;
+
+		fd = open(dev->nodes[type], O_RDWR | O_CLOEXEC);
+		if (fd >= 0) {
+			struct gbm_device *gbm = gbm_create_device(fd);
+			if (gbm) {
+				// DRM master might be taken by accident on a primary node even
+				// if master is not needed for GBM. Drop it so that programs
+				// that actually need DRM master (e.g. Chrome) won't be blocked.
+				if (type == DRM_NODE_PRIMARY && drmIsMaster(fd))
+					drmDropMaster(fd);
+				*out_fd = fd;
+				return gbm;
+			}
+			close(fd);
+		}
+	}
+
+	return NULL;
+}
+
+PUBLIC struct gbm_device *minigbm_create_default_device(int *out_fd)
+{
+	struct gbm_device *gbm;
+	drmDevicePtr devs[64];
+	int dev_count;
+	int fd;
+
+	/* try gbm_get_default_device_fd first */
+	fd = gbm_get_default_device_fd();
+	if (fd >= 0) {
+		gbm = gbm_create_device(fd);
+		if (gbm) {
+			*out_fd = fd;
+			return gbm;
+		}
+		close(fd);
+	}
+
+	dev_count = drmGetDevices2(0, devs, sizeof(devs) / sizeof(devs[0]));
+
+	/* try render nodes and then primary nodes */
+	gbm = try_drm_devices(devs, dev_count, DRM_NODE_RENDER, out_fd);
+	if (!gbm)
+		gbm = try_drm_devices(devs, dev_count, DRM_NODE_PRIMARY, out_fd);
+
+	drmFreeDevices(devs, dev_count);
+
+	return gbm;
+}
diff --git a/minigbm_helpers.h b/minigbm_helpers.h
index 08e6283..dbbb644 100644
--- a/minigbm_helpers.h
+++ b/minigbm_helpers.h
@@ -6,6 +6,8 @@
 #ifndef _MINIGBM_HELPERS_H_
 #define _MINIGBM_HELPERS_H_
 
+#include <stdint.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -18,6 +20,8 @@
 #define GBM_DEV_TYPE_FLAG_BLOCKED (1u << 5)	 /* Unsuitable device e.g. vgem, udl, evdi. */
 #define GBM_DEV_TYPE_FLAG_INTERNAL_LCD (1u << 6) /* Device is driving internal LCD. */
 
+struct gbm_device;
+
 struct gbm_device_info {
 	uint32_t dev_type_flags;
 	int dri_node_num; /* DRI node number (0..63), for easy matching of devices. */
@@ -32,9 +36,9 @@
 				struct gbm_device_info *info);
 
 /*
- * Select "default" device to use for graphics memory allocator.
+ * Create "default" gbm device.
  */
-int gbm_get_default_device_fd(void);
+struct gbm_device *minigbm_create_default_device(int *out_fd);
 
 #ifdef __cplusplus
 }
diff --git a/msm.c b/msm.c
index 5a2a73c..0e86d95 100644
--- a/msm.c
+++ b/msm.c
@@ -36,9 +36,9 @@
 
 #define MSM_UBWC_TILING 1
 
-static const uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888,
-						  DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888,
-						  DRM_FORMAT_XRGB8888, DRM_FORMAT_ABGR2101010,
+static const uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888,	   DRM_FORMAT_ARGB8888,
+						  DRM_FORMAT_RGB565,	   DRM_FORMAT_XBGR8888,
+						  DRM_FORMAT_XRGB8888,	   DRM_FORMAT_ABGR2101010,
 						  DRM_FORMAT_ABGR16161616F };
 
 static const uint32_t texture_source_formats[] = { DRM_FORMAT_NV12, DRM_FORMAT_R8,
@@ -73,6 +73,8 @@
 	switch (bo->meta.format) {
 	case DRM_FORMAT_NV12:
 		return VENUS_STRIDE_ALIGN;
+	case DRM_FORMAT_P010:
+		return VENUS_STRIDE_ALIGN * 2;
 	case DRM_FORMAT_YVU420:
 	case DRM_FORMAT_YVU420_ANDROID:
 		/* TODO other YUV formats? */
@@ -105,8 +107,8 @@
 		if (bo->meta.format == DRM_FORMAT_P010)
 			width *= 2;
 
-		y_stride = ALIGN(width, VENUS_STRIDE_ALIGN);
-		uv_stride = ALIGN(width, VENUS_STRIDE_ALIGN);
+		y_stride = ALIGN(width, get_pitch_alignment(bo));
+		uv_stride = ALIGN(width, get_pitch_alignment(bo));
 		y_scanline = ALIGN(height, VENUS_SCANLINE_ALIGN * 2);
 		uv_scanline = ALIGN(DIV_ROUND_UP(height, 2),
 				    VENUS_SCANLINE_ALIGN * (bo->meta.tiling ? 2 : 1));
@@ -138,7 +140,9 @@
 			DRM_FORMAT_R8 of height one is used for JPEG camera output, so don't
 			height align that. */
 		if (bo->meta.format == DRM_FORMAT_YVU420_ANDROID ||
+		    bo->meta.format == DRM_FORMAT_YVU420 ||
 		    (bo->meta.format == DRM_FORMAT_R8 && height == 1)) {
+			assert(bo->meta.tiling != MSM_UBWC_TILING);
 			alignh = height;
 		} else {
 			alignh = ALIGN(height, DEFAULT_ALIGNMENT);
@@ -147,7 +151,7 @@
 		stride = drv_stride_from_format(bo->meta.format, alignw, 0);
 
 		/* Calculate size and assign stride, size, offset to each plane based on format */
-		drv_bo_from_format(bo, stride, alignh, bo->meta.format);
+		drv_bo_from_format(bo, stride, 1, alignh, bo->meta.format);
 
 		/* For all RGB UBWC formats */
 		if (bo->meta.tiling == MSM_UBWC_TILING) {
@@ -204,22 +208,7 @@
 	 * See b/163137550
 	 */
 	if (dlsym(RTLD_DEFAULT, "waffle_display_connect")) {
-		drv_log("WARNING: waffle detected, disabling UBWC\n");
-		return true;
-	}
-
-	/* Sommelier relies on implicit modifier, which does not pass host modifier to
-	 * zwp_linux_buffer_params_v1_add. Graphics will be broken if UBWC is enabled.
-	 * Sommelier shall be fixed to mirror what arc wayland_service does, and then
-	 * we can re-enable UBWC here.
-	 *
-	 * Inherit the trick from crrev/c/2523246 previously used for gtest. The side
-	 * effect is all VM guests on msm will revert back to use linear modifier.
-	 *
-	 * See b/229147702
-	 */
-	if (!dlsym(RTLD_DEFAULT, "cupsFilePrintf")) {
-		drv_log("WARNING: virtualization detected, disabling UBWC\n");
+		drv_logi("WARNING: waffle detected, disabling UBWC\n");
 		return true;
 	}
 #endif
@@ -258,7 +247,8 @@
 	 */
 	drv_modify_combination(drv, DRM_FORMAT_R8, &LINEAR_METADATA,
 			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
-				   BO_USE_HW_VIDEO_ENCODER);
+				   BO_USE_HW_VIDEO_ENCODER | BO_USE_GPU_DATA_BUFFER |
+				   BO_USE_SENSOR_DIRECT_DATA);
 
 	/*
 	 * Android also frequently requests YV12 formats for some camera implementations
@@ -266,6 +256,8 @@
 	 */
 	drv_modify_combination(drv, DRM_FORMAT_YVU420_ANDROID, &LINEAR_METADATA,
 			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
+	drv_modify_combination(drv, DRM_FORMAT_YVU420, &LINEAR_METADATA,
+			       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);
@@ -314,7 +306,7 @@
 
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MSM_GEM_NEW, &req);
 	if (ret) {
-		drv_log("DRM_IOCTL_MSM_GEM_NEW failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_MSM_GEM_NEW failed with %s\n", strerror(errno));
 		return -errno;
 	}
 
@@ -353,22 +345,25 @@
 	struct combination *combo = drv_get_combination(bo->drv, format, flags);
 
 	if (!combo) {
-		drv_log("invalid format = %d, flags = %" PRIx64 " combination\n", format, flags);
+		drv_loge("invalid format = %d, flags = %" PRIx64 " combination\n", format, flags);
 		return -EINVAL;
 	}
 
 	return msm_bo_create_for_modifier(bo, width, height, format, combo->metadata.modifier);
 }
 
-static void *msm_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+static void *msm_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	int ret;
 	struct drm_msm_gem_info req = { 0 };
 
+	if (bo->meta.format_modifier)
+		return MAP_FAILED;
+
 	req.handle = bo->handles[0].u32;
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MSM_GEM_INFO, &req);
 	if (ret) {
-		drv_log("DRM_IOCLT_MSM_GEM_INFO failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCLT_MSM_GEM_INFO failed with %s\n", strerror(errno));
 		return MAP_FAILED;
 	}
 	vma->length = bo->meta.total_size;
diff --git a/rockchip.c b/rockchip.c
index 6d25e3a..2dc7146 100644
--- a/rockchip.c
+++ b/rockchip.c
@@ -107,7 +107,8 @@
 	 */
 	drv_add_combination(drv, DRM_FORMAT_R8, &metadata,
 			    BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_SW_MASK |
-				BO_USE_LINEAR | BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER);
+				BO_USE_LINEAR | BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER |
+				BO_USE_GPU_DATA_BUFFER | BO_USE_SENSOR_DIRECT_DATA);
 
 	return 0;
 }
@@ -135,7 +136,7 @@
 		uint32_t aligned_width = w_mbs * 16;
 		uint32_t aligned_height = h_mbs * 16;
 
-		drv_bo_from_format(bo, aligned_width, aligned_height, format);
+		drv_bo_from_format(bo, aligned_width, 1, aligned_height, format);
 		/*
 		 * drv_bo_from_format updates total_size. Add an extra data space for rockchip video
 		 * driver to store motion vectors.
@@ -148,7 +149,7 @@
 	} else {
 		if (!drv_has_modifier(modifiers, count, DRM_FORMAT_MOD_LINEAR)) {
 			errno = EINVAL;
-			drv_log("no usable modifier found\n");
+			drv_loge("no usable modifier found\n");
 			return -errno;
 		}
 
@@ -165,15 +166,15 @@
 		else
 			stride = ALIGN(stride, 64);
 
-		drv_bo_from_format(bo, stride, height, format);
+		drv_bo_from_format(bo, stride, 1, height, format);
 	}
 
 	gem_create.size = bo->meta.total_size;
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_ROCKCHIP_GEM_CREATE, &gem_create);
 
 	if (ret) {
-		drv_log("DRM_IOCTL_ROCKCHIP_GEM_CREATE failed (size=%" PRIu64 ")\n",
-			gem_create.size);
+		drv_loge("DRM_IOCTL_ROCKCHIP_GEM_CREATE failed (size=%" PRIu64 ")\n",
+			 gem_create.size);
 		return -errno;
 	}
 
@@ -191,7 +192,7 @@
 						 ARRAY_SIZE(modifiers));
 }
 
-static void *rockchip_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+static void *rockchip_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	int ret;
 	struct rockchip_private_map_data *priv;
@@ -207,7 +208,7 @@
 	gem_map.handle = bo->handles[0].u32;
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET, &gem_map);
 	if (ret) {
-		drv_log("DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET failed\n");
+		drv_loge("DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET failed\n");
 		return MAP_FAILED;
 	}
 
diff --git a/vc4.c b/vc4.c
index 820e4fe..d53fabf 100644
--- a/vc4.c
+++ b/vc4.c
@@ -52,7 +52,7 @@
 	case DRM_FORMAT_MOD_LINEAR:
 		break;
 	case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
-		drv_log("DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED not supported yet\n");
+		drv_loge("DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED not supported yet\n");
 		return -EINVAL;
 	default:
 		return -EINVAL;
@@ -64,13 +64,13 @@
 	 */
 	stride = drv_stride_from_format(format, width, 0);
 	stride = ALIGN(stride, 64);
-	drv_bo_from_format(bo, stride, height, format);
+	drv_bo_from_format(bo, stride, 1, height, format);
 
 	bo_create.size = bo->meta.total_size;
 
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VC4_CREATE_BO, &bo_create);
 	if (ret) {
-		drv_log("DRM_IOCTL_VC4_CREATE_BO failed (size=%zu)\n", bo->meta.total_size);
+		drv_loge("DRM_IOCTL_VC4_CREATE_BO failed (size=%zu)\n", bo->meta.total_size);
 		return -errno;
 	}
 
@@ -105,7 +105,7 @@
 	return vc4_bo_create_for_modifier(bo, width, height, format, modifier);
 }
 
-static void *vc4_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+static void *vc4_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	int ret;
 	struct drm_vc4_mmap_bo bo_map = { 0 };
@@ -113,7 +113,7 @@
 	bo_map.handle = bo->handles[0].u32;
 	ret = drmCommandWriteRead(bo->drv->fd, DRM_VC4_MMAP_BO, &bo_map, sizeof(bo_map));
 	if (ret) {
-		drv_log("DRM_VC4_MMAP_BO failed\n");
+		drv_loge("DRM_VC4_MMAP_BO failed\n");
 		return MAP_FAILED;
 	}
 
diff --git a/virtgpu.c b/virtgpu.c
index db50b46..2f4b8db 100644
--- a/virtgpu.c
+++ b/virtgpu.c
@@ -48,7 +48,7 @@
 		get_param.value = (uint64_t)(uintptr_t)&params[i].value;
 		int ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GETPARAM, &get_param);
 		if (ret)
-			drv_log("virtgpu backend not enabling %s\n", params[i].name);
+			drv_logi("virtgpu backend not enabling %s\n", params[i].name);
 	}
 
 	for (uint32_t i = 0; i < ARRAY_SIZE(virtgpu_backends); i++) {
diff --git a/virtgpu_cross_domain.c b/virtgpu_cross_domain.c
index 10930fc..45b5580 100644
--- a/virtgpu_cross_domain.c
+++ b/virtgpu_cross_domain.c
@@ -19,16 +19,16 @@
 #define CAPSET_CROSS_DOMAIN 5
 #define CAPSET_CROSS_FAKE 30
 
-static const uint32_t scanout_render_formats[] = { DRM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR8888,
-						   DRM_FORMAT_ARGB2101010, DRM_FORMAT_ARGB8888,
-						   DRM_FORMAT_RGB565,	   DRM_FORMAT_XBGR2101010,
-						   DRM_FORMAT_XBGR8888,	   DRM_FORMAT_XRGB2101010,
+static const uint32_t scanout_render_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888,
+						   DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888,
 						   DRM_FORMAT_XRGB8888 };
 
-static const uint32_t render_formats[] = { DRM_FORMAT_ABGR16161616F };
-
-static const uint32_t texture_only_formats[] = { DRM_FORMAT_R8, DRM_FORMAT_NV12, DRM_FORMAT_P010,
-						 DRM_FORMAT_YVU420, DRM_FORMAT_YVU420_ANDROID };
+static const uint32_t texture_only_formats[] = {
+	DRM_FORMAT_R8,		 DRM_FORMAT_NV12,	    DRM_FORMAT_P010,
+	DRM_FORMAT_YVU420,	 DRM_FORMAT_YVU420_ANDROID, DRM_FORMAT_ABGR2101010,
+	DRM_FORMAT_ARGB2101010,	 DRM_FORMAT_XBGR2101010,    DRM_FORMAT_XRGB2101010,
+	DRM_FORMAT_ABGR16161616F
+};
 
 extern struct virtgpu_param params[];
 
@@ -53,8 +53,8 @@
 
 		ret = drmIoctl(drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
 		if (ret) {
-			drv_log("DRM_IOCTL_GEM_CLOSE failed (handle=%x) error %d\n",
-				priv->ring_handle, ret);
+			drv_loge("DRM_IOCTL_GEM_CLOSE failed (handle=%x) error %d\n",
+				 priv->ring_handle, ret);
 		}
 	}
 
@@ -78,9 +78,6 @@
 	drv_add_combinations(drv, scanout_render_formats, ARRAY_SIZE(scanout_render_formats),
 			     &metadata, BO_USE_RENDER_MASK | BO_USE_SCANOUT);
 
-	drv_add_combinations(drv, render_formats, ARRAY_SIZE(render_formats), &metadata,
-			     BO_USE_RENDER_MASK);
-
 	drv_add_combinations(drv, texture_only_formats, ARRAY_SIZE(texture_only_formats), &metadata,
 			     BO_USE_TEXTURE_MASK);
 
@@ -89,15 +86,18 @@
 
 	drv_modify_combination(drv, DRM_FORMAT_YVU420, &metadata, BO_USE_HW_VIDEO_ENCODER);
 	drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata,
-			       BO_USE_HW_VIDEO_DECODER | BO_USE_SCANOUT | BO_USE_HW_VIDEO_ENCODER);
+			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
+				   BO_USE_SCANOUT | BO_USE_HW_VIDEO_ENCODER);
 
 	/*
 	 * R8 format is used for Android's HAL_PIXEL_FORMAT_BLOB and is used for JPEG snapshots
-	 * from camera and input/output from hardware decoder/encoder.
+	 * from camera, input/output from hardware decoder/encoder and sensors, and
+	 * AHBs used as SSBOs/UBOs.
 	 */
 	drv_modify_combination(drv, DRM_FORMAT_R8, &metadata,
 			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
-				   BO_USE_HW_VIDEO_ENCODER);
+				   BO_USE_HW_VIDEO_ENCODER | BO_USE_SENSOR_DIRECT_DATA |
+				   BO_USE_GPU_DATA_BUFFER);
 
 	drv_modify_linear_combinations(drv);
 }
@@ -109,17 +109,17 @@
 	struct drm_virtgpu_execbuffer exec = { 0 };
 	struct cross_domain_private *priv = drv->priv;
 
+	exec.flags = VIRTGPU_EXECBUF_RING_IDX;
 	exec.command = (uint64_t)&cmd[0];
 	exec.size = cmd_size;
 	if (wait) {
-		exec.flags = VIRTGPU_EXECBUF_RING_IDX;
 		exec.bo_handles = (uint64_t)&priv->ring_handle;
 		exec.num_bo_handles = 1;
 	}
 
 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &exec);
 	if (ret < 0) {
-		drv_log("DRM_IOCTL_VIRTGPU_EXECBUFFER failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_EXECBUFFER failed with %s\n", strerror(errno));
 		return -EINVAL;
 	}
 
@@ -130,7 +130,7 @@
 	}
 
 	if (ret < 0) {
-		drv_log("DRM_IOCTL_VIRTGPU_WAIT failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_WAIT failed with %s\n", strerror(errno));
 		return ret;
 	}
 
@@ -212,6 +212,22 @@
 	return ret;
 }
 
+/* Fill out metadata for guest buffers, used only for CPU access: */
+void cross_domain_get_emulated_metadata(struct bo_metadata *metadata)
+{
+	uint32_t offset = 0;
+
+	for (size_t i = 0; i < metadata->num_planes; i++) {
+		metadata->strides[i] = drv_stride_from_format(metadata->format, metadata->width, i);
+		metadata->sizes[i] = drv_size_from_format(metadata->format, metadata->strides[i],
+							  metadata->height, i);
+		metadata->offsets[i] = offset;
+		offset += metadata->sizes[i];
+	}
+
+	metadata->total_size = offset;
+}
+
 static int cross_domain_init(struct driver *drv)
 {
 	int ret;
@@ -264,7 +280,7 @@
 
 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GET_CAPS, &args);
 	if (ret) {
-		drv_log("DRM_IOCTL_VIRTGPU_GET_CAPS failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_GET_CAPS failed with %s\n", strerror(errno));
 		goto free_private;
 	}
 
@@ -287,7 +303,7 @@
 	init.num_params = 2;
 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_CONTEXT_INIT, &init);
 	if (ret) {
-		drv_log("DRM_IOCTL_VIRTGPU_CONTEXT_INIT failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_CONTEXT_INIT failed with %s\n", strerror(errno));
 		goto free_private;
 	}
 
@@ -298,7 +314,7 @@
 
 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &drm_rc_blob);
 	if (ret < 0) {
-		drv_log("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno));
+		drv_loge("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno));
 		goto free_private;
 	}
 
@@ -308,7 +324,7 @@
 	map.handle = priv->ring_handle;
 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_MAP, &map);
 	if (ret < 0) {
-		drv_log("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno));
 		goto free_private;
 	}
 
@@ -316,7 +332,7 @@
 	    mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, drv->fd, map.offset);
 
 	if (priv->ring_addr == MAP_FAILED) {
-		drv_log("mmap failed with %s\n", strerror(errno));
+		drv_loge("mmap failed with %s\n", strerror(errno));
 		goto free_private;
 	}
 
@@ -349,36 +365,42 @@
 	uint32_t blob_flags = VIRTGPU_BLOB_FLAG_USE_SHAREABLE;
 	struct drm_virtgpu_resource_create_blob drm_rc_blob = { 0 };
 
-	ret = cross_domain_metadata_query(bo->drv, &bo->meta);
-	if (ret < 0) {
-		drv_log("Metadata query failed");
-		return ret;
-	}
-
-	if (use_flags & BO_USE_SW_MASK)
+	if (use_flags & (BO_USE_SW_MASK | BO_USE_GPU_DATA_BUFFER))
 		blob_flags |= VIRTGPU_BLOB_FLAG_USE_MAPPABLE;
 
-	if (params[param_cross_device].value)
-		blob_flags |= VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE;
-
-	/// It may be possible to have host3d blobs and handles from guest memory at the same time.
-	/// But for the immediate use cases, we will either have one or the other.  For now, just
-	/// prefer guest memory since adding that feature is more involved (requires --udmabuf
-	/// flag to crosvm), so developers would likely test that.
-	if (params[param_create_guest_handle].value) {
+	if (!(use_flags & BO_USE_HW_MASK)) {
+		cross_domain_get_emulated_metadata(&bo->meta);
 		drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_GUEST;
-		blob_flags |= VIRTGPU_BLOB_FLAG_CREATE_GUEST_HANDLE;
-	} else if (params[param_host_visible].value) {
-		drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_HOST3D;
+	} else {
+		ret = cross_domain_metadata_query(bo->drv, &bo->meta);
+		if (ret < 0) {
+			drv_loge("Metadata query failed");
+			return ret;
+		}
+
+		if (params[param_cross_device].value)
+			blob_flags |= VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE;
+
+		/// It may be possible to have host3d blobs and handles from guest memory at the
+		/// same time. But for the immediate use cases, we will either have one or the
+		/// other.  For now, just prefer guest memory since adding that feature is more
+		/// involved (requires --udmabuf flag to crosvm), so developers would likely test
+		/// that.
+		if (params[param_create_guest_handle].value) {
+			drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_GUEST;
+			blob_flags |= VIRTGPU_BLOB_FLAG_CREATE_GUEST_HANDLE;
+		} else if (params[param_host_visible].value) {
+			drm_rc_blob.blob_mem = VIRTGPU_BLOB_MEM_HOST3D;
+		}
+		drm_rc_blob.blob_id = (uint64_t)bo->meta.blob_id;
 	}
 
 	drm_rc_blob.size = bo->meta.total_size;
 	drm_rc_blob.blob_flags = blob_flags;
-	drm_rc_blob.blob_id = (uint64_t)bo->meta.blob_id;
 
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &drm_rc_blob);
 	if (ret < 0) {
-		drv_log("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno));
+		drv_loge("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno));
 		return -errno;
 	}
 
@@ -388,7 +410,7 @@
 	return 0;
 }
 
-static void *cross_domain_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+static void *cross_domain_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	int ret;
 	struct drm_virtgpu_map gem_map = { 0 };
@@ -396,7 +418,7 @@
 	gem_map.handle = bo->handles[0].u32;
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_MAP, &gem_map);
 	if (ret) {
-		drv_log("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno));
 		return MAP_FAILED;
 	}
 
diff --git a/virtgpu_virgl.c b/virtgpu_virgl.c
index 8bcfc9d..9474c40 100644
--- a/virtgpu_virgl.c
+++ b/virtgpu_virgl.c
@@ -6,10 +6,13 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <stdatomic.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <unistd.h>
 #include <xf86drm.h>
 
 #include "drv_helpers.h"
@@ -22,11 +25,6 @@
 
 #define PIPE_TEXTURE_2D 2
 
-#define MESA_LLVMPIPE_MAX_TEXTURE_2D_LEVELS 15
-#define MESA_LLVMPIPE_MAX_TEXTURE_2D_SIZE (1 << (MESA_LLVMPIPE_MAX_TEXTURE_2D_LEVELS - 1))
-#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
@@ -98,7 +96,7 @@
 	case DRM_FORMAT_YVU420_ANDROID:
 		return VIRGL_FORMAT_YV12;
 	default:
-		drv_log("Unhandled format:%d\n", drm_fourcc);
+		drv_loge("Unhandled format:%d\n", drm_fourcc);
 		return 0;
 	}
 }
@@ -352,13 +350,13 @@
 	if (params[param_3d].value) {
 		if ((use_flags & BO_USE_SCANOUT) &&
 		    !virgl_supports_combination_natively(drv, drm_format, BO_USE_SCANOUT)) {
-			drv_log("Strip scanout on format: %d\n", drm_format);
+			drv_logi("Strip scanout on format: %d\n", drm_format);
 			use_flags &= ~BO_USE_SCANOUT;
 		}
 
 		if (!virgl_supports_combination_natively(drv, drm_format, use_flags) &&
 		    !virgl_supports_combination_through_emulation(drv, drm_format, use_flags)) {
-			drv_log("Skipping unsupported combination format:%d\n", drm_format);
+			drv_logi("Skipping unsupported combination format:%d\n", drm_format);
 			return;
 		}
 	}
@@ -398,7 +396,7 @@
 	}
 }
 
-static uint32_t compute_virgl_bind_flags(uint64_t use_flags, uint32_t format)
+static uint32_t compute_virgl_bind_flags(uint64_t use_flags)
 {
 	/* In crosvm, VIRGL_BIND_SHARED means minigbm will allocate, not virglrenderer. */
 	uint32_t bind = VIRGL_BIND_SHARED;
@@ -408,6 +406,7 @@
 	handle_flag(&use_flags, BO_USE_SCANOUT, &bind, VIRGL_BIND_SCANOUT);
 	handle_flag(&use_flags, BO_USE_CURSOR, &bind, VIRGL_BIND_CURSOR);
 	handle_flag(&use_flags, BO_USE_LINEAR, &bind, VIRGL_BIND_LINEAR);
+	handle_flag(&use_flags, BO_USE_SENSOR_DIRECT_DATA, &bind, VIRGL_BIND_LINEAR);
 	handle_flag(&use_flags, BO_USE_GPU_DATA_BUFFER, &bind, VIRGL_BIND_LINEAR);
 	handle_flag(&use_flags, BO_USE_FRONT_RENDERING, &bind, VIRGL_BIND_LINEAR);
 
@@ -440,7 +439,7 @@
 		    VIRGL_BIND_MINIGBM_HW_VIDEO_ENCODER);
 
 	if (use_flags)
-		drv_log("Unhandled bo use flag: %llx\n", (unsigned long long)use_flags);
+		drv_loge("Unhandled bo use flag: %llx\n", (unsigned long long)use_flags);
 
 	return bind;
 }
@@ -456,7 +455,7 @@
 
 	if (virgl_supports_combination_natively(bo->drv, format, use_flags)) {
 		stride = drv_stride_from_format(format, width, 0);
-		drv_bo_from_format(bo, stride, height, format);
+		drv_bo_from_format(bo, stride, 1, height, format);
 	} else {
 		assert(virgl_supports_combination_through_emulation(bo->drv, format, use_flags));
 
@@ -483,7 +482,7 @@
 
 	res_create.target = PIPE_TEXTURE_2D;
 	res_create.format = translate_format(format);
-	res_create.bind = compute_virgl_bind_flags(use_flags, format);
+	res_create.bind = compute_virgl_bind_flags(use_flags);
 	res_create.width = width;
 	res_create.height = height;
 
@@ -496,7 +495,7 @@
 	res_create.size = ALIGN(bo->meta.total_size, PAGE_SIZE); // PAGE_SIZE = 0x1000
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE, &res_create);
 	if (ret) {
-		drv_log("DRM_IOCTL_VIRTGPU_RESOURCE_CREATE failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_RESOURCE_CREATE failed with %s\n", strerror(errno));
 		return ret;
 	}
 
@@ -506,7 +505,7 @@
 	return 0;
 }
 
-static void *virgl_3d_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+static void *virgl_3d_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	int ret;
 	struct drm_virtgpu_map gem_map = { 0 };
@@ -514,7 +513,7 @@
 	gem_map.handle = bo->handles[0].u32;
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_MAP, &gem_map);
 	if (ret) {
-		drv_log("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_MAP failed with %s\n", strerror(errno));
 		return MAP_FAILED;
 	}
 
@@ -551,7 +550,7 @@
 
 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GET_CAPS, &cap_args);
 	if (ret) {
-		drv_log("DRM_IOCTL_VIRTGPU_GET_CAPS failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_GET_CAPS failed with %s\n", strerror(errno));
 		*caps_is_v2 = 0;
 
 		// Fallback to v1
@@ -560,7 +559,7 @@
 
 		ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GET_CAPS, &cap_args);
 		if (ret)
-			drv_log("DRM_IOCTL_VIRTGPU_GET_CAPS failed with %s\n", strerror(errno));
+			drv_loge("DRM_IOCTL_VIRTGPU_GET_CAPS failed with %s\n", strerror(errno));
 	}
 
 	return ret;
@@ -642,9 +641,11 @@
 	virgl_add_combination(drv, DRM_FORMAT_P010, &LINEAR_METADATA,
 			      BO_USE_SCANOUT | BO_USE_TEXTURE | BO_USE_SW_MASK |
 				  BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
+	/* Android VTS sensors hal tests require BO_USE_SENSOR_DIRECT_DATA. */
 	drv_modify_combination(drv, DRM_FORMAT_R8, &LINEAR_METADATA,
 			       BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
-				   BO_USE_HW_VIDEO_ENCODER | BO_USE_GPU_DATA_BUFFER);
+				   BO_USE_HW_VIDEO_ENCODER | BO_USE_SENSOR_DIRECT_DATA |
+				   BO_USE_GPU_DATA_BUFFER);
 
 	if (!priv->host_gbm_enabled) {
 		drv_modify_combination(drv, DRM_FORMAT_ABGR8888, &LINEAR_METADATA,
@@ -686,7 +687,7 @@
 	struct virgl_priv *priv = (struct virgl_priv *)drv->priv;
 
 	uint32_t blob_flags = VIRTGPU_BLOB_FLAG_USE_SHAREABLE;
-	if (bo->meta.use_flags & BO_USE_SW_MASK)
+	if (bo->meta.use_flags & (BO_USE_SW_MASK | BO_USE_GPU_DATA_BUFFER))
 		blob_flags |= VIRTGPU_BLOB_FLAG_USE_MAPPABLE;
 
 	// For now, all blob use cases are cross device. When we add wider
@@ -695,7 +696,7 @@
 
 	cur_blob_id = atomic_fetch_add(&priv->next_blob_id, 1);
 	stride = drv_stride_from_format(bo->meta.format, bo->meta.width, 0);
-	drv_bo_from_format(bo, stride, bo->meta.height, bo->meta.format);
+	drv_bo_from_format(bo, stride, 1, bo->meta.height, bo->meta.format);
 	bo->meta.total_size = ALIGN(bo->meta.total_size, PAGE_SIZE);
 	bo->meta.tiling = blob_flags;
 
@@ -704,8 +705,7 @@
 	cmd[VIRGL_PIPE_RES_CREATE_WIDTH] = bo->meta.width;
 	cmd[VIRGL_PIPE_RES_CREATE_HEIGHT] = bo->meta.height;
 	cmd[VIRGL_PIPE_RES_CREATE_FORMAT] = translate_format(bo->meta.format);
-	cmd[VIRGL_PIPE_RES_CREATE_BIND] =
-	    compute_virgl_bind_flags(bo->meta.use_flags, bo->meta.format);
+	cmd[VIRGL_PIPE_RES_CREATE_BIND] = compute_virgl_bind_flags(bo->meta.use_flags);
 	cmd[VIRGL_PIPE_RES_CREATE_DEPTH] = 1;
 	cmd[VIRGL_PIPE_RES_CREATE_BLOB_ID] = cur_blob_id;
 
@@ -718,7 +718,7 @@
 
 	ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &drm_rc_blob);
 	if (ret < 0) {
-		drv_log("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno));
+		drv_loge("DRM_VIRTGPU_RESOURCE_CREATE_BLOB failed with %s\n", strerror(errno));
 		return -errno;
 	}
 
@@ -774,6 +774,21 @@
 		return virgl_2d_dumb_bo_create(bo, width, height, format, use_flags);
 }
 
+static int virgl_bo_create_with_modifiers(struct bo *bo, uint32_t width, uint32_t height,
+					  uint32_t format, const uint64_t *modifiers,
+					  uint32_t count)
+{
+	uint64_t use_flags = 0;
+
+	for (uint32_t i = 0; i < count; i++) {
+		if (modifiers[i] == DRM_FORMAT_MOD_LINEAR) {
+			return virgl_bo_create(bo, width, height, format, use_flags);
+		}
+	}
+
+	return -EINVAL;
+}
+
 static int virgl_bo_destroy(struct bo *bo)
 {
 	if (params[param_3d].value)
@@ -782,12 +797,42 @@
 		return drv_dumb_bo_destroy(bo);
 }
 
-static void *virgl_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
+static void *virgl_bo_map(struct bo *bo, struct vma *vma, uint32_t map_flags)
 {
 	if (params[param_3d].value)
-		return virgl_3d_bo_map(bo, vma, plane, map_flags);
+		return virgl_3d_bo_map(bo, vma, map_flags);
 	else
-		return drv_dumb_bo_map(bo, vma, plane, map_flags);
+		return drv_dumb_bo_map(bo, vma, map_flags);
+}
+
+static bool is_arc_screen_capture_bo(struct bo *bo)
+{
+	struct drm_prime_handle prime_handle = {};
+	int ret, fd;
+	char tmp[256];
+
+	if (bo->meta.num_planes != 1 ||
+	    (bo->meta.format != DRM_FORMAT_ABGR8888 && bo->meta.format != DRM_FORMAT_ARGB8888 &&
+	     bo->meta.format != DRM_FORMAT_XRGB8888 && bo->meta.format != DRM_FORMAT_XBGR8888))
+		return false;
+	prime_handle.handle = bo->handles[0].u32;
+	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle);
+	if (ret < 0)
+		return false;
+	snprintf(tmp, sizeof(tmp), "/proc/self/fdinfo/%d", prime_handle.fd);
+	fd = open(tmp, O_RDONLY);
+	if (fd < 0) {
+		close(prime_handle.fd);
+		return false;
+	}
+	ret = read(fd, tmp, sizeof(tmp) - 1);
+	close(prime_handle.fd);
+	close(fd);
+	if (ret < 0)
+		return false;
+	tmp[ret] = 0;
+
+	return strstr(tmp, "ARC-SCREEN-CAP");
 }
 
 static int virgl_bo_invalidate(struct bo *bo, struct mapping *mapping)
@@ -812,6 +857,15 @@
 	else
 		host_write_flags |= BO_USE_HW_VIDEO_DECODER;
 
+	// TODO(b/267892346): Revert this workaround after migrating to virtgpu_cross_domain
+	// backend since it's a special arc only behavior.
+	if (!(bo->meta.use_flags & (BO_USE_ARC_SCREEN_CAP_PROBED | BO_USE_RENDERING))) {
+		bo->meta.use_flags |= BO_USE_ARC_SCREEN_CAP_PROBED;
+		if (is_arc_screen_capture_bo(bo)) {
+			bo->meta.use_flags |= BO_USE_RENDERING;
+		}
+	}
+
 	if ((bo->meta.use_flags & host_write_flags) == 0)
 		return 0;
 
@@ -863,8 +917,8 @@
 
 		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST, &xfer);
 		if (ret) {
-			drv_log("DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST failed with %s\n",
-				strerror(errno));
+			drv_loge("DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST failed with %s\n",
+				 strerror(errno));
 			return -errno;
 		}
 	}
@@ -875,7 +929,7 @@
 	waitcmd.handle = mapping->vma->handle;
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_WAIT, &waitcmd);
 	if (ret) {
-		drv_log("DRM_IOCTL_VIRTGPU_WAIT failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_WAIT failed with %s\n", strerror(errno));
 		return -errno;
 	}
 
@@ -939,8 +993,8 @@
 
 		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST, &xfer);
 		if (ret) {
-			drv_log("DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST failed with %s\n",
-				strerror(errno));
+			drv_loge("DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST failed with %s\n",
+				 strerror(errno));
 			return -errno;
 		}
 	}
@@ -954,7 +1008,7 @@
 
 		ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_WAIT, &waitcmd);
 		if (ret) {
-			drv_log("DRM_IOCTL_VIRTGPU_WAIT failed with %s\n", strerror(errno));
+			drv_loge("DRM_IOCTL_VIRTGPU_WAIT failed with %s\n", strerror(errno));
 			return -errno;
 		}
 	}
@@ -968,22 +1022,31 @@
 {
 	*out_format = format;
 	*out_use_flags = use_flags;
+
+	/* resolve flexible format into explicit format */
 	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 */
+			/* HACK: See b/28671744 and b/264408280 */
 			*out_format = DRM_FORMAT_XBGR8888;
 			*out_use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
+			*out_use_flags |= BO_USE_LINEAR;
 		}
 		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. */
 		*out_format = DRM_FORMAT_NV12;
-		/* fallthrough */
+		break;
+	default:
+		break;
+	}
+
+	/* resolve explicit format */
+	switch (*out_format) {
 	case DRM_FORMAT_NV12:
 	case DRM_FORMAT_ABGR8888:
 	case DRM_FORMAT_ARGB8888:
@@ -992,8 +1055,8 @@
 	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))
+		if ((*out_use_flags & BO_USE_SCANOUT) &&
+		    !virgl_supports_combination_natively(drv, *out_format, BO_USE_SCANOUT))
 			*out_use_flags &= ~BO_USE_SCANOUT;
 		break;
 	case DRM_FORMAT_YVU420_ANDROID:
@@ -1066,7 +1129,7 @@
 	res_info.type = VIRTGPU_RESOURCE_INFO_TYPE_EXTENDED;
 	ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_RESOURCE_INFO_CROS, &res_info);
 	if (ret) {
-		drv_log("DRM_IOCTL_VIRTGPU_RESOURCE_INFO failed with %s\n", strerror(errno));
+		drv_loge("DRM_IOCTL_VIRTGPU_RESOURCE_INFO failed with %s\n", strerror(errno));
 		return ret;
 	}
 
@@ -1098,6 +1161,7 @@
 				       .init = virgl_init,
 				       .close = virgl_close,
 				       .bo_create = virgl_bo_create,
+				       .bo_create_with_modifiers = virgl_bo_create_with_modifiers,
 				       .bo_destroy = virgl_bo_destroy,
 				       .bo_import = drv_prime_bo_import,
 				       .bo_map = virgl_bo_map,