aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl/lower_packed_varyings.cpp
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2013-08-19 09:03:18 +0200
committermarha <marha@users.sourceforge.net>2013-08-19 09:03:18 +0200
commit854ec4da20ddff9b830be0a7d5b81d8cb4774132 (patch)
tree223425d84b5ea3727f74546c92dee8b03c074158 /mesalib/src/glsl/lower_packed_varyings.cpp
parent0659c77949b38440a2a9ba67e1ee9cacef1f3a7f (diff)
downloadvcxsrv-854ec4da20ddff9b830be0a7d5b81d8cb4774132.tar.gz
vcxsrv-854ec4da20ddff9b830be0a7d5b81d8cb4774132.tar.bz2
vcxsrv-854ec4da20ddff9b830be0a7d5b81d8cb4774132.zip
fontconfig libX11 libXdmcp libxcb xkeyboard-config mesa pixman xserver git update 19 aug 2013
xserver commit fe7463b8ce0de301c2f82b108c93963424f77219 libxcb commit 5648ddd2b97068f549268284129a438a6845e14c libxcb/xcb-proto commit 56a82005ac388fcb7a4d1c82e07c7e72eaf69a32 xkeyboard-config commit 87c865aee1844b2cc6b1a5a208116dd095f4d76a libX11 commit 9b291044a240e5b9b031ed814e0c84e53a1c3084 libXdmcp commit 66514a4af7eaa47e8718434356d7efce95e570cf libXext commit 7378d4bdbd33ed49ed6cfa5c4f73d7527982aab4 libfontenc commit 3acba630d8b57084f7e92c15732408711ed5137a libXinerama commit 6e1d1dc328ba8162bba2f4694e7f3c706a1491ff libXau commit 899790011304c4029e15abf410e49ce7cec17e0a xkbcomp commit 0ebdf47fd4bc434ac3d2339544c022a869510738 pixman commit 3518a0dafa63098d41e466f73d105b7e3e4b12de xextproto commit f27fcc99d1cf935cc289933326f7d3baacd5107a randrproto commit ca7cc541c2e43e6c784df19b4583ac35829d2f72 glproto commit 8e3407e02980d088e20041e79bdcdd3737e7827e mkfontscale commit f48de13423c7300f4da9f61993b624426b38ddc0 xwininfo commit ba0d1b0da21d2dbdd81098ed5778f3792b472e13 libXft commit c5e760a239afc62a1c75e0509868e35957c8df52 libXmu commit d5dac08d65c4865f311cb62c161dbb1300eecd11 libxtrans commit f6a161f2a003f4da0a2e414b4faa0ee0de0c01f0 fontconfig commit 084cf7c44e985dd48c088d921ad0d9a43b0b00b4 mesa commit d13003f544417db6de44c65a0c118bd2b189458a
Diffstat (limited to 'mesalib/src/glsl/lower_packed_varyings.cpp')
-rw-r--r--mesalib/src/glsl/lower_packed_varyings.cpp291
1 files changed, 255 insertions, 36 deletions
diff --git a/mesalib/src/glsl/lower_packed_varyings.cpp b/mesalib/src/glsl/lower_packed_varyings.cpp
index cdf2289b4..31a50bba5 100644
--- a/mesalib/src/glsl/lower_packed_varyings.cpp
+++ b/mesalib/src/glsl/lower_packed_varyings.cpp
@@ -74,6 +74,74 @@
* This lowering pass also handles varyings whose type is a struct or an array
* of struct. Structs are packed in order and with no gaps, so there may be a
* performance penalty due to structure elements being double-parked.
+ *
+ * Lowering of geometry shader inputs is slightly more complex, since geometry
+ * inputs are always arrays, so we need to lower arrays to arrays. For
+ * example, the following input:
+ *
+ * in struct Foo {
+ * float f;
+ * vec3 v;
+ * vec2 a[2];
+ * } arr[3]; // location=4, location_frac=0
+ *
+ * Would get lowered like this if it occurred in a fragment shader:
+ *
+ * struct Foo {
+ * float f;
+ * vec3 v;
+ * vec2 a[2];
+ * } arr[3];
+ * in vec4 packed4; // location=4, location_frac=0
+ * in vec4 packed5; // location=5, location_frac=0
+ * in vec4 packed6; // location=6, location_frac=0
+ * in vec4 packed7; // location=7, location_frac=0
+ * in vec4 packed8; // location=8, location_frac=0
+ * in vec4 packed9; // location=9, location_frac=0
+ *
+ * main()
+ * {
+ * arr[0].f = packed4.x;
+ * arr[0].v = packed4.yzw;
+ * arr[0].a[0] = packed5.xy;
+ * arr[0].a[1] = packed5.zw;
+ * arr[1].f = packed6.x;
+ * arr[1].v = packed6.yzw;
+ * arr[1].a[0] = packed7.xy;
+ * arr[1].a[1] = packed7.zw;
+ * arr[2].f = packed8.x;
+ * arr[2].v = packed8.yzw;
+ * arr[2].a[0] = packed9.xy;
+ * arr[2].a[1] = packed9.zw;
+ * ...
+ * }
+ *
+ * But it would get lowered like this if it occurred in a geometry shader:
+ *
+ * struct Foo {
+ * float f;
+ * vec3 v;
+ * vec2 a[2];
+ * } arr[3];
+ * in vec4 packed4[3]; // location=4, location_frac=0
+ * in vec4 packed5[3]; // location=5, location_frac=0
+ *
+ * main()
+ * {
+ * arr[0].f = packed4[0].x;
+ * arr[0].v = packed4[0].yzw;
+ * arr[0].a[0] = packed5[0].xy;
+ * arr[0].a[1] = packed5[0].zw;
+ * arr[1].f = packed4[1].x;
+ * arr[1].v = packed4[1].yzw;
+ * arr[1].a[0] = packed5[1].xy;
+ * arr[1].a[1] = packed5[1].zw;
+ * arr[2].f = packed4[2].x;
+ * arr[2].v = packed4[2].yzw;
+ * arr[2].a[0] = packed5[2].xy;
+ * arr[2].a[1] = packed5[2].zw;
+ * ...
+ * }
*/
#include "glsl_symbol_table.h"
@@ -93,7 +161,8 @@ public:
lower_packed_varyings_visitor(void *mem_ctx, unsigned location_base,
unsigned locations_used,
ir_variable_mode mode,
- exec_list *main_instructions);
+ unsigned gs_input_vertices,
+ exec_list *out_instructions);
void run(exec_list *instructions);
@@ -101,13 +170,16 @@ private:
ir_assignment *bitwise_assign_pack(ir_rvalue *lhs, ir_rvalue *rhs);
ir_assignment *bitwise_assign_unpack(ir_rvalue *lhs, ir_rvalue *rhs);
unsigned lower_rvalue(ir_rvalue *rvalue, unsigned fine_location,
- ir_variable *unpacked_var, const char *name);
+ ir_variable *unpacked_var, const char *name,
+ bool gs_input_toplevel, unsigned vertex_index);
unsigned lower_arraylike(ir_rvalue *rvalue, unsigned array_size,
unsigned fine_location,
- ir_variable *unpacked_var, const char *name);
- ir_variable *get_packed_varying(unsigned location,
- ir_variable *unpacked_var,
- const char *name);
+ ir_variable *unpacked_var, const char *name,
+ bool gs_input_toplevel, unsigned vertex_index);
+ ir_dereference *get_packed_varying_deref(unsigned location,
+ ir_variable *unpacked_var,
+ const char *name,
+ unsigned vertex_index);
bool needs_lowering(ir_variable *var);
/**
@@ -145,15 +217,23 @@ private:
const ir_variable_mode mode;
/**
- * List of instructions corresponding to the main() function. This is
- * where we add instructions to pack or unpack the varyings.
+ * If we are currently lowering geometry shader inputs, the number of input
+ * vertices the geometry shader accepts. Otherwise zero.
*/
- exec_list *main_instructions;
+ const unsigned gs_input_vertices;
+
+ /**
+ * Exec list into which the visitor should insert the packing instructions.
+ * Caller provides this list; it should insert the instructions into the
+ * appropriate place in the shader once the visitor has finished running.
+ */
+ exec_list *out_instructions;
};
lower_packed_varyings_visitor::lower_packed_varyings_visitor(
void *mem_ctx, unsigned location_base, unsigned locations_used,
- ir_variable_mode mode, exec_list *main_instructions)
+ ir_variable_mode mode, unsigned gs_input_vertices,
+ exec_list *out_instructions)
: mem_ctx(mem_ctx),
location_base(location_base),
locations_used(locations_used),
@@ -161,7 +241,8 @@ lower_packed_varyings_visitor::lower_packed_varyings_visitor(
rzalloc_array_size(mem_ctx, sizeof(*packed_varyings),
locations_used)),
mode(mode),
- main_instructions(main_instructions)
+ gs_input_vertices(gs_input_vertices),
+ out_instructions(out_instructions)
{
}
@@ -195,7 +276,7 @@ lower_packed_varyings_visitor::run(exec_list *instructions)
/* Recursively pack or unpack it. */
this->lower_rvalue(deref, var->location * 4 + var->location_frac, var,
- var->name);
+ var->name, this->gs_input_vertices != 0, 0);
}
}
@@ -277,6 +358,15 @@ lower_packed_varyings_visitor::bitwise_assign_unpack(ir_rvalue *lhs,
* in multiples of a float, rather than multiples of a vec4 as is used
* elsewhere in Mesa.
*
+ * \param gs_input_toplevel should be set to true if we are lowering geometry
+ * shader inputs, and we are currently lowering the whole input variable
+ * (i.e. we are lowering the array whose index selects the vertex).
+ *
+ * \param vertex_index: if we are lowering geometry shader inputs, and the
+ * level of the array that we are currently lowering is *not* the top level,
+ * then this indicates which vertex we are currently lowering. Otherwise it
+ * is ignored.
+ *
* \return the location where the next constituent vector (after this one)
* should be packed.
*/
@@ -284,8 +374,15 @@ unsigned
lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
unsigned fine_location,
ir_variable *unpacked_var,
- const char *name)
+ const char *name,
+ bool gs_input_toplevel,
+ unsigned vertex_index)
{
+ /* When gs_input_toplevel is set, we should be looking at a geometry shader
+ * input array.
+ */
+ assert(!gs_input_toplevel || rvalue->type->is_array());
+
if (rvalue->type->is_record()) {
for (unsigned i = 0; i < rvalue->type->length; i++) {
if (i != 0)
@@ -296,7 +393,8 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
char *deref_name
= ralloc_asprintf(this->mem_ctx, "%s.%s", name, field_name);
fine_location = this->lower_rvalue(dereference_record, fine_location,
- unpacked_var, deref_name);
+ unpacked_var, deref_name, false,
+ vertex_index);
}
return fine_location;
} else if (rvalue->type->is_array()) {
@@ -304,13 +402,15 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
* sequence.
*/
return this->lower_arraylike(rvalue, rvalue->type->array_size(),
- fine_location, unpacked_var, name);
+ fine_location, unpacked_var, name,
+ gs_input_toplevel, vertex_index);
} else if (rvalue->type->is_matrix()) {
/* Matrices are packed/unpacked by considering each column vector in
* sequence.
*/
return this->lower_arraylike(rvalue, rvalue->type->matrix_columns,
- fine_location, unpacked_var, name);
+ fine_location, unpacked_var, name,
+ false, vertex_index);
} else if (rvalue->type->vector_elements + fine_location % 4 > 4) {
/* This vector is going to be "double parked" across two varying slots,
* so handle it as two separate assignments.
@@ -340,9 +440,10 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
char *right_name
= ralloc_asprintf(this->mem_ctx, "%s.%s", name, right_swizzle_name);
fine_location = this->lower_rvalue(left_swizzle, fine_location,
- unpacked_var, left_name);
+ unpacked_var, left_name, false,
+ vertex_index);
return this->lower_rvalue(right_swizzle, fine_location, unpacked_var,
- right_name);
+ right_name, false, vertex_index);
} else {
/* No special handling is necessary; pack the rvalue into the
* varying.
@@ -353,19 +454,19 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
unsigned location_frac = fine_location % 4;
for (unsigned i = 0; i < components; ++i)
swizzle_values[i] = i + location_frac;
- ir_dereference_variable *packed_deref = new(this->mem_ctx)
- ir_dereference_variable(this->get_packed_varying(location,
- unpacked_var, name));
+ ir_dereference *packed_deref =
+ this->get_packed_varying_deref(location, unpacked_var, name,
+ vertex_index);
ir_swizzle *swizzle = new(this->mem_ctx)
ir_swizzle(packed_deref, swizzle_values, components);
if (this->mode == ir_var_shader_out) {
ir_assignment *assignment
= this->bitwise_assign_pack(swizzle, rvalue);
- this->main_instructions->push_tail(assignment);
+ this->out_instructions->push_tail(assignment);
} else {
ir_assignment *assignment
= this->bitwise_assign_unpack(rvalue, swizzle);
- this->main_instructions->push_head(assignment);
+ this->out_instructions->push_tail(assignment);
}
return fine_location + components;
}
@@ -376,13 +477,24 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
* constituent elements, accessing each one using an ir_dereference_array.
* This takes care of both arrays and matrices, since ir_dereference_array
* treats a matrix like an array of its column vectors.
+ *
+ * \param gs_input_toplevel should be set to true if we are lowering geometry
+ * shader inputs, and we are currently lowering the whole input variable
+ * (i.e. we are lowering the array whose index selects the vertex).
+ *
+ * \param vertex_index: if we are lowering geometry shader inputs, and the
+ * level of the array that we are currently lowering is *not* the top level,
+ * then this indicates which vertex we are currently lowering. Otherwise it
+ * is ignored.
*/
unsigned
lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue,
unsigned array_size,
unsigned fine_location,
ir_variable *unpacked_var,
- const char *name)
+ const char *name,
+ bool gs_input_toplevel,
+ unsigned vertex_index)
{
for (unsigned i = 0; i < array_size; i++) {
if (i != 0)
@@ -392,8 +504,20 @@ lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue,
ir_dereference_array(rvalue, constant);
char *subscripted_name
= ralloc_asprintf(this->mem_ctx, "%s[%d]", name, i);
- fine_location = this->lower_rvalue(dereference_array, fine_location,
- unpacked_var, subscripted_name);
+ if (gs_input_toplevel) {
+ /* Geometry shader inputs are a special case. Instead of storing
+ * each element of the array at a different location, all elements
+ * are at the same location, but with a different vertex index.
+ */
+ (void) this->lower_rvalue(dereference_array, fine_location,
+ unpacked_var, subscripted_name,
+ false, i);
+ } else {
+ fine_location =
+ this->lower_rvalue(dereference_array, fine_location,
+ unpacked_var, subscripted_name,
+ false, vertex_index);
+ }
}
return fine_location;
}
@@ -406,11 +530,14 @@ lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue,
* The newly created varying inherits its interpolation parameters from \c
* unpacked_var. Its base type is ivec4 if we are lowering a flat varying,
* vec4 otherwise.
+ *
+ * \param vertex_index: if we are lowering geometry shader inputs, then this
+ * indicates which vertex we are currently lowering. Otherwise it is ignored.
*/
-ir_variable *
-lower_packed_varyings_visitor::get_packed_varying(unsigned location,
- ir_variable *unpacked_var,
- const char *name)
+ir_dereference *
+lower_packed_varyings_visitor::get_packed_varying_deref(
+ unsigned location, ir_variable *unpacked_var, const char *name,
+ unsigned vertex_index)
{
unsigned slot = location - this->location_base;
assert(slot < locations_used);
@@ -421,18 +548,44 @@ lower_packed_varyings_visitor::get_packed_varying(unsigned location,
packed_type = glsl_type::ivec4_type;
else
packed_type = glsl_type::vec4_type;
+ if (this->gs_input_vertices != 0) {
+ packed_type =
+ glsl_type::get_array_instance(packed_type,
+ this->gs_input_vertices);
+ }
ir_variable *packed_var = new(this->mem_ctx)
ir_variable(packed_type, packed_name, this->mode);
+ if (this->gs_input_vertices != 0) {
+ /* Prevent update_array_sizes() from messing with the size of the
+ * array.
+ */
+ packed_var->max_array_access = this->gs_input_vertices - 1;
+ }
packed_var->centroid = unpacked_var->centroid;
packed_var->interpolation = unpacked_var->interpolation;
packed_var->location = location;
unpacked_var->insert_before(packed_var);
this->packed_varyings[slot] = packed_var;
} else {
- ralloc_asprintf_append((char **) &this->packed_varyings[slot]->name,
- ",%s", name);
+ /* For geometry shader inputs, only update the packed variable name the
+ * first time we visit each component.
+ */
+ if (this->gs_input_vertices == 0 || vertex_index == 0) {
+ ralloc_asprintf_append((char **) &this->packed_varyings[slot]->name,
+ ",%s", name);
+ }
+ }
+
+ ir_dereference *deref = new(this->mem_ctx)
+ ir_dereference_variable(this->packed_varyings[slot]);
+ if (this->gs_input_vertices != 0) {
+ /* When lowering GS inputs, the packed variable is an array, so we need
+ * to dereference it using vertex_index.
+ */
+ ir_constant *constant = new(this->mem_ctx) ir_constant(vertex_index);
+ deref = new(this->mem_ctx) ir_dereference_array(deref, constant);
}
- return this->packed_varyings[slot];
+ return deref;
}
bool
@@ -440,6 +593,10 @@ lower_packed_varyings_visitor::needs_lowering(ir_variable *var)
{
/* Things composed of vec4's don't need lowering. Everything else does. */
const glsl_type *type = var->type;
+ if (this->gs_input_vertices != 0) {
+ assert(type->is_array());
+ type = type->element_type();
+ }
if (type->is_array())
type = type->fields.array;
if (type->vector_elements == 4)
@@ -447,19 +604,81 @@ 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,
- gl_shader *shader)
+ unsigned gs_input_vertices, gl_shader *shader)
{
exec_list *instructions = shader->ir;
ir_function *main_func = shader->symbols->get_function("main");
exec_list void_parameters;
ir_function_signature *main_func_sig
= main_func->matching_signature(&void_parameters);
- exec_list *main_instructions = &main_func_sig->body;
+ exec_list new_instructions;
lower_packed_varyings_visitor visitor(mem_ctx, location_base,
locations_used, mode,
- main_instructions);
+ gs_input_vertices, &new_instructions);
visitor.run(instructions);
+ if (mode == ir_var_shader_out) {
+ 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);
+ }
}