aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl/ir_set_program_inouts.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/ir_set_program_inouts.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/ir_set_program_inouts.cpp')
-rw-r--r--mesalib/src/glsl/ir_set_program_inouts.cpp202
1 files changed, 167 insertions, 35 deletions
diff --git a/mesalib/src/glsl/ir_set_program_inouts.cpp b/mesalib/src/glsl/ir_set_program_inouts.cpp
index 91a8b4526..6196d6a64 100644
--- a/mesalib/src/glsl/ir_set_program_inouts.cpp
+++ b/mesalib/src/glsl/ir_set_program_inouts.cpp
@@ -44,11 +44,10 @@
class ir_set_program_inouts_visitor : public ir_hierarchical_visitor {
public:
- ir_set_program_inouts_visitor(struct gl_program *prog,
- bool is_fragment_shader)
+ ir_set_program_inouts_visitor(struct gl_program *prog, GLenum shader_type)
{
this->prog = prog;
- this->is_fragment_shader = is_fragment_shader;
+ this->shader_type = shader_type;
}
~ir_set_program_inouts_visitor()
{
@@ -60,8 +59,12 @@ public:
virtual ir_visitor_status visit_enter(ir_discard *);
virtual ir_visitor_status visit(ir_dereference_variable *);
+private:
+ void mark_whole_variable(ir_variable *var);
+ bool try_mark_partial_variable(ir_variable *var, ir_rvalue *index);
+
struct gl_program *prog;
- bool is_fragment_shader;
+ GLenum shader_type;
};
static inline bool
@@ -104,6 +107,23 @@ mark(struct gl_program *prog, ir_variable *var, int offset, int len,
}
}
+/**
+ * Mark an entire variable as used. Caller must ensure that the variable
+ * represents a shader input or output.
+ */
+void
+ir_set_program_inouts_visitor::mark_whole_variable(ir_variable *var)
+{
+ const glsl_type *type = var->type;
+ if (this->shader_type == GL_GEOMETRY_SHADER &&
+ var->mode == ir_var_shader_in && type->is_array()) {
+ type = type->fields.array;
+ }
+
+ mark(this->prog, var, 0, type->count_attribute_slots(),
+ this->shader_type == GL_FRAGMENT_SHADER);
+}
+
/* Default handler: Mark all the locations in the variable as used. */
ir_visitor_status
ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
@@ -111,43 +131,154 @@ ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
if (!is_shader_inout(ir->var))
return visit_continue;
- if (ir->type->is_array()) {
- mark(this->prog, ir->var, 0,
- ir->type->length * ir->type->fields.array->matrix_columns,
- this->is_fragment_shader);
- } else {
- mark(this->prog, ir->var, 0, ir->type->matrix_columns,
- this->is_fragment_shader);
- }
+ mark_whole_variable(ir->var);
return visit_continue;
}
-ir_visitor_status
-ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
+/**
+ * Try to mark a portion of the given variable as used. Caller must ensure
+ * that the variable represents a shader input or output which can be indexed
+ * into in array fashion (an array or matrix). For the purpose of geometry
+ * shader inputs (which are always arrays*), this means that the array element
+ * must be something that can be indexed into in array fashion.
+ *
+ * *Except gl_PrimitiveIDIn, as noted below.
+ *
+ * If the index can't be interpreted as a constant, or some other problem
+ * occurs, then nothing will be marked and false will be returned.
+ */
+bool
+ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var,
+ ir_rvalue *index)
{
- ir_dereference_variable *deref_var;
- ir_constant *index = ir->array_index->as_constant();
- deref_var = ir->array->as_dereference_variable();
- ir_variable *var = deref_var ? deref_var->var : NULL;
+ const glsl_type *type = var->type;
- /* Check that we're dereferencing a shader in or out */
- if (!var || !is_shader_inout(var))
- return visit_continue;
+ if (this->shader_type == GL_GEOMETRY_SHADER &&
+ var->mode == ir_var_shader_in) {
+ /* The only geometry shader input that is not an array is
+ * gl_PrimitiveIDIn, and in that case, this code will never be reached,
+ * because gl_PrimitiveIDIn can't be indexed into in array fashion.
+ */
+ assert(type->is_array());
+ type = type->fields.array;
+ }
- if (index) {
- int width = 1;
+ /* The code below only handles:
+ *
+ * - Indexing into matrices
+ * - Indexing into arrays of (matrices, vectors, or scalars)
+ *
+ * All other possibilities are either prohibited by GLSL (vertex inputs and
+ * fragment outputs can't be structs) or should have been eliminated by
+ * lowering passes (do_vec_index_to_swizzle() gets rid of indexing into
+ * vectors, and lower_packed_varyings() gets rid of structs that occur in
+ * varyings).
+ */
+ if (!(type->is_matrix() ||
+ (type->is_array() &&
+ (type->fields.array->is_numeric() ||
+ type->fields.array->is_boolean())))) {
+ assert(!"Unexpected indexing in ir_set_program_inouts");
- if (deref_var->type->is_array() &&
- deref_var->type->fields.array->is_matrix()) {
- width = deref_var->type->fields.array->matrix_columns;
- }
+ /* For safety in release builds, in case we ever encounter unexpected
+ * indexing, give up and let the caller mark the whole variable as used.
+ */
+ return false;
+ }
+
+ ir_constant *index_as_constant = index->as_constant();
+ if (!index_as_constant)
+ return false;
+
+ unsigned elem_width;
+ unsigned num_elems;
+ if (type->is_array()) {
+ num_elems = type->length;
+ if (type->fields.array->is_matrix())
+ elem_width = type->fields.array->matrix_columns;
+ else
+ elem_width = 1;
+ } else {
+ num_elems = type->matrix_columns;
+ elem_width = 1;
+ }
- mark(this->prog, var, index->value.i[0] * width, width,
- this->is_fragment_shader);
- return visit_continue_with_parent;
+ if (index_as_constant->value.u[0] >= num_elems) {
+ /* Constant index outside the bounds of the matrix/array. This could
+ * arise as a result of constant folding of a legal GLSL program.
+ *
+ * Even though the spec says that indexing outside the bounds of a
+ * matrix/array results in undefined behaviour, we don't want to pass
+ * out-of-range values to mark() (since this could result in slots that
+ * don't exist being marked as used), so just let the caller mark the
+ * whole variable as used.
+ */
+ return false;
}
+ mark(this->prog, var, index_as_constant->value.u[0] * elem_width,
+ elem_width, this->shader_type == GL_FRAGMENT_SHADER);
+ return true;
+}
+
+ir_visitor_status
+ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
+{
+ /* Note: for geometry shader inputs, lower_named_interface_blocks may
+ * create 2D arrays, so we need to be able to handle those. 2D arrays
+ * shouldn't be able to crop up for any other reason.
+ */
+ if (ir_dereference_array * const inner_array =
+ ir->array->as_dereference_array()) {
+ /* ir => foo[i][j]
+ * inner_array => foo[i]
+ */
+ if (ir_dereference_variable * const deref_var =
+ inner_array->array->as_dereference_variable()) {
+ if (this->shader_type == GL_GEOMETRY_SHADER &&
+ deref_var->var->mode == ir_var_shader_in) {
+ /* foo is a geometry shader input, so i is the vertex, and j the
+ * part of the input we're accessing.
+ */
+ if (try_mark_partial_variable(deref_var->var, ir->array_index))
+ {
+ /* We've now taken care of foo and j, but i might contain a
+ * subexpression that accesses shader inputs. So manually
+ * visit i and then continue with the parent.
+ */
+ inner_array->array_index->accept(this);
+ return visit_continue_with_parent;
+ }
+ }
+ }
+ } else if (ir_dereference_variable * const deref_var =
+ ir->array->as_dereference_variable()) {
+ /* ir => foo[i], where foo is a variable. */
+ if (this->shader_type == GL_GEOMETRY_SHADER &&
+ deref_var->var->mode == ir_var_shader_in) {
+ /* foo is a geometry shader input, so i is the vertex, and we're
+ * accessing the entire input.
+ */
+ mark_whole_variable(deref_var->var);
+ /* We've now taken care of foo, but i might contain a subexpression
+ * that accesses shader inputs. So manually visit i and then
+ * continue with the parent.
+ */
+ ir->array_index->accept(this);
+ return visit_continue_with_parent;
+ } else if (is_shader_inout(deref_var->var)) {
+ /* foo is a shader input/output, but not a geometry shader input,
+ * so i is the part of the input we're accessing.
+ */
+ if (try_mark_partial_variable(deref_var->var, ir->array_index))
+ return visit_continue_with_parent;
+ }
+ }
+
+ /* The expression is something we don't recognize. Just visit its
+ * subexpressions.
+ */
return visit_continue;
}
@@ -164,7 +295,8 @@ ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
ir_visitor_status
ir_set_program_inouts_visitor::visit_enter(ir_expression *ir)
{
- if (is_fragment_shader && ir->operation == ir_unop_dFdy) {
+ if (this->shader_type == GL_FRAGMENT_SHADER &&
+ ir->operation == ir_unop_dFdy) {
gl_fragment_program *fprog = (gl_fragment_program *) prog;
fprog->UsesDFdy = true;
}
@@ -175,7 +307,7 @@ ir_visitor_status
ir_set_program_inouts_visitor::visit_enter(ir_discard *)
{
/* discards are only allowed in fragment shaders. */
- assert(is_fragment_shader);
+ assert(this->shader_type == GL_FRAGMENT_SHADER);
gl_fragment_program *fprog = (gl_fragment_program *) prog;
fprog->UsesKill = true;
@@ -185,14 +317,14 @@ ir_set_program_inouts_visitor::visit_enter(ir_discard *)
void
do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
- bool is_fragment_shader)
+ GLenum shader_type)
{
- ir_set_program_inouts_visitor v(prog, is_fragment_shader);
+ ir_set_program_inouts_visitor v(prog, shader_type);
prog->InputsRead = 0;
prog->OutputsWritten = 0;
prog->SystemValuesRead = 0;
- if (is_fragment_shader) {
+ if (shader_type == GL_FRAGMENT_SHADER) {
gl_fragment_program *fprog = (gl_fragment_program *) prog;
memset(fprog->InterpQualifier, 0, sizeof(fprog->InterpQualifier));
fprog->IsCentroid = 0;