draw: hook up final bits of tessellation
authorDave Airlie <airlied@redhat.com>
Mon, 17 Feb 2020 07:13:11 +0000 (17:13 +1000)
committerDave Airlie <airlied@redhat.com>
Fri, 28 Feb 2020 08:33:34 +0000 (18:33 +1000)
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@vmware.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3841>

src/gallium/auxiliary/draw/draw_context.c
src/gallium/auxiliary/draw/draw_context.h
src/gallium/auxiliary/draw/draw_gs_tmp.h
src/gallium/auxiliary/draw/draw_llvm.c
src/gallium/auxiliary/draw/draw_prim_assembler.c
src/gallium/auxiliary/draw/draw_pt.c
src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
src/gallium/auxiliary/draw/draw_pt_so_emit.c
src/gallium/auxiliary/draw/draw_split_tmp.h

index 70dccda9972882088ea3165ed86cec401ec8918a..3b2b2d0306fcdb1c6ebf677b6570da2a9c083c23 100644 (file)
@@ -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];
+}
index 5ad26f1cf48110518bd4bd9c727db495db8084e5..659b81fd0bebb918738f44cbba9486a7e5fbe38d 100644 (file)
@@ -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
index bf276d38224d2ab5e71214ec0efca57f99b610fc..5a5b9e22ab380a75614fb788a95d1bf1f099a42f 100644 (file)
@@ -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:                                  \
index e7cf576cbd13cdb140af3a1f6338dacc03a6658c..3cfed5e65d874993c2848124d5d461d50150cb24 100644 (file)
@@ -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;
    }
 }
 
index 7ff705a91a5ba7489291ea9907eb9799b69c9d00..c0bc145f38bcce7c605e6f00021614c7df7ab3c4 100644 (file)
@@ -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;
 }
index 24ac054272650d84dc1cc4bdea0761c507ff9767..986f87e015282031f5178d26f0d2c70ce7469e1f 100644 (file)
@@ -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);
index 3a75a00c363644ebd2fc419b61067d6a21431885..f9db2928582e3b55b4889c7bd627b2f13886416e 100644 (file)
@@ -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);
    }
 }
index 6cb38fb9a5e74d7222de1f68361a6ed0987abeaf..83f4a31a6ae376b7c4e25c00e54e2f1e1c97ab51 100644 (file)
@@ -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;
    }
index 084699df602efe6267dd1334b4dbbaeac9a5bb66..dc6918897e5f45197b1b364319fd7c758b2c615f 100644 (file)
@@ -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: