X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fshader_query.cpp;h=df9081b734d29624b00a9113c0b8d3186a7349dc;hb=2768a0b1b42f3c1531ab9c3647a93f0504002280;hp=23667a13328206dd6fce023ca718eafa780304b5;hpb=b12b5d9ab5c0153c93ca5ad9cd93cb36e41be4eb;p=mesa.git diff --git a/src/mesa/main/shader_query.cpp b/src/mesa/main/shader_query.cpp index 23667a13328..df9081b734d 100644 --- a/src/mesa/main/shader_query.cpp +++ b/src/mesa/main/shader_query.cpp @@ -40,7 +40,7 @@ extern "C" { } void GLAPIENTRY -_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index, +_mesa_BindAttribLocation(GLhandleARB program, GLuint index, const GLcharARB *name) { GET_CURRENT_CONTEXT(ctx); @@ -59,7 +59,7 @@ _mesa_BindAttribLocationARB(GLhandleARB program, GLuint index, return; } - if (index >= ctx->Const.VertexProgram.MaxAttribs) { + if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)"); return; } @@ -76,14 +76,44 @@ _mesa_BindAttribLocationARB(GLhandleARB program, GLuint index, */ } +static bool +is_active_attrib(const ir_variable *var) +{ + if (!var) + return false; + + switch (var->data.mode) { + case ir_var_shader_in: + return var->data.location != -1; + + case ir_var_system_value: + /* From GL 4.3 core spec, section 11.1.1 (Vertex Attributes): + * "For GetActiveAttrib, all active vertex shader input variables + * are enumerated, including the special built-in inputs gl_VertexID + * and gl_InstanceID." + */ + return var->data.location == SYSTEM_VALUE_VERTEX_ID || + var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE || + var->data.location == SYSTEM_VALUE_INSTANCE_ID; + + default: + return false; + } +} + void GLAPIENTRY -_mesa_GetActiveAttribARB(GLhandleARB program, GLuint desired_index, +_mesa_GetActiveAttrib(GLhandleARB program, GLuint desired_index, GLsizei maxLength, GLsizei * length, GLint * size, GLenum * type, GLcharARB * name) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg; + if (maxLength < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(maxLength < 0)"); + return; + } + shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib"); if (!shProg) return; @@ -102,17 +132,25 @@ _mesa_GetActiveAttribARB(GLhandleARB program, GLuint desired_index, exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir; unsigned current_index = 0; - foreach_list(node, ir) { - const ir_variable *const var = ((ir_instruction *) node)->as_variable(); + foreach_in_list(ir_instruction, node, ir) { + const ir_variable *const var = node->as_variable(); - if (var == NULL - || var->mode != ir_var_in - || var->location == -1 - || var->location < VERT_ATTRIB_GENERIC0) - continue; + if (!is_active_attrib(var)) + continue; if (current_index == desired_index) { - _mesa_copy_string(name, maxLength, length, var->name); + const char *var_name = var->name; + + /* Since gl_VertexID may be lowered to gl_VertexIDMESA, we need to + * consider gl_VertexIDMESA as gl_VertexID for purposes of checking + * active attributes. + */ + if (var->data.mode == ir_var_system_value && + var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE) { + var_name = "gl_VertexID"; + } + + _mesa_copy_string(name, maxLength, length, var_name); if (size) *size = (var->type->is_array()) ? var->type->length : 1; @@ -132,8 +170,65 @@ _mesa_GetActiveAttribARB(GLhandleARB program, GLuint desired_index, _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)"); } +/* Locations associated with shader variables (array or non-array) can be + * queried using its base name or using the base name appended with the + * valid array index. For example, in case of below vertex shader, valid + * queries can be made to know the location of "xyz", "array", "array[0]", + * "array[1]", "array[2]" and "array[3]". In this example index reurned + * will be 0, 0, 0, 1, 2, 3 respectively. + * + * [Vertex Shader] + * layout(location=0) in vec4 xyz; + * layout(location=1) in vec4[4] array; + * void main() + * { } + * + * This requirement came up with the addition of ARB_program_interface_query + * to OpenGL 4.3 specification. See page 101 (page 122 of the PDF) for details. + * + * This utility function is used by: + * _mesa_GetAttribLocation + * _mesa_GetFragDataLocation + * _mesa_GetFragDataIndex + * + * Returns 0: + * if the 'name' string matches var->name. + * Returns 'matched index': + * if the 'name' string matches var->name appended with valid array index. + */ +int static inline +get_matching_index(const ir_variable *const var, const char *name) { + unsigned idx = 0; + const char *const paren = strchr(name, '['); + const unsigned len = (paren != NULL) ? paren - name : strlen(name); + + if (paren != NULL) { + if (!var->type->is_array()) + return -1; + + char *endptr; + idx = (unsigned) strtol(paren + 1, &endptr, 10); + const unsigned idx_len = endptr != (paren + 1) ? endptr - paren - 1 : 0; + + /* Validate the sub string representing index in 'name' string */ + if ((idx > 0 && paren[1] == '0') /* leading zeroes */ + || (idx == 0 && idx_len > 1) /* all zeroes */ + || paren[1] == ' ' /* whitespace */ + || endptr[0] != ']' /* closing brace */ + || endptr[1] != '\0' /* null char */ + || idx_len == 0 /* missing index */ + || idx >= var->type->length) /* exceeding array bound */ + return -1; + } + + if (strncmp(var->name, name, len) == 0 && var->name[len] == '\0') + return idx; + + return -1; +} + GLint GLAPIENTRY -_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name) +_mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *const shProg = @@ -158,8 +253,8 @@ _mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name) return -1; exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir; - foreach_list(node, ir) { - const ir_variable *const var = ((ir_instruction *) node)->as_variable(); + foreach_in_list(ir_instruction, node, ir) { + const ir_variable *const var = node->as_variable(); /* The extra check against VERT_ATTRIB_GENERIC0 is because * glGetAttribLocation cannot be used on "conventional" attributes. @@ -170,13 +265,15 @@ _mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name) * attribute, or if an error occurs, -1 will be returned." */ if (var == NULL - || var->mode != ir_var_in - || var->location == -1 - || var->location < VERT_ATTRIB_GENERIC0) + || var->data.mode != ir_var_shader_in + || var->data.location == -1 + || var->data.location < VERT_ATTRIB_GENERIC0) continue; - if (strcmp(var->name, name) == 0) - return var->location - VERT_ATTRIB_GENERIC0; + int index = get_matching_index(var, (const char *) name); + + if (index >= 0) + return var->data.location + index - VERT_ATTRIB_GENERIC0; } return -1; @@ -194,14 +291,11 @@ _mesa_count_active_attribs(struct gl_shader_program *shProg) exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir; unsigned i = 0; - foreach_list(node, ir) { - const ir_variable *const var = ((ir_instruction *) node)->as_variable(); + foreach_in_list(ir_instruction, node, ir) { + const ir_variable *const var = node->as_variable(); - if (var == NULL - || var->mode != ir_var_in - || var->location == -1 - || var->location < VERT_ATTRIB_GENERIC0) - continue; + if (!is_active_attrib(var)) + continue; i++; } @@ -221,13 +315,12 @@ _mesa_longest_attribute_name_length(struct gl_shader_program *shProg) exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir; size_t longest = 0; - foreach_list(node, ir) { - const ir_variable *const var = ((ir_instruction *) node)->as_variable(); + foreach_in_list(ir_instruction, node, ir) { + const ir_variable *const var = node->as_variable(); if (var == NULL - || var->mode != ir_var_in - || var->location == -1 - || var->location < VERT_ATTRIB_GENERIC0) + || var->data.mode != ir_var_shader_in + || var->data.location == -1) continue; const size_t len = strlen(var->name); @@ -241,11 +334,18 @@ _mesa_longest_attribute_name_length(struct gl_shader_program *shProg) void GLAPIENTRY _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber, const GLchar *name) +{ + _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name); +} + +void GLAPIENTRY +_mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber, + GLuint index, const GLchar *name) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *const shProg = - _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocation"); + _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed"); if (!shProg) return; @@ -253,13 +353,22 @@ _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber, return; if (strncmp(name, "gl_", 3) == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBindFragDataLocation(illegal name)"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)"); + return; + } + + if (index > 1) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)"); + return; + } + + if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)"); return; } - if (colorNumber >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocation(index)"); + if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)"); return; } @@ -268,9 +377,124 @@ _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber, * between built-in attributes and user-defined attributes. */ shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name); - + shProg->FragDataIndexBindings->put(index, name); /* * Note that this binding won't go into effect until * glLinkProgram is called again. */ + +} + +GLint GLAPIENTRY +_mesa_GetFragDataIndex(GLuint program, const GLchar *name) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *const shProg = + _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex"); + + if (!shProg) { + return -1; + } + + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFragDataIndex(program not linked)"); + return -1; + } + + if (!name) + return -1; + + if (strncmp(name, "gl_", 3) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFragDataIndex(illegal name)"); + return -1; + } + + /* Not having a fragment shader is not an error. + */ + if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) + return -1; + + exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir; + foreach_in_list(ir_instruction, node, ir) { + const ir_variable *const var = node->as_variable(); + + /* The extra check against FRAG_RESULT_DATA0 is because + * glGetFragDataLocation cannot be used on "conventional" attributes. + * + * From page 95 of the OpenGL 3.0 spec: + * + * "If name is not an active attribute, if name is a conventional + * attribute, or if an error occurs, -1 will be returned." + */ + if (var == NULL + || var->data.mode != ir_var_shader_out + || var->data.location == -1 + || var->data.location < FRAG_RESULT_DATA0) + continue; + + if (get_matching_index(var, (const char *) name) >= 0) + return var->data.index; + } + + return -1; +} + +GLint GLAPIENTRY +_mesa_GetFragDataLocation(GLuint program, const GLchar *name) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *const shProg = + _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation"); + + if (!shProg) { + return -1; + } + + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFragDataLocation(program not linked)"); + return -1; + } + + if (!name) + return -1; + + if (strncmp(name, "gl_", 3) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFragDataLocation(illegal name)"); + return -1; + } + + /* Not having a fragment shader is not an error. + */ + if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) + return -1; + + exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir; + foreach_in_list(ir_instruction, node, ir) { + const ir_variable *const var = node->as_variable(); + + /* The extra check against FRAG_RESULT_DATA0 is because + * glGetFragDataLocation cannot be used on "conventional" attributes. + * + * From page 95 of the OpenGL 3.0 spec: + * + * "If name is not an active attribute, if name is a conventional + * attribute, or if an error occurs, -1 will be returned." + */ + if (var == NULL + || var->data.mode != ir_var_shader_out + || var->data.location == -1 + || var->data.location < FRAG_RESULT_DATA0) + continue; + + int index = get_matching_index(var, (const char *) name); + + if (index >= 0) + return var->data.location + index - FRAG_RESULT_DATA0; + } + + return -1; }