gallium: separate out floating-point CAPs into its own enum
[mesa.git] / src / gallium / drivers / nvc0 / nvc0_shader_state.c
index 981b5488d088be36110265a5990c9d0403fb3859..f4a12fbee11fb5baa8c37ec4f24da133223b8727 100644 (file)
 
 #include "nvc0_context.h"
 
-static boolean
-nvc0_program_validate(struct nvc0_context *nvc0, struct nvc0_program *prog)
+static INLINE void
+nvc0_program_update_context_state(struct nvc0_context *nvc0,
+                                  struct nvc0_program *prog, int stage)
 {
-   int ret;
-   unsigned size;
+   struct nouveau_channel *chan = nvc0->screen->base.channel;
 
-   if (prog->translated)
-      return TRUE;
+   if (prog->hdr[1])
+      nvc0->state.tls_required |= 1 << stage;
+   else
+      nvc0->state.tls_required &= ~(1 << stage);
 
-   prog->translated = nvc0_program_translate(prog);
-   if (!prog->translated)
-      return FALSE;
+   if (prog->immd_size) {
+      const unsigned rl = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD;
 
-   size = align(prog->code_size + NVC0_SHADER_HEADER_SIZE, 0x100);
+      BEGIN_RING(chan, RING_3D(CB_SIZE), 3);
+      /* NOTE: may overlap code of a different shader */
+      OUT_RING  (chan, align(prog->immd_size, 0x100));
+      OUT_RELOCh(chan, nvc0->screen->text, prog->immd_base, rl);
+      OUT_RELOCl(chan, nvc0->screen->text, prog->immd_base, rl);
+      BEGIN_RING(chan, RING_3D(CB_BIND(stage)), 1);
+      OUT_RING  (chan, (14 << 4) | 1);
 
-   ret = nouveau_resource_alloc(nvc0->screen->text_heap, size, prog,
-                                &prog->res);
-   if (ret)
-      return FALSE;
+      nvc0->state.c14_bound |= 1 << stage;
+   } else
+   if (nvc0->state.c14_bound & (1 << stage)) {
+      BEGIN_RING(chan, RING_3D(CB_BIND(stage)), 1);
+      OUT_RING  (chan, (14 << 4) | 0);
 
-   prog->code_base = prog->res->start;
+      nvc0->state.c14_bound &= ~(1 << stage);
+   }
+}
 
-   nvc0_m2mf_push_linear(nvc0, nvc0->screen->text, NOUVEAU_BO_VRAM,
-                         prog->code_base, NVC0_SHADER_HEADER_SIZE, prog->hdr);
-   nvc0_m2mf_push_linear(nvc0, nvc0->screen->text, NOUVEAU_BO_VRAM,
-                         prog->code_base + NVC0_SHADER_HEADER_SIZE,
-                         prog->code_size, prog->code);
+static void
+nvc0_program_validate_clip(struct nvc0_context *nvc0, struct nvc0_program *vp)
+{
+   struct nouveau_channel *chan = nvc0->screen->base.channel;
 
-   BEGIN_RING(nvc0->screen->base.channel, RING_3D_(0x021c), 1);
-   OUT_RING  (nvc0->screen->base.channel, 0x1111);
+   if (nvc0->vertprog->vp.num_ucps)
+      return;
 
-   return TRUE;
+   if (nvc0->state.clip_enable != vp->vp.clip_enable) {
+      nvc0->state.clip_enable = vp->vp.clip_enable;
+      IMMED_RING(chan, RING_3D(CLIP_DISTANCE_ENABLE), vp->vp.clip_enable);
+   }
+   if (nvc0->state.clip_mode != vp->vp.clip_mode) {
+      nvc0->state.clip_mode = vp->vp.clip_mode;
+      BEGIN_RING(chan, RING_3D(CLIP_DISTANCE_MODE), 1);
+      OUT_RING  (chan, vp->vp.clip_mode);
+   }
+}
+
+static INLINE boolean
+nvc0_program_validate(struct nvc0_context *nvc0, struct nvc0_program *prog)
+{
+   if (prog->res)
+      return TRUE;
+
+   if (!prog->translated) {
+      prog->translated = nvc0_program_translate(prog);
+      if (!prog->translated)
+         return FALSE;
+   }
+
+   return nvc0_program_upload_code(nvc0, prog);
 }
 
 void
@@ -77,6 +109,7 @@ nvc0_vertprog_validate(struct nvc0_context *nvc0)
 
    if (!nvc0_program_validate(nvc0, vp))
          return;
+   nvc0_program_update_context_state(nvc0, vp, 0);
 
    BEGIN_RING(chan, RING_3D(SP_SELECT(1)), 2);
    OUT_RING  (chan, 0x11);
@@ -84,10 +117,11 @@ nvc0_vertprog_validate(struct nvc0_context *nvc0)
    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(1)), 1);
    OUT_RING  (chan, vp->max_gpr);
 
+   if (!nvc0->gmtyprog && !nvc0->tevlprog)
+      nvc0_program_validate_clip(nvc0, vp);
+
    // BEGIN_RING(chan, RING_3D_(0x163c), 1);
    // OUT_RING  (chan, 0);
-   BEGIN_RING(chan, RING_3D(VERT_COLOR_CLAMP_EN), 1);
-   OUT_RING  (chan, 1);
 }
 
 void
@@ -98,9 +132,8 @@ nvc0_fragprog_validate(struct nvc0_context *nvc0)
 
    if (!nvc0_program_validate(nvc0, fp))
          return;
+   nvc0_program_update_context_state(nvc0, fp, 4);
 
