X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fprogram_resource.c;h=4eacdfb9e9aeda6c09170220df369828799f102c;hb=edd50828618ed2efe799013c2723d67c407d86b4;hp=a60b2e4e658b8e194dfb471cfd886b0e54b66713;hpb=2a5a0d19d67b2ccd7eee33a6f3bead66cc2d78ff;p=mesa.git diff --git a/src/mesa/main/program_resource.c b/src/mesa/main/program_resource.c index a60b2e4e658..4eacdfb9e9a 100644 --- a/src/mesa/main/program_resource.c +++ b/src/mesa/main/program_resource.c @@ -28,43 +28,74 @@ #include "main/mtypes.h" #include "main/shaderapi.h" #include "main/shaderobj.h" +#include "main/context.h" #include "program_resource.h" - +#include "compiler/glsl/ir_uniform.h" static bool -supported_interface_enum(GLenum iface) +supported_interface_enum(struct gl_context *ctx, GLenum iface) { switch (iface) { case GL_UNIFORM: case GL_UNIFORM_BLOCK: case GL_PROGRAM_INPUT: case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_BUFFER: case GL_TRANSFORM_FEEDBACK_VARYING: case GL_ATOMIC_COUNTER_BUFFER: + case GL_BUFFER_VARIABLE: + case GL_SHADER_STORAGE_BLOCK: return true; case GL_VERTEX_SUBROUTINE: - case GL_TESS_CONTROL_SUBROUTINE: - case GL_TESS_EVALUATION_SUBROUTINE: - case GL_GEOMETRY_SUBROUTINE: case GL_FRAGMENT_SUBROUTINE: - case GL_COMPUTE_SUBROUTINE: case GL_VERTEX_SUBROUTINE_UNIFORM: - case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: - case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: - case GL_GEOMETRY_SUBROUTINE_UNIFORM: case GL_FRAGMENT_SUBROUTINE_UNIFORM: + return _mesa_has_ARB_shader_subroutine(ctx); + case GL_GEOMETRY_SUBROUTINE: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + return _mesa_has_geometry_shaders(ctx) && _mesa_has_ARB_shader_subroutine(ctx); + case GL_COMPUTE_SUBROUTINE: case GL_COMPUTE_SUBROUTINE_UNIFORM: - case GL_BUFFER_VARIABLE: - case GL_SHADER_STORAGE_BLOCK: + return _mesa_has_compute_shaders(ctx) && _mesa_has_ARB_shader_subroutine(ctx); + case GL_TESS_CONTROL_SUBROUTINE: + case GL_TESS_EVALUATION_SUBROUTINE: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + return _mesa_has_tessellation(ctx) && _mesa_has_ARB_shader_subroutine(ctx); default: return false; } } +static struct gl_shader_program * +lookup_linked_program(GLuint program, const char *caller) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *prog = + _mesa_lookup_shader_program_err(ctx, program, caller); + + if (!prog) + return NULL; + + if (prog->data->LinkStatus == linking_failure) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", + caller); + return NULL; + } + return prog; +} + void GLAPIENTRY _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint *params) { GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_API) { + _mesa_debug(ctx, "glGetProgramInterfaceiv(%u, %s, %s, %p)\n", + program, _mesa_enum_to_string(programInterface), + _mesa_enum_to_string(pname), params); + } + unsigned i; struct gl_shader_program *shProg = _mesa_lookup_shader_program_err(ctx, program, @@ -79,74 +110,128 @@ _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface, } /* Validate interface. */ - if (!supported_interface_enum(programInterface)) { + if (!supported_interface_enum(ctx, programInterface)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s)", - _mesa_lookup_enum_by_nr(programInterface)); + _mesa_enum_to_string(programInterface)); return; } /* Validate pname against interface. */ switch(pname) { case GL_ACTIVE_RESOURCES: - for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) - if (shProg->ProgramResourceList[i].Type == programInterface) + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) + if (shProg->data->ProgramResourceList[i].Type == programInterface) (*params)++; break; case GL_MAX_NAME_LENGTH: - if (programInterface == GL_ATOMIC_COUNTER_BUFFER) { + if (programInterface == GL_ATOMIC_COUNTER_BUFFER || + programInterface == GL_TRANSFORM_FEEDBACK_BUFFER) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s pname %s)", - _mesa_lookup_enum_by_nr(programInterface), - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(programInterface), + _mesa_enum_to_string(pname)); return; } /* Name length consists of base name, 3 additional chars '[0]' if * resource is an array and finally 1 char for string terminator. */ - for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) { - if (shProg->ProgramResourceList[i].Type != programInterface) + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type != programInterface) continue; - const char *name = - _mesa_program_resource_name(&shProg->ProgramResourceList[i]); - unsigned array_size = - _mesa_program_resource_array_size(&shProg->ProgramResourceList[i]); - *params = MAX2(*params, strlen(name) + (array_size ? 3 : 0) + 1); + unsigned len = + _mesa_program_resource_name_len(&shProg->data->ProgramResourceList[i]); + *params = MAX2(*params, len + 1); } break; case GL_MAX_NUM_ACTIVE_VARIABLES: switch (programInterface) { case GL_UNIFORM_BLOCK: - for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) { - if (shProg->ProgramResourceList[i].Type == programInterface) { + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { struct gl_uniform_block *block = (struct gl_uniform_block *) - shProg->ProgramResourceList[i].Data; + shProg->data->ProgramResourceList[i].Data; *params = MAX2(*params, block->NumUniforms); } } break; + case GL_SHADER_STORAGE_BLOCK: + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { + struct gl_uniform_block *block = + (struct gl_uniform_block *) + shProg->data->ProgramResourceList[i].Data; + GLint block_params = 0; + for (unsigned j = 0; j < block->NumUniforms; j++) { + const char *iname = block->Uniforms[j].IndexName; + struct gl_program_resource *uni = + _mesa_program_resource_find_name(shProg, GL_BUFFER_VARIABLE, + iname, NULL); + if (!uni) + continue; + block_params++; + } + *params = MAX2(*params, block_params); + } + } + break; case GL_ATOMIC_COUNTER_BUFFER: - for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) { - if (shProg->ProgramResourceList[i].Type == programInterface) { + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { struct gl_active_atomic_buffer *buffer = (struct gl_active_atomic_buffer *) - shProg->ProgramResourceList[i].Data; + shProg->data->ProgramResourceList[i].Data; *params = MAX2(*params, buffer->NumUniforms); } } break; + case GL_TRANSFORM_FEEDBACK_BUFFER: + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { + struct gl_transform_feedback_buffer *buffer = + (struct gl_transform_feedback_buffer *) + shProg->data->ProgramResourceList[i].Data; + *params = MAX2(*params, buffer->NumVaryings); + } + } + break; default: _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s pname %s)", - _mesa_lookup_enum_by_nr(programInterface), - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(programInterface), + _mesa_enum_to_string(pname)); }; break; case GL_MAX_NUM_COMPATIBLE_SUBROUTINES: + switch (programInterface) { + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: { + for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { + if (shProg->data->ProgramResourceList[i].Type == programInterface) { + struct gl_uniform_storage *uni = + (struct gl_uniform_storage *) + shProg->data->ProgramResourceList[i].Data; + *params = MAX2(*params, uni->num_compatible_subroutines); + } + } + break; + } + + default: + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetProgramInterfaceiv(%s pname %s)", + _mesa_enum_to_string(programInterface), + _mesa_enum_to_string(pname)); + } + break; default: _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(pname %s)", - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(pname)); } } @@ -173,32 +258,18 @@ is_xfb_marker(const char *str) return false; } -/** - * Checks if given name index is legal for GetProgramResourceIndex, - * check is written to be compatible with GL_ARB_array_of_arrays. - */ -static bool -valid_program_resource_index_name(const GLchar *name) -{ - const char *array = strstr(name, "["); - const char *close = strrchr(name, ']'); - - /* Not array, no need for the check. */ - if (!array) - return true; - - /* Last array index has to be zero. */ - if (!close || *--close != '0') - return false; - - return true; -} - GLuint GLAPIENTRY _mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name) { GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_API) { + _mesa_debug(ctx, "glGetProgramResourceIndex(%u, %s, %s)\n", + program, _mesa_enum_to_string(programInterface), name); + } + + unsigned array_index = 0; struct gl_program_resource *res; struct gl_shader_program *shProg = _mesa_lookup_shader_program_err(ctx, program, @@ -206,6 +277,11 @@ _mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface, if (!shProg || !name) return GL_INVALID_INDEX; + if (!supported_interface_enum(ctx, programInterface)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)", + _mesa_enum_to_string(programInterface)); + return GL_INVALID_INDEX; + } /* * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX * should be returned when querying the index assigned to the special names @@ -217,24 +293,36 @@ _mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface, return GL_INVALID_INDEX; switch (programInterface) { + case GL_TESS_CONTROL_SUBROUTINE: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_VERTEX_SUBROUTINE: + case GL_FRAGMENT_SUBROUTINE: + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: case GL_PROGRAM_INPUT: case GL_PROGRAM_OUTPUT: case GL_UNIFORM: - case GL_UNIFORM_BLOCK: + case GL_BUFFER_VARIABLE: case GL_TRANSFORM_FEEDBACK_VARYING: - /* Validate name syntax for arrays. */ - if (!valid_program_resource_index_name(name)) - return GL_INVALID_INDEX; - - res = _mesa_program_resource_find_name(shProg, programInterface, name); - if (!res) + case GL_UNIFORM_BLOCK: + case GL_SHADER_STORAGE_BLOCK: + res = _mesa_program_resource_find_name(shProg, programInterface, name, + &array_index); + if (!res || array_index > 0) return GL_INVALID_INDEX; return _mesa_program_resource_index(shProg, res); case GL_ATOMIC_COUNTER_BUFFER: + case GL_TRANSFORM_FEEDBACK_BUFFER: default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)", - _mesa_lookup_enum_by_nr(programInterface)); + _mesa_enum_to_string(programInterface)); } return GL_INVALID_INDEX; @@ -246,23 +334,25 @@ _mesa_GetProgramResourceName(GLuint program, GLenum programInterface, GLchar *name) { GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_API) { + _mesa_debug(ctx, "glGetProgramResourceName(%u, %s, %u, %d, %p, %p)\n", + program, _mesa_enum_to_string(programInterface), index, + bufSize, length, name); + } + struct gl_shader_program *shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceName"); - /* Set user friendly return values in case of errors. */ - if (name) - *name = '\0'; - if (length) - *length = 0; - if (!shProg || !name) return; if (programInterface == GL_ATOMIC_COUNTER_BUFFER || - !supported_interface_enum(programInterface)) { + programInterface == GL_TRANSFORM_FEEDBACK_BUFFER || + !supported_interface_enum(ctx, programInterface)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)", - _mesa_lookup_enum_by_nr(programInterface)); + _mesa_enum_to_string(programInterface)); return; } @@ -276,18 +366,118 @@ _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params) { + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_API) { + _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n", + program, _mesa_enum_to_string(programInterface), index, + propCount, props, bufSize, length, params); + } + + struct gl_shader_program *shProg = + _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv"); + + if (!shProg || !params) + return; + + /* The error INVALID_VALUE is generated if is zero. + * Note that we check < 0 here because it makes sense to bail early. + */ + if (propCount <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetProgramResourceiv(propCount <= 0)"); + return; + } + + _mesa_get_program_resourceiv(shProg, programInterface, index, + propCount, props, bufSize, length, params); } GLint GLAPIENTRY _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar *name) { + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_API) { + _mesa_debug(ctx, "glGetProgramResourceLocation(%u, %s, %s)\n", + program, _mesa_enum_to_string(programInterface), name); + } + + struct gl_shader_program *shProg = + lookup_linked_program(program, "glGetProgramResourceLocation"); + + if (!shProg || !name) + return -1; + + /* Validate programInterface. */ + switch (programInterface) { + case GL_UNIFORM: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + break; + + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + if (!_mesa_has_ARB_shader_subroutine(ctx)) + goto fail; + break; + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx)) + goto fail; + break; + case GL_COMPUTE_SUBROUTINE_UNIFORM: + if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx)) + goto fail; + break; + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + if (!_mesa_has_tessellation(ctx) || !_mesa_has_ARB_shader_subroutine(ctx)) + goto fail; + break; + default: + goto fail; + } + + return _mesa_program_resource_location(shProg, programInterface, name); +fail: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)", + _mesa_enum_to_string(programInterface), name); return -1; } +/** + * Returns output index for dual source blending. + */ GLint GLAPIENTRY _mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar *name) { - return -1; + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_API) { + _mesa_debug(ctx, "glGetProgramResourceLocationIndex(%u, %s, %s)\n", + program, _mesa_enum_to_string(programInterface), name); + } + + struct gl_shader_program *shProg = + lookup_linked_program(program, "glGetProgramResourceLocationIndex"); + + if (!shProg || !name) + return -1; + + /* From the GL_ARB_program_interface_query spec: + * + * "For GetProgramResourceLocationIndex, must be + * PROGRAM_OUTPUT." + */ + if (programInterface != GL_PROGRAM_OUTPUT) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetProgramResourceLocationIndex(%s)", + _mesa_enum_to_string(programInterface)); + return -1; + } + + return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT, + name); }