Mesa (master): draw: hook up final bits of tessellation

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Feb 28 08:53:33 UTC 2020


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

Author: Dave Airlie <airlied at redhat.com>
Date:   Mon Feb 17 17:13:11 2020 +1000

draw: hook up final bits of tessellation

This hooks tessellation into various parts of draw, so the
tessellation shaders are used in the correct places as the
last shader of the pipeline.

Reviewed-by: Roland Scheidegger <sroland at vmware.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3841>

---

 src/gallium/auxiliary/draw/draw_context.c          | 103 ++++++++-
 src/gallium/auxiliary/draw/draw_context.h          |   5 +
 src/gallium/auxiliary/draw/draw_gs_tmp.h           |   1 -
 src/gallium/auxiliary/draw/draw_llvm.c             |  82 +++++--
 src/gallium/auxiliary/draw/draw_prim_assembler.c   |  10 +-
 src/gallium/auxiliary/draw/draw_pt.c               |  21 +-
 .../draw/draw_pt_fetch_shade_pipeline_llvm.c       | 255 ++++++++++++++++++++-
 src/gallium/auxiliary/draw/draw_pt_so_emit.c       |   3 +
 src/gallium/auxiliary/draw/draw_split_tmp.h        |   7 +-
 9 files changed, 446 insertions(+), 41 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c
index 70dccda9972..3b2b2d0306f 100644
--- a/src/gallium/auxiliary/draw/draw_context.c
+++ b/src/gallium/auxiliary/draw/draw_context.c
@@ -44,6 +44,7 @@
 #include "draw_prim_assembler.h"
 #include "draw_vs.h"
 #include "draw_gs.h"
+#include "draw_tess.h"
 
 #ifdef LLVM_AVAILABLE
 #include "gallivm/lp_bld_init.h"
@@ -454,7 +455,9 @@ draw_set_mapped_constant_buffer(struct draw_context *draw,
                                 unsigned size )
 {
    debug_assert(shader_type == PIPE_SHADER_VERTEX ||
-                shader_type == PIPE_SHADER_GEOMETRY);
+                shader_type == PIPE_SHADER_GEOMETRY ||
+                shader_type == PIPE_SHADER_TESS_CTRL ||
+                shader_type == PIPE_SHADER_TESS_EVAL);
    debug_assert(slot < PIPE_MAX_CONSTANT_BUFFERS);
 
    draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE);
@@ -468,6 +471,14 @@ draw_set_mapped_constant_buffer(struct draw_context *draw,
       draw->pt.user.gs_constants[slot] = buffer;
       draw->pt.user.gs_constants_size[slot] = size;
       break;
+   case PIPE_SHADER_TESS_CTRL:
+      draw->pt.user.tcs_constants[slot] = buffer;
+      draw->pt.user.tcs_constants_size[slot] = size;
+      break;
+   case PIPE_SHADER_TESS_EVAL:
+      draw->pt.user.tes_constants[slot] = buffer;
+      draw->pt.user.tes_constants_size[slot] = size;
+      break;
    default:
       assert(0 && "invalid shader type in draw_set_mapped_constant_buffer");
    }
@@ -481,7 +492,9 @@ draw_set_mapped_shader_buffer(struct draw_context *draw,
                               unsigned size )
 {
    debug_assert(shader_type == PIPE_SHADER_VERTEX ||
-                shader_type == PIPE_SHADER_GEOMETRY);
+                shader_type == PIPE_SHADER_GEOMETRY ||
+                shader_type == PIPE_SHADER_TESS_CTRL ||
+                shader_type == PIPE_SHADER_TESS_EVAL);
    debug_assert(slot < PIPE_MAX_SHADER_BUFFERS);
 
    draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE);
@@ -495,6 +508,14 @@ draw_set_mapped_shader_buffer(struct draw_context *draw,
       draw->pt.user.gs_ssbos[slot] = buffer;
       draw->pt.user.gs_ssbos_size[slot] = size;
       break;
+   case PIPE_SHADER_TESS_CTRL:
+      draw->pt.user.tcs_ssbos[slot] = buffer;
+      draw->pt.user.tcs_ssbos_size[slot] = size;
+      break;
+   case PIPE_SHADER_TESS_EVAL:
+      draw->pt.user.tes_ssbos[slot] = buffer;
+      draw->pt.user.tes_ssbos_size[slot] = size;
+      break;
    default:
       assert(0 && "invalid shader type in draw_set_mapped_shader_buffer");
    }
@@ -622,6 +643,8 @@ draw_get_shader_info(const struct draw_context *draw)
 
    if (draw->gs.geometry_shader) {
       return &draw->gs.geometry_shader->info;
+   } else if (draw->tes.tess_eval_shader) {
+      return &draw->tes.tess_eval_shader->info;
    } else {
       return &draw->vs.vertex_shader->info;
    }
