iris: Add support for TCS passthrough
authorCaio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Fri, 21 Sep 2018 19:22:34 +0000 (12:22 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 21 Feb 2019 18:26:08 +0000 (10:26 -0800)
If no TCS is provided, create a "passthrough" TCS that will take the
default values set in the API as constants and pass to the TES, along
with any other inputs it expects.  The code to create the NIR shader
is the same as in i965.

Tested with

    ./piglit run -t 'tess' quick_shader r

and fixed a dozen crashes from that list.

src/gallium/drivers/iris/iris_context.h
src/gallium/drivers/iris/iris_program.c
src/gallium/drivers/iris/iris_state.c

index 9f847136937a407d8f82a286e33611c12d2d7986..48ebeb63ec27f6e1fc0faad33568535851519edd 100644 (file)
@@ -357,6 +357,9 @@ struct iris_context {
       struct pipe_stencil_ref stencil_ref;
       struct pipe_framebuffer_state framebuffer;
 
+      float default_outer_level[4];
+      float default_inner_level[2];
+
       bool primitive_restart;
       unsigned cut_index;
       enum pipe_prim_type prim_mode:8;
index ab2ce81596120427114c289a5b7d5cd9d2c490b3..8c425c46d17b410376ca0497802f18ed1b0c41de 100644 (file)
@@ -491,6 +491,8 @@ iris_compile_tcs(struct iris_context *ice,
 {
    struct iris_screen *screen = (struct iris_screen *)ice->ctx.screen;
    const struct brw_compiler *compiler = screen->compiler;
+   const struct nir_shader_compiler_options *options =
+      compiler->glsl_compiler_options[MESA_SHADER_TESS_CTRL].NirOptions;
    const struct gen_device_info *devinfo = &screen->devinfo;
    void *mem_ctx = ralloc_context(NULL);
    struct brw_tcs_prog_data *tcs_prog_data =
@@ -498,11 +500,21 @@ iris_compile_tcs(struct iris_context *ice,
    struct brw_vue_prog_data *vue_prog_data = &tcs_prog_data->base;
    struct brw_stage_prog_data *prog_data = &vue_prog_data->base;
 
-   nir_shader *nir = ish->nir;
+   nir_shader *nir;
 
-   assign_common_binding_table_offsets(devinfo, nir, prog_data, 0);
+   if (ish) {
+      nir = ish->nir;
 
-   iris_setup_uniforms(compiler, mem_ctx, nir, prog_data);
+      assign_common_binding_table_offsets(devinfo, nir, prog_data, 0);
+      iris_setup_uniforms(compiler, mem_ctx, nir, prog_data);
+   } else {
+      nir = brw_nir_create_passthrough_tcs(mem_ctx, compiler, options, key);
+
+      /* Reserve space for passing the default tess levels as constants. */
+      prog_data->param = rzalloc_array(mem_ctx, uint32_t, 8);
+      prog_data->nr_params = 8;
+      prog_data->ubo_ranges[0].length = 1;
+   }
 
    char *error_str = NULL;
    const unsigned *program =
@@ -533,21 +545,13 @@ iris_update_compiled_tcs(struct iris_context *ice)
 {
    struct iris_uncompiled_shader *tcs =
       ice->shaders.uncompiled[MESA_SHADER_TESS_CTRL];
-   struct iris_uncompiled_shader *tes =
-      ice->shaders.uncompiled[MESA_SHADER_TESS_EVAL];
-
-   assert(!(tes && !tcs));
-
-   if (!tcs) {
-      iris_unbind_shader(ice, IRIS_CACHE_TCS);
-      return;
-   }
 
    const struct shader_info *tes_info =
       iris_get_shader_info(ice, MESA_SHADER_TESS_EVAL);
    struct brw_tcs_prog_key key = {
-      .program_string_id = tcs->program_id,
+      .program_string_id = tcs ? tcs->program_id : get_new_program_id((void *)ice->ctx.screen),
       .tes_primitive_mode = tes_info->tess.primitive_mode,
+      .input_vertices = ice->state.vertices_per_patch,
    };
    get_unified_tess_slots(ice, &key.outputs_written,
                           &key.patch_outputs_written);
@@ -620,11 +624,6 @@ iris_update_compiled_tes(struct iris_context *ice)
    struct iris_uncompiled_shader *ish =
       ice->shaders.uncompiled[MESA_SHADER_TESS_EVAL];
 
-   if (!ish) {
-      iris_unbind_shader(ice, IRIS_CACHE_TES);
-      return;
-   }
-
    struct brw_tes_prog_key key = { .program_string_id = ish->program_id };
    get_unified_tess_slots(ice, &key.inputs_read, &key.patch_inputs_read);
    ice->vtbl.populate_tes_key(ice, &key);
@@ -861,12 +860,20 @@ iris_update_compiled_shaders(struct iris_context *ice)
          old_prog_datas[i] = get_vue_prog_data(ice, i);
    }
 
+   if (dirty & (IRIS_DIRTY_UNCOMPILED_TCS | IRIS_DIRTY_UNCOMPILED_TES)) {
+       struct iris_uncompiled_shader *tes =
+          ice->shaders.uncompiled[MESA_SHADER_TESS_EVAL];
+       if (tes) {
+          iris_update_compiled_tcs(ice);
+          iris_update_compiled_tes(ice);
+       } else {
+          iris_unbind_shader(ice, IRIS_CACHE_TCS);
+          iris_unbind_shader(ice, IRIS_CACHE_TES);
+       }
+   }
+
    if (dirty & IRIS_DIRTY_UNCOMPILED_VS)
       iris_update_compiled_vs(ice);
-   if (dirty & IRIS_DIRTY_UNCOMPILED_TCS)
-      iris_update_compiled_tcs(ice);
-   if (dirty & IRIS_DIRTY_UNCOMPILED_TES)
-      iris_update_compiled_tes(ice);
    if (dirty & IRIS_DIRTY_UNCOMPILED_GS)
       iris_update_compiled_gs(ice);
 
index 0abd0fd2f02aff05fd5ac055ad84e5bd2d6ca9c7..0485a8aa2fd75de2967126872cd2dfc1d5b2ccd9 100644 (file)
@@ -1510,6 +1510,22 @@ iris_set_sampler_views(struct pipe_context *ctx,
    ice->state.dirty |= (IRIS_DIRTY_BINDINGS_VS << stage);
 }
 
+/**
+ * The pipe->set_tess_state() driver hook.
+ */
+static void
+iris_set_tess_state(struct pipe_context *ctx,
+                    const float default_outer_level[4],
+                    const float default_inner_level[2])
+{
+   struct iris_context *ice = (struct iris_context *) ctx;
+
+   memcpy(&ice->state.default_outer_level[0], &default_outer_level[0], 4 * sizeof(float));
+   memcpy(&ice->state.default_inner_level[0], &default_inner_level[0], 2 * sizeof(float));
+
+   ice->state.dirty |= IRIS_DIRTY_CONSTANTS_TCS;
+}
+
 static void
 iris_surface_destroy(struct pipe_context *ctx, struct pipe_surface *p_surf)
 {
@@ -3157,7 +3173,6 @@ iris_populate_binding_table(struct iris_context *ice,
    if (!shader)
       return;
 
-   const struct shader_info *info = iris_get_shader_info(ice, stage);
    struct iris_shader_state *shs = &ice->state.shaders[stage];
    uint32_t binder_addr = binder->bo->gtt_offset;
 
@@ -3165,6 +3180,13 @@ iris_populate_binding_table(struct iris_context *ice,
    uint32_t *bt_map = binder->map + binder->bt_offset[stage];
    int s = 0;
 
+   const struct shader_info *info = iris_get_shader_info(ice, stage);
+   if (!info) {
+      /* TCS passthrough doesn't need a binding table. */
+      assert(stage == MESA_SHADER_TESS_CTRL);
+      return;
+   }
+
    if (stage == MESA_SHADER_FRAGMENT) {
       struct pipe_framebuffer_state *cso_fb = &ice->state.framebuffer;
       /* Note that cso_fb->nr_cbufs == fs_key->nr_color_regions. */
@@ -3495,6 +3517,43 @@ iris_upload_dirty_render_state(struct iris_context *ice,
       }
    }
 
+   /* Upload constants for TCS passthrough. */
+   if ((dirty & IRIS_DIRTY_CONSTANTS_TCS) &&
+       ice->shaders.prog[MESA_SHADER_TESS_CTRL] &&
+       !ice->shaders.uncompiled[MESA_SHADER_TESS_CTRL]) {
+      struct iris_compiled_shader *tes_shader = ice->shaders.prog[MESA_SHADER_TESS_EVAL];
+      assert(tes_shader);
+
+      /* Passthrough always copies 2 vec4s, so when uploading data we ensure
+       * it is in the right layout for TES.
+       */
+      float hdr[8] = {};
+      struct brw_tes_prog_data *tes_prog_data = (void *) tes_shader->prog_data;
+      switch (tes_prog_data->domain) {
+      case BRW_TESS_DOMAIN_QUAD:
+         for (int i = 0; i < 4; i++)
+            hdr[7 - i] = ice->state.default_outer_level[i];
+         hdr[3] = ice->state.default_inner_level[0];
+         hdr[2] = ice->state.default_inner_level[1];
+         break;
+      case BRW_TESS_DOMAIN_TRI:
+         for (int i = 0; i < 3; i++)
+            hdr[7 - i] = ice->state.default_outer_level[i];
+         hdr[4] = ice->state.default_inner_level[0];
+         break;
+      case BRW_TESS_DOMAIN_ISOLINE:
+         hdr[7] = ice->state.default_outer_level[1];
+         hdr[6] = ice->state.default_outer_level[0];
+         break;
+      }
+
+      struct iris_shader_state *shs = &ice->state.shaders[MESA_SHADER_TESS_CTRL];
+      struct iris_const_buffer *cbuf = &shs->constbuf[0];
+      u_upload_data(ice->ctx.const_uploader, 0, sizeof(hdr), 32,
+                    &hdr[0], &cbuf->data.offset,
+                    &cbuf->data.res);
+   }
+
    for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) {
       if (!(dirty & (IRIS_DIRTY_CONSTANTS_VS << stage)))
          continue;
@@ -4415,6 +4474,7 @@ genX(init_state)(struct iris_context *ice)
    ctx->set_constant_buffer = iris_set_constant_buffer;
    ctx->set_shader_buffers = iris_set_shader_buffers;
    ctx->set_sampler_views = iris_set_sampler_views;
+   ctx->set_tess_state = iris_set_tess_state;
    ctx->set_framebuffer_state = iris_set_framebuffer_state;
    ctx->set_polygon_stipple = iris_set_polygon_stipple;
    ctx->set_sample_mask = iris_set_sample_mask;