draw: implement support for multiple viewports
authorZack Rusin <zackr@vmware.com>
Fri, 24 May 2013 20:17:26 +0000 (16:17 -0400)
committerZack Rusin <zackr@vmware.com>
Sat, 25 May 2013 13:49:20 +0000 (09:49 -0400)
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@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/auxiliary/draw/draw_cliptest_tmp.h
src/gallium/auxiliary/draw/draw_context.c
src/gallium/auxiliary/draw/draw_gs.c
src/gallium/auxiliary/draw/draw_gs.h
src/gallium/auxiliary/draw/draw_pipe_clip.c
src/gallium/auxiliary/draw/draw_private.h
src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
src/gallium/auxiliary/draw/draw_vs.c
src/gallium/auxiliary/draw/draw_vs_variant.c

index 48f234931cdcd24fd1f97df0bfae3bf63b4b02ba..09e1fd713341ca7dd23e8a46f37ce3e120119ce6 100644 (file)
@@ -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);
 
index b555c65e858627cbf268300d4a13dde816633c71..4250f10d13a257239f3505e7c555389f06ce180a 100644 (file)
@@ -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);
 }
 
 
@@ -693,6 +700,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.
index fa0981ee10e8bf6417f4c9864b8b8143643dab2d..67e5117c587a3f2641175ed6825bbf8f116222f9 100644 (file)
@@ -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;
index 46d2d614f06996adcc7a8df698aac44ccbf7e0cf..2b0856924d9b6eba80d0264ec724a910c97b5ac2 100644 (file)
@@ -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;
index 8da0c41390fd2269dcf8139b197e9a74104c61ea..b01e51994cba9eaa22b7cd09f8cc522760a0e74a 100644 (file)
@@ -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];
index 1b2d55fac556f3fd42ba6828fe9422a5786934c4..e5f192b75763396b894bdcc1d465bd4bed09a460 100644 (file)
@@ -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);
 
 
 /*******************************************************************************
index f734311e73c3a1136869869d2127ccfebd0d12c3..5d2993eaa1738c95c858691741c2cf37d42d05f8 100644 (file)
@@ -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;
 }
 
 
index afec3760e770e24170504f55df03b58a009ced07..95f678ab2cd061f7b67aba665f599abc7743fe87 100644 (file)
 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)
index d8f030f61eb2f785d160d087107de45c98112690..0387eafbbce4e59ec60bf55d8316d64924f8863c 100644 (file)
@@ -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];