@@ -788,11 +811,22 @@ draw_texture_sampler(struct draw_context *draw,
                      enum pipe_shader_type shader,
                      struct tgsi_sampler *sampler)
 {
-   if (shader == PIPE_SHADER_VERTEX) {
+   switch (shader) {
+   case PIPE_SHADER_VERTEX:
       draw->vs.tgsi.sampler = sampler;
-   } else {
-      debug_assert(shader == PIPE_SHADER_GEOMETRY);
+      break;
+   case PIPE_SHADER_GEOMETRY:
       draw->gs.tgsi.sampler = sampler;
+      break;
+   case PIPE_SHADER_TESS_CTRL:
+      draw->tcs.tgsi.sampler = sampler;
+      break;
+   case PIPE_SHADER_TESS_EVAL:
+      draw->tes.tgsi.sampler = sampler;
+      break;
+   default:
+      assert(0);
+      break;
    }
 }
 
@@ -806,11 +840,22 @@ draw_image(struct draw_context *draw,
            enum pipe_shader_type shader,
            struct tgsi_image *image)
 {
-   if (shader == PIPE_SHADER_VERTEX) {
+   switch (shader) {
+   case PIPE_SHADER_VERTEX:
       draw->vs.tgsi.image = image;
-   } else {
-      debug_assert(shader == PIPE_SHADER_GEOMETRY);
+      break;
+   case PIPE_SHADER_GEOMETRY:
       draw->gs.tgsi.image = image;
+      break;
+   case PIPE_SHADER_TESS_CTRL:
+      draw->tcs.tgsi.image = image;
+      break;
+   case PIPE_SHADER_TESS_EVAL:
+      draw->tes.tgsi.image = image;
+      break;
+   default:
+      assert(0);
+      break;
    }
 }
 
@@ -824,11 +869,22 @@ draw_buffer(struct draw_context *draw,
             enum pipe_shader_type shader,
             struct tgsi_buffer *buffer)
 {
-   if (shader == PIPE_SHADER_VERTEX) {
+   switch (shader) {
+   case PIPE_SHADER_VERTEX:
       draw->vs.tgsi.buffer = buffer;
-   } else {
-      debug_assert(shader == PIPE_SHADER_GEOMETRY);
+      break;
+   case PIPE_SHADER_GEOMETRY:
       draw->gs.tgsi.buffer = buffer;
+      break;
+   case PIPE_SHADER_TESS_CTRL:
+      draw->tcs.tgsi.buffer = buffer;
+      break;
+   case PIPE_SHADER_TESS_EVAL:
+      draw->tes.tgsi.buffer = buffer;
+      break;
+   default:
+      assert(0);
+      break;
    }
 }
 
@@ -905,6 +961,8 @@ draw_current_shader_position_output(const struct draw_context *draw)
 {
    if (draw->gs.geometry_shader)
       return draw->gs.position_output;
+   if (draw->tes.tess_eval_shader)
+      return draw->tes.position_output;
    return draw->vs.position_output;
 }
 
@@ -918,6 +976,8 @@ draw_current_shader_viewport_index_output(const struct draw_context *draw)
 {
    if (draw->gs.geometry_shader)
       return draw->gs.geometry_shader->viewport_index_output;
+   else if (draw->tes.tess_eval_shader)
+      return draw->tes.tess_eval_shader->viewport_index_output;
    return draw->vs.vertex_shader->viewport_index_output;
 }
 
@@ -945,6 +1005,8 @@ draw_current_shader_clipvertex_output(const struct draw_context *draw)
 {
    if (draw->gs.geometry_shader)
       return draw->gs.position_output;
+   if (draw->tes.tess_eval_shader)
+      return draw->tes.position_output;
    return draw->vs.clipvertex_output;
 }
 
@@ -954,6 +1016,8 @@ draw_current_shader_ccdistance_output(const struct draw_context *draw, int index
    debug_assert(index < PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT);
    if (draw->gs.geometry_shader)
       return draw->gs.geometry_shader->ccdistance_output[index];
+   if (draw->tes.tess_eval_shader)
+      return draw->tes.tess_eval_shader->ccdistance_output[index];
    return draw->vs.ccdistance_output[index];
 }
 
@@ -963,6 +1027,8 @@ draw_current_shader_num_written_clipdistances(const struct draw_context *draw)
 {
    if (draw->gs.geometry_shader)
       return draw->gs.geometry_shader->info.num_written_clipdistance;
+   if (draw->tes.tess_eval_shader)
+      return draw->tes.tess_eval_shader->info.num_written_clipdistance;
    return draw->vs.vertex_shader->info.num_written_clipdistance;
 }
 
@@ -971,6 +1037,8 @@ draw_current_shader_num_written_culldistances(const struct draw_context *draw)
 {
    if (draw->gs.geometry_shader)
       return draw->gs.geometry_shader->info.num_written_culldistance;
+   if (draw->tes.tess_eval_shader)
+      return draw->tes.tess_eval_shader->info.num_written_culldistance;
    return draw->vs.vertex_shader->info.num_written_culldistance;
 }
 
@@ -1168,6 +1236,8 @@ draw_get_shader_param(enum pipe_shader_type shader, enum pipe_shader_cap param)
       switch(shader) {
       case PIPE_SHADER_VERTEX:
       case PIPE_SHADER_GEOMETRY:
+      case PIPE_SHADER_TESS_CTRL:
+      case PIPE_SHADER_TESS_EVAL:
          return gallivm_get_shader_param(param);
       default:
          return 0;
@@ -1250,3 +1320,14 @@ draw_will_inject_frontface(const struct draw_context *draw)
            (rast->fill_front != PIPE_POLYGON_MODE_FILL ||
             rast->fill_back != PIPE_POLYGON_MODE_FILL));
 }
+
+void
+draw_set_tess_state(struct draw_context *draw,
+		    const float default_outer_level[4],
+		    const float default_inner_level[2])
+{
+   for (unsigned i = 0; i < 4; i++)
+      draw->default_outer_tess_level[i] = default_outer_level[i];
+   for (unsigned i = 0; i < 2; i++)
+      draw->default_inner_tess_level[i] = default_inner_level[i];
+}
diff --git a/src/gallium/auxiliary/draw/draw_context.h b/src/gallium/auxiliary/draw/draw_context.h
index 5ad26f1cf48..659b81fd0be 100644
--- a/src/gallium/auxiliary/draw/draw_context.h
+++ b/src/gallium/auxiliary/draw/draw_context.h
@@ -45,6 +45,8 @@ struct draw_context;
 struct draw_stage;
 struct draw_vertex_shader;
 struct draw_geometry_shader;
+struct draw_tess_ctrl_shader;
+struct draw_tess_eval_shader;
 struct draw_fragment_shader;
 struct tgsi_sampler;
 struct tgsi_image;
@@ -265,6 +267,9 @@ void draw_bind_tess_eval_shader(struct draw_context *draw,
                                 struct draw_tess_eval_shader *dvs);
 void draw_delete_tess_eval_shader(struct draw_context *draw,
                                   struct draw_tess_eval_shader *dvs);
+void draw_set_tess_state(struct draw_context *draw,
+                         const float default_outer_level[4],
+                         const float default_inner_level[2]);
 
 /*
  * Vertex data functions
diff --git a/src/gallium/auxiliary/draw/draw_gs_tmp.h b/src/gallium/auxiliary/draw/draw_gs_tmp.h
index bf276d38224..5a5b9e22ab3 100644
--- a/src/gallium/auxiliary/draw/draw_gs_tmp.h
+++ b/src/gallium/auxiliary/draw/draw_gs_tmp.h
@@ -12,7 +12,6 @@
    const boolean quads_flatshade_last = FALSE;                    \
    const boolean last_vertex_last = !gs->draw->rasterizer->flatshade_first;  \
    do {                                                           \
-      debug_assert(input_prims->primitive_count == 1);            \
       switch (prim) {                                             \
       case PIPE_PRIM_QUADS:                                       \
       case PIPE_PRIM_QUAD_STRIP:                                  \
diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c
index e7cf576cbd1..3cfed5e65d8 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_llvm.c
@@ -2412,18 +2412,24 @@ draw_llvm_set_mapped_texture(struct draw_context *draw,
    unsigned j;
    struct draw_jit_texture *jit_tex;
 
-   assert(shader_stage == PIPE_SHADER_VERTEX ||
-          shader_stage == PIPE_SHADER_GEOMETRY);
-
-   if (shader_stage == PIPE_SHADER_VERTEX) {
+   switch (shader_stage) {
+   case PIPE_SHADER_VERTEX:
       assert(sview_idx < ARRAY_SIZE(draw->llvm->jit_context.textures));
-
       jit_tex = &draw->llvm->jit_context.textures[sview_idx];
-   } else if (shader_stage == PIPE_SHADER_GEOMETRY) {
+      break;
+   case PIPE_SHADER_GEOMETRY:
       assert(sview_idx < ARRAY_SIZE(draw->llvm->gs_jit_context.textures));
-
       jit_tex = &draw->llvm->gs_jit_context.textures[sview_idx];
-   } else {
+      break;
+   case PIPE_SHADER_TESS_CTRL:
+      assert(sview_idx < ARRAY_SIZE(draw->llvm->tcs_jit_context.textures));
+      jit_tex = &draw->llvm->tcs_jit_context.textures[sview_idx];
+      break;
+   case PIPE_SHADER_TESS_EVAL:
+      assert(sview_idx < ARRAY_SIZE(draw->llvm->tes_jit_context.textures));
+      jit_tex = &draw->llvm->tes_jit_context.textures[sview_idx];
+      break;
+   default:
       assert(0);
       return;
    }
@@ -2453,18 +2459,24 @@ draw_llvm_set_mapped_image(struct draw_context *draw,
 {
    struct draw_jit_image *jit_image;
 
-   assert(shader_stage == PIPE_SHADER_VERTEX ||
-          shader_stage == PIPE_SHADER_GEOMETRY);
-
-   if (shader_stage == PIPE_SHADER_VERTEX) {
+   switch (shader_stage) {
+   case PIPE_SHADER_VERTEX:
       assert(idx < ARRAY_SIZE(draw->llvm->jit_context.images));
-
       jit_image = &draw->llvm->jit_context.images[idx];
-   } else if (shader_stage == PIPE_SHADER_GEOMETRY) {
+      break;
+   case PIPE_SHADER_GEOMETRY:
       assert(idx < ARRAY_SIZE(draw->llvm->gs_jit_context.images));
-
       jit_image = &draw->llvm->gs_jit_context.images[idx];
-   } else {
+      break;
+   case PIPE_SHADER_TESS_CTRL:
+      assert(idx < ARRAY_SIZE(draw->llvm->tcs_jit_context.images));
+      jit_image = &draw->llvm->tcs_jit_context.images[idx];
+      break;
+   case PIPE_SHADER_TESS_EVAL:
+      assert(idx < ARRAY_SIZE(draw->llvm->tes_jit_context.images));
+      jit_image = &draw->llvm->tes_jit_context.images[idx];
+      break;
+   default:
       assert(0);
       return;
    }
@@ -2485,7 +2497,8 @@ draw_llvm_set_sampler_state(struct draw_context *draw,
 {
    unsigned i;
 
-   if (shader_type == PIPE_SHADER_VERTEX) {
+   switch (shader_type) {
+   case PIPE_SHADER_VERTEX:
       for (i = 0; i < draw->num_samplers[PIPE_SHADER_VERTEX]; i++) {
          struct draw_jit_sampler *jit_sam = &draw->llvm->jit_context.samplers[i];
 
@@ -2498,7 +2511,8 @@ draw_llvm_set_sampler_state(struct draw_context *draw,
             COPY_4V(jit_sam->border_color, s->border_color.f);
          }
       }
-   } else if (shader_type == PIPE_SHADER_GEOMETRY) {
+      break;
+   case PIPE_SHADER_GEOMETRY:
       for (i = 0; i < draw->num_samplers[PIPE_SHADER_GEOMETRY]; i++) {
          struct draw_jit_sampler *jit_sam = &draw->llvm->gs_jit_context.samplers[i];
 
@@ -2511,6 +2525,38 @@ draw_llvm_set_sampler_state(struct draw_context *draw,
             COPY_4V(jit_sam->border_color, s->border_color.f);
          }
       }
+      break;
+   case PIPE_SHADER_TESS_CTRL:
+      for (i = 0; i < draw->num_samplers[PIPE_SHADER_TESS_CTRL]; i++) {
+         struct draw_jit_sampler *jit_sam = &draw->llvm->tcs_jit_context.samplers[i];
+
+         if (draw->samplers[PIPE_SHADER_TESS_CTRL][i]) {
+            const struct pipe_sampler_state *s
+               = draw->samplers[PIPE_SHADER_TESS_CTRL][i];
+            jit_sam->min_lod = s->min_lod;
+            jit_sam->max_lod = s->max_lod;
+            jit_sam->lod_bias = s->lod_bias;
+            COPY_4V(jit_sam->border_color, s->border_color.f);
+         }
+      }
+      break;
+   case PIPE_SHADER_TESS_EVAL:
+      for (i = 0; i < draw->num_samplers[PIPE_SHADER_TESS_EVAL]; i++) {
+         struct draw_jit_sampler *jit_sam = &draw->llvm->tes_jit_context.samplers[i];
+
+         if (draw->samplers[PIPE_SHADER_TESS_EVAL][i]) {
+            const struct pipe_sampler_state *s
+               = draw->samplers[PIPE_SHADER_TESS_EVAL][i];
+            jit_sam->min_lod = s->min_lod;
+            jit_sam->max_lod = s->max_lod;
+            jit_sam->lod_bias = s->lod_bias;
+            COPY_4V(jit_sam->border_color, s->border_color.f);
+         }
+      }
+      break;
+   default:
+      assert(0);
+      break;
    }
 }
 
diff --git a/src/gallium/auxiliary/draw/draw_prim_assembler.c b/src/gallium/auxiliary/draw/draw_prim_assembler.c
index 7ff705a91a5..c0bc145f38b 100644
--- a/src/gallium/auxiliary/draw/draw_prim_assembler.c
+++ b/src/gallium/auxiliary/draw/draw_prim_assembler.c
@@ -29,7 +29,7 @@
 
 #include "draw_fs.h"
 #include "draw_gs.h"
-
+#include "draw_tess.h"
 #include "util/u_debug.h"
 #include "util/u_memory.h"
 #include "util/u_prim.h"
@@ -59,8 +59,14 @@ needs_primid(const struct draw_context *draw)
 {
    const struct draw_fragment_shader *fs = draw->fs.fragment_shader;
    const struct draw_geometry_shader *gs = draw->gs.geometry_shader;
+   const struct draw_tess_eval_shader *tes = draw->tes.tess_eval_shader;
    if (fs && fs->info.uses_primid) {
-      return !gs || !gs->info.uses_primid;
+      if (gs)
+         return !gs->info.uses_primid;
+      else if (tes)
+         return !tes->info.uses_primid;
+      else
+         return TRUE;
    }
    return FALSE;
 }
diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c
index 24ac0542726..986f87e0152 100644
--- a/src/gallium/auxiliary/draw/draw_pt.c
+++ b/src/gallium/auxiliary/draw/draw_pt.c
@@ -32,6 +32,7 @@
 
 #include "draw/draw_context.h"
 #include "draw/draw_gs.h"
+#include "draw/draw_tess.h"
 #include "draw/draw_private.h"
 #include "draw/draw_pt.h"
 #include "draw/draw_vbuf.h"
@@ -66,16 +67,24 @@ draw_pt_arrays(struct draw_context *draw,
     */
    {
       unsigned first, incr;
-      draw_pt_split_prim(prim, &first, &incr);
+
+      if (prim == PIPE_PRIM_PATCHES) {
+         first = draw->pt.vertices_per_patch;
+         incr = draw->pt.vertices_per_patch;
+      } else
+         draw_pt_split_prim(prim, &first, &incr);
       count = draw_pt_trim_count(count, first, incr);
       if (count < first)
          return TRUE;
    }
 
    if (!draw->force_passthrough) {
-      unsigned gs_out_prim = (draw->gs.geometry_shader ? 
-                              draw->gs.geometry_shader->output_primitive :
-                              prim);
+      unsigned out_prim = prim;
+
+      if (draw->gs.geometry_shader)
+         out_prim = draw->gs.geometry_shader->output_primitive;
+      else if (draw->tes.tess_eval_shader)
+         out_prim = get_tes_output_prim(draw->tes.tess_eval_shader);
 
       if (!draw->render) {
          opt |= PT_PIPELINE;
@@ -83,7 +92,7 @@ draw_pt_arrays(struct draw_context *draw,
 
       if (draw_need_pipeline(draw,
                              draw->rasterizer,
-                             gs_out_prim)) {
+                             out_prim)) {
          opt |= PT_PIPELINE;
       }
 
@@ -487,6 +496,8 @@ draw_vbo(struct draw_context *draw,
    draw->pt.user.eltSize = info->index_size ? draw->pt.user.eltSizeIB : 0;
    draw->pt.user.drawid = info->drawid;
 
+   draw->pt.vertices_per_patch = info->vertices_per_patch;
+
    if (0)
       debug_printf("draw_vbo(mode=%u start=%u count=%u):\n",
                    info->mode, info->start, count);
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 3a75a00c363..f9db2928582 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
@@ -30,6 +30,7 @@
 #include "util/u_prim.h"
 #include "draw/draw_context.h"
 #include "draw/draw_gs.h"
+#include "draw/draw_tess.h"
 #include "draw/draw_vbuf.h"
 #include "draw/draw_vertex.h"
 #include "draw/draw_pt.h"
@@ -138,6 +139,146 @@ llvm_middle_end_prepare_gs(struct llvm_middle_end *fpme)
    gs->current_variant = variant;
 }
 
+static void
+llvm_middle_end_prepare_tcs(struct llvm_middle_end *fpme)
+{
+   struct draw_context *draw = fpme->draw;
+   struct draw_llvm *llvm = fpme->llvm;
+   struct draw_tess_ctrl_shader *tcs = draw->tcs.tess_ctrl_shader;
+   struct draw_tcs_llvm_variant_key *key;
+   struct draw_tcs_llvm_variant *variant = NULL;
+   struct draw_tcs_llvm_variant_list_item *li;
+   struct llvm_tess_ctrl_shader *shader = llvm_tess_ctrl_shader(tcs);
+   char store[DRAW_TCS_LLVM_MAX_VARIANT_KEY_SIZE];
+   unsigned i;
+
+   key = draw_tcs_llvm_make_variant_key(llvm, store);
+
+   /* Search shader's list of variants for the key */
+   li = first_elem(&shader->variants);
+   while (!at_end(&shader->variants, li)) {
+      if (memcmp(&li->base->key, key, shader->variant_key_size) == 0) {
+         variant = li->base;
+         break;
+      }
+      li = next_elem(li);
+   }
+
+   if (variant) {
+      /* found the variant, move to head of global list (for LRU) */
+      move_to_head(&llvm->tcs_variants_list, &variant->list_item_global);
+   }
+   else {
+      /* Need to create new variant */
+
+      /* First check if we've created too many variants.  If so, free
+       * 3.125% of the LRU to avoid using too much memory.
+       */
+      if (llvm->nr_tcs_variants >= DRAW_MAX_SHADER_VARIANTS) {
+         if (gallivm_debug & GALLIVM_DEBUG_PERF) {
+            debug_printf("Evicting TCS: %u tcs variants,\t%u total variants\n",
+                      shader->variants_cached, llvm->nr_tcs_variants);
+         }
+
+         /*
+          * XXX: should we flush here ?
+          */
+         for (i = 0; i < DRAW_MAX_SHADER_VARIANTS / 32; i++) {
+            struct draw_tcs_llvm_variant_list_item *item;
+            if (is_empty_list(&llvm->tcs_variants_list)) {
+               break;
+            }
+            item = last_elem(&llvm->tcs_variants_list);
+            assert(item);
+            assert(item->base);
+            draw_tcs_llvm_destroy_variant(item->base);
+         }
+      }
+
+      variant = draw_tcs_llvm_create_variant(llvm, 0, key);
+
+      if (variant) {
+         insert_at_head(&shader->variants, &variant->list_item_local);
+         insert_at_head(&llvm->tcs_variants_list,
+                        &variant->list_item_global);
+         llvm->nr_tcs_variants++;
+         shader->variants_cached++;
+      }
+   }
+
+   tcs->current_variant = variant;
+}
+
+static void
+llvm_middle_end_prepare_tes(struct llvm_middle_end *fpme)
+{
+   struct draw_context *draw = fpme->draw;
+   struct draw_llvm *llvm = fpme->llvm;
+   struct draw_tess_eval_shader *tes = draw->tes.tess_eval_shader;
+   struct draw_tes_llvm_variant_key *key;
+   struct draw_tes_llvm_variant *variant = NULL;
+   struct draw_tes_llvm_variant_list_item *li;
+   struct llvm_tess_eval_shader *shader = llvm_tess_eval_shader(tes);
+   char store[DRAW_TES_LLVM_MAX_VARIANT_KEY_SIZE];
+   unsigned i;
+
+   key = draw_tes_llvm_make_variant_key(llvm, store);
+
+   /* Search shader's list of variants for the key */
+   li = first_elem(&shader->variants);
+   while (!at_end(&shader->variants, li)) {
+      if (memcmp(&li->base->key, key, shader->variant_key_size) == 0) {
+         variant = li->base;
+         break;
+      }
+      li = next_elem(li);
+   }
+
+   if (variant) {
+      /* found the variant, move to head of global list (for LRU) */
+      move_to_head(&llvm->tes_variants_list, &variant->list_item_global);
+   }
+   else {
+      /* Need to create new variant */
+
+      /* First check if we've created too many variants.  If so, free
+       * 3.125% of the LRU to avoid using too much memory.
+       */
+      if (llvm->nr_tes_variants >= DRAW_MAX_SHADER_VARIANTS) {
+         if (gallivm_debug & GALLIVM_DEBUG_PERF) {
+            debug_printf("Evicting TES: %u tes variants,\t%u total variants\n",
+                      shader->variants_cached, llvm->nr_tes_variants);
+         }
+
+         /*
+          * XXX: should we flush here ?
+          */
+         for (i = 0; i < DRAW_MAX_SHADER_VARIANTS / 32; i++) {
+            struct draw_tes_llvm_variant_list_item *item;
+            if (is_empty_list(&llvm->tes_variants_list)) {
+               break;
+            }
+            item = last_elem(&llvm->tes_variants_list);
+            assert(item);
+            assert(item->base);
+            draw_tes_llvm_destroy_variant(item->base);
+         }
+      }
+
+      variant = draw_tes_llvm_create_variant(llvm, tes->info.num_outputs, key);
+
+      if (variant) {
+         insert_at_head(&shader->variants, &variant->list_item_local);
+         insert_at_head(&llvm->tes_variants_list,
+                        &variant->list_item_global);
+         llvm->nr_tes_variants++;
+         shader->variants_cached++;
+      }
+   }
+
+   tes->current_variant = variant;
+}
+
 /**
  * Prepare/validate middle part of the vertex pipeline.
  * NOTE: if you change this function, also look at the non-LLVM
@@ -154,7 +295,9 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
    struct draw_llvm *llvm = fpme->llvm;
    struct draw_vertex_shader *vs = draw->vs.vertex_shader;
    struct draw_geometry_shader *gs = draw->gs.geometry_shader;
-   const unsigned out_prim = gs ? gs->output_primitive :
+   struct draw_tess_ctrl_shader *tcs = draw->tcs.tess_ctrl_shader;
+   struct draw_tess_eval_shader *tes = draw->tes.tess_eval_shader;
+   const unsigned out_prim = gs ? gs->output_primitive : tes ? get_tes_output_prim(tes) :
       u_assembled_prim(in_prim);
    unsigned point_clip = draw->rasterizer->fill_front == PIPE_POLYGON_MODE_POINT ||
                          out_prim == PIPE_PRIM_POINTS;
@@ -270,6 +413,12 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
    if (gs) {
       llvm_middle_end_prepare_gs(fpme);
    }
+   if (tcs) {
+      llvm_middle_end_prepare_tcs(fpme);
+   }
+   if (tes) {
+      llvm_middle_end_prepare_tes(fpme);
+   }
 }
 
 
@@ -329,6 +478,42 @@ llvm_middle_end_bind_parameters(struct draw_pt_middle_end *middle)
       }
    }
 
+   for (i = 0; i < ARRAY_SIZE(llvm->tcs_jit_context.constants); ++i) {
+      int num_consts =
+         DIV_ROUND_UP(draw->pt.user.tcs_constants_size[i], (sizeof(float) * 4));
+      llvm->tcs_jit_context.constants[i] = draw->pt.user.tcs_constants[i];
+      llvm->tcs_jit_context.num_constants[i] = num_consts;
+      if (num_consts == 0) {
+         llvm->tcs_jit_context.constants[i] = fake_const_buf;
+      }
+   }
+   for (i = 0; i < ARRAY_SIZE(llvm->tcs_jit_context.ssbos); ++i) {
+      int num_ssbos = draw->pt.user.tcs_ssbos_size[i];
+      llvm->tcs_jit_context.ssbos[i] = draw->pt.user.tcs_ssbos[i];
+      llvm->tcs_jit_context.num_ssbos[i] = num_ssbos;
+      if (num_ssbos == 0) {
+         llvm->tcs_jit_context.ssbos[i] = (const uint32_t *)fake_const_buf;
+      }
+   }
+
+   for (i = 0; i < ARRAY_SIZE(llvm->tes_jit_context.constants); ++i) {
+      int num_consts =
+         DIV_ROUND_UP(draw->pt.user.tes_constants_size[i], (sizeof(float) * 4));
+      llvm->tes_jit_context.constants[i] = draw->pt.user.tes_constants[i];
+      llvm->tes_jit_context.num_constants[i] = num_consts;
+      if (num_consts == 0) {
+         llvm->tes_jit_context.constants[i] = fake_const_buf;
+      }
+   }
+   for (i = 0; i < ARRAY_SIZE(llvm->tes_jit_context.ssbos); ++i) {
+      int num_ssbos = draw->pt.user.tes_ssbos_size[i];
+      llvm->tes_jit_context.ssbos[i] = draw->pt.user.tes_ssbos[i];
+      llvm->tes_jit_context.num_ssbos[i] = num_ssbos;
+      if (num_ssbos == 0) {
+         llvm->tes_jit_context.ssbos[i] = (const uint32_t *)fake_const_buf;
+      }
+   }
+
    llvm->jit_context.planes =
       (float (*)[DRAW_TOTAL_CLIP_PLANES][4]) draw->pt.user.planes[0];
    llvm->gs_jit_context.planes =
@@ -377,8 +562,14 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle,
    struct llvm_middle_end *fpme = llvm_middle_end(middle);
    struct draw_context *draw = fpme->draw;
    struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
+   struct draw_tess_ctrl_shader *tcs_shader = draw->tcs.tess_ctrl_shader;
+   struct draw_tess_eval_shader *tes_shader = draw->tes.tess_eval_shader;
+   struct draw_prim_info tcs_prim_info;
+   struct draw_prim_info tes_prim_info;
    struct draw_prim_info gs_prim_info[TGSI_MAX_VERTEX_STREAMS];
    struct draw_vertex_info llvm_vert_info;
+   struct draw_vertex_info tcs_vert_info;
+   struct draw_vertex_info tes_vert_info;
    struct draw_vertex_info gs_vert_info[TGSI_MAX_VERTEX_STREAMS];
    struct draw_vertex_info *vert_info;
    struct draw_prim_info ia_prim_info;
@@ -389,6 +580,7 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle,
    boolean clipped = 0;
    unsigned start_or_maxelt, vid_base;
    const unsigned *elts;
+   ushort *tes_elts_out = NULL;
 
    assert(fetch_info->count > 0);
    llvm_vert_info.count = fetch_info->count;
@@ -436,6 +628,56 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle,
    fetch_info = NULL;
    vert_info = &llvm_vert_info;
 
+   if (opt & PT_SHADE) {
+      struct draw_vertex_shader *vshader = draw->vs.vertex_shader;
+      if (tcs_shader) {
+         draw_tess_ctrl_shader_run(tcs_shader,
+                                   draw->pt.user.tcs_constants,
+                                   draw->pt.user.tcs_constants_size,
+                                   vert_info,
+                                   prim_info,
+                                   &vshader->info,
+                                   &tcs_vert_info,
+                                   &tcs_prim_info);
+         FREE(vert_info->verts);
+         vert_info = &tcs_vert_info;
+         prim_info = &tcs_prim_info;
+
+      } else if (tes_shader) {
+         unsigned num_prims = prim_info->count / draw->pt.vertices_per_patch;
+         tcs_prim_info = *prim_info;
+         tcs_prim_info.primitive_count = num_prims;
+         prim_info = &tcs_prim_info;
+      }
+
+      if (tes_shader) {
+         draw_tess_eval_shader_run(tes_shader,
+                                   draw->pt.user.tes_constants,
+                                   draw->pt.user.tes_constants_size,
+                                   tcs_shader ? tcs_shader->vertices_out : draw->pt.vertices_per_patch,
+                                   vert_info,
+                                   prim_info,
+                                   tcs_shader ? &tcs_shader->info : &vshader->info,
+                                   &tes_vert_info,
+                                   &tes_prim_info, &tes_elts_out);
+
+         FREE(vert_info->verts);
+         vert_info = &tes_vert_info;
+         prim_info = &tes_prim_info;
+         free_prim_info = TRUE;
+
+         /*
+          * pt emit can only handle ushort number of vertices (see
+          * render->allocate_vertices).
+          * vsplit guarantees there's never more than 4096, however GS can
+          * easily blow this up (by a factor of 256 (or even 1024) max).
+          */
+         if (vert_info->count > 65535) {
+            opt |= PT_PIPELINE;
+         }
+      }
+   }
+
    if ((opt & PT_SHADE) && gshader) {
       struct draw_vertex_shader *vshader = draw->vs.vertex_shader;
       draw_geometry_shader_run(gshader,
@@ -443,13 +685,18 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle,
                                draw->pt.user.gs_constants_size,
                                vert_info,
                                prim_info,
-                               &vshader->info,
+                               tes_shader ? &tes_shader->info : &vshader->info,
                                gs_vert_info,
                                gs_prim_info);
 
       FREE(vert_info->verts);
+      if (free_prim_info) {
+         FREE(prim_info->primitive_lengths);
+         FREE(tes_elts_out);
+      }
       vert_info = &gs_vert_info[0];
       prim_info = &gs_prim_info[0];
+      free_prim_info = FALSE;
       /*
        * pt emit can only handle ushort number of vertices (see
        * render->allocate_vertices).
@@ -477,6 +724,7 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle,
 
       FREE(vert_info->verts);
       if (free_prim_info) {
+         FREE(tes_elts_out);
          FREE(prim_info->primitive_lengths);
       }
       return;
@@ -492,7 +740,7 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle,
     * will try to access non-existent position output.
     */
    if (draw_current_shader_position_output(draw) != -1) {
-      if ((opt & PT_SHADE) && (gshader ||
+      if ((opt & PT_SHADE) && (gshader || tes_shader ||
                                draw->vs.vertex_shader->info.writes_viewport_index)) {
          clipped = draw_pt_post_vs_run( fpme->post_vs, vert_info, prim_info );
       }
@@ -512,6 +760,7 @@ llvm_pipeline_generic(struct draw_pt_middle_end *middle,
    }
    FREE(vert_info->verts);
    if (free_prim_info) {
+      FREE(tes_elts_out);
       FREE(prim_info->primitive_lengths);
    }
 }
diff --git a/src/gallium/auxiliary/draw/draw_pt_so_emit.c b/src/gallium/auxiliary/draw/draw_pt_so_emit.c
index 6cb38fb9a5e..83f4a31a6ae 100644
--- a/src/gallium/auxiliary/draw/draw_pt_so_emit.c
+++ b/src/gallium/auxiliary/draw/draw_pt_so_emit.c
@@ -28,6 +28,7 @@
 #include "draw/draw_private.h"
 #include "draw/draw_vs.h"
 #include "draw/draw_gs.h"
+#include "draw/draw_tess.h"
 #include "draw/draw_context.h"
 #include "draw/draw_vbuf.h"
 #include "draw/draw_vertex.h"
@@ -60,6 +61,8 @@ draw_so_info(const struct draw_context *draw)
 
    if (draw->gs.geometry_shader) {
       state = &draw->gs.geometry_shader->state.stream_output;
+   } else if (draw->tes.tess_eval_shader) {
+      state = &draw->tes.tess_eval_shader->state.stream_output;
    } else {
       state = &draw->vs.vertex_shader->state.stream_output;
    }
diff --git a/src/gallium/auxiliary/draw/draw_split_tmp.h b/src/gallium/auxiliary/draw/draw_split_tmp.h
index 084699df602..dc6918897e5 100644
--- a/src/gallium/auxiliary/draw/draw_split_tmp.h
+++ b/src/gallium/auxiliary/draw/draw_split_tmp.h
@@ -40,7 +40,11 @@ FUNC(FUNC_VARS)
                    max_count_loop, max_count_fan);
    }
 
-   draw_pt_split_prim(prim, &first, &incr);
+   if (prim == PIPE_PRIM_PATCHES) {
+      first = vsplit->draw->pt.vertices_per_patch;
+      incr = vsplit->draw->pt.vertices_per_patch;
+   } else
+      draw_pt_split_prim(prim, &first, &incr);
    /* sanitize primitive length */
    count = draw_pt_trim_count(count, first, incr);
    if (count < first)
@@ -75,6 +79,7 @@ FUNC(FUNC_VARS)
        * That is, remaining is implicitly trimmed.
        */
       switch (prim) {
+      case PIPE_PRIM_PATCHES:
       case PIPE_PRIM_POINTS:
       case PIPE_PRIM_LINES:
       case PIPE_PRIM_LINE_STRIP:



More information about the mesa-commit mailing list