diff options
author | Kenneth Graunke <[email protected]> | 2014-10-29 20:56:07 -0700 |
---|---|---|
committer | Kenneth Graunke <[email protected]> | 2014-11-06 16:30:47 -0800 |
commit | a16ca4ac6a356e02c6aa03c1e305f613a4e23202 (patch) | |
tree | dd15611d27b6f632ccf62ab5bf094dde4d52e0b1 | |
parent | 4f22db5fbbe59eacb762aa410f18c3078e85c2b7 (diff) |
glsl: Skip loop-too-large heuristic if indexing arrays of a certain size
A pattern in certain shaders is:
uniform vec4 colors[NUM_LIGHTS];
for (int i = 0; i < NUM_LIGHTS; i++) {
...use colors[i]...
}
In this case, the application author expects the shader compiler to
unroll the loop. By doing so, it replaces variable indexing of the
array with constant indexing, which is more efficient.
This patch extends the heuristic to see if arrays accessed within the
loop are indexed by an induction variable, and if the array size exactly
matches the number of loop iterations. If so, the application author
probably intended us to unroll it. If not, we rely on the existing
loop-too-large heuristic.
Improves performance in a phong shading microbenchmark by 2.88x, and a
shadow mapping microbenchmark by 1.63x. Without variable indexing, we
can upload the small uniform arrays as push constants instead of pull
constants, avoiding shader memory access. Affects several games, but
doesn't appear to impact their performance.
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Matt Turner <[email protected]>
Acked-by: Kristian Høgsberg <[email protected]>
-rw-r--r-- | src/glsl/loop_unroll.cpp | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/src/glsl/loop_unroll.cpp b/src/glsl/loop_unroll.cpp index ce795f6cd24..635e1dd99cd 100644 --- a/src/glsl/loop_unroll.cpp +++ b/src/glsl/loop_unroll.cpp @@ -64,6 +64,7 @@ class loop_unroll_count : public ir_hierarchical_visitor { public: int nodes; bool unsupported_variable_indexing; + bool array_indexed_by_induction_var_with_exact_iterations; /* If there are nested loops, the node count will be inaccurate. */ bool nested_loop; @@ -74,6 +75,7 @@ public: nodes = 0; nested_loop = false; unsupported_variable_indexing = false; + array_indexed_by_induction_var_with_exact_iterations = false; run(list); } @@ -112,6 +114,14 @@ public: ir_variable *array = ir->array->variable_referenced(); loop_variable *lv = ls->get(ir->array_index->variable_referenced()); if (array && lv && lv->is_induction_var()) { + /* If an array is indexed by a loop induction variable, and the + * array size is exactly the number of loop iterations, this is + * probably a simple for-loop trying to access each element in + * turn; the application may expect it to be unrolled. + */ + if (int(array->type->length) == ls->limiting_terminator->iterations) + array_indexed_by_induction_var_with_exact_iterations = true; + switch (array->data.mode) { case ir_var_auto: case ir_var_temporary: @@ -314,7 +324,8 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) bool loop_too_large = count.nested_loop || count.nodes * iterations > max_iterations * 5; - if (loop_too_large && !count.unsupported_variable_indexing) + if (loop_too_large && !count.unsupported_variable_indexing && + !count.array_indexed_by_induction_var_with_exact_iterations) return visit_continue; /* Note: the limiting terminator contributes 1 to ls->num_loop_jumps. |