[virglrenderer-devel] [PATCH 19/21] tessellation: add shader building support for tess eval/ctrl. (v2)

Dave Airlie airlied at gmail.com
Wed Jun 13 00:56:53 UTC 2018


From: Dave Airlie <airlied at redhat.com>

This adds all the shader program building and dirtying for
tess shaders.

The big change is building the key so that we get the correct
tess input/output blocks.

It might be possible SSO could reduce some of that overheads

v2: fixup warnings
---
 src/vrend_renderer.c | 159 +++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 143 insertions(+), 16 deletions(-)

diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
index b756c10..33883a3 100644
--- a/src/vrend_renderer.c
+++ b/src/vrend_renderer.c
@@ -864,7 +864,9 @@ static void set_stream_out_varyings(int prog_id, struct vrend_shader_info *sinfo
 static struct vrend_linked_shader_program *add_shader_program(struct vrend_context *ctx,
                                                               struct vrend_shader *vs,
                                                               struct vrend_shader *fs,
-                                                              struct vrend_shader *gs)
+                                                              struct vrend_shader *gs,
+                                                              struct vrend_shader *tcs,
+                                                              struct vrend_shader *tes)
 {
    struct vrend_linked_shader_program *sprog = CALLOC_STRUCT(vrend_linked_shader_program);
    char name[64];
@@ -880,7 +882,9 @@ static struct vrend_linked_shader_program *add_shader_program(struct vrend_conte
    /* need to rewrite VS code to add interpolation params */
    if (gs && gs->compiled_fs_id != fs->id)
       do_patch = true;
-   if (!gs && vs->compiled_fs_id != fs->id)
+   if (!gs && tes && tes->compiled_fs_id != fs->id)
+      do_patch = true;
+   if (!gs && !tes && vs->compiled_fs_id != fs->id)
       do_patch = true;
 
    if (do_patch) {
@@ -890,24 +894,35 @@ static struct vrend_linked_shader_program *add_shader_program(struct vrend_conte
          vrend_patch_vertex_shader_interpolants(&ctx->shader_cfg, gs->glsl_prog,
                                                 &gs->sel->sinfo,
                                                 &fs->sel->sinfo, "gso", fs->key.flatshade);
+      else if (tes)
+         vrend_patch_vertex_shader_interpolants(&ctx->shader_cfg, tes->glsl_prog,
+                                                &tes->sel->sinfo,
+                                                &fs->sel->sinfo, "teo", fs->key.flatshade);
       else
          vrend_patch_vertex_shader_interpolants(&ctx->shader_cfg, vs->glsl_prog,
                                                 &vs->sel->sinfo,
                                                 &fs->sel->sinfo, "vso", fs->key.flatshade);
-      ret = vrend_compile_shader(ctx, gs ? gs : vs);
+      ret = vrend_compile_shader(ctx, gs ? gs : (tes ? tes : vs));
       if (ret == false) {
-         glDeleteShader(gs ? gs->id : vs->id);
+         glDeleteShader(gs ? gs->id : (tes ? tes->id : vs->id));
          free(sprog);
          return NULL;
       }
       if (gs)
          gs->compiled_fs_id = fs->id;
+      else if (tes)
+         tes->compiled_fs_id = fs->id;
       else
          vs->compiled_fs_id = fs->id;
    }
 
    prog_id = glCreateProgram();
    glAttachShader(prog_id, vs->id);
+   if (tcs && tcs->id > 0)
+      glAttachShader(prog_id, tcs->id);
+   if (tes && tes->id > 0)
+      glAttachShader(prog_id, tes->id);
+
    if (gs) {
       if (gs->id > 0)
          glAttachShader(prog_id, gs->id);
@@ -961,13 +976,19 @@ static struct vrend_linked_shader_program *add_shader_program(struct vrend_conte
    sprog->ss[PIPE_SHADER_VERTEX] = vs;
    sprog->ss[PIPE_SHADER_FRAGMENT] = fs;
    sprog->ss[PIPE_SHADER_GEOMETRY] = gs;
+   sprog->ss[PIPE_SHADER_TESS_CTRL] = tcs;
+   sprog->ss[PIPE_SHADER_TESS_EVAL] = tes;
 
    list_add(&sprog->sl[PIPE_SHADER_VERTEX], &vs->programs);
    list_add(&sprog->sl[PIPE_SHADER_FRAGMENT], &fs->programs);
    if (gs)
       list_add(&sprog->sl[PIPE_SHADER_GEOMETRY], &gs->programs);
+   if (tcs)
+      list_add(&sprog->sl[PIPE_SHADER_TESS_CTRL], &tcs->programs);
+   if (tes)
+      list_add(&sprog->sl[PIPE_SHADER_TESS_EVAL], &tes->programs);
 
-   last_shader = gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT;
+   last_shader = tes ? PIPE_SHADER_TESS_EVAL : (gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT);
    sprog->id = prog_id;
 
    list_addtail(&sprog->head, &ctx->sub->programs);
@@ -978,6 +999,8 @@ static struct vrend_linked_shader_program *add_shader_program(struct vrend_conte
       sprog->fs_stipple_loc = -1;
    sprog->vs_ws_adjust_loc = glGetUniformLocation(prog_id, "winsys_adjust_y");
    for (id = PIPE_SHADER_VERTEX; id <= last_shader; id++) {
+      if (!sprog->ss[id])
+         continue;
       if (sprog->ss[id]->sel->sinfo.samplers_used_mask) {
          uint32_t mask = sprog->ss[id]->sel->sinfo.samplers_used_mask;
          int nsamp = util_bitcount(sprog->ss[id]->sel->sinfo.samplers_used_mask);
@@ -1020,6 +1043,8 @@ static struct vrend_linked_shader_program *add_shader_program(struct vrend_conte
    }
 
    for (id = PIPE_SHADER_VERTEX; id <= last_shader; id++) {
+      if (!sprog->ss[id])
+         continue;
       if (sprog->ss[id]->sel->sinfo.num_consts) {
          sprog->const_locs[id] = calloc(sprog->ss[id]->sel->sinfo.num_consts, sizeof(uint32_t));
          if (sprog->const_locs[id]) {
@@ -1047,6 +1072,8 @@ static struct vrend_linked_shader_program *add_shader_program(struct vrend_conte
    }
 
    for (id = PIPE_SHADER_VERTEX; id <= last_shader; id++) {
+      if (!sprog->ss[id])
+         continue;
       if (sprog->ss[id]->sel->sinfo.num_ubos) {
          const char *prefix = pipe_shader_to_prefix(id);
 
@@ -1077,6 +1104,8 @@ static struct vrend_linked_shader_program *lookup_shader_program(struct vrend_co
                                                                  GLuint vs_id,
                                                                  GLuint fs_id,
                                                                  GLuint gs_id,
+                                                                 GLuint tcs_id,
+                                                                 GLuint tes_id,
                                                                  bool dual_src)
 {
    struct vrend_linked_shader_program *ent;
@@ -1091,6 +1120,12 @@ static struct vrend_linked_shader_program *lookup_shader_program(struct vrend_co
       if (ent->ss[PIPE_SHADER_GEOMETRY] &&
           ent->ss[PIPE_SHADER_GEOMETRY]->id != gs_id)
         continue;
+      if (ent->ss[PIPE_SHADER_TESS_CTRL] &&
+          ent->ss[PIPE_SHADER_TESS_CTRL]->id != tcs_id)
+         continue;
+      if (ent->ss[PIPE_SHADER_TESS_EVAL] &&
+          ent->ss[PIPE_SHADER_TESS_EVAL]->id != tes_id)
+         continue;
       return ent;
    }
    return NULL;
@@ -1102,7 +1137,7 @@ static void vrend_destroy_program(struct vrend_linked_shader_program *ent)
    glDeleteProgram(ent->id);
    list_del(&ent->head);
 
-   for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_GEOMETRY; i++) {
+   for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_TESS_EVAL; i++) {
       if (ent->ss[i])
          list_del(&ent->sl[i]);
       free(ent->shadow_samp_mask_locs[i]);
@@ -2170,11 +2205,73 @@ static inline void vrend_fill_shader_key(struct vrend_context *ctx,
 
    if (ctx->sub->shaders[PIPE_SHADER_GEOMETRY])
       key->gs_present = true;
+   if (ctx->sub->shaders[PIPE_SHADER_TESS_CTRL])
+      key->tcs_present = true;
+   if (ctx->sub->shaders[PIPE_SHADER_TESS_EVAL])
+      key->tes_present = true;
+
+   int prev_type = -1;
 
-   if ((type == PIPE_SHADER_GEOMETRY || type == PIPE_SHADER_FRAGMENT) && ctx->sub->shaders[PIPE_SHADER_VERTEX]) {
-      key->prev_stage_pervertex_out = ctx->sub->shaders[PIPE_SHADER_VERTEX]->sinfo.has_pervertex_out;
-      key->prev_stage_num_clip_out = ctx->sub->shaders[PIPE_SHADER_VERTEX]->sinfo.num_clip_out;
-      key->prev_stage_num_cull_out = ctx->sub->shaders[PIPE_SHADER_VERTEX]->sinfo.num_cull_out;
+   switch (type) {
+   case PIPE_SHADER_GEOMETRY:
+      if (key->tcs_present || key->tes_present)
+	 prev_type = PIPE_SHADER_TESS_EVAL;
+      else
+	 prev_type = PIPE_SHADER_VERTEX;
+      break;
+   case PIPE_SHADER_FRAGMENT:
+      if (key->gs_present)
+	 prev_type = PIPE_SHADER_GEOMETRY;
+      else if (key->tcs_present || key->tes_present)
+	 prev_type = PIPE_SHADER_TESS_EVAL;
+      else
+	 prev_type = PIPE_SHADER_VERTEX;
+      break;
+   case PIPE_SHADER_TESS_EVAL:
+      prev_type = PIPE_SHADER_TESS_CTRL;
+      break;
+   case PIPE_SHADER_TESS_CTRL:
+      prev_type = PIPE_SHADER_VERTEX;
+      break;
+   default:
+      break;
+   }
+   if (prev_type != -1 && ctx->sub->shaders[prev_type]) {
+      key->prev_stage_pervertex_out = ctx->sub->shaders[prev_type]->sinfo.has_pervertex_out;
+      key->prev_stage_num_clip_out = ctx->sub->shaders[prev_type]->sinfo.num_clip_out;
+      key->prev_stage_num_cull_out = ctx->sub->shaders[prev_type]->sinfo.num_cull_out;
+      key->num_indirect_generic_inputs = ctx->sub->shaders[prev_type]->sinfo.num_indirect_generic_outputs;
+      key->num_indirect_patch_inputs = ctx->sub->shaders[prev_type]->sinfo.num_indirect_patch_outputs;
+   }
+
+   int next_type = -1;
+   switch (type) {
+   case PIPE_SHADER_VERTEX:
+     if (key->tcs_present)
+       next_type = PIPE_SHADER_TESS_CTRL;
+     else if (key->gs_present)
+       next_type = PIPE_SHADER_GEOMETRY;
+     else
+       next_type = PIPE_SHADER_FRAGMENT;
+     break;
+   case PIPE_SHADER_TESS_CTRL:
+     next_type = PIPE_SHADER_TESS_EVAL;
+     break;
+   case PIPE_SHADER_GEOMETRY:
+     next_type = PIPE_SHADER_FRAGMENT;
+     break;
+   case PIPE_SHADER_TESS_EVAL:
+     if (key->gs_present)
+       next_type = PIPE_SHADER_GEOMETRY;
+     else
+       next_type = PIPE_SHADER_FRAGMENT;
+   default:
+     break;
+   }
+
+   if (next_type != -1 && ctx->sub->shaders[next_type]) {
+      key->num_indirect_generic_outputs = ctx->sub->shaders[next_type]->sinfo.num_indirect_generic_inputs;
+      key->num_indirect_patch_outputs = ctx->sub->shaders[next_type]->sinfo.num_indirect_patch_inputs;
    }
 }
 
@@ -2313,7 +2410,12 @@ int vrend_create_shader(struct vrend_context *ctx,
    bool finished = false;
    int ret;
 
-   if (type > PIPE_SHADER_GEOMETRY)
+   if (type > PIPE_SHADER_TESS_EVAL)
+      return EINVAL;
+
+   if (!vrend_state.have_tessellation &&
+       (type == PIPE_SHADER_TESS_CTRL ||
+        type == PIPE_SHADER_TESS_EVAL))
       return EINVAL;
 
    if (offlen & VIRGL_OBJ_SHADER_OFFSET_CONT)
@@ -2440,7 +2542,7 @@ void vrend_bind_shader(struct vrend_context *ctx,
 {
    struct vrend_shader_selector *sel;
 
-   if (type > PIPE_SHADER_GEOMETRY)
+   if (type > PIPE_SHADER_TESS_EVAL)
       return;
 
    if (handle == 0) {
@@ -2988,7 +3090,7 @@ void vrend_draw_vbo(struct vrend_context *ctx,
 
    if (ctx->sub->shader_dirty) {
       struct vrend_linked_shader_program *prog;
-      bool fs_dirty, vs_dirty, gs_dirty;
+      bool fs_dirty, vs_dirty, gs_dirty, tcs_dirty, tes_dirty;
       bool dual_src = util_blend_state_is_dual(&ctx->sub->blend_state, 0);
       bool same_prog;
       if (!ctx->sub->shaders[PIPE_SHADER_VERTEX] || !ctx->sub->shaders[PIPE_SHADER_FRAGMENT]) {
@@ -3000,10 +3102,16 @@ void vrend_draw_vbo(struct vrend_context *ctx,
       vrend_shader_select(ctx, ctx->sub->shaders[PIPE_SHADER_VERTEX], &vs_dirty);
       if (ctx->sub->shaders[PIPE_SHADER_GEOMETRY])
          vrend_shader_select(ctx, ctx->sub->shaders[PIPE_SHADER_GEOMETRY], &gs_dirty);
+      if (ctx->sub->shaders[PIPE_SHADER_TESS_CTRL])
+         vrend_shader_select(ctx, ctx->sub->shaders[PIPE_SHADER_TESS_CTRL], &tcs_dirty);
+      if (ctx->sub->shaders[PIPE_SHADER_TESS_EVAL])
+         vrend_shader_select(ctx, ctx->sub->shaders[PIPE_SHADER_TESS_EVAL], &tes_dirty);
 
       if (!ctx->sub->shaders[PIPE_SHADER_VERTEX]->current ||
           !ctx->sub->shaders[PIPE_SHADER_FRAGMENT]->current ||
-          (ctx->sub->shaders[PIPE_SHADER_GEOMETRY] && !ctx->sub->shaders[PIPE_SHADER_GEOMETRY]->current)) {
+          (ctx->sub->shaders[PIPE_SHADER_GEOMETRY] && !ctx->sub->shaders[PIPE_SHADER_GEOMETRY]->current) ||
+          (ctx->sub->shaders[PIPE_SHADER_TESS_CTRL] && !ctx->sub->shaders[PIPE_SHADER_TESS_CTRL]->current) ||
+          (ctx->sub->shaders[PIPE_SHADER_TESS_EVAL] && !ctx->sub->shaders[PIPE_SHADER_TESS_EVAL]->current)) {
          fprintf(stderr, "failure to compile shader variants: %s\n", ctx->debug_name);
          return;
       }
@@ -3016,23 +3124,31 @@ void vrend_draw_vbo(struct vrend_context *ctx,
          same_prog = false;
       if (ctx->sub->prog && ctx->sub->prog->dual_src_linked != dual_src)
          same_prog = false;
+      if (ctx->sub->shaders[PIPE_SHADER_TESS_CTRL] && ctx->sub->shaders[PIPE_SHADER_TESS_CTRL]->current->id != (GLuint)ctx->sub->prog_ids[PIPE_SHADER_TESS_CTRL])
+         same_prog = false;
+      if (ctx->sub->shaders[PIPE_SHADER_TESS_EVAL] && ctx->sub->shaders[PIPE_SHADER_TESS_EVAL]->current->id != (GLuint)ctx->sub->prog_ids[PIPE_SHADER_TESS_EVAL])
+         same_prog = false;
 
       if (!same_prog) {
          prog = lookup_shader_program(ctx,
                                       ctx->sub->shaders[PIPE_SHADER_VERTEX]->current->id,
                                       ctx->sub->shaders[PIPE_SHADER_FRAGMENT]->current->id,
                                       ctx->sub->shaders[PIPE_SHADER_GEOMETRY] ? ctx->sub->shaders[PIPE_SHADER_GEOMETRY]->current->id : 0,
+                                      ctx->sub->shaders[PIPE_SHADER_TESS_CTRL] ? ctx->sub->shaders[PIPE_SHADER_TESS_CTRL]->current->id : 0,
+                                      ctx->sub->shaders[PIPE_SHADER_TESS_EVAL] ? ctx->sub->shaders[PIPE_SHADER_TESS_EVAL]->current->id : 0,
                                       dual_src);
          if (!prog) {
             prog = add_shader_program(ctx,
                                       ctx->sub->shaders[PIPE_SHADER_VERTEX]->current,
                                       ctx->sub->shaders[PIPE_SHADER_FRAGMENT]->current,
-                                      ctx->sub->shaders[PIPE_SHADER_GEOMETRY] ? ctx->sub->shaders[PIPE_SHADER_GEOMETRY]->current : NULL);
+                                      ctx->sub->shaders[PIPE_SHADER_GEOMETRY] ? ctx->sub->shaders[PIPE_SHADER_GEOMETRY]->current : NULL,
+                                      ctx->sub->shaders[PIPE_SHADER_TESS_CTRL] ? ctx->sub->shaders[PIPE_SHADER_TESS_CTRL]->current : NULL,
+                                      ctx->sub->shaders[PIPE_SHADER_TESS_EVAL] ? ctx->sub->shaders[PIPE_SHADER_TESS_EVAL]->current : NULL);
             if (!prog)
                return;
          }
 
-         ctx->sub->last_shader_idx = ctx->sub->shaders[PIPE_SHADER_GEOMETRY] ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT;
+         ctx->sub->last_shader_idx = ctx->sub->shaders[PIPE_SHADER_TESS_EVAL] ? PIPE_SHADER_TESS_EVAL : (ctx->sub->shaders[PIPE_SHADER_GEOMETRY] ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT);
       } else
          prog = ctx->sub->prog;
       if (ctx->sub->prog != prog) {
@@ -3041,6 +3157,10 @@ void vrend_draw_vbo(struct vrend_context *ctx,
          ctx->sub->prog_ids[PIPE_SHADER_FRAGMENT] = ctx->sub->shaders[PIPE_SHADER_FRAGMENT]->current->id;
          if (ctx->sub->shaders[PIPE_SHADER_GEOMETRY])
             ctx->sub->prog_ids[PIPE_SHADER_GEOMETRY] = ctx->sub->shaders[PIPE_SHADER_GEOMETRY]->current->id;
+         if (ctx->sub->shaders[PIPE_SHADER_TESS_CTRL])
+            ctx->sub->prog_ids[PIPE_SHADER_TESS_CTRL] = ctx->sub->shaders[PIPE_SHADER_TESS_CTRL]->current->id;
+         if (ctx->sub->shaders[PIPE_SHADER_TESS_EVAL])
+            ctx->sub->prog_ids[PIPE_SHADER_TESS_EVAL] = ctx->sub->shaders[PIPE_SHADER_TESS_EVAL]->current->id;
          ctx->sub->prog = prog;
       }
    }
@@ -3131,6 +3251,9 @@ void vrend_draw_vbo(struct vrend_context *ctx,
    else
       glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
 
+   if (info->vertices_per_patch && vrend_state.have_tessellation)
+      glPatchParameteri(GL_PATCH_VERTICES, info->vertices_per_patch);
+
    /* set the vertex state up now on a delay */
    if (!info->indexed) {
       GLenum mode = info->mode;
@@ -4395,6 +4518,8 @@ static void vrend_destroy_sub_context(struct vrend_sub_context *sub)
    vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_VERTEX], NULL);
    vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_FRAGMENT], NULL);
    vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_GEOMETRY], NULL);
+   vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_TESS_CTRL], NULL);
+   vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_TESS_EVAL], NULL);
 
    vrend_free_programs(sub);
    for (i = 0; i < PIPE_SHADER_TYPES; i++) {
@@ -4446,6 +4571,8 @@ bool vrend_destroy_context(struct vrend_context *ctx)
    vrend_set_num_sampler_views(ctx, PIPE_SHADER_VERTEX, 0, 0);
    vrend_set_num_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 0);
    vrend_set_num_sampler_views(ctx, PIPE_SHADER_GEOMETRY, 0, 0);
+   vrend_set_num_sampler_views(ctx, PIPE_SHADER_TESS_CTRL, 0, 0);
+   vrend_set_num_sampler_views(ctx, PIPE_SHADER_TESS_EVAL, 0, 0);
 
    vrend_set_streamout_targets(ctx, 0, 0, NULL);
    vrend_set_num_vbo(ctx, 0);
-- 
2.14.3



More information about the virglrenderer-devel mailing list