tu: Implement extendedDynamicState2PatchControlPoints
authorConnor Abbott <cwabbott0@gmail.com>
Wed, 21 Sep 2022 14:46:53 +0000 (16:46 +0200)
committerMarge Bot <emma+marge@anholt.net>
Tue, 4 Oct 2022 15:39:43 +0000 (15:39 +0000)
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18773>

src/freedreno/vulkan/tu_clear_blit.c
src/freedreno/vulkan/tu_cmd_buffer.c
src/freedreno/vulkan/tu_cmd_buffer.h
src/freedreno/vulkan/tu_device.c
src/freedreno/vulkan/tu_pipeline.c
src/freedreno/vulkan/tu_pipeline.h

index 3d6c004..24ab70a 100644 (file)
@@ -760,7 +760,7 @@ r3d_common(struct tu_cmd_buffer *cmd, struct tu_cs *cs, bool blit,
    }
    tu_cs_emit_regs(cs, A6XX_VFD_MULTIVIEW_CNTL());
 
-   tu6_emit_vpc(cs, vs, NULL, NULL, NULL, fs, 0);
+   tu6_emit_vpc(cs, vs, NULL, NULL, NULL, fs);
 
    /* REPL_MODE for varying with RECTLIST (2 vertices only) */
    tu_cs_emit_regs(cs, A6XX_VPC_VARYING_INTERP_MODE(0, 0));
