egl/android: handle multi-fd native windows
authorRob Clark <robdclark@chromium.org>
Fri, 12 Jul 2019 16:17:30 +0000 (09:17 -0700)
committerRob Clark <robdclark@gmail.com>
Tue, 16 Jul 2019 18:14:44 +0000 (18:14 +0000)
We can hit multi-fd EGL_NATIVE_BUFFER_ANDROID case when the native
android buffer is YUV.  So we need to handle that.

Currently this went unnoticed because, even though we have two or
three fd's for YUV native android buffers, they all reference the
same backing buffer.  But we really shouldn't rely on that.

Signed-off-by: Rob Clark <robdclark@chromium.org>
Reviewed-by: Eric Engestrom <eric@engestrom.ch>
Reviewed-by: Kristian H. Kristensen <hoegsberg@google.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
src/egl/drivers/dri2/platform_android.c

index db6ba4a4b4d63a5acafec93e4d9aafb6b0937066..d949ed42a3825bc9c3b0300e632aed28a915f4de 100644 (file)
@@ -72,7 +72,7 @@ static const struct droid_yuv_format droid_yuv_formats[] = {
    { HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 1, __DRI_IMAGE_FOURCC_YUV420 },
    { HAL_PIXEL_FORMAT_YCbCr_420_888, YCrCb, 1, __DRI_IMAGE_FOURCC_YVU420 },
    { HAL_PIXEL_FORMAT_YV12,          YCrCb, 1, __DRI_IMAGE_FOURCC_YVU420 },
-   /* HACK: See droid_create_image_from_prime_fd() and
+   /* HACK: See droid_create_image_from_prime_fds() and
     * https://issuetracker.google.com/32077885. */
    { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 2, __DRI_IMAGE_FOURCC_NV12 },
    { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 1, __DRI_IMAGE_FOURCC_YUV420 },
@@ -167,16 +167,24 @@ static int get_format(int format)
    return -1;
 }
 
-static int
-get_native_buffer_fd(struct ANativeWindowBuffer *buf)
+/* returns # of fds, and by reference the actual fds */
+static unsigned
+get_native_buffer_fds(struct ANativeWindowBuffer *buf, int fds[3])
 {
    native_handle_t *handle = (native_handle_t *)buf->handle;
+
+   if (!handle)
+      return 0;
+
    /*
     * Various gralloc implementations exist, but the dma-buf fd tends
     * to be first. Access it directly to avoid a dependency on specific
     * gralloc versions.
     */
-   return (handle && handle->numFds) ? handle->data[0] : -1;
+   for (int i = 0; i < handle->numFds; i++)
+      fds[i] = handle->data[i];
+
+   return handle->numFds;
 }
 
 #ifdef HAVE_DRM_GRALLOC
@@ -533,7 +541,8 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
    struct dri2_egl_display *dri2_dpy =
       dri2_egl_display(dri2_surf->base.Resource.Display);
    int fourcc, pitch;
-   int offset = 0, fd;
+   int offset = 0, fds[3];
+   unsigned num_fds;
 
    if (dri2_surf->dri_image_back)
       return 0;
@@ -544,8 +553,8 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
          return -1;
       }
 
-      fd = get_native_buffer_fd(dri2_surf->buffer);
-      if (fd < 0) {
+      num_fds = get_native_buffer_fds(dri2_surf->buffer, fds);
+      if (num_fds == 0) {
          _eglLog(_EGL_WARNING, "Could not get native buffer FD");
          return -1;
       }
@@ -566,8 +575,8 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
                                              dri2_surf->base.Width,
                                              dri2_surf->base.Height,
                                              fourcc,
-                                             &fd,
-                                             1,
+                                             fds,
+                                             num_fds,
                                              &pitch,
                                              &offset,
                                              dri2_surf);
