iris: Hack around gbm_gralloc stride restrictions
authorKenneth Graunke <kenneth@whitecape.org>
Mon, 27 Mar 2023 20:43:38 +0000 (13:43 -0700)
committerMarge Bot <emma+marge@anholt.net>
Tue, 11 Apr 2023 23:45:04 +0000 (23:45 +0000)
gbm_bo_map returns a stride for the mapping, which may differ from the
stride of the underlying BO.  Drivers may implement mappings via staging
blits, returning a map of a temporary resource instead.  That temporary
may have fewer stride restrictions (i.e. it isn't used for display), and
thus be more tightly packed, saving memory.

However, gbm_gralloc has a design flaw where after calling gbm_bo_map,
it asserts that the stride exactly matches the original BO's stride:

   assert(stride == gbm_bo_get_stride(bo));

This is a bad assumption, as the GBM API returns a stride explicitly
precisely because it -can- differ.  But, this would require significant
changes to gbm_gralloc to fix.  So, to work around it, we add a driver
hack for Android-only that forces staging maps of any external BO to use
the original resource's stride.

This should fix issues with mapping cursor planes and SW media codec
uploads on Android-x86.

Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/7974
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22156>

src/gallium/drivers/iris/iris_resource.c

index 48b9c6d..07678db 100644 (file)
@@ -2077,14 +2077,37 @@ iris_map_copy_region(struct iris_transfer *map)
       .format = res->internal_format,
    };
 
-   if (xfer->resource->target == PIPE_BUFFER)
+   if (xfer->resource->target == PIPE_BUFFER) {
       templ.target = PIPE_BUFFER;
-   else if (templ.array_size > 1)
-      templ.target = PIPE_TEXTURE_2D_ARRAY;
-   else
-      templ.target = PIPE_TEXTURE_2D;
+      map->staging = iris_resource_create_for_buffer(pscreen, &templ);
+   } else {
+      templ.target = templ.array_size > 1 ? PIPE_TEXTURE_2D_ARRAY
+                                          : PIPE_TEXTURE_2D;
+
+      unsigned row_pitch_B = 0;
+
+#ifdef ANDROID
+      /* Staging buffers for stall-avoidance blits don't always have the
+       * same restrictions on stride as the original buffer.  For example,
+       * the original buffer may be used for scanout, while the staging
+       * buffer will not be.  So we may compute a smaller stride for the
+       * staging buffer than the original.
+       *
+       * Normally, this is good, as it saves memory.  Unfortunately, for
+       * Android, gbm_gralloc incorrectly asserts that the stride returned
+       * by gbm_bo_map() must equal the result of gbm_bo_get_stride(),
+       * which simply isn't always the case.
+       *
+       * Because gralloc is unlikely to be fixed, we hack around it in iris
+       * by forcing the staging buffer to have a matching stride.
+       */
+      if (iris_bo_is_external(res->bo))
+         row_pitch_B = res->surf.row_pitch_B;
+#endif
 
-   map->staging = iris_resource_create(pscreen, &templ);
+      map->staging =
+         iris_resource_create_for_image(pscreen, &templ, NULL, 0, row_pitch_B);
+   }
 
    /* If we fail to create a staging resource, the caller will fallback
     * to mapping directly on the CPU.