diff options
author | Bryan Cain <[email protected]> | 2013-02-15 09:46:50 -0600 |
---|---|---|
committer | Paul Berry <[email protected]> | 2013-08-01 20:20:45 -0700 |
commit | 2548092ad80156a407281a124f833a6a93fbf2f3 (patch) | |
tree | e839a3d1c14eb45dbfe1362f5a8f4ce9afeb0c74 /src | |
parent | 844bd71736dd59808e1ea4319800db042a7c4267 (diff) |
glsl: support compilation of geometry shaders
This commit adds all of the parsing and semantics for GLSL 150 style
geometry shaders.
v2 (Paul Berry <[email protected]>): 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 <[email protected]>): fix indexing order of 2D
arrays. Also, allow interpolation qualifiers in geometry shaders.
v4 (Paul Berry <[email protected]>): 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 <[email protected]>
v5 (Paul Berry <[email protected]>): 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 <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/glsl/ast_to_hir.cpp | 32 | ||||
-rw-r--r-- | src/glsl/ir.cpp | 21 | ||||
-rw-r--r-- | src/glsl/ir.h | 3 | ||||
-rw-r--r-- | src/glsl/linker.cpp | 54 | ||||
-rw-r--r-- | 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 */ |