@@ -766,8 +775,9 @@ droid_set_damage_region(_EGLDriver *drv,
 #endif
 
 static _EGLImage *
-droid_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx,
-                                     struct ANativeWindowBuffer *buf, int fd)
+droid_create_image_from_prime_fds_yuv(_EGLDisplay *disp, _EGLContext *ctx,
+                                     struct ANativeWindowBuffer *buf,
+                                     int num_fds, int fds[3])
 {
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    struct android_ycbcr ycbcr;
@@ -786,7 +796,7 @@ droid_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx,
    ret = dri2_dpy->gralloc->lock_ycbcr(dri2_dpy->gralloc, buf->handle,
                                        0, 0, 0, 0, 0, &ycbcr);
    if (ret) {
-      /* HACK: See droid_create_image_from_prime_fd() and
+      /* HACK: See droid_create_image_from_prime_fds() and
        * https://issuetracker.google.com/32077885.*/
       if (buf->format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)
          return NULL;
@@ -827,16 +837,28 @@ droid_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx,
       return NULL;
    }
 
+   /*
+    * Since this is EGL_NATIVE_BUFFER_ANDROID don't assume that
+    * the single-fd case cannot happen.  So handle eithe single
+    * fd or fd-per-plane case:
+    */
+   if (num_fds == 1) {
+      fds[2] = fds[1] = fds[0];
+   } else {
+      int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3;
+      assert(num_fds == expected_planes);
+   }
+
    if (ycbcr.chroma_step == 2) {
       /* Semi-planar Y + CbCr or Y + CrCb format. */
       const EGLint attr_list_2plane[] = {
          EGL_WIDTH, buf->width,
          EGL_HEIGHT, buf->height,
          EGL_LINUX_DRM_FOURCC_EXT, fourcc,
-         EGL_DMA_BUF_PLANE0_FD_EXT, fd,
+         EGL_DMA_BUF_PLANE0_FD_EXT, fds[0],
          EGL_DMA_BUF_PLANE0_PITCH_EXT, pitches[0],
          EGL_DMA_BUF_PLANE0_OFFSET_EXT, offsets[0],
-         EGL_DMA_BUF_PLANE1_FD_EXT, fd,
+         EGL_DMA_BUF_PLANE1_FD_EXT, fds[1],
          EGL_DMA_BUF_PLANE1_PITCH_EXT, pitches[1],
          EGL_DMA_BUF_PLANE1_OFFSET_EXT, offsets[1],
          EGL_NONE, 0
@@ -849,13 +871,13 @@ droid_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx,
          EGL_WIDTH, buf->width,
          EGL_HEIGHT, buf->height,
          EGL_LINUX_DRM_FOURCC_EXT, fourcc,
-         EGL_DMA_BUF_PLANE0_FD_EXT, fd,
+         EGL_DMA_BUF_PLANE0_FD_EXT, fds[0],
          EGL_DMA_BUF_PLANE0_PITCH_EXT, pitches[0],
          EGL_DMA_BUF_PLANE0_OFFSET_EXT, offsets[0],
-         EGL_DMA_BUF_PLANE1_FD_EXT, fd,
+         EGL_DMA_BUF_PLANE1_FD_EXT, fds[1],
          EGL_DMA_BUF_PLANE1_PITCH_EXT, pitches[1],
          EGL_DMA_BUF_PLANE1_OFFSET_EXT, offsets[1],
-         EGL_DMA_BUF_PLANE2_FD_EXT, fd,
+         EGL_DMA_BUF_PLANE2_FD_EXT, fds[2],
          EGL_DMA_BUF_PLANE2_PITCH_EXT, pitches[2],
          EGL_DMA_BUF_PLANE2_OFFSET_EXT, offsets[2],
          EGL_NONE, 0
@@ -866,15 +888,15 @@ droid_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx,
 }
 
 static _EGLImage *
-droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
-                                 struct ANativeWindowBuffer *buf, int fd)
+droid_create_image_from_prime_fds(_EGLDisplay *disp, _EGLContext *ctx,
+                                  struct ANativeWindowBuffer *buf, int num_fds, int fds[3])
 {
    unsigned int pitch;
 
    if (is_yuv(buf->format)) {
       _EGLImage *image;
 
-      image = droid_create_image_from_prime_fd_yuv(disp, ctx, buf, fd);
+      image = droid_create_image_from_prime_fds_yuv(disp, ctx, buf, num_fds, fds);
       /*
        * HACK: https://issuetracker.google.com/32077885
        * There is no API available to properly query the IMPLEMENTATION_DEFINED
@@ -886,6 +908,13 @@ droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
          return image;
    }
 
+   /*
+    * Non-YUV formats could *also* have multiple planes, such as ancillary
+    * color compression state buffer, but the rest of the code isn't ready
+    * yet to deal with modifiers:
+    */
+   assert(num_fds == 1);
+
    const int fourcc = get_fourcc(buf->format);
    if (fourcc == -1) {
       _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
@@ -902,7 +931,7 @@ droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
       EGL_WIDTH, buf->width,
       EGL_HEIGHT, buf->height,
       EGL_LINUX_DRM_FOURCC_EXT, fourcc,
-      EGL_DMA_BUF_PLANE0_FD_EXT, fd,
+      EGL_DMA_BUF_PLANE0_FD_EXT, fds[0],
       EGL_DMA_BUF_PLANE0_PITCH_EXT, pitch,
       EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
       EGL_NONE, 0
@@ -988,7 +1017,8 @@ dri2_create_image_android_native_buffer(_EGLDisplay *disp,
                                         _EGLContext *ctx,
                                         struct ANativeWindowBuffer *buf)
 {
-   int fd;
+   int fds[3];
+   unsigned num_fds;
 
    if (ctx != NULL) {
       /* From the EGL_ANDROID_image_native_buffer spec:
@@ -1008,9 +1038,9 @@ dri2_create_image_android_native_buffer(_EGLDisplay *disp,
       return NULL;
    }
 
-   fd = get_native_buffer_fd(buf);
-   if (fd >= 0)
-      return droid_create_image_from_prime_fd(disp, ctx, buf, fd);
+   num_fds = get_native_buffer_fds(buf, fds);
+   if (num_fds > 0)
+      return droid_create_image_from_prime_fds(disp, ctx, buf, num_fds, fds);
 
 #ifdef HAVE_DRM_GRALLOC
    return droid_create_image_from_name(disp, ctx, buf);