[Mesa-dev] [RFC 11/13] gbm: dri: support for creating YUV formatted buffers

Topi Pohjolainen topi.pohjolainen at intel.com
Tue Feb 26 05:19:02 PST 2013


Specifically YUV420, YVU420 (YV12) and NV12 formatted. The logic is
pretty much taken from Kristian Hogsberg [1]. All the planes are
back-to-back but each starts at page boundary. Horizontal and
vertical alignment are set according to sampling engine constraints.
This is to serve piglit testing of the image external extension as
one needs a way of creating and writing YUV formatted buffers that
can be further passed to EGL as images.

[1] http://cgit.freedesktop.org/~krh/simple-yuv

Signed-off-by: Topi Pohjolainen <topi.pohjolainen at intel.com>
---
 src/gbm/backends/dri/gbm_dri.c             |    9 ++++
 src/mesa/drivers/dri/intel/intel_regions.c |   64 ++++++++++++++++++++++++++++
 src/mesa/drivers/dri/intel/intel_regions.h |    6 +++
 src/mesa/drivers/dri/intel/intel_screen.c  |   22 ++++++++--
 4 files changed, 98 insertions(+), 3 deletions(-)

diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c
index a3a0530..8bd9303 100644
--- a/src/gbm/backends/dri/gbm_dri.c
+++ b/src/gbm/backends/dri/gbm_dri.c
@@ -547,6 +547,15 @@ gbm_dri_bo_create(struct gbm_device *gbm,
    case GBM_FORMAT_ABGR8888:
       dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
       break;
+   case GBM_FORMAT_YUV420:
+      dri_format = __DRI_IMAGE_FOURCC_YUV420;
+      break;
+   case GBM_FORMAT_YVU420:
+      dri_format = __DRI_IMAGE_FOURCC_YVU420;
+      break;
+   case GBM_FORMAT_NV12:
+      dri_format = __DRI_IMAGE_FOURCC_NV12;
+      break;
    default:
       return NULL;
    }
diff --git a/src/mesa/drivers/dri/intel/intel_regions.c b/src/mesa/drivers/dri/intel/intel_regions.c
index e0b9217..9989240 100644
--- a/src/mesa/drivers/dri/intel/intel_regions.c
+++ b/src/mesa/drivers/dri/intel/intel_regions.c
@@ -43,6 +43,7 @@
 #include <errno.h>
 
 #include "main/hash.h"
+#include "main/macros.h"
 #include "intel_context.h"
 #include "intel_regions.h"
 #include "intel_blit.h"
@@ -219,6 +220,69 @@ intel_region_alloc(struct intel_screen *screen,
    return region;
 }
 
