Home | History | Annotate | Download | only in dri
      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