Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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@intel.com>
  29.  */
  30.  
  31. #include "main/context.h"
  32. #include "main/core.h"
  33. #include "glsl_symbol_table.h"
  34. #include "ir.h"
  35. #include "shaderobj.h"
  36. #include "program/hash_table.h"
  37. #include "../glsl/program.h"
  38. #include "uniforms.h"
  39. #include "main/enums.h"
  40.  
  41. extern "C" {
  42. #include "shaderapi.h"
  43. }
  44.  
  45. static GLint
  46. program_resource_location(struct gl_shader_program *shProg,
  47.                           struct gl_program_resource *res, const char *name);
  48.  
  49. /**
  50.  * Declare convenience functions to return resource data in a given type.
  51.  * Warning! this is not type safe so be *very* careful when using these.
  52.  */
  53. #define DECL_RESOURCE_FUNC(name, type) \
  54. const type * RESOURCE_ ## name (gl_program_resource *res) { \
  55.    assert(res->Data); \
  56.    return (type *) res->Data; \
  57. }
  58.  
  59. DECL_RESOURCE_FUNC(VAR, ir_variable);
  60. DECL_RESOURCE_FUNC(UBO, gl_uniform_block);
  61. DECL_RESOURCE_FUNC(UNI, gl_uniform_storage);
  62. DECL_RESOURCE_FUNC(ATC, gl_active_atomic_buffer);
  63. DECL_RESOURCE_FUNC(XFB, gl_transform_feedback_varying_info);
  64.  
  65. void GLAPIENTRY
  66. _mesa_BindAttribLocation(GLhandleARB program, GLuint index,
  67.                             const GLcharARB *name)
  68. {
  69.    GET_CURRENT_CONTEXT(ctx);
  70.  
  71.    struct gl_shader_program *const shProg =
  72.       _mesa_lookup_shader_program_err(ctx, program, "glBindAttribLocation");
  73.    if (!shProg)
  74.       return;
  75.  
  76.    if (!name)
  77.       return;
  78.  
  79.    if (strncmp(name, "gl_", 3) == 0) {
  80.       _mesa_error(ctx, GL_INVALID_OPERATION,
  81.                   "glBindAttribLocation(illegal name)");
  82.       return;
  83.    }
  84.  
  85.    if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
  86.       _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
  87.       return;
  88.    }
  89.  
  90.    /* Replace the current value if it's already in the list.  Add
  91.     * VERT_ATTRIB_GENERIC0 because that's how the linker differentiates
  92.     * between built-in attributes and user-defined attributes.
  93.     */
  94.    shProg->AttributeBindings->put(index + VERT_ATTRIB_GENERIC0, name);
  95.  
  96.    /*
  97.     * Note that this attribute binding won't go into effect until
  98.     * glLinkProgram is called again.
  99.     */
  100. }
  101.  
  102. static bool
  103. is_active_attrib(const ir_variable *var)
  104. {
  105.    if (!var)
  106.       return false;
  107.  
  108.    switch (var->data.mode) {
  109.    case ir_var_shader_in:
  110.       return var->data.location != -1;
  111.  
  112.    case ir_var_system_value:
  113.       /* From GL 4.3 core spec, section 11.1.1 (Vertex Attributes):
  114.        * "For GetActiveAttrib, all active vertex shader input variables
  115.        * are enumerated, including the special built-in inputs gl_VertexID
  116.        * and gl_InstanceID."
  117.        */
  118.       return var->data.location == SYSTEM_VALUE_VERTEX_ID ||
  119.              var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE ||
  120.              var->data.location == SYSTEM_VALUE_INSTANCE_ID;
  121.  
  122.    default:
  123.       return false;
  124.    }
  125. }
  126.  
  127. void GLAPIENTRY
  128. _mesa_GetActiveAttrib(GLhandleARB program, GLuint desired_index,
  129.                          GLsizei maxLength, GLsizei * length, GLint * size,
  130.                          GLenum * type, GLcharARB * name)
  131. {
  132.    GET_CURRENT_CONTEXT(ctx);
  133.    struct gl_shader_program *shProg;
  134.  
  135.    if (maxLength < 0) {
  136.       _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(maxLength < 0)");
  137.       return;
  138.    }
  139.  
  140.    shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
  141.    if (!shProg)
  142.       return;
  143.  
  144.    if (!shProg->LinkStatus) {
  145.       _mesa_error(ctx, GL_INVALID_VALUE,
  146.                   "glGetActiveAttrib(program not linked)");
  147.       return;
  148.    }
  149.  
  150.    if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
  151.       _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(no vertex shader)");
  152.       return;
  153.    }
  154.  
  155.    struct gl_program_resource *res =
  156.       _mesa_program_resource_find_index(shProg, GL_PROGRAM_INPUT,
  157.                                         desired_index);
  158.  
  159.    /* User asked for index that does not exist. */
  160.    if (!res) {
  161.       _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
  162.       return;
  163.    }
  164.  
  165.    const ir_variable *const var = RESOURCE_VAR(res);
  166.  
  167.    if (!is_active_attrib(var))
  168.       return;
  169.  
  170.    const char *var_name = var->name;
  171.  
  172.    /* Since gl_VertexID may be lowered to gl_VertexIDMESA, we need to
  173.     * consider gl_VertexIDMESA as gl_VertexID for purposes of checking
  174.     * active attributes.
  175.     */
  176.    if (var->data.mode == ir_var_system_value &&
  177.        var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE) {
  178.       var_name = "gl_VertexID";
  179.    }
  180.  
  181.    _mesa_copy_string(name, maxLength, length, var_name);
  182.  
  183.    if (size)
  184.       _mesa_program_resource_prop(shProg, res, desired_index, GL_ARRAY_SIZE,
  185.                                   size, "glGetActiveAttrib");
  186.  
  187.    if (type)
  188.       _mesa_program_resource_prop(shProg, res, desired_index, GL_TYPE,
  189.                                   (GLint *) type, "glGetActiveAttrib");
  190. }
  191.  
  192. /* Locations associated with shader variables (array or non-array) can be
  193.  * queried using its base name or using the base name appended with the
  194.  * valid array index. For example, in case of below vertex shader, valid
  195.  * queries can be made to know the location of "xyz", "array", "array[0]",
  196.  * "array[1]", "array[2]" and "array[3]". In this example index reurned
  197.  * will be 0, 0, 0, 1, 2, 3 respectively.
  198.  *
  199.  * [Vertex Shader]
  200.  * layout(location=0) in vec4 xyz;
  201.  * layout(location=1) in vec4[4] array;
  202.  * void main()
  203.  * { }
  204.  *
  205.  * This requirement came up with the addition of ARB_program_interface_query
  206.  * to OpenGL 4.3 specification. See page 101 (page 122 of the PDF) for details.
  207.  *
  208.  * This utility function is used by:
  209.  * _mesa_GetAttribLocation
  210.  * _mesa_GetFragDataLocation
  211.  * _mesa_GetFragDataIndex
  212.  *
  213.  * Returns 0:
  214.  *    if the 'name' string matches var->name.
  215.  * Returns 'matched index':
  216.  *    if the 'name' string matches var->name appended with valid array index.
  217.  */
  218. int static inline
  219. get_matching_index(const ir_variable *const var, const char *name) {
  220.    unsigned idx = 0;
  221.    const char *const paren = strchr(name, '[');
  222.    const unsigned len = (paren != NULL) ? paren - name : strlen(name);
  223.  
  224.    if (paren != NULL) {
  225.       if (!var->type->is_array())
  226.          return -1;
  227.  
  228.       char *endptr;
  229.       idx = (unsigned) strtol(paren + 1, &endptr, 10);
  230.       const unsigned idx_len = endptr != (paren + 1) ? endptr - paren - 1 : 0;
  231.  
  232.       /* Validate the sub string representing index in 'name' string */
  233.       if ((idx > 0 && paren[1] == '0') /* leading zeroes */
  234.           || (idx == 0 && idx_len > 1) /* all zeroes */
  235.           || paren[1] == ' ' /* whitespace */
  236.           || endptr[0] != ']' /* closing brace */
  237.           || endptr[1] != '\0' /* null char */
  238.           || idx_len == 0 /* missing index */
  239.           || idx >= var->type->length) /* exceeding array bound */
  240.          return -1;
  241.    }
  242.  
  243.    if (strncmp(var->name, name, len) == 0 && var->name[len] == '\0')
  244.       return idx;
  245.  
  246.    return -1;
  247. }
  248.  
  249. GLint GLAPIENTRY
  250. _mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name)
  251. {
  252.    GET_CURRENT_CONTEXT(ctx);
  253.    struct gl_shader_program *const shProg =
  254.       _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
  255.  
  256.    if (!shProg) {
  257.       return -1;
  258.    }
  259.  
  260.    if (!shProg->LinkStatus) {
  261.       _mesa_error(ctx, GL_INVALID_OPERATION,
  262.                   "glGetAttribLocation(program not linked)");
  263.       return -1;
  264.    }
  265.  
  266.    if (!name)
  267.       return -1;
  268.  
  269.    /* Not having a vertex shader is not an error.
  270.     */
  271.    if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)
  272.       return -1;
  273.  
  274.    struct gl_program_resource *res =
  275.       _mesa_program_resource_find_name(shProg, GL_PROGRAM_INPUT, name);
  276.  
  277.    if (!res)
  278.       return -1;
  279.  
  280.    GLint loc = program_resource_location(shProg, res, name);
  281.  
  282.    /* The extra check against against 0 is made because of builtin-attribute
  283.     * locations that have offset applied. Function program_resource_location
  284.     * can return built-in attribute locations < 0 and glGetAttribLocation
  285.     * cannot be used on "conventional" attributes.
  286.     *
  287.     * From page 95 of the OpenGL 3.0 spec:
  288.     *
  289.     *     "If name is not an active attribute, if name is a conventional
  290.     *     attribute, or if an error occurs, -1 will be returned."
  291.     */
  292.    return (loc >= 0) ? loc : -1;
  293. }
  294.  
  295. unsigned
  296. _mesa_count_active_attribs(struct gl_shader_program *shProg)
  297. {
  298.    if (!shProg->LinkStatus
  299.        || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
  300.       return 0;
  301.    }
  302.  
  303.    struct gl_program_resource *res = shProg->ProgramResourceList;
  304.    unsigned count = 0;
  305.    for (unsigned j = 0; j < shProg->NumProgramResourceList; j++, res++) {
  306.       if (res->Type == GL_PROGRAM_INPUT &&
  307.           res->StageReferences & (1 << MESA_SHADER_VERTEX) &&
  308.           is_active_attrib(RESOURCE_VAR(res)))
  309.          count++;
  310.    }
  311.    return count;
  312. }
  313.  
  314.  
  315. size_t
  316. _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
  317. {
  318.    if (!shProg->LinkStatus
  319.        || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
  320.       return 0;
  321.    }
  322.  
  323.    struct gl_program_resource *res = shProg->ProgramResourceList;
  324.    size_t longest = 0;
  325.    for (unsigned j = 0; j < shProg->NumProgramResourceList; j++, res++) {
  326.       if (res->Type == GL_PROGRAM_INPUT &&
  327.           res->StageReferences & (1 << MESA_SHADER_VERTEX)) {
  328.  
  329.           const size_t length = strlen(RESOURCE_VAR(res)->name);
  330.           if (length >= longest)
  331.              longest = length + 1;
  332.       }
  333.    }
  334.  
  335.    return longest;
  336. }
  337.  
  338. void GLAPIENTRY
  339. _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
  340.                            const GLchar *name)
  341. {
  342.    _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
  343. }
  344.  
  345. void GLAPIENTRY
  346. _mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
  347.                                   GLuint index, const GLchar *name)
  348. {
  349.    GET_CURRENT_CONTEXT(ctx);
  350.  
  351.    struct gl_shader_program *const shProg =
  352.       _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
  353.    if (!shProg)
  354.       return;
  355.  
  356.    if (!name)
  357.       return;
  358.  
  359.    if (strncmp(name, "gl_", 3) == 0) {
  360.       _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
  361.       return;
  362.    }
  363.  
  364.    if (index > 1) {
  365.       _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
  366.       return;
  367.    }
  368.  
  369.    if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) {
  370.       _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
  371.       return;
  372.    }
  373.  
  374.    if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) {
  375.       _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
  376.       return;
  377.    }
  378.  
  379.    /* Replace the current value if it's already in the list.  Add
  380.     * FRAG_RESULT_DATA0 because that's how the linker differentiates
  381.     * between built-in attributes and user-defined attributes.
  382.     */
  383.    shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
  384.    shProg->FragDataIndexBindings->put(index, name);
  385.    /*
  386.     * Note that this binding won't go into effect until
  387.     * glLinkProgram is called again.
  388.     */
  389.  
  390. }
  391.  
  392. GLint GLAPIENTRY
  393. _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
  394. {
  395.    GET_CURRENT_CONTEXT(ctx);
  396.    struct gl_shader_program *const shProg =
  397.       _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
  398.  
  399.    if (!shProg) {
  400.       return -1;
  401.    }
  402.  
  403.    if (!shProg->LinkStatus) {
  404.       _mesa_error(ctx, GL_INVALID_OPERATION,
  405.                   "glGetFragDataIndex(program not linked)");
  406.       return -1;
  407.    }
  408.  
  409.    if (!name)
  410.       return -1;
  411.  
  412.    if (strncmp(name, "gl_", 3) == 0) {
  413.       _mesa_error(ctx, GL_INVALID_OPERATION,
  414.                   "glGetFragDataIndex(illegal name)");
  415.       return -1;
  416.    }
  417.  
  418.    /* Not having a fragment shader is not an error.
  419.     */
  420.    if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
  421.       return -1;
  422.  
  423.    return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
  424.                                                 name);
  425. }
  426.  
  427. GLint GLAPIENTRY
  428. _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
  429. {
  430.    GET_CURRENT_CONTEXT(ctx);
  431.    struct gl_shader_program *const shProg =
  432.       _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
  433.  
  434.    if (!shProg) {
  435.       return -1;
  436.    }
  437.  
  438.    if (!shProg->LinkStatus) {
  439.       _mesa_error(ctx, GL_INVALID_OPERATION,
  440.                   "glGetFragDataLocation(program not linked)");
  441.       return -1;
  442.    }
  443.  
  444.    if (!name)
  445.       return -1;
  446.  
  447.    if (strncmp(name, "gl_", 3) == 0) {
  448.       _mesa_error(ctx, GL_INVALID_OPERATION,
  449.                   "glGetFragDataLocation(illegal name)");
  450.       return -1;
  451.    }
  452.  
  453.    /* Not having a fragment shader is not an error.
  454.     */
  455.    if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
  456.       return -1;
  457.  
  458.    struct gl_program_resource *res =
  459.       _mesa_program_resource_find_name(shProg, GL_PROGRAM_OUTPUT, name);
  460.  
  461.    if (!res)
  462.       return -1;
  463.  
  464.    GLint loc = program_resource_location(shProg, res, name);
  465.  
  466.    /* The extra check against against 0 is made because of builtin-attribute
  467.     * locations that have offset applied. Function program_resource_location
  468.     * can return built-in attribute locations < 0 and glGetFragDataLocation
  469.     * cannot be used on "conventional" attributes.
  470.     *
  471.     * From page 95 of the OpenGL 3.0 spec:
  472.     *
  473.     *     "If name is not an active attribute, if name is a conventional
  474.     *     attribute, or if an error occurs, -1 will be returned."
  475.     */
  476.    return (loc >= 0) ? loc : -1;
  477. }
  478.  
  479. const char*
  480. _mesa_program_resource_name(struct gl_program_resource *res)
  481. {
  482.    switch (res->Type) {
  483.    case GL_UNIFORM_BLOCK:
  484.       return RESOURCE_UBO(res)->Name;
  485.    case GL_TRANSFORM_FEEDBACK_VARYING:
  486.       return RESOURCE_XFB(res)->Name;
  487.    case GL_PROGRAM_INPUT:
  488.    case GL_PROGRAM_OUTPUT:
  489.       return RESOURCE_VAR(res)->name;
  490.    case GL_UNIFORM:
  491.       return RESOURCE_UNI(res)->name;
  492.    default:
  493.       assert(!"support for resource type not implemented");
  494.    }
  495.    return NULL;
  496. }
  497.  
  498.  
  499. unsigned
  500. _mesa_program_resource_array_size(struct gl_program_resource *res)
  501. {
  502.    switch (res->Type) {
  503.    case GL_TRANSFORM_FEEDBACK_VARYING:
  504.       return RESOURCE_XFB(res)->Size > 1 ?
  505.              RESOURCE_XFB(res)->Size : 0;
  506.    case GL_PROGRAM_INPUT:
  507.    case GL_PROGRAM_OUTPUT:
  508.       return RESOURCE_VAR(res)->data.max_array_access;
  509.    case GL_UNIFORM:
  510.       return RESOURCE_UNI(res)->array_elements;
  511.    case GL_ATOMIC_COUNTER_BUFFER:
  512.    case GL_UNIFORM_BLOCK:
  513.       return 0;
  514.    default:
  515.       assert(!"support for resource type not implemented");
  516.    }
  517.    return 0;
  518. }
  519.  
  520. static int
  521. array_index_of_resource(struct gl_program_resource *res,
  522.                         const char *name)
  523. {
  524.    assert(res->Data);
  525.  
  526.    switch (res->Type) {
  527.    case GL_PROGRAM_INPUT:
  528.    case GL_PROGRAM_OUTPUT:
  529.       return get_matching_index(RESOURCE_VAR(res), name);
  530.    default:
  531.       assert(!"support for resource type not implemented");
  532.       return -1;
  533.    }
  534. }
  535.  
  536. /* Find a program resource with specific name in given interface.
  537.  */
  538. struct gl_program_resource *
  539. _mesa_program_resource_find_name(struct gl_shader_program *shProg,
  540.                                  GLenum programInterface, const char *name)
  541. {
  542.    struct gl_program_resource *res = shProg->ProgramResourceList;
  543.    for (unsigned i = 0; i < shProg->NumProgramResourceList; i++, res++) {
  544.       if (res->Type != programInterface)
  545.          continue;
  546.  
  547.       /* Resource basename. */
  548.       const char *rname = _mesa_program_resource_name(res);
  549.       unsigned baselen = strlen(rname);
  550.  
  551.       switch (programInterface) {
  552.       case GL_TRANSFORM_FEEDBACK_VARYING:
  553.       case GL_UNIFORM_BLOCK:
  554.       case GL_UNIFORM:
  555.          if (strncmp(rname, name, baselen) == 0) {
  556.             /* Basename match, check if array or struct. */
  557.             if (name[baselen] == '\0' ||
  558.                 name[baselen] == '[' ||
  559.                 name[baselen] == '.') {
  560.                return res;
  561.             }
  562.          }
  563.          break;
  564.       case GL_PROGRAM_INPUT:
  565.       case GL_PROGRAM_OUTPUT:
  566.          if (array_index_of_resource(res, name) >= 0)
  567.             return res;
  568.          break;
  569.       default:
  570.          assert(!"not implemented for given interface");
  571.       }
  572.    }
  573.    return NULL;
  574. }
  575.  
  576. static GLuint
  577. calc_resource_index(struct gl_shader_program *shProg,
  578.                     struct gl_program_resource *res)
  579. {
  580.    unsigned i;
  581.    GLuint index = 0;
  582.    for (i = 0; i < shProg->NumProgramResourceList; i++) {
  583.       if (&shProg->ProgramResourceList[i] == res)
  584.          return index;
  585.       if (shProg->ProgramResourceList[i].Type == res->Type)
  586.          index++;
  587.    }
  588.    return GL_INVALID_INDEX;
  589. }
  590.  
  591. /**
  592.  * Calculate index for the given resource.
  593.  */
  594. GLuint
  595. _mesa_program_resource_index(struct gl_shader_program *shProg,
  596.                              struct gl_program_resource *res)
  597. {
  598.    if (!res)
  599.       return GL_INVALID_INDEX;
  600.  
  601.    switch (res->Type) {
  602.    case GL_UNIFORM_BLOCK:
  603.       return RESOURCE_UBO(res)- shProg->UniformBlocks;
  604.    case GL_ATOMIC_COUNTER_BUFFER:
  605.       return RESOURCE_ATC(res) - shProg->AtomicBuffers;
  606.    case GL_TRANSFORM_FEEDBACK_VARYING:
  607.    default:
  608.       return calc_resource_index(shProg, res);
  609.    }
  610. }
  611.  
  612. /* Find a program resource with specific index in given interface.
  613.  */
  614. struct gl_program_resource *
  615. _mesa_program_resource_find_index(struct gl_shader_program *shProg,
  616.                                   GLenum programInterface, GLuint index)
  617. {
  618.    struct gl_program_resource *res = shProg->ProgramResourceList;
  619.    int idx = -1;
  620.  
  621.    for (unsigned i = 0; i < shProg->NumProgramResourceList; i++, res++) {
  622.       if (res->Type != programInterface)
  623.          continue;
  624.  
  625.       switch (res->Type) {
  626.       case GL_UNIFORM_BLOCK:
  627.       case GL_ATOMIC_COUNTER_BUFFER:
  628.          if (_mesa_program_resource_index(shProg, res) == index)
  629.             return res;
  630.          break;
  631.       case GL_TRANSFORM_FEEDBACK_VARYING:
  632.       case GL_PROGRAM_INPUT:
  633.       case GL_PROGRAM_OUTPUT:
  634.       case GL_UNIFORM:
  635.          if (++idx == (int) index)
  636.             return res;
  637.          break;
  638.       default:
  639.          assert(!"not implemented for given interface");
  640.       }
  641.    }
  642.    return NULL;
  643. }
  644.  
  645. /* Get full name of a program resource.
  646.  */
  647. bool
  648. _mesa_get_program_resource_name(struct gl_shader_program *shProg,
  649.                                 GLenum programInterface, GLuint index,
  650.                                 GLsizei bufSize, GLsizei *length,
  651.                                 GLchar *name, const char *caller)
  652. {
  653.    GET_CURRENT_CONTEXT(ctx);
  654.  
  655.    /* Find resource with given interface and index. */
  656.    struct gl_program_resource *res =
  657.       _mesa_program_resource_find_index(shProg, programInterface, index);
  658.  
  659.    /* The error INVALID_VALUE is generated if <index> is greater than
  660.    * or equal to the number of entries in the active resource list for
  661.    * <programInterface>.
  662.    */
  663.    if (!res) {
  664.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(index %u)", caller, index);
  665.       return false;
  666.    }
  667.  
  668.    if (bufSize < 0) {
  669.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(bufSize %d)", caller, bufSize);
  670.       return false;
  671.    }
  672.  
  673.    GLsizei localLength;
  674.  
  675.    if (length == NULL)
  676.       length = &localLength;
  677.  
  678.    _mesa_copy_string(name, bufSize, length, _mesa_program_resource_name(res));
  679.  
  680.    /* Page 61 (page 73 of the PDF) in section 2.11 of the OpenGL ES 3.0
  681.     * spec says:
  682.     *
  683.     *     "If the active uniform is an array, the uniform name returned in
  684.     *     name will always be the name of the uniform array appended with
  685.     *     "[0]"."
  686.     *
  687.     * The same text also appears in the OpenGL 4.2 spec.  It does not,
  688.     * however, appear in any previous spec.  Previous specifications are
  689.     * ambiguous in this regard.  However, either name can later be passed
  690.     * to glGetUniformLocation (and related APIs), so there shouldn't be any
  691.     * harm in always appending "[0]" to uniform array names.
  692.     *
  693.     * Geometry shader stage has different naming convention where the 'normal'
  694.     * condition is an array, therefore for variables referenced in geometry
  695.     * stage we do not add '[0]'.
  696.     *
  697.     * Note, that TCS outputs and TES inputs should not have index appended
  698.     * either.
  699.     */
  700.    bool add_index = !(((programInterface == GL_PROGRAM_INPUT) &&
  701.                        res->StageReferences & (1 << MESA_SHADER_GEOMETRY)));
  702.  
  703.    if (add_index && _mesa_program_resource_array_size(res)) {
  704.       int i;
  705.  
  706.       /* The comparison is strange because *length does *NOT* include the
  707.        * terminating NUL, but maxLength does.
  708.        */
  709.       for (i = 0; i < 3 && (*length + i + 1) < bufSize; i++)
  710.          name[*length + i] = "[0]"[i];
  711.  
  712.       name[*length + i] = '\0';
  713.       *length += i;
  714.    }
  715.    return true;
  716. }
  717.  
  718. static GLint
  719. program_resource_location(struct gl_shader_program *shProg,
  720.                           struct gl_program_resource *res, const char *name)
  721. {
  722.    unsigned index, offset;
  723.    int array_index = -1;
  724.  
  725.    if (res->Type == GL_PROGRAM_INPUT || res->Type == GL_PROGRAM_OUTPUT) {
  726.       array_index = array_index_of_resource(res, name);
  727.       if (array_index < 0)
  728.          return -1;
  729.    }
  730.  
  731.    /* VERT_ATTRIB_GENERIC0 and FRAG_RESULT_DATA0 are decremented as these
  732.     * offsets are used internally to differentiate between built-in attributes
  733.     * and user-defined attributes.
  734.     */
  735.    switch (res->Type) {
  736.    case GL_PROGRAM_INPUT:
  737.       return RESOURCE_VAR(res)->data.location + array_index - VERT_ATTRIB_GENERIC0;
  738.    case GL_PROGRAM_OUTPUT:
  739.       return RESOURCE_VAR(res)->data.location + array_index - FRAG_RESULT_DATA0;
  740.    case GL_UNIFORM:
  741.       index = _mesa_get_uniform_location(shProg, name, &offset);
  742.  
  743.       if (index == GL_INVALID_INDEX)
  744.          return -1;
  745.  
  746.       /* From the GL_ARB_uniform_buffer_object spec:
  747.        *
  748.        *     "The value -1 will be returned if <name> does not correspond to an
  749.        *     active uniform variable name in <program>, if <name> is associated
  750.        *     with a named uniform block, or if <name> starts with the reserved
  751.        *     prefix "gl_"."
  752.        */
  753.       if (RESOURCE_UNI(res)->block_index != -1 ||
  754.           RESOURCE_UNI(res)->atomic_buffer_index != -1)
  755.          return -1;
  756.  
  757.       /* location in remap table + array element offset */
  758.       return RESOURCE_UNI(res)->remap_location + offset;
  759.  
  760.    default:
  761.       return -1;
  762.    }
  763. }
  764.  
  765. /**
  766.  * Function implements following location queries:
  767.  *    glGetAttribLocation
  768.  *    glGetFragDataLocation
  769.  *    glGetUniformLocation
  770.  */
  771. GLint
  772. _mesa_program_resource_location(struct gl_shader_program *shProg,
  773.                                 GLenum programInterface, const char *name)
  774. {
  775.    struct gl_program_resource *res =
  776.       _mesa_program_resource_find_name(shProg, programInterface, name);
  777.  
  778.    /* Resource not found. */
  779.    if (!res)
  780.       return -1;
  781.  
  782.    return program_resource_location(shProg, res, name);
  783. }
  784.  
  785. /**
  786.  * Function implements following index queries:
  787.  *    glGetFragDataIndex
  788.  */
  789. GLint
  790. _mesa_program_resource_location_index(struct gl_shader_program *shProg,
  791.                                       GLenum programInterface, const char *name)
  792. {
  793.    struct gl_program_resource *res =
  794.       _mesa_program_resource_find_name(shProg, programInterface, name);
  795.  
  796.    /* Non-existent variable or resource is not referenced by fragment stage. */
  797.    if (!res || !(res->StageReferences & (1 << MESA_SHADER_FRAGMENT)))
  798.       return -1;
  799.  
  800.    return RESOURCE_VAR(res)->data.index;
  801. }
  802.  
  803. static uint8_t
  804. stage_from_enum(GLenum ref)
  805. {
  806.    switch (ref) {
  807.    case GL_REFERENCED_BY_VERTEX_SHADER:
  808.       return MESA_SHADER_VERTEX;
  809.    case GL_REFERENCED_BY_GEOMETRY_SHADER:
  810.       return MESA_SHADER_GEOMETRY;
  811.    case GL_REFERENCED_BY_FRAGMENT_SHADER:
  812.       return MESA_SHADER_FRAGMENT;
  813.    case GL_REFERENCED_BY_COMPUTE_SHADER:
  814.       return MESA_SHADER_COMPUTE;
  815.    default:
  816.       assert(!"shader stage not supported");
  817.       return MESA_SHADER_STAGES;
  818.    }
  819. }
  820.  
  821. /**
  822.  * Check if resource is referenced by given 'referenced by' stage enum.
  823.  * ATC and UBO resources hold stage references of their own.
  824.  */
  825. static bool
  826. is_resource_referenced(struct gl_shader_program *shProg,
  827.                        struct gl_program_resource *res,
  828.                        GLuint index, uint8_t stage)
  829. {
  830.    /* First, check if we even have such a stage active. */
  831.    if (!shProg->_LinkedShaders[stage])
  832.       return false;
  833.  
  834.    if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
  835.       return RESOURCE_ATC(res)->StageReferences[stage];
  836.  
  837.    if (res->Type == GL_UNIFORM_BLOCK)
  838.       return shProg->UniformBlockStageIndex[stage][index] != -1;
  839.  
  840.    return res->StageReferences & (1 << stage);
  841. }
  842.  
  843. static unsigned
  844. get_buffer_property(struct gl_shader_program *shProg,
  845.                     struct gl_program_resource *res, const GLenum prop,
  846.                     GLint *val, const char *caller)
  847. {
  848.    GET_CURRENT_CONTEXT(ctx);
  849.    if (res->Type != GL_UNIFORM_BLOCK &&
  850.        res->Type != GL_ATOMIC_COUNTER_BUFFER)
  851.       goto invalid_operation;
  852.  
  853.    if (res->Type == GL_UNIFORM_BLOCK) {
  854.       switch (prop) {
  855.       case GL_BUFFER_BINDING:
  856.          *val = RESOURCE_UBO(res)->Binding;
  857.          return 1;
  858.       case GL_BUFFER_DATA_SIZE:
  859.          *val = RESOURCE_UBO(res)->UniformBufferSize;
  860.          return 1;
  861.       case GL_NUM_ACTIVE_VARIABLES:
  862.          *val = 0;
  863.          for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) {
  864.             const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
  865.             struct gl_program_resource *uni =
  866.                _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname);
  867.             if (!uni)
  868.                continue;
  869.             (*val)++;
  870.          }
  871.          return 1;
  872.       case GL_ACTIVE_VARIABLES:
  873.          for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) {
  874.             const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
  875.             struct gl_program_resource *uni =
  876.                _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname);
  877.             if (!uni)
  878.                continue;
  879.             *val++ =
  880.                _mesa_program_resource_index(shProg, uni);
  881.          }
  882.          return RESOURCE_UBO(res)->NumUniforms;
  883.       }
  884.    } else if (res->Type == GL_ATOMIC_COUNTER_BUFFER) {
  885.       switch (prop) {
  886.       case GL_BUFFER_BINDING:
  887.          *val = RESOURCE_ATC(res)->Binding;
  888.          return 1;
  889.       case GL_BUFFER_DATA_SIZE:
  890.          *val = RESOURCE_ATC(res)->MinimumSize;
  891.          return 1;
  892.       case GL_NUM_ACTIVE_VARIABLES:
  893.          *val = RESOURCE_ATC(res)->NumUniforms;
  894.          return 1;
  895.       case GL_ACTIVE_VARIABLES:
  896.          for (unsigned i = 0; i < RESOURCE_ATC(res)->NumUniforms; i++)
  897.             *val++ = RESOURCE_ATC(res)->Uniforms[i];
  898.          return RESOURCE_ATC(res)->NumUniforms;
  899.       }
  900.    }
  901.    assert(!"support for property type not implemented");
  902.  
  903. invalid_operation:
  904.    _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
  905.                _mesa_lookup_enum_by_nr(res->Type),
  906.                _mesa_lookup_enum_by_nr(prop));
  907.  
  908.    return 0;
  909. }
  910.  
  911. unsigned
  912. _mesa_program_resource_prop(struct gl_shader_program *shProg,
  913.                             struct gl_program_resource *res, GLuint index,
  914.                             const GLenum prop, GLint *val, const char *caller)
  915. {
  916.    GET_CURRENT_CONTEXT(ctx);
  917.  
  918. #define VALIDATE_TYPE(type)\
  919.    if (res->Type != type)\
  920.       goto invalid_operation;
  921.  
  922.    switch(prop) {
  923.    case GL_NAME_LENGTH:
  924.       if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
  925.          goto invalid_operation;
  926.       /* Base name +3 if array '[0]' + terminator. */
  927.       *val = strlen(_mesa_program_resource_name(res)) +
  928.          (_mesa_program_resource_array_size(res) > 0 ? 3 : 0) + 1;
  929.       return 1;
  930.    case GL_TYPE:
  931.       switch (res->Type) {
  932.       case GL_UNIFORM:
  933.          *val = RESOURCE_UNI(res)->type->gl_type;
  934.          return 1;
  935.       case GL_PROGRAM_INPUT:
  936.       case GL_PROGRAM_OUTPUT:
  937.          *val = RESOURCE_VAR(res)->type->gl_type;
  938.          return 1;
  939.       case GL_TRANSFORM_FEEDBACK_VARYING:
  940.          *val = RESOURCE_XFB(res)->Type;
  941.          return 1;
  942.       default:
  943.          goto invalid_operation;
  944.       }
  945.    case GL_ARRAY_SIZE:
  946.       switch (res->Type) {
  947.       case GL_UNIFORM:
  948.             *val = MAX2(RESOURCE_UNI(res)->array_elements, 1);
  949.             return 1;
  950.       case GL_PROGRAM_INPUT:
  951.       case GL_PROGRAM_OUTPUT:
  952.          *val = MAX2(RESOURCE_VAR(res)->type->length, 1);
  953.          return 1;
  954.       case GL_TRANSFORM_FEEDBACK_VARYING:
  955.          *val = MAX2(RESOURCE_XFB(res)->Size, 1);
  956.          return 1;
  957.       default:
  958.          goto invalid_operation;
  959.       }
  960.    case GL_OFFSET:
  961.       VALIDATE_TYPE(GL_UNIFORM);
  962.       *val = RESOURCE_UNI(res)->offset;
  963.       return 1;
  964.    case GL_BLOCK_INDEX:
  965.       VALIDATE_TYPE(GL_UNIFORM);
  966.       *val = RESOURCE_UNI(res)->block_index;
  967.       return 1;
  968.    case GL_ARRAY_STRIDE:
  969.       VALIDATE_TYPE(GL_UNIFORM);
  970.       *val = RESOURCE_UNI(res)->array_stride;
  971.       return 1;
  972.    case GL_MATRIX_STRIDE:
  973.       VALIDATE_TYPE(GL_UNIFORM);
  974.       *val = RESOURCE_UNI(res)->matrix_stride;
  975.       return 1;
  976.    case GL_IS_ROW_MAJOR:
  977.       VALIDATE_TYPE(GL_UNIFORM);
  978.       *val = RESOURCE_UNI(res)->row_major;
  979.       return 1;
  980.    case GL_ATOMIC_COUNTER_BUFFER_INDEX:
  981.       VALIDATE_TYPE(GL_UNIFORM);
  982.       *val = RESOURCE_UNI(res)->atomic_buffer_index;
  983.       return 1;
  984.    case GL_BUFFER_BINDING:
  985.    case GL_BUFFER_DATA_SIZE:
  986.    case GL_NUM_ACTIVE_VARIABLES:
  987.    case GL_ACTIVE_VARIABLES:
  988.       return get_buffer_property(shProg, res, prop, val, caller);
  989.    case GL_REFERENCED_BY_COMPUTE_SHADER:
  990.       if (!_mesa_has_compute_shaders(ctx))
  991.          goto invalid_enum;
  992.       /* fallthrough */
  993.    case GL_REFERENCED_BY_VERTEX_SHADER:
  994.    case GL_REFERENCED_BY_GEOMETRY_SHADER:
  995.    case GL_REFERENCED_BY_FRAGMENT_SHADER:
  996.       switch (res->Type) {
  997.       case GL_UNIFORM:
  998.       case GL_PROGRAM_INPUT:
  999.       case GL_PROGRAM_OUTPUT:
  1000.       case GL_UNIFORM_BLOCK:
  1001.       case GL_ATOMIC_COUNTER_BUFFER:
  1002.          *val = is_resource_referenced(shProg, res, index,
  1003.                                        stage_from_enum(prop));
  1004.          return 1;
  1005.       default:
  1006.          goto invalid_operation;
  1007.       }
  1008.    case GL_LOCATION:
  1009.       switch (res->Type) {
  1010.       case GL_UNIFORM:
  1011.       case GL_PROGRAM_INPUT:
  1012.       case GL_PROGRAM_OUTPUT:
  1013.          *val = program_resource_location(shProg, res,
  1014.                                           _mesa_program_resource_name(res));
  1015.          return 1;
  1016.       default:
  1017.          goto invalid_operation;
  1018.       }
  1019.    case GL_LOCATION_INDEX:
  1020.       if (res->Type != GL_PROGRAM_OUTPUT)
  1021.          goto invalid_operation;
  1022.       *val = RESOURCE_VAR(res)->data.index;
  1023.       return 1;
  1024.  
  1025.    /* GL_ARB_tessellation_shader */
  1026.    case GL_IS_PER_PATCH:
  1027.    case GL_REFERENCED_BY_TESS_CONTROL_SHADER:
  1028.    case GL_REFERENCED_BY_TESS_EVALUATION_SHADER:
  1029.    default:
  1030.       goto invalid_enum;
  1031.    }
  1032.  
  1033. #undef VALIDATE_TYPE
  1034.  
  1035. invalid_enum:
  1036.    _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s prop %s)", caller,
  1037.                _mesa_lookup_enum_by_nr(res->Type),
  1038.                _mesa_lookup_enum_by_nr(prop));
  1039.    return 0;
  1040.  
  1041. invalid_operation:
  1042.    _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
  1043.                _mesa_lookup_enum_by_nr(res->Type),
  1044.                _mesa_lookup_enum_by_nr(prop));
  1045.    return 0;
  1046. }
  1047.  
  1048. extern void
  1049. _mesa_get_program_resourceiv(struct gl_shader_program *shProg,
  1050.                              GLenum programInterface, GLuint index, GLsizei propCount,
  1051.                              const GLenum *props, GLsizei bufSize,
  1052.                              GLsizei *length, GLint *params)
  1053. {
  1054.    GET_CURRENT_CONTEXT(ctx);
  1055.    GLint *val = (GLint *) params;
  1056.    const GLenum *prop = props;
  1057.    GLsizei amount = 0;
  1058.  
  1059.    struct gl_program_resource *res =
  1060.       _mesa_program_resource_find_index(shProg, programInterface, index);
  1061.  
  1062.    /* No such resource found or bufSize negative. */
  1063.    if (!res || bufSize < 0) {
  1064.       _mesa_error(ctx, GL_INVALID_VALUE,
  1065.                   "glGetProgramResourceiv(%s index %d bufSize %d)",
  1066.                   _mesa_lookup_enum_by_nr(programInterface), index, bufSize);
  1067.       return;
  1068.    }
  1069.  
  1070.    /* Write propCount values until error occurs or bufSize reached. */
  1071.    for (int i = 0; i < propCount && i < bufSize; i++, val++, prop++) {
  1072.       int props_written =
  1073.          _mesa_program_resource_prop(shProg, res, index, *prop, val,
  1074.                                      "glGetProgramResourceiv");
  1075.  
  1076.       /* Error happened. */
  1077.       if (props_written == 0)
  1078.          return;
  1079.  
  1080.       amount += props_written;
  1081.    }
  1082.  
  1083.    /* If <length> is not NULL, the actual number of integer values
  1084.     * written to <params> will be written to <length>.
  1085.     */
  1086.    if (length)
  1087.       *length = amount;
  1088. }
  1089.