From 0a18f160159b93c57943e5cb4d9d9a78a5b72996 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 20 Apr 2015 10:27:58 +1000 Subject: [PATCH] program_resource: add subroutine support (v3.1) This fleshes out the ARB_program_query support for the APIs that ARB_shader_subroutine introduces, leaving some TODOs for later addition. v2: reworked for lots of the ARB_program_interface_query entry points and tests v3: use common function to test for subroutine support v3.1: add tess, fix missing breaks Acked-by: Kenneth Graunke Signed-off-by: Dave Airlie --- src/mesa/main/program_resource.c | 100 +++++++++++++++++++++++------- src/mesa/main/shader_query.cpp | 101 +++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 22 deletions(-) diff --git a/src/mesa/main/program_resource.c b/src/mesa/main/program_resource.c index e77bb03e9a1..641ef22c1a6 100644 --- a/src/mesa/main/program_resource.c +++ b/src/mesa/main/program_resource.c @@ -28,10 +28,11 @@ #include "main/mtypes.h" #include "main/shaderapi.h" #include "main/shaderobj.h" +#include "main/context.h" #include "program_resource.h" - +#include "ir_uniform.h" static bool -supported_interface_enum(GLenum iface) +supported_interface_enum(struct gl_context *ctx, GLenum iface) { switch (iface) { case GL_UNIFORM: @@ -42,17 +43,21 @@ supported_interface_enum(GLenum iface) case GL_ATOMIC_COUNTER_BUFFER: 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_shader_subroutine(ctx); + case GL_GEOMETRY_SUBROUTINE: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + return _mesa_has_geometry_shaders(ctx) && _mesa_has_shader_subroutine(ctx); + case GL_COMPUTE_SUBROUTINE: case GL_COMPUTE_SUBROUTINE_UNIFORM: + return _mesa_has_compute_shaders(ctx) && _mesa_has_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_shader_subroutine(ctx); case GL_BUFFER_VARIABLE: case GL_SHADER_STORAGE_BLOCK: default: @@ -79,7 +84,7 @@ _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_enum_to_string(programInterface)); return; @@ -143,6 +148,31 @@ _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface, }; 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->NumProgramResourceList; i++) { + if (shProg->ProgramResourceList[i].Type == programInterface) { + struct gl_uniform_storage *uni = + (struct gl_uniform_storage *) + shProg->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)", @@ -206,6 +236,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,6 +252,18 @@ _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: @@ -260,7 +307,7 @@ _mesa_GetProgramResourceName(GLuint program, GLenum programInterface, return; if (programInterface == GL_ATOMIC_COUNTER_BUFFER || - !supported_interface_enum(programInterface)) { + !supported_interface_enum(ctx, programInterface)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)", _mesa_enum_to_string(programInterface)); return; @@ -366,24 +413,33 @@ _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface, case GL_PROGRAM_OUTPUT: break; - /* For reference valid cases requiring additional extension support: - * GL_ARB_shader_subroutine - * GL_ARB_tessellation_shader - * GL_ARB_compute_shader - */ 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: + if (!_mesa_has_shader_subroutine(ctx)) + goto fail; + break; + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_shader_subroutine(ctx)) + goto fail; + break; case GL_COMPUTE_SUBROUTINE_UNIFORM: - + if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_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_shader_subroutine(ctx)) + goto fail; + break; default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)", - _mesa_enum_to_string(programInterface), name); + 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; } /** diff --git a/src/mesa/main/shader_query.cpp b/src/mesa/main/shader_query.cpp index 59b9396f19b..3e52a098a67 100644 --- a/src/mesa/main/shader_query.cpp +++ b/src/mesa/main/shader_query.cpp @@ -61,6 +61,7 @@ DECL_RESOURCE_FUNC(UBO, gl_uniform_block); DECL_RESOURCE_FUNC(UNI, gl_uniform_storage); DECL_RESOURCE_FUNC(ATC, gl_active_atomic_buffer); DECL_RESOURCE_FUNC(XFB, gl_transform_feedback_varying_info); +DECL_RESOURCE_FUNC(SUB, gl_subroutine_function); void GLAPIENTRY _mesa_BindAttribLocation(GLhandleARB program, GLuint index, @@ -497,6 +498,20 @@ _mesa_program_resource_name(struct gl_program_resource *res) return RESOURCE_VAR(res)->name; case GL_UNIFORM: return RESOURCE_UNI(res)->name; + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + return RESOURCE_UNI(res)->name + MESA_SUBROUTINE_PREFIX_LEN; + case GL_VERTEX_SUBROUTINE: + case GL_GEOMETRY_SUBROUTINE: + case GL_FRAGMENT_SUBROUTINE: + case GL_COMPUTE_SUBROUTINE: + case GL_TESS_CONTROL_SUBROUTINE: + case GL_TESS_EVALUATION_SUBROUTINE: + return RESOURCE_SUB(res)->name; default: assert(!"support for resource type not implemented"); } @@ -515,7 +530,19 @@ _mesa_program_resource_array_size(struct gl_program_resource *res) case GL_PROGRAM_OUTPUT: return RESOURCE_VAR(res)->data.max_array_access; case GL_UNIFORM: + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: return RESOURCE_UNI(res)->array_elements; + case GL_VERTEX_SUBROUTINE: + case GL_GEOMETRY_SUBROUTINE: + case GL_FRAGMENT_SUBROUTINE: + case GL_COMPUTE_SUBROUTINE: + case GL_TESS_CONTROL_SUBROUTINE: + case GL_TESS_EVALUATION_SUBROUTINE: case GL_ATOMIC_COUNTER_BUFFER: case GL_UNIFORM_BLOCK: return 0; @@ -571,6 +598,18 @@ _mesa_program_resource_find_name(struct gl_shader_program *shProg, case GL_TRANSFORM_FEEDBACK_VARYING: case GL_UNIFORM_BLOCK: case GL_UNIFORM: + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + case GL_VERTEX_SUBROUTINE: + case GL_GEOMETRY_SUBROUTINE: + case GL_FRAGMENT_SUBROUTINE: + case GL_COMPUTE_SUBROUTINE: + case GL_TESS_CONTROL_SUBROUTINE: + case GL_TESS_EVALUATION_SUBROUTINE: if (strncmp(rname, name, baselen) == 0) { /* Basename match, check if array or struct. */ if (name[baselen] == '\0' || @@ -651,6 +690,18 @@ _mesa_program_resource_find_index(struct gl_shader_program *shProg, case GL_PROGRAM_INPUT: case GL_PROGRAM_OUTPUT: case GL_UNIFORM: + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + case GL_VERTEX_SUBROUTINE: + case GL_GEOMETRY_SUBROUTINE: + case GL_FRAGMENT_SUBROUTINE: + case GL_COMPUTE_SUBROUTINE: + case GL_TESS_CONTROL_SUBROUTINE: + case GL_TESS_EVALUATION_SUBROUTINE: if (++idx == (int) index) return res; break; @@ -740,6 +791,8 @@ program_resource_location(struct gl_shader_program *shProg, { unsigned index, offset; int array_index = -1; + long offset_ret; + const GLchar *base_name_end; if (res->Type == GL_PROGRAM_INPUT || res->Type == GL_PROGRAM_OUTPUT) { array_index = array_index_of_resource(res, name); @@ -780,6 +833,14 @@ program_resource_location(struct gl_shader_program *shProg, /* location in remap table + array element offset */ return RESOURCE_UNI(res)->remap_location + offset; + case GL_VERTEX_SUBROUTINE_UNIFORM: + case GL_GEOMETRY_SUBROUTINE_UNIFORM: + case GL_FRAGMENT_SUBROUTINE_UNIFORM: + case GL_COMPUTE_SUBROUTINE_UNIFORM: + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: + case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: + offset_ret = parse_program_resource_name(name, &base_name_end); + return RESOURCE_UNI(res)->remap_location + ((offset_ret != -1) ? offset_ret : 0); default: return -1; } @@ -1048,6 +1109,46 @@ _mesa_program_resource_prop(struct gl_shader_program *shProg, goto invalid_operation; *val = RESOURCE_VAR(res)->data.index; return 1; + + case GL_NUM_COMPATIBLE_SUBROUTINES: + if (res->Type != GL_VERTEX_SUBROUTINE_UNIFORM && + res->Type != GL_FRAGMENT_SUBROUTINE_UNIFORM && + res->Type != GL_GEOMETRY_SUBROUTINE_UNIFORM && + res->Type != GL_COMPUTE_SUBROUTINE_UNIFORM && + res->Type != GL_TESS_CONTROL_SUBROUTINE_UNIFORM && + res->Type != GL_TESS_EVALUATION_SUBROUTINE_UNIFORM) + goto invalid_operation; + *val = RESOURCE_UNI(res)->num_compatible_subroutines; + return 1; + case GL_COMPATIBLE_SUBROUTINES: { + const struct gl_uniform_storage *uni; + struct gl_shader *sh; + unsigned count, i; + int j; + + if (res->Type != GL_VERTEX_SUBROUTINE_UNIFORM && + res->Type != GL_FRAGMENT_SUBROUTINE_UNIFORM && + res->Type != GL_GEOMETRY_SUBROUTINE_UNIFORM && + res->Type != GL_COMPUTE_SUBROUTINE_UNIFORM && + res->Type != GL_TESS_CONTROL_SUBROUTINE_UNIFORM && + res->Type != GL_TESS_EVALUATION_SUBROUTINE_UNIFORM) + goto invalid_operation; + uni = RESOURCE_UNI(res); + + sh = shProg->_LinkedShaders[_mesa_shader_stage_from_subroutine_uniform(res->Type)]; + count = 0; + for (i = 0; i < sh->NumSubroutineFunctions; i++) { + struct gl_subroutine_function *fn = &sh->SubroutineFunctions[i]; + for (j = 0; j < fn->num_compat_types; j++) { + if (fn->types[j] == uni->type) { + val[count++] = i; + break; + } + } + } + return count; + } + /* GL_ARB_tessellation_shader */ case GL_IS_PER_PATCH: switch (res->Type) { case GL_PROGRAM_INPUT: -- 2.30.2