Home | History | Annotate | Download | only in main
      1 /*
      2  * Copyright  2011 Intel Corporation
      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 (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 /**
     25  * \file shader_query.cpp
     26  * C-to-C++ bridge functions to query GLSL shader data
     27  *
     28  * \author Ian Romanick <ian.d.romanick (at) intel.com>
     29  */
     30 
     31 #include "main/core.h"
     32 #include "glsl_symbol_table.h"
     33 #include "ir.h"
     34 #include "shaderobj.h"
     35 #include "program/hash_table.h"
     36 #include "../glsl/program.h"
     37 
     38 extern "C" {
     39 #include "shaderapi.h"
     40 }
     41 
     42 void GLAPIENTRY
     43 _mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
     44                             const GLcharARB *name)
     45 {
     46    GET_CURRENT_CONTEXT(ctx);
     47 
     48    struct gl_shader_program *const shProg =
     49       _mesa_lookup_shader_program_err(ctx, program, "glBindAttribLocation");
     50    if (!shProg)
     51       return;
     52 
     53    if (!name)
     54       return;
     55 
     56    if (strncmp(name, "gl_", 3) == 0) {
     57       _mesa_error(ctx, GL_INVALID_OPERATION,
     58                   "glBindAttribLocation(illegal name)");
     59       return;
     60    }
     61 
     62    if (index >= ctx->Const.VertexProgram.MaxAttribs) {
     63       _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
     64       return;
     65    }
     66 
     67    /* Replace the current value if it's already in the list.  Add
     68     * VERT_ATTRIB_GENERIC0 because that's how the linker differentiates
     69     * between built-in attributes and user-defined attributes.
     70     */
     71    shProg->AttributeBindings->put(index + VERT_ATTRIB_GENERIC0, name);
     72 
     73    /*
     74     * Note that this attribute binding won't go into effect until
     75     * glLinkProgram is called again.
     76     */
     77 }
     78 
     79 void GLAPIENTRY
     80 _mesa_GetActiveAttribARB(GLhandleARB program, GLuint desired_index,
     81                          GLsizei maxLength, GLsizei * length, GLint * size,
     82                          GLenum * type, GLcharARB * name)
     83 {
     84    GET_CURRENT_CONTEXT(ctx);
     85    struct gl_shader_program *shProg;
     86 
     87    shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
     88    if (!shProg)
     89       return;
     90 
     91    if (!shProg->LinkStatus) {
     92       _mesa_error(ctx, GL_INVALID_VALUE,
     93                   "glGetActiveAttrib(program not linked)");
     94       return;
     95    }
     96 
     97    if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
     98       _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(no vertex shader)");
     99       return;
    100    }
    101 
    102    exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
    103    unsigned current_index = 0;
    104 
    105    foreach_list(node, ir) {
    106       const ir_variable *const var = ((ir_instruction *) node)->as_variable();
    107 
    108       if (var == NULL
    109 	  || var->mode != ir_var_in
    110 	  || var->location == -1)
    111 	 continue;
    112 
    113       if (current_index == desired_index) {
    114 	 _mesa_copy_string(name, maxLength, length, var->name);
    115 
    116 	 if (size)
    117 	    *size = (var->type->is_array()) ? var->type->length : 1;
    118 
    119 	 if (type)
    120 	    *type = var->type->gl_type;
    121 
    122 	 return;
    123       }
    124 
    125       current_index++;
    126    }
    127 
    128    /* If the loop did not return early, the caller must have asked for
    129     * an index that did not exit.  Set an error.
    130     */
    131    _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
    132 }
    133 
    134 GLint GLAPIENTRY
    135 _mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
    136 {
    137    GET_CURRENT_CONTEXT(ctx);
    138    struct gl_shader_program *const shProg =
    139       _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
    140 
    141    if (!shProg) {
    142       return -1;
    143    }
    144 
    145    if (!shProg->LinkStatus) {
    146       _mesa_error(ctx, GL_INVALID_OPERATION,
    147                   "glGetAttribLocation(program not linked)");
    148       return -1;
    149    }
    150 
    151    if (!name)
    152       return -1;
    153 
    154    /* Not having a vertex shader is not an error.
    155     */
    156    if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)
    157       return -1;
    158 
    159    exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
    160    foreach_list(node, ir) {
    161       const ir_variable *const var = ((ir_instruction *) node)->as_variable();
    162 
    163       /* The extra check against VERT_ATTRIB_GENERIC0 is because
    164        * glGetAttribLocation cannot be used on "conventional" attributes.
    165        *
    166        * From page 95 of the OpenGL 3.0 spec:
    167        *
    168        *     "If name is not an active attribute, if name is a conventional
    169        *     attribute, or if an error occurs, -1 will be returned."
    170        */
    171       if (var == NULL
    172 	  || var->mode != ir_var_in
    173 	  || var->location == -1
    174 	  || var->location < VERT_ATTRIB_GENERIC0)
    175 	 continue;
    176 
    177       if (strcmp(var->name, name) == 0)
    178 	 return var->location - VERT_ATTRIB_GENERIC0;
    179    }
    180 
    181    return -1;
    182 }
    183 
    184 
    185 unsigned
    186 _mesa_count_active_attribs(struct gl_shader_program *shProg)
    187 {
    188    if (!shProg->LinkStatus
    189        || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
    190       return 0;
    191    }
    192 
    193    exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
    194    unsigned i = 0;
    195 
    196    foreach_list(node, ir) {
    197       const ir_variable *const var = ((ir_instruction *) node)->as_variable();
    198 
    199       if (var == NULL
    200 	  || var->mode != ir_var_in
    201 	  || var->location == -1)
    202 	 continue;
    203 
    204       i++;
    205    }
    206 
    207    return i;
    208 }
    209 
    210 
    211 size_t
    212 _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
    213 {
    214    if (!shProg->LinkStatus
    215        || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
    216       return 0;
    217    }
    218 
    219    exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
    220    size_t longest = 0;
    221 
    222    foreach_list(node, ir) {
    223       const ir_variable *const var = ((ir_instruction *) node)->as_variable();
    224 
    225       if (var == NULL
    226 	  || var->mode != ir_var_in
    227 	  || var->location == -1)
    228 	 continue;
    229 
    230       const size_t len = strlen(var->name);
    231       if (len >= longest)
    232 	 longest = len + 1;
    233    }
    234 
    235    return longest;
    236 }
    237 
    238 void GLAPIENTRY
    239 _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
    240 			   const GLchar *name)
    241 {
    242    _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
    243 }
    244 
    245 void GLAPIENTRY
    246 _mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
    247                                   GLuint index, const GLchar *name)
    248 {
    249    GET_CURRENT_CONTEXT(ctx);
    250 
    251    struct gl_shader_program *const shProg =
    252       _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
    253    if (!shProg)
    254       return;
    255 
    256    if (!name)
    257       return;
    258 
    259    if (strncmp(name, "gl_", 3) == 0) {
    260       _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
    261       return;
    262    }
    263 
    264    if (index > 1) {
    265       _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
    266       return;
    267    }
    268 
    269    if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) {
    270       _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
    271       return;
    272    }
    273 
    274    if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) {
    275       _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
    276       return;
    277    }
    278 
    279    /* Replace the current value if it's already in the list.  Add
    280     * FRAG_RESULT_DATA0 because that's how the linker differentiates
    281     * between built-in attributes and user-defined attributes.
    282     */
    283    shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
    284    shProg->FragDataIndexBindings->put(index, name);
    285    /*
    286     * Note that this binding won't go into effect until
    287     * glLinkProgram is called again.
    288     */
    289 
    290 }
    291 
    292 GLint GLAPIENTRY
    293 _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
    294 {
    295    GET_CURRENT_CONTEXT(ctx);
    296    struct gl_shader_program *const shProg =
    297       _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
    298 
    299    if (!shProg) {
    300       return -1;
    301    }
    302 
    303    if (!shProg->LinkStatus) {
    304       _mesa_error(ctx, GL_INVALID_OPERATION,
    305                   "glGetFragDataIndex(program not linked)");
    306       return -1;
    307    }
    308 
    309    if (!name)
    310       return -1;
    311 
    312    if (strncmp(name, "gl_", 3) == 0) {
    313       _mesa_error(ctx, GL_INVALID_OPERATION,
    314                   "glGetFragDataIndex(illegal name)");
    315       return -1;
    316    }
    317 
    318    /* Not having a fragment shader is not an error.
    319     */
    320    if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
    321       return -1;
    322 
    323    exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
    324    foreach_list(node, ir) {
    325       const ir_variable *const var = ((ir_instruction *) node)->as_variable();
    326 
    327       /* The extra check against FRAG_RESULT_DATA0 is because
    328        * glGetFragDataLocation cannot be used on "conventional" attributes.
    329        *
    330        * From page 95 of the OpenGL 3.0 spec:
    331        *
    332        *     "If name is not an active attribute, if name is a conventional
    333        *     attribute, or if an error occurs, -1 will be returned."
    334        */
    335       if (var == NULL
    336           || var->mode != ir_var_out
    337           || var->location == -1
    338           || var->location < FRAG_RESULT_DATA0)
    339          continue;
    340 
    341       if (strcmp(var->name, name) == 0)
    342          return var->index;
    343    }
    344 
    345    return -1;
    346 }
    347 
    348 GLint GLAPIENTRY
    349 _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
    350 {
    351    GET_CURRENT_CONTEXT(ctx);
    352    struct gl_shader_program *const shProg =
    353       _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
    354 
    355    if (!shProg) {
    356       return -1;
    357    }
    358 
    359    if (!shProg->LinkStatus) {
    360       _mesa_error(ctx, GL_INVALID_OPERATION,
    361                   "glGetFragDataLocation(program not linked)");
    362       return -1;
    363    }
    364 
    365    if (!name)
    366       return -1;
    367 
    368    if (strncmp(name, "gl_", 3) == 0) {
    369       _mesa_error(ctx, GL_INVALID_OPERATION,
    370                   "glGetFragDataLocation(illegal name)");
    371       return -1;
    372    }
    373 
    374    /* Not having a fragment shader is not an error.
    375     */
    376    if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
    377       return -1;
    378 
    379    exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
    380    foreach_list(node, ir) {
    381       const ir_variable *const var = ((ir_instruction *) node)->as_variable();
    382 
    383       /* The extra check against FRAG_RESULT_DATA0 is because
    384        * glGetFragDataLocation cannot be used on "conventional" attributes.
    385        *
    386        * From page 95 of the OpenGL 3.0 spec:
    387        *
    388        *     "If name is not an active attribute, if name is a conventional
    389        *     attribute, or if an error occurs, -1 will be returned."
    390        */
    391       if (var == NULL
    392 	  || var->mode != ir_var_out
    393 	  || var->location == -1
    394 	  || var->location < FRAG_RESULT_DATA0)
    395 	 continue;
    396 
    397       if (strcmp(var->name, name) == 0)
    398 	 return var->location - FRAG_RESULT_DATA0;
    399    }
    400 
    401    return -1;
    402 }
    403