+/**
+ * The region is allocated in a way that it can be accessed by the sampling
+ * engine as it is (width aligned by four and height by two). Also the plane
+ * offsets are on page boundary in order to allow them to be further used as
+ * images on their own.
+ */
+struct intel_region *
+intel_region_planar_alloc(struct intel_screen *screen,
+			  int fourcc, GLuint width, GLuint height,
+			  uint32_t *strides, uint32_t *offsets)
+{
+   drm_intel_bo *buffer;
+   struct intel_region *region;
+   unsigned total;
+
+   /* For now one supports only formats with 2x2 subsampled UV-planes */
+   if (height % 2 || width % 2)
+      return NULL;
+
+   strides[0] = ALIGN(width, 4);
+   offsets[0] = 0;
+
+   total = strides[0] * ALIGN(height, 2);
+
+   switch (fourcc) {
+   case __DRI_IMAGE_FOURCC_YUV420:
+   case __DRI_IMAGE_FOURCC_YVU420:
+      strides[1] = ALIGN(width / 2, 4);
+      offsets[1] = ALIGN(total, 4096);
+
+      total = offsets[1] + strides[1] * ALIGN(height / 2, 2);
+      strides[2] = ALIGN(width / 2, 4);
+
+      offsets[2] = ALIGN(total, 4096);
+      total = offsets[2] + strides[2] * ALIGN(height / 2, 2);
+      break;
+   case __DRI_IMAGE_FOURCC_NV12:
+      strides[1] = ALIGN(width, 4);
+      offsets[1] = ALIGN(total, 4096);
+
+      total = offsets[1] + strides[1] * ALIGN(height / 2, 2);
+
+      strides[2] = 0;
+      offsets[2] = 0;
+      break;
+   default:
+      return NULL;
+   }
+
+   buffer = drm_intel_bo_alloc(screen->bufmgr, "region", total, 0);
+   if (buffer == NULL)
+      return NULL;
+
+   region = intel_region_alloc_internal(screen, 1, width, height,
+                                        width, I915_TILING_NONE, buffer);
+   if (region == NULL) {
+      drm_intel_bo_unreference(buffer);
+      return NULL;
+   }
+
+   return region;
+}
+
 bool
 intel_region_flink(struct intel_region *region, uint32_t *name)
 {
diff --git a/src/mesa/drivers/dri/intel/intel_regions.h b/src/mesa/drivers/dri/intel/intel_regions.h
index 543b3a7..bc3157b 100644
--- a/src/mesa/drivers/dri/intel/intel_regions.h
+++ b/src/mesa/drivers/dri/intel/intel_regions.h
@@ -83,6 +83,12 @@ struct intel_region *intel_region_alloc(struct intel_screen *screen,
                                         GLuint height,
 					bool expect_accelerated_upload);
 
+struct intel_region *intel_region_planar_alloc(struct intel_screen *screen,
+					       int fourcc,
+					       GLuint width, GLuint height,
+					       uint32_t *strides,
+					       uint32_t *offsets);
+
 struct intel_region *
 intel_region_alloc_for_handle(struct intel_screen *screen,
 			      GLuint cpp,
diff --git a/src/mesa/drivers/dri/intel/intel_screen.c b/src/mesa/drivers/dri/intel/intel_screen.c
index 698c8ac..8b5040a 100644
--- a/src/mesa/drivers/dri/intel/intel_screen.c
+++ b/src/mesa/drivers/dri/intel/intel_screen.c
@@ -307,6 +307,12 @@ intel_allocate_image(int dri_format, void *loaderPrivate)
     case __DRI_IMAGE_FORMAT_GR88:
        image->format = MESA_FORMAT_GR88;
        break;
+    case __DRI_IMAGE_FOURCC_YUV420:
+    case __DRI_IMAGE_FOURCC_YVU420:
+    case __DRI_IMAGE_FOURCC_NV12:
+       image->format = MESA_FORMAT_R8;
+       image->planar_format = intel_image_format_lookup(dri_format);
+       break;
     case __DRI_IMAGE_FORMAT_NONE:
        image->format = MESA_FORMAT_NONE;
        break;
@@ -527,9 +533,19 @@ intel_create_image(__DRIscreen *screen,
    }
 
    image = intel_allocate_image(format, loaderPrivate);
-   cpp = _mesa_get_format_bytes(image->format);
-   image->region =
-      intel_region_alloc(intelScreen, tiling, cpp, width, height, true);
+
+   if (format == __DRI_IMAGE_FOURCC_YUV420 ||
+       format == __DRI_IMAGE_FOURCC_YVU420 ||
+       format == __DRI_IMAGE_FOURCC_NV12) {
+      image->region =
+         intel_region_planar_alloc(intelScreen, format, width, height,
+	 			   image->strides, image->offsets);
+   } else {
+      cpp = _mesa_get_format_bytes(image->format);
+      image->region =
+         intel_region_alloc(intelScreen, tiling, cpp, width, height, true);
+   }
+
    if (image->region == NULL) {
       free(image);
       return NULL;
-- 
1.7.9.5



More information about the mesa-dev mailing list