1 /* 2 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include <dlfcn.h> 24 #include "util/u_memory.h" 25 #include "pipe/p_screen.h" 26 #include "state_tracker/st_texture.h" 27 #include "state_tracker/st_context.h" 28 #include "state_tracker/st_cb_fbo.h" 29 #include "main/texobj.h" 30 31 #include "dri_helpers.h" 32 33 static bool 34 dri2_is_opencl_interop_loaded_locked(struct dri_screen *screen) 35 { 36 return screen->opencl_dri_event_add_ref && 37 screen->opencl_dri_event_release && 38 screen->opencl_dri_event_wait && 39 screen->opencl_dri_event_get_fence; 40 } 41 42 static bool 43 dri2_load_opencl_interop(struct dri_screen *screen) 44 { 45 #if defined(RTLD_DEFAULT) 46 bool success; 47 48 mtx_lock(&screen->opencl_func_mutex); 49 50 if (dri2_is_opencl_interop_loaded_locked(screen)) { 51 mtx_unlock(&screen->opencl_func_mutex); 52 return true; 53 } 54 55 screen->opencl_dri_event_add_ref = 56 dlsym(RTLD_DEFAULT, "opencl_dri_event_add_ref"); 57 screen->opencl_dri_event_release = 58 dlsym(RTLD_DEFAULT, "opencl_dri_event_release"); 59 screen->opencl_dri_event_wait = 60 dlsym(RTLD_DEFAULT, "opencl_dri_event_wait"); 61 screen->opencl_dri_event_get_fence = 62 dlsym(RTLD_DEFAULT, "opencl_dri_event_get_fence"); 63 64 success = dri2_is_opencl_interop_loaded_locked(screen); 65 mtx_unlock(&screen->opencl_func_mutex); 66 return success; 67 #else 68 return false; 69 #endif 70 } 71 72 struct dri2_fence { 73 struct dri_screen *driscreen; 74 struct pipe_fence_handle *pipe_fence; 75 void *cl_event; 76 }; 77 78 static unsigned dri2_fence_get_caps(__DRIscreen *_screen) 79 { 80 struct dri_screen *driscreen = dri_screen(_screen); 81 struct pipe_screen *screen = driscreen->base.screen; 82 unsigned caps = 0; 83 84 if (screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD)) 85 caps |= __DRI_FENCE_CAP_NATIVE_FD; 86 87 return caps; 88 } 89 90 static void * 91 dri2_create_fence(__DRIcontext *_ctx) 92 { 93 struct st_context_iface *stapi = dri_context(_ctx)->st; 94 struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence); 95 96 if (!fence) 97 return NULL; 98 99 stapi->flush(stapi, 0, &fence->pipe_fence); 100 101 if (!fence->pipe_fence) { 102 FREE(fence); 103 return NULL; 104 } 105 106 fence->driscreen = dri_screen(_ctx->driScreenPriv); 107 return fence; 108 } 109 110 static void * 111 dri2_create_fence_fd(__DRIcontext *_ctx, int fd) 112 { 113 struct st_context_iface *stapi = dri_context(_ctx)->st; 114 struct pipe_context *ctx = stapi->pipe; 115 struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence); 116 117 if (fd == -1) { 118 /* exporting driver created fence, flush: */ 119 stapi->flush(stapi, ST_FLUSH_FENCE_FD, &fence->pipe_fence); 120 } else { 121 /* importing a foreign fence fd: */ 122 ctx->create_fence_fd(ctx, &fence->pipe_fence, fd); 123 } 124 if (!fence->pipe_fence) { 125 FREE(fence); 126 return NULL; 127 } 128 129 fence->driscreen = dri_screen(_ctx->driScreenPriv); 130 return fence; 131 } 132 133 static int 134 dri2_get_fence_fd(__DRIscreen *_screen, void *_fence) 135 { 136 struct dri_screen *driscreen = dri_screen(_screen); 137 struct pipe_screen *screen = driscreen->base.screen; 138 struct dri2_fence *fence = (struct dri2_fence*)_fence; 139 140 return screen->fence_get_fd(screen, fence->pipe_fence); 141 } 142 143 static void * 144 dri2_get_fence_from_cl_event(__DRIscreen *_screen, intptr_t cl_event) 145 { 146 struct dri_screen *driscreen = dri_screen(_screen); 147 struct dri2_fence *fence; 148 149 if (!dri2_load_opencl_interop(driscreen)) 150 return NULL; 151 152 fence = CALLOC_STRUCT(dri2_fence); 153 if (!fence) 154 return NULL; 155 156 fence->cl_event = (void*)cl_event; 157 158 if (!driscreen->opencl_dri_event_add_ref(fence->cl_event)) { 159 free(fence); 160 return NULL; 161 } 162 163 fence->driscreen = driscreen; 164 return fence; 165 } 166 167 static void 168 dri2_destroy_fence(__DRIscreen *_screen, void *_fence) 169 { 170 struct dri_screen *driscreen = dri_screen(_screen); 171 struct pipe_screen *screen = driscreen->base.screen; 172 struct dri2_fence *fence = (struct dri2_fence*)_fence; 173 174 if (fence->pipe_fence) 175 screen->fence_reference(screen, &fence->pipe_fence, NULL); 176 else if (fence->cl_event) 177 driscreen->opencl_dri_event_release(fence->cl_event); 178 else 179 assert(0); 180 181 FREE(fence); 182 } 183 184 static GLboolean 185 dri2_client_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags, 186 uint64_t timeout) 187 { 188 struct dri2_fence *fence = (struct dri2_fence*)_fence; 189 struct dri_screen *driscreen = fence->driscreen; 190 struct pipe_screen *screen = driscreen->base.screen; 191 192 /* No need to flush. The context was flushed when the fence was created. */ 193 194 if (fence->pipe_fence) 195 return screen->fence_finish(screen, NULL, fence->pipe_fence, timeout); 196 else if (fence->cl_event) { 197 struct pipe_fence_handle *pipe_fence = 198 driscreen->opencl_dri_event_get_fence(fence->cl_event); 199 200 if (pipe_fence) 201 return screen->fence_finish(screen, NULL, pipe_fence, timeout); 202 else 203 return driscreen->opencl_dri_event_wait(fence->cl_event, timeout); 204 } 205 else { 206 assert(0); 207 return false; 208 } 209 } 210 211 static void 212 dri2_server_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags) 213 { 214 struct pipe_context *ctx = dri_context(_ctx)->st->pipe; 215 struct dri2_fence *fence = (struct dri2_fence*)_fence; 216 217 if (ctx->fence_server_sync) 218 ctx->fence_server_sync(ctx, fence->pipe_fence); 219 } 220 221 const __DRI2fenceExtension dri2FenceExtension = { 222 .base = { __DRI2_FENCE, 2 }, 223 224 .create_fence = dri2_create_fence, 225 .get_fence_from_cl_event = dri2_get_fence_from_cl_event, 226 .destroy_fence = dri2_destroy_fence, 227 .client_wait_sync = dri2_client_wait_sync, 228 .server_wait_sync = dri2_server_wait_sync, 229 .get_capabilities = dri2_fence_get_caps, 230 .create_fence_fd = dri2_create_fence_fd, 231 .get_fence_fd = dri2_get_fence_fd, 232 }; 233 234 __DRIimage * 235 dri2_lookup_egl_image(struct dri_screen *screen, void *handle) 236 { 237 const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image; 238 __DRIimage *img; 239 240 if (!loader->lookupEGLImage) 241 return NULL; 242 243 img = loader->lookupEGLImage(screen->sPriv, 244 handle, screen->sPriv->loaderPrivate); 245 246 return img; 247 } 248 249 __DRIimage * 250 dri2_create_image_from_renderbuffer2(__DRIcontext *context, 251 int renderbuffer, void *loaderPrivate, 252 unsigned *error) 253 { 254 struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx; 255 struct gl_renderbuffer *rb; 256 struct pipe_resource *tex; 257 __DRIimage *img; 258 259 /* Section 3.9 (EGLImage Specification and Management) of the EGL 1.5 260 * specification says: 261 * 262 * "If target is EGL_GL_RENDERBUFFER and buffer is not the name of a 263 * renderbuffer object, or if buffer is the name of a multisampled 264 * renderbuffer object, the error EGL_BAD_PARAMETER is generated." 265 * 266 * "If target is EGL_GL_TEXTURE_2D , EGL_GL_TEXTURE_CUBE_MAP_*, 267 * EGL_GL_RENDERBUFFER or EGL_GL_TEXTURE_3D and buffer refers to the 268 * default GL texture object (0) for the corresponding GL target, the 269 * error EGL_BAD_PARAMETER is generated." 270 * (rely on _mesa_lookup_renderbuffer returning NULL in this case) 271 */ 272 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 273 if (!rb || rb->NumSamples > 0) { 274 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; 275 return NULL; 276 } 277 278 tex = st_get_renderbuffer_resource(rb); 279 if (!tex) { 280 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; 281 return NULL; 282 } 283 284 img = CALLOC_STRUCT(__DRIimageRec); 285 if (!img) { 286 *error = __DRI_IMAGE_ERROR_BAD_ALLOC; 287 return NULL; 288 } 289 290 img->dri_format = driGLFormatToImageFormat(rb->Format); 291 img->loader_private = loaderPrivate; 292 293 if (img->dri_format == __DRI_IMAGE_FORMAT_NONE) { 294 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; 295 free(img); 296 return NULL; 297 } 298 299 pipe_resource_reference(&img->texture, tex); 300 301 *error = __DRI_IMAGE_ERROR_SUCCESS; 302 return img; 303 } 304 305 __DRIimage * 306 dri2_create_image_from_renderbuffer(__DRIcontext *context, 307 int renderbuffer, void *loaderPrivate) 308 { 309 unsigned error; 310 return dri2_create_image_from_renderbuffer2(context, renderbuffer, 311 loaderPrivate, &error); 312 } 313 314 void 315 dri2_destroy_image(__DRIimage *img) 316 { 317 pipe_resource_reference(&img->texture, NULL); 318 FREE(img); 319 } 320 321 322 __DRIimage * 323 dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture, 324 int depth, int level, unsigned *error, 325 void *loaderPrivate) 326 { 327 __DRIimage *img; 328 struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx; 329 struct gl_texture_object *obj; 330 struct pipe_resource *tex; 331 GLuint face = 0; 332 333 obj = _mesa_lookup_texture(ctx, texture); 334 if (!obj || obj->Target != target) { 335 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; 336 return NULL; 337 } 338 339 tex = st_get_texobj_resource(obj); 340 if (!tex) { 341 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; 342 return NULL; 343 } 344 345 if (target == GL_TEXTURE_CUBE_MAP) 346 face = depth; 347 348 _mesa_test_texobj_completeness(ctx, obj); 349 if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) { 350 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; 351 return NULL; 352 } 353 354 if (level < obj->BaseLevel || level > obj->_MaxLevel) { 355 *error = __DRI_IMAGE_ERROR_BAD_MATCH; 356 return NULL; 357 } 358 359 if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < depth) { 360 *error = __DRI_IMAGE_ERROR_BAD_MATCH; 361 return NULL; 362 } 363 364 img = CALLOC_STRUCT(__DRIimageRec); 365 if (!img) { 366 *error = __DRI_IMAGE_ERROR_BAD_ALLOC; 367 return NULL; 368 } 369 370 img->level = level; 371 img->layer = depth; 372 img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat); 373 374 img->loader_private = loaderPrivate; 375 376 if (img->dri_format == __DRI_IMAGE_FORMAT_NONE) { 377 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; 378 free(img); 379 return NULL; 380 } 381 382 pipe_resource_reference(&img->texture, tex); 383 384 *error = __DRI_IMAGE_ERROR_SUCCESS; 385 return img; 386 } 387 388 /* vim: set sw=3 ts=8 sts=3 expandtab: */ 389