Home | History | Annotate | Download | only in main
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 2004-2008  Brian Paul   All Rights Reserved.
      5  * Copyright (C) 2009-2010  VMware, Inc.  All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 /**
     26  * \file shaderobj.c
     27  * \author Brian Paul
     28  *
     29  */
     30 
     31 
     32 #include "main/glheader.h"
     33 #include "main/context.h"
     34 #include "main/hash.h"
     35 #include "main/mfeatures.h"
     36 #include "main/mtypes.h"
     37 #include "main/shaderobj.h"
     38 #include "main/uniforms.h"
     39 #include "program/program.h"
     40 #include "program/prog_parameter.h"
     41 #include "program/hash_table.h"
     42 #include "ralloc.h"
     43 
     44 /**********************************************************************/
     45 /*** Shader object functions                                        ***/
     46 /**********************************************************************/
     47 
     48 
     49 /**
     50  * Set ptr to point to sh.
     51  * If ptr is pointing to another shader, decrement its refcount (and delete
     52  * if refcount hits zero).
     53  * Then set ptr to point to sh, incrementing its refcount.
     54  */
     55 void
     56 _mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
     57                        struct gl_shader *sh)
     58 {
     59    assert(ptr);
     60    if (*ptr == sh) {
     61       /* no-op */
     62       return;
     63    }
     64    if (*ptr) {
     65       /* Unreference the old shader */
     66       GLboolean deleteFlag = GL_FALSE;
     67       struct gl_shader *old = *ptr;
     68 
     69       ASSERT(old->RefCount > 0);
     70       old->RefCount--;
     71       /*printf("SHADER DECR %p (%d) to %d\n",
     72         (void*) old, old->Name, old->RefCount);*/
     73       deleteFlag = (old->RefCount == 0);
     74 
     75       if (deleteFlag) {
     76 	 if (old->Name != 0)
     77 	    _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
     78          ctx->Driver.DeleteShader(ctx, old);
     79       }
     80 
     81       *ptr = NULL;
     82    }
     83    assert(!*ptr);
     84 
     85    if (sh) {
     86       /* reference new */
     87       sh->RefCount++;
     88       /*printf("SHADER INCR %p (%d) to %d\n",
     89         (void*) sh, sh->Name, sh->RefCount);*/
     90       *ptr = sh;
     91    }
     92 }
     93 
     94 void
     95 _mesa_init_shader(struct gl_context *ctx, struct gl_shader *shader)
     96 {
     97    shader->RefCount = 1;
     98 }
     99 
    100 /**
    101  * Allocate a new gl_shader object, initialize it.
    102  * Called via ctx->Driver.NewShader()
    103  */
    104 struct gl_shader *
    105 _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
    106 {
    107    struct gl_shader *shader;
    108    assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER ||
    109           type == GL_GEOMETRY_SHADER_ARB);
    110    shader = rzalloc(NULL, struct gl_shader);
    111    if (shader) {
    112       shader->Type = type;
    113       shader->Name = name;
    114       _mesa_init_shader(ctx, shader);
    115    }
    116    return shader;
    117 }
    118 
    119 
    120 /**
    121  * Delete a shader object.
    122  * Called via ctx->Driver.DeleteShader().
    123  */
    124 static void
    125 _mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh)
    126 {
    127    if (sh->Source)
    128       free((void *) sh->Source);
    129    _mesa_reference_program(ctx, &sh->Program, NULL);
    130    ralloc_free(sh);
    131 }
    132 
    133 
    134 /**
    135  * Lookup a GLSL shader object.
    136  */
    137 struct gl_shader *
    138 _mesa_lookup_shader(struct gl_context *ctx, GLuint name)
    139 {
    140    if (name) {
    141       struct gl_shader *sh = (struct gl_shader *)
    142          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
    143       /* Note that both gl_shader and gl_shader_program objects are kept
    144        * in the same hash table.  Check the object's type to be sure it's
    145        * what we're expecting.
    146        */
    147       if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
    148          return NULL;
    149       }
    150       return sh;
    151    }
    152    return NULL;
    153 }
    154 
    155 
    156 /**
    157  * As above, but record an error if shader is not found.
    158  */
    159 struct gl_shader *
    160 _mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
    161 {
    162    if (!name) {
    163       _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
    164       return NULL;
    165    }
    166    else {
    167       struct gl_shader *sh = (struct gl_shader *)
    168          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
    169       if (!sh) {
    170          _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
    171          return NULL;
    172       }
    173       if (sh->Type == GL_SHADER_PROGRAM_MESA) {
    174          _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
    175          return NULL;
    176       }
    177       return sh;
    178    }
    179 }
    180 
    181 
    182 
    183 /**********************************************************************/
    184 /*** Shader Program object functions                                ***/
    185 /**********************************************************************/
    186 
    187 
    188 /**
    189  * Set ptr to point to shProg.
    190  * If ptr is pointing to another object, decrement its refcount (and delete
    191  * if refcount hits zero).
    192  * Then set ptr to point to shProg, incrementing its refcount.
    193  */
    194 void
    195 _mesa_reference_shader_program(struct gl_context *ctx,
    196                                struct gl_shader_program **ptr,
    197                                struct gl_shader_program *shProg)
    198 {
    199    assert(ptr);
    200    if (*ptr == shProg) {
    201       /* no-op */
    202       return;
    203    }
    204    if (*ptr) {
    205       /* Unreference the old shader program */
    206       GLboolean deleteFlag = GL_FALSE;
    207       struct gl_shader_program *old = *ptr;
    208 
    209       ASSERT(old->RefCount > 0);
    210       old->RefCount--;
    211 #if 0
    212       printf("ShaderProgram %p ID=%u  RefCount-- to %d\n",
    213              (void *) old, old->Name, old->RefCount);
    214 #endif
    215       deleteFlag = (old->RefCount == 0);
    216 
    217       if (deleteFlag) {
    218 	 if (old->Name != 0)
    219 	    _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
    220          ctx->Driver.DeleteShaderProgram(ctx, old);
    221       }
    222 
    223       *ptr = NULL;
    224    }
    225    assert(!*ptr);
    226 
    227    if (shProg) {
    228       shProg->RefCount++;
    229 #if 0
    230       printf("ShaderProgram %p ID=%u  RefCount++ to %d\n",
    231              (void *) shProg, shProg->Name, shProg->RefCount);
    232 #endif
    233       *ptr = shProg;
    234    }
    235 }
    236 
    237 void
    238 _mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog)
    239 {
    240    prog->Type = GL_SHADER_PROGRAM_MESA;
    241    prog->RefCount = 1;
    242 
    243    prog->AttributeBindings = string_to_uint_map_ctor();
    244    prog->FragDataBindings = string_to_uint_map_ctor();
    245    prog->FragDataIndexBindings = string_to_uint_map_ctor();
    246 
    247 #if FEATURE_ARB_geometry_shader4
    248    prog->Geom.VerticesOut = 0;
    249    prog->Geom.InputType = GL_TRIANGLES;
    250    prog->Geom.OutputType = GL_TRIANGLE_STRIP;
    251 #endif
    252 
    253    prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS;
    254 
    255    prog->InfoLog = ralloc_strdup(prog, "");
    256 }
    257 
    258 /**
    259  * Allocate a new gl_shader_program object, initialize it.
    260  * Called via ctx->Driver.NewShaderProgram()
    261  */
    262 static struct gl_shader_program *
    263 _mesa_new_shader_program(struct gl_context *ctx, GLuint name)
    264 {
    265    struct gl_shader_program *shProg;
    266    shProg = rzalloc(NULL, struct gl_shader_program);
    267    if (shProg) {
    268       shProg->Name = name;
    269       _mesa_init_shader_program(ctx, shProg);
    270    }
    271    return shProg;
    272 }
    273 
    274 
    275 /**
    276  * Clear (free) the shader program state that gets produced by linking.
    277  */
    278 void
    279 _mesa_clear_shader_program_data(struct gl_context *ctx,
    280                                 struct gl_shader_program *shProg)
    281 {
    282    if (shProg->UniformStorage) {
    283       unsigned i;
    284       for (i = 0; i < shProg->NumUserUniformStorage; ++i)
    285          _mesa_uniform_detach_all_driver_storage(&shProg->UniformStorage[i]);
    286       ralloc_free(shProg->UniformStorage);
    287       shProg->NumUserUniformStorage = 0;
    288       shProg->UniformStorage = NULL;
    289    }
    290 
    291    if (shProg->UniformHash) {
    292       string_to_uint_map_dtor(shProg->UniformHash);
    293       shProg->UniformHash = NULL;
    294    }
    295 
    296    assert(shProg->InfoLog != NULL);
    297    ralloc_free(shProg->InfoLog);
    298    shProg->InfoLog = ralloc_strdup(shProg, "");
    299 }
    300 
    301 
    302 /**
    303  * Free all the data that hangs off a shader program object, but not the
    304  * object itself.
    305  */
    306 void
    307 _mesa_free_shader_program_data(struct gl_context *ctx,
    308                                struct gl_shader_program *shProg)
    309 {
    310    GLuint i;
    311    gl_shader_type sh;
    312 
    313    assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
    314 
    315    _mesa_clear_shader_program_data(ctx, shProg);
    316 
    317    if (shProg->AttributeBindings) {
    318       string_to_uint_map_dtor(shProg->AttributeBindings);
    319       shProg->AttributeBindings = NULL;
    320    }
    321 
    322    if (shProg->FragDataBindings) {
    323       string_to_uint_map_dtor(shProg->FragDataBindings);
    324       shProg->FragDataBindings = NULL;
    325    }
    326 
    327    if (shProg->FragDataIndexBindings) {
    328       string_to_uint_map_dtor(shProg->FragDataIndexBindings);
    329       shProg->FragDataIndexBindings = NULL;
    330    }
    331 
    332    /* detach shaders */
    333    for (i = 0; i < shProg->NumShaders; i++) {
    334       _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
    335    }
    336    shProg->NumShaders = 0;
    337 
    338    if (shProg->Shaders) {
    339       free(shProg->Shaders);
    340       shProg->Shaders = NULL;
    341    }
    342 
    343    /* Transform feedback varying vars */
    344    for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
    345       free(shProg->TransformFeedback.VaryingNames[i]);
    346    }
    347    free(shProg->TransformFeedback.VaryingNames);
    348    shProg->TransformFeedback.VaryingNames = NULL;
    349    shProg->TransformFeedback.NumVarying = 0;
    350 
    351 
    352    for (sh = 0; sh < MESA_SHADER_TYPES; sh++) {
    353       if (shProg->_LinkedShaders[sh] != NULL) {
    354 	 ctx->Driver.DeleteShader(ctx, shProg->_LinkedShaders[sh]);
    355 	 shProg->_LinkedShaders[sh] = NULL;
    356       }
    357    }
    358 }
    359 
    360 
    361 /**
    362  * Free/delete a shader program object.
    363  * Called via ctx->Driver.DeleteShaderProgram().
    364  */
    365 static void
    366 _mesa_delete_shader_program(struct gl_context *ctx, struct gl_shader_program *shProg)
    367 {
    368    _mesa_free_shader_program_data(ctx, shProg);
    369 
    370    ralloc_free(shProg);
    371 }
    372 
    373 
    374 /**
    375  * Lookup a GLSL program object.
    376  */
    377 struct gl_shader_program *
    378 _mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
    379 {
    380    struct gl_shader_program *shProg;
    381    if (name) {
    382       shProg = (struct gl_shader_program *)
    383          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
    384       /* Note that both gl_shader and gl_shader_program objects are kept
    385        * in the same hash table.  Check the object's type to be sure it's
    386        * what we're expecting.
    387        */
    388       if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
    389          return NULL;
    390       }
    391       return shProg;
    392    }
    393    return NULL;
    394 }
    395 
    396 
    397 /**
    398  * As above, but record an error if program is not found.
    399  */
    400 struct gl_shader_program *
    401 _mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
    402                                 const char *caller)
    403 {
    404    if (!name) {
    405       _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
    406       return NULL;
    407    }
    408    else {
    409       struct gl_shader_program *shProg = (struct gl_shader_program *)
    410          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
    411       if (!shProg) {
    412          _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
    413          return NULL;
    414       }
    415       if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
    416          _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
    417          return NULL;
    418       }
    419       return shProg;
    420    }
    421 }
    422 
    423 
    424 void
    425 _mesa_init_shader_object_functions(struct dd_function_table *driver)
    426 {
    427    driver->NewShader = _mesa_new_shader;
    428    driver->DeleteShader = _mesa_delete_shader;
    429    driver->NewShaderProgram = _mesa_new_shader_program;
    430    driver->DeleteShaderProgram = _mesa_delete_shader_program;
    431    driver->LinkShader = _mesa_ir_link_shader;
    432 }
    433