diff --git a/src/freedreno/vulkan/tu_cmd_buffer.cc b/src/freedreno/vulkan/tu_cmd_buffer.cc index bb8006d207e..fb9b42d637f 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.cc +++ b/src/freedreno/vulkan/tu_cmd_buffer.cc @@ -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) { - 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 @@ -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,22 +4861,22 @@ 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) { - 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; } diff --git a/src/freedreno/vulkan/tu_cmd_buffer.h b/src/freedreno/vulkan/tu_cmd_buffer.h index cd82e6dd3d3..19090c4117c 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.h +++ b/src/freedreno/vulkan/tu_cmd_buffer.h @@ -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 diff --git a/src/freedreno/vulkan/tu_pipeline.cc b/src/freedreno/vulkan/tu_pipeline.cc index 51f0f429d66..2d69cb77411 100644 --- a/src/freedreno/vulkan/tu_pipeline.cc +++ b/src/freedreno/vulkan/tu_pipeline.cc @@ -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 diff --git a/src/freedreno/vulkan/tu_pipeline.h b/src/freedreno/vulkan/tu_pipeline.h index 097125ec61a..7d6b2d48586 100644 --- a/src/freedreno/vulkan/tu_pipeline.h +++ b/src/freedreno/vulkan/tu_pipeline.h @@ -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; diff --git a/src/freedreno/vulkan/tu_shader.cc b/src/freedreno/vulkan/tu_shader.cc index dc62737b264..b24b17d048c 100644 --- a/src/freedreno/vulkan/tu_shader.cc +++ b/src/freedreno/vulkan/tu_shader.cc @@ -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; diff --git a/src/freedreno/vulkan/tu_shader.h b/src/freedreno/vulkan/tu_shader.h index 15e5e9df858..b086c27847a 100644 --- a/src/freedreno/vulkan/tu_shader.h +++ b/src/freedreno/vulkan/tu_shader.h @@ -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;