Mesa (master): draw: implement support for multiple viewports

Zack Rusin zack at kemper.freedesktop.org
Wed May 29 22:08:54 UTC 2013


Module: Mesa
Branch: master
Commit: 7756aae815a26c533948081c2c319c20bcf5962c
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=7756aae815a26c533948081c2c319c20bcf5962c

Author: Zack Rusin <zackr at vmware.com>
Date:   Fri May 24 16:17:26 2013 -0400

draw: implement support for multiple viewports

This adds support for multiple viewports to the draw module.
Multiple viewports depend on the presence of geometry shaders
which can write the viewport index.

Signed-off-by: Zack Rusin <zackr at vmware.com>
Reviewed-by: José Fonseca<jfonseca at vmware.com>
Reviewed-by: Brian Paul <brianp at vmware.com>
Reviewed-by: Roland Scheidegger <sroland at vmware.com>

---

 src/gallium/auxiliary/draw/draw_cliptest_tmp.h     |   10 +++-
 src/gallium/auxiliary/draw/draw_context.c          |   52 ++++++++++++++++----
 src/gallium/auxiliary/draw/draw_gs.c               |   11 +++-
 src/gallium/auxiliary/draw/draw_gs.h               |    1 +
 src/gallium/auxiliary/draw/draw_pipe_clip.c        |   11 +++-
 src/gallium/auxiliary/draw/draw_private.h          |    8 ++--
 .../draw/draw_pt_fetch_shade_pipeline_llvm.c       |    4 +-
 src/gallium/auxiliary/draw/draw_vs.c               |    7 ---
 src/gallium/auxiliary/draw/draw_vs_variant.c       |   34 +++++++++++--
 9 files changed, 105 insertions(+), 33 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_cliptest_tmp.h b/src/gallium/auxiliary/draw/draw_cliptest_tmp.h