index 062f925..769fca2 100644 (file)
@@ -2564,15 +2564,11 @@ tu_CmdBindPipeline(VkCommandBuffer commandBuffer,
    if (pipeline->active_stages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
       cmd->state.rp.has_tess = true;
 
-      /* maximum number of patches that can fit in tess factor/param buffers */
-      uint32_t subdraw_size = MIN2(TU_TESS_FACTOR_SIZE / ir3_tess_factor_stride(pipeline->tess.patch_type),
-                           TU_TESS_PARAM_SIZE / pipeline->program.hs_param_stride);
-      /* convert from # of patches to draw count */
-      subdraw_size *= pipeline->tess.patch_control_points;
-
-      /* TODO: Move this packet to pipeline state, since it's constant based on the pipeline. */
-      tu_cs_emit_pkt7(cs, CP_SET_SUBDRAW_SIZE, 1);
-      tu_cs_emit(cs, subdraw_size);
+      if (!(pipeline->dynamic_state_mask &
+            BIT(TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS)))
+         cmd->state.patch_control_points = pipeline->tess.patch_control_points;
+      else
+         cmd->state.dirty |= TU_CMD_DIRTY_PATCH_CONTROL_POINTS;
    }
 
    cmd->state.line_mode = pipeline->rast.line_mode;
@@ -3030,7 +3026,11 @@ VKAPI_ATTR void VKAPI_CALL
 tu_CmdSetPatchControlPointsEXT(VkCommandBuffer commandBuffer,
                                uint32_t patchControlPoints)
 {
-   tu_stub();
+   TU_FROM_HANDLE(tu_cmd_buffer, cmd, commandBuffer);
+
+   cmd->state.patch_control_points = patchControlPoints;
+
+   cmd->state.dirty |= TU_CMD_DIRTY_PATCH_CONTROL_POINTS;
 }
 
 VKAPI_ATTR void VKAPI_CALL
@@ -4465,6 +4465,15 @@ tu6_draw_common(struct tu_cmd_buffer *cmd,
       tu6_emit_blend(&cs, cmd);
    }
 
+   if (cmd->state.dirty & TU_CMD_DIRTY_PATCH_CONTROL_POINTS) {
+      bool tess = cmd->state.pipeline->active_stages &
+         VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
+      struct tu_cs cs = tu_cmd_dynamic_state(cmd, TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS,
+                                             tess ? TU6_EMIT_PATCH_CONTROL_POINTS_DWORDS : 0);
+      tu6_emit_patch_control_points(&cs, cmd->state.pipeline,
+                                    cmd->state.patch_control_points);
+   }
+
    /* for the first draw in a renderpass, re-emit all the draw states
     *
     * and if a draw-state disabling path (CmdClearAttachments 3D fallback) was
@@ -4502,7 +4511,8 @@ tu6_draw_common(struct tu_cmd_buffer *cmd,
       /* emit draw states that were just updated
        * note we eventually don't want to have to emit anything here
        */
-      bool emit_binding_stride = false, emit_blend = false;
+      bool emit_binding_stride = false, emit_blend = false,
+           emit_patch_control_points = false;
       uint32_t draw_state_count =
          ((cmd->state.dirty & TU_CMD_DIRTY_SHADER_CONSTS) ? 1 : 0) +
          ((cmd->state.dirty & TU_CMD_DIRTY_DESC_SETS_LOAD) ? 1 : 0) +
@@ -4522,6 +4532,13 @@ tu6_draw_common(struct tu_cmd_buffer *cmd,
          draw_state_count += 1;
       }
 
+      if ((cmd->state.dirty & TU_CMD_DIRTY_PATCH_CONTROL_POINTS) &&
+          (pipeline->dynamic_state_mask &
+           BIT(TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS))) {
+         emit_patch_control_points = true;
+         draw_state_count += 1;
+      }
+
       if (draw_state_count > 0)
          tu_cs_emit_pkt7(cs, CP_SET_DRAW_STATE, 3 * draw_state_count);
 
@@ -4539,6 +4556,10 @@ tu6_draw_common(struct tu_cmd_buffer *cmd,
          tu_cs_emit_draw_state(cs, TU_DRAW_STATE_DYNAMIC + TU_DYNAMIC_STATE_BLEND,
                                cmd->state.dynamic_state[TU_DYNAMIC_STATE_BLEND]);
       }
+      if (emit_patch_control_points) {
+         tu_cs_emit_draw_state(cs, TU_DRAW_STATE_DYNAMIC + TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS,
+                               cmd->state.dynamic_state[TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS]);
+      }
       if (cmd->state.dirty & TU_CMD_DIRTY_VS_PARAMS)
          tu_cs_emit_draw_state(cs, TU_DRAW_STATE_VS_PARAMS, cmd->state.vs_params);
 
@@ -4564,7 +4585,7 @@ tu_draw_initiator(struct tu_cmd_buffer *cmd, enum pc_di_src_sel src_sel)
    enum pc_di_primtype primtype = cmd->state.primtype;
 
    if (primtype == DI_PT_PATCHES0)
-      primtype += pipeline->tess.patch_control_points;
+      primtype += cmd->state.patch_control_points;
 
    uint32_t initiator =
       CP_DRAW_INDX_OFFSET_0_PRIM_TYPE(primtype) |
index ae359ce..e41698a 100644 (file)
@@ -66,8 +66,9 @@ enum tu_cmd_dirty_bits
    TU_CMD_DIRTY_RASTERIZER_DISCARD = BIT(10),
    TU_CMD_DIRTY_VIEWPORTS = BIT(11),
    TU_CMD_DIRTY_BLEND = BIT(12),
+   TU_CMD_DIRTY_PATCH_CONTROL_POINTS = BIT(13),
    /* all draw states were disabled and need to be re-enabled: */
-   TU_CMD_DIRTY_DRAW_STATE = BIT(13)
+   TU_CMD_DIRTY_DRAW_STATE = BIT(14)
 };
 
 /* There are only three cache domains we have to care about: the CCU, or
@@ -408,6 +409,8 @@ struct tu_cmd_state
    bool msaa_disable;
    bool z_negative_one_to_one;
 
+   unsigned patch_control_points;
+
    /* VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT and
     * VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT are allowed to run simultaniously,
     * but they use the same {START,STOP}_PRIMITIVE_CTRS control.
index 3a66954..3f2e6dc 100644 (file)
@@ -754,7 +754,7 @@ tu_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
             (VkPhysicalDeviceExtendedDynamicState2FeaturesEXT *)ext;
          features->extendedDynamicState2 = true;
          features->extendedDynamicState2LogicOp = true;
-         features->extendedDynamicState2PatchControlPoints = false;
+         features->extendedDynamicState2PatchControlPoints = true;
          break;
       }
       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR: {
index 804776e..0dcb181 100644 (file)
@@ -1165,8 +1165,7 @@ tu6_emit_vpc(struct tu_cs *cs,
              const struct ir3_shader_variant *hs,
              const struct ir3_shader_variant *ds,
              const struct ir3_shader_variant *gs,
-             const struct ir3_shader_variant *fs,
-             uint32_t patch_control_points)
+             const struct ir3_shader_variant *fs)
 {
    /* note: doesn't compile as static because of the array regs.. */
    const struct reg_config {
@@ -1417,39 +1416,6 @@ tu6_emit_vpc(struct tu_cs *cs,
       tu_cs_emit_pkt4(cs, REG_A6XX_PC_TESS_NUM_VERTEX, 1);
       tu_cs_emit(cs, hs->tess.tcs_vertices_out);
 
-      uint32_t patch_local_mem_size_16b =
-         patch_control_points * vs->output_size / 4;
-
-      /* Total attribute slots in HS incoming patch. */
-      tu_cs_emit_pkt4(cs, REG_A6XX_PC_HS_INPUT_SIZE, 1);
-      tu_cs_emit(cs, patch_local_mem_size_16b);
-
-      const uint32_t wavesize = 64;
-      const uint32_t vs_hs_local_mem_size = 16384;
-
-      uint32_t max_patches_per_wave;
-      if (cs->device->physical_device->info->a6xx.tess_use_shared) {
-         /* HS invocations for a patch are always within the same wave,
-          * making barriers less expensive. VS can't have barriers so we
-          * don't care about VS invocations being in the same wave.
-          */
-         max_patches_per_wave = wavesize / hs->tess.tcs_vertices_out;
-      } else {
-         /* VS is also in the same wave */
-         max_patches_per_wave =
-            wavesize / MAX2(patch_control_points, hs->tess.tcs_vertices_out);
-      }
-
-      uint32_t patches_per_wave =
-         MIN2(vs_hs_local_mem_size / (patch_local_mem_size_16b * 16),
-              max_patches_per_wave);
-
-      uint32_t wave_input_size = DIV_ROUND_UP(
-         patches_per_wave * patch_local_mem_size_16b * 16, 256);
-
-      tu_cs_emit_pkt4(cs, REG_A6XX_SP_HS_WAVE_INPUT_SIZE, 1);
-      tu_cs_emit(cs, wave_input_size);
-
       /* In SPIR-V generated from GLSL, the tessellation primitive params are
        * are specified in the tess eval shader, but in SPIR-V generated from
        * HLSL, they are specified in the tess control shader. */
@@ -1723,55 +1689,140 @@ tu6_emit_fs_outputs(struct tu_cs *cs,
 }
 
 static void
-tu6_emit_geom_tess_consts(struct tu_cs *cs,
-                          const struct ir3_shader_variant *vs,
-                          const struct ir3_shader_variant *hs,
-                          const struct ir3_shader_variant *ds,
-                          const struct ir3_shader_variant *gs,
-                          uint32_t cps_per_patch)
+tu6_emit_vs_params(struct tu_cs *cs,
+                   const struct ir3_const_state *const_state,
+                   unsigned constlen,
+                   unsigned param_stride,
+                   unsigned num_vertices)
 {
-   struct tu_device *dev = cs->device;
-
-   uint32_t num_vertices =
-         hs ? cps_per_patch : gs->gs.vertices_in;
-
    uint32_t vs_params[4] = {
-      vs->output_size * num_vertices * 4,  /* vs primitive stride */
-      vs->output_size * 4,                 /* vs vertex stride */
+      param_stride * num_vertices * 4,  /* vs primitive stride */
+      param_stride * 4,                 /* vs vertex stride */
       0,
       0,
    };
-   uint32_t vs_base = ir3_const_state(vs)->offsets.primitive_param;
+   uint32_t vs_base = const_state->offsets.primitive_param;
    tu6_emit_const(cs, CP_LOAD_STATE6_GEOM, vs_base, SB6_VS_SHADER, 0,
                   ARRAY_SIZE(vs_params), vs_params);
+}
 
-   if (hs) {
-      assert(ds->type != MESA_SHADER_NONE);
-
-      /* Create the shared tess factor BO the first time tess is used on the device. */
+static void
+tu_get_tess_iova(struct tu_device *dev,
+                 uint64_t *tess_factor_iova,
+                 uint64_t *tess_param_iova)
+{
+   /* Create the shared tess factor BO the first time tess is used on the device. */
+   if (!dev->tess_bo) {
       mtx_lock(&dev->mutex);
       if (!dev->tess_bo)
          tu_bo_init_new(dev, &dev->tess_bo, TU_TESS_BO_SIZE, TU_BO_ALLOC_NO_FLAGS, "tess");
       mtx_unlock(&dev->mutex);
+   }
 
-      uint64_t tess_factor_iova = dev->tess_bo->iova;
-      uint64_t tess_param_iova = tess_factor_iova + TU_TESS_FACTOR_SIZE;
+   *tess_factor_iova = dev->tess_bo->iova;
+   *tess_param_iova = dev->tess_bo->iova + TU_TESS_FACTOR_SIZE;
+}
 
-      uint32_t hs_params[8] = {
-         vs->output_size * num_vertices * 4,  /* hs primitive stride */
-         vs->output_size * 4,                 /* hs vertex stride */
-         hs->output_size,
-         cps_per_patch,
-         tess_param_iova,
-         tess_param_iova >> 32,
-         tess_factor_iova,
-         tess_factor_iova >> 32,
-      };
+void
+tu6_emit_patch_control_points(struct tu_cs *cs,
+                              const struct tu_pipeline *pipeline,
+                              unsigned patch_control_points)
+{
+   if (!(pipeline->active_stages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT))
+      return;
+
+   struct tu_device *dev = cs->device;
+
+   tu6_emit_vs_params(cs,
+                      &pipeline->program.link[MESA_SHADER_VERTEX].const_state,
+                      pipeline->program.link[MESA_SHADER_VERTEX].constlen,
+                      pipeline->program.vs_param_stride,
+                      patch_control_points);
+
+   uint64_t tess_factor_iova, tess_param_iova;
+   tu_get_tess_iova(dev, &tess_factor_iova, &tess_param_iova);
+
+   uint32_t hs_params[8] = {
+      pipeline->program.vs_param_stride * patch_control_points * 4,  /* hs primitive stride */
+      pipeline->program.vs_param_stride * 4,                         /* hs vertex stride */
+      pipeline->program.hs_param_stride,
+      patch_control_points,
+      tess_param_iova,
+      tess_param_iova >> 32,
+      tess_factor_iova,
+      tess_factor_iova >> 32,
+   };
+
+   const struct ir3_const_state *hs_const =
+      &pipeline->program.link[MESA_SHADER_TESS_CTRL].const_state;
+   unsigned hs_constlen =
+      pipeline->program.link[MESA_SHADER_TESS_CTRL].constlen;
+   uint32_t hs_base = hs_const->offsets.primitive_param;
+   uint32_t hs_param_dwords = MIN2((hs_constlen - hs_base) * 4, ARRAY_SIZE(hs_params));
+   tu6_emit_const(cs, CP_LOAD_STATE6_GEOM, hs_base, SB6_HS_SHADER, 0,
+                  hs_param_dwords, hs_params);
+
+   uint32_t patch_local_mem_size_16b =
+      patch_control_points * pipeline->program.vs_param_stride / 4;
+
+   /* Total attribute slots in HS incoming patch. */
+   tu_cs_emit_pkt4(cs, REG_A6XX_PC_HS_INPUT_SIZE, 1);
+   tu_cs_emit(cs, patch_local_mem_size_16b);
+
+   const uint32_t wavesize = 64;
+   const uint32_t vs_hs_local_mem_size = 16384;
+
+   uint32_t max_patches_per_wave;
+   if (dev->physical_device->info->a6xx.tess_use_shared) {
+      /* HS invocations for a patch are always within the same wave,
+       * making barriers less expensive. VS can't have barriers so we
+       * don't care about VS invocations being in the same wave.
+       */
+      max_patches_per_wave = wavesize / pipeline->program.hs_vertices_out;
+   } else {
+      /* VS is also in the same wave */
+      max_patches_per_wave =
+         wavesize / MAX2(patch_control_points,
+                         pipeline->program.hs_vertices_out);
+   }
+
+   uint32_t patches_per_wave =
+      MIN2(vs_hs_local_mem_size / (patch_local_mem_size_16b * 16),
+           max_patches_per_wave);
+
+   uint32_t wave_input_size = DIV_ROUND_UP(
+      patches_per_wave * patch_local_mem_size_16b * 16, 256);
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_SP_HS_WAVE_INPUT_SIZE, 1);
+   tu_cs_emit(cs, wave_input_size);
 
-      uint32_t hs_base = hs->const_state->offsets.primitive_param;
-      uint32_t hs_param_dwords = MIN2((hs->constlen - hs_base) * 4, ARRAY_SIZE(hs_params));
-      tu6_emit_const(cs, CP_LOAD_STATE6_GEOM, hs_base, SB6_HS_SHADER, 0,
-                     hs_param_dwords, hs_params);
+   /* maximum number of patches that can fit in tess factor/param buffers */
+   uint32_t subdraw_size = MIN2(TU_TESS_FACTOR_SIZE / ir3_tess_factor_stride(pipeline->tess.patch_type),
+                        TU_TESS_PARAM_SIZE / (pipeline->program.hs_param_stride * 4));
+   /* convert from # of patches to draw count */
+   subdraw_size *= patch_control_points;
+
+   tu_cs_emit_pkt7(cs, CP_SET_SUBDRAW_SIZE, 1);
+   tu_cs_emit(cs, subdraw_size);
+}
+
+static void
+tu6_emit_geom_tess_consts(struct tu_cs *cs,
+                          const struct ir3_shader_variant *vs,
+                          const struct ir3_shader_variant *hs,
+                          const struct ir3_shader_variant *ds,
+                          const struct ir3_shader_variant *gs)
+{
+   struct tu_device *dev = cs->device;
+
+   if (gs && !hs) {
+      tu6_emit_vs_params(cs, ir3_const_state(vs), vs->constlen,
+                         vs->output_size, gs->gs.vertices_in);
+   }
+
+   if (hs) {
+      uint64_t tess_factor_iova, tess_param_iova;
+      tu_get_tess_iova(dev, &tess_factor_iova, &tess_param_iova);
 
       uint32_t ds_params[8] = {
          gs ? ds->output_size * gs->gs.vertices_in * 4 : 0,  /* ds primitive stride */
@@ -1793,7 +1844,7 @@ tu6_emit_geom_tess_consts(struct tu_cs *cs,
    if (gs) {
       const struct ir3_shader_variant *prev = ds ? ds : vs;
       uint32_t gs_params[4] = {
-         prev->output_size * num_vertices * 4,  /* gs primitive stride */
+         prev->output_size * gs->gs.vertices_in * 4,  /* gs primitive stride */
          prev->output_size * 4,                 /* gs vertex stride */
          0,
          0,
@@ -1842,7 +1893,6 @@ tu6_emit_program(struct tu_cs *cs,
    const struct ir3_shader_variant *gs = builder->variants[MESA_SHADER_GEOMETRY];
    const struct ir3_shader_variant *fs = builder->variants[MESA_SHADER_FRAGMENT];
    gl_shader_stage stage = MESA_SHADER_VERTEX;
-   uint32_t cps_per_patch = pipeline->tess.patch_control_points;
    bool multi_pos_output = vs->multi_pos_output;
 
   /* Don't use the binning pass variant when GS is present because we don't
@@ -1899,7 +1949,7 @@ tu6_emit_program(struct tu_cs *cs,
 
    tu6_emit_vfd_dest(cs, vs);
 
-   tu6_emit_vpc(cs, vs, hs, ds, gs, fs, cps_per_patch);
+   tu6_emit_vpc(cs, vs, hs, ds, gs, fs);
 
    if (fs) {
       tu6_emit_fs_inputs(cs, fs);
@@ -1912,7 +1962,7 @@ tu6_emit_program(struct tu_cs *cs,
    }
 
    if (gs || hs) {
-      tu6_emit_geom_tess_consts(cs, vs, hs, ds, gs, cps_per_patch);
+      tu6_emit_geom_tess_consts(cs, vs, hs, ds, gs);
    }
 }
 
@@ -3644,6 +3694,10 @@ tu_pipeline_builder_parse_dynamic(struct tu_pipeline_builder *builder,
          pipeline->dynamic_state_mask |= BIT(TU_DYNAMIC_STATE_VERTEX_INPUT) |
             BIT(TU_DYNAMIC_STATE_VB_STRIDE);
          break;
+      case VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT:
+         pipeline->dynamic_state_mask |=
+            BIT(TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS);
+         break;
       default:
          assert(!"unsupported dynamic state");
          break;
@@ -3699,7 +3753,8 @@ tu_pipeline_builder_parse_libraries(struct tu_pipeline_builder *builder,
             BIT(VK_DYNAMIC_STATE_SCISSOR) |
             BIT(VK_DYNAMIC_STATE_LINE_WIDTH) |
             BIT(VK_DYNAMIC_STATE_DEPTH_BIAS) |
-            BIT(TU_DYNAMIC_STATE_RASTERIZER_DISCARD);
+            BIT(TU_DYNAMIC_STATE_RASTERIZER_DISCARD) |
+            BIT(TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS);
       }
 
       if (library->state &
@@ -3819,6 +3874,19 @@ tu_pipeline_set_linkage(struct tu_program_descriptor_linkage *link,
    link->constlen = v->constlen;
 }
 
+static bool
+tu_pipeline_static_state(struct tu_pipeline *pipeline, struct tu_cs *cs,
+                         uint32_t id, uint32_t size)
+{
+   assert(id < ARRAY_SIZE(pipeline->dynamic_state));
+
+   if (pipeline->dynamic_state_mask & BIT(id))
+      return false;
+
+   pipeline->dynamic_state[id] = tu_cs_draw_state(&pipeline->cs, cs, size);
+   return true;
+}
+
 static void
 tu_pipeline_builder_parse_shader_stages(struct tu_pipeline_builder *builder,
                                         struct tu_pipeline *pipeline)
@@ -3857,22 +3925,21 @@ tu_pipeline_builder_parse_shader_stages(struct tu_pipeline_builder *builder,
                               builder->variants[i]);
    }
 
+   struct ir3_shader_variant *vs = builder->variants[MESA_SHADER_VERTEX];
    struct ir3_shader_variant *hs = builder->variants[MESA_SHADER_TESS_CTRL];
-   if (hs)
-      pipeline->program.hs_param_stride = hs->output_size * 4;
-}
-
-static bool
-tu_pipeline_static_state(struct tu_pipeline *pipeline, struct tu_cs *cs,
-                         uint32_t id, uint32_t size)
-{
-   assert(id < ARRAY_SIZE(pipeline->dynamic_state));
-
-   if (pipeline->dynamic_state_mask & BIT(id))
-      return false;
-
-   pipeline->dynamic_state[id] = tu_cs_draw_state(&pipeline->cs, cs, size);
-   return true;
+   if (hs) {
+      pipeline->program.vs_param_stride = vs->output_size;
+      pipeline->program.hs_param_stride = hs->output_size;
+      pipeline->program.hs_vertices_out = hs->tess.tcs_vertices_out;
+
+      struct tu_cs cs;
+      if (tu_pipeline_static_state(pipeline, &cs,
+                                   TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS,
+                                   TU6_EMIT_PATCH_CONTROL_POINTS_DWORDS)) {
+         tu6_emit_patch_control_points(&cs, pipeline,
+                                       pipeline->tess.patch_control_points);
+      }
+   }
 }
 
 static void
@@ -3970,8 +4037,12 @@ tu_pipeline_builder_parse_tessellation(struct tu_pipeline_builder *builder,
    const VkPipelineTessellationStateCreateInfo *tess_info =
       builder->create_info->pTessellationState;
 
-   assert(tess_info->patchControlPoints <= 32);
-   pipeline->tess.patch_control_points = tess_info->patchControlPoints;
+   if (!(pipeline->dynamic_state_mask &
+         BIT(TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS))) {
+      assert(tess_info->patchControlPoints <= 32);
+      pipeline->tess.patch_control_points = tess_info->patchControlPoints;
+   }
+
    const VkPipelineTessellationDomainOriginStateCreateInfo *domain_info =
          vk_find_struct_const(tess_info->pNext, PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO);
    pipeline->tess.upper_left_domain_origin = !domain_info ||
index 507f111..1328913 100644 (file)
@@ -27,6 +27,7 @@ enum tu_dynamic_state
    TU_DYNAMIC_STATE_RASTERIZER_DISCARD,
    TU_DYNAMIC_STATE_BLEND,
    TU_DYNAMIC_STATE_VERTEX_INPUT,
+   TU_DYNAMIC_STATE_PATCH_CONTROL_POINTS,
    TU_DYNAMIC_STATE_COUNT,
    /* no associated draw state: */
    TU_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY = TU_DYNAMIC_STATE_COUNT,
@@ -206,7 +207,9 @@ struct tu_pipeline
 
       struct tu_program_descriptor_linkage link[MESA_SHADER_STAGES];
 
+      uint32_t vs_param_stride;
       uint32_t hs_param_stride;
+      uint32_t hs_vertices_out;
    } program;
 
    struct
@@ -290,6 +293,13 @@ void tu6_emit_vertex_input(struct tu_cs *cs,
                            uint32_t attr_count,
                            const VkVertexInputAttributeDescription2EXT *attrs);
 
+#define EMIT_CONST_DWORDS(const_dwords) (4 + const_dwords)
+#define TU6_EMIT_PATCH_CONTROL_POINTS_DWORDS \
+   (EMIT_CONST_DWORDS(4) + EMIT_CONST_DWORDS(8) + 2 + 2 + 2)
+void tu6_emit_patch_control_points(struct tu_cs *cs,
+                                   const struct tu_pipeline *pipeline,
+                                   unsigned patch_control_points);
+
 uint32_t tu6_rb_mrt_control_rop(VkLogicOp op, bool *rop_reads_dst);
 
 struct tu_pvtmem_config {
@@ -317,8 +327,7 @@ tu6_emit_vpc(struct tu_cs *cs,
              const struct ir3_shader_variant *hs,
              const struct ir3_shader_variant *ds,
              const struct ir3_shader_variant *gs,
-             const struct ir3_shader_variant *fs,
-             uint32_t patch_control_points);
+             const struct ir3_shader_variant *fs);
 
 void
 tu6_emit_fs_inputs(struct tu_cs *cs, const struct ir3_shader_variant *fs);