From: Nicolai Hähnle <nicolai.haeh...@amd.com> --- src/gallium/drivers/radeonsi/si_shader.c | 239 ++++++++----------------------- 1 file changed, 61 insertions(+), 178 deletions(-)
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c index a3b1189..58f8c15 100644 --- a/src/gallium/drivers/radeonsi/si_shader.c +++ b/src/gallium/drivers/radeonsi/si_shader.c @@ -7151,60 +7151,98 @@ int si_compile_tgsi_shader(struct si_screen *sscreen, } return 0; } /** * Create, compile and return a shader part (prolog or epilog). * * \param sscreen screen * \param list list of shader parts of the same category + * \param type shader type * \param key shader part key + * \param prolog whether the part being requested is a prolog * \param tm LLVM target machine * \param debug debug callback - * \param compile the callback responsible for compilation + * \param build the callback responsible for building the main function * \return non-NULL on success */ static struct si_shader_part * si_get_shader_part(struct si_screen *sscreen, struct si_shader_part **list, + enum pipe_shader_type type, + bool prolog, union si_shader_part_key *key, LLVMTargetMachineRef tm, struct pipe_debug_callback *debug, - bool (*compile)(struct si_screen *, - LLVMTargetMachineRef, - struct pipe_debug_callback *, - struct si_shader_part *)) + void (*build)(struct si_shader_context *, + union si_shader_part_key *), + const char *name) { struct si_shader_part *result; pipe_mutex_lock(sscreen->shader_parts_mutex); /* Find existing. */ for (result = *list; result; result = result->next) { if (memcmp(&result->key, key, sizeof(*key)) == 0) { pipe_mutex_unlock(sscreen->shader_parts_mutex); return result; } } /* Compile a new one. */ result = CALLOC_STRUCT(si_shader_part); result->key = *key; - if (!compile(sscreen, tm, debug, result)) { + + struct si_shader shader = {}; + struct si_shader_context ctx; + struct gallivm_state *gallivm = &ctx.gallivm; + + si_init_shader_ctx(&ctx, sscreen, &shader, tm); + ctx.type = type; + + switch (type) { + case PIPE_SHADER_VERTEX: + break; + case PIPE_SHADER_TESS_CTRL: + assert(!prolog); + shader.key.tcs.epilog = key->tcs_epilog.states; + break; + case PIPE_SHADER_FRAGMENT: + if (prolog) + shader.key.ps.prolog = key->ps_prolog.states; + else + shader.key.ps.epilog = key->ps_epilog.states; + break; + default: + unreachable("bad shader part"); + } + + build(&ctx, key); + + /* Compile. */ + si_llvm_finalize_module(&ctx, + r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_FRAGMENT)); + + if (si_compile_llvm(sscreen, &result->binary, &result->config, tm, + gallivm->module, debug, ctx.type, name)) { FREE(result); - pipe_mutex_unlock(sscreen->shader_parts_mutex); - return NULL; + result = NULL; + goto out; } result->next = *list; *list = result; + +out: + si_llvm_dispose(&ctx); pipe_mutex_unlock(sscreen->shader_parts_mutex); return result; } /** * Build the vertex shader prolog function. * * The inputs are the same as VS (a lot of SGPRs and 4 VGPR system values). * All inputs are returned unmodified. The vertex load indices are * stored after them, which will be used by the API VS for fetching inputs. @@ -7294,52 +7332,20 @@ static void si_build_vs_prolog_function(struct si_shader_context *ctx, index = LLVMBuildBitCast(gallivm->builder, index, ctx->f32, ""); ret = LLVMBuildInsertValue(gallivm->builder, ret, index, num_params++, ""); } si_llvm_build_ret(ctx, ret); } /** - * Create a vertex shader prolog. - */ -static bool si_compile_vs_prolog(struct si_screen *sscreen, - LLVMTargetMachineRef tm, - struct pipe_debug_callback *debug, - struct si_shader_part *out) -{ - union si_shader_part_key *key = &out->key; - struct si_shader shader = {}; - struct si_shader_context ctx; - struct gallivm_state *gallivm = &ctx.gallivm; - bool status = true; - - si_init_shader_ctx(&ctx, sscreen, &shader, tm); - ctx.type = PIPE_SHADER_VERTEX; - - si_build_vs_prolog_function(&ctx, key); - - /* Compile. */ - si_llvm_finalize_module(&ctx, - r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_VERTEX)); - - if (si_compile_llvm(sscreen, &out->binary, &out->config, tm, - gallivm->module, debug, ctx.type, - "Vertex Shader Prolog")) - status = false; - - si_llvm_dispose(&ctx); - return status; -} - -/** * Build the vertex shader epilog function. This is also used by the tessellation * evaluation shader compiled as VS. * * The input is PrimitiveID. * * If PrimitiveID is required by the pixel shader, export it. * Otherwise, do nothing. */ static void si_build_vs_epilog_function(struct si_shader_context *ctx, union si_shader_part_key *key) @@ -7380,67 +7386,37 @@ static void si_build_vs_epilog_function(struct si_shader_context *ctx, lp_build_intrinsic(base->gallivm->builder, "llvm.SI.export", LLVMVoidTypeInContext(base->gallivm->context), args, 9, 0); } LLVMBuildRetVoid(gallivm->builder); } /** - * Compile the vertex shader epilog. This is also used by the tessellation - * evaluation shader compiled as VS. - */ -static bool si_compile_vs_epilog(struct si_screen *sscreen, - LLVMTargetMachineRef tm, - struct pipe_debug_callback *debug, - struct si_shader_part *out) -{ - union si_shader_part_key *key = &out->key; - struct si_shader_context ctx; - struct gallivm_state *gallivm = &ctx.gallivm; - bool status = true; - - si_init_shader_ctx(&ctx, sscreen, NULL, tm); - ctx.type = PIPE_SHADER_VERTEX; - - si_build_vs_epilog_function(&ctx, key); - - /* Compile. */ - si_llvm_finalize_module(&ctx, - r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_VERTEX)); - - if (si_compile_llvm(sscreen, &out->binary, &out->config, tm, - gallivm->module, debug, ctx.type, - "Vertex Shader Epilog")) - status = false; - - si_llvm_dispose(&ctx); - return status; -} - -/** * Create & compile a vertex shader epilog. This a helper used by VS and TES. */ static bool si_get_vs_epilog(struct si_screen *sscreen, LLVMTargetMachineRef tm, struct si_shader *shader, struct pipe_debug_callback *debug, struct si_vs_epilog_bits *states) { union si_shader_part_key epilog_key; si_get_vs_epilog_key(shader, states, &epilog_key); shader->epilog = si_get_shader_part(sscreen, &sscreen->vs_epilogs, + PIPE_SHADER_VERTEX, true, &epilog_key, tm, debug, - si_compile_vs_epilog); + si_build_vs_epilog_function, + "Vertex Shader Epilog"); return shader->epilog != NULL; } /** * Select and compile (or reuse) vertex shader parts (prolog & epilog). */ static bool si_shader_select_vs_parts(struct si_screen *sscreen, LLVMTargetMachineRef tm, struct si_shader *shader, struct pipe_debug_callback *debug) @@ -7448,22 +7424,24 @@ static bool si_shader_select_vs_parts(struct si_screen *sscreen, struct tgsi_shader_info *info = &shader->selector->info; union si_shader_part_key prolog_key; /* Get the prolog. */ si_get_vs_prolog_key(shader, &prolog_key); /* The prolog is a no-op if there are no inputs. */ if (info->num_inputs) { shader->prolog = si_get_shader_part(sscreen, &sscreen->vs_prologs, + PIPE_SHADER_VERTEX, true, &prolog_key, tm, debug, - si_compile_vs_prolog); + si_build_vs_prolog_function, + "Vertex Shader Prolog"); if (!shader->prolog) return false; } /* Get the epilog. */ if (!shader->key.vs.as_es && !shader->key.vs.as_ls && !si_get_vs_epilog(sscreen, tm, shader, debug, &shader->key.vs.epilog)) return false; @@ -7525,70 +7503,38 @@ static void si_build_tcs_epilog_function(struct si_shader_context *ctx, si_write_tess_factors(bld_base, LLVMGetParam(func, last_sgpr + 1), LLVMGetParam(func, last_sgpr + 2), LLVMGetParam(func, last_sgpr + 3)); LLVMBuildRetVoid(gallivm->builder); } /** - * Compile the TCS epilog. This writes tesselation factors to memory based on - * the output primitive type of the tesselator (determined by TES). - */ -static bool si_compile_tcs_epilog(struct si_screen *sscreen, - LLVMTargetMachineRef tm, - struct pipe_debug_callback *debug, - struct si_shader_part *out) -{ - union si_shader_part_key *key = &out->key; - struct si_shader shader = {}; - struct si_shader_context ctx; - struct gallivm_state *gallivm = &ctx.gallivm; - bool status = true; - - si_init_shader_ctx(&ctx, sscreen, &shader, tm); - ctx.type = PIPE_SHADER_TESS_CTRL; - shader.key.tcs.epilog = key->tcs_epilog.states; - - si_build_tcs_epilog_function(&ctx, key); - - /* Compile. */ - si_llvm_finalize_module(&ctx, - r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_TESS_CTRL)); - - if (si_compile_llvm(sscreen, &out->binary, &out->config, tm, - gallivm->module, debug, ctx.type, - "Tessellation Control Shader Epilog")) - status = false; - - si_llvm_dispose(&ctx); - return status; -} - -/** * Select and compile (or reuse) TCS parts (epilog). */ static bool si_shader_select_tcs_parts(struct si_screen *sscreen, LLVMTargetMachineRef tm, struct si_shader *shader, struct pipe_debug_callback *debug) { union si_shader_part_key epilog_key; /* Get the epilog. */ memset(&epilog_key, 0, sizeof(epilog_key)); epilog_key.tcs_epilog.states = shader->key.tcs.epilog; shader->epilog = si_get_shader_part(sscreen, &sscreen->tcs_epilogs, + PIPE_SHADER_TESS_CTRL, false, &epilog_key, tm, debug, - si_compile_tcs_epilog); + si_build_tcs_epilog_function, + "Tessellation Control Shader Epilog"); return shader->epilog != NULL; } /** * Build the pixel shader prolog function. This handles: * - two-side color selection and interpolation * - overriding interpolation parameters for the API PS * - polygon stippling * * All preloaded SGPRs and VGPRs are passed through unmodified unless they are @@ -7825,53 +7771,20 @@ static void si_build_ps_prolog_function(struct si_shader_context *ctx, /* Tell LLVM to insert WQM instruction sequence when needed. */ if (key->ps_prolog.wqm) { LLVMAddTargetDependentFunctionAttr(func, "amdgpu-ps-wqm-outputs", ""); } si_llvm_build_ret(ctx, ret); } /** - * Compile the pixel shader prolog. - */ -static bool si_compile_ps_prolog(struct si_screen *sscreen, - LLVMTargetMachineRef tm, - struct pipe_debug_callback *debug, - struct si_shader_part *out) -{ - union si_shader_part_key *key = &out->key; - struct si_shader shader = {}; - struct si_shader_context ctx; - struct gallivm_state *gallivm = &ctx.gallivm; - bool status = true; - - si_init_shader_ctx(&ctx, sscreen, &shader, tm); - ctx.type = PIPE_SHADER_FRAGMENT; - shader.key.ps.prolog = key->ps_prolog.states; - - si_build_ps_prolog_function(&ctx, key); - - /* Compile. */ - si_llvm_finalize_module(&ctx, - r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_FRAGMENT)); - - if (si_compile_llvm(sscreen, &out->binary, &out->config, tm, - gallivm->module, debug, ctx.type, - "Fragment Shader Prolog")) - status = false; - - si_llvm_dispose(&ctx); - return status; -} - -/** * Build the pixel shader epilog function. This handles everything that must be * emulated for pixel shader exports. (alpha-test, format conversions, etc) */ static void si_build_ps_epilog_function(struct si_shader_context *ctx, union si_shader_part_key *key) { struct gallivm_state *gallivm = &ctx->gallivm; struct lp_build_tgsi_context *bld_base = &ctx->soa.bld_base; LLVMTypeRef params[16+8*4+3]; LLVMValueRef depth = NULL, stencil = NULL, samplemask = NULL; @@ -7958,85 +7871,55 @@ static void si_build_ps_epilog_function(struct si_shader_context *ctx, else if (last_color_export == -1) si_export_null(bld_base); if (exp.num) si_emit_ps_exports(ctx, &exp); /* Compile. */ LLVMBuildRetVoid(gallivm->builder); } - -/** - * Compile the pixel shader epilog to a binary for concatenation. - */ -static bool si_compile_ps_epilog(struct si_screen *sscreen, - LLVMTargetMachineRef tm, - struct pipe_debug_callback *debug, - struct si_shader_part *out) -{ - union si_shader_part_key *key = &out->key; - struct si_shader shader = {}; - struct si_shader_context ctx; - struct gallivm_state *gallivm = &ctx.gallivm; - bool status = true; - - si_init_shader_ctx(&ctx, sscreen, &shader, tm); - ctx.type = PIPE_SHADER_FRAGMENT; - shader.key.ps.epilog = key->ps_epilog.states; - - si_build_ps_epilog_function(&ctx, key); - - /* Compile. */ - si_llvm_finalize_module(&ctx, - r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_FRAGMENT)); - - if (si_compile_llvm(sscreen, &out->binary, &out->config, tm, - gallivm->module, debug, ctx.type, - "Fragment Shader Epilog")) - status = false; - - si_llvm_dispose(&ctx); - return status; -} - /** * Select and compile (or reuse) pixel shader parts (prolog & epilog). */ static bool si_shader_select_ps_parts(struct si_screen *sscreen, LLVMTargetMachineRef tm, struct si_shader *shader, struct pipe_debug_callback *debug) { union si_shader_part_key prolog_key; union si_shader_part_key epilog_key; /* Get the prolog. */ si_get_ps_prolog_key(shader, &prolog_key, true); /* The prolog is a no-op if these aren't set. */ if (si_need_ps_prolog(&prolog_key)) { shader->prolog = si_get_shader_part(sscreen, &sscreen->ps_prologs, + PIPE_SHADER_FRAGMENT, true, &prolog_key, tm, debug, - si_compile_ps_prolog); + si_build_ps_prolog_function, + "Fragment Shader Prolog"); if (!shader->prolog) return false; } /* Get the epilog. */ si_get_ps_epilog_key(shader, &epilog_key); shader->epilog = si_get_shader_part(sscreen, &sscreen->ps_epilogs, + PIPE_SHADER_FRAGMENT, false, &epilog_key, tm, debug, - si_compile_ps_epilog); + si_build_ps_epilog_function, + "Fragment Shader Epilog"); if (!shader->epilog) return false; /* Enable POS_FIXED_PT if polygon stippling is enabled. */ if (shader->key.ps.prolog.poly_stipple) { shader->config.spi_ps_input_ena |= S_0286CC_POS_FIXED_PT_ENA(1); assert(G_0286CC_POS_FIXED_PT_ENA(shader->config.spi_ps_input_addr)); } /* Set up the enable bits for per-sample shading if needed. */ -- 2.7.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev