[Mesa-dev] [PATCH 4/4] llvmpipe: implement support for multiple viewports

Roland Scheidegger sroland at vmware.com
Thu May 23 14:32:33 PDT 2013


Am 23.05.2013 22:33, schrieb Zack Rusin:
> 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 at vmware.com>
> ---
>  src/gallium/drivers/llvmpipe/lp_context.h       |    9 ++++--
>  src/gallium/drivers/llvmpipe/lp_screen.c        |    2 +-
>  src/gallium/drivers/llvmpipe/lp_setup.c         |   34 +++++++++++++++--------
>  src/gallium/drivers/llvmpipe/lp_setup.h         |    5 ++--
>  src/gallium/drivers/llvmpipe/lp_setup_context.h |    9 ++++--
>  src/gallium/drivers/llvmpipe/lp_setup_line.c    |   12 ++++++--
>  src/gallium/drivers/llvmpipe/lp_setup_point.c   |   12 +++++---
>  src/gallium/drivers/llvmpipe/lp_setup_tri.c     |   17 ++++++++----
>  src/gallium/drivers/llvmpipe/lp_state_clip.c    |    8 ++++--
>  src/gallium/drivers/llvmpipe/lp_state_derived.c |   15 +++++++++-
>  src/gallium/drivers/llvmpipe/lp_surface.c       |    4 +--
>  11 files changed, 91 insertions(+), 36 deletions(-)
> 
> diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h
> index d605dba..444c768 100644
> --- a/src/gallium/drivers/llvmpipe/lp_context.h
> +++ b/src/gallium/drivers/llvmpipe/lp_context.h
> @@ -75,10 +75,12 @@ 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];
> +   unsigned num_scissors;
>     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];
> +   unsigned num_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 +118,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;
>     
> diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
> index 712b7c6..9c4de72 100644
> --- a/src/gallium/drivers/llvmpipe/lp_screen.c
> +++ b/src/gallium/drivers/llvmpipe/lp_screen.c
> @@ -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_MULTIPLE_VIEWPORTS:
> -      return 0;
> +      return 1;
>     }
>     /* should only get here on unhandled cases */
>     debug_printf("Unexpected PIPE_CAP %d query\n", param);
> diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c
> index 9fef34e..caa168d 100644
> --- a/src/gallium/drivers/llvmpipe/lp_setup.c
> +++ b/src/gallium/drivers/llvmpipe/lp_setup.c
> @@ -616,17 +616,23 @@ 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,
> +                       unsigned num_scissors,
> +                       const struct pipe_scissor_state *scissors )
>  {
> +   unsigned i;
>     LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
>  
> -   assert(scissor);
> +   assert(scissors);
> +
> +   setup->num_scissors = num_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 < num_scissors; ++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;
>  }
>  
> @@ -1012,10 +1018,15 @@ 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;
> +      /* we always need at least one draw region */
> +      setup->draw_regions[0] = setup->framebuffer;
> +      for (i = 0; i < setup->num_scissors; ++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
> @@ -1061,6 +1072,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);
>  
> diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h
> index 802ab01..68c710b 100644
> --- a/src/gallium/drivers/llvmpipe/lp_setup.h
> +++ b/src/gallium/drivers/llvmpipe/lp_setup.h
> @@ -117,8 +117,9 @@ 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,
> +                       unsigned num_scissors,
> +                       const struct pipe_scissor_state *scissors );
>  
>  void
>  lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
> diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h
> index 6b35a02..da85f78 100644
> --- a/src/gallium/drivers/llvmpipe/lp_setup_context.h
> +++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h
> @@ -103,11 +103,13 @@ 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];
> +   unsigned num_scissors;
> +   struct u_rect draw_regions[PIPE_MAX_VIEWPORTS];   /* intersection of fb & scissor */
>  
>     struct {
>        unsigned flags;
> @@ -195,6 +197,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
> diff --git a/src/gallium/drivers/llvmpipe/lp_setup_line.c b/src/gallium/drivers/llvmpipe/lp_setup_line.c
> index 54f19cb..c2a069f 100644
> --- a/src/gallium/drivers/llvmpipe/lp_setup_line.c
> +++ b/src/gallium/drivers/llvmpipe/lp_setup_line.c
> @@ -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);
>  }
>  
>  
> diff --git a/src/gallium/drivers/llvmpipe/lp_setup_point.c b/src/gallium/drivers/llvmpipe/lp_setup_point.c
> index 146f1bd..30ce7490 100644
> --- a/src/gallium/drivers/llvmpipe/lp_setup_point.c
> +++ b/src/gallium/drivers/llvmpipe/lp_setup_point.c
> @@ -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);
>  }
>  
>  
> diff --git a/src/gallium/drivers/llvmpipe/lp_setup_tri.c b/src/gallium/drivers/llvmpipe/lp_setup_tri.c
> index b2c8cb5..c1ba52e 100644
> --- a/src/gallium/drivers/llvmpipe/lp_setup_tri.c
> +++ b/src/gallium/drivers/llvmpipe/lp_setup_tri.c
> @@ -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
>      */
> diff --git a/src/gallium/drivers/llvmpipe/lp_state_clip.c b/src/gallium/drivers/llvmpipe/lp_state_clip.c
> index ed47e5e..e33d82a 100644
> --- a/src/gallium/drivers/llvmpipe/lp_state_clip.c
> +++ b/src/gallium/drivers/llvmpipe/lp_state_clip.c
> @@ -53,7 +53,9 @@ llvmpipe_set_viewport_states(struct pipe_context *pipe,
>     /* pass the viewport info to the draw module */
>     draw_set_viewport_states(llvmpipe->draw, num_viewports, viewports);
>  
> -   llvmpipe->viewport = *viewports; /* struct copy */
> +   memcpy(llvmpipe->viewports, viewports,
> +          sizeof(struct pipe_viewport_state) * num_viewports);
> +   llvmpipe->num_viewports = num_viewports;
>     llvmpipe->dirty |= LP_NEW_VIEWPORT;
>  }
>  
> @@ -67,7 +69,9 @@ llvmpipe_set_scissor_states(struct pipe_context *pipe,
>  
>     draw_flush(llvmpipe->draw);
>  
> -   llvmpipe->scissor = *scissors; /* struct copy */
> +   llvmpipe->num_scissors = num_scissors;
> +   memcpy(llvmpipe->scissors, scissors,
> +          sizeof(struct pipe_scissor_state) * num_scissors);
>     llvmpipe->dirty |= LP_NEW_SCISSOR;
>  }
>  
> diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c
> index aef222d..9002139 100644
> --- a/src/gallium/drivers/llvmpipe/lp_state_derived.c
> +++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c
> @@ -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) {
Couldn't vs_index legitimately be output zero?
Though I guess that would be more a problem with draw_find_shader_output
(as it returns 0 for not found indices) than viewport index here
specifically.



> +      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,8 @@ 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->num_scissors,
> +                            llvmpipe->scissors);
>  
>     if (llvmpipe->dirty & LP_NEW_DEPTH_STENCIL_ALPHA) {
>        lp_setup_set_alpha_ref_value(llvmpipe->setup, 
> diff --git a/src/gallium/drivers/llvmpipe/lp_surface.c b/src/gallium/drivers/llvmpipe/lp_surface.c
> index 036b129..5a174f6 100644
> --- a/src/gallium/drivers/llvmpipe/lp_surface.c
> +++ b/src/gallium/drivers/llvmpipe/lp_surface.c
> @@ -214,8 +214,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_viewports(lp->blitter, 1, &lp->viewport);
> -   util_blitter_save_scissors(lp->blitter, 1, &lp->scissor);
> +   util_blitter_save_viewports(lp->blitter, lp->num_viewports, lp->viewports);
> +   util_blitter_save_scissors(lp->blitter, lp->num_scissors, lp->scissors);
>     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);
> 

Otherwise looks good.

Roland


More information about the mesa-dev mailing list