nv50: implement multiple viewports/scissors, enable ARB_viewport_array
authorIlia Mirkin <imirkin@alum.mit.edu>
Tue, 21 Jan 2014 07:56:01 +0000 (02:56 -0500)
committerIlia Mirkin <imirkin@alum.mit.edu>
Thu, 13 Feb 2014 02:47:36 +0000 (21:47 -0500)
Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Reviewed-by: Christoph Bumiller <e0425955@student.tuwien.ac.at>
src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
src/gallium/drivers/nouveau/nv50/nv50_context.h
src/gallium/drivers/nouveau/nv50/nv50_program.c
src/gallium/drivers/nouveau/nv50/nv50_program.h
src/gallium/drivers/nouveau/nv50/nv50_screen.c
src/gallium/drivers/nouveau/nv50/nv50_screen.h
src/gallium/drivers/nouveau/nv50/nv50_shader_state.c
src/gallium/drivers/nouveau/nv50/nv50_state.c
src/gallium/drivers/nouveau/nv50/nv50_state_validate.c

index 78a6c831fc5a2e6b802acea4c62db4445a505721..d226d0c36c98bf4292efcb356ad44b8b529ed48a 100644 (file)
@@ -1031,6 +1031,7 @@ bool Source::scanInstruction(const struct tgsi_full_instruction *inst)
          if (info->out[dst.getIndex(0)].sn == TGSI_SEMANTIC_PSIZE ||
              info->out[dst.getIndex(0)].sn == TGSI_SEMANTIC_PRIMID ||
              info->out[dst.getIndex(0)].sn == TGSI_SEMANTIC_LAYER ||
+             info->out[dst.getIndex(0)].sn == TGSI_SEMANTIC_VIEWPORT_INDEX ||
              info->out[dst.getIndex(0)].sn == TGSI_SEMANTIC_FOG)
             info->out[dst.getIndex(0)].mask &= 1;
 
index 1ce52c9793602b97e104ec19c684ed112400293c..57a3090833a45a9d19f971086add9d1bfa063382 100644 (file)
@@ -163,8 +163,10 @@ struct nv50_context {
    struct pipe_blend_color blend_colour;
    struct pipe_stencil_ref stencil_ref;
    struct pipe_poly_stipple stipple;
-   struct pipe_scissor_state scissor;
-   struct pipe_viewport_state viewport;
+   struct pipe_scissor_state scissors[NV50_MAX_VIEWPORTS];
+   unsigned scissors_dirty;
+   struct pipe_viewport_state viewports[NV50_MAX_VIEWPORTS];
+   unsigned viewports_dirty;
    struct pipe_clip_state clip;
 
    unsigned sample_mask;
index e5064383fb7298abf4763b23ee21f58957b363a3..0e06125df01133f3a8adcbacb8b74115da581ad4 100644 (file)
@@ -107,6 +107,10 @@ nv50_vertprog_assign_slots(struct nv50_ir_prog_info *info)
          prog->gp.has_layer = TRUE;
          prog->gp.layerid = n;
          break;
+      case TGSI_SEMANTIC_VIEWPORT_INDEX:
+         prog->gp.has_viewport = true;
+         prog->gp.viewportid = n;
+         break;
       default:
          break;
       }
@@ -344,6 +348,7 @@ nv50_program_translate(struct nv50_program *prog, uint16_t chipset)
    prog->vp.clpd[1] = map_undef;
    prog->vp.psiz = map_undef;
    prog->gp.has_layer = 0;
+   prog->gp.has_viewport = 0;
 
    info->driverPriv = prog;
 
index 8c1b3270e034b31b0d6d01b2ee19a78ae0438e2c..87b06790d4fb8b785e4382133e2ac8388f65e53f 100644 (file)
@@ -91,6 +91,8 @@ struct nv50_program {
       uint8_t prim_type; /* point, line strip or tri strip */
       uint8_t has_layer;
       ubyte layerid; /* hw value of layer output */
+      uint8_t has_viewport;
+      ubyte viewportid; /* hw value of viewport index output */
    } gp;
 
    void *fixups; /* relocation records */
index db3265fb29e95ad5d4f52bc5d6731c8cca094ca7..781b39158b457bdda2e3de417c547ef1e74dbb88 100644 (file)
@@ -197,6 +197,8 @@ nv50_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
       return PIPE_ENDIAN_LITTLE;
    case PIPE_CAP_TGSI_VS_LAYER:
       return 0;
+   case PIPE_CAP_MAX_VIEWPORTS:
+      return NV50_MAX_VIEWPORTS;
    default:
       NOUVEAU_ERR("unknown PIPE_CAP %d\n", param);
       return 0;
@@ -528,9 +530,14 @@ nv50_screen_init_hwctx(struct nv50_screen *screen)
 
    BEGIN_NV04(push, NV50_3D(VIEWPORT_TRANSFORM_EN), 1);
    PUSH_DATA (push, 1);
-   BEGIN_NV04(push, NV50_3D(DEPTH_RANGE_NEAR(0)), 2);
-   PUSH_DATAf(push, 0.0f);
-   PUSH_DATAf(push, 1.0f);
+   for (i = 0; i < NV50_MAX_VIEWPORTS; i++) {
+      BEGIN_NV04(push, NV50_3D(DEPTH_RANGE_NEAR(i)), 2);
+      PUSH_DATAf(push, 0.0f);
+      PUSH_DATAf(push, 1.0f);
+      BEGIN_NV04(push, NV50_3D(VIEWPORT_HORIZ(i)), 2);
+      PUSH_DATA (push, 8192 << 16);
+      PUSH_DATA (push, 8192 << 16);
+   }
 
    BEGIN_NV04(push, NV50_3D(VIEW_VOLUME_CLIP_CTRL), 1);
 #ifdef NV50_SCISSORS_CLIPPING
@@ -545,10 +552,12 @@ nv50_screen_init_hwctx(struct nv50_screen *screen)
    /* We use scissors instead of exact view volume clipping,
     * so they're always enabled.
     */
-   BEGIN_NV04(push, NV50_3D(SCISSOR_ENABLE(0)), 3);
-   PUSH_DATA (push, 1);
-   PUSH_DATA (push, 8192 << 16);
-   PUSH_DATA (push, 8192 << 16);
+   for (i = 0; i < NV50_MAX_VIEWPORTS; i++) {
+      BEGIN_NV04(push, NV50_3D(SCISSOR_ENABLE(i)), 3);
+      PUSH_DATA (push, 1);
+      PUSH_DATA (push, 8192 << 16);
+      PUSH_DATA (push, 8192 << 16);
+   }
 
    BEGIN_NV04(push, NV50_3D(RASTERIZE_ENABLE), 1);
    PUSH_DATA (push, 1);
index 091a3921a4b374a83530e8d394a1b17a8dc46aea..f8ce365135a33c701b6e62b654d07efedd9dd6c8 100644 (file)
@@ -21,6 +21,8 @@ struct nv50_context;
 
 #define NV50_SCREEN_RESIDENT_BO_COUNT 5
 
+#define NV50_MAX_VIEWPORTS 16
+
 struct nv50_blitter;
 
 struct nv50_screen {
index 129ed2ae82484f45569e1842ecab5c5a1cb00f32..28cff8ba913358e0d10e16c6cdc09029ffe0c0a2 100644 (file)
@@ -347,6 +347,7 @@ nv50_fp_linkage_validate(struct nv50_context *nv50)
    int i, n, c, m;
    uint32_t primid = 0;
    uint32_t layerid = 0;
+   uint32_t viewportid = 0;
    uint32_t psiz = 0x000;
    uint32_t interp = fp->fp.interp;
    uint32_t colors = fp->fp.colors;
@@ -408,6 +409,9 @@ nv50_fp_linkage_validate(struct nv50_context *nv50)
       case TGSI_SEMANTIC_LAYER:
          layerid = m;
          break;
+      case TGSI_SEMANTIC_VIEWPORT_INDEX:
+         viewportid = m;
+         break;
       }
       m = nv50_vec4_map(map, m, lin,
                         &fp->in[i], (n < vp->out_nr) ? &vp->out[n] : &dummy);