index 48f2349..09e1fd7 100644
--- a/src/gallium/auxiliary/draw/draw_cliptest_tmp.h
+++ b/src/gallium/auxiliary/draw/draw_cliptest_tmp.h
@@ -31,8 +31,6 @@ static boolean TAG(do_cliptest)( struct pt_post_vs *pvs,
                                  struct draw_vertex_info *info )
 {
    struct vertex_header *out = info->verts;
-   const float *scale = pvs->draw->viewport.scale;
-   const float *trans = pvs->draw->viewport.translate;
    /* const */ float (*plane)[4] = pvs->draw->plane;
    const unsigned pos = draw_current_shader_position_output(pvs->draw);
    const unsigned cv = draw_current_shader_clipvertex_output(pvs->draw);
@@ -44,6 +42,9 @@ static boolean TAG(do_cliptest)( struct pt_post_vs *pvs,
    unsigned j;
    unsigned i;
    bool have_cd = false;
+   unsigned viewport_index_output =
+      draw_current_shader_viewport_index_output(pvs->draw);
+      
    cd[0] = draw_current_shader_clipdistance_output(pvs->draw, 0);
    cd[1] = draw_current_shader_clipdistance_output(pvs->draw, 1);
   
@@ -52,7 +53,12 @@ static boolean TAG(do_cliptest)( struct pt_post_vs *pvs,
 
    for (j = 0; j < info->count; j++) {
       float *position = out->data[pos];
+      int viewport_index = 
+         draw_current_shader_uses_viewport_index(pvs->draw) ?
+         *((unsigned*)out->data[viewport_index_output]): 0;
       unsigned mask = 0x0;
+      const float *scale = pvs->draw->viewports[viewport_index].scale;
+      const float *trans = pvs->draw->viewports[viewport_index].translate;
   
       initialize_vertex_header(out);
 
diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c
index b555c65..4250f10 100644
--- a/src/gallium/auxiliary/draw/draw_context.c
+++ b/src/gallium/auxiliary/draw/draw_context.c
@@ -318,17 +318,24 @@ void draw_set_viewport_states( struct draw_context *draw,
 {
    const struct pipe_viewport_state *viewport = vps;
    draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE);
-   draw->viewport = *viewport; /* struct copy */
-   draw->identity_viewport = (viewport->scale[0] == 1.0f &&
-                              viewport->scale[1] == 1.0f &&
-                              viewport->scale[2] == 1.0f &&
-                              viewport->scale[3] == 1.0f &&
-                              viewport->translate[0] == 0.0f &&
-                              viewport->translate[1] == 0.0f &&
-                              viewport->translate[2] == 0.0f &&
-                              viewport->translate[3] == 0.0f);
 
-   draw_vs_set_viewport( draw, viewport );
+   if (start_slot > PIPE_MAX_VIEWPORTS)
+      return;
+
+   if ((start_slot + num_viewports) > PIPE_MAX_VIEWPORTS)
+      num_viewports = PIPE_MAX_VIEWPORTS - start_slot;
+
+   memcpy(draw->viewports + start_slot, vps,
+          sizeof(struct pipe_viewport_state) * num_viewports);
+   draw->identity_viewport = (num_viewports == 1) &&
+      (viewport->scale[0] == 1.0f &&
+       viewport->scale[1] == 1.0f &&
+       viewport->scale[2] == 1.0f &&
+       viewport->scale[3] == 1.0f &&
+       viewport->translate[0] == 0.0f &&
+       viewport->translate[1] == 0.0f &&
+       viewport->translate[2] == 0.0f &&
+       viewport->translate[3] == 0.0f);
 }
 
 
@@ -695,6 +702,31 @@ draw_current_shader_position_output(const struct draw_context *draw)
 
 /**
  * Return the index of the shader output which will contain the
+ * viewport index.
+ */
+uint
+draw_current_shader_viewport_index_output(const struct draw_context *draw)
+{
+   if (draw->gs.geometry_shader)
+      return draw->gs.geometry_shader->viewport_index_output;
+   return 0;
+}
+
+/**
+ * Returns true if there's a geometry shader bound and the geometry
+ * shader writes out a viewport index.
+ */
+boolean
+draw_current_shader_uses_viewport_index(const struct draw_context *draw)
+{
+   if (draw->gs.geometry_shader)
+      return draw->gs.geometry_shader->info.writes_viewport_index;
+   return FALSE;
+}
+
+
+/**
+ * Return the index of the shader output which will contain the
  * vertex position.
  */
 uint
diff --git a/src/gallium/auxiliary/draw/draw_gs.c b/src/gallium/auxiliary/draw/draw_gs.c
index fa0981e..67e5117 100644
--- a/src/gallium/auxiliary/draw/draw_gs.c
+++ b/src/gallium/auxiliary/draw/draw_gs.c
@@ -335,8 +335,13 @@ llvm_fetch_gs_outputs(struct draw_geometry_shader *shader,
       int i;
       for (i = 0; i < total_verts; ++i) {
          struct vertex_header *vh = (struct vertex_header *)(output_ptr + shader->vertex_size * i);
-         debug_printf("%d) [%f, %f, %f, %f]\n", i,
-                      vh->data[0][0], vh->data[0][1], vh->data[0][2], vh->data[0][3]);
+         debug_printf("%d) Vertex:\n", i);
+         for (j = 0; j < shader->info.num_outputs; ++j) {
+            unsigned *udata = (unsigned*)vh->data[j];
+            debug_printf("    %d) [%f, %f, %f, %f] [%d, %d, %d, %d]\n", j,
+                         vh->data[j][0], vh->data[j][1], vh->data[j][2], vh->data[j][3],
+                         udata[0], udata[1], udata[2], udata[3]);
+         }
          
       }
    }
@@ -784,6 +789,8 @@ draw_create_geometry_shader(struct draw_context *draw,
       if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION &&
           gs->info.output_semantic_index[i] == 0)
          gs->position_output = i;
+      if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_VIEWPORT_INDEX)
+         gs->viewport_index_output = i;
    }
 
    gs->machine = draw->gs.tgsi.machine;
diff --git a/src/gallium/auxiliary/draw/draw_gs.h b/src/gallium/auxiliary/draw/draw_gs.h
index 46d2d61..2b08569 100644
--- a/src/gallium/auxiliary/draw/draw_gs.h
+++ b/src/gallium/auxiliary/draw/draw_gs.h
@@ -66,6 +66,7 @@ struct draw_geometry_shader {
 
    struct tgsi_shader_info info;
    unsigned position_output;
+   unsigned viewport_index_output;
 
    unsigned max_output_vertices;
    unsigned primitive_boundary;
diff --git a/src/gallium/auxiliary/draw/draw_pipe_clip.c b/src/gallium/auxiliary/draw/draw_pipe_clip.c
index 8da0c41..b01e519 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_clip.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_clip.c
@@ -127,6 +127,8 @@ static void interp( const struct clip_stage *clip,
    const unsigned clip_attr = draw_current_shader_clipvertex_output(clip->stage.draw);
    unsigned j;
    float t_nopersp;
+   unsigned viewport_index_output =
+      draw_current_shader_viewport_index_output(clip->stage.draw);
 
    /* Vertex header.
     */
@@ -145,9 +147,14 @@ static void interp( const struct clip_stage *clip,
     * new window coordinates:
     */
    {
+      int viewport_index = 
+         draw_current_shader_uses_viewport_index(clip->stage.draw) ?
+         *((unsigned*)in->data[viewport_index_output]) : 0;
       const float *pos = dst->pre_clip_pos;
-      const float *scale = clip->stage.draw->viewport.scale;
-      const float *trans = clip->stage.draw->viewport.translate;
+      const float *scale =
+         clip->stage.draw->viewports[viewport_index].scale;
+      const float *trans =
+         clip->stage.draw->viewports[viewport_index].translate;
       const float oow = 1.0f / pos[3];
 
       dst->data[pos_attr][0] = pos[0] * oow * scale[0] + trans[0];
diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h
index 1b2d55f..e5f192b 100644
--- a/src/gallium/auxiliary/draw/draw_private.h
+++ b/src/gallium/auxiliary/draw/draw_private.h
@@ -241,7 +241,7 @@ struct draw_context
    /** Rasterizer CSOs without culling/stipple/etc */
    void *rasterizer_no_cull[2][2];
 
-   struct pipe_viewport_state viewport;
+   struct pipe_viewport_state viewports[PIPE_MAX_VIEWPORTS];
    boolean identity_viewport;
 
    /** Vertex shader state */
@@ -372,9 +372,6 @@ void draw_new_instance(struct draw_context *draw);
 boolean draw_vs_init( struct draw_context *draw );
 void draw_vs_destroy( struct draw_context *draw );
 
-void draw_vs_set_viewport( struct draw_context *, 
-                           const struct pipe_viewport_state * );
-
 
 /*******************************************************************************
  * Geometry shading code:
@@ -389,11 +386,14 @@ void draw_gs_destroy( struct draw_context *draw );
  */
 uint draw_current_shader_outputs(const struct draw_context *draw);
 uint draw_current_shader_position_output(const struct draw_context *draw);
+uint draw_current_shader_viewport_index_output(const struct draw_context *draw);
 uint draw_current_shader_clipvertex_output(const struct draw_context *draw);
 uint draw_current_shader_clipdistance_output(const struct draw_context *draw, int index);
 int draw_alloc_extra_vertex_attrib(struct draw_context *draw,
                                    uint semantic_name, uint semantic_index);
 void draw_remove_extra_vertex_attribs(struct draw_context *draw);
+boolean draw_current_shader_uses_viewport_index(
+   const struct draw_context *draw);
 
 
 /*******************************************************************************
diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
index f734311..5d2993e 100644
--- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
@@ -277,8 +277,8 @@ llvm_middle_end_bind_parameters(struct draw_pt_middle_end *middle)
    fpme->llvm->gs_jit_context.planes =
       (float (*)[DRAW_TOTAL_CLIP_PLANES][4]) draw->pt.user.planes[0];
 
-   fpme->llvm->jit_context.viewport = (float *) draw->viewport.scale;
-   fpme->llvm->gs_jit_context.viewport = (float *) draw->viewport.scale;
+   fpme->llvm->jit_context.viewport = (float *) draw->viewports[0].scale;
+   fpme->llvm->gs_jit_context.viewport = (float *) draw->viewports[0].scale;
 }
 
 
diff --git a/src/gallium/auxiliary/draw/draw_vs.c b/src/gallium/auxiliary/draw/draw_vs.c
index afec376..95f678a 100644
--- a/src/gallium/auxiliary/draw/draw_vs.c
+++ b/src/gallium/auxiliary/draw/draw_vs.c
@@ -49,13 +49,6 @@
 DEBUG_GET_ONCE_BOOL_OPTION(gallium_dump_vs, "GALLIUM_DUMP_VS", FALSE)
 
 
-void draw_vs_set_viewport( struct draw_context *draw,
-                           const struct pipe_viewport_state *viewport )
-{
-}
-
-
-
 struct draw_vertex_shader *
 draw_create_vertex_shader(struct draw_context *draw,
                           const struct pipe_shader_state *shader)
diff --git a/src/gallium/auxiliary/draw/draw_vs_variant.c b/src/gallium/auxiliary/draw/draw_vs_variant.c
index d8f030f..0387eaf 100644
--- a/src/gallium/auxiliary/draw/draw_vs_variant.c
+++ b/src/gallium/auxiliary/draw/draw_vs_variant.c
@@ -78,6 +78,26 @@ static void vsvg_set_buffer( struct draw_vs_variant *variant,
                            max_index );
 }
 
+static const struct pipe_viewport_state *
+find_viewport(struct draw_context *draw,
+              char *buffer,
+              unsigned vertex_idx,
+              unsigned stride)
+{
+   int viewport_index_output =
+      draw_current_shader_viewport_index_output(draw);
+   char *ptr = buffer + vertex_idx * stride;
+   unsigned *data = (unsigned *)ptr;
+   int viewport_index =
+      draw_current_shader_uses_viewport_index(draw) ?
+      data[viewport_index_output * 4] : 0;
+   
+   debug_assert(viewport_index < PIPE_MAX_VIEWPORTS);
+   viewport_index = MIN2(viewport_index, PIPE_MAX_VIEWPORTS - 1);
+
+   return &draw->viewports[viewport_index];
+}
+   
 
 /* Mainly for debug at this stage:
  */
@@ -86,14 +106,17 @@ static void do_rhw_viewport( struct draw_vs_variant_generic *vsvg,
                              void *output_buffer )
 {
    char *ptr = (char *)output_buffer;
-   const float *scale = vsvg->base.vs->draw->viewport.scale;
-   const float *trans = vsvg->base.vs->draw->viewport.translate;
    unsigned stride = vsvg->temp_vertex_stride;
    unsigned j;
 
    ptr += vsvg->base.vs->position_output * 4 * sizeof(float);
 
    for (j = 0; j < count; j++, ptr += stride) {
+      const struct pipe_viewport_state *viewport =
+         find_viewport(vsvg->base.vs->draw, (char*)output_buffer,
+                       j, stride);
+      const float *scale = viewport->scale;
+      const float *trans = viewport->translate;
       float *data = (float *)ptr;
       float w = 1.0f / data[3];
 
@@ -109,14 +132,17 @@ static void do_viewport( struct draw_vs_variant_generic *vsvg,
                          void *output_buffer )
 {
    char *ptr = (char *)output_buffer;
-   const float *scale = vsvg->base.vs->draw->viewport.scale;
-   const float *trans = vsvg->base.vs->draw->viewport.translate;
    unsigned stride = vsvg->temp_vertex_stride;
    unsigned j;
 
    ptr += vsvg->base.vs->position_output * 4 * sizeof(float);
 
    for (j = 0; j < count; j++, ptr += stride) {
+      const struct pipe_viewport_state *viewport =
+         find_viewport(vsvg->base.vs->draw, (char*)output_buffer,
+                       j, stride);
+      const float *scale = viewport->scale;
+      const float *trans = viewport->translate;
       float *data = (float *)ptr;
 
       data[0] = data[0] * scale[0] + trans[0];




More information about the mesa-commit mailing list