nv50: make edgeflags work
authorChristoph Bumiller <e0425955@student.tuwien.ac.at>
Thu, 24 Dec 2009 11:39:42 +0000 (12:39 +0100)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Thu, 24 Dec 2009 11:48:00 +0000 (12:48 +0100)
It doesn't seem to be possible to set the egdeflag in the
vertex shader, so we need to fallback to pushing vertices
through the FIFO and use method 0x15e4 if they are used.

This only works if VP does MOV OUT[X] IN[Y] where X is the
edgeflag output, and Y is saved so we can tell the correct
input later.

The VP still writes the useless values to wasted outputs
as punishment.

src/gallium/drivers/nv50/nv50_program.c
src/gallium/drivers/nv50/nv50_program.h
src/gallium/drivers/nv50/nv50_screen.c
src/gallium/drivers/nv50/nv50_vbo.c

index 679c28ce4b1240ca840a5c29a59ec3316620aa86..ce3fa5fc88b6b37ea7baaceadc200871749f00b6 100644 (file)
@@ -159,6 +159,8 @@ struct nv50_pc {
        unsigned insn_nr;
 
        boolean allow32;
+
+       uint8_t edgeflag_out;
 };
 
 static INLINE struct nv50_reg *
@@ -2554,10 +2556,16 @@ prep_inspect_insn(struct nv50_pc *pc, const struct tgsi_full_instruction *insn)
        mask = dst->WriteMask;
 
         if (dst->File == TGSI_FILE_TEMPORARY)
-                reg = pc->temp;
+               reg = pc->temp;
         else
-        if (dst->File == TGSI_FILE_OUTPUT)
-                reg = pc->result;
+       if (dst->File == TGSI_FILE_OUTPUT) {
+               reg = pc->result;
+
+               if (insn->Instruction.Opcode == TGSI_OPCODE_MOV &&
+                   dst->Index == pc->edgeflag_out &&
+                   insn->Src[0].Register.File == TGSI_FILE_INPUT)
+                       pc->p->cfg.edgeflag_in = insn->Src[0].Register.Index;
+       }
 
        if (reg) {
                for (c = 0; c < 4; c++) {
@@ -2856,6 +2864,9 @@ nv50_program_tx_prep(struct nv50_pc *pc)
                                        if (p->cfg.io_nr > first)
                                                p->cfg.io_nr = first;
                                        break;
+                               case TGSI_SEMANTIC_EDGEFLAG:
+                                       pc->edgeflag_out = first;
+                                       break;
                                        /*
                                case TGSI_SEMANTIC_CLIP_DISTANCE:
                                        p->cfg.clpd = MIN2(p->cfg.clpd, first);
@@ -3104,6 +3115,8 @@ ctor_nv50_pc(struct nv50_pc *pc, struct nv50_program *p)
        p->cfg.two_side[0].hw = 0x40;
        p->cfg.two_side[1].hw = 0x40;
 
+       p->cfg.edgeflag_in = pc->edgeflag_out = 0xff;
+
        switch (p->type) {
        case PIPE_SHADER_VERTEX:
                p->cfg.psiz = 0x40;
index 4a90c372ce34610c5eee7f04dd60ca811626f784..461fec1d89c323663602f52e89e4d23358bebdd9 100644 (file)
@@ -58,6 +58,7 @@ struct nv50_program {
                /* VP only */
                uint8_t clpd, clpd_nr;
                uint8_t psiz;
+               uint8_t edgeflag_in;
        } cfg;
 };
 
index d443ca3ad06905a714816da5425308aa164a2548..2435f65ed2594191fb3577c4221598a3d46a3402 100644 (file)
@@ -441,6 +441,9 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
        so_method(so, screen->tesla, NV50TCL_SCISSOR_ENABLE, 1);
        so_data  (so, 1);
 
+       so_method(so, screen->tesla, 0x15e4, 1);
+       so_data  (so, 1); /* default edgeflag to TRUE */
+
        so_emit(chan, so);
        so_ref (so, &screen->static_init);
        so_ref (NULL, &so);
index f7fa0659e8c68490bc2ed74e7ceac46fccd095ee..39324e30f6b86a3308b9159ea0bf73268e288f74 100644 (file)
@@ -372,6 +372,10 @@ nv50_vbo_static_attrib(struct nv50_context *nv50, unsigned attrib,
                so_data  (so, fui(v[1]));
                break;
        case 1:
+               if (attrib == nv50->vertprog->cfg.edgeflag_in) {
+                       so_method(so, tesla, 0x15e4, 1);
+                       so_data  (so, v[0] ? 1 : 0);
+               }
                so_method(so, tesla, NV50TCL_VTX_ATTR_1F(attrib), 1);
                so_data  (so, fui(v[0]));
                break;
@@ -401,6 +405,9 @@ nv50_vbo_validate(struct nv50_context *nv50)
                    !(nv50->vtxbuf[i].buffer->usage & PIPE_BUFFER_USAGE_VERTEX))
                        nv50->vbo_fifo = 0xffff;
 