@@ -418,6 +422,11 @@ nv50_fp_linkage_validate(struct nv50_context *nv50)
       map[m++] = vp->gp.layerid;
    }
 
+   if (vp->gp.has_viewport && !viewportid) {
+      viewportid = m;
+      map[m++] = vp->gp.viewportid;
+   }
+
    if (nv50->rast->pipe.point_size_per_vertex) {
       psiz = (m << 4) | 1;
       map[m++] = vp->vp.psiz;
@@ -472,12 +481,16 @@ nv50_fp_linkage_validate(struct nv50_context *nv50)
       PUSH_DATAp(push, map, n);
    }
 
-   BEGIN_NV04(push, NV50_3D(SEMANTIC_COLOR), 4);
+   BEGIN_NV04(push, NV50_3D(GP_VIEWPORT_ID_ENABLE), 5);
+   PUSH_DATA (push, vp->gp.has_viewport);
    PUSH_DATA (push, colors);
    PUSH_DATA (push, (vp->vp.clpd_nr << 8) | 4);
    PUSH_DATA (push, layerid);
    PUSH_DATA (push, psiz);
 
+   BEGIN_NV04(push, NV50_3D(SEMANTIC_VIEWPORT), 1);
+   PUSH_DATA (push, viewportid);
+
    BEGIN_NV04(push, NV50_3D(LAYER), 1);
    PUSH_DATA (push, vp->gp.has_layer << 16);
 
