tu: Rewrite tessellation modes handling

Before this, we combined the modes after compiling the shaders when
constructing the pipeline. But that's a bit awkward with shader objects,
where there is no good place to put state derived from TCS and TES but
not the other stages. However, shader objects leaves us with an out:
when compiling separately, the modes must be on one of the shaders. So
instead we just copy the modes earlier, in the NIR shaders, and then get
them from the appropriate shader later. That way there is no extra
overhead when fast-linking, as there currently is, and we don't need to
create an awkward separate object just for this.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25276>
This commit is contained in:
Connor Abbott
2023-09-06 17:24:00 +02:00
committed by Marge Bot
parent 169a44d562
commit efaf77bbdd
6 changed files with 123 additions and 103 deletions

View File

@@ -758,8 +758,9 @@ tu6_update_msaa_disable(struct tu_cmd_buffer *cmd)
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;
@@ -2962,7 +2963,25 @@ tu_bind_tcs(struct tu_cmd_buffer *cmd, struct tu_shader *tcs)
static void
tu_bind_tes(struct tu_cmd_buffer *cmd, struct tu_shader *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
@@ -3084,23 +3103,6 @@ tu_CmdBindPipeline(VkCommandBuffer commandBuffer,
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
@@ -4738,7 +4740,7 @@ tu6_draw_common(struct tu_cmd_buffer *cmd,
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);
}
@@ -4859,7 +4861,9 @@ tu_draw_initiator(struct tu_cmd_buffer *cmd, enum pc_di_src_sel src_sel)
if (pipeline->active_stages & VK_SHADER_STAGE_GEOMETRY_BIT)
initiator |= CP_DRAW_INDX_OFFSET_0_GS_ENABLE;
switch (pipeline->tess.patch_type) {
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;
@@ -4868,14 +4872,12 @@ tu_draw_initiator(struct tu_cmd_buffer *cmd, enum pc_di_src_sel src_sel)
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;
}
}
return initiator;
}

View File

@@ -69,9 +69,10 @@ enum tu_cmd_dirty_bits
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

View File

@@ -977,6 +977,7 @@ static unsigned
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)
{
@@ -991,6 +992,7 @@ void
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)
{
@@ -1060,7 +1062,7 @@ tu6_emit_patch_control_points(struct tu_cs *cs,
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;
@@ -1927,19 +1929,39 @@ tu_pipeline_builder_compile_shaders(struct tu_pipeline_builder *builder,
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 ||
@@ -2050,12 +2072,6 @@ done:
}
}
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;
@@ -2152,11 +2168,6 @@ tu_pipeline_builder_parse_libraries(struct tu_pipeline_builder *builder,
pipeline->shared_consts = library->base.shared_consts;
}
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;
@@ -2346,43 +2357,6 @@ tu_pipeline_builder_parse_shader_stages(struct tu_pipeline_builder *builder,
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;
@@ -3496,6 +3470,7 @@ tu_pipeline_builder_emit_state(struct tu_pipeline_builder *builder,
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
@@ -3678,6 +3653,7 @@ tu_emit_draw_state(struct tu_cmd_buffer *cmd)
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

View File

@@ -114,10 +114,6 @@ struct tu_pipeline
uint32_t set_state_mask;
struct tu_draw_state dynamic_state[TU_DYNAMIC_STATE_COUNT];
struct {
unsigned patch_type;
} tess;
struct {
bool raster_order_attachment_access;
} ds;
@@ -158,9 +154,6 @@ struct tu_pipeline
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;

View File

@@ -2097,6 +2097,9 @@ tu_shader_serialize(struct vk_pipeline_cache_object *object,
}
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;
@@ -2132,6 +2135,9 @@ tu_shader_deserialize(struct vk_pipeline_cache *cache,
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;
@@ -2297,6 +2303,42 @@ tu_shader_create(struct tu_device *dev,
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;

View File

@@ -64,6 +64,12 @@ struct tu_shader
uint8_t active_desc_sets;
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;