+       if (nv50->vertprog->cfg.edgeflag_in < 16)
+               nv50->vbo_fifo = 0xffff; /* vertprog can't set edgeflag */
+
        n_ve = MAX2(nv50->vtxelt_nr, nv50->state.vtxelt_nr);
 
        vtxattr = NULL;
@@ -479,6 +486,9 @@ struct nv50_vbo_emitctx
        unsigned nr_ve;
        unsigned vtx_dwords;
        unsigned vtx_max;
+
+       float edgeflag;
+       unsigned ve_edgeflag;
 };
 
 static INLINE void
@@ -622,6 +632,9 @@ emit_prepare(struct nv50_context *nv50, struct nv50_vbo_emitctx *emit,
        if (nv50_map_vbufs(nv50) == FALSE)
                return FALSE;
 
+       emit->ve_edgeflag = nv50->vertprog->cfg.edgeflag_in;
+
+       emit->edgeflag = 0.5f;
        emit->nr_ve = 0;
        emit->vtx_dwords = 0;
 
@@ -644,7 +657,8 @@ emit_prepare(struct nv50_context *nv50, struct nv50_vbo_emitctx *emit,
                desc = util_format_description(ve->src_format);
                assert(desc);
 
-               size = util_format_get_component_bits(ve->src_format, UTIL_FORMAT_COLORSPACE_RGB, 0);
+               size = util_format_get_component_bits(
+                       ve->src_format, UTIL_FORMAT_COLORSPACE_RGB, 0);
 
                assert(ve->nr_components > 0 && ve->nr_components <= 4);
 
@@ -686,10 +700,31 @@ emit_prepare(struct nv50_context *nv50, struct nv50_vbo_emitctx *emit,
        }
 
        emit->vtx_max = 512 / emit->vtx_dwords;
+       if (emit->ve_edgeflag < 16)
+               emit->vtx_max = 1;
 
        return TRUE;
 }
 
+static INLINE void
+set_edgeflag(struct nouveau_channel *chan,
+            struct nouveau_grobj *tesla,
+            struct nv50_vbo_emitctx *emit, uint32_t index)
+{
+       unsigned i = emit->ve_edgeflag;
+
+       if (i < 16) {
+               float f = *((float *)(emit->map[i] + index * emit->stride[i]));
+
+               if (emit->edgeflag != f) {
+                       emit->edgeflag = f;
+
+                       BEGIN_RING(chan, tesla, 0x15e4, 1);
+                       OUT_RING  (chan, f ? 1 : 0);
+               }
+       }
+}
+
 static boolean
 nv50_push_arrays(struct nv50_context *nv50, unsigned start, unsigned count)
 {
@@ -704,6 +739,8 @@ nv50_push_arrays(struct nv50_context *nv50, unsigned start, unsigned count)
                unsigned i, dw, nr = MIN2(count, emit.vtx_max);
                dw = nr * emit.vtx_dwords;
 
+               set_edgeflag(chan, tesla, &emit, 0); /* nr will be 1 */
+
                BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw);
                for (i = 0; i < nr; ++i)
                        emit_vtx_next(chan, &emit);
@@ -729,6 +766,8 @@ nv50_push_elements_u32(struct nv50_context *nv50, uint32_t *map, unsigned count)
                unsigned i, dw, nr = MIN2(count, emit.vtx_max);
                dw = nr * emit.vtx_dwords;
 
+               set_edgeflag(chan, tesla, &emit, *map);
+
                BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw);
                for (i = 0; i < nr; ++i)
                        emit_vtx(chan, &emit, *map++);
@@ -754,6 +793,8 @@ nv50_push_elements_u16(struct nv50_context *nv50, uint16_t *map, unsigned count)
                unsigned i, dw, nr = MIN2(count, emit.vtx_max);
                dw = nr * emit.vtx_dwords;
 
+               set_edgeflag(chan, tesla, &emit, *map);
+
                BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw);
                for (i = 0; i < nr; ++i)
                        emit_vtx(chan, &emit, *map++);
@@ -779,6 +820,8 @@ nv50_push_elements_u08(struct nv50_context *nv50, uint8_t *map, unsigned count)
                unsigned i, dw, nr = MIN2(count, emit.vtx_max);
                dw = nr * emit.vtx_dwords;
 
+               set_edgeflag(chan, tesla, &emit, *map);
+
                BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw);
                for (i = 0; i < nr; ++i)
                        emit_vtx(chan, &emit, *map++);