index 247f295f8bc73e8a6b2c27e62b71b5ec57fe8c15..288ba462195d82e867751afc14338580a2377c7e 100644 (file)
@@ -235,8 +235,10 @@ nv50_rasterizer_state_create(struct pipe_context *pipe,
    so->pipe = *cso;
 
 #ifndef NV50_SCISSORS_CLIPPING
-   SB_BEGIN_3D(so, SCISSOR_ENABLE(0), 1);
-   SB_DATA    (so, cso->scissor);
+   for (int i = 0; i < NV50_MAX_VIEWPORTS; i++) {
+      SB_BEGIN_3D(so, SCISSOR_ENABLE(i), 1);
+      SB_DATA    (so, cso->scissor);
+   }
 #endif
 
    SB_BEGIN_3D(so, SHADE_MODEL, 1);
@@ -903,9 +905,16 @@ nv50_set_scissor_states(struct pipe_context *pipe,
                         const struct pipe_scissor_state *scissor)
 {
    struct nv50_context *nv50 = nv50_context(pipe);
+   int i;
 
-   nv50->scissor = *scissor;
-   nv50->dirty |= NV50_NEW_SCISSOR;
+   assert(start_slot + num_scissors <= NV50_MAX_VIEWPORTS);
+   for (i = 0; i < num_scissors; i++) {
+      if (!memcmp(&nv50->scissors[start_slot + i], &scissor[i], sizeof(*scissor)))
+         continue;
+      nv50->scissors[start_slot + i] = scissor[i];
+      nv50->scissors_dirty |= 1 << (start_slot + i);
+      nv50->dirty |= NV50_NEW_SCISSOR;
+   }
 }
 
 static void
@@ -915,9 +924,16 @@ nv50_set_viewport_states(struct pipe_context *pipe,
                          const struct pipe_viewport_state *vpt)
 {
    struct nv50_context *nv50 = nv50_context(pipe);
+   int i;
 
-   nv50->viewport = *vpt;
-   nv50->dirty |= NV50_NEW_VIEWPORT;
+   assert(start_slot + num_viewports <= NV50_MAX_VIEWPORTS);
+   for (i = 0; i < num_viewports; i++) {
+      if (!memcmp(&nv50->viewports[start_slot + i], &vpt[i], sizeof(*vpt)))
+         continue;
+      nv50->viewports[start_slot + i] = vpt[i];
+      nv50->viewports_dirty |= 1 << (start_slot + i);
+      nv50->dirty |= NV50_NEW_VIEWPORT;
+   }
 }
 
 static void
index 95592533bb3f3068630bf15ac38c51612513e6c6..dfce193b02017f3df4f022d0f11b6558166252b6 100644 (file)
@@ -124,6 +124,7 @@ nv50_validate_fb(struct nv50_context *nv50)
    BEGIN_NV04(push, NV50_3D(MULTISAMPLE_MODE), 1);
    PUSH_DATA (push, ms_mode);
 
+   /* Only need to initialize the first viewport, which is used for clears */
    BEGIN_NV04(push, NV50_3D(VIEWPORT_HORIZ(0)), 2);
    PUSH_DATA (push, fb->width << 16);
    PUSH_DATA (push, fb->height << 16);
@@ -167,42 +168,63 @@ static void
 nv50_validate_scissor(struct nv50_context *nv50)
 {
    struct nouveau_pushbuf *push = nv50->base.pushbuf;
-   struct pipe_scissor_state *s = &nv50->scissor;
 #ifdef NV50_SCISSORS_CLIPPING
-   struct pipe_viewport_state *vp = &nv50->viewport;
-   int minx, maxx, miny, maxy;
+   int minx, maxx, miny, maxy, i;
 
    if (!(nv50->dirty &
          (NV50_NEW_SCISSOR | NV50_NEW_VIEWPORT | NV50_NEW_FRAMEBUFFER)) &&
        nv50->state.scissor == nv50->rast->pipe.scissor)
       return;
+
+   if (nv50->state.scissor != nv50->rast->pipe.scissor)
+      nv50->scissors_dirty = (1 << NV50_MAX_VIEWPORTS) - 1;
+
    nv50->state.scissor = nv50->rast->pipe.scissor;
 
-   if (nv50->state.scissor) {
-      minx = s->minx;
-      maxx = s->maxx;
-      miny = s->miny;
-      maxy = s->maxy;
-   } else {
-      minx = 0;
-      maxx = nv50->framebuffer.width;
-      miny = 0;
-      maxy = nv50->framebuffer.height;
-   }
+   if ((nv50->dirty & NV50_NEW_FRAMEBUFFER) && !nv50->state.scissor)
+      nv50->scissors_dirty = (1 << NV50_MAX_VIEWPORTS) - 1;
+
+   for (i = 0; i < NV50_MAX_VIEWPORTS; i++) {
+      struct pipe_scissor_state *s = &nv50->scissors[i];
+      struct pipe_viewport_state *vp = &nv50->viewports[i];
+
+      if (!(nv50->scissors_dirty & (1 << i)) &&
+          !(nv50->viewports_dirty & (1 << i)))
+         continue;
+
+      if (nv50->state.scissor) {
+         minx = s->minx;
+         maxx = s->maxx;
+         miny = s->miny;
+         maxy = s->maxy;
+      } else {
+         minx = 0;
+         maxx = nv50->framebuffer.width;
+         miny = 0;
+         maxy = nv50->framebuffer.height;
+      }
+
+      minx = MAX2(minx, (int)(vp->translate[0] - fabsf(vp->scale[0])));
+      maxx = MIN2(maxx, (int)(vp->translate[0] + fabsf(vp->scale[0])));
+      miny = MAX2(miny, (int)(vp->translate[1] - fabsf(vp->scale[1])));
+      maxy = MIN2(maxy, (int)(vp->translate[1] + fabsf(vp->scale[1])));
 
-   minx = MAX2(minx, (int)(vp->translate[0] - fabsf(vp->scale[0])));
-   maxx = MIN2(maxx, (int)(vp->translate[0] + fabsf(vp->scale[0])));
-   miny = MAX2(miny, (int)(vp->translate[1] - fabsf(vp->scale[1])));
-   maxy = MIN2(maxy, (int)(vp->translate[1] + fabsf(vp->scale[1])));
+      minx = MIN2(minx, 8192);
+      maxx = MAX2(maxx, 0);
+      miny = MIN2(miny, 8192);
+      maxy = MAX2(maxy, 0);
 
-   BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(0)), 2);
-   PUSH_DATA (push, (maxx << 16) | minx);
-   PUSH_DATA (push, (maxy << 16) | miny);
+      BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(i)), 2);
+      PUSH_DATA (push, (maxx << 16) | minx);
+      PUSH_DATA (push, (maxy << 16) | miny);
 #else
