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  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23  * OTHER DEALINGS IN THE SOFTWARE.
     24  */
     25 
     26 /**
     27  * \file shaderobj.c
     28  * \author Brian Paul
     29  *
     30  */
     31 
     32 
     33 #include "main/glheader.h"
     34 #include "main/context.h"
     35 #include "main/hash.h"
     36 #include "main/mtypes.h"
     37 #include "main/shaderapi.h"
     38 #include "main/shaderobj.h"
     39 #include "main/uniforms.h"
     40 #include "program/program.h"
     41 #include "program/prog_parameter.h"
     42 #include "util/ralloc.h"
     43 #include "util/string_to_uint_map.h"
     44 #include "util/u_atomic.h"
     45 
     46 /**********************************************************************/
     47 /*** Shader object functions                                        ***/
     48 /**********************************************************************/
     49 
     50 
     51 /**
     52  * Set ptr to point to sh.
     53  * If ptr is pointing to another shader, decrement its refcount (and delete
     54  * if refcount hits zero).
     55  * Then set ptr to point to sh, incrementing its refcount.
     56  */
     57 void
     58 _mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
     59                        struct gl_shader *sh)
     60 {
     61    assert(ptr);
     62    if (*ptr == sh) {
     63       /* no-op */
     64       return;
     65    }
     66    if (*ptr) {
     67       /* Unreference the old shader */
     68       struct gl_shader *old = *ptr;
     69 
     70       assert(old->RefCount > 0);
     71 
     72       if (p_atomic_dec_zero(&old->RefCount)) {
     73 	 if (old->Name != 0)
     74 	    _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
     75          _mesa_delete_shader(ctx, old);
     76       }
     77 
     78       *ptr = NULL;
     79    }
     80    assert(!*ptr);
     81 
     82    if (sh) {
     83       /* reference new */
     84       p_atomic_inc(&sh->RefCount);
     85       *ptr = sh;
     86    }
     87 }
     88 
     89 static void
     90 _mesa_init_shader(struct gl_shader *shader)
     91 {
     92    shader->RefCount = 1;
     93    shader->info.Geom.VerticesOut = -1;
     94    shader->info.Geom.InputType = GL_TRIANGLES;
     95    shader->info.Geom.OutputType = GL_TRIANGLE_STRIP;
     96 }
     97 
     98 /**
     99  * Allocate a new gl_shader object, initialize it.
    100  */
    101 struct gl_shader *
    102 _mesa_new_shader(GLuint name, gl_shader_stage stage)
    103 {
    104    struct gl_shader *shader;
    105    shader = rzalloc(NULL, struct gl_shader);
    106    if (shader) {
    107       shader->Stage = stage;
    108       shader->Name = name;
    109 #ifdef DEBUG
    110       shader->SourceChecksum = 0xa110c; /* alloc */
    111 #endif
    112       _mesa_init_shader(shader);
    113    }
    114    return shader;
    115 }
    116 
    117 
    118 /**
    119  * Delete a shader object.
    120  */
    121 void
    122 _mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh)
    123 {
    124    free((void *)sh->Source);
    125    free(sh->Label);
    126    ralloc_free(sh);
    127 }
    128 
    129 
    130 /**
    131  * Delete a shader object.
    132  */
    133 void
    134 _mesa_delete_linked_shader(struct gl_context *ctx,
    135                            struct gl_linked_shader *sh)
    136 {
    137    _mesa_reference_program(ctx, &sh->Program, NULL);
    138    ralloc_free(sh);
    139 }
    140 
    141 
    142 /**
    143  * Lookup a GLSL shader object.
    144  */
    145 struct gl_shader *
    146 _mesa_lookup_shader(struct gl_context *ctx, GLuint name)
    147 {
    148    if (name) {
    149       struct gl_shader *sh = (struct gl_shader *)
    150          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
    151       /* Note that both gl_shader and gl_shader_program objects are kept
    152        * in the same hash table.  Check the object's type to be sure it's
    153        * what we're expecting.
    154        */
    155       if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
    156          return NULL;
    157       }
    158       return sh;
    159    }
    160    return NULL;
    161 }
    162 
    163 
    164 /**
    165  * As above, but record an error if shader is not found.
    166  */
    167 struct gl_shader *
    168 _mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
    169 {
    170    if (!name) {
    171       _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
    172       return NULL;
    173    }
    174    else {
    175       struct gl_shader *sh = (struct gl_shader *)
    176          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
    177       if (!sh) {
    178          _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
    179          return NULL;
    180       }
    181       if (sh->Type == GL_SHADER_PROGRAM_MESA) {
    182          _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
    183          return NULL;
    184       }
    185       return sh;
    186    }
    187 }
    188 
    189 
    190 
    191 /**********************************************************************/
    192 /*** Shader Program object functions                                ***/
    193 /**********************************************************************/
    194 
    195 
    196 void
    197 _mesa_reference_shader_program_data(struct gl_context *ctx,
    198                                     struct gl_shader_program_data **ptr,
    199                                     struct gl_shader_program_data *data)
    200 {
    201    if (*ptr == data)
    202       return;
    203 
    204    if (*ptr) {
    205       struct gl_shader_program_data *oldData = *ptr;
    206 
    207       assert(oldData->RefCount > 0);
    208 
    209       if (p_atomic_dec_zero(&oldData->RefCount)) {
    210          assert(ctx);
    211          ralloc_free(oldData);
    212       }
    213 
    214       *ptr = NULL;
    215    }
    216 
    217    if (data)
    218       p_atomic_inc(&data->RefCount);
    219 
    220    *ptr = data;
    221 }
    222 
    223 /**
    224  * Set ptr to point to shProg.
    225  * If ptr is pointing to another object, decrement its refcount (and delete
    226  * if refcount hits zero).
    227  * Then set ptr to point to shProg, incrementing its refcount.
    228  */
    229 void
    230 _mesa_reference_shader_program_(struct gl_context *ctx,
    231                                 struct gl_shader_program **ptr,
    232                                 struct gl_shader_program *shProg)
    233 {
    234    assert(ptr);
    235    if (*ptr == shProg) {
    236       /* no-op */
    237       return;
    238    }
    239    if (*ptr) {
    240       /* Unreference the old shader program */
    241       struct gl_shader_program *old = *ptr;
    242 
    243       assert(old->RefCount > 0);
    244 
    245       if (p_atomic_dec_zero(&old->RefCount)) {
    246 	 if (old->Name != 0)
    247 	    _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
    248          _mesa_delete_shader_program(ctx, old);
    249       }
    250 
    251       *ptr = NULL;
    252    }
    253    assert(!*ptr);
    254 
    255    if (shProg) {
    256       p_atomic_inc(&shProg->RefCount);
    257       *ptr = shProg;
    258    }
    259 }
    260 
    261 static struct gl_shader_program_data *
    262 create_shader_program_data()
    263 {
    264    struct gl_shader_program_data *data;
    265    data = rzalloc(NULL, struct gl_shader_program_data);
    266    if (data)
    267       data->RefCount = 1;
    268 
    269    return data;
    270 }
    271 
    272 static void
    273 init_shader_program(struct gl_shader_program *prog)
    274 {
    275    prog->Type = GL_SHADER_PROGRAM_MESA;
    276    prog->RefCount = 1;
    277 
    278    prog->AttributeBindings = string_to_uint_map_ctor();
    279    prog->FragDataBindings = string_to_uint_map_ctor();
    280    prog->FragDataIndexBindings = string_to_uint_map_ctor();
    281 
    282    prog->Geom.UsesEndPrimitive = false;
    283    prog->Geom.UsesStreams = false;
    284 
    285    prog->Comp.LocalSizeVariable = false;
    286 
    287    prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS;
    288 
    289    exec_list_make_empty(&prog->EmptyUniformLocations);
    290 
    291    prog->data->InfoLog = ralloc_strdup(prog->data, "");
    292 }
    293 
    294 /**
    295  * Allocate a new gl_shader_program object, initialize it.
    296  */
    297 struct gl_shader_program *
    298 _mesa_new_shader_program(GLuint name)
    299 {
    300    struct gl_shader_program *shProg;
    301    shProg = rzalloc(NULL, struct gl_shader_program);
    302    if (shProg) {
    303       shProg->Name = name;
    304       shProg->data = create_shader_program_data();
    305       if (!shProg->data) {
    306          ralloc_free(shProg);
    307          return NULL;
    308       }
    309       init_shader_program(shProg);
    310    }
    311    return shProg;
    312 }
    313 
    314 
    315 /**
    316  * Clear (free) the shader program state that gets produced by linking.
    317  */
    318 void
    319 _mesa_clear_shader_program_data(struct gl_context *ctx,
    320                                 struct gl_shader_program *shProg)
    321 {
    322    for (gl_shader_stage sh = 0; sh < MESA_SHADER_STAGES; sh++) {
    323       if (shProg->_LinkedShaders[sh] != NULL) {
    324          _mesa_delete_linked_shader(ctx, shProg->_LinkedShaders[sh]);
    325          shProg->_LinkedShaders[sh] = NULL;
    326       }
    327    }
    328 
    329    shProg->data->linked_stages = 0;
    330 
    331    if (shProg->data->UniformStorage) {
    332       for (unsigned i = 0; i < shProg->data->NumUniformStorage; ++i)
    333          _mesa_uniform_detach_all_driver_storage(&shProg->data->
    334                                                     UniformStorage[i]);
    335       ralloc_free(shProg->data->UniformStorage);
    336       shProg->data->NumUniformStorage = 0;
    337       shProg->data->UniformStorage = NULL;
    338    }
    339 
    340    if (shProg->UniformRemapTable) {
    341       ralloc_free(shProg->UniformRemapTable);
    342       shProg->NumUniformRemapTable = 0;
    343       shProg->UniformRemapTable = NULL;
    344    }
    345 
    346    if (shProg->UniformHash) {
    347       string_to_uint_map_dtor(shProg->UniformHash);
    348       shProg->UniformHash = NULL;
    349    }
    350 
    351    assert(shProg->data->InfoLog != NULL);
    352    ralloc_free(shProg->data->InfoLog);
    353    shProg->data->InfoLog = ralloc_strdup(shProg->data, "");
    354 
    355    ralloc_free(shProg->data->UniformBlocks);
    356    shProg->data->UniformBlocks = NULL;
    357    shProg->data->NumUniformBlocks = 0;
    358 
    359    ralloc_free(shProg->data->ShaderStorageBlocks);
    360    shProg->data->ShaderStorageBlocks = NULL;
    361    shProg->data->NumShaderStorageBlocks = 0;
    362 
    363    ralloc_free(shProg->data->AtomicBuffers);
    364    shProg->data->AtomicBuffers = NULL;
    365    shProg->data->NumAtomicBuffers = 0;
    366 
    367    if (shProg->ProgramResourceList) {
    368       ralloc_free(shProg->ProgramResourceList);
    369       shProg->ProgramResourceList = NULL;
    370       shProg->NumProgramResourceList = 0;
    371    }
    372 }
    373 
    374 
    375 /**
    376  * Free all the data that hangs off a shader program object, but not the
    377  * object itself.
    378  */
    379 void
    380 _mesa_free_shader_program_data(struct gl_context *ctx,
    381                                struct gl_shader_program *shProg)
    382 {
    383    GLuint i;
    384 
    385    assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
    386 
    387    _mesa_clear_shader_program_data(ctx, shProg);
    388 
    389    if (shProg->AttributeBindings) {
    390       string_to_uint_map_dtor(shProg->AttributeBindings);
    391       shProg->AttributeBindings = NULL;
    392    }
    393 
    394    if (shProg->FragDataBindings) {
    395       string_to_uint_map_dtor(shProg->FragDataBindings);
    396       shProg->FragDataBindings = NULL;
    397    }
    398 
    399    if (shProg->FragDataIndexBindings) {
    400       string_to_uint_map_dtor(shProg->FragDataIndexBindings);
    401       shProg->FragDataIndexBindings = NULL;
    402    }
    403 
    404    /* detach shaders */
    405    for (i = 0; i < shProg->NumShaders; i++) {
    406       _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
    407    }
    408    shProg->NumShaders = 0;
    409 
    410    free(shProg->Shaders);
    411    shProg->Shaders = NULL;
    412 
    413    /* Transform feedback varying vars */
    414    for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
    415       free(shProg->TransformFeedback.VaryingNames[i]);
    416    }
    417    free(shProg->TransformFeedback.VaryingNames);
    418    shProg->TransformFeedback.VaryingNames = NULL;
    419    shProg->TransformFeedback.NumVarying = 0;
    420 
    421    free(shProg->Label);
    422    shProg->Label = NULL;
    423 }
    424 
    425 
    426 /**
    427  * Free/delete a shader program object.
    428  */
    429 void
    430 _mesa_delete_shader_program(struct gl_context *ctx,
    431                             struct gl_shader_program *shProg)
    432 {
    433    _mesa_free_shader_program_data(ctx, shProg);
    434    _mesa_reference_shader_program_data(ctx, &shProg->data, NULL);
    435    ralloc_free(shProg);
    436 }
    437 
    438 
    439 /**
    440  * Lookup a GLSL program object.
    441  */
    442 struct gl_shader_program *
    443 _mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
    444 {
    445    struct gl_shader_program *shProg;
    446    if (name) {
    447       shProg = (struct gl_shader_program *)
    448          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
    449       /* Note that both gl_shader and gl_shader_program objects are kept
    450        * in the same hash table.  Check the object's type to be sure it's
    451        * what we're expecting.
    452        */
    453       if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
    454          return NULL;
    455       }
    456       return shProg;
    457    }
    458    return NULL;
    459 }
    460 
    461 
    462 /**
    463  * As above, but record an error if program is not found.
    464  */
    465 struct gl_shader_program *
    466 _mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
    467                                 const char *caller)
    468 {
    469    if (!name) {
    470       _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
    471       return NULL;
    472    }
    473    else {
    474       struct gl_shader_program *shProg = (struct gl_shader_program *)
    475          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
    476       if (!shProg) {
    477          _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
    478          return NULL;
    479       }
    480       if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
    481          _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
    482          return NULL;
    483       }
    484       return shProg;
    485    }
    486 }
    487 
    488 
    489 void
    490 _mesa_init_shader_object_functions(struct dd_function_table *driver)
    491 {
    492    driver->LinkShader = _mesa_ir_link_shader;
    493 }
    494