vc4: Handle discards while in control flow.
authorEric Anholt <eric@anholt.net>
Fri, 26 Aug 2016 20:57:09 +0000 (13:57 -0700)
committerEric Anholt <eric@anholt.net>
Mon, 29 Aug 2016 18:03:11 +0000 (11:03 -0700)
I missed this while adding loop support because the discard test inside a
loop was crashing before, anyway.  Fixes piglit glsl-fs-discard-04.

src/gallium/drivers/vc4/vc4_program.c
src/gallium/drivers/vc4/vc4_qir.h

index 19bb8a332b49cf5646ffc5bb72a468a9983cf54d..b1189bf4c6bc2d8a82394cc7ae6f66d0b020dcde 100644 (file)
@@ -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);
index a82c47c03412d56f79d0b602fc0ff673d42b74fe..366521675951a5a6d7b75e521d0a89293cc03121 100644 (file)
@@ -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;