-   BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(0)), 2);
-   PUSH_DATA (push, (s->maxx << 16) | s->minx);
-   PUSH_DATA (push, (s->maxy << 16) | s->miny);
+      BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(i)), 2);
+      PUSH_DATA (push, (s->maxx << 16) | s->minx);
+      PUSH_DATA (push, (s->maxy << 16) | s->miny);
 #endif
+   }
+
+   nv50->scissors_dirty = 0;
 }
 
 static void
@@ -210,24 +232,34 @@ nv50_validate_viewport(struct nv50_context *nv50)
 {
    struct nouveau_pushbuf *push = nv50->base.pushbuf;
    float zmin, zmax;
+   int i;
 
-   BEGIN_NV04(push, NV50_3D(VIEWPORT_TRANSLATE_X(0)), 3);
-   PUSH_DATAf(push, nv50->viewport.translate[0]);
-   PUSH_DATAf(push, nv50->viewport.translate[1]);
-   PUSH_DATAf(push, nv50->viewport.translate[2]);
-   BEGIN_NV04(push, NV50_3D(VIEWPORT_SCALE_X(0)), 3);
-   PUSH_DATAf(push, nv50->viewport.scale[0]);
-   PUSH_DATAf(push, nv50->viewport.scale[1]);
-   PUSH_DATAf(push, nv50->viewport.scale[2]);
+   for (i = 0; i < NV50_MAX_VIEWPORTS; i++) {
+      struct pipe_viewport_state *vpt = &nv50->viewports[i];
 
-   zmin = nv50->viewport.translate[2] - fabsf(nv50->viewport.scale[2]);
-   zmax = nv50->viewport.translate[2] + fabsf(nv50->viewport.scale[2]);
+      if (!(nv50->viewports_dirty & (1 << i)))
+         continue;
+
+      BEGIN_NV04(push, NV50_3D(VIEWPORT_TRANSLATE_X(i)), 3);
+      PUSH_DATAf(push, vpt->translate[0]);
+      PUSH_DATAf(push, vpt->translate[1]);
+      PUSH_DATAf(push, vpt->translate[2]);
+      BEGIN_NV04(push, NV50_3D(VIEWPORT_SCALE_X(i)), 3);
+      PUSH_DATAf(push, vpt->scale[0]);
+      PUSH_DATAf(push, vpt->scale[1]);
+      PUSH_DATAf(push, vpt->scale[2]);
+
+      zmin = vpt->translate[2] - fabsf(vpt->scale[2]);
+      zmax = vpt->translate[2] + fabsf(vpt->scale[2]);
 
 #ifdef NV50_SCISSORS_CLIPPING
-   BEGIN_NV04(push, NV50_3D(DEPTH_RANGE_NEAR(0)), 2);
-   PUSH_DATAf(push, zmin);
-   PUSH_DATAf(push, zmax);
+      BEGIN_NV04(push, NV50_3D(DEPTH_RANGE_NEAR(i)), 2);
+      PUSH_DATAf(push, zmin);
+      PUSH_DATAf(push, zmax);
 #endif
+   }
+
+   nv50->viewports_dirty = 0;
 }
 
 static INLINE void