/**
* Get the value of a shader input parameter and extract a bitfield.
*/
-static LLVMValueRef unpack_param(struct si_shader_context *ctx,
- unsigned param, unsigned rshift,
- unsigned bitwidth)
+static LLVMValueRef unpack_llvm_param(struct si_shader_context *ctx,
+ LLVMValueRef value, unsigned rshift,
+ unsigned bitwidth)
{
- LLVMValueRef value = LLVMGetParam(ctx->main_fn,
- param);
-
if (LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMFloatTypeKind)
value = ac_to_integer(&ctx->ac, value);
return value;
}
+static LLVMValueRef unpack_param(struct si_shader_context *ctx,
+ unsigned param, unsigned rshift,
+ unsigned bitwidth)
+{
+ LLVMValueRef value = LLVMGetParam(ctx->main_fn, param);
+
+ return unpack_llvm_param(ctx, value, rshift, bitwidth);
+}
+
static LLVMValueRef get_rel_patch_id(struct si_shader_context *ctx)
{
switch (ctx->type) {
case PIPE_SHADER_TESS_CTRL:
- return unpack_param(ctx, ctx->param_tcs_rel_ids, 0, 8);
+ return unpack_llvm_param(ctx, ctx->abi.tcs_rel_ids, 0, 8);
case PIPE_SHADER_TESS_EVAL:
return LLVMGetParam(ctx->main_fn,
return LLVMGetParam(ctx->main_fn,
ctx->param_vs_prim_id);
case PIPE_SHADER_TESS_CTRL:
- return LLVMGetParam(ctx->main_fn,
- ctx->param_tcs_patch_id);
+ return ctx->abi.tcs_patch_id;
case PIPE_SHADER_TESS_EVAL:
- return LLVMGetParam(ctx->main_fn,
- ctx->param_tes_patch_id);
+ return ctx->abi.tes_patch_id;
case PIPE_SHADER_GEOMETRY:
return ctx->abi.gs_prim_id;
default:
return lds_load(bld_base, tgsi2llvmtype(bld_base, type), swizzle, dw_addr);
}
-static LLVMValueRef si_nir_load_input_tcs(struct ac_shader_abi *abi,
- LLVMValueRef vertex_index,
- LLVMValueRef param_index,
- unsigned const_index,
- unsigned location,
- unsigned driver_location,
- unsigned component,
- unsigned num_components,
- bool is_patch,
- bool is_compact)
+static LLVMValueRef si_nir_load_tcs_varyings(struct ac_shader_abi *abi,
+ LLVMValueRef vertex_index,
+ LLVMValueRef param_index,
+ unsigned const_index,
+ unsigned location,
+ unsigned driver_location,
+ unsigned component,
+ unsigned num_components,
+ bool is_patch,
+ bool is_compact,
+ bool load_input)
{
struct si_shader_context *ctx = si_shader_context_from_abi(abi);
struct tgsi_shader_info *info = &ctx->shader->selector->info;
driver_location = driver_location / 4;
- stride = get_tcs_in_vertex_dw_stride(ctx);
- dw_addr = get_tcs_in_current_patch_offset(ctx);
+ if (load_input) {
+ stride = get_tcs_in_vertex_dw_stride(ctx);
+ dw_addr = get_tcs_in_current_patch_offset(ctx);
+ } else {
+ if (is_patch) {
+ stride = NULL;
+ dw_addr = get_tcs_out_current_patch_data_offset(ctx);
+ } else {
+ stride = get_tcs_out_vertex_dw_stride(ctx);
+ dw_addr = get_tcs_out_current_patch_offset(ctx);
+ }
+ }
if (param_index) {
/* Add the constant index to the indirect index */
unsigned component,
unsigned num_components,
bool is_patch,
- bool is_compact)
+ bool is_compact,
+ bool load_input)
{
struct si_shader_context *ctx = si_shader_context_from_abi(abi);
struct tgsi_shader_info *info = &ctx->shader->selector->info;
}
}
+static void si_nir_store_output_tcs(struct ac_shader_abi *abi,
+ LLVMValueRef vertex_index,
+ LLVMValueRef param_index,
+ unsigned const_index,
+ unsigned location,
+ unsigned driver_location,
+ LLVMValueRef src,
+ unsigned component,
+ bool is_patch,
+ bool is_compact,
+ unsigned writemask)
+{
+ struct si_shader_context *ctx = si_shader_context_from_abi(abi);
+ struct tgsi_shader_info *info = &ctx->shader->selector->info;
+ LLVMValueRef dw_addr, stride;
+ LLVMValueRef buffer, base, addr;
+ LLVMValueRef values[4];
+ bool skip_lds_store;
+ bool is_tess_factor = false, is_tess_inner = false;
+
+ driver_location = driver_location / 4;
+
+ if (param_index) {
+ /* Add the constant index to the indirect index */
+ param_index = LLVMBuildAdd(ctx->ac.builder, param_index,
+ LLVMConstInt(ctx->i32, const_index, 0), "");
+ } else {
+ if (const_index != 0)
+ param_index = LLVMConstInt(ctx->i32, const_index, 0);
+ }
+
+ if (!is_patch) {
+ stride = get_tcs_out_vertex_dw_stride(ctx);
+ dw_addr = get_tcs_out_current_patch_offset(ctx);
+ dw_addr = get_dw_address_from_generic_indices(ctx, stride, dw_addr,
+ vertex_index, param_index,
+ driver_location,
+ info->output_semantic_name,
+ info->output_semantic_index,
+ is_patch);
+
+ skip_lds_store = !info->reads_pervertex_outputs;
+ } else {
+ dw_addr = get_tcs_out_current_patch_data_offset(ctx);
+ dw_addr = get_dw_address_from_generic_indices(ctx, NULL, dw_addr,
+ vertex_index, param_index,
+ driver_location,
+ info->output_semantic_name,
+ info->output_semantic_index,
+ is_patch);
+
+ skip_lds_store = !info->reads_perpatch_outputs;
+
+ if (!param_index) {
+ int name = info->output_semantic_name[driver_location];
+
+ /* Always write tess factors into LDS for the TCS epilog. */
+ if (name == TGSI_SEMANTIC_TESSINNER ||
+ name == TGSI_SEMANTIC_TESSOUTER) {
+ /* The epilog doesn't read LDS if invocation 0 defines tess factors. */
+ skip_lds_store = !info->reads_tessfactor_outputs &&
+ ctx->shader->selector->tcs_info.tessfactors_are_def_in_all_invocs;
+ is_tess_factor = true;
+ is_tess_inner = name == TGSI_SEMANTIC_TESSINNER;
+ }
+ }
+ }
+
+ buffer = desc_from_addr_base64k(ctx, ctx->param_tcs_offchip_addr_base64k);
+
+ base = LLVMGetParam(ctx->main_fn, ctx->param_tcs_offchip_offset);
+
+ addr = get_tcs_tes_buffer_address_from_generic_indices(ctx, vertex_index,
+ param_index, driver_location,
+ info->output_semantic_name,
+ info->output_semantic_index,
+ is_patch);
+
+ for (unsigned chan = 0; chan < 4; chan++) {
+ if (!(writemask & (1 << chan)))
+ continue;
+ LLVMValueRef value = ac_llvm_extract_elem(&ctx->ac, src, chan - component);
+
+ /* Skip LDS stores if there is no LDS read of this output. */
+ if (!skip_lds_store)
+ ac_lds_store(&ctx->ac, dw_addr, value);
+
+ value = ac_to_integer(&ctx->ac, value);
+ values[chan] = value;
+
+ if (writemask != 0xF && !is_tess_factor) {
+ ac_build_buffer_store_dword(&ctx->ac, buffer, value, 1,
+ addr, base,
+ 4 * chan, 1, 0, true, false);
+ }
+
+ /* Write tess factors into VGPRs for the epilog. */
+ if (is_tess_factor &&
+ ctx->shader->selector->tcs_info.tessfactors_are_def_in_all_invocs) {
+ if (!is_tess_inner) {
+ LLVMBuildStore(ctx->ac.builder, value, /* outer */
+ ctx->invoc0_tess_factors[chan]);
+ } else if (chan < 2) {
+ LLVMBuildStore(ctx->ac.builder, value, /* inner */
+ ctx->invoc0_tess_factors[4 + chan]);
+ }
+ }
+ }
+
+ if (writemask == 0xF && !is_tess_factor) {
+ LLVMValueRef value = lp_build_gather_values(&ctx->gallivm,
+ values, 4);
+ ac_build_buffer_store_dword(&ctx->ac, buffer, value, 4, addr,
+ base, 0, 1, 0, true, false);
+ }
+}
+
LLVMValueRef si_llvm_load_input_gs(struct ac_shader_abi *abi,
unsigned input_index,
unsigned vtx_offset_param,
return lp_build_gather_values(&ctx->gallivm, pos, 4);
}
+static LLVMValueRef si_load_tess_coord(struct ac_shader_abi *abi,
+ LLVMTypeRef type,
+ unsigned num_components)
+{
+ struct si_shader_context *ctx = si_shader_context_from_abi(abi);
+ struct lp_build_context *bld = &ctx->bld_base.base;
+
+ LLVMValueRef coord[4] = {
+ LLVMGetParam(ctx->main_fn, ctx->param_tes_u),
+ LLVMGetParam(ctx->main_fn, ctx->param_tes_v),
+ ctx->ac.f32_0,
+ ctx->ac.f32_0
+ };
+
+ /* For triangles, the vector should be (u, v, 1-u-v). */
+ if (ctx->shader->selector->info.properties[TGSI_PROPERTY_TES_PRIM_MODE] ==
+ PIPE_PRIM_TRIANGLES)
+ coord[2] = lp_build_sub(bld, ctx->ac.f32_1,
+ lp_build_add(bld, coord[0], coord[1]));
+
+ return lp_build_gather_values(&ctx->gallivm, coord, 4);
+}
+
+static LLVMValueRef load_tess_level(struct si_shader_context *ctx,
+ unsigned semantic_name)
+{
+ LLVMValueRef buffer, base, addr;
+
+ int param = si_shader_io_get_unique_index_patch(semantic_name, 0);
+
+ buffer = desc_from_addr_base64k(ctx, ctx->param_tcs_offchip_addr_base64k);
+
+ base = LLVMGetParam(ctx->main_fn, ctx->param_tcs_offchip_offset);
+ addr = get_tcs_tes_buffer_address(ctx, get_rel_patch_id(ctx), NULL,
+ LLVMConstInt(ctx->i32, param, 0));
+
+ return buffer_load(&ctx->bld_base, ctx->f32,
+ ~0, buffer, base, addr, true);
+
+}
+
+static LLVMValueRef si_load_tess_level(struct ac_shader_abi *abi,
+ unsigned varying_id)
+{
+ struct si_shader_context *ctx = si_shader_context_from_abi(abi);
+ unsigned semantic_name;
+
+ switch (varying_id) {
+ case VARYING_SLOT_TESS_LEVEL_INNER:
+ semantic_name = TGSI_SEMANTIC_TESSINNER;
+ break;
+ case VARYING_SLOT_TESS_LEVEL_OUTER:
+ semantic_name = TGSI_SEMANTIC_TESSOUTER;
+ break;
+ default:
+ unreachable("unknown tess level");
+ }
+
+ return load_tess_level(ctx, semantic_name);
+
+}
+
+static LLVMValueRef si_load_patch_vertices_in(struct ac_shader_abi *abi)
+{
+ struct si_shader_context *ctx = si_shader_context_from_abi(abi);
+ if (ctx->type == PIPE_SHADER_TESS_CTRL)
+ return unpack_param(ctx, ctx->param_tcs_out_lds_layout, 26, 6);
+ else if (ctx->type == PIPE_SHADER_TESS_EVAL)
+ return get_num_tcs_out_vertices(ctx);
+ else
+ unreachable("invalid shader stage for TGSI_SEMANTIC_VERTICESIN");
+}
+
void si_load_system_value(struct si_shader_context *ctx,
unsigned index,
const struct tgsi_full_declaration *decl)
{
- struct lp_build_context *bld = &ctx->bld_base.base;
LLVMValueRef value = 0;
assert(index < RADEON_LLVM_MAX_SYSTEM_VALUES);
case TGSI_SEMANTIC_INVOCATIONID:
if (ctx->type == PIPE_SHADER_TESS_CTRL)
- value = unpack_param(ctx, ctx->param_tcs_rel_ids, 8, 5);
+ value = unpack_llvm_param(ctx, ctx->abi.tcs_rel_ids, 8, 5);
else if (ctx->type == PIPE_SHADER_GEOMETRY)
value = ctx->abi.gs_invocation_id;
else
break;
case TGSI_SEMANTIC_TESSCOORD:
- {
- LLVMValueRef coord[4] = {
- LLVMGetParam(ctx->main_fn, ctx->param_tes_u),
- LLVMGetParam(ctx->main_fn, ctx->param_tes_v),
- ctx->ac.f32_0,
- ctx->ac.f32_0
- };
-
- /* For triangles, the vector should be (u, v, 1-u-v). */
- if (ctx->shader->selector->info.properties[TGSI_PROPERTY_TES_PRIM_MODE] ==
- PIPE_PRIM_TRIANGLES)
- coord[2] = lp_build_sub(bld, ctx->ac.f32_1,
- lp_build_add(bld, coord[0], coord[1]));
-
- value = lp_build_gather_values(&ctx->gallivm, coord, 4);
+ value = si_load_tess_coord(&ctx->abi, NULL, 4);
break;
- }
case TGSI_SEMANTIC_VERTICESIN:
- if (ctx->type == PIPE_SHADER_TESS_CTRL)
- value = unpack_param(ctx, ctx->param_tcs_out_lds_layout, 26, 6);
- else if (ctx->type == PIPE_SHADER_TESS_EVAL)
- value = get_num_tcs_out_vertices(ctx);
- else
- assert(!"invalid shader stage for TGSI_SEMANTIC_VERTICESIN");
+ value = si_load_patch_vertices_in(&ctx->abi);
break;
case TGSI_SEMANTIC_TESSINNER:
case TGSI_SEMANTIC_TESSOUTER:
- {
- LLVMValueRef buffer, base, addr;
- int param = si_shader_io_get_unique_index_patch(decl->Semantic.Name, 0);
-
- buffer = desc_from_addr_base64k(ctx, ctx->param_tcs_offchip_addr_base64k);
-
- base = LLVMGetParam(ctx->main_fn, ctx->param_tcs_offchip_offset);
- addr = get_tcs_tes_buffer_address(ctx, get_rel_patch_id(ctx), NULL,
- LLVMConstInt(ctx->i32, param, 0));
-
- value = buffer_load(&ctx->bld_base, ctx->f32,
- ~0, buffer, base, addr, true);
-
+ value = load_tess_level(ctx, decl->Semantic.Name);
break;
- }
case TGSI_SEMANTIC_DEFAULT_TESSOUTER_SI:
case TGSI_SEMANTIC_DEFAULT_TESSINNER_SI:
LLVMValueRef lds_vertex_stride, lds_vertex_offset, lds_base;
uint64_t inputs;
- invocation_id = unpack_param(ctx, ctx->param_tcs_rel_ids, 8, 5);
+ invocation_id = unpack_llvm_param(ctx, ctx->abi.tcs_rel_ids, 8, 5);
buffer = desc_from_addr_base64k(ctx, ctx->param_tcs_offchip_addr_base64k);
buffer_offset = LLVMGetParam(ctx->main_fn, ctx->param_tcs_offchip_offset);
}
/* This only writes the tessellation factor levels. */
-static void si_llvm_emit_tcs_epilogue(struct lp_build_tgsi_context *bld_base)
+static void si_llvm_emit_tcs_epilogue(struct ac_shader_abi *abi,
+ unsigned max_outputs,
+ LLVMValueRef *addrs)
{
- struct si_shader_context *ctx = si_shader_context(bld_base);
+ struct si_shader_context *ctx = si_shader_context_from_abi(abi);
+ struct lp_build_tgsi_context *bld_base = &ctx->bld_base;
LLVMBuilderRef builder = ctx->ac.builder;
LLVMValueRef rel_patch_id, invocation_id, tf_lds_offset;
si_copy_tcs_inputs(bld_base);
rel_patch_id = get_rel_patch_id(ctx);
- invocation_id = unpack_param(ctx, ctx->param_tcs_rel_ids, 8, 5);
+ invocation_id = unpack_llvm_param(ctx, ctx->abi.tcs_rel_ids, 8, 5);
tf_lds_offset = get_tcs_out_current_patch_data_offset(ctx);
if (ctx->screen->info.chip_class >= GFX9) {
tf_lds_offset = ac_to_float(&ctx->ac, tf_lds_offset);
/* Leave a hole corresponding to the two input VGPRs. This ensures that
- * the invocation_id output does not alias the param_tcs_rel_ids input,
+ * the invocation_id output does not alias the tcs_rel_ids input,
* which saves a V_MOV on gfx9.
*/
vgpr += 2;
8 + GFX9_SGPR_TCS_SAMPLERS_AND_IMAGES);
unsigned vgpr = 8 + GFX9_TCS_NUM_USER_SGPR;
- ret = si_insert_input_ret_float(ctx, ret,
- ctx->param_tcs_patch_id, vgpr++);
- ret = si_insert_input_ret_float(ctx, ret,
- ctx->param_tcs_rel_ids, vgpr++);
+ ret = LLVMBuildInsertValue(ctx->ac.builder, ret,
+ ac_to_float(&ctx->ac, ctx->abi.tcs_patch_id),
+ vgpr++, "");
+ ret = LLVMBuildInsertValue(ctx->ac.builder, ret,
+ ac_to_float(&ctx->ac, ctx->abi.tcs_rel_ids),
+ vgpr++, "");
ctx->return_value = ret;
}
ctx->param_tes_u = add_arg(fninfo, ARG_VGPR, ctx->f32);
ctx->param_tes_v = add_arg(fninfo, ARG_VGPR, ctx->f32);
ctx->param_tes_rel_patch_id = add_arg(fninfo, ARG_VGPR, ctx->i32);
- ctx->param_tes_patch_id = add_arg(fninfo, ARG_VGPR, ctx->i32);
+ add_arg_assign(fninfo, ARG_VGPR, ctx->i32, &ctx->abi.tes_patch_id);
}
enum {
ctx->param_tcs_factor_offset = add_arg(&fninfo, ARG_SGPR, ctx->i32);
/* VGPRs */
- ctx->param_tcs_patch_id = add_arg(&fninfo, ARG_VGPR, ctx->i32);
- ctx->param_tcs_rel_ids = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ add_arg_assign(&fninfo, ARG_VGPR, ctx->i32, &ctx->abi.tcs_patch_id);
+ add_arg_assign(&fninfo, ARG_VGPR, ctx->i32, &ctx->abi.tcs_rel_ids);
/* param_tcs_offchip_offset and param_tcs_factor_offset are
* placed after the user SGPRs.
ctx->type == PIPE_SHADER_TESS_CTRL);
/* VGPRs (first TCS, then VS) */
- ctx->param_tcs_patch_id = add_arg(&fninfo, ARG_VGPR, ctx->i32);
- ctx->param_tcs_rel_ids = add_arg(&fninfo, ARG_VGPR, ctx->i32);
+ add_arg_assign(&fninfo, ARG_VGPR, ctx->i32, &ctx->abi.tcs_patch_id);
+ add_arg_assign(&fninfo, ARG_VGPR, ctx->i32, &ctx->abi.tcs_rel_ids);
if (ctx->type == PIPE_SHADER_VERTEX) {
declare_vs_input_vgprs(ctx, &fninfo,
break;
case PIPE_SHADER_TESS_CTRL:
bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = fetch_input_tcs;
- ctx->abi.load_tess_inputs = si_nir_load_input_tcs;
+ ctx->abi.load_tess_varyings = si_nir_load_tcs_varyings;
bld_base->emit_fetch_funcs[TGSI_FILE_OUTPUT] = fetch_output_tcs;
bld_base->emit_store = store_output_tcs;
- bld_base->emit_epilogue = si_llvm_emit_tcs_epilogue;
+ ctx->abi.store_tcs_outputs = si_nir_store_output_tcs;
+ ctx->abi.emit_outputs = si_llvm_emit_tcs_epilogue;
+ ctx->abi.load_patch_vertices_in = si_load_patch_vertices_in;
+ bld_base->emit_epilogue = si_tgsi_emit_epilogue;
break;
case PIPE_SHADER_TESS_EVAL:
bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = fetch_input_tes;
- ctx->abi.load_tess_inputs = si_nir_load_input_tes;
+ ctx->abi.load_tess_varyings = si_nir_load_input_tes;
+ ctx->abi.load_tess_coord = si_load_tess_coord;
+ ctx->abi.load_tess_level = si_load_tess_level;
+ ctx->abi.load_patch_vertices_in = si_load_patch_vertices_in;
if (shader->key.as_es)
ctx->abi.emit_outputs = si_llvm_emit_es_epilogue;
else