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 33static bool 34dri2_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 42static bool 43dri2_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 72struct dri2_fence { 73 struct dri_screen *driscreen; 74 struct pipe_fence_handle *pipe_fence; 75 void *cl_event; 76}; 77 78static 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 90static void * 91dri2_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 110static void * 111dri2_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, PIPE_FD_TYPE_NATIVE_SYNC); 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 133static int 134dri2_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 143static void * 144dri2_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 167static void 168dri2_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 184static GLboolean 185dri2_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 211static void 212dri2_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 /* We might be called here with a NULL fence as a result of WaitSyncKHR 218 * on a EGL_KHR_reusable_sync fence. Nothing to do here in such case. 219 */ 220 if (!fence) 221 return; 222 223 if (ctx->fence_server_sync) 224 ctx->fence_server_sync(ctx, fence->pipe_fence); 225} 226 227const __DRI2fenceExtension dri2FenceExtension = { 228 .base = { __DRI2_FENCE, 2 }, 229 230 .create_fence = dri2_create_fence, 231 .get_fence_from_cl_event = dri2_get_fence_from_cl_event, 232 .destroy_fence = dri2_destroy_fence, 233 .client_wait_sync = dri2_client_wait_sync, 234 .server_wait_sync = dri2_server_wait_sync, 235 .get_capabilities = dri2_fence_get_caps, 236 .create_fence_fd = dri2_create_fence_fd, 237 .get_fence_fd = dri2_get_fence_fd, 238}; 239 240__DRIimage * 241dri2_lookup_egl_image(struct dri_screen *screen, void *handle) 242{ 243 const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image; 244 __DRIimage *img; 245 246 if (!loader->lookupEGLImage) 247 return NULL; 248 249 img = loader->lookupEGLImage(screen->sPriv, 250 handle, screen->sPriv->loaderPrivate); 251 252 return img; 253} 254 255__DRIimage * 256dri2_create_image_from_renderbuffer2(__DRIcontext *context, 257 int renderbuffer, void *loaderPrivate, 258 unsigned *error) 259{ 260 struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx; 261 struct gl_renderbuffer *rb; 262 struct pipe_resource *tex; 263 __DRIimage *img; 264 265 /* Section 3.9 (EGLImage Specification and Management) of the EGL 1.5 266 * specification says: 267 * 268 * "If target is EGL_GL_RENDERBUFFER and buffer is not the name of a 269 * renderbuffer object, or if buffer is the name of a multisampled 270 * renderbuffer object, the error EGL_BAD_PARAMETER is generated." 271 * 272 * "If target is EGL_GL_TEXTURE_2D , EGL_GL_TEXTURE_CUBE_MAP_*, 273 * EGL_GL_RENDERBUFFER or EGL_GL_TEXTURE_3D and buffer refers to the 274 * default GL texture object (0) for the corresponding GL target, the 275 * error EGL_BAD_PARAMETER is generated." 276 * (rely on _mesa_lookup_renderbuffer returning NULL in this case) 277 */ 278 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 279 if (!rb || rb->NumSamples > 0) { 280 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; 281 return NULL; 282 } 283 284 tex = st_get_renderbuffer_resource(rb); 285 if (!tex) { 286 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; 287 return NULL; 288 } 289 290 img = CALLOC_STRUCT(__DRIimageRec); 291 if (!img) { 292 *error = __DRI_IMAGE_ERROR_BAD_ALLOC; 293 return NULL; 294 } 295 296 img->dri_format = driGLFormatToImageFormat(rb->Format); 297 img->loader_private = loaderPrivate; 298 299 pipe_resource_reference(&img->texture, tex); 300 301 *error = __DRI_IMAGE_ERROR_SUCCESS; 302 return img; 303} 304 305__DRIimage * 306dri2_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 314void 315dri2_destroy_image(__DRIimage *img) 316{ 317 pipe_resource_reference(&img->texture, NULL); 318 FREE(img); 319} 320 321 322__DRIimage * 323dri2_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 pipe_resource_reference(&img->texture, tex); 377 378 *error = __DRI_IMAGE_ERROR_SUCCESS; 379 return img; 380} 381 382/* vim: set sw=3 ts=8 sts=3 expandtab: */ 383