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 if (!screen->resource_get_handle && !screen->interop_export_object)
47 return MESA_GLINTEROP_UNSUPPORTED;
48
49 /* PCI values are obsolete on version >= 4 of the interface */
50 if (out->version < 4) {
51 out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP);
52 out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS);
53 out->pci_device = screen->get_param(screen, PIPE_CAP_PCI_DEVICE);
54 out->pci_function = screen->get_param(screen, PIPE_CAP_PCI_FUNCTION);
55 }
56
57 out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID);
58 out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID);
59
60 if (out->version > 1 && screen->interop_query_device_info)
61 out->driver_data_size = screen->interop_query_device_info(screen,
62 out->driver_data_size,
63 out->driver_data);
64
65 if (out->version >= 3 && screen->get_device_uuid)
66 screen->get_device_uuid(screen, out->device_uuid);
67
68 /* Instruct the caller that we support up-to version four of the interface */
69 out->version = MIN2(out->version, 4);
70
71 return MESA_GLINTEROP_SUCCESS;
72 }
73
74 static int
lookup_object(struct gl_context * ctx,struct mesa_glinterop_export_in * in,struct mesa_glinterop_export_out * out,struct pipe_resource ** res)75 lookup_object(struct gl_context *ctx,
76 struct mesa_glinterop_export_in *in,
77 struct mesa_glinterop_export_out *out, struct pipe_resource **res)
78 {
79 unsigned target = in->target;
80 /* Validate the target. */
81 switch (in->target) {
82 case GL_TEXTURE_BUFFER:
83 case GL_TEXTURE_1D:
84 case GL_TEXTURE_2D:
85 case GL_TEXTURE_3D:
86 case GL_TEXTURE_RECTANGLE:
87 case GL_TEXTURE_1D_ARRAY:
88 case GL_TEXTURE_2D_ARRAY:
89 case GL_TEXTURE_CUBE_MAP_ARRAY:
90 case GL_TEXTURE_CUBE_MAP:
91 case GL_TEXTURE_2D_MULTISAMPLE:
92 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
93 case GL_TEXTURE_EXTERNAL_OES:
94 case GL_RENDERBUFFER:
95 case GL_ARRAY_BUFFER:
96 break;
97 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
98 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
99 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
100 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
101 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
102 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
103 target = GL_TEXTURE_CUBE_MAP;
104 break;
105 default:
106 return MESA_GLINTEROP_INVALID_TARGET;
107 }
108
109 /* Validate the simple case of miplevel. */
110 if ((target == GL_RENDERBUFFER || target == GL_ARRAY_BUFFER) &&
111 in->miplevel != 0)
112 return MESA_GLINTEROP_INVALID_MIP_LEVEL;
113
114 if (target == GL_ARRAY_BUFFER) {
115 /* Buffer objects.
116 *
117 * The error checking is based on the documentation of
118 * clCreateFromGLBuffer from OpenCL 2.0 SDK.
119 */
120 struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, in->obj);
121
122 /* From OpenCL 2.0 SDK, clCreateFromGLBuffer:
123 * "CL_INVALID_GL_OBJECT if bufobj is not a GL buffer object or is
124 * a GL buffer object but does not have an existing data store or
125 * the size of the buffer is 0."
126 */
127 if (!buf || buf->Size == 0)
128 return MESA_GLINTEROP_INVALID_OBJECT;
129
130 *res = buf->buffer;
131 /* this shouldn't happen */
132 if (!*res)
133 return MESA_GLINTEROP_INVALID_OBJECT;
134
135 if (out) {
136 out->buf_offset = 0;
137 out->buf_size = buf->Size;
138
139 buf->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
140 }
141 } else if (target == GL_RENDERBUFFER) {
142 /* Renderbuffers.
143 *
144 * The error checking is based on the documentation of
145 * clCreateFromGLRenderbuffer from OpenCL 2.0 SDK.
146 */
147 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, in->obj);
148
149 /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
150 * "CL_INVALID_GL_OBJECT if renderbuffer is not a GL renderbuffer
151 * object or if the width or height of renderbuffer is zero."
152 */
153 if (!rb || rb->Width == 0 || rb->Height == 0)
154 return MESA_GLINTEROP_INVALID_OBJECT;
155
156 /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
157 * "CL_INVALID_OPERATION if renderbuffer is a multi-sample GL
158 * renderbuffer object."
159 */
160 if (rb->NumSamples > 1)
161 return MESA_GLINTEROP_INVALID_OPERATION;
162
163 /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
164 * "CL_OUT_OF_RESOURCES if there is a failure to allocate resources
165 * required by the OpenCL implementation on the device."
166 */
167 *res = rb->texture;
168 if (!*res)
169 return MESA_GLINTEROP_OUT_OF_RESOURCES;
170
171 if (out) {
172 out->internal_format = rb->InternalFormat;
173 out->view_minlevel = 0;
174 out->view_numlevels = 1;
175 out->view_minlayer = 0;
176 out->view_numlayers = 1;
177
178 if (out->version >= 2) {
179 out->width = rb->Width;
180 out->height = rb->Height;
181 out->depth = MAX2(1, rb->Depth);
182 }
183 }
184 } else {
185 /* Texture objects.
186 *
187 * The error checking is based on the documentation of
188 * clCreateFromGLTexture from OpenCL 2.0 SDK.
189 */
190 struct gl_texture_object *obj = _mesa_lookup_texture(ctx, in->obj);
191
192 if (obj)
193 _mesa_test_texobj_completeness(ctx, obj);
194
195 /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
196 * "CL_INVALID_GL_OBJECT if texture is not a GL texture object whose
197 * type matches texture_target, if the specified miplevel of texture
198 * is not defined, or if the width or height of the specified
199 * miplevel is zero or if the GL texture object is incomplete."
200 */
201 if (!obj ||
202 obj->Target != target ||
203 !obj->_BaseComplete ||
204 (in->miplevel > 0 && !obj->_MipmapComplete))
205 return MESA_GLINTEROP_INVALID_OBJECT;
206
207 if (target == GL_TEXTURE_BUFFER) {
208 struct gl_buffer_object *stBuf =
209 obj->BufferObject;
210
211 /* this shouldn't happen */
212 if (!stBuf || !stBuf->buffer)
213 return MESA_GLINTEROP_INVALID_OBJECT;
214 *res = stBuf->buffer;
215
216 if (out) {
217 out->internal_format = obj->BufferObjectFormat;
218 out->buf_offset = obj->BufferOffset;
219 out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size :
220 obj->BufferSize;
221
222 obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
223 }
224 } else {
225 /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
226 * "CL_INVALID_MIP_LEVEL if miplevel is less than the value of
227 * levelbase (for OpenGL implementations) or zero (for OpenGL ES
228 * implementations); or greater than the value of q (for both OpenGL
229 * and OpenGL ES). levelbase and q are defined for the texture in
230 * section 3.8.10 (Texture Completeness) of the OpenGL 2.1
231 * specification and section 3.7.10 of the OpenGL ES 2.0."
232 */
233 if (in->miplevel < obj->Attrib.BaseLevel || in->miplevel > obj->_MaxLevel)
234 return MESA_GLINTEROP_INVALID_MIP_LEVEL;
235
236 if (!st_finalize_texture(ctx, ctx->st->pipe, obj, 0))
237 return MESA_GLINTEROP_OUT_OF_RESOURCES;
238
239 *res = st_get_texobj_resource(obj);
240 /* Incomplete texture buffer object? This shouldn't really occur. */
241 if (!*res)
242 return MESA_GLINTEROP_INVALID_OBJECT;
243
244 if (out) {
245 out->internal_format = obj->Image[0][0]->InternalFormat;
246 out->view_minlevel = obj->Attrib.MinLevel;
247 out->view_numlevels = obj->Attrib.NumLevels;
248 out->view_minlayer = obj->Attrib.MinLayer;
249 out->view_numlayers = obj->Attrib.NumLayers;
250
251 if (out->version >= 2) {
252 const GLuint face = _mesa_tex_target_to_face(in->target);;
253 struct gl_texture_image *image = obj->Image[face][in->miplevel];
254
255 out->width = image->Width;
256 out->height = image->Height;
257 out->depth = image->Depth;
258 }
259 }
260 }
261 }
262 return MESA_GLINTEROP_SUCCESS;
263 }
264
265 int
st_interop_export_object(struct st_context * st,struct mesa_glinterop_export_in * in,struct mesa_glinterop_export_out * out)266 st_interop_export_object(struct st_context *st,
267 struct mesa_glinterop_export_in *in,
268 struct mesa_glinterop_export_out *out)
269 {
270 struct pipe_screen *screen = st->pipe->screen;
271 struct gl_context *ctx = st->ctx;
272 struct pipe_resource *res = NULL;
273 struct winsys_handle whandle;
274 unsigned usage;
275 bool success;
276 bool need_export_dmabuf = true;
277
278 /* There is no version 0, thus we do not support it */
279 if (in->version == 0 || out->version == 0)
280 return MESA_GLINTEROP_INVALID_VERSION;
281
282 if (!screen->resource_get_handle && !screen->interop_export_object)
283 return MESA_GLINTEROP_UNSUPPORTED;
284
285 /* Wait for glthread to finish to get up-to-date GL object lookups. */
286 _mesa_glthread_finish(st->ctx);
287
288 /* Validate the OpenGL object and get pipe_resource. */
289 simple_mtx_lock(&ctx->Shared->Mutex);
290
291 int ret = lookup_object(ctx, in, out, &res);
292 if (ret != MESA_GLINTEROP_SUCCESS) {
293 simple_mtx_unlock(&ctx->Shared->Mutex);
294 return ret;
295 }
296
297 /* Get the handle. */
298 switch (in->access) {
299 case MESA_GLINTEROP_ACCESS_READ_ONLY:
300 usage = 0;
301 break;
302 case MESA_GLINTEROP_ACCESS_READ_WRITE:
303 case MESA_GLINTEROP_ACCESS_WRITE_ONLY:
304 usage = PIPE_HANDLE_USAGE_SHADER_WRITE;
305 break;
306 default:
307 usage = 0;
308 }
309
310 out->out_driver_data_written = 0;
311 if (screen->interop_export_object) {
312 out->out_driver_data_written = screen->interop_export_object(screen,
313 res,
314 in->out_driver_data_size,
315 in->out_driver_data,
316 &need_export_dmabuf);
317 }
318
319 memset(&whandle, 0, sizeof(whandle));
320
321 if (need_export_dmabuf) {
322 whandle.type = WINSYS_HANDLE_TYPE_FD;
323
324 /* OpenCL requires explicit flushes. */
325 if (out->version >= 2)
326 usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
327
328 success = screen->resource_get_handle(screen, st->pipe, res, &whandle,
329 usage);
330
331 if (!success) {
332 simple_mtx_unlock(&ctx->Shared->Mutex);
333 return MESA_GLINTEROP_OUT_OF_HOST_MEMORY;
334 }
335
336 #ifndef _WIN32
337 out->dmabuf_fd = whandle.handle;
338 #else
339 out->win32_handle = whandle.handle;
340 #endif
341
342 if (out->version >= 2) {
343 out->modifier = whandle.modifier;
344 out->stride = whandle.stride;
345 }
346 }
347
348 simple_mtx_unlock(&ctx->Shared->Mutex);
349
350 if (res->target == PIPE_BUFFER)
351 out->buf_offset += whandle.offset;
352
353 /* Instruct the caller of the version of the interface we support */
354 in->version = MIN2(in->version, 2);
355 out->version = MIN2(out->version, 2);
356
357 return MESA_GLINTEROP_SUCCESS;
358 }
359
360 static int
flush_object(struct gl_context * ctx,struct mesa_glinterop_export_in * in)361 flush_object(struct gl_context *ctx,
362 struct mesa_glinterop_export_in *in)
363 {
364 struct pipe_resource *res = NULL;
365 /* There is no version 0, thus we do not support it */
366 if (in->version == 0)
367 return MESA_GLINTEROP_INVALID_VERSION;
368
369 int ret = lookup_object(ctx, in, NULL, &res);
370 if (ret != MESA_GLINTEROP_SUCCESS)
371 return ret;
372
373 ctx->pipe->flush_resource(ctx->pipe, res);
374
375 /* Instruct the caller of the version of the interface we support */
376 in->version = MIN2(in->version, 2);
377
378 return MESA_GLINTEROP_SUCCESS;
379 }
380
381 int
st_interop_flush_objects(struct st_context * st,unsigned count,struct mesa_glinterop_export_in * objects,struct mesa_glinterop_flush_out * out)382 st_interop_flush_objects(struct st_context *st,
383 unsigned count, struct mesa_glinterop_export_in *objects,
384 struct mesa_glinterop_flush_out *out)
385 {
386 struct gl_context *ctx = st->ctx;
387 bool flush_out_struct = false;
388
389 if (!ctx->screen->resource_get_handle && !ctx->screen->interop_export_object)
390 return MESA_GLINTEROP_UNSUPPORTED;
391
392 /* Wait for glthread to finish to get up-to-date GL object lookups. */
393 _mesa_glthread_finish(st->ctx);
394
395 simple_mtx_lock(&ctx->Shared->Mutex);
396
397 for (unsigned i = 0; i < count; ++i) {
398 int ret = flush_object(ctx, &objects[i]);
399
400 if (objects[i].version >= 2)
401 flush_out_struct = true;
402
403 if (ret != MESA_GLINTEROP_SUCCESS) {
404 simple_mtx_unlock(&ctx->Shared->Mutex);
405 return ret;
406 }
407 }
408
409 simple_mtx_unlock(&ctx->Shared->Mutex);
410
411 if (count > 0 && out) {
412 if (flush_out_struct) {
413 if (out->sync) {
414 *out->sync = _mesa_fence_sync(ctx, GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
415 }
416 if (out->fence_fd) {
417 struct pipe_fence_handle *fence = NULL;
418 ctx->pipe->flush(ctx->pipe, &fence, PIPE_FLUSH_FENCE_FD | PIPE_FLUSH_ASYNC);
419 *out->fence_fd = ctx->screen->fence_get_fd(ctx->screen, fence);
420 }
421 out->version = MIN2(out->version, 1);
422 } else {
423 GLsync *sync = (GLsync *)out;
424 *sync = _mesa_fence_sync(ctx, GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
425 }
426 }
427
428 return MESA_GLINTEROP_SUCCESS;
429 }
430