• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009, VMware, Inc.
3  * Copyright (C) 2010 LunarG Inc.
4  * Copyright © Microsoft Corporation
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23  * IN THE SOFTWARE.
24  */
25 
26 #include "st_interop.h"
27 #include "st_cb_texture.h"
28 #include "st_cb_flush.h"
29 #include "st_texture.h"
30 
31 #include "bufferobj.h"
32 #include "texobj.h"
33 #include "teximage.h"
34 #include "syncobj.h"
35 
36 int
st_interop_query_device_info(struct st_context * st,struct mesa_glinterop_device_info * out)37 st_interop_query_device_info(struct st_context *st,
38                              struct mesa_glinterop_device_info *out)
39 {
40    struct pipe_screen *screen = st->pipe->screen;
41 
42    /* There is no version 0, thus we do not support it */
43    if (out->version == 0)
44       return MESA_GLINTEROP_INVALID_VERSION;
45 
46    /* PCI values are obsolete on version >= 4 of the interface */
47    if (out->version < 4) {
48       out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP);
49       out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS);
50       out->pci_device = screen->get_param(screen, PIPE_CAP_PCI_DEVICE);
51       out->pci_function = screen->get_param(screen, PIPE_CAP_PCI_FUNCTION);
52    }
53 
54    out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID);
55    out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID);
56 
57    if (out->version > 1 && screen->interop_query_device_info)
58       out->driver_data_size = screen->interop_query_device_info(screen,
59                                                                 out->driver_data_size,
60                                                                 out->driver_data);
61 
62    if (out->version >= 3 && screen->get_device_uuid)
63       screen->get_device_uuid(screen, out->device_uuid);
64 
65    /* Instruct the caller that we support up-to version four of the interface */
66    out->version = MIN2(out->version, 4);
67 
68    return MESA_GLINTEROP_SUCCESS;
69 }
70 
71 static int
lookup_object(struct gl_context * ctx,struct mesa_glinterop_export_in * in,struct mesa_glinterop_export_out * out,struct pipe_resource ** res)72 lookup_object(struct gl_context *ctx,
73               struct mesa_glinterop_export_in *in,
74               struct mesa_glinterop_export_out *out, struct pipe_resource **res)
75 {
76    unsigned target = in->target;
77    /* Validate the target. */
78    switch (in->target) {
79    case GL_TEXTURE_BUFFER:
80    case GL_TEXTURE_1D:
81    case GL_TEXTURE_2D:
82    case GL_TEXTURE_3D:
83    case GL_TEXTURE_RECTANGLE:
84    case GL_TEXTURE_1D_ARRAY:
85    case GL_TEXTURE_2D_ARRAY:
86    case GL_TEXTURE_CUBE_MAP_ARRAY:
87    case GL_TEXTURE_CUBE_MAP:
88    case GL_TEXTURE_2D_MULTISAMPLE:
89    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
90    case GL_TEXTURE_EXTERNAL_OES:
91    case GL_RENDERBUFFER:
92    case GL_ARRAY_BUFFER:
93       break;
94    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
95    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
96    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
97    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
98    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
99    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
100       target = GL_TEXTURE_CUBE_MAP;
101       break;
102    default:
103       return MESA_GLINTEROP_INVALID_TARGET;
104    }
105 
106    /* Validate the simple case of miplevel. */
107    if ((target == GL_RENDERBUFFER || target == GL_ARRAY_BUFFER) &&
108        in->miplevel != 0)
109       return MESA_GLINTEROP_INVALID_MIP_LEVEL;
110 
111    if (target == GL_ARRAY_BUFFER) {
112       /* Buffer objects.
113       *
114       * The error checking is based on the documentation of
115       * clCreateFromGLBuffer from OpenCL 2.0 SDK.
116       */
117       struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, in->obj);
118 
119       /* From OpenCL 2.0 SDK, clCreateFromGLBuffer:
120       *  "CL_INVALID_GL_OBJECT if bufobj is not a GL buffer object or is
121       *   a GL buffer object but does not have an existing data store or
122       *   the size of the buffer is 0."
123       */
124       if (!buf || buf->Size == 0)
125          return MESA_GLINTEROP_INVALID_OBJECT;
126 
127       *res = buf->buffer;
128       /* this shouldn't happen */
129       if (!*res)
130          return MESA_GLINTEROP_INVALID_OBJECT;
131 
132       if (out) {
133          out->buf_offset = 0;
134          out->buf_size = buf->Size;
135 
136          buf->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
137       }
138    } else if (target == GL_RENDERBUFFER) {
139       /* Renderbuffers.
140       *
141       * The error checking is based on the documentation of
142       * clCreateFromGLRenderbuffer from OpenCL 2.0 SDK.
143       */
144       struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, in->obj);
145 
146       /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
147       *   "CL_INVALID_GL_OBJECT if renderbuffer is not a GL renderbuffer
148       *    object or if the width or height of renderbuffer is zero."
149       */
150       if (!rb || rb->Width == 0 || rb->Height == 0)
151          return MESA_GLINTEROP_INVALID_OBJECT;
152 
153       /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
154       *   "CL_INVALID_OPERATION if renderbuffer is a multi-sample GL
155       *    renderbuffer object."
156       */
157       if (rb->NumSamples > 1)
158          return MESA_GLINTEROP_INVALID_OPERATION;
159 
160       /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
161       *   "CL_OUT_OF_RESOURCES if there is a failure to allocate resources
162       *    required by the OpenCL implementation on the device."
163       */
164       *res = rb->texture;
165       if (!*res)
166          return MESA_GLINTEROP_OUT_OF_RESOURCES;
167 
168       if (out) {
169          out->internal_format = rb->InternalFormat;
170          out->view_minlevel = 0;
171          out->view_numlevels = 1;
172          out->view_minlayer = 0;
173          out->view_numlayers = 1;
174 
175          if (out->version >= 2) {
176            out->width = rb->Width;
177            out->height = rb->Height;
178            out->depth = MAX2(1, rb->Depth);
179          }
180       }
181    } else {
182       /* Texture objects.
183       *
184       * The error checking is based on the documentation of
185       * clCreateFromGLTexture from OpenCL 2.0 SDK.
186       */
187       struct gl_texture_object *obj = _mesa_lookup_texture(ctx, in->obj);
188 
189       if (obj)
190          _mesa_test_texobj_completeness(ctx, obj);
191 
192       /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
193       *   "CL_INVALID_GL_OBJECT if texture is not a GL texture object whose
194       *    type matches texture_target, if the specified miplevel of texture
195       *    is not defined, or if the width or height of the specified
196       *    miplevel is zero or if the GL texture object is incomplete."
197       */
198       if (!obj ||
199           obj->Target != target ||
200           !obj->_BaseComplete ||
201           (in->miplevel > 0 && !obj->_MipmapComplete))
202          return MESA_GLINTEROP_INVALID_OBJECT;
203 
204       if (target == GL_TEXTURE_BUFFER) {
205          struct gl_buffer_object *stBuf =
206             obj->BufferObject;
207 
208          /* this shouldn't happen */
209          if (!stBuf || !stBuf->buffer)
210             return MESA_GLINTEROP_INVALID_OBJECT;
211          *res = stBuf->buffer;
212 
213          if (out) {
214             out->internal_format = obj->BufferObjectFormat;
215             out->buf_offset = obj->BufferOffset;
216             out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size :
217                obj->BufferSize;
218 
219             obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
220          }
221       } else {
222          /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
223          *   "CL_INVALID_MIP_LEVEL if miplevel is less than the value of
224          *    levelbase (for OpenGL implementations) or zero (for OpenGL ES
225          *    implementations); or greater than the value of q (for both OpenGL
226          *    and OpenGL ES). levelbase and q are defined for the texture in
227          *    section 3.8.10 (Texture Completeness) of the OpenGL 2.1
228          *    specification and section 3.7.10 of the OpenGL ES 2.0."
229          */
230          if (in->miplevel < obj->Attrib.BaseLevel || in->miplevel > obj->_MaxLevel)
231             return MESA_GLINTEROP_INVALID_MIP_LEVEL;
232 
233          if (!st_finalize_texture(ctx, ctx->st->pipe, obj, 0))
234             return MESA_GLINTEROP_OUT_OF_RESOURCES;
235 
236          *res = st_get_texobj_resource(obj);
237          /* Incomplete texture buffer object? This shouldn't really occur. */
238          if (!*res)
239             return MESA_GLINTEROP_INVALID_OBJECT;
240 
241          if (out) {
242             out->internal_format = obj->Image[0][0]->InternalFormat;
243             out->view_minlevel = obj->Attrib.MinLevel;
244             out->view_numlevels = obj->Attrib.NumLevels;
245             out->view_minlayer = obj->Attrib.MinLayer;
246             out->view_numlayers = obj->Attrib.NumLayers;
247 
248             if (out->version >= 2) {
249                const GLuint face = _mesa_tex_target_to_face(in->target);;
250                struct gl_texture_image *image = obj->Image[face][in->miplevel];
251 
252                out->width = image->Width;
253                out->height = image->Height;
254                out->depth = image->Depth;
255             }
256          }
257       }
258    }
259    return MESA_GLINTEROP_SUCCESS;
260 }
261 
262 int
st_interop_export_object(struct st_context * st,struct mesa_glinterop_export_in * in,struct mesa_glinterop_export_out * out)263 st_interop_export_object(struct st_context *st,
264                          struct mesa_glinterop_export_in *in,
265                          struct mesa_glinterop_export_out *out)
266 {
267    struct pipe_screen *screen = st->pipe->screen;
268    struct gl_context *ctx = st->ctx;
269    struct pipe_resource *res = NULL;
270    struct winsys_handle whandle;
271    unsigned usage;
272    bool success;
273    bool need_export_dmabuf = true;
274 
275    /* There is no version 0, thus we do not support it */
276    if (in->version == 0 || out->version == 0)
277       return MESA_GLINTEROP_INVALID_VERSION;
278 
279    /* Wait for glthread to finish to get up-to-date GL object lookups. */
280    _mesa_glthread_finish(st->ctx);
281 
282    /* Validate the OpenGL object and get pipe_resource. */
283    simple_mtx_lock(&ctx->Shared->Mutex);
284 
285    int ret = lookup_object(ctx, in, out, &res);
286    if (ret != MESA_GLINTEROP_SUCCESS) {
287       simple_mtx_unlock(&ctx->Shared->Mutex);
288       return ret;
289    }
290 
291    /* Get the handle. */
292    switch (in->access) {
293    case MESA_GLINTEROP_ACCESS_READ_ONLY:
294       usage = 0;
295       break;
296    case MESA_GLINTEROP_ACCESS_READ_WRITE:
297    case MESA_GLINTEROP_ACCESS_WRITE_ONLY:
298       usage = PIPE_HANDLE_USAGE_SHADER_WRITE;
299       break;
300    default:
301       usage = 0;
302    }
303 
304    out->out_driver_data_written = 0;
305    if (screen->interop_export_object) {
306       out->out_driver_data_written = screen->interop_export_object(screen,
307                                                                    res,
308                                                                    in->out_driver_data_size,
309                                                                    in->out_driver_data,
310                                                                    &need_export_dmabuf);
311    }
312 
313    memset(&whandle, 0, sizeof(whandle));
314 
315    if (need_export_dmabuf) {
316       whandle.type = WINSYS_HANDLE_TYPE_FD;
317 
318       /* OpenCL requires explicit flushes. */
319       if (out->version >= 2)
320          usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
321 
322       success = screen->resource_get_handle(screen, st->pipe, res, &whandle,
323                                             usage);
324 
325       if (!success) {
326          simple_mtx_unlock(&ctx->Shared->Mutex);
327          return MESA_GLINTEROP_OUT_OF_HOST_MEMORY;
328       }
329 
330 #ifndef _WIN32
331       out->dmabuf_fd = whandle.handle;
332 #else
333       out->win32_handle = whandle.handle;
334 #endif
335 
336       if (out->version >= 2) {
337          out->modifier = whandle.modifier;
338          out->stride = whandle.stride;
339       }
340    }
341 
342    simple_mtx_unlock(&ctx->Shared->Mutex);
343 
344    if (res->target == PIPE_BUFFER)
345       out->buf_offset += whandle.offset;
346 
347    /* Instruct the caller of the version of the interface we support */
348    in->version = MIN2(in->version, 2);
349    out->version = MIN2(out->version, 2);
350 
351    return MESA_GLINTEROP_SUCCESS;
352 }
353 
354 static int
flush_object(struct gl_context * ctx,struct mesa_glinterop_export_in * in)355 flush_object(struct gl_context *ctx,
356                         struct mesa_glinterop_export_in *in)
357 {
358    struct pipe_resource *res = NULL;
359    /* There is no version 0, thus we do not support it */
360    if (in->version == 0)
361       return MESA_GLINTEROP_INVALID_VERSION;
362 
363    int ret = lookup_object(ctx, in, NULL, &res);
364    if (ret != MESA_GLINTEROP_SUCCESS)
365       return ret;
366 
367    ctx->pipe->flush_resource(ctx->pipe, res);
368 
369    /* Instruct the caller of the version of the interface we support */
370    in->version = MIN2(in->version, 2);
371 
372    return MESA_GLINTEROP_SUCCESS;
373 }
374 
375 int
st_interop_flush_objects(struct st_context * st,unsigned count,struct mesa_glinterop_export_in * objects,struct mesa_glinterop_flush_out * out)376 st_interop_flush_objects(struct st_context *st,
377                          unsigned count, struct mesa_glinterop_export_in *objects,
378                          struct mesa_glinterop_flush_out *out)
379 {
380    struct gl_context *ctx = st->ctx;
381    bool flush_out_struct = false;
382 
383    /* Wait for glthread to finish to get up-to-date GL object lookups. */
384    _mesa_glthread_finish(st->ctx);
385 
386    simple_mtx_lock(&ctx->Shared->Mutex);
387 
388    for (unsigned i = 0; i < count; ++i) {
389       int ret = flush_object(ctx, &objects[i]);
390 
391       if (objects[i].version >= 2)
392          flush_out_struct = true;
393 
394       if (ret != MESA_GLINTEROP_SUCCESS) {
395          simple_mtx_unlock(&ctx->Shared->Mutex);
396          return ret;
397       }
398    }
399 
400    simple_mtx_unlock(&ctx->Shared->Mutex);
401 
402    if (count > 0 && out) {
403       if (flush_out_struct) {
404          if (out->sync) {
405             *out->sync = _mesa_fence_sync(ctx, GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
406          }
407          if (out->fence_fd) {
408             struct pipe_fence_handle *fence = NULL;
409             ctx->pipe->flush(ctx->pipe, &fence, PIPE_FLUSH_FENCE_FD | PIPE_FLUSH_ASYNC);
410             *out->fence_fd = ctx->screen->fence_get_fd(ctx->screen, fence);
411          }
412          out->version = MIN2(out->version, 1);
413       } else {
414          GLsync *sync = (GLsync *)out;
415          *sync = _mesa_fence_sync(ctx, GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
416       }
417    }
418 
419    return MESA_GLINTEROP_SUCCESS;
420 }
421