topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP ||
topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
(topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
- cmd->state.pipeline &&
- cmd->state.pipeline->base.tess.patch_type == IR3_TESS_ISOLINES);
+ cmd->state.shaders[MESA_SHADER_TESS_EVAL] &&
+ cmd->state.shaders[MESA_SHADER_TESS_EVAL]->variant &&
+ cmd->state.shaders[MESA_SHADER_TESS_EVAL]->variant->key.tessellation == IR3_TESS_ISOLINES);
bool msaa_disable = is_line &&
cmd->vk.dynamic_graphics_state.rs.line.mode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
static void
tu_bind_tes(struct tu_cmd_buffer *cmd, struct tu_shader *tes)
{
- cmd->state.shaders[MESA_SHADER_TESS_EVAL] = tes;
+ if (cmd->state.shaders[MESA_SHADER_TESS_EVAL] != tes) {
+ cmd->state.shaders[MESA_SHADER_TESS_EVAL] = tes;
+ cmd->state.dirty |= TU_CMD_DIRTY_TES;
+
+ if (!cmd->state.tess_params.valid ||
+ cmd->state.tess_params.output_upper_left !=
+ tes->tes.tess_output_upper_left ||
+ cmd->state.tess_params.output_lower_left !=
+ tes->tes.tess_output_lower_left ||
+ cmd->state.tess_params.spacing != tes->tes.tess_spacing) {
+ cmd->state.tess_params.output_upper_left =
+ tes->tes.tess_output_upper_left;
+ cmd->state.tess_params.output_lower_left =
+ tes->tes.tess_output_lower_left;
+ cmd->state.tess_params.spacing = tes->tes.tess_spacing;
+ cmd->state.tess_params.valid = true;
+ cmd->state.dirty |= TU_CMD_DIRTY_TESS_PARAMS;
+ }
+ }
}
static void
cmd->state.per_view_viewport = pipeline->program.per_view_viewport;
cmd->state.dirty |= TU_CMD_DIRTY_PER_VIEW_VIEWPORT;
}
-
- if (pipeline->active_stages & MESA_SHADER_TESS_CTRL) {
- if (!cmd->state.tess_params.valid ||
- cmd->state.tess_params.output_upper_left !=
- pipeline->program.tess_output_upper_left ||
- cmd->state.tess_params.output_lower_left !=
- pipeline->program.tess_output_lower_left ||
- cmd->state.tess_params.spacing != pipeline->program.tess_spacing) {
- cmd->state.tess_params.output_upper_left =
- pipeline->program.tess_output_upper_left;
- cmd->state.tess_params.output_lower_left =
- pipeline->program.tess_output_lower_left;
- cmd->state.tess_params.spacing = pipeline->program.tess_spacing;
- cmd->state.tess_params.valid = true;
- cmd->state.dirty |= TU_CMD_DIRTY_TESS_PARAMS;
- }
- }
}
static void
MESA_VK_DYNAMIC_IA_PRIMITIVE_TOPOLOGY) ||
BITSET_TEST(cmd->vk.dynamic_graphics_state.dirty,
MESA_VK_DYNAMIC_RS_LINE_MODE) ||
- (cmd->state.dirty & TU_CMD_DIRTY_PIPELINE)) {
+ (cmd->state.dirty & TU_CMD_DIRTY_TES)) {
tu6_update_msaa_disable(cmd);
}
if (pipeline->active_stages & VK_SHADER_STAGE_GEOMETRY_BIT)
initiator |= CP_DRAW_INDX_OFFSET_0_GS_ENABLE;
- switch (pipeline->tess.patch_type) {
- case IR3_TESS_TRIANGLES:
- initiator |= CP_DRAW_INDX_OFFSET_0_PATCH_TYPE(TESS_TRIANGLES) |
- CP_DRAW_INDX_OFFSET_0_TESS_ENABLE;
- break;
- case IR3_TESS_ISOLINES:
- initiator |= CP_DRAW_INDX_OFFSET_0_PATCH_TYPE(TESS_ISOLINES) |
- CP_DRAW_INDX_OFFSET_0_TESS_ENABLE;
- break;
- case IR3_TESS_NONE:
- initiator |= CP_DRAW_INDX_OFFSET_0_PATCH_TYPE(TESS_QUADS);
- break;
- case IR3_TESS_QUADS:
- initiator |= CP_DRAW_INDX_OFFSET_0_PATCH_TYPE(TESS_QUADS) |
- CP_DRAW_INDX_OFFSET_0_TESS_ENABLE;
- break;
+ const struct tu_shader *tes = cmd->state.shaders[MESA_SHADER_TESS_EVAL];
+ if (tes->variant) {
+ switch (tes->variant->key.tessellation) {
+ case IR3_TESS_TRIANGLES:
+ initiator |= CP_DRAW_INDX_OFFSET_0_PATCH_TYPE(TESS_TRIANGLES) |
+ CP_DRAW_INDX_OFFSET_0_TESS_ENABLE;
+ break;
+ case IR3_TESS_ISOLINES:
+ initiator |= CP_DRAW_INDX_OFFSET_0_PATCH_TYPE(TESS_ISOLINES) |
+ CP_DRAW_INDX_OFFSET_0_TESS_ENABLE;
+ break;
+ case IR3_TESS_QUADS:
+ initiator |= CP_DRAW_INDX_OFFSET_0_PATCH_TYPE(TESS_QUADS) |
+ CP_DRAW_INDX_OFFSET_0_TESS_ENABLE;
+ break;
+ }
}
return initiator;
}
TU_CMD_DIRTY_SUBPASS = BIT(7),
TU_CMD_DIRTY_FDM = BIT(8),
TU_CMD_DIRTY_PER_VIEW_VIEWPORT = BIT(9),
- TU_CMD_DIRTY_PIPELINE = BIT(10),
+ TU_CMD_DIRTY_TES = BIT(10),
+ TU_CMD_DIRTY_PIPELINE = BIT(11),
/* all draw states were disabled and need to be re-enabled: */
- TU_CMD_DIRTY_DRAW_STATE = BIT(11)
+ TU_CMD_DIRTY_DRAW_STATE = BIT(12)
};
/* There are only three cache domains we have to care about: the CCU, or
tu6_patch_control_points_size(struct tu_device *dev,
const struct tu_shader *vs,
const struct tu_shader *tcs,
+ const struct tu_shader *tes,
const struct tu_pipeline *pipeline,
uint32_t patch_control_points)
{
tu6_emit_patch_control_points(struct tu_cs *cs,
const struct tu_shader *vs,
const struct tu_shader *tcs,
+ const struct tu_shader *tes,
const struct tu_pipeline *pipeline,
uint32_t patch_control_points)
{
tu_cs_emit(cs, wave_input_size);
/* 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),
+ uint32_t subdraw_size = MIN2(TU_TESS_FACTOR_SIZE / ir3_tess_factor_stride(tes->variant->key.tessellation),
TU_TESS_PARAM_SIZE / (tcs->variant->output_size * 4));
/* convert from # of patches to draw count */
subdraw_size *= patch_control_points;
nir_shaders = tu_nir_cache_insert(builder->cache, nir_shaders);
}
+ /* With pipelines, tessellation modes can be set on either shader, for
+ * compatibility with HLSL and GLSL, and the driver is supposed to merge
+ * them. Shader objects requires modes to be set on at least the TES except
+ * for OutputVertices which has to be set at least on the TCS. Make sure
+ * all modes are set on the TES when compiling together multiple shaders,
+ * and then from this point on we will use the modes in the TES (and output
+ * vertices on the TCS).
+ */
+ if (nir[MESA_SHADER_TESS_EVAL]) {
+ nir_shader *tcs = nir[MESA_SHADER_TESS_CTRL];
+ nir_shader *tes = nir[MESA_SHADER_TESS_EVAL];
+
+ if (tes->info.tess._primitive_mode == TESS_PRIMITIVE_UNSPECIFIED)
+ tes->info.tess._primitive_mode = tcs->info.tess._primitive_mode;
+
+ tes->info.tess.point_mode |= tcs->info.tess.point_mode;
+ tes->info.tess.ccw |= tcs->info.tess.ccw;
+
+ if (tes->info.tess.spacing == TESS_SPACING_UNSPECIFIED) {
+ tes->info.tess.spacing = tcs->info.tess.spacing;
+ }
+
+ if (tcs->info.tess.tcs_vertices_out == 0)
+ tcs->info.tess.tcs_vertices_out = tes->info.tess.tcs_vertices_out;
+
+ ir3_key.tessellation = tu6_get_tessmode(tes);
+ }
+
for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < ARRAY_SIZE(nir);
stage = (gl_shader_stage) (stage + 1)) {
if (!nir[stage])
continue;
- /* In SPIR-V generated from GLSL, the primitive mode is specified in the
- * tessellation evaluation shader, but in SPIR-V generated from HLSL,
- * the mode is specified in the tessellation control shader. */
- if ((stage == MESA_SHADER_TESS_EVAL || stage == MESA_SHADER_TESS_CTRL) &&
- ir3_key.tessellation == IR3_TESS_NONE) {
- ir3_key.tessellation = tu6_get_tessmode(nir[stage]);
- }
-
if (stage > MESA_SHADER_TESS_CTRL) {
if (stage == MESA_SHADER_FRAGMENT) {
ir3_key.tcs_store_primid = ir3_key.tcs_store_primid ||
}
}
- if (shaders[MESA_SHADER_TESS_CTRL] &&
- shaders[MESA_SHADER_TESS_CTRL]->variant) {
- pipeline->tess.patch_type =
- shaders[MESA_SHADER_TESS_CTRL]->variant->key.tessellation;
- }
-
if (shaders[MESA_SHADER_VERTEX]) {
const struct ir3_shader_variant *vs =
shaders[MESA_SHADER_VERTEX]->variant;
}
if (library->state &
- VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
- pipeline->tess = library->base.tess;
- }
-
- if (library->state &
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) {
pipeline->ds = library->base.ds;
pipeline->lrz.lrz_status |= library->base.lrz.lrz_status;
uint32_t hs_base = hs_const->offsets.primitive_param;
pipeline->program.hs_param_dwords =
MIN2((hs_constlen - hs_base) * 4, 8);
-
- /* 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. */
- const struct ir3_shader_variant *tess =
- ds->tess.spacing == TESS_SPACING_UNSPECIFIED ? hs : ds;
- if (tess->tess.point_mode) {
- pipeline->program.tess_output_lower_left =
- pipeline->program.tess_output_upper_left = TESS_POINTS;
- } else if (tess->tess.primitive_mode == TESS_PRIMITIVE_ISOLINES) {
- pipeline->program.tess_output_lower_left =
- pipeline->program.tess_output_upper_left = TESS_LINES;
- } else if (tess->tess.ccw) {
- /* Tessellation orientation in HW is specified with a lower-left
- * origin, we need to swap them if the origin is upper-left.
- */
- pipeline->program.tess_output_lower_left = TESS_CCW_TRIS;
- pipeline->program.tess_output_upper_left = TESS_CW_TRIS;
- } else {
- pipeline->program.tess_output_lower_left = TESS_CW_TRIS;
- pipeline->program.tess_output_upper_left = TESS_CCW_TRIS;
- }
-
- switch (tess->tess.spacing) {
- case TESS_SPACING_EQUAL:
- pipeline->program.tess_spacing = TESS_EQUAL;
- break;
- case TESS_SPACING_FRACTIONAL_ODD:
- pipeline->program.tess_spacing = TESS_FRACTIONAL_ODD;
- break;
- case TESS_SPACING_FRACTIONAL_EVEN:
- pipeline->program.tess_spacing = TESS_FRACTIONAL_EVEN;
- break;
- case TESS_SPACING_UNSPECIFIED:
- default:
- unreachable("invalid tess spacing");
- }
}
const struct ir3_shader_variant *last_shader;
pipeline_contains_all_shader_state(pipeline),
pipeline->shaders[MESA_SHADER_VERTEX],
pipeline->shaders[MESA_SHADER_TESS_CTRL],
+ pipeline->shaders[MESA_SHADER_TESS_EVAL],
pipeline,
builder->graphics_state.ts->patch_control_points);
#undef DRAW_STATE
cmd->state.dirty & TU_CMD_DIRTY_PIPELINE,
cmd->state.shaders[MESA_SHADER_VERTEX],
cmd->state.shaders[MESA_SHADER_TESS_CTRL],
+ cmd->state.shaders[MESA_SHADER_TESS_EVAL],
&cmd->state.pipeline->base,
cmd->vk.dynamic_graphics_state.ts.patch_control_points);
#undef DRAW_STATE
struct tu_draw_state dynamic_state[TU_DYNAMIC_STATE_COUNT];
struct {
- unsigned patch_type;
- } tess;
-
- struct {
bool raster_order_attachment_access;
} ds;
struct tu_program_descriptor_linkage link[MESA_SHADER_STAGES];
bool per_view_viewport;
-
- enum a6xx_tess_output tess_output_upper_left, tess_output_lower_left;
- enum a6xx_tess_spacing tess_spacing;
} program;
struct tu_lrz_pipeline lrz;
}
switch (shader->variant->type) {
+ case MESA_SHADER_TESS_EVAL:
+ blob_write_bytes(blob, &shader->tes, sizeof(shader->tes));
+ break;
case MESA_SHADER_FRAGMENT:
blob_write_bytes(blob, &shader->fs, sizeof(shader->fs));
break;
shader->safe_const_variant = ir3_retrieve_variant(blob, dev->compiler, NULL);
switch (shader->variant->type) {
+ case MESA_SHADER_TESS_EVAL:
+ blob_copy_bytes(blob, &shader->tes, sizeof(shader->tes));
+ break;
case MESA_SHADER_FRAGMENT:
blob_copy_bytes(blob, &shader->fs, sizeof(shader->fs));
break;
shader->view_mask = key->multiview_mask;
switch (shader->variant->type) {
+ case MESA_SHADER_TESS_EVAL: {
+ const struct ir3_shader_variant *tes = shader->variant;
+ if (tes->tess.point_mode) {
+ shader->tes.tess_output_lower_left =
+ shader->tes.tess_output_upper_left = TESS_POINTS;
+ } else if (tes->tess.primitive_mode == TESS_PRIMITIVE_ISOLINES) {
+ shader->tes.tess_output_lower_left =
+ shader->tes.tess_output_upper_left = TESS_LINES;
+ } else if (tes->tess.ccw) {
+ /* Tessellation orientation in HW is specified with a lower-left
+ * origin, we need to swap them if the origin is upper-left.
+ */
+ shader->tes.tess_output_lower_left = TESS_CCW_TRIS;
+ shader->tes.tess_output_upper_left = TESS_CW_TRIS;
+ } else {
+ shader->tes.tess_output_lower_left = TESS_CW_TRIS;
+ shader->tes.tess_output_upper_left = TESS_CCW_TRIS;
+ }
+
+ switch (tes->tess.spacing) {
+ case TESS_SPACING_EQUAL:
+ shader->tes.tess_spacing = TESS_EQUAL;
+ break;
+ case TESS_SPACING_FRACTIONAL_ODD:
+ shader->tes.tess_spacing = TESS_FRACTIONAL_ODD;
+ break;
+ case TESS_SPACING_FRACTIONAL_EVEN:
+ shader->tes.tess_spacing = TESS_FRACTIONAL_EVEN;
+ break;
+ case TESS_SPACING_UNSPECIFIED:
+ default:
+ unreachable("invalid tess spacing");
+ }
+
+ break;
+ }
case MESA_SHADER_FRAGMENT: {
const struct ir3_shader_variant *fs = shader->variant;
shader->fs.per_samp = fs->per_samp || ir3_key->sample_shading;
union {
struct {
+ unsigned patch_type;
+ enum a6xx_tess_output tess_output_upper_left, tess_output_lower_left;
+ enum a6xx_tess_spacing tess_spacing;
+ } tes;
+
+ struct {
bool per_samp;
bool has_fdm;