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