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

Zack Rusin zackr at vmware.com
Fri May 24 13:56:04 PDT 2013


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>
---
 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];
-- 
1.7.10.4


More information about the mesa-dev mailing list