summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2016-08-26 13:57:09 -0700
committerEric Anholt <[email protected]>2016-08-29 11:03:11 -0700
commit60bed14d0fdc3a05b6251b4ffc6013b5d3ca3e0f (patch)
treea66021502eb0ced924df355e1f544914248ab714
parentb9a74fbec7e3fe8c159a3a18447a416e09c68693 (diff)
vc4: Handle discards while in control flow.
I missed this while adding loop support because the discard test inside a loop was crashing before, anyway. Fixes piglit glsl-fs-discard-04.
-rw-r--r--src/gallium/drivers/vc4/vc4_program.c33
-rw-r--r--src/gallium/drivers/vc4/vc4_qir.h1
2 files changed, 28 insertions, 6 deletions
diff --git a/src/gallium/drivers/vc4/vc4_program.c b/src/gallium/drivers/vc4/vc4_program.c
index 19bb8a332b4..b1189bf4c6b 100644
--- a/src/gallium/drivers/vc4/vc4_program.c
+++ b/src/gallium/drivers/vc4/vc4_program.c
@@ -1236,7 +1236,7 @@ emit_frag_end(struct vc4_compile *c)
}
uint32_t discard_cond = QPU_COND_ALWAYS;
- if (c->discard.file != QFILE_NULL) {
+ if (c->s->info.fs.uses_discard) {
qir_SF(c, c->discard);
discard_cond = QPU_COND_ZS;
}
@@ -1721,15 +1721,33 @@ ntq_emit_intrinsic(struct vc4_compile *c, nir_intrinsic_instr *instr)
break;
case nir_intrinsic_discard:
- c->discard = qir_uniform_ui(c, ~0);
+ if (c->execute.file != QFILE_NULL) {
+ qir_SF(c, c->execute);
+ qir_MOV_cond(c, QPU_COND_ZS, c->discard,
+ qir_uniform_ui(c, ~0));
+ } else {
+ qir_MOV_dest(c, c->discard, qir_uniform_ui(c, ~0));
+ }
break;
- case nir_intrinsic_discard_if:
- if (c->discard.file == QFILE_NULL)
- c->discard = qir_uniform_ui(c, 0);
- c->discard = qir_OR(c, c->discard,
+ case nir_intrinsic_discard_if: {
+ /* true (~0) if we're discarding */
+ struct qreg cond = ntq_get_src(c, instr->src[0], 0);
+
+ if (c->execute.file != QFILE_NULL) {
+ /* execute == 0 means the channel is active. Invert
+ * the condition so that we can use zero as "executing
+ * and discarding."
+ */
+ qir_SF(c, qir_AND(c, c->execute, qir_NOT(c, cond)));
+ qir_MOV_cond(c, QPU_COND_ZS, c->discard, cond);
+ } else {
+ qir_OR_dest(c, c->discard, c->discard,
ntq_get_src(c, instr->src[0], 0));
+ }
+
break;
+ }
default:
fprintf(stderr, "Unknown intrinsic: ");
@@ -2001,6 +2019,9 @@ ntq_emit_impl(struct vc4_compile *c, nir_function_impl *impl)
static void
nir_to_qir(struct vc4_compile *c)
{
+ if (c->stage == QSTAGE_FRAG && c->s->info.fs.uses_discard)
+ c->discard = qir_MOV(c, qir_uniform_ui(c, 0));
+
ntq_setup_inputs(c);
ntq_setup_outputs(c);
ntq_setup_uniforms(c);
diff --git a/src/gallium/drivers/vc4/vc4_qir.h b/src/gallium/drivers/vc4/vc4_qir.h
index a82c47c0341..36652167595 100644
--- a/src/gallium/drivers/vc4/vc4_qir.h
+++ b/src/gallium/drivers/vc4/vc4_qir.h
@@ -448,6 +448,7 @@ struct vc4_compile {
struct qreg execute;
struct qreg line_x, point_x, point_y;
+ /** boolean (~0 -> true) if the fragment has been discarded. */
struct qreg discard;
struct qreg payload_FRAG_Z;
struct qreg payload_FRAG_W;