summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Berry <[email protected]>2013-04-10 16:32:40 -0700
committerPaul Berry <[email protected]>2013-08-01 20:23:12 -0700
commit72219acf6bd415063f93ce8b9be954a225be4b49 (patch)
treee69130c17ba328a815ec918853bbb6af2857d03f
parentf2ecc8482673c8aec9c3f009fce6c072d8c6f20a (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]>
-rw-r--r--src/glsl/lower_packed_varyings.cpp59
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);