Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2015 Intel Corporation.  All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  *
  24.  */
  25.  
  26. #include "main/enums.h"
  27. #include "main/macros.h"
  28. #include "main/mtypes.h"
  29. #include "main/shaderapi.h"
  30. #include "main/shaderobj.h"
  31. #include "program_resource.h"
  32.  
  33. static bool
  34. supported_interface_enum(GLenum iface)
  35. {
  36.    switch (iface) {
  37.    case GL_UNIFORM:
  38.    case GL_UNIFORM_BLOCK:
  39.    case GL_PROGRAM_INPUT:
  40.    case GL_PROGRAM_OUTPUT:
  41.    case GL_TRANSFORM_FEEDBACK_VARYING:
  42.    case GL_ATOMIC_COUNTER_BUFFER:
  43.       return true;
  44.    case GL_VERTEX_SUBROUTINE:
  45.    case GL_TESS_CONTROL_SUBROUTINE:
  46.    case GL_TESS_EVALUATION_SUBROUTINE:
  47.    case GL_GEOMETRY_SUBROUTINE:
  48.    case GL_FRAGMENT_SUBROUTINE:
  49.    case GL_COMPUTE_SUBROUTINE:
  50.    case GL_VERTEX_SUBROUTINE_UNIFORM:
  51.    case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
  52.    case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
  53.    case GL_GEOMETRY_SUBROUTINE_UNIFORM:
  54.    case GL_FRAGMENT_SUBROUTINE_UNIFORM:
  55.    case GL_COMPUTE_SUBROUTINE_UNIFORM:
  56.    case GL_BUFFER_VARIABLE:
  57.    case GL_SHADER_STORAGE_BLOCK:
  58.    default:
  59.       return false;
  60.    }
  61. }
  62.  
  63. void GLAPIENTRY
  64. _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface,
  65.                             GLenum pname, GLint *params)
  66. {
  67.    GET_CURRENT_CONTEXT(ctx);
  68.    unsigned i;
  69.    struct gl_shader_program *shProg =
  70.       _mesa_lookup_shader_program_err(ctx, program,
  71.                                       "glGetProgramInterfaceiv");
  72.    if (!shProg)
  73.       return;
  74.  
  75.    if (!params) {
  76.       _mesa_error(ctx, GL_INVALID_OPERATION,
  77.                   "glGetProgramInterfaceiv(params NULL)");
  78.       return;
  79.    }
  80.  
  81.    /* Validate interface. */
  82.    if (!supported_interface_enum(programInterface)) {
  83.       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s)",
  84.                   _mesa_lookup_enum_by_nr(programInterface));
  85.       return;
  86.    }
  87.  
  88.    /* Validate pname against interface. */
  89.    switch(pname) {
  90.    case GL_ACTIVE_RESOURCES:
  91.       for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++)
  92.          if (shProg->ProgramResourceList[i].Type == programInterface)
  93.             (*params)++;
  94.       break;
  95.    case GL_MAX_NAME_LENGTH:
  96.       if (programInterface == GL_ATOMIC_COUNTER_BUFFER) {
  97.          _mesa_error(ctx, GL_INVALID_OPERATION,
  98.                      "glGetProgramInterfaceiv(%s pname %s)",
  99.                      _mesa_lookup_enum_by_nr(programInterface),
  100.                      _mesa_lookup_enum_by_nr(pname));
  101.          return;
  102.       }
  103.       /* Name length consists of base name, 3 additional chars '[0]' if
  104.        * resource is an array and finally 1 char for string terminator.
  105.        */
  106.       for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
  107.          if (shProg->ProgramResourceList[i].Type != programInterface)
  108.             continue;
  109.          const char *name =
  110.             _mesa_program_resource_name(&shProg->ProgramResourceList[i]);
  111.          unsigned array_size =
  112.             _mesa_program_resource_array_size(&shProg->ProgramResourceList[i]);
  113.          *params = MAX2(*params, strlen(name) + (array_size ? 3 : 0) + 1);
  114.       }
  115.       break;
  116.    case GL_MAX_NUM_ACTIVE_VARIABLES:
  117.       switch (programInterface) {
  118.       case GL_UNIFORM_BLOCK:
  119.          for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
  120.             if (shProg->ProgramResourceList[i].Type == programInterface) {
  121.                struct gl_uniform_block *block =
  122.                   (struct gl_uniform_block *)
  123.                   shProg->ProgramResourceList[i].Data;
  124.                *params = MAX2(*params, block->NumUniforms);
  125.             }
  126.          }
  127.          break;
  128.       case GL_ATOMIC_COUNTER_BUFFER:
  129.          for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
  130.             if (shProg->ProgramResourceList[i].Type == programInterface) {
  131.                struct gl_active_atomic_buffer *buffer =
  132.                   (struct gl_active_atomic_buffer *)
  133.                   shProg->ProgramResourceList[i].Data;
  134.                *params = MAX2(*params, buffer->NumUniforms);
  135.             }
  136.          }
  137.          break;
  138.       default:
  139.         _mesa_error(ctx, GL_INVALID_OPERATION,
  140.                     "glGetProgramInterfaceiv(%s pname %s)",
  141.                     _mesa_lookup_enum_by_nr(programInterface),
  142.                     _mesa_lookup_enum_by_nr(pname));
  143.       };
  144.       break;
  145.    case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
  146.    default:
  147.       _mesa_error(ctx, GL_INVALID_OPERATION,
  148.                   "glGetProgramInterfaceiv(pname %s)",
  149.                   _mesa_lookup_enum_by_nr(pname));
  150.    }
  151. }
  152.  
  153. static bool
  154. is_xfb_marker(const char *str)
  155. {
  156.    static const char *markers[] = {
  157.       "gl_NextBuffer",
  158.       "gl_SkipComponents1",
  159.       "gl_SkipComponents2",
  160.       "gl_SkipComponents3",
  161.       "gl_SkipComponents4",
  162.       NULL
  163.    };
  164.    const char **m = markers;
  165.  
  166.    if (strncmp(str, "gl_", 3) != 0)
  167.       return false;
  168.  
  169.    for (; *m; m++)
  170.       if (strcmp(*m, str) == 0)
  171.          return true;
  172.  
  173.    return false;
  174. }
  175.  
  176. /**
  177.  * Checks if given name index is legal for GetProgramResourceIndex,
  178.  * check is written to be compatible with GL_ARB_array_of_arrays.
  179.  */
  180. static bool
  181. valid_program_resource_index_name(const GLchar *name)
  182. {
  183.    const char *array = strstr(name, "[");
  184.    const char *close = strrchr(name, ']');
  185.  
  186.    /* Not array, no need for the check. */
  187.    if (!array)
  188.       return true;
  189.  
  190.    /* Last array index has to be zero. */
  191.    if (!close || *--close != '0')
  192.       return false;
  193.  
  194.    return true;
  195. }
  196.  
  197. GLuint GLAPIENTRY
  198. _mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface,
  199.                               const GLchar *name)
  200. {
  201.    GET_CURRENT_CONTEXT(ctx);
  202.    struct gl_program_resource *res;
  203.    struct gl_shader_program *shProg =
  204.       _mesa_lookup_shader_program_err(ctx, program,
  205.                                       "glGetProgramResourceIndex");
  206.    if (!shProg || !name)
  207.       return GL_INVALID_INDEX;
  208.  
  209.    /*
  210.     * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX
  211.     * should be returned when querying the index assigned to the special names
  212.     * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2",
  213.     * "gl_SkipComponents3", and "gl_SkipComponents4".
  214.     */
  215.    if (programInterface == GL_TRANSFORM_FEEDBACK_VARYING &&
  216.        is_xfb_marker(name))
  217.       return GL_INVALID_INDEX;
  218.  
  219.    switch (programInterface) {
  220.    case GL_PROGRAM_INPUT:
  221.    case GL_PROGRAM_OUTPUT:
  222.    case GL_UNIFORM:
  223.    case GL_UNIFORM_BLOCK:
  224.    case GL_TRANSFORM_FEEDBACK_VARYING:
  225.       /* Validate name syntax for arrays. */
  226.       if (!valid_program_resource_index_name(name))
  227.          return GL_INVALID_INDEX;
  228.  
  229.       res = _mesa_program_resource_find_name(shProg, programInterface, name);
  230.       if (!res)
  231.          return GL_INVALID_INDEX;
  232.  
  233.       return _mesa_program_resource_index(shProg, res);
  234.    case GL_ATOMIC_COUNTER_BUFFER:
  235.    default:
  236.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
  237.                   _mesa_lookup_enum_by_nr(programInterface));
  238.    }
  239.  
  240.    return GL_INVALID_INDEX;
  241. }
  242.  
  243. void GLAPIENTRY
  244. _mesa_GetProgramResourceName(GLuint program, GLenum programInterface,
  245.                              GLuint index, GLsizei bufSize, GLsizei *length,
  246.                              GLchar *name)
  247. {
  248.    GET_CURRENT_CONTEXT(ctx);
  249.    struct gl_shader_program *shProg =
  250.       _mesa_lookup_shader_program_err(ctx, program,
  251.                                       "glGetProgramResourceName");
  252.  
  253.    /* Set user friendly return values in case of errors. */
  254.    if (name)
  255.       *name = '\0';
  256.    if (length)
  257.       *length = 0;
  258.  
  259.    if (!shProg || !name)
  260.       return;
  261.  
  262.    if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
  263.        !supported_interface_enum(programInterface)) {
  264.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)",
  265.                   _mesa_lookup_enum_by_nr(programInterface));
  266.       return;
  267.    }
  268.  
  269.    _mesa_get_program_resource_name(shProg, programInterface, index, bufSize,
  270.                                    length, name, "glGetProgramResourceName");
  271. }
  272.  
  273. void GLAPIENTRY
  274. _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface,
  275.                            GLuint index, GLsizei propCount,
  276.                            const GLenum *props, GLsizei bufSize,
  277.                            GLsizei *length, GLint *params)
  278. {
  279.    GET_CURRENT_CONTEXT(ctx);
  280.    struct gl_shader_program *shProg =
  281.       _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv");
  282.  
  283.    if (!shProg || !params)
  284.       return;
  285.  
  286.    /* The error INVALID_VALUE is generated if <propCount> is zero.
  287.     * Note that we check < 0 here because it makes sense to bail early.
  288.     */
  289.    if (propCount <= 0) {
  290.       _mesa_error(ctx, GL_INVALID_VALUE,
  291.                   "glGetProgramResourceiv(propCount <= 0)");
  292.       return;
  293.    }
  294.  
  295.    /* No need to write any properties, user requested none. */
  296.    if (bufSize == 0)
  297.       return;
  298.  
  299.    _mesa_get_program_resourceiv(shProg, programInterface, index,
  300.                                 propCount, props, bufSize, length, params);
  301. }
  302.  
  303. /**
  304.  * Function verifies syntax of given name for GetProgramResourceLocation
  305.  * and GetProgramResourceLocationIndex for the following cases:
  306.  *
  307.  * "array element portion of a string passed to GetProgramResourceLocation
  308.  * or GetProgramResourceLocationIndex must not have, a "+" sign, extra
  309.  * leading zeroes, or whitespace".
  310.  *
  311.  * Check is written to be compatible with GL_ARB_array_of_arrays.
  312.  */
  313. static bool
  314. invalid_array_element_syntax(const GLchar *name)
  315. {
  316.    char *first = strchr(name, '[');
  317.    char *last = strrchr(name, '[');
  318.  
  319.    if (!first)
  320.       return false;
  321.  
  322.    /* No '+' or ' ' allowed anywhere. */
  323.    if (strchr(first, '+') || strchr(first, ' '))
  324.       return true;
  325.  
  326.    /* Check that last array index is 0. */
  327.    if (last[1] == '0' && last[2] != ']')
  328.       return true;
  329.  
  330.    return false;
  331. }
  332.  
  333. static struct gl_shader_program *
  334. lookup_linked_program(GLuint program, const char *caller)
  335. {
  336.    GET_CURRENT_CONTEXT(ctx);
  337.    struct gl_shader_program *prog =
  338.       _mesa_lookup_shader_program_err(ctx, program, caller);
  339.  
  340.    if (!prog)
  341.       return NULL;
  342.  
  343.    if (prog->LinkStatus == GL_FALSE) {
  344.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
  345.                   caller);
  346.       return NULL;
  347.    }
  348.    return prog;
  349. }
  350.  
  351. GLint GLAPIENTRY
  352. _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface,
  353.                                  const GLchar *name)
  354. {
  355.    GET_CURRENT_CONTEXT(ctx);
  356.    struct gl_shader_program *shProg =
  357.       lookup_linked_program(program, "glGetProgramResourceLocation");
  358.  
  359.    if (!shProg || !name || invalid_array_element_syntax(name))
  360.       return -1;
  361.  
  362.    /* Validate programInterface. */
  363.    switch (programInterface) {
  364.    case GL_UNIFORM:
  365.    case GL_PROGRAM_INPUT:
  366.    case GL_PROGRAM_OUTPUT:
  367.       break;
  368.  
  369.    /* For reference valid cases requiring additional extension support:
  370.     * GL_ARB_shader_subroutine
  371.     * GL_ARB_tessellation_shader
  372.     * GL_ARB_compute_shader
  373.     */
  374.    case GL_VERTEX_SUBROUTINE_UNIFORM:
  375.    case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
  376.    case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
  377.    case GL_GEOMETRY_SUBROUTINE_UNIFORM:
  378.    case GL_FRAGMENT_SUBROUTINE_UNIFORM:
  379.    case GL_COMPUTE_SUBROUTINE_UNIFORM:
  380.  
  381.    default:
  382.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)",
  383.                   _mesa_lookup_enum_by_nr(programInterface), name);
  384.    }
  385.  
  386.    return _mesa_program_resource_location(shProg, programInterface, name);
  387. }
  388.  
  389. /**
  390.  * Returns output index for dual source blending.
  391.  */
  392. GLint GLAPIENTRY
  393. _mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface,
  394.                                       const GLchar *name)
  395. {
  396.    GET_CURRENT_CONTEXT(ctx);
  397.    struct gl_shader_program *shProg =
  398.       lookup_linked_program(program, "glGetProgramResourceLocationIndex");
  399.  
  400.    if (!shProg || !name || invalid_array_element_syntax(name))
  401.       return -1;
  402.  
  403.    /* From the GL_ARB_program_interface_query spec:
  404.     *
  405.     * "For GetProgramResourceLocationIndex, <programInterface> must be
  406.     * PROGRAM_OUTPUT."
  407.     */
  408.    if (programInterface != GL_PROGRAM_OUTPUT) {
  409.       _mesa_error(ctx, GL_INVALID_ENUM,
  410.                   "glGetProgramResourceLocationIndex(%s)",
  411.                   _mesa_lookup_enum_by_nr(programInterface));
  412.       return -1;
  413.    }
  414.  
  415.    return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
  416.                                                 name);
  417. }
  418.