[Mesa-dev] [PATCH v2 10/14] anv: Compile TCS/TES shaders.

Jason Ekstrand jason at jlekstrand.net
Tue Jan 10 17:17:45 UTC 2017


On Mon, Jan 9, 2017 at 11:37 PM, Kenneth Graunke <kenneth at whitecape.org>
wrote:

> v2: Merge more TCS/TES info.
>
> Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
> ---
>  src/intel/vulkan/anv_pipeline.c | 189 ++++++++++++++++++++++++++++++
> +++++++++-
>  1 file changed, 187 insertions(+), 2 deletions(-)
>
> Jason and I figured out caching.  It turns out I had a one line bug.
>
> diff --git a/src/intel/vulkan/anv_pipeline.c b/src/intel/vulkan/anv_
> pipeline.c
> index 0dc7019efb1..79536e62458 100644
> --- a/src/intel/vulkan/anv_pipeline.c
> +++ b/src/intel/vulkan/anv_pipeline.c
> @@ -499,6 +499,184 @@ anv_pipeline_compile_vs(struct anv_pipeline
> *pipeline,
>     return VK_SUCCESS;
>  }
>
> +static void
> +merge_tess_info(struct shader_info *tes_info,
> +                const struct shader_info *tcs_info)
> +{
> +   /* The Vulkan 1.0.38 spec, section 21.1 Tessellator says:
> +    *
> +    *    "PointMode. Controls generation of points rather than triangles
> +    *     or lines. This functionality defaults to disabled, and is
> +    *     enabled if either shader stage includes the execution mode.
> +    *
> +    * and about Triangles, Quads, IsoLines, VertexOrderCw, VertexOrderCcw,
> +    * PointMode, SpacingEqual, SpacingFractionalEven,
> SpacingFractionalOdd,
> +    * and OutputVertices, it says:
> +    *
> +    *    "One mode must be set in at least one of the tessellation
> +    *     shader stages."
> +    *
> +    * So, the fields can be set in either the TCS or TES, but they must
> +    * agree if set in both.  Our backend looks at TES, so bitwise-or in
> +    * the values from the TCS.
> +    */
> +   assert(tcs_info->tess.tcs_vertices_out == 0 ||
> +          tes_info->tess.tcs_vertices_out == 0 ||
> +          tcs_info->tess.tcs_vertices_out == tes_info->tess.tcs_vertices_
> out);
> +   tes_info->tess.tcs_vertices_out |= tcs_info->tess.tcs_vertices_out;
> +
> +   assert(tcs_info->tess.spacing == TESS_SPACING_UNSPECIFIED ||
> +          tes_info->tess.spacing == TESS_SPACING_UNSPECIFIED ||
> +          tcs_info->tess.spacing == tes_info->tess.spacing);
> +   tes_info->tess.spacing |= tcs_info->tess.spacing;
> +
> +   tes_info->tess.ccw |= tcs_info->tess.ccw;
> +   tes_info->tess.point_mode |= tcs_info->tess.point_mode;
> +}
> +
> +static VkResult
> +anv_pipeline_compile_tcs_tes(struct anv_pipeline *pipeline,
> +                             struct anv_pipeline_cache *cache,
> +                             const VkGraphicsPipelineCreateInfo *info,
> +                             struct anv_shader_module *tcs_module,
> +                             const char *tcs_entrypoint,
> +                             const VkSpecializationInfo *tcs_spec_info,
> +                             struct anv_shader_module *tes_module,
> +                             const char *tes_entrypoint,
> +                             const VkSpecializationInfo *tes_spec_info)
> +{
> +   const struct gen_device_info *devinfo = &pipeline->device->info;
> +   const struct brw_compiler *compiler =
> +      pipeline->device->instance->physicalDevice.compiler;
> +   struct anv_pipeline_bind_map tcs_map;
> +   struct anv_pipeline_bind_map tes_map;
> +   struct brw_tcs_prog_key tcs_key = { 0, };
> +   struct brw_tes_prog_key tes_key = { 0, };
> +   struct anv_shader_bin *tcs_bin = NULL;
> +   struct anv_shader_bin *tes_bin = NULL;
> +   unsigned char tcs_sha1[20];
> +   unsigned char tes_sha1[20];
> +
> +   populate_sampler_prog_key(&pipeline->device->info, &tcs_key.tex);
> +   populate_sampler_prog_key(&pipeline->device->info, &tes_key.tex);
> +   tcs_key.input_vertices = info->pTessellationState->patchControlPoints;
> +
> +   if (cache) {
> +      anv_hash_shader(tcs_sha1, &tcs_key, sizeof(tcs_key), tcs_module,
> +                      tcs_entrypoint, pipeline->layout, tcs_spec_info);
> +      anv_hash_shader(tes_sha1, &tes_key, sizeof(tes_key), tes_module,
> +                      tes_entrypoint, pipeline->layout, tes_spec_info);
> +      tcs_bin = anv_pipeline_cache_search(cache, tcs_sha1, 20);
> +      tes_bin = anv_pipeline_cache_search(cache, tes_sha1, 20);
> +   }
> +
> +   if (tcs_bin == NULL || tes_bin == NULL) {
>

So... caching... What happens if one of them succeeds but not the other?  I
think we have a fundamental caching problem here in that we assume that
they are compiled together but we cache them separately.  My feeling is
that they have to somehow be cached together.  This may mean some pipeline
cache changes.  Or...

Another option would be to hash the two keys together somehow.
Specifically, you could concatenate the two individual hashes and hash that
to get a new "joint hash" which includes both.  You then just need to do
something to it to ensure that the TES and TCS have different hashes.  We
could do something stupid such as XOR in some bits to turn TES into TCS or
vice versa or we could just change the order of the concatenation or
something.  In any case, we need both hashes to take the other shader into
account.


> +      struct brw_tcs_prog_data tcs_prog_data = { 0, };
> +      struct brw_tes_prog_data tes_prog_data = { 0, };
> +      struct anv_pipeline_binding tcs_surface_to_descriptor[256];
> +      struct anv_pipeline_binding tcs_sampler_to_descriptor[256];
> +      struct anv_pipeline_binding tes_surface_to_descriptor[256];
> +      struct anv_pipeline_binding tes_sampler_to_descriptor[256];
> +
> +      tcs_map = (struct anv_pipeline_bind_map) {
> +         .surface_to_descriptor = tcs_surface_to_descriptor,
> +         .sampler_to_descriptor = tcs_sampler_to_descriptor
> +      };
> +      tes_map = (struct anv_pipeline_bind_map) {
> +         .surface_to_descriptor = tes_surface_to_descriptor,
> +         .sampler_to_descriptor = tes_sampler_to_descriptor
> +      };
> +
> +      nir_shader *tcs_nir =
> +         anv_pipeline_compile(pipeline, tcs_module, tcs_entrypoint,
> +                              MESA_SHADER_TESS_CTRL, tcs_spec_info,
> +                              &tcs_prog_data.base.base, &tcs_map);
> +      nir_shader *tes_nir =
> +         anv_pipeline_compile(pipeline, tes_module, tes_entrypoint,
> +                              MESA_SHADER_TESS_EVAL, tes_spec_info,
> +                              &tes_prog_data.base.base, &tes_map);
> +      if (tcs_nir == NULL || tes_nir == NULL)
> +         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
> +
> +      nir_lower_tes_patch_vertices(tes_nir,
> +                                   tcs_nir->info->tess.tcs_vertices_out);
> +
> +      /* Copy TCS info into the TES info */
> +      merge_tess_info(tes_nir->info, tcs_nir->info);
> +
> +      anv_fill_binding_table(&tcs_prog_data.base.base, 0);
> +      anv_fill_binding_table(&tes_prog_data.base.base, 0);
> +
> +      void *mem_ctx = ralloc_context(NULL);
> +
> +      ralloc_steal(mem_ctx, tcs_nir);
> +      ralloc_steal(mem_ctx, tes_nir);
> +
> +      /* Whacking the key after cache lookup is a bit sketchy, but all of
> +       * this comes from the SPIR-V, which is part of the hash used for
> the
> +       * pipeline cache.  So it should be safe.
> +       */
> +      tcs_key.tes_primitive_mode = tes_nir->info->tess.primitive_mode;
> +      tcs_key.outputs_written = tcs_nir->info->outputs_written;
> +      tcs_key.patch_outputs_written = tcs_nir->info->patch_outputs_
> written;
> +      tcs_key.quads_workaround =
> +         devinfo->gen < 9 &&
> +         tes_nir->info->tess.primitive_mode == 7 /* GL_QUADS */ &&
> +         tes_nir->info->tess.spacing == TESS_SPACING_EQUAL;
> +
> +      tes_key.inputs_read = tcs_key.outputs_written;
> +      tes_key.patch_inputs_read = tcs_key.patch_outputs_written;
> +
> +      unsigned code_size;
> +      const int shader_time_index = -1;
> +      const unsigned *shader_code;
> +
> +      shader_code =
> +         brw_compile_tcs(compiler, NULL, mem_ctx, &tcs_key,
> &tcs_prog_data,
> +                         tcs_nir, shader_time_index, &code_size, NULL);
> +      if (shader_code == NULL) {
> +         ralloc_free(mem_ctx);
> +         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
> +      }
> +
> +      tcs_bin = anv_pipeline_upload_kernel(pipeline, cache, tcs_sha1, 20,
> +                                           shader_code, code_size,
> +                                           &tcs_prog_data.base.base,
> +                                           sizeof(tcs_prog_data),
> +                                           &tcs_map);
> +      if (!tcs_bin) {
> +         ralloc_free(mem_ctx);
> +         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
> +      }
> +
> +      shader_code =
> +         brw_compile_tes(compiler, NULL, mem_ctx, &tes_key,
> +                         &tcs_prog_data.base.vue_map, &tes_prog_data,
> tes_nir,
> +                         NULL, shader_time_index, &code_size, NULL);
> +      if (shader_code == NULL) {
> +         ralloc_free(mem_ctx);
> +         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
> +      }
> +
> +      tes_bin = anv_pipeline_upload_kernel(pipeline, cache, tes_sha1, 20,
> +                                           shader_code, code_size,
> +                                           &tes_prog_data.base.base,
> +                                           sizeof(tes_prog_data),
> +                                           &tes_map);
> +      if (!tes_bin) {
> +         ralloc_free(mem_ctx);
> +         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
> +      }
> +
> +      ralloc_free(mem_ctx);
> +   }
> +
> +   anv_pipeline_add_compiled_stage(pipeline, MESA_SHADER_TESS_CTRL,
> tcs_bin);
> +   anv_pipeline_add_compiled_stage(pipeline, MESA_SHADER_TESS_EVAL,
> tes_bin);
> +
> +   return VK_SUCCESS;
> +}
> +
>  static VkResult
>  anv_pipeline_compile_gs(struct anv_pipeline *pipeline,
>                          struct anv_pipeline_cache *cache,
> @@ -1032,8 +1210,15 @@ anv_pipeline_init(struct anv_pipeline *pipeline,
>           goto compile_fail;
>     }
>
> -   if (modules[MESA_SHADER_TESS_CTRL] || modules[MESA_SHADER_TESS_EVAL])
> -      anv_finishme("no tessellation support");
> +   if (modules[MESA_SHADER_TESS_EVAL]) {
> +      anv_pipeline_compile_tcs_tes(pipeline, cache, pCreateInfo,
> +                                   modules[MESA_SHADER_TESS_CTRL],
> +                                   pStages[MESA_SHADER_TESS_CTRL]->pName,
> +                                   pStages[MESA_SHADER_TESS_CTRL]
> ->pSpecializationInfo,
> +                                   modules[MESA_SHADER_TESS_EVAL],
> +                                   pStages[MESA_SHADER_TESS_EVAL]->pName,
> +                                   pStages[MESA_SHADER_TESS_EVAL]
> ->pSpecializationInfo);
> +   }
>
>     if (modules[MESA_SHADER_GEOMETRY]) {
>        result = anv_pipeline_compile_gs(pipeline, cache, pCreateInfo,
> --
> 2.11.0
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170110/80022f44/attachment-0001.html>


More information about the mesa-dev mailing list