diff options
author | Paul Berry <[email protected]> | 2013-04-10 16:32:40 -0700 |
---|---|---|
committer | Paul Berry <[email protected]> | 2013-08-01 20:23:12 -0700 |
commit | 72219acf6bd415063f93ce8b9be954a225be4b49 (patch) | |
tree | e69130c17ba328a815ec918853bbb6af2857d03f /src/glsl | |
parent | f2ecc8482673c8aec9c3f009fce6c072d8c6f20a (diff) |
glsl: Properly pack GS output varyings
In geometry shaders, outputs are consumed at the time of a call to
EmitVertex() (as opposed to all other shader types, where outputs are
consumed when the shader exits). Therefore, when packing geometry
shader output varyings using lower_packed_varyings, we need to do the
packing at the time of the EmitVertex() call.
This patch accomplishes that by adding a new visitor class,
lower_packed_varyings_gs_splicer, which is responsible for splicing
the varying packing code into place wherever EmitVertex() is found.
Reviewed-by: Ian Romanick <[email protected]>
Diffstat (limited to 'src/glsl')
-rw-r--r-- | src/glsl/lower_packed_varyings.cpp | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/src/glsl/lower_packed_varyings.cpp b/src/glsl/lower_packed_varyings.cpp index 4ab016db05f..31a50bba59f 100644 --- a/src/glsl/lower_packed_varyings.cpp +++ b/src/glsl/lower_packed_varyings.cpp @@ -604,6 +604,51 @@ lower_packed_varyings_visitor::needs_lowering(ir_variable *var) return true; } + +/** + * Visitor that splices varying packing code before every use of EmitVertex() + * in a geometry shader. + */ +class lower_packed_varyings_gs_splicer : public ir_hierarchical_visitor +{ +public: + explicit lower_packed_varyings_gs_splicer(void *mem_ctx, + const exec_list *instructions); + + virtual ir_visitor_status visit(ir_emit_vertex *ev); + +private: + /** + * Memory context used to allocate new instructions for the shader. + */ + void * const mem_ctx; + + /** + * Instructions that should be spliced into place before each EmitVertex() + * call. + */ + const exec_list *instructions; +}; + + +lower_packed_varyings_gs_splicer::lower_packed_varyings_gs_splicer( + void *mem_ctx, const exec_list *instructions) + : mem_ctx(mem_ctx), instructions(instructions) +{ +} + + +ir_visitor_status +lower_packed_varyings_gs_splicer::visit(ir_emit_vertex *ev) +{ + foreach_list(node, this->instructions) { + ir_instruction *ir = (ir_instruction *) node; + ev->insert_before(ir->clone(this->mem_ctx, NULL)); + } + return visit_continue; +} + + void lower_packed_varyings(void *mem_ctx, unsigned location_base, unsigned locations_used, ir_variable_mode mode, @@ -620,8 +665,18 @@ lower_packed_varyings(void *mem_ctx, unsigned location_base, gs_input_vertices, &new_instructions); visitor.run(instructions); if (mode == ir_var_shader_out) { - /* Shader outputs need to be lowered at the end of main() */ - main_func_sig->body.append_list(&new_instructions); + if (shader->Type == GL_GEOMETRY_SHADER) { + /* For geometry shaders, outputs need to be lowered before each call + * to EmitVertex() + */ + lower_packed_varyings_gs_splicer splicer(mem_ctx, &new_instructions); + splicer.run(instructions); + } else { + /* For other shader types, outputs need to be lowered at the end of + * main() + */ + main_func_sig->body.append_list(&new_instructions); + } } else { /* Shader inputs need to be lowered at the beginning of main() */ main_func_sig->body.head->insert_before(&new_instructions); |