[Mesa-dev] [PATCH 5/5] st/dri: implement the GL interop DRI extension

Marek Olšák maraeo at gmail.com
Thu Mar 3 19:46:18 UTC 2016


From: Marek Olšák <marek.olsak at amd.com>

---
 src/gallium/state_trackers/dri/dri2.c | 255 ++++++++++++++++++++++++++++++++++
 1 file changed, 255 insertions(+)

diff --git a/src/gallium/state_trackers/dri/dri2.c b/src/gallium/state_trackers/dri/dri2.c
index 7f7fbc4..b0e42a8 100644
--- a/src/gallium/state_trackers/dri/dri2.c
+++ b/src/gallium/state_trackers/dri/dri2.c
@@ -30,14 +30,19 @@
 
 #include <xf86drm.h>
 #include <dlfcn.h>
+#include "GL/mesa_glinterop.h"
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
 #include "util/u_format.h"
 #include "util/u_debug.h"
 #include "state_tracker/drm_driver.h"
+#include "state_tracker/st_cb_bufferobjects.h"
+#include "state_tracker/st_cb_fbo.h"
+#include "state_tracker/st_cb_texture.h"
 #include "state_tracker/st_texture.h"
 #include "state_tracker/st_context.h"
 #include "pipe-loader/pipe_loader.h"
+#include "main/bufferobj.h"
 #include "main/texobj.h"
 
 #include "dri_screen.h"
@@ -1417,6 +1422,254 @@ static const __DRIrobustnessExtension dri2Robustness = {
    .base = { __DRI2_ROBUSTNESS, 1 }
 };
 