-   BEGIN_RING(chan, RING_3D(EARLY_FRAGMENT_TESTS), 1);
-   OUT_RING  (chan, fp->fp.early_z);
    BEGIN_RING(chan, RING_3D(SP_SELECT(5)), 2);
    OUT_RING  (chan, 0x51);
    OUT_RING  (chan, fp->code_base);
@@ -127,12 +160,20 @@ nvc0_tctlprog_validate(struct nvc0_context *nvc0)
    }
    if (!nvc0_program_validate(nvc0, tp))
          return;
+   nvc0_program_update_context_state(nvc0, tp, 1);
 
+   if (tp->tp.tess_mode != ~0) {
+      BEGIN_RING(chan, RING_3D(TESS_MODE), 1);
+      OUT_RING  (chan, tp->tp.tess_mode);
+   }
    BEGIN_RING(chan, RING_3D(SP_SELECT(2)), 2);
    OUT_RING  (chan, 0x21);
    OUT_RING  (chan, tp->code_base);
    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(2)), 1);
-   OUT_RING  (chan, tp->max_gpr);   
+   OUT_RING  (chan, tp->max_gpr);
+
+   if (tp->tp.input_patch_size <= 32)
+      IMMED_RING(chan, RING_3D(PATCH_VERTICES), tp->tp.input_patch_size);
 }
 
 void
@@ -148,13 +189,21 @@ nvc0_tevlprog_validate(struct nvc0_context *nvc0)
    }
    if (!nvc0_program_validate(nvc0, tp))
          return;
+   nvc0_program_update_context_state(nvc0, tp, 2);
 
+   if (tp->tp.tess_mode != ~0) {
+      BEGIN_RING(chan, RING_3D(TESS_MODE), 1);
+      OUT_RING  (chan, tp->tp.tess_mode);
+   }
    BEGIN_RING(chan, RING_3D(TEP_SELECT), 1);
    OUT_RING  (chan, 0x31);
    BEGIN_RING(chan, RING_3D(SP_START_ID(3)), 1);
    OUT_RING  (chan, tp->code_base);
    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(3)), 1);
-   OUT_RING  (chan, tp->max_gpr);   
+   OUT_RING  (chan, tp->max_gpr);
+
+   if (!nvc0->gmtyprog)
+      nvc0_program_validate_clip(nvc0, tp);
 }
 
 void
@@ -166,15 +215,77 @@ nvc0_gmtyprog_validate(struct nvc0_context *nvc0)
    if (!gp) {
       BEGIN_RING(chan, RING_3D(GP_SELECT), 1);
       OUT_RING  (chan, 0x40);
+      IMMED_RING(chan, RING_3D(LAYER), 0);
       return;
    }
    if (!nvc0_program_validate(nvc0, gp))
          return;
+   nvc0_program_update_context_state(nvc0, gp, 3);
 
    BEGIN_RING(chan, RING_3D(GP_SELECT), 1);
    OUT_RING  (chan, 0x41);
    BEGIN_RING(chan, RING_3D(SP_START_ID(4)), 1);
    OUT_RING  (chan, gp->code_base);
    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(4)), 1);
-   OUT_RING  (chan, gp->max_gpr);   
+   OUT_RING  (chan, gp->max_gpr);
+   BEGIN_RING(chan, RING_3D(LAYER), 1);
+   OUT_RING  (chan, (gp->hdr[13] & (1 << 9)) ? NVC0_3D_LAYER_USE_GP : 0);
+
+   nvc0_program_validate_clip(nvc0, gp);
+}
+
+/* It's *is* kind of shader related. We need to inspect the program
+ * to get the output locations right.
+ */
+void
+nvc0_tfb_validate(struct nvc0_context *nvc0)
+{
+   struct nouveau_channel *chan = nvc0->screen->base.channel;
+   struct nvc0_program *vp;
+   struct nvc0_transform_feedback_state *tfb = nvc0->tfb;
+   int b;
+
+   BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1);
+   if (!tfb) {
+      OUT_RING(chan, 0);
+      return;
+   }
+   OUT_RING(chan, 1);
+
+   vp = nvc0->vertprog ? nvc0->vertprog : nvc0->gmtyprog;
+
+   for (b = 0; b < nvc0->num_tfbbufs; ++b) {
+      uint8_t idx, var[128];
+      int i, n;
+      struct nv04_resource *buf = nv04_resource(nvc0->tfbbuf[b]);
+
+      BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 5);
+      OUT_RING  (chan, 1);
+      OUT_RESRCh(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR);
+      OUT_RESRCl(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR);
+      OUT_RING  (chan, buf->base.width0 - nvc0->tfb_offset[b]);
+      OUT_RING  (chan, 0); /* TFB_PRIMITIVE_ID <- offset ? */
+
+      if (!(nvc0->dirty & NVC0_NEW_TFB))
+         continue;
+
+      BEGIN_RING(chan, RING_3D(TFB_UNK07X0(b)), 3);
+      OUT_RING  (chan, 0);
+      OUT_RING  (chan, tfb->varying_count[b]);
+      OUT_RING  (chan, tfb->stride[b]);
+
+      n = b ? tfb->varying_count[b - 1] : 0;
+      i = 0;
+      for (; i < tfb->varying_count[b]; ++i) {
+         idx = tfb->varying_index[n + i];
+         var[i] = vp->vp.out_pos[idx >> 2] + (idx & 3);
+      }
+      for (; i & 3; ++i)
+         var[i] = 0;
+
+      BEGIN_RING(chan, RING_3D(TFB_VARYING_LOCS(b, 0)), i / 4);
+      OUT_RINGp (chan, var, i / 4);
+   }
+   for (; b < 4; ++b)
+      IMMED_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 0);
 }