softpipe: implement some support for multiple viewports
authorEdward O'Callaghan <eocallaghan@alterapraxis.com>
Fri, 11 Dec 2015 11:43:30 +0000 (22:43 +1100)
committerRoland Scheidegger <sroland@vmware.com>
Fri, 11 Dec 2015 19:09:21 +0000 (20:09 +0100)
Mostly related to making sure the rasterizer can correctly
pick out the correct scissor box for the current viewport.

Signed-off-by: Edward O'Callaghan <eocallaghan@alterapraxis.com>
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
src/gallium/drivers/softpipe/sp_context.h
src/gallium/drivers/softpipe/sp_quad.h
src/gallium/drivers/softpipe/sp_quad_depth_test.c
src/gallium/drivers/softpipe/sp_setup.c
src/gallium/drivers/softpipe/sp_setup.h
src/gallium/drivers/softpipe/sp_state_clip.c
src/gallium/drivers/softpipe/sp_state_derived.c
src/gallium/drivers/softpipe/sp_surface.c

index 073b71a913ede6d7bc2cb14dcbb842bb507ed979..8e5e24217a5213dac45ef63837a24c26961325d6 100644 (file)
@@ -79,10 +79,10 @@ struct softpipe_context {
    struct pipe_resource *constants[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS];
    struct pipe_framebuffer_state framebuffer;
    struct pipe_poly_stipple poly_stipple;
-   struct pipe_scissor_state scissor;
+   struct pipe_scissor_state scissors[PIPE_MAX_VIEWPORTS];
    struct pipe_sampler_view *sampler_views[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_SAMPLER_VIEWS];
 
-   struct pipe_viewport_state viewport;
+   struct pipe_viewport_state viewports[PIPE_MAX_VIEWPORTS];
    struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
    struct pipe_index_buffer index_buffer;
    struct pipe_resource *mapped_vs_tex[PIPE_MAX_SHADER_SAMPLER_VIEWS];
@@ -123,6 +123,9 @@ struct softpipe_context {
    /** Which vertex shader output slot contains point size */
    int psize_slot;
 
+   /** Which vertex shader output slot contains viewport index */
+   int viewport_index_slot;
+
    /** Which vertex shader output slot contains layer */
    int layer_slot;
 
@@ -140,7 +143,7 @@ struct softpipe_context {
    unsigned reduced_prim;
 
    /** Derived from scissor and surface bounds: */
-   struct pipe_scissor_state cliprect;
+   struct pipe_scissor_state cliprect[PIPE_MAX_VIEWPORTS];
 
    unsigned line_stipple_counter;
 
index b29dad2ea957c4066dd524a1556c1431e2391eef..2c2b018a24f4088f1e1b4a13d7227e364552996c 100644 (file)
@@ -63,6 +63,7 @@ struct quad_header_input
 {
    int x0, y0;                /**< quad window pos, always even */
    unsigned layer;
+   unsigned viewport_index;
    float coverage[TGSI_QUAD_SIZE]; /**< fragment coverage for antialiasing */
    unsigned facing:1;         /**< Front (0) or back (1) facing? */
    unsigned prim:2;           /**< QUAD_PRIM_POINT, LINE, TRI */
index bac40c013b30e3d143d0403b3deffe5c54722eb4..4cce9e9bc127e5b957951f1ef898ee8e89021f97 100644 (file)
@@ -785,6 +785,7 @@ depth_test_quads_fallback(struct quad_stage *qs,
    boolean interp_depth = !fsInfo->writes_z;
    boolean shader_stencil_ref = fsInfo->writes_stencil;
    struct depth_data data;
+   unsigned vp_idx = quads[0]->input.viewport_index;
 
    data.use_shader_stencil_refs = FALSE;
 
@@ -804,8 +805,8 @@ depth_test_quads_fallback(struct quad_stage *qs,
                                      quads[0]->input.y0, quads[0]->input.layer);
       data.clamp = !qs->softpipe->rasterizer->depth_clip;
 
-      near_val = qs->softpipe->viewport.translate[2] - qs->softpipe->viewport.scale[2];
-      far_val = near_val + (qs->softpipe->viewport.scale[2] * 2.0);
+      near_val = qs->softpipe->viewports[vp_idx].translate[2] - qs->softpipe->viewports[vp_idx].scale[2];
+      far_val = near_val + (qs->softpipe->viewports[vp_idx].scale[2] * 2.0);
       data.minval = MIN2(near_val, far_val);
       data.maxval = MAX2(near_val, far_val);
 
index 973803e909d6908c8b8577bf7d0a1201ddf94189..ac2d97825ce9c9406b7a22adcbfc8d66ddc92142 100644 (file)
@@ -128,7 +128,8 @@ struct setup_context {
 static inline void
 quad_clip(struct setup_context *setup, struct quad_header *quad)
 {
-   const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
+   unsigned viewport_index = quad[0].input.viewport_index;
+   const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect[viewport_index];
    const int minx = (int) cliprect->minx;
    const int maxx = (int) cliprect->maxx;
    const int miny = (int) cliprect->miny;
@@ -159,7 +160,7 @@ quad_clip(struct setup_context *setup, struct quad_header *quad)
 static inline void
 clip_emit_quad(struct setup_context *setup, struct quad_header *quad)
 {
-   quad_clip( setup, quad );
+   quad_clip(setup, quad);
 
    if (quad->inout.mask) {
       struct softpipe_context *sp = setup->softpipe;
@@ -707,9 +708,10 @@ static void
 subtriangle(struct setup_context *setup,
             struct edge *eleft,
             struct edge *eright,
-            int lines)
+            int lines,
+            unsigned viewport_index)
 {
-   const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
+   const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect[viewport_index];
    const int minx = (int) cliprect->minx;
    const int maxx = (int) cliprect->maxx;
    const int miny = (int) cliprect->miny;
@@ -807,6 +809,7 @@ sp_setup_tri(struct setup_context *setup,
 {
    float det;
    uint layer = 0;
+   unsigned viewport_index = 0;
 #if DEBUG_VERTS
    debug_printf("Setup triangle:\n");
    print_vertex(setup, v0);
@@ -845,19 +848,25 @@ sp_setup_tri(struct setup_context *setup,
    }
    setup->quad[0].input.layer = layer;
 
+   if (setup->softpipe->viewport_index_slot > 0) {
+      unsigned *udata = (unsigned*)v0[setup->softpipe->viewport_index_slot];
+      viewport_index = sp_clamp_viewport_idx(*udata);
+   }
+   setup->quad[0].input.viewport_index = viewport_index;
+
    /*   init_constant_attribs( setup ); */
 
    if (setup->oneoverarea < 0.0) {
       /* emaj on left:
        */
-      subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines );
-      subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines );
+      subtriangle(setup, &setup->emaj, &setup->ebot, setup->ebot.lines, viewport_index);
+      subtriangle(setup, &setup->emaj, &setup->etop, setup->etop.lines, viewport_index);
    }
    else {
       /* emaj on right:
        */
-      subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines );
-      subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines );
+      subtriangle(setup, &setup->ebot, &setup->emaj, setup->ebot.lines, viewport_index);
+      subtriangle(setup, &setup->etop, &setup->emaj, setup->etop.lines, viewport_index);
    }
 
    flush_spans( setup );
@@ -1054,7 +1063,7 @@ plot(struct setup_context *setup, int x, int y)
       /* flush prev quad, start new quad */
 
       if (setup->quad[0].input.x0 != -1)
-         clip_emit_quad( setup, &setup->quad[0] );
+         clip_emit_quad(setup, &setup->quad[0]);
 
       setup->quad[0].input.x0 = quadX;
       setup->quad[0].input.y0 = quadY;
@@ -1083,6 +1092,7 @@ sp_setup_line(struct setup_context *setup,
    int dy = y1 - y0;
    int xstep, ystep;
    uint layer = 0;
+   unsigned viewport_index = 0;
 
 #if DEBUG_VERTS
    debug_printf("Setup line:\n");
@@ -1132,6 +1142,12 @@ sp_setup_line(struct setup_context *setup,
    }
    setup->quad[0].input.layer = layer;
 
+   if (setup->softpipe->viewport_index_slot > 0) {
+      unsigned *udata = (unsigned*)setup->vprovoke[setup->softpipe->viewport_index_slot];
+      viewport_index = sp_clamp_viewport_idx(*udata);
+   }
+   setup->quad[0].input.viewport_index = viewport_index;
+
    /* XXX temporary: set coverage to 1.0 so the line appears
     * if AA mode happens to be enabled.
     */
@@ -1183,7 +1199,7 @@ sp_setup_line(struct setup_context *setup,
 
    /* draw final quad */
    if (setup->quad[0].inout.mask) {
-      clip_emit_quad( setup, &setup->quad[0] );
+      clip_emit_quad(setup, &setup->quad[0]);
    }
 }
 
@@ -1223,6 +1239,7 @@ sp_setup_point(struct setup_context *setup,
    const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
    uint fragSlot;
    uint layer = 0;
+   unsigned viewport_index = 0;
 #if DEBUG_VERTS
    debug_printf("Setup point:\n");
    print_vertex(setup, v0);
@@ -1239,6 +1256,12 @@ sp_setup_point(struct setup_context *setup,
    }
    setup->quad[0].input.layer = layer;
 
+   if (setup->softpipe->viewport_index_slot > 0) {
+      unsigned *udata = (unsigned*)v0[setup->softpipe->viewport_index_slot];
+      viewport_index = sp_clamp_viewport_idx(*udata);
+   }
+   setup->quad[0].input.viewport_index = viewport_index;
+
    /* For points, all interpolants are constant-valued.
     * However, for point sprites, we'll need to setup texcoords appropriately.
     * XXX: which coefficients are the texcoords???
@@ -1300,7 +1323,7 @@ sp_setup_point(struct setup_context *setup,
       setup->quad[0].input.x0 = (int) x - ix;
       setup->quad[0].input.y0 = (int) y - iy;
       setup->quad[0].inout.mask = (1 << ix) << (2 * iy);
-      clip_emit_quad( setup, &setup->quad[0] );
+      clip_emit_quad(setup, &setup->quad[0]);
    }
    else {
       if (round) {
@@ -1361,7 +1384,7 @@ sp_setup_point(struct setup_context *setup,
                if (setup->quad[0].inout.mask) {
                   setup->quad[0].input.x0 = ix;
                   setup->quad[0].input.y0 = iy;
-                  clip_emit_quad( setup, &setup->quad[0] );
+                  clip_emit_quad(setup, &setup->quad[0]);
                }
             }
          }
@@ -1408,7 +1431,7 @@ sp_setup_point(struct setup_context *setup,
                setup->quad[0].inout.mask = mask;
                setup->quad[0].input.x0 = ix;
                setup->quad[0].input.y0 = iy;
-               clip_emit_quad( setup, &setup->quad[0] );
+               clip_emit_quad(setup, &setup->quad[0]);
             }
          }
       }
index 885be739033f72f76407c6600298d11bed7a9291..191494acbb83ca73cc831fb43cd2e2091232f404 100644 (file)
@@ -45,6 +45,11 @@ void
 sp_setup_point( struct setup_context *setup,
              const float (*v0)[4] );
 
+static inline unsigned
+sp_clamp_viewport_idx(int idx)
+{
+   return (PIPE_MAX_VIEWPORTS > idx && idx >= 0) ? idx : 0;
+}
 
 struct setup_context *sp_setup_create_context( struct softpipe_context *softpipe );
 void sp_setup_prepare( struct setup_context *setup );
index 59c22c6a67c400e5cfffaea80abaac7920db18ef..4de6296fce5300a25c038d716e609d8d664678f7 100644 (file)
@@ -47,15 +47,16 @@ static void
 softpipe_set_viewport_states(struct pipe_context *pipe,
                              unsigned start_slot,
                              unsigned num_viewports,
-                             const struct pipe_viewport_state *viewport)
+                             const struct pipe_viewport_state *viewports)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
 
    /* pass the viewport info to the draw module */
    draw_set_viewport_states(softpipe->draw, start_slot, num_viewports,
-                            viewport);
+                            viewports);
 
-   softpipe->viewport = *viewport; /* struct copy */
+   memcpy(softpipe->viewports + start_slot, viewports,
+          sizeof(struct pipe_viewport_state) * num_viewports);
    softpipe->dirty |= SP_NEW_VIEWPORT;
 }
 
@@ -64,13 +65,17 @@ static void
 softpipe_set_scissor_states(struct pipe_context *pipe,
                             unsigned start_slot,
                             unsigned num_scissors,
-                            const struct pipe_scissor_state *scissor)
+                            const struct pipe_scissor_state *scissors)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
 
    draw_flush(softpipe->draw);
 
-   softpipe->scissor = *scissor; /* struct copy */
+   debug_assert(start_slot < PIPE_MAX_VIEWPORTS);
+   debug_assert((start_slot + num_scissors) <= PIPE_MAX_VIEWPORTS);
+
+   memcpy(softpipe->scissors + start_slot, scissors,
+          sizeof(struct pipe_scissor_state) * num_scissors);
    softpipe->dirty |= SP_NEW_SCISSOR;
 }
 
index 2a6a6f47f55d72118dfc6f6bfce69a643e2a2787..7e998af1325f620717f7dcc647d44ef0cee8eb89 100644 (file)
@@ -64,6 +64,7 @@ struct vertex_info *
 softpipe_get_vertex_info(struct softpipe_context *softpipe)
 {
    struct vertex_info *vinfo = &softpipe->vertex_info;
+   int vs_index;
 
    if (vinfo->num_attribs == 0) {
       /* compute vertex layout now */
@@ -135,17 +136,35 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe)
          draw_emit_vertex_attr(vinfo, EMIT_4F, interp, src);
       }
 
-      softpipe->psize_slot = draw_find_shader_output(softpipe->draw,
-                                                 TGSI_SEMANTIC_PSIZE, 0);
-      if (softpipe->psize_slot >= 0) {
-         draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT,
-                               softpipe->psize_slot);
+      /* Figure out if we need pointsize as well. */
+      vs_index = draw_find_shader_output(softpipe->draw,
+                                         TGSI_SEMANTIC_PSIZE, 0);
+
+      if (vs_index >= 0) {
+         softpipe->psize_slot = vinfo->num_attribs;
+         draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, vs_index);
+      }
+
+      /* Figure out if we need viewport index */
+      vs_index = draw_find_shader_output(softpipe->draw,
+                                         TGSI_SEMANTIC_VIEWPORT_INDEX,
+                                         0);
+      if (vs_index >= 0) {
+         softpipe->viewport_index_slot = vinfo->num_attribs;
+         draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, vs_index);
+      } else {
+         softpipe->viewport_index_slot = 0;
       }
 
-      softpipe->layer_slot = draw_find_shader_output(softpipe->draw,
-                                         TGSI_SEMANTIC_LAYER, 0);
-      if (softpipe->layer_slot >= 0) {
-         draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, softpipe->layer_slot);
+      /* Figure out if we need layer */
+      vs_index = draw_find_shader_output(softpipe->draw,
+                                         TGSI_SEMANTIC_LAYER,
+                                         0);
+      if (vs_index >= 0) {
+         softpipe->layer_slot = vinfo->num_attribs;
+         draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, vs_index);
+      } else {
+         softpipe->layer_slot = 0;
       }
 
       draw_compute_vertex_size(vinfo);
@@ -183,30 +202,33 @@ softpipe_get_vbuf_vertex_info(struct softpipe_context *softpipe)
 static void
 compute_cliprect(struct softpipe_context *sp)
 {
+   unsigned i;
    /* SP_NEW_FRAMEBUFFER
     */
    uint surfWidth = sp->framebuffer.width;
    uint surfHeight = sp->framebuffer.height;
 
-   /* SP_NEW_RASTERIZER
-    */
-   if (sp->rasterizer->scissor) {
-
-      /* SP_NEW_SCISSOR
-       *
-       * clip to scissor rect:
+   for (i = 0; i < PIPE_MAX_VIEWPORTS; i++) {
+      /* SP_NEW_RASTERIZER
        */
-      sp->cliprect.minx = MAX2(sp->scissor.minx, 0);
-      sp->cliprect.miny = MAX2(sp->scissor.miny, 0);
-      sp->cliprect.maxx = MIN2(sp->scissor.maxx, surfWidth);
-      sp->cliprect.maxy = MIN2(sp->scissor.maxy, surfHeight);
-   }
-   else {
-      /* clip to surface bounds */
-      sp->cliprect.minx = 0;
-      sp->cliprect.miny = 0;
-      sp->cliprect.maxx = surfWidth;
-      sp->cliprect.maxy = surfHeight;
+      if (sp->rasterizer->scissor) {
+
+         /* SP_NEW_SCISSOR
+          *
+          * clip to scissor rect:
+          */
+         sp->cliprect[i].minx = MAX2(sp->scissors[i].minx, 0);
+         sp->cliprect[i].miny = MAX2(sp->scissors[i].miny, 0);
+         sp->cliprect[i].maxx = MIN2(sp->scissors[i].maxx, surfWidth);
+         sp->cliprect[i].maxy = MIN2(sp->scissors[i].maxy, surfHeight);
+      }
+      else {
+         /* clip to surface bounds */
+         sp->cliprect[i].minx = 0;
+         sp->cliprect[i].miny = 0;
+         sp->cliprect[i].maxx = surfWidth;
+         sp->cliprect[i].maxy = surfHeight;
+      }
    }
 }
 
index 768e8989b204588aedb3fd4d7af4d59e50903ecd..e2ecbdf2b01cd2ea1d5a6cdfc332fbba6acd84f8 100644 (file)
@@ -67,8 +67,8 @@ static void sp_blit(struct pipe_context *pipe,
    util_blitter_save_so_targets(sp->blitter, sp->num_so_targets,
                      (struct pipe_stream_output_target**)sp->so_targets);
    util_blitter_save_rasterizer(sp->blitter, sp->rasterizer);
-   util_blitter_save_viewport(sp->blitter, &sp->viewport);
-   util_blitter_save_scissor(sp->blitter, &sp->scissor);
+   util_blitter_save_viewport(sp->blitter, &sp->viewports[0]);
+   util_blitter_save_scissor(sp->blitter, &sp->scissors[0]);
    util_blitter_save_fragment_shader(sp->blitter, sp->fs);
    util_blitter_save_blend(sp->blitter, sp->blend);
    util_blitter_save_depth_stencil_alpha(sp->blitter, sp->depth_stencil);