From 2548092ad80156a407281a124f833a6a93fbf2f3 Mon Sep 17 00:00:00 2001 From: Bryan Cain Date: Fri, 15 Feb 2013 09:46:50 -0600 Subject: [PATCH] glsl: support compilation of geometry shaders This commit adds all of the parsing and semantics for GLSL 150 style geometry shaders. v2 (Paul Berry ): Add a few missing calls to get_pipeline_stage(). Fix some signed/unsigned comparison warnings. Fix handling of NULL consumer in assign_varying_locations(). v3 (Bryan Cain ): fix indexing order of 2D arrays. Also, allow interpolation qualifiers in geometry shaders. v4 (Paul Berry ): Eliminate get_pipeline_stage()--it is no longer needed thanks to 030ca23 (mesa: renumber shader indices according to their placement in pipeline). Remove 2D stuff. Move vertices_per_prim() to ir.h, so that it will be accessible from outside the linker. Remove inject_num_vertices_visitor. Rework for GLSL 1.50. Reviewed-by: Ian Romanick v5 (Paul Berry ): Split out do_set_program_inouts() argument refactoring to a separate patch. Move geom_array_resizing_visitor to later in the series. Reviewed-by: Kenneth Graunke --- src/glsl/ast_to_hir.cpp | 32 +++++++++++++++++++----- src/glsl/ir.cpp | 21 ++++++++++++++++ src/glsl/ir.h | 3 +++ src/glsl/linker.cpp | 54 ++++++++++++++++++++++++++++++++++++++--- src/mesa/main/mtypes.h | 4 ++- 5 files changed, 103 insertions(+), 11 deletions(-) diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index 598da92f8fb..4b5645221a4 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -2056,12 +2056,12 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, var->interpolation = INTERP_QUALIFIER_NONE; if (var->interpolation != INTERP_QUALIFIER_NONE && - !(state->target == vertex_shader && var->mode == ir_var_shader_out) && - !(state->target == fragment_shader && var->mode == ir_var_shader_in)) { + ((state->target == vertex_shader && var->mode == ir_var_shader_in) || + (state->target == fragment_shader && var->mode == ir_var_shader_out))) { _mesa_glsl_error(loc, state, - "interpolation qualifier `%s' can only be applied to " - "vertex shader outputs and fragment shader inputs", - var->interpolation_string()); + "interpolation qualifier `%s' cannot be applied to " + "vertex shader inputs or fragment shader outputs", + var->interpolation_string()); } var->pixel_center_integer = qual->flags.q.pixel_center_integer; @@ -2662,6 +2662,26 @@ ast_declarator_list::hir(exec_list *instructions, var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto); + /* The 'varying in' and 'varying out' qualifiers can only be used with + * ARB_geometry_shader4 and EXT_geometry_shader4, which we don't support + * yet. + */ + if (this->type->qualifier.flags.q.varying) { + if (this->type->qualifier.flags.q.in) { + _mesa_glsl_error(& loc, state, + "`varying in' qualifier in declaration of " + "`%s' only valid for geometry shaders using " + "ARB_geometry_shader4 or EXT_geometry_shader4", + decl->identifier); + } else if (this->type->qualifier.flags.q.out) { + _mesa_glsl_error(& loc, state, + "`varying out' qualifier in declaration of " + "`%s' only valid for geometry shaders using " + "ARB_geometry_shader4 or EXT_geometry_shader4", + decl->identifier); + } + } + /* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification; * * "Global variables can only use the qualifiers const, @@ -2906,7 +2926,7 @@ ast_declarator_list::hir(exec_list *instructions, } break; default: - assert(0); + break; } } diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index dad58deeb97..99dceacf85f 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -1778,3 +1778,24 @@ ir_rvalue::as_rvalue_to_saturate() return NULL; } + + +unsigned +vertices_per_prim(GLenum prim) +{ + switch (prim) { + case GL_POINTS: + return 1; + case GL_LINES: + return 2; + case GL_TRIANGLES: + return 3; + case GL_LINES_ADJACENCY: + return 4; + case GL_TRIANGLES_ADJACENCY: + return 6; + default: + assert(!"Bad primitive"); + return 3; + } +} diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 4cb1202e65b..62e3b27ca92 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -2128,4 +2128,7 @@ extern void _mesa_print_ir(struct exec_list *instructions, } /* extern "C" */ #endif +unsigned +vertices_per_prim(GLenum prim); + #endif /* IR_H */ diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index d7ea740dbf0..f25dca2109d 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -73,11 +73,14 @@ #include "linker.h" #include "link_varyings.h" #include "ir_optimization.h" +#include "ir_rvalue_visitor.h" extern "C" { #include "main/shaderobj.h" } +void linker_error(gl_shader_program *, const char *, ...); + /** * Visitor that determines whether or not a variable is ever written. */ @@ -402,6 +405,24 @@ validate_fragment_shader_executable(struct gl_shader_program *prog, } } +/** + * Verify that a geometry shader executable meets all semantic requirements + * + * Also sets prog->Geom.VerticesIn as a side effect. + * + * \param shader Geometry shader executable to be verified + */ +void +validate_geometry_shader_executable(struct gl_shader_program *prog, + struct gl_shader *shader) +{ + if (shader == NULL) + return; + + unsigned num_vertices = vertices_per_prim(prog->Geom.InputType); + prog->Geom.VerticesIn = num_vertices; +} + /** * Generate a string describing the mode of a variable @@ -1613,11 +1634,15 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) unsigned num_vert_shaders = 0; struct gl_shader **frag_shader_list; unsigned num_frag_shaders = 0; + struct gl_shader **geom_shader_list; + unsigned num_geom_shaders = 0; vert_shader_list = (struct gl_shader **) calloc(prog->NumShaders, sizeof(struct gl_shader *)); frag_shader_list = (struct gl_shader **) calloc(prog->NumShaders, sizeof(struct gl_shader *)); + geom_shader_list = (struct gl_shader **) + calloc(prog->NumShaders, sizeof(struct gl_shader *)); unsigned min_version = UINT_MAX; unsigned max_version = 0; @@ -1643,8 +1668,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) num_frag_shaders++; break; case GL_GEOMETRY_SHADER: - /* FINISHME: Support geometry shaders. */ - assert(prog->Shaders[i]->Type != GL_GEOMETRY_SHADER); + geom_shader_list[num_geom_shaders] = prog->Shaders[i]; + num_geom_shaders++; break; } } @@ -1706,6 +1731,22 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) sh); } + if (num_geom_shaders > 0) { + gl_shader *const sh = + link_intrastage_shaders(mem_ctx, ctx, prog, geom_shader_list, + num_geom_shaders); + + if (!prog->LinkStatus) + goto done; + + validate_geometry_shader_executable(prog, sh); + if (!prog->LinkStatus) + goto done; + + _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_GEOMETRY], + sh); + } + /* Here begins the inter-stage linking phase. Some initial validation is * performed, then locations are assigned for uniforms, attributes, and * varyings. @@ -1792,7 +1833,11 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) prog->_LinkedShaders[MESA_SHADER_VERTEX], VERT_ATTRIB_GENERIC0, VARYING_SLOT_VAR0); } - /* FINISHME: Geometry shaders not implemented yet */ + if (prog->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) { + link_invalidate_variable_locations( + prog->_LinkedShaders[MESA_SHADER_GEOMETRY], + VARYING_SLOT_VAR0, VARYING_SLOT_VAR0); + } if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL) { link_invalidate_variable_locations( prog->_LinkedShaders[MESA_SHADER_FRAGMENT], @@ -1826,7 +1871,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) * non-zero, but the program object has no vertex or geometry * shader; */ - if (first >= MESA_SHADER_FRAGMENT) { + if (first == MESA_SHADER_FRAGMENT) { linker_error(prog, "Transform feedback varyings specified, but " "no vertex or geometry shader is present."); goto done; @@ -1950,6 +1995,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) done: free(vert_shader_list); free(frag_shader_list); + free(geom_shader_list); for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { if (prog->_LinkedShaders[i] == NULL) diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 91c3abf683e..c78fe855f6c 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1852,7 +1852,7 @@ struct gl_program GLuint Id; GLubyte *String; /**< Null-terminated program text */ GLint RefCount; - GLenum Target; /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB */ + GLenum Target; /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB, GL_GEOMETRY_PROGRAM_NV */ GLenum Format; /**< String encoding format */ struct prog_instruction *Instructions; @@ -1919,6 +1919,7 @@ struct gl_geometry_program { struct gl_program Base; /**< base class */ + GLint VerticesIn; GLint VerticesOut; GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB, GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */ @@ -2321,6 +2322,7 @@ struct gl_shader_program /** Geometry shader state - copied into gl_geometry_program at link time */ struct { + GLint VerticesIn; GLint VerticesOut; GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB, GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */ -- 2.30.2