llvmpipe: implement support for multiple viewports
authorZack Rusin <zackr@vmware.com>
Fri, 24 May 2013 20:28:19 +0000 (16:28 -0400)
committerZack Rusin <zackr@vmware.com>
Sat, 25 May 2013 13:49:20 +0000 (09:49 -0400)
Largely related to making sure the rasterizer can correctly
pick out the correct scissor box for the current viewport.

Signed-off-by: Zack Rusin <zackr@vmware.com>
Reviewed-by: José Fonseca<jfonseca@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_screen.c
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_setup.h
src/gallium/drivers/llvmpipe/lp_setup_context.h
src/gallium/drivers/llvmpipe/lp_setup_line.c
src/gallium/drivers/llvmpipe/lp_setup_point.c
src/gallium/drivers/llvmpipe/lp_setup_tri.c
src/gallium/drivers/llvmpipe/lp_state_clip.c
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_surface.c

index d605dba2260c76992c676b96884f97f2a1f6d88a..54f38303ae520a3e5092418be75ac23adebfe58a 100644 (file)
@@ -75,10 +75,10 @@ struct llvmpipe_context {
    struct pipe_constant_buffer constants[PIPE_SHADER_TYPES][LP_MAX_TGSI_CONST_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];
@@ -116,6 +116,9 @@ struct llvmpipe_context {
    /** Which vertex shader output slot contains point size */
    int psize_slot;
 
+   /** Which vertex shader output slot contains viewport index */
+   int viewport_index_slot;
+
    /**< minimum resolvable depth value, for polygon offset */   
    double mrd;
    
index 35630b95249f11ef379e2d33449acc54b7b7330b..562fb518b28c593aa77cab169a7916e636f8e478 100644 (file)
@@ -231,7 +231,7 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER:
       return 0;
    case PIPE_CAP_MAX_VIEWPORTS:
-      return 1;
+      return PIPE_MAX_VIEWPORTS;
    }
    /* should only get here on unhandled cases */
    debug_printf("Unexpected PIPE_CAP %d query\n", param);
index a6dce24bec29bff77c0dac21221a2b3fddbcbb21..0134b700096b1538b4a9235f6dc38c4b3e076bd5 100644 (file)
@@ -616,17 +616,20 @@ lp_setup_set_blend_color( struct lp_setup_context *setup,
 
 
 void
-lp_setup_set_scissor( struct lp_setup_context *setup,
-                      const struct pipe_scissor_state *scissor )
+lp_setup_set_scissors( struct lp_setup_context *setup,
+                       const struct pipe_scissor_state *scissors )
 {
+   unsigned i;
    LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   assert(scissor);
+   assert(scissors);
 
-   setup->scissor.x0 = scissor->minx;
-   setup->scissor.x1 = scissor->maxx-1;
-   setup->scissor.y0 = scissor->miny;
-   setup->scissor.y1 = scissor->maxy-1;
+   for (i = 0; i < PIPE_MAX_VIEWPORTS; ++i) {
+      setup->scissors[i].x0 = scissors[i].minx;
+      setup->scissors[i].x1 = scissors[i].maxx-1;
+      setup->scissors[i].y0 = scissors[i].miny;
+      setup->scissors[i].y1 = scissors[i].maxy-1;
+   }
    setup->dirty |= LP_SETUP_NEW_SCISSOR;
 }
 
@@ -1010,10 +1013,13 @@ try_update_scene_state( struct lp_setup_context *setup )
    }
 
    if (setup->dirty & LP_SETUP_NEW_SCISSOR) {
-      setup->draw_region = setup->framebuffer;
-      if (setup->scissor_test) {
-         u_rect_possible_intersection(&setup->scissor,
-                                      &setup->draw_region);
+      unsigned i;
+      for (i = 0; i < PIPE_MAX_VIEWPORTS; ++i) {
+         setup->draw_regions[i] = setup->framebuffer;
+         if (setup->scissor_test) {
+            u_rect_possible_intersection(&setup->scissors[i],
+                                         &setup->draw_regions[i]);
+         }
       }
       /* If the framebuffer is large we have to think about fixed-point
        * integer overflow.  For 2K by 2K images, coordinates need 15 bits
@@ -1059,6 +1065,7 @@ lp_setup_update_state( struct lp_setup_context *setup,
        * to know about vertex shader point size attribute.
        */
       setup->psize = lp->psize_slot;
+      setup->viewport_index_slot = lp->viewport_index_slot;
 
       assert(lp->dirty == 0);
 
index 802ab0105e813423738aef1bac0ffc32f5644356..1f55aa41c7f8674e098b642705c5a85981826d7c 100644 (file)
@@ -117,8 +117,8 @@ lp_setup_set_blend_color( struct lp_setup_context *setup,
                           const struct pipe_blend_color *blend_color );
 
 void
-lp_setup_set_scissor( struct lp_setup_context *setup,
-                      const struct pipe_scissor_state *scissor );
+lp_setup_set_scissors( struct lp_setup_context *setup,
+                       const struct pipe_scissor_state *scissors );
 
 void
 lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
index 6b35a0209ca78c9aeddf9b6c3503b880d5349e9d..62d5a3c5796595e9fa90bd79f50b1625745f6d2a 100644 (file)
@@ -103,11 +103,12 @@ struct lp_setup_context
    float line_width;
    float point_size;
    float psize;
+   unsigned viewport_index_slot;
 
    struct pipe_framebuffer_state fb;
    struct u_rect framebuffer;
-   struct u_rect scissor;
-   struct u_rect draw_region;   /* intersection of fb & scissor */
+   struct u_rect scissors[PIPE_MAX_VIEWPORTS];
+   struct u_rect draw_regions[PIPE_MAX_VIEWPORTS];   /* intersection of fb & scissor */
 
    struct {
       unsigned flags;
@@ -195,6 +196,7 @@ boolean
 lp_setup_bin_triangle( struct lp_setup_context *setup,
                        struct lp_rast_triangle *tri,
                        const struct u_rect *bbox,
-                       int nr_planes );
+                       int nr_planes,
+                       unsigned scissor_index );
 
 #endif
index 54f19cb9f3c3ed20fc67b13c82de7c665c3bc106..c2a069fe0663d5d5d086056f4410d8346e9d8ab6 100644 (file)
@@ -289,6 +289,7 @@ try_setup_line( struct lp_setup_context *setup,
    int y[4];
    int i;
    int nr_planes = 4;
+   unsigned scissor_index = 0;
    
    /* linewidth should be interpreted as integer */
    int fixed_width = util_iround(width) * FIXED_ONE;
@@ -315,6 +316,10 @@ try_setup_line( struct lp_setup_context *setup,
 
    if (setup->scissor_test) {
       nr_planes = 8;
+      if (setup->viewport_index_slot > 0) {
+         unsigned *udata = (unsigned*)v1[setup->viewport_index_slot];
+         scissor_index = *udata;
+      }
    }
    else {
       nr_planes = 4;
@@ -563,7 +568,7 @@ try_setup_line( struct lp_setup_context *setup,
       return TRUE;
    }
 
-   if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
+   if (!u_rect_test_intersection(&setup->draw_regions[scissor_index], &bbox)) {
       if (0) debug_printf("offscreen\n");
       LP_COUNT(nr_culled_tris);
       return TRUE;
@@ -672,7 +677,8 @@ try_setup_line( struct lp_setup_context *setup,
     * these planes elsewhere.
     */
    if (nr_planes == 8) {
-      const struct u_rect *scissor = &setup->scissor;
+      const struct u_rect *scissor =
+         &setup->scissors[scissor_index];
 
       plane[4].dcdx = -1;
       plane[4].dcdy = 0;
@@ -695,7 +701,7 @@ try_setup_line( struct lp_setup_context *setup,
       plane[7].eo = 0;
    }
 
-   return lp_setup_bin_triangle(setup, line, &bbox, nr_planes);
+   return lp_setup_bin_triangle(setup, line, &bbox, nr_planes, scissor_index);
 }
 
 
index 146f1bd07ca1f5c24ee731b3f17f9bbb95cbd27e..30ce7490de983531c6f5279a3f3bd349be5fcd6f 100644 (file)
@@ -324,8 +324,12 @@ try_setup_point( struct lp_setup_context *setup,
    struct u_rect bbox;
    unsigned nr_planes = 4;
    struct point_info info;
+   unsigned scissor_index = 0;
 
-
+   if (setup->viewport_index_slot > 0) {
+      unsigned *udata = (unsigned*)v0[setup->viewport_index_slot];
+      scissor_index = *udata;
+   }
    /* Bounding rectangle (in pixels) */
    {
       /* Yes this is necessary to accurately calculate bounding boxes
@@ -346,13 +350,13 @@ try_setup_point( struct lp_setup_context *setup,
       bbox.y1--;
    }
    
-   if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
+   if (!u_rect_test_intersection(&setup->draw_regions[scissor_index], &bbox)) {
       if (0) debug_printf("offscreen\n");
       LP_COUNT(nr_culled_tris);
       return TRUE;
    }
 
-   u_rect_find_intersection(&setup->draw_region, &bbox);
+   u_rect_find_intersection(&setup->draw_regions[scissor_index], &bbox);
 
    point = lp_setup_alloc_triangle(scene,
                                    key->num_inputs,
@@ -407,7 +411,7 @@ try_setup_point( struct lp_setup_context *setup,
       plane[3].eo = 0;
    }
 
-   return lp_setup_bin_triangle(setup, point, &bbox, nr_planes);
+   return lp_setup_bin_triangle(setup, point, &bbox, nr_planes, scissor_index);
 }
 
 
index b2c8cb5250091ebd4badd7423d36eabab68d0fa3..c1ba52e8ca66229eb28b9517b78c73411fef6de4 100644 (file)
@@ -246,6 +246,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
    struct u_rect bbox;
    unsigned tri_bytes;
    int nr_planes = 3;
+   unsigned scissor_index = 0;
 
    /* Area should always be positive here */
    assert(position->area > 0);
@@ -255,6 +256,10 @@ do_triangle_ccw(struct lp_setup_context *setup,
 
    if (setup->scissor_test) {
       nr_planes = 7;
+      if (setup->viewport_index_slot > 0) {
+         unsigned *udata = (unsigned*)v0[setup->viewport_index_slot];
+         scissor_index = *udata;
+      }
    }
    else {
       nr_planes = 3;
@@ -285,7 +290,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
       return TRUE;
    }
 
-   if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
+   if (!u_rect_test_intersection(&setup->draw_regions[scissor_index], &bbox)) {
       if (0) debug_printf("offscreen\n");
       LP_COUNT(nr_culled_tris);
       return TRUE;
@@ -491,7 +496,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
     * these planes elsewhere.
     */
    if (nr_planes == 7) {
-      const struct u_rect *scissor = &setup->scissor;
+      const struct u_rect *scissor = &setup->scissors[scissor_index];
 
       plane[3].dcdx = -1;
       plane[3].dcdy = 0;
@@ -514,7 +519,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
       plane[6].eo = 0;
    }
 
-   return lp_setup_bin_triangle( setup, tri, &bbox, nr_planes );
+   return lp_setup_bin_triangle( setup, tri, &bbox, nr_planes, scissor_index );
 }
 
 /*
@@ -548,7 +553,8 @@ boolean
 lp_setup_bin_triangle( struct lp_setup_context *setup,
                        struct lp_rast_triangle *tri,
                        const struct u_rect *bbox,
-                       int nr_planes )
+                       int nr_planes,
+                       unsigned scissor_index )
 {
    struct lp_scene *scene = setup->scene;
    struct u_rect trimmed_box = *bbox;   
@@ -570,7 +576,8 @@ lp_setup_bin_triangle( struct lp_setup_context *setup,
     * the rasterizer to also respect scissor, etc, just for the rare
     * cases where a small triangle extends beyond the scissor.
     */
-   u_rect_find_intersection(&setup->draw_region, &trimmed_box);
+   u_rect_find_intersection(&setup->draw_regions[scissor_index],
+                            &trimmed_box);
 
    /* Determine which tile(s) intersect the triangle's bounding box
     */
index a26c79f72f61f58d63e5c1cd027bb48625ae3e6f..0e027fa9128ae29c43b95134a7dff47d1941b2e4 100644 (file)
@@ -55,7 +55,8 @@ llvmpipe_set_viewport_states(struct pipe_context *pipe,
    draw_set_viewport_states(llvmpipe->draw, start_slot, num_viewports,
                             viewports);
 
-   llvmpipe->viewport = *viewports; /* struct copy */
+   memcpy(llvmpipe->viewports + start_slot, viewports,
+          sizeof(struct pipe_viewport_state) * num_viewports);
    llvmpipe->dirty |= LP_NEW_VIEWPORT;
 }
 
@@ -70,7 +71,8 @@ llvmpipe_set_scissor_states(struct pipe_context *pipe,
 
    draw_flush(llvmpipe->draw);
 
-   llvmpipe->scissor = *scissors; /* struct copy */
+   memcpy(llvmpipe->scissors + start_slot, scissors,
+          sizeof(struct pipe_scissor_state) * num_scissors);
    llvmpipe->dirty |= LP_NEW_SCISSOR;
 }
 
index aef222d20f63f1bbffe27e41a2d2e7a7fc346257..9c5e84722f1230e2e9e8e235c2beb573b0a130fe 100644 (file)
@@ -116,6 +116,18 @@ compute_vertex_info(struct llvmpipe_context *llvmpipe)
       draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, vs_index);
    }
 
+   /* Figure out if we need viewport index */
+   vs_index = draw_find_shader_output(llvmpipe->draw,
+                                      TGSI_SEMANTIC_VIEWPORT_INDEX,
+                                      0);
+   if (vs_index > 0) {
+      llvmpipe->viewport_index_slot = vinfo->num_attribs;
+      draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, vs_index);
+   } else {
+      llvmpipe->viewport_index_slot = 0;
+   }
+   
+
    draw_compute_vertex_size(vinfo);
    lp_setup_set_vertex_info(llvmpipe->setup, vinfo);
 }
@@ -164,7 +176,7 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
                                &llvmpipe->blend_color);
 
    if (llvmpipe->dirty & LP_NEW_SCISSOR)
-      lp_setup_set_scissor(llvmpipe->setup, &llvmpipe->scissor);
+      lp_setup_set_scissors(llvmpipe->setup, llvmpipe->scissors);
 
    if (llvmpipe->dirty & LP_NEW_DEPTH_STENCIL_ALPHA) {
       lp_setup_set_alpha_ref_value(llvmpipe->setup, 
index 961d0bcc734fc8fe2f1886fc4de8ec41f787e2ea..2019d52f09cc3d3321513d1b5468c534de6aed82 100644 (file)
@@ -212,8 +212,8 @@ static void lp_blit(struct pipe_context *pipe,
    util_blitter_save_so_targets(lp->blitter, lp->num_so_targets,
                                 (struct pipe_stream_output_target**)lp->so_targets);
    util_blitter_save_rasterizer(lp->blitter, (void*)lp->rasterizer);
-   util_blitter_save_viewport(lp->blitter, &lp->viewport);
-   util_blitter_save_scissor(lp->blitter, &lp->scissor);
+   util_blitter_save_viewport(lp->blitter, &lp->viewports[0]);
+   util_blitter_save_scissor(lp->blitter, &lp->scissors[0]);
    util_blitter_save_fragment_shader(lp->blitter, lp->fs);
    util_blitter_save_blend(lp->blitter, (void*)lp->blend);
    util_blitter_save_depth_stencil_alpha(lp->blitter, (void*)lp->depth_stencil);