+#define offset_after(type, ptr, member) \
+   offsetof(type, member) + sizeof(ptr->member)
+
+static int
+dri2_interop_query_device_info(__DRIcontext *_ctx,
+                               mesa_glinterop_device_info *out)
+{
+   struct pipe_screen *screen = dri_context(_ctx)->st->pipe->screen;
+
+   if (out->size < offset_after(mesa_glinterop_device_info, out, device_id))
+      return MESA_GLINTEROP_INVALID_VALUE;
+
+   out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP);
+   out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS);
+   out->pci_device = screen->get_param(screen, PIPE_CAP_PCI_DEVICE);
+   out->pci_function = screen->get_param(screen, PIPE_CAP_PCI_FUNCTION);
+
+   out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID);
+   out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID);
+
+   return MESA_GLINTEROP_SUCCESS;
+}
+
+static int
+dri2_interop_export_object(__DRIcontext *_ctx,
+                           mesa_glinterop_export_in *in,
+                           mesa_glinterop_export_out *out)
+{
+   struct st_context_iface *st = dri_context(_ctx)->st;
+   struct pipe_screen *screen = st->pipe->screen;
+   struct gl_context *ctx = ((struct st_context *)st)->ctx;
+   struct pipe_resource *res = NULL;
+   struct winsys_handle whandle;
+   unsigned target, usage;
+   boolean success;
+
+   /* Check structure sizes first. */
+   if (in->size < offset_after(mesa_glinterop_export_in, in,
+                               out_driver_data))
+      return MESA_GLINTEROP_INVALID_VALUE;
+
+   if (out->size < offset_after(mesa_glinterop_export_out, out,
+                                view_numlayers))
+      return MESA_GLINTEROP_INVALID_VALUE;
+
+   /* Validate the target. */
+   switch (in->target) {
+   case GL_TEXTURE_BUFFER:
+   case GL_TEXTURE_1D:
+   case GL_TEXTURE_2D:
+   case GL_TEXTURE_3D:
+   case GL_TEXTURE_RECTANGLE:
+   case GL_TEXTURE_1D_ARRAY:
+   case GL_TEXTURE_2D_ARRAY:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_TEXTURE_CUBE_MAP:
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_TEXTURE_EXTERNAL_OES:
+   case GL_RENDERBUFFER:
+   case GL_ARRAY_BUFFER:
+      target = in->target;
+      break;
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+      target = GL_TEXTURE_CUBE_MAP;
+      break;
+   default:
+      return MESA_GLINTEROP_INVALID_TARGET;
+   }
+
+   /* Validate the simple case of miplevel. */
+   if ((target == GL_RENDERBUFFER || target == GL_ARRAY_BUFFER) &&
+       in->miplevel != 0)
+      return MESA_GLINTEROP_INVALID_MIP_LEVEL;
+
+   /* Validate the OpenGL object and get pipe_resource. */
+   mtx_lock(&ctx->Shared->Mutex);
+
+   if (target == GL_ARRAY_BUFFER) {
+      /* Buffer objects.
+       *
+       * The error checking is based on the documentation of
+       * clCreateFromGLBuffer from OpenCL 2.0 SDK.
+       */
+      struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, in->obj);
+
+      /* From OpenCL 2.0 SDK, clCreateFromGLBuffer:
+       *  "CL_INVALID_GL_OBJECT if bufobj is not a GL buffer object or is
+       *   a GL buffer object but does not have an existing data store or
+       *   the size of the buffer is 0."
+       */
+      if (!buf || buf->Size == 0) {
+         mtx_unlock(&ctx->Shared->Mutex);
+         return MESA_GLINTEROP_INVALID_OBJECT;
+      }
+
+      res = st_buffer_object(buf)->buffer;
+      if (!res) {
+         /* this shouldn't happen */
+         mtx_unlock(&ctx->Shared->Mutex);
+         return MESA_GLINTEROP_INVALID_OBJECT;
+      }
+
+      buf->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
+   } else if (target == GL_RENDERBUFFER) {
+      /* Renderbuffers.
+       *
+       * The error checking is based on the documentation of
+       * clCreateFromGLRenderbuffer from OpenCL 2.0 SDK.
+       */
+      struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, in->obj);
+
+      /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
+       *   "CL_INVALID_GL_OBJECT if renderbuffer is not a GL renderbuffer
+       *    object or if the width or height of renderbuffer is zero."
+       */
+      if (!rb || rb->Width == 0 || rb->Height == 0) {
+         mtx_unlock(&ctx->Shared->Mutex);
+         return MESA_GLINTEROP_INVALID_OBJECT;
+      }
+
+      /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
+       *   "CL_INVALID_OPERATION if renderbuffer is a multi-sample GL
+       *    renderbuffer object."
+       */
+      if (rb->NumSamples > 1) {
+         mtx_unlock(&ctx->Shared->Mutex);
+         return MESA_GLINTEROP_INVALID_OPERATION;
+      }
+
+      /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
+       *   "CL_OUT_OF_RESOURCES if there is a failure to allocate resources
+       *    required by the OpenCL implementation on the device."
+       */
+      res = st_renderbuffer(rb)->texture;
+      if (!res) {
+         mtx_unlock(&ctx->Shared->Mutex);
+         return MESA_GLINTEROP_OUT_OF_RESOURCES;
+      }
+
+      out->internalformat = rb->InternalFormat;
+      out->view_minlevel = 0;
+      out->view_numlevels = 1;
+      out->view_minlayer = 0;
+      out->view_numlayers = 1;
+   } else {
+      /* Texture objects.
+       *
+       * The error checking is based on the documentation of
+       * clCreateFromGLTexture from OpenCL 2.0 SDK.
+       */
+      struct gl_texture_object *obj = _mesa_lookup_texture(ctx, in->obj);
+
+      if (obj)
+         _mesa_test_texobj_completeness(ctx, obj);
+
+      /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
+       *   "CL_INVALID_GL_OBJECT if texture is not a GL texture object whose
+       *    type matches texture_target, if the specified miplevel of texture
+       *    is not defined, or if the width or height of the specified
+       *    miplevel is zero or if the GL texture object is incomplete."
+       */
+      if (!obj ||
+          obj->Target != target ||
+          !obj->_BaseComplete ||
+          (in->miplevel > 0 && !obj->_MipmapComplete)) {
+         mtx_unlock(&ctx->Shared->Mutex);
+         return MESA_GLINTEROP_INVALID_OBJECT;
+      }
+
+      /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
+       *   "CL_INVALID_MIP_LEVEL if miplevel is less than the value of
+       *    levelbase (for OpenGL implementations) or zero (for OpenGL ES
+       *    implementations); or greater than the value of q (for both OpenGL
+       *    and OpenGL ES). levelbase and q are defined for the texture in
+       *    section 3.8.10 (Texture Completeness) of the OpenGL 2.1
+       *    specification and section 3.7.10 of the OpenGL ES 2.0."
+       */
+      if (in->miplevel < obj->BaseLevel || in->miplevel > obj->_MaxLevel) {
+         mtx_unlock(&ctx->Shared->Mutex);
+         return MESA_GLINTEROP_INVALID_MIP_LEVEL;
+      }
+
+      if (!st_finalize_texture(ctx, st->pipe, obj)) {
+         mtx_unlock(&ctx->Shared->Mutex);
+         return MESA_GLINTEROP_OUT_OF_RESOURCES;
+      }
+
+      res = st_get_texobj_resource(obj);
+      if (!res) {
+         /* Incomplete texture buffer object? This shouldn't really occur. */
+         mtx_unlock(&ctx->Shared->Mutex);
+         return MESA_GLINTEROP_INVALID_OBJECT;
+      }
+
+      if (target == GL_TEXTURE_BUFFER) {
+         out->internalformat = obj->BufferObjectFormat;
+         out->buf_offset = obj->BufferOffset;
+         out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size :
+                                                 obj->BufferSize;
+      } else {
+         out->internalformat = obj->Image[0][0]->InternalFormat;
+         out->view_minlevel = obj->MinLevel;
+         out->view_numlevels = obj->NumLevels;
+         out->view_minlayer = obj->MinLayer;
+         out->view_numlayers = obj->NumLayers;
+      }
+   }
+
+   /* Get the handle. */
+   switch (in->access) {
+   case MESA_GLINTEROP_ACCESS_READ_WRITE:
+      usage = PIPE_HANDLE_USAGE_READ_WRITE;
+      break;
+   case MESA_GLINTEROP_ACCESS_READ_ONLY:
+      usage = PIPE_HANDLE_USAGE_READ;
+      break;
+   case MESA_GLINTEROP_ACCESS_WRITE_ONLY:
+      usage = PIPE_HANDLE_USAGE_WRITE;
+      break;
+   default:
+      usage = 0;
+   }
+
+   memset(&whandle, 0, sizeof(whandle));
+   whandle.type = DRM_API_HANDLE_TYPE_FD;
+
+   success = screen->resource_get_handle(screen, res, &whandle, usage);
+   mtx_unlock(&ctx->Shared->Mutex);
+
+   if (!success)
+      return MESA_GLINTEROP_OUT_OF_HOST_MEMORY;
+
+   out->dmabuf_fd = whandle.handle;
+   return MESA_GLINTEROP_SUCCESS;
+}
+
+static const __DRI2interopExtension dri2InteropExtension = {
+   .base = { __DRI2_INTEROP, 1 },
+   .query_device_info = dri2_interop_query_device_info,
+   .export_object = dri2_interop_export_object
+};
+
 /*
  * Backend function init_screen.
  */
@@ -1429,6 +1682,7 @@ static const __DRIextension *dri_screen_extensions[] = {
    &dri2ConfigQueryExtension.base,
    &dri2ThrottleExtension.base,
    &dri2FenceExtension.base,
+   &dri2InteropExtension.base,
    NULL
 };
 
@@ -1440,6 +1694,7 @@ static const __DRIextension *dri_robust_screen_extensions[] = {
    &dri2ConfigQueryExtension.base,
    &dri2ThrottleExtension.base,
    &dri2FenceExtension.base,
+   &dri2InteropExtension.base,
    &dri2Robustness.base,
    NULL
 };
-- 
2.5.0



More information about the mesa-dev mailing list