i915: avoid vertical alignment for FORMAT_BLOB

HAL_PIXEL_FORMAT_BLOB gets resolved into DRM_FORMAT_R8 with height of 1.
Avoid doing any vertical alignment for this case. Ideally we want a new
DRM_FORMAT_BLOB format.

BUG=b:255226937
TEST=atest CtsNNAPITestCases:GpuNnapiTest

Change-Id: Iea86481392b40c6c827f84323cb50450ddec03a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/4035255
Auto-Submit: Yiwei Zhang <zzyiwei@chromium.org>
Reviewed-by: Chad Versace <chadversary@chromium.org>
Tested-by: Yiwei Zhang <zzyiwei@chromium.org>
Commit-Queue: Yiwei Zhang <zzyiwei@chromium.org>
diff --git a/i915.c b/i915.c
index a40f88f..29b1c69 100644
--- a/i915.c
+++ b/i915.c
@@ -316,7 +316,7 @@
 	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;
@@ -342,7 +342,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:
@@ -473,7 +490,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;