Home | History | Annotate | Download | only in main
      1 /**************************************************************************
      2  *
      3  * Copyright 2013 Advanced Micro Devices, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 /*
     29  * Authors:
     30  *      Christian Knig <christian.koenig (at) amd.com>
     31  *
     32  */
     33 
     34 #include <stdbool.h>
     35 #include "util/hash_table.h"
     36 #include "util/set.h"
     37 #include "context.h"
     38 #include "glformats.h"
     39 #include "texobj.h"
     40 #include "teximage.h"
     41 #include "vdpau.h"
     42 
     43 #define MAX_TEXTURES 4
     44 
     45 struct vdp_surface
     46 {
     47    GLenum target;
     48    struct gl_texture_object *textures[MAX_TEXTURES];
     49    GLenum access, state;
     50    GLboolean output;
     51    const GLvoid *vdpSurface;
     52 };
     53 
     54 void GLAPIENTRY
     55 _mesa_VDPAUInitNV(const GLvoid *vdpDevice, const GLvoid *getProcAddress)
     56 {
     57    GET_CURRENT_CONTEXT(ctx);
     58 
     59    if (!vdpDevice) {
     60       _mesa_error(ctx, GL_INVALID_VALUE, "vdpDevice");
     61       return;
     62    }
     63 
     64    if (!getProcAddress) {
     65       _mesa_error(ctx, GL_INVALID_VALUE, "getProcAddress");
     66       return;
     67    }
     68 
     69    if (ctx->vdpDevice || ctx->vdpGetProcAddress || ctx->vdpSurfaces) {
     70       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUInitNV");
     71       return;
     72    }
     73 
     74    ctx->vdpDevice = vdpDevice;
     75    ctx->vdpGetProcAddress = getProcAddress;
     76    ctx->vdpSurfaces = _mesa_set_create(NULL, _mesa_hash_pointer,
     77                                        _mesa_key_pointer_equal);
     78 }
     79 
     80 static void
     81 unregister_surface(struct set_entry *entry)
     82 {
     83    struct vdp_surface *surf = (struct vdp_surface *)entry->key;
     84    GET_CURRENT_CONTEXT(ctx);
     85 
     86    if (surf->state == GL_SURFACE_MAPPED_NV) {
     87       GLintptr surfaces[] = { (GLintptr)surf };
     88       _mesa_VDPAUUnmapSurfacesNV(1, surfaces);
     89    }
     90 
     91    _mesa_set_remove(ctx->vdpSurfaces, entry);
     92    free(surf);
     93 }
     94 
     95 void GLAPIENTRY
     96 _mesa_VDPAUFiniNV(void)
     97 {
     98    GET_CURRENT_CONTEXT(ctx);
     99 
    100    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
    101       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUFiniNV");
    102       return;
    103    }
    104 
    105    _mesa_set_destroy(ctx->vdpSurfaces, unregister_surface);
    106 
    107    ctx->vdpDevice = 0;
    108    ctx->vdpGetProcAddress = 0;
    109    ctx->vdpSurfaces = NULL;
    110 }
    111 
    112 static GLintptr
    113 register_surface(struct gl_context *ctx, GLboolean isOutput,
    114                  const GLvoid *vdpSurface, GLenum target,
    115                  GLsizei numTextureNames, const GLuint *textureNames)
    116 {
    117    struct vdp_surface *surf;
    118    int i;
    119 
    120    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
    121       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAURegisterSurfaceNV");
    122       return (GLintptr)NULL;
    123    }
    124 
    125    if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE) {
    126       _mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV");
    127       return (GLintptr)NULL;
    128    }
    129 
    130    if (target == GL_TEXTURE_RECTANGLE && !ctx->Extensions.NV_texture_rectangle) {
    131       _mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV");
    132       return (GLintptr)NULL;
    133    }
    134 
    135    surf = CALLOC_STRUCT( vdp_surface );
    136    if (surf == NULL) {
    137       _mesa_error_no_memory("VDPAURegisterSurfaceNV");
    138       return (GLintptr)NULL;
    139    }
    140 
    141    surf->vdpSurface = vdpSurface;
    142    surf->target = target;
    143    surf->access = GL_READ_WRITE;
    144    surf->state = GL_SURFACE_REGISTERED_NV;
    145    surf->output = isOutput;
    146    for (i = 0; i < numTextureNames; ++i) {
    147       struct gl_texture_object *tex;
    148       tex  = _mesa_lookup_texture(ctx, textureNames[i]);
    149       if (tex == NULL) {
    150          free(surf);
    151          _mesa_error(ctx, GL_INVALID_OPERATION,
    152                      "VDPAURegisterSurfaceNV(texture ID not found)");
    153          return (GLintptr)NULL;
    154       }
    155 
    156       _mesa_lock_texture(ctx, tex);
    157 
    158       if (tex->Immutable) {
    159          _mesa_unlock_texture(ctx, tex);
    160          free(surf);
    161          _mesa_error(ctx, GL_INVALID_OPERATION,
    162                      "VDPAURegisterSurfaceNV(texture is immutable)");
    163          return (GLintptr)NULL;
    164       }
    165 
    166       if (tex->Target == 0) {
    167          tex->Target = target;
    168          tex->TargetIndex = _mesa_tex_target_to_index(ctx, target);
    169       } else if (tex->Target != target) {
    170          _mesa_unlock_texture(ctx, tex);
    171          free(surf);
    172          _mesa_error(ctx, GL_INVALID_OPERATION,
    173                      "VDPAURegisterSurfaceNV(target mismatch)");
    174          return (GLintptr)NULL;
    175       }
    176 
    177       /* This will disallow respecifying the storage. */
    178       tex->Immutable = GL_TRUE;
    179       _mesa_unlock_texture(ctx, tex);
    180 
    181       _mesa_reference_texobj(&surf->textures[i], tex);
    182    }
    183 
    184    _mesa_set_add(ctx->vdpSurfaces, surf);
    185 
    186    return (GLintptr)surf;
    187 }
    188 
    189 GLintptr GLAPIENTRY
    190 _mesa_VDPAURegisterVideoSurfaceNV(const GLvoid *vdpSurface, GLenum target,
    191                                   GLsizei numTextureNames,
    192                                   const GLuint *textureNames)
    193 {
    194    GET_CURRENT_CONTEXT(ctx);
    195 
    196    if (numTextureNames != 4) {
    197       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAURegisterVideoSurfaceNV");
    198       return (GLintptr)NULL;
    199    }
    200 
    201    return register_surface(ctx, false, vdpSurface, target,
    202                            numTextureNames, textureNames);
    203 }
    204 
    205 GLintptr GLAPIENTRY
    206 _mesa_VDPAURegisterOutputSurfaceNV(const GLvoid *vdpSurface, GLenum target,
    207                                    GLsizei numTextureNames,
    208                                    const GLuint *textureNames)
    209 {
    210    GET_CURRENT_CONTEXT(ctx);
    211 
    212    if (numTextureNames != 1) {
    213       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAURegisterVideoSurfaceNV");
    214       return (GLintptr)NULL;
    215    }
    216 
    217    return register_surface(ctx, true, vdpSurface, target,
    218                            numTextureNames, textureNames);
    219 }
    220 
    221 GLboolean GLAPIENTRY
    222 _mesa_VDPAUIsSurfaceNV(GLintptr surface)
    223 {
    224    struct vdp_surface *surf = (struct vdp_surface *)surface;
    225    GET_CURRENT_CONTEXT(ctx);
    226 
    227    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
    228       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUIsSurfaceNV");
    229       return false;
    230    }
    231 
    232    if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
    233       return false;
    234    }
    235 
    236    return true;
    237 }
    238 
    239 void GLAPIENTRY
    240 _mesa_VDPAUUnregisterSurfaceNV(GLintptr surface)
    241 {
    242    struct vdp_surface *surf = (struct vdp_surface *)surface;
    243    struct set_entry *entry;
    244    int i;
    245    GET_CURRENT_CONTEXT(ctx);
    246 
    247    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
    248       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUUnregisterSurfaceNV");
    249       return;
    250    }
    251 
    252    /* according to the spec it's ok when this is zero */
    253    if (surface == 0)
    254       return;
    255 
    256    entry = _mesa_set_search(ctx->vdpSurfaces, surf);
    257    if (!entry) {
    258       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUUnregisterSurfaceNV");
    259       return;
    260    }
    261 
    262    for (i = 0; i < MAX_TEXTURES; i++) {
    263       if (surf->textures[i]) {
    264          surf->textures[i]->Immutable = GL_FALSE;
    265          _mesa_reference_texobj(&surf->textures[i], NULL);
    266       }
    267    }
    268 
    269    _mesa_set_remove(ctx->vdpSurfaces, entry);
    270    free(surf);
    271 }
    272 
    273 void GLAPIENTRY
    274 _mesa_VDPAUGetSurfaceivNV(GLintptr surface, GLenum pname, GLsizei bufSize,
    275                           GLsizei *length, GLint *values)
    276 {
    277    struct vdp_surface *surf = (struct vdp_surface *)surface;
    278    GET_CURRENT_CONTEXT(ctx);
    279 
    280    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
    281       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUGetSurfaceivNV");
    282       return;
    283    }
    284 
    285    if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
    286       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUGetSurfaceivNV");
    287       return;
    288    }
    289 
    290    if (pname != GL_SURFACE_STATE_NV) {
    291       _mesa_error(ctx, GL_INVALID_ENUM, "VDPAUGetSurfaceivNV");
    292       return;
    293    }
    294 
    295    if (bufSize < 1) {
    296       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUGetSurfaceivNV");
    297       return;
    298    }
    299 
    300    values[0] = surf->state;
    301 
    302    if (length != NULL)
    303       *length = 1;
    304 }
    305 
    306 void GLAPIENTRY
    307 _mesa_VDPAUSurfaceAccessNV(GLintptr surface, GLenum access)
    308 {
    309    struct vdp_surface *surf = (struct vdp_surface *)surface;
    310    GET_CURRENT_CONTEXT(ctx);
    311 
    312    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
    313       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
    314       return;
    315    }
    316 
    317    if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
    318       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
    319       return;
    320    }
    321 
    322    if (access != GL_READ_ONLY && access != GL_WRITE_ONLY &&
    323        access != GL_READ_WRITE) {
    324 
    325       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
    326       return;
    327    }
    328 
    329    if (surf->state == GL_SURFACE_MAPPED_NV) {
    330       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
    331       return;
    332    }
    333 
    334    surf->access = access;
    335 }
    336 
    337 void GLAPIENTRY
    338 _mesa_VDPAUMapSurfacesNV(GLsizei numSurfaces, const GLintptr *surfaces)
    339 {
    340    GET_CURRENT_CONTEXT(ctx);
    341    int i;
    342 
    343    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
    344       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUUnmapSurfacesNV");
    345       return;
    346    }
    347 
    348    for (i = 0; i < numSurfaces; ++i) {
    349       struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];
    350 
    351       if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
    352          _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
    353          return;
    354       }
    355 
    356       if (surf->state == GL_SURFACE_MAPPED_NV) {
    357          _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
    358          return;
    359       }
    360    }
    361 
    362    for (i = 0; i < numSurfaces; ++i) {
    363       struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];
    364       unsigned numTextureNames = surf->output ? 1 : 4;
    365       unsigned j;
    366 
    367       for (j = 0; j < numTextureNames; ++j) {
    368          struct gl_texture_object *tex = surf->textures[j];
    369          struct gl_texture_image *image;
    370 
    371          _mesa_lock_texture(ctx, tex);
    372          image = _mesa_get_tex_image(ctx, tex, surf->target, 0);
    373          if (!image) {
    374             _mesa_error(ctx, GL_OUT_OF_MEMORY, "VDPAUMapSurfacesNV");
    375             _mesa_unlock_texture(ctx, tex);
    376             return;
    377          }
    378 
    379          ctx->Driver.FreeTextureImageBuffer(ctx, image);
    380 
    381          ctx->Driver.VDPAUMapSurface(ctx, surf->target, surf->access,
    382                                      surf->output, tex, image,
    383                                      surf->vdpSurface, j);
    384 
    385          _mesa_unlock_texture(ctx, tex);
    386       }
    387       surf->state = GL_SURFACE_MAPPED_NV;
    388    }
    389 }
    390 
    391 void GLAPIENTRY
    392 _mesa_VDPAUUnmapSurfacesNV(GLsizei numSurfaces, const GLintptr *surfaces)
    393 {
    394    GET_CURRENT_CONTEXT(ctx);
    395    int i;
    396 
    397    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
    398       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUUnmapSurfacesNV");
    399       return;
    400    }
    401 
    402    for (i = 0; i < numSurfaces; ++i) {
    403       struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];
    404 
    405       if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
    406          _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
    407          return;
    408       }
    409 
    410       if (surf->state != GL_SURFACE_MAPPED_NV) {
    411          _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
    412          return;
    413       }
    414    }
    415 
    416    for (i = 0; i < numSurfaces; ++i) {
    417       struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];
    418       unsigned numTextureNames = surf->output ? 1 : 4;
    419       unsigned j;
    420 
    421       for (j = 0; j < numTextureNames; ++j) {
    422          struct gl_texture_object *tex = surf->textures[j];
    423          struct gl_texture_image *image;
    424 
    425          _mesa_lock_texture(ctx, tex);
    426 
    427          image = _mesa_select_tex_image(tex, surf->target, 0);
    428 
    429          ctx->Driver.VDPAUUnmapSurface(ctx, surf->target, surf->access,
    430                                        surf->output, tex, image,
    431                                        surf->vdpSurface, j);
    432 
    433          if (image)
    434             ctx->Driver.FreeTextureImageBuffer(ctx, image);
    435 
    436          _mesa_unlock_texture(ctx, tex);
    437       }
    438       surf->state = GL_SURFACE_REGISTERED_NV;
    439    }
    440 }
    441