From d656c600a399e09a80dbec4c03e5d8e122904521 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Wed, 14 Oct 2020 10:38:02 -0400 Subject: [PATCH] zink: add handling for gs in ntv this hooks up execution modes and the gs-specific instructions Reviewed-by: Erik Faye-Lund Part-of: --- .../drivers/zink/nir_to_spirv/nir_to_spirv.c | 120 ++++++++++++++++++++- src/gallium/drivers/zink/zink_compiler.c | 8 +- src/gallium/drivers/zink/zink_compiler.h | 2 + src/gallium/drivers/zink/zink_program.c | 1 + 4 files changed, 125 insertions(+), 6 deletions(-) diff --git a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c index a22b4cf..2c8f28a 100644 --- a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c +++ b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c @@ -39,6 +39,7 @@ struct ntv_context { SpvId GLSL_std_450; gl_shader_stage stage; + const struct zink_so_info *so_info; SpvId ubos[128]; size_t num_ubos; @@ -1703,6 +1704,23 @@ emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr) emit_load_uint_input(ctx, intr, &ctx->invocation_id_var, "gl_InvocationId", SpvBuiltInInvocationId); break; + case nir_intrinsic_emit_vertex_with_counter: + /* geometry shader emits copied xfb outputs just prior to EmitVertex(), + * since that's the end of the shader + */ + if (ctx->so_info) + emit_so_outputs(ctx, ctx->so_info); + spirv_builder_emit_vertex(&ctx->builder); + break; + + case nir_intrinsic_set_vertex_and_primitive_count: + /* do nothing */ + break; + + case nir_intrinsic_end_primitive_with_counter: + spirv_builder_end_primitive(&ctx->builder); + break; + default: fprintf(stderr, "emit_intrinsic: not implemented (%s)\n", nir_intrinsic_infos[intr->intrinsic].name); @@ -2202,6 +2220,86 @@ emit_cf_list(struct ntv_context *ctx, struct exec_list *list) } } +static SpvExecutionMode +get_input_prim_type_mode(uint16_t type) +{ + switch (type) { + case GL_POINTS: + return SpvExecutionModeInputPoints; + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + return SpvExecutionModeInputLines; + case GL_TRIANGLE_STRIP: + case GL_TRIANGLES: + case GL_TRIANGLE_FAN: + return SpvExecutionModeTriangles; + case GL_QUADS: + case GL_QUAD_STRIP: + return SpvExecutionModeQuads; + break; + case GL_POLYGON: + unreachable("handle polygons in gs"); + break; + case GL_LINES_ADJACENCY: + case GL_LINE_STRIP_ADJACENCY: + return SpvExecutionModeInputLinesAdjacency; + case GL_TRIANGLES_ADJACENCY: + case GL_TRIANGLE_STRIP_ADJACENCY: + return SpvExecutionModeInputTrianglesAdjacency; + break; + case GL_ISOLINES: + return SpvExecutionModeIsolines; + default: + debug_printf("unknown geometry shader input mode %u\n", type); + unreachable("error!"); + break; + } + + return 0; +} +static SpvExecutionMode +get_output_prim_type_mode(uint16_t type) +{ + switch (type) { + case GL_POINTS: + return SpvExecutionModeOutputPoints; + case GL_LINES: + case GL_LINE_LOOP: + unreachable("GL_LINES/LINE_LOOP passed as gs output"); + break; + case GL_LINE_STRIP: + return SpvExecutionModeOutputLineStrip; + case GL_TRIANGLE_STRIP: + return SpvExecutionModeOutputTriangleStrip; + case GL_TRIANGLES: + case GL_TRIANGLE_FAN: //FIXME: not sure if right for output + return SpvExecutionModeTriangles; + case GL_QUADS: + case GL_QUAD_STRIP: + return SpvExecutionModeQuads; + case GL_POLYGON: + unreachable("handle polygons in gs"); + break; + case GL_LINES_ADJACENCY: + case GL_LINE_STRIP_ADJACENCY: + unreachable("handle line adjacency in gs"); + break; + case GL_TRIANGLES_ADJACENCY: + case GL_TRIANGLE_STRIP_ADJACENCY: + unreachable("handle triangle adjacency in gs"); + break; + case GL_ISOLINES: + return SpvExecutionModeIsolines; + default: + debug_printf("unknown geometry shader output mode %u\n", type); + unreachable("error!"); + break; + } + + return 0; +} + struct spirv_shader * nir_to_spirv(struct nir_shader *s, const struct zink_so_info *so_info, unsigned char *shader_slot_map, unsigned char *shader_slots_reserved) @@ -2228,6 +2326,10 @@ nir_to_spirv(struct nir_shader *s, const struct zink_so_info *so_info, case MESA_SHADER_GEOMETRY: spirv_builder_emit_cap(&ctx.builder, SpvCapabilityGeometry); + if (s->info.gs.active_stream_mask) + spirv_builder_emit_cap(&ctx.builder, SpvCapabilityGeometryStreams); + if (s->info.outputs_written & BITFIELD64_BIT(VARYING_SLOT_PSIZ)) + spirv_builder_emit_cap(&ctx.builder, SpvCapabilityGeometryPointSize); break; default: @@ -2249,6 +2351,7 @@ nir_to_spirv(struct nir_shader *s, const struct zink_so_info *so_info, } ctx.stage = s->info.stage; + ctx.so_info = so_info; ctx.shader_slot_map = shader_slot_map; ctx.shader_slots_reserved = *shader_slots_reserved; ctx.GLSL_std_450 = spirv_builder_import(&ctx.builder, "GLSL.std.450"); @@ -2309,20 +2412,28 @@ nir_to_spirv(struct nir_shader *s, const struct zink_so_info *so_info, nir_var_mem_ssbo)) emit_uniform(&ctx, var); - if (s->info.stage == MESA_SHADER_FRAGMENT) { + switch (s->info.stage) { + case MESA_SHADER_FRAGMENT: spirv_builder_emit_exec_mode(&ctx.builder, entry_point, SpvExecutionModeOriginUpperLeft); if (s->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) spirv_builder_emit_exec_mode(&ctx.builder, entry_point, SpvExecutionModeDepthReplacing); + break; + case MESA_SHADER_GEOMETRY: + spirv_builder_emit_exec_mode(&ctx.builder, entry_point, get_input_prim_type_mode(s->info.gs.input_primitive)); + spirv_builder_emit_exec_mode(&ctx.builder, entry_point, get_output_prim_type_mode(s->info.gs.output_primitive)); + spirv_builder_emit_exec_mode_literal(&ctx.builder, entry_point, SpvExecutionModeInvocations, s->info.gs.invocations); + spirv_builder_emit_exec_mode_literal(&ctx.builder, entry_point, SpvExecutionModeOutputVertices, s->info.gs.vertices_out); + break; + default: + break; } - if (so_info && so_info->so_info.num_outputs) { spirv_builder_emit_cap(&ctx.builder, SpvCapabilityTransformFeedback); spirv_builder_emit_exec_mode(&ctx.builder, entry_point, SpvExecutionModeXfb); } - spirv_builder_function(&ctx.builder, entry_point, type_void, SpvFunctionControlMaskNone, type_main); @@ -2369,7 +2480,8 @@ nir_to_spirv(struct nir_shader *s, const struct zink_so_info *so_info, emit_cf_list(&ctx, &entry->body); - if (so_info) + /* vertex shader emits copied xfb outputs at the end of the shader */ + if (so_info && ctx.stage == MESA_SHADER_VERTEX) emit_so_outputs(&ctx, so_info); spirv_builder_return(&ctx.builder); // doesn't belong here, but whatevz diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c index 77297d5..bd35160 100644 --- a/src/gallium/drivers/zink/zink_compiler.c +++ b/src/gallium/drivers/zink/zink_compiler.c @@ -221,7 +221,9 @@ zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, unsigned char *shader_slot_map, unsigned char *shader_slots_reserved) { VkShaderModule mod = VK_NULL_HANDLE; - void *streamout = zs->streamout.so_info_slots ? &zs->streamout : NULL; + void *streamout = NULL; + if (zs->streamout.so_info_slots && (zs->nir->info.stage != MESA_SHADER_VERTEX || !zs->has_geometry_shader)) + streamout = &zs->streamout; struct spirv_shader *spirv = nir_to_spirv(zs->nir, streamout, shader_slot_map, shader_slots_reserved); assert(spirv); @@ -267,8 +269,10 @@ zink_shader_create(struct zink_screen *screen, struct nir_shader *nir, NIR_PASS_V(nir, nir_lower_uniforms_to_ubo, 16); NIR_PASS_V(nir, nir_lower_ubo_vec4); NIR_PASS_V(nir, nir_lower_clip_halfz); - if (nir->info.stage == MESA_SHADER_VERTEX) + if (nir->info.stage < MESA_SHADER_FRAGMENT) have_psiz = check_psiz(nir); + if (nir->info.stage == MESA_SHADER_GEOMETRY) + NIR_PASS_V(nir, nir_lower_gs_intrinsics, nir_lower_gs_intrinsics_per_stream); NIR_PASS_V(nir, nir_lower_regs_to_ssa); optimize_nir(nir); NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp, NULL); diff --git a/src/gallium/drivers/zink/zink_compiler.h b/src/gallium/drivers/zink/zink_compiler.h index 3a473bd..7ea485f 100644 --- a/src/gallium/drivers/zink/zink_compiler.h +++ b/src/gallium/drivers/zink/zink_compiler.h @@ -69,6 +69,8 @@ struct zink_shader { } bindings[PIPE_MAX_CONSTANT_BUFFERS + PIPE_MAX_SHADER_SAMPLER_VIEWS]; size_t num_bindings; struct set *programs; + + bool has_geometry_shader; // vertex shaders need to know if a geometry shader exists }; VkShaderModule diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c index f7bd9ca..82620cd 100644 --- a/src/gallium/drivers/zink/zink_program.c +++ b/src/gallium/drivers/zink/zink_program.c @@ -153,6 +153,7 @@ update_shader_modules(struct zink_context *ctx, struct zink_shader *stages[ZINK_ prog->modules[type] = CALLOC_STRUCT(zink_shader_module); assert(prog->modules[type]); pipe_reference_init(&prog->modules[type]->reference, 1); + dirty[i]->has_geometry_shader = dirty[MESA_SHADER_GEOMETRY] || stages[PIPE_SHADER_GEOMETRY]; prog->modules[type]->shader = zink_shader_compile(zink_screen(ctx->base.screen), dirty[i], prog->shader_slot_map, &prog->shader_slots_reserved); } else if (stages[type]) /* reuse existing shader module */ -- 2.7.4