From 4fa3d35cc52bc49fd0e2c3e7976d428885bc94ba Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Mon, 29 Feb 2016 23:25:59 +0100 Subject: [PATCH] st/dri: implement the GL interop DRI extension (v2.2) v2: - set interop_version - simplify the offset_after macro v2.1: - use version numbers, remove offset_after - set "out_driver_data_written" v2.2: - set buf_offset & buf_size for GL_ARRAY_BUFFER too - add whandle.offset to buf_offset - disable the minmax cache for GL_TEXTURE_BUFFER --- src/gallium/state_trackers/dri/dri2.c | 258 ++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) diff --git a/src/gallium/state_trackers/dri/dri2.c b/src/gallium/state_trackers/dri/dri2.c index 468d0569b52..675a9bb21cf 100644 --- a/src/gallium/state_trackers/dri/dri2.c +++ b/src/gallium/state_trackers/dri/dri2.c @@ -30,14 +30,19 @@ #include #include +#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" @@ -1416,6 +1421,257 @@ static const __DRIrobustnessExtension dri2Robustness = { .base = { __DRI2_ROBUSTNESS, 1 } }; +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->struct_version) + 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); + + out->interop_version = 1; + + return MESA_GLINTEROP_SUCCESS; +} + +static int +dri2_interop_export_object(__DRIcontext *_ctx, + const 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; + + if (!in->struct_version || !out->struct_version) + 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; + } + + out->buf_offset = 0; + out->buf_size = buf->Size; + + 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; + + obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE; + } 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; + out->out_driver_data_written = 0; + + if (res->target == PIPE_BUFFER) + out->buf_offset += whandle.offset; + + 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. */ @@ -1428,6 +1684,7 @@ static const __DRIextension *dri_screen_extensions[] = { &dri2ConfigQueryExtension.base, &dri2ThrottleExtension.base, &dri2FenceExtension.base, + &dri2InteropExtension.base, NULL }; @@ -1439,6 +1696,7 @@ static const __DRIextension *dri_robust_screen_extensions[] = { &dri2ConfigQueryExtension.base, &dri2ThrottleExtension.base, &dri2FenceExtension.base, + &dri2InteropExtension.base, &dri2Robustness.base, NULL }; -- 2.30.2