ac/nir, radv, radeonsi: Switch to using ac_shader_args
Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Acked-by: Marek Olšák <marek.olsak@amd.com>
This commit is contained in:
@@ -38,6 +38,7 @@
|
|||||||
struct ac_nir_context {
|
struct ac_nir_context {
|
||||||
struct ac_llvm_context ac;
|
struct ac_llvm_context ac;
|
||||||
struct ac_shader_abi *abi;
|
struct ac_shader_abi *abi;
|
||||||
|
const struct ac_shader_args *args;
|
||||||
|
|
||||||
gl_shader_stage stage;
|
gl_shader_stage stage;
|
||||||
shader_info *info;
|
shader_info *info;
|
||||||
@@ -1435,16 +1436,22 @@ static LLVMValueRef visit_load_push_constant(struct ac_nir_context *ctx,
|
|||||||
offset += LLVMConstIntGetZExtValue(src0);
|
offset += LLVMConstIntGetZExtValue(src0);
|
||||||
offset /= 4;
|
offset /= 4;
|
||||||
|
|
||||||
offset -= ctx->abi->base_inline_push_consts;
|
offset -= ctx->args->base_inline_push_consts;
|
||||||
|
|
||||||
if (offset + count <= ctx->abi->num_inline_push_consts) {
|
unsigned num_inline_push_consts = ctx->args->num_inline_push_consts;
|
||||||
|
if (offset + count <= num_inline_push_consts) {
|
||||||
|
LLVMValueRef push_constants[num_inline_push_consts];
|
||||||
|
for (unsigned i = 0; i < num_inline_push_consts; i++)
|
||||||
|
push_constants[i] = ac_get_arg(&ctx->ac,
|
||||||
|
ctx->args->inline_push_consts[i]);
|
||||||
return ac_build_gather_values(&ctx->ac,
|
return ac_build_gather_values(&ctx->ac,
|
||||||
ctx->abi->inline_push_consts + offset,
|
push_constants + offset,
|
||||||
count);
|
count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = LLVMBuildGEP(ctx->ac.builder, ctx->abi->push_constants, &addr, 1, "");
|
ptr = LLVMBuildGEP(ctx->ac.builder,
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args->push_constants), &addr, 1, "");
|
||||||
|
|
||||||
if (instr->dest.ssa.bit_size == 8) {
|
if (instr->dest.ssa.bit_size == 8) {
|
||||||
unsigned load_dwords = instr->dest.ssa.num_components > 1 ? 2 : 1;
|
unsigned load_dwords = instr->dest.ssa.num_components > 1 ? 2 : 1;
|
||||||
@@ -2902,7 +2909,8 @@ visit_load_local_invocation_index(struct ac_nir_context *ctx)
|
|||||||
{
|
{
|
||||||
LLVMValueRef result;
|
LLVMValueRef result;
|
||||||
LLVMValueRef thread_id = ac_get_thread_id(&ctx->ac);
|
LLVMValueRef thread_id = ac_get_thread_id(&ctx->ac);
|
||||||
result = LLVMBuildAnd(ctx->ac.builder, ctx->abi->tg_size,
|
result = LLVMBuildAnd(ctx->ac.builder,
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args->tg_size),
|
||||||
LLVMConstInt(ctx->ac.i32, 0xfc0, false), "");
|
LLVMConstInt(ctx->ac.i32, 0xfc0, false), "");
|
||||||
|
|
||||||
if (ctx->ac.wave_size == 32)
|
if (ctx->ac.wave_size == 32)
|
||||||
@@ -2917,7 +2925,8 @@ visit_load_subgroup_id(struct ac_nir_context *ctx)
|
|||||||
{
|
{
|
||||||
if (ctx->stage == MESA_SHADER_COMPUTE) {
|
if (ctx->stage == MESA_SHADER_COMPUTE) {
|
||||||
LLVMValueRef result;
|
LLVMValueRef result;
|
||||||
result = LLVMBuildAnd(ctx->ac.builder, ctx->abi->tg_size,
|
result = LLVMBuildAnd(ctx->ac.builder,
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args->tg_size),
|
||||||
LLVMConstInt(ctx->ac.i32, 0xfc0, false), "");
|
LLVMConstInt(ctx->ac.i32, 0xfc0, false), "");
|
||||||
return LLVMBuildLShr(ctx->ac.builder, result, LLVMConstInt(ctx->ac.i32, 6, false), "");
|
return LLVMBuildLShr(ctx->ac.builder, result, LLVMConstInt(ctx->ac.i32, 6, false), "");
|
||||||
} else {
|
} else {
|
||||||
@@ -2929,7 +2938,8 @@ static LLVMValueRef
|
|||||||
visit_load_num_subgroups(struct ac_nir_context *ctx)
|
visit_load_num_subgroups(struct ac_nir_context *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->stage == MESA_SHADER_COMPUTE) {
|
if (ctx->stage == MESA_SHADER_COMPUTE) {
|
||||||
return LLVMBuildAnd(ctx->ac.builder, ctx->abi->tg_size,
|
return LLVMBuildAnd(ctx->ac.builder,
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args->tg_size),
|
||||||
LLVMConstInt(ctx->ac.i32, 0x3f, false), "");
|
LLVMConstInt(ctx->ac.i32, 0x3f, false), "");
|
||||||
} else {
|
} else {
|
||||||
return LLVMConstInt(ctx->ac.i32, 1, false);
|
return LLVMConstInt(ctx->ac.i32, 1, false);
|
||||||
@@ -3059,8 +3069,10 @@ static LLVMValueRef load_sample_pos(struct ac_nir_context *ctx)
|
|||||||
LLVMValueRef values[2];
|
LLVMValueRef values[2];
|
||||||
LLVMValueRef pos[2];
|
LLVMValueRef pos[2];
|
||||||
|
|
||||||
pos[0] = ac_to_float(&ctx->ac, ctx->abi->frag_pos[0]);
|
pos[0] = ac_to_float(&ctx->ac,
|
||||||
pos[1] = ac_to_float(&ctx->ac, ctx->abi->frag_pos[1]);
|
ac_get_arg(&ctx->ac, ctx->args->frag_pos[0]));
|
||||||
|
pos[1] = ac_to_float(&ctx->ac,
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args->frag_pos[1]));
|
||||||
|
|
||||||
values[0] = ac_build_fract(&ctx->ac, pos[0], 32);
|
values[0] = ac_build_fract(&ctx->ac, pos[0], 32);
|
||||||
values[1] = ac_build_fract(&ctx->ac, pos[1], 32);
|
values[1] = ac_build_fract(&ctx->ac, pos[1], 32);
|
||||||
@@ -3077,19 +3089,19 @@ static LLVMValueRef lookup_interp_param(struct ac_nir_context *ctx,
|
|||||||
case INTERP_MODE_SMOOTH:
|
case INTERP_MODE_SMOOTH:
|
||||||
case INTERP_MODE_NONE:
|
case INTERP_MODE_NONE:
|
||||||
if (location == INTERP_CENTER)
|
if (location == INTERP_CENTER)
|
||||||
return ctx->abi->persp_center;
|
return ac_get_arg(&ctx->ac, ctx->args->persp_center);
|
||||||
else if (location == INTERP_CENTROID)
|
else if (location == INTERP_CENTROID)
|
||||||
return ctx->abi->persp_centroid;
|
return ctx->abi->persp_centroid;
|
||||||
else if (location == INTERP_SAMPLE)
|
else if (location == INTERP_SAMPLE)
|
||||||
return ctx->abi->persp_sample;
|
return ac_get_arg(&ctx->ac, ctx->args->persp_sample);
|
||||||
break;
|
break;
|
||||||
case INTERP_MODE_NOPERSPECTIVE:
|
case INTERP_MODE_NOPERSPECTIVE:
|
||||||
if (location == INTERP_CENTER)
|
if (location == INTERP_CENTER)
|
||||||
return ctx->abi->linear_center;
|
return ac_get_arg(&ctx->ac, ctx->args->linear_center);
|
||||||
else if (location == INTERP_CENTROID)
|
else if (location == INTERP_CENTROID)
|
||||||
return ctx->abi->linear_centroid;
|
return ctx->abi->linear_centroid;
|
||||||
else if (location == INTERP_SAMPLE)
|
else if (location == INTERP_SAMPLE)
|
||||||
return ctx->abi->linear_sample;
|
return ac_get_arg(&ctx->ac, ctx->args->linear_sample);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -3203,10 +3215,10 @@ static LLVMValueRef load_interpolated_input(struct ac_nir_context *ctx,
|
|||||||
LLVMValueRef llvm_chan = LLVMConstInt(ctx->ac.i32, comp_start + comp, false);
|
LLVMValueRef llvm_chan = LLVMConstInt(ctx->ac.i32, comp_start + comp, false);
|
||||||
if (bitsize == 16) {
|
if (bitsize == 16) {
|
||||||
values[comp] = ac_build_fs_interp_f16(&ctx->ac, llvm_chan, attr_number,
|
values[comp] = ac_build_fs_interp_f16(&ctx->ac, llvm_chan, attr_number,
|
||||||
ctx->abi->prim_mask, i, j);
|
ac_get_arg(&ctx->ac, ctx->args->prim_mask), i, j);
|
||||||
} else {
|
} else {
|
||||||
values[comp] = ac_build_fs_interp(&ctx->ac, llvm_chan, attr_number,
|
values[comp] = ac_build_fs_interp(&ctx->ac, llvm_chan, attr_number,
|
||||||
ctx->abi->prim_mask, i, j);
|
ac_get_arg(&ctx->ac, ctx->args->prim_mask), i, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3234,7 +3246,7 @@ static LLVMValueRef load_flat_input(struct ac_nir_context *ctx,
|
|||||||
LLVMConstInt(ctx->ac.i32, 2, false),
|
LLVMConstInt(ctx->ac.i32, 2, false),
|
||||||
llvm_chan,
|
llvm_chan,
|
||||||
attr_number,
|
attr_number,
|
||||||
ctx->abi->prim_mask);
|
ac_get_arg(&ctx->ac, ctx->args->prim_mask));
|
||||||
values[chan] = LLVMBuildBitCast(ctx->ac.builder, values[chan], ctx->ac.i32, "");
|
values[chan] = LLVMBuildBitCast(ctx->ac.builder, values[chan], ctx->ac.i32, "");
|
||||||
values[chan] = LLVMBuildTruncOrBitCast(ctx->ac.builder, values[chan],
|
values[chan] = LLVMBuildTruncOrBitCast(ctx->ac.builder, values[chan],
|
||||||
bit_size == 16 ? ctx->ac.i16 : ctx->ac.i32, "");
|
bit_size == 16 ? ctx->ac.i16 : ctx->ac.i32, "");
|
||||||
@@ -3274,8 +3286,8 @@ static void visit_intrinsic(struct ac_nir_context *ctx,
|
|||||||
LLVMValueRef values[3];
|
LLVMValueRef values[3];
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
values[i] = ctx->abi->workgroup_ids[i] ?
|
values[i] = ctx->args->workgroup_ids[i].used ?
|
||||||
ctx->abi->workgroup_ids[i] : ctx->ac.i32_0;
|
ac_get_arg(&ctx->ac, ctx->args->workgroup_ids[i]) : ctx->ac.i32_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ac_build_gather_values(&ctx->ac, values, 3);
|
result = ac_build_gather_values(&ctx->ac, values, 3);
|
||||||
@@ -3289,51 +3301,56 @@ static void visit_intrinsic(struct ac_nir_context *ctx,
|
|||||||
result = ctx->abi->load_local_group_size(ctx->abi);
|
result = ctx->abi->load_local_group_size(ctx->abi);
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_vertex_id:
|
case nir_intrinsic_load_vertex_id:
|
||||||
result = LLVMBuildAdd(ctx->ac.builder, ctx->abi->vertex_id,
|
result = LLVMBuildAdd(ctx->ac.builder,
|
||||||
ctx->abi->base_vertex, "");
|
ac_get_arg(&ctx->ac, ctx->args->vertex_id),
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args->base_vertex), "");
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_vertex_id_zero_base: {
|
case nir_intrinsic_load_vertex_id_zero_base: {
|
||||||
result = ctx->abi->vertex_id;
|
result = ctx->abi->vertex_id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case nir_intrinsic_load_local_invocation_id: {
|
case nir_intrinsic_load_local_invocation_id: {
|
||||||
result = ctx->abi->local_invocation_ids;
|
result = ac_get_arg(&ctx->ac, ctx->args->local_invocation_ids);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case nir_intrinsic_load_base_instance:
|
case nir_intrinsic_load_base_instance:
|
||||||
result = ctx->abi->start_instance;
|
result = ac_get_arg(&ctx->ac, ctx->args->start_instance);
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_draw_id:
|
case nir_intrinsic_load_draw_id:
|
||||||
result = ctx->abi->draw_id;
|
result = ac_get_arg(&ctx->ac, ctx->args->draw_id);
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_view_index:
|
case nir_intrinsic_load_view_index:
|
||||||
result = ctx->abi->view_index;
|
result = ac_get_arg(&ctx->ac, ctx->args->view_index);
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_invocation_id:
|
case nir_intrinsic_load_invocation_id:
|
||||||
if (ctx->stage == MESA_SHADER_TESS_CTRL) {
|
if (ctx->stage == MESA_SHADER_TESS_CTRL) {
|
||||||
result = ac_unpack_param(&ctx->ac, ctx->abi->tcs_rel_ids, 8, 5);
|
result = ac_unpack_param(&ctx->ac,
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args->tcs_rel_ids),
|
||||||
|
8, 5);
|
||||||
} else {
|
} else {
|
||||||
if (ctx->ac.chip_class >= GFX10) {
|
if (ctx->ac.chip_class >= GFX10) {
|
||||||
result = LLVMBuildAnd(ctx->ac.builder,
|
result = LLVMBuildAnd(ctx->ac.builder,
|
||||||
ctx->abi->gs_invocation_id,
|
ac_get_arg(&ctx->ac, ctx->args->gs_invocation_id),
|
||||||
LLVMConstInt(ctx->ac.i32, 127, 0), "");
|
LLVMConstInt(ctx->ac.i32, 127, 0), "");
|
||||||
} else {
|
} else {
|
||||||
result = ctx->abi->gs_invocation_id;
|
result = ac_get_arg(&ctx->ac, ctx->args->gs_invocation_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_primitive_id:
|
case nir_intrinsic_load_primitive_id:
|
||||||
if (ctx->stage == MESA_SHADER_GEOMETRY) {
|
if (ctx->stage == MESA_SHADER_GEOMETRY) {
|
||||||
result = ctx->abi->gs_prim_id;
|
result = ac_get_arg(&ctx->ac, ctx->args->gs_prim_id);
|
||||||
} else if (ctx->stage == MESA_SHADER_TESS_CTRL) {
|
} else if (ctx->stage == MESA_SHADER_TESS_CTRL) {
|
||||||
result = ctx->abi->tcs_patch_id;
|
result = ac_get_arg(&ctx->ac, ctx->args->tcs_patch_id);
|
||||||
} else if (ctx->stage == MESA_SHADER_TESS_EVAL) {
|
} else if (ctx->stage == MESA_SHADER_TESS_EVAL) {
|
||||||
result = ctx->abi->tes_patch_id;
|
result = ac_get_arg(&ctx->ac, ctx->args->tes_patch_id);
|
||||||
} else
|
} else
|
||||||
fprintf(stderr, "Unknown primitive id intrinsic: %d", ctx->stage);
|
fprintf(stderr, "Unknown primitive id intrinsic: %d", ctx->stage);
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_sample_id:
|
case nir_intrinsic_load_sample_id:
|
||||||
result = ac_unpack_param(&ctx->ac, ctx->abi->ancillary, 8, 4);
|
result = ac_unpack_param(&ctx->ac,
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args->ancillary),
|
||||||
|
8, 4);
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_sample_pos:
|
case nir_intrinsic_load_sample_pos:
|
||||||
result = load_sample_pos(ctx);
|
result = load_sample_pos(ctx);
|
||||||
@@ -3343,10 +3360,11 @@ static void visit_intrinsic(struct ac_nir_context *ctx,
|
|||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_frag_coord: {
|
case nir_intrinsic_load_frag_coord: {
|
||||||
LLVMValueRef values[4] = {
|
LLVMValueRef values[4] = {
|
||||||
ctx->abi->frag_pos[0],
|
ac_get_arg(&ctx->ac, ctx->args->frag_pos[0]),
|
||||||
ctx->abi->frag_pos[1],
|
ac_get_arg(&ctx->ac, ctx->args->frag_pos[1]),
|
||||||
ctx->abi->frag_pos[2],
|
ac_get_arg(&ctx->ac, ctx->args->frag_pos[2]),
|
||||||
ac_build_fdiv(&ctx->ac, ctx->ac.f32_1, ctx->abi->frag_pos[3])
|
ac_build_fdiv(&ctx->ac, ctx->ac.f32_1,
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args->frag_pos[3]))
|
||||||
};
|
};
|
||||||
result = ac_to_integer(&ctx->ac,
|
result = ac_to_integer(&ctx->ac,
|
||||||
ac_build_gather_values(&ctx->ac, values, 4));
|
ac_build_gather_values(&ctx->ac, values, 4));
|
||||||
@@ -3356,7 +3374,7 @@ static void visit_intrinsic(struct ac_nir_context *ctx,
|
|||||||
result = ctx->abi->inputs[ac_llvm_reg_index_soa(VARYING_SLOT_LAYER, 0)];
|
result = ctx->abi->inputs[ac_llvm_reg_index_soa(VARYING_SLOT_LAYER, 0)];
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_front_face:
|
case nir_intrinsic_load_front_face:
|
||||||
result = ctx->abi->front_face;
|
result = ac_get_arg(&ctx->ac, ctx->args->front_face);
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_helper_invocation:
|
case nir_intrinsic_load_helper_invocation:
|
||||||
result = ac_build_load_helper_invocation(&ctx->ac);
|
result = ac_build_load_helper_invocation(&ctx->ac);
|
||||||
@@ -3375,7 +3393,7 @@ static void visit_intrinsic(struct ac_nir_context *ctx,
|
|||||||
result = ctx->abi->instance_id;
|
result = ctx->abi->instance_id;
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_num_work_groups:
|
case nir_intrinsic_load_num_work_groups:
|
||||||
result = ctx->abi->num_work_groups;
|
result = ac_get_arg(&ctx->ac, ctx->args->num_work_groups);
|
||||||
break;
|
break;
|
||||||
case nir_intrinsic_load_local_invocation_index:
|
case nir_intrinsic_load_local_invocation_index:
|
||||||
result = visit_load_local_invocation_index(ctx);
|
result = visit_load_local_invocation_index(ctx);
|
||||||
@@ -4714,13 +4732,14 @@ setup_shared(struct ac_nir_context *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ac_nir_translate(struct ac_llvm_context *ac, struct ac_shader_abi *abi,
|
void ac_nir_translate(struct ac_llvm_context *ac, struct ac_shader_abi *abi,
|
||||||
struct nir_shader *nir)
|
const struct ac_shader_args *args, struct nir_shader *nir)
|
||||||
{
|
{
|
||||||
struct ac_nir_context ctx = {};
|
struct ac_nir_context ctx = {};
|
||||||
struct nir_function *func;
|
struct nir_function *func;
|
||||||
|
|
||||||
ctx.ac = *ac;
|
ctx.ac = *ac;
|
||||||
ctx.abi = abi;
|
ctx.abi = abi;
|
||||||
|
ctx.args = args;
|
||||||
|
|
||||||
ctx.stage = nir->info.stage;
|
ctx.stage = nir->info.stage;
|
||||||
ctx.info = &nir->info;
|
ctx.info = &nir->info;
|
||||||
|
@@ -34,6 +34,7 @@ struct nir_shader;
|
|||||||
struct nir_variable;
|
struct nir_variable;
|
||||||
struct ac_llvm_context;
|
struct ac_llvm_context;
|
||||||
struct ac_shader_abi;
|
struct ac_shader_abi;
|
||||||
|
struct ac_shader_args;
|
||||||
|
|
||||||
/* Interpolation locations */
|
/* Interpolation locations */
|
||||||
#define INTERP_CENTER 0
|
#define INTERP_CENTER 0
|
||||||
@@ -50,7 +51,7 @@ void ac_lower_indirect_derefs(struct nir_shader *nir, enum chip_class);
|
|||||||
bool ac_are_tessfactors_def_in_all_invocs(const struct nir_shader *nir);
|
bool ac_are_tessfactors_def_in_all_invocs(const struct nir_shader *nir);
|
||||||
|
|
||||||
void ac_nir_translate(struct ac_llvm_context *ac, struct ac_shader_abi *abi,
|
void ac_nir_translate(struct ac_llvm_context *ac, struct ac_shader_abi *abi,
|
||||||
struct nir_shader *nir);
|
const struct ac_shader_args *args, struct nir_shader *nir);
|
||||||
|
|
||||||
void
|
void
|
||||||
ac_handle_shader_output_decl(struct ac_llvm_context *ctx,
|
ac_handle_shader_output_decl(struct ac_llvm_context *ctx,
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
#define AC_SHADER_ABI_H
|
#define AC_SHADER_ABI_H
|
||||||
|
|
||||||
#include <llvm-c/Core.h>
|
#include <llvm-c/Core.h>
|
||||||
|
#include <assert.h>
|
||||||
#include "ac_shader_args.h"
|
#include "ac_shader_args.h"
|
||||||
|
|
||||||
#include "compiler/shader_enums.h"
|
#include "compiler/shader_enums.h"
|
||||||
@@ -49,47 +50,14 @@ enum ac_descriptor_type {
|
|||||||
* radv to share a compiler backend.
|
* radv to share a compiler backend.
|
||||||
*/
|
*/
|
||||||
struct ac_shader_abi {
|
struct ac_shader_abi {
|
||||||
LLVMValueRef base_vertex;
|
LLVMValueRef outputs[AC_LLVM_MAX_OUTPUTS * 4];
|
||||||
LLVMValueRef start_instance;
|
|
||||||
LLVMValueRef draw_id;
|
/* These input registers sometimes need to be fixed up. */
|
||||||
LLVMValueRef vertex_id;
|
LLVMValueRef vertex_id;
|
||||||
LLVMValueRef instance_id;
|
LLVMValueRef instance_id;
|
||||||
LLVMValueRef tcs_patch_id;
|
LLVMValueRef persp_centroid, linear_centroid;
|
||||||
LLVMValueRef tcs_rel_ids;
|
LLVMValueRef color0, color1;
|
||||||
LLVMValueRef tes_patch_id;
|
|
||||||
LLVMValueRef gs_prim_id;
|
|
||||||
LLVMValueRef gs_invocation_id;
|
|
||||||
|
|
||||||
/* PS */
|
|
||||||
LLVMValueRef frag_pos[4];
|
|
||||||
LLVMValueRef front_face;
|
|
||||||
LLVMValueRef ancillary;
|
|
||||||
LLVMValueRef sample_coverage;
|
|
||||||
LLVMValueRef prim_mask;
|
|
||||||
LLVMValueRef color0;
|
|
||||||
LLVMValueRef color1;
|
|
||||||
LLVMValueRef user_data;
|
LLVMValueRef user_data;
|
||||||
LLVMValueRef persp_sample;
|
|
||||||
LLVMValueRef persp_center;
|
|
||||||
LLVMValueRef persp_centroid;
|
|
||||||
LLVMValueRef linear_sample;
|
|
||||||
LLVMValueRef linear_center;
|
|
||||||
LLVMValueRef linear_centroid;
|
|
||||||
|
|
||||||
/* CS */
|
|
||||||
LLVMValueRef local_invocation_ids;
|
|
||||||
LLVMValueRef num_work_groups;
|
|
||||||
LLVMValueRef workgroup_ids[3];
|
|
||||||
LLVMValueRef tg_size;
|
|
||||||
|
|
||||||
/* Vulkan only */
|
|
||||||
LLVMValueRef push_constants;
|
|
||||||
LLVMValueRef inline_push_consts[AC_MAX_INLINE_PUSH_CONSTS];
|
|
||||||
unsigned num_inline_push_consts;
|
|
||||||
unsigned base_inline_push_consts;
|
|
||||||
LLVMValueRef view_index;
|
|
||||||
|
|
||||||
LLVMValueRef outputs[AC_LLVM_MAX_OUTPUTS * 4];
|
|
||||||
|
|
||||||
/* For VS and PS: pre-loaded shader inputs.
|
/* For VS and PS: pre-loaded shader inputs.
|
||||||
*
|
*
|
||||||
|
@@ -101,6 +101,7 @@ libradv_files = files(
|
|||||||
'radv_radeon_winsys.h',
|
'radv_radeon_winsys.h',
|
||||||
'radv_shader.c',
|
'radv_shader.c',
|
||||||
'radv_shader.h',
|
'radv_shader.h',
|
||||||
|
'radv_shader_args.h',
|
||||||
'radv_shader_helper.h',
|
'radv_shader_helper.h',
|
||||||
'radv_shader_info.c',
|
'radv_shader_info.c',
|
||||||
'radv_query.c',
|
'radv_query.c',
|
||||||
|
File diff suppressed because it is too large
Load Diff
76
src/amd/vulkan/radv_shader_args.h
Normal file
76
src/amd/vulkan/radv_shader_args.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2019 Valve Corporation.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ac_shader_args.h"
|
||||||
|
#include "radv_constants.h"
|
||||||
|
#include "util/list.h"
|
||||||
|
#include "amd_family.h"
|
||||||
|
|
||||||
|
struct radv_shader_args {
|
||||||
|
struct ac_shader_args ac;
|
||||||
|
struct radv_shader_info *shader_info;
|
||||||
|
const struct radv_nir_compiler_options *options;
|
||||||
|
|
||||||
|
struct ac_arg descriptor_sets[MAX_SETS];
|
||||||
|
struct ac_arg ring_offsets;
|
||||||
|
|
||||||
|
struct ac_arg vertex_buffers;
|
||||||
|
struct ac_arg rel_auto_id;
|
||||||
|
struct ac_arg vs_prim_id;
|
||||||
|
struct ac_arg es2gs_offset;
|
||||||
|
|
||||||
|
struct ac_arg oc_lds;
|
||||||
|
struct ac_arg merged_wave_info;
|
||||||
|
struct ac_arg tess_factor_offset;
|
||||||
|
struct ac_arg tes_rel_patch_id;
|
||||||
|
struct ac_arg tes_u;
|
||||||
|
struct ac_arg tes_v;
|
||||||
|
|
||||||
|
/* HW GS */
|
||||||
|
/* On gfx10:
|
||||||
|
* - bits 0..10: ordered_wave_id
|
||||||
|
* - bits 12..20: number of vertices in group
|
||||||
|
* - bits 22..30: number of primitives in group
|
||||||
|
*/
|
||||||
|
struct ac_arg gs_tg_info;
|
||||||
|
struct ac_arg gs2vs_offset;
|
||||||
|
struct ac_arg gs_wave_id;
|
||||||
|
struct ac_arg gs_vtx_offset[6];
|
||||||
|
|
||||||
|
/* Streamout */
|
||||||
|
struct ac_arg streamout_buffers;
|
||||||
|
struct ac_arg streamout_write_idx;
|
||||||
|
struct ac_arg streamout_config;
|
||||||
|
struct ac_arg streamout_offset[4];
|
||||||
|
|
||||||
|
bool is_gs_copy_shader;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct radv_shader_args *
|
||||||
|
radv_shader_args_from_ac(struct ac_shader_args *args)
|
||||||
|
{
|
||||||
|
struct radv_shader_args *radv_args = NULL;
|
||||||
|
return (struct radv_shader_args *) container_of(args, radv_args, ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@@ -31,12 +31,12 @@
|
|||||||
|
|
||||||
static LLVMValueRef get_wave_id_in_tg(struct si_shader_context *ctx)
|
static LLVMValueRef get_wave_id_in_tg(struct si_shader_context *ctx)
|
||||||
{
|
{
|
||||||
return si_unpack_param(ctx, ctx->param_merged_wave_info, 24, 4);
|
return si_unpack_param(ctx, ctx->merged_wave_info, 24, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef get_tgsize(struct si_shader_context *ctx)
|
static LLVMValueRef get_tgsize(struct si_shader_context *ctx)
|
||||||
{
|
{
|
||||||
return si_unpack_param(ctx, ctx->param_merged_wave_info, 28, 4);
|
return si_unpack_param(ctx, ctx->merged_wave_info, 28, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef get_thread_id_in_tg(struct si_shader_context *ctx)
|
static LLVMValueRef get_thread_id_in_tg(struct si_shader_context *ctx)
|
||||||
@@ -50,32 +50,22 @@ static LLVMValueRef get_thread_id_in_tg(struct si_shader_context *ctx)
|
|||||||
|
|
||||||
static LLVMValueRef ngg_get_vtx_cnt(struct si_shader_context *ctx)
|
static LLVMValueRef ngg_get_vtx_cnt(struct si_shader_context *ctx)
|
||||||
{
|
{
|
||||||
return ac_build_bfe(&ctx->ac, ctx->gs_tg_info,
|
return si_unpack_param(ctx, ctx->gs_tg_info, 12, 9);
|
||||||
LLVMConstInt(ctx->ac.i32, 12, false),
|
|
||||||
LLVMConstInt(ctx->ac.i32, 9, false),
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef ngg_get_prim_cnt(struct si_shader_context *ctx)
|
static LLVMValueRef ngg_get_prim_cnt(struct si_shader_context *ctx)
|
||||||
{
|
{
|
||||||
return ac_build_bfe(&ctx->ac, ctx->gs_tg_info,
|
return si_unpack_param(ctx, ctx->gs_tg_info, 22, 9);
|
||||||
LLVMConstInt(ctx->ac.i32, 22, false),
|
|
||||||
LLVMConstInt(ctx->ac.i32, 9, false),
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef ngg_get_ordered_id(struct si_shader_context *ctx)
|
static LLVMValueRef ngg_get_ordered_id(struct si_shader_context *ctx)
|
||||||
{
|
{
|
||||||
return ac_build_bfe(&ctx->ac, ctx->gs_tg_info,
|
return si_unpack_param(ctx, ctx->gs_tg_info, 0, 11);
|
||||||
ctx->i32_0,
|
|
||||||
LLVMConstInt(ctx->ac.i32, 11, false),
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef ngg_get_query_buf(struct si_shader_context *ctx)
|
static LLVMValueRef ngg_get_query_buf(struct si_shader_context *ctx)
|
||||||
{
|
{
|
||||||
LLVMValueRef buf_ptr = LLVMGetParam(ctx->main_fn,
|
LLVMValueRef buf_ptr = ac_get_arg(&ctx->ac, ctx->rw_buffers);
|
||||||
ctx->param_rw_buffers);
|
|
||||||
|
|
||||||
return ac_build_load_to_sgpr(&ctx->ac, buf_ptr,
|
return ac_build_load_to_sgpr(&ctx->ac, buf_ptr,
|
||||||
LLVMConstInt(ctx->i32, GFX10_GS_QUERY_BUF, false));
|
LLVMConstInt(ctx->i32, GFX10_GS_QUERY_BUF, false));
|
||||||
@@ -212,7 +202,7 @@ static void build_streamout(struct si_shader_context *ctx,
|
|||||||
struct tgsi_shader_info *info = &ctx->shader->selector->info;
|
struct tgsi_shader_info *info = &ctx->shader->selector->info;
|
||||||
struct pipe_stream_output_info *so = &ctx->shader->selector->so;
|
struct pipe_stream_output_info *so = &ctx->shader->selector->so;
|
||||||
LLVMBuilderRef builder = ctx->ac.builder;
|
LLVMBuilderRef builder = ctx->ac.builder;
|
||||||
LLVMValueRef buf_ptr = LLVMGetParam(ctx->main_fn, ctx->param_rw_buffers);
|
LLVMValueRef buf_ptr = ac_get_arg(&ctx->ac, ctx->rw_buffers);
|
||||||
LLVMValueRef tid = get_thread_id_in_tg(ctx);
|
LLVMValueRef tid = get_thread_id_in_tg(ctx);
|
||||||
LLVMValueRef tmp, tmp2;
|
LLVMValueRef tmp, tmp2;
|
||||||
LLVMValueRef i32_2 = LLVMConstInt(ctx->i32, 2, false);
|
LLVMValueRef i32_2 = LLVMConstInt(ctx->i32, 2, false);
|
||||||
@@ -583,16 +573,16 @@ void gfx10_emit_ngg_epilogue(struct ac_shader_abi *abi,
|
|||||||
|
|
||||||
ac_build_endif(&ctx->ac, ctx->merged_wrap_if_label);
|
ac_build_endif(&ctx->ac, ctx->merged_wrap_if_label);
|
||||||
|
|
||||||
LLVMValueRef prims_in_wave = si_unpack_param(ctx, ctx->param_merged_wave_info, 8, 8);
|
LLVMValueRef prims_in_wave = si_unpack_param(ctx, ctx->merged_wave_info, 8, 8);
|
||||||
LLVMValueRef vtx_in_wave = si_unpack_param(ctx, ctx->param_merged_wave_info, 0, 8);
|
LLVMValueRef vtx_in_wave = si_unpack_param(ctx, ctx->merged_wave_info, 0, 8);
|
||||||
LLVMValueRef is_gs_thread = LLVMBuildICmp(builder, LLVMIntULT,
|
LLVMValueRef is_gs_thread = LLVMBuildICmp(builder, LLVMIntULT,
|
||||||
ac_get_thread_id(&ctx->ac), prims_in_wave, "");
|
ac_get_thread_id(&ctx->ac), prims_in_wave, "");
|
||||||
LLVMValueRef is_es_thread = LLVMBuildICmp(builder, LLVMIntULT,
|
LLVMValueRef is_es_thread = LLVMBuildICmp(builder, LLVMIntULT,
|
||||||
ac_get_thread_id(&ctx->ac), vtx_in_wave, "");
|
ac_get_thread_id(&ctx->ac), vtx_in_wave, "");
|
||||||
LLVMValueRef vtxindex[] = {
|
LLVMValueRef vtxindex[] = {
|
||||||
si_unpack_param(ctx, ctx->param_gs_vtx01_offset, 0, 16),
|
si_unpack_param(ctx, ctx->gs_vtx01_offset, 0, 16),
|
||||||
si_unpack_param(ctx, ctx->param_gs_vtx01_offset, 16, 16),
|
si_unpack_param(ctx, ctx->gs_vtx01_offset, 16, 16),
|
||||||
si_unpack_param(ctx, ctx->param_gs_vtx23_offset, 0, 16),
|
si_unpack_param(ctx, ctx->gs_vtx23_offset, 0, 16),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Determine the number of vertices per primitive. */
|
/* Determine the number of vertices per primitive. */
|
||||||
@@ -606,7 +596,7 @@ void gfx10_emit_ngg_epilogue(struct ac_shader_abi *abi,
|
|||||||
num_vertices_val = LLVMConstInt(ctx->i32, 3, 0);
|
num_vertices_val = LLVMConstInt(ctx->i32, 3, 0);
|
||||||
} else {
|
} else {
|
||||||
/* Extract OUTPRIM field. */
|
/* Extract OUTPRIM field. */
|
||||||
tmp = si_unpack_param(ctx, ctx->param_vs_state_bits, 2, 2);
|
tmp = si_unpack_param(ctx, ctx->vs_state_bits, 2, 2);
|
||||||
num_vertices_val = LLVMBuildAdd(builder, tmp, ctx->i32_1, "");
|
num_vertices_val = LLVMBuildAdd(builder, tmp, ctx->i32_1, "");
|
||||||
num_vertices = 3; /* TODO: optimize for points & lines */
|
num_vertices = 3; /* TODO: optimize for points & lines */
|
||||||
}
|
}
|
||||||
@@ -673,14 +663,14 @@ void gfx10_emit_ngg_epilogue(struct ac_shader_abi *abi,
|
|||||||
ac_build_ifcc(&ctx->ac, is_gs_thread, 5400);
|
ac_build_ifcc(&ctx->ac, is_gs_thread, 5400);
|
||||||
/* Extract the PROVOKING_VTX_INDEX field. */
|
/* Extract the PROVOKING_VTX_INDEX field. */
|
||||||
LLVMValueRef provoking_vtx_in_prim =
|
LLVMValueRef provoking_vtx_in_prim =
|
||||||
si_unpack_param(ctx, ctx->param_vs_state_bits, 4, 2);
|
si_unpack_param(ctx, ctx->vs_state_bits, 4, 2);
|
||||||
|
|
||||||
/* provoking_vtx_index = vtxindex[provoking_vtx_in_prim]; */
|
/* provoking_vtx_index = vtxindex[provoking_vtx_in_prim]; */
|
||||||
LLVMValueRef indices = ac_build_gather_values(&ctx->ac, vtxindex, 3);
|
LLVMValueRef indices = ac_build_gather_values(&ctx->ac, vtxindex, 3);
|
||||||
LLVMValueRef provoking_vtx_index =
|
LLVMValueRef provoking_vtx_index =
|
||||||
LLVMBuildExtractElement(builder, indices, provoking_vtx_in_prim, "");
|
LLVMBuildExtractElement(builder, indices, provoking_vtx_in_prim, "");
|
||||||
|
|
||||||
LLVMBuildStore(builder, ctx->abi.gs_prim_id,
|
LLVMBuildStore(builder, ac_get_arg(&ctx->ac, ctx->args.gs_prim_id),
|
||||||
ac_build_gep0(&ctx->ac, ctx->esgs_ring, provoking_vtx_index));
|
ac_build_gep0(&ctx->ac, ctx->esgs_ring, provoking_vtx_index));
|
||||||
ac_build_endif(&ctx->ac, 5400);
|
ac_build_endif(&ctx->ac, 5400);
|
||||||
}
|
}
|
||||||
@@ -690,7 +680,7 @@ void gfx10_emit_ngg_epilogue(struct ac_shader_abi *abi,
|
|||||||
/* Update query buffer */
|
/* Update query buffer */
|
||||||
/* TODO: this won't catch 96-bit clear_buffer via transform feedback. */
|
/* TODO: this won't catch 96-bit clear_buffer via transform feedback. */
|
||||||
if (!info->properties[TGSI_PROPERTY_VS_BLIT_SGPRS_AMD]) {
|
if (!info->properties[TGSI_PROPERTY_VS_BLIT_SGPRS_AMD]) {
|
||||||
tmp = si_unpack_param(ctx, ctx->param_vs_state_bits, 6, 1);
|
tmp = si_unpack_param(ctx, ctx->vs_state_bits, 6, 1);
|
||||||
tmp = LLVMBuildTrunc(builder, tmp, ctx->i1, "");
|
tmp = LLVMBuildTrunc(builder, tmp, ctx->i1, "");
|
||||||
ac_build_ifcc(&ctx->ac, tmp, 5029); /* if (STREAMOUT_QUERY_ENABLED) */
|
ac_build_ifcc(&ctx->ac, tmp, 5029); /* if (STREAMOUT_QUERY_ENABLED) */
|
||||||
tmp = LLVMBuildICmp(builder, LLVMIntEQ, get_wave_id_in_tg(ctx), ctx->ac.i32_0, "");
|
tmp = LLVMBuildICmp(builder, LLVMIntEQ, get_wave_id_in_tg(ctx), ctx->ac.i32_0, "");
|
||||||
@@ -752,7 +742,8 @@ void gfx10_emit_ngg_epilogue(struct ac_shader_abi *abi,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = LLVMBuildLShr(builder, ctx->abi.gs_invocation_id,
|
tmp = LLVMBuildLShr(builder,
|
||||||
|
ac_get_arg(&ctx->ac, ctx->args.gs_invocation_id),
|
||||||
LLVMConstInt(ctx->ac.i32, 8 + i, false), "");
|
LLVMConstInt(ctx->ac.i32, 8 + i, false), "");
|
||||||
prim.edgeflag[i] = LLVMBuildTrunc(builder, tmp, ctx->ac.i1, "");
|
prim.edgeflag[i] = LLVMBuildTrunc(builder, tmp, ctx->ac.i1, "");
|
||||||
|
|
||||||
@@ -1099,7 +1090,7 @@ void gfx10_ngg_gs_emit_epilogue(struct si_shader_context *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write shader query data. */
|
/* Write shader query data. */
|
||||||
tmp = si_unpack_param(ctx, ctx->param_vs_state_bits, 6, 1);
|
tmp = si_unpack_param(ctx, ctx->vs_state_bits, 6, 1);
|
||||||
tmp = LLVMBuildTrunc(builder, tmp, ctx->i1, "");
|
tmp = LLVMBuildTrunc(builder, tmp, ctx->i1, "");
|
||||||
ac_build_ifcc(&ctx->ac, tmp, 5109); /* if (STREAMOUT_QUERY_ENABLED) */
|
ac_build_ifcc(&ctx->ac, tmp, 5109); /* if (STREAMOUT_QUERY_ENABLED) */
|
||||||
unsigned num_query_comps = sel->so.num_outputs ? 8 : 4;
|
unsigned num_query_comps = sel->so.num_outputs ? 8 : 4;
|
||||||
|
@@ -318,50 +318,51 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
ac_add_function_attr(ctx->ac.context, vs, -1, AC_FUNC_ATTR_ALWAYSINLINE);
|
ac_add_function_attr(ctx->ac.context, vs, -1, AC_FUNC_ATTR_ALWAYSINLINE);
|
||||||
LLVMSetLinkage(vs, LLVMPrivateLinkage);
|
LLVMSetLinkage(vs, LLVMPrivateLinkage);
|
||||||
|
|
||||||
LLVMTypeRef const_desc_type;
|
enum ac_arg_type const_desc_type;
|
||||||
if (ctx->shader->selector->info.const_buffers_declared == 1 &&
|
if (ctx->shader->selector->info.const_buffers_declared == 1 &&
|
||||||
ctx->shader->selector->info.shader_buffers_declared == 0)
|
ctx->shader->selector->info.shader_buffers_declared == 0)
|
||||||
const_desc_type = ctx->f32;
|
const_desc_type = AC_ARG_CONST_FLOAT_PTR;
|
||||||
else
|
else
|
||||||
const_desc_type = ctx->v4i32;
|
const_desc_type = AC_ARG_CONST_DESC_PTR;
|
||||||
|
|
||||||
struct si_function_info fninfo;
|
memset(&ctx->args, 0, sizeof(ctx->args));
|
||||||
si_init_function_info(&fninfo);
|
|
||||||
|
|
||||||
LLVMValueRef index_buffers_and_constants, vertex_counter, vb_desc, const_desc;
|
struct ac_arg param_index_buffers_and_constants, param_vertex_counter;
|
||||||
LLVMValueRef base_vertex, start_instance, block_id, local_id, ordered_wave_id;
|
struct ac_arg param_vb_desc, param_const_desc;
|
||||||
LLVMValueRef restart_index, vp_scale[2], vp_translate[2], smallprim_precision;
|
struct ac_arg param_base_vertex, param_start_instance;
|
||||||
LLVMValueRef num_prims_udiv_multiplier, num_prims_udiv_terms, sampler_desc;
|
struct ac_arg param_block_id, param_local_id, param_ordered_wave_id;
|
||||||
LLVMValueRef last_wave_prim_id, vertex_count_addr;
|
struct ac_arg param_restart_index, param_smallprim_precision;
|
||||||
|
struct ac_arg param_num_prims_udiv_multiplier, param_num_prims_udiv_terms;
|
||||||
|
struct ac_arg param_sampler_desc, param_last_wave_prim_id, param_vertex_count_addr;
|
||||||
|
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ac_array_in_const32_addr_space(ctx->v4i32),
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_CONST_DESC_PTR,
|
||||||
&index_buffers_and_constants);
|
¶m_index_buffers_and_constants);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &vertex_counter);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_vertex_counter);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &last_wave_prim_id);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_last_wave_prim_id);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &vertex_count_addr);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_vertex_count_addr);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ac_array_in_const32_addr_space(ctx->v4i32),
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_CONST_DESC_PTR,
|
||||||
&vb_desc);
|
¶m_vb_desc);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ac_array_in_const32_addr_space(const_desc_type),
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, const_desc_type,
|
||||||
&const_desc);
|
¶m_const_desc);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ac_array_in_const32_addr_space(ctx->v8i32),
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_CONST_IMAGE_PTR,
|
||||||
&sampler_desc);
|
¶m_sampler_desc);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &base_vertex);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_base_vertex);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &start_instance);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_start_instance);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &num_prims_udiv_multiplier);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_num_prims_udiv_multiplier);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &num_prims_udiv_terms);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_num_prims_udiv_terms);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &restart_index);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_restart_index);
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->f32, &smallprim_precision);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_FLOAT, ¶m_smallprim_precision);
|
||||||
|
|
||||||
/* Block ID and thread ID inputs. */
|
/* Block ID and thread ID inputs. */
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &block_id);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_block_id);
|
||||||
if (VERTEX_COUNTER_GDS_MODE == 2)
|
if (VERTEX_COUNTER_GDS_MODE == 2)
|
||||||
add_arg_assign(&fninfo, ARG_SGPR, ctx->i32, &ordered_wave_id);
|
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, ¶m_ordered_wave_id);
|
||||||
add_arg_assign(&fninfo, ARG_VGPR, ctx->i32, &local_id);
|
ac_add_arg(&ctx->args, AC_ARG_VGPR, 1, AC_ARG_INT, ¶m_local_id);
|
||||||
|
|
||||||
/* Create the compute shader function. */
|
/* Create the compute shader function. */
|
||||||
unsigned old_type = ctx->type;
|
unsigned old_type = ctx->type;
|
||||||
ctx->type = PIPE_SHADER_COMPUTE;
|
ctx->type = PIPE_SHADER_COMPUTE;
|
||||||
si_create_function(ctx, "prim_discard_cs", NULL, 0, &fninfo, THREADGROUP_SIZE);
|
si_create_function(ctx, "prim_discard_cs", NULL, 0, THREADGROUP_SIZE);
|
||||||
ctx->type = old_type;
|
ctx->type = old_type;
|
||||||
|
|
||||||
if (VERTEX_COUNTER_GDS_MODE == 1) {
|
if (VERTEX_COUNTER_GDS_MODE == 1) {
|
||||||
@@ -376,14 +377,14 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
|
|
||||||
vs_params[num_vs_params++] = LLVMGetUndef(LLVMTypeOf(LLVMGetParam(vs, 0))); /* RW_BUFFERS */
|
vs_params[num_vs_params++] = LLVMGetUndef(LLVMTypeOf(LLVMGetParam(vs, 0))); /* RW_BUFFERS */
|
||||||
vs_params[num_vs_params++] = LLVMGetUndef(LLVMTypeOf(LLVMGetParam(vs, 1))); /* BINDLESS */
|
vs_params[num_vs_params++] = LLVMGetUndef(LLVMTypeOf(LLVMGetParam(vs, 1))); /* BINDLESS */
|
||||||
vs_params[num_vs_params++] = const_desc;
|
vs_params[num_vs_params++] = ac_get_arg(&ctx->ac, param_const_desc);
|
||||||
vs_params[num_vs_params++] = sampler_desc;
|
vs_params[num_vs_params++] = ac_get_arg(&ctx->ac, param_sampler_desc);
|
||||||
vs_params[num_vs_params++] = LLVMConstInt(ctx->i32,
|
vs_params[num_vs_params++] = LLVMConstInt(ctx->i32,
|
||||||
S_VS_STATE_INDEXED(key->opt.cs_indexed), 0);
|
S_VS_STATE_INDEXED(key->opt.cs_indexed), 0);
|
||||||
vs_params[num_vs_params++] = base_vertex;
|
vs_params[num_vs_params++] = ac_get_arg(&ctx->ac, param_base_vertex);
|
||||||
vs_params[num_vs_params++] = start_instance;
|
vs_params[num_vs_params++] = ac_get_arg(&ctx->ac, param_start_instance);
|
||||||
vs_params[num_vs_params++] = ctx->i32_0; /* DrawID */
|
vs_params[num_vs_params++] = ctx->i32_0; /* DrawID */
|
||||||
vs_params[num_vs_params++] = vb_desc;
|
vs_params[num_vs_params++] = ac_get_arg(&ctx->ac, param_vb_desc);
|
||||||
|
|
||||||
vs_params[(param_vertex_id = num_vs_params++)] = NULL; /* VertexID */
|
vs_params[(param_vertex_id = num_vs_params++)] = NULL; /* VertexID */
|
||||||
vs_params[(param_instance_id = num_vs_params++)] = NULL; /* InstanceID */
|
vs_params[(param_instance_id = num_vs_params++)] = NULL; /* InstanceID */
|
||||||
@@ -396,6 +397,7 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
/* Load descriptors. (load 8 dwords at once) */
|
/* Load descriptors. (load 8 dwords at once) */
|
||||||
LLVMValueRef input_indexbuf, output_indexbuf, tmp, desc[8];
|
LLVMValueRef input_indexbuf, output_indexbuf, tmp, desc[8];
|
||||||
|
|
||||||
|
LLVMValueRef index_buffers_and_constants = ac_get_arg(&ctx->ac, param_index_buffers_and_constants);
|
||||||
tmp = LLVMBuildPointerCast(builder, index_buffers_and_constants,
|
tmp = LLVMBuildPointerCast(builder, index_buffers_and_constants,
|
||||||
ac_array_in_const32_addr_space(ctx->v8i32), "");
|
ac_array_in_const32_addr_space(ctx->v8i32), "");
|
||||||
tmp = ac_build_load_to_sgpr(&ctx->ac, tmp, ctx->i32_0);
|
tmp = ac_build_load_to_sgpr(&ctx->ac, tmp, ctx->i32_0);
|
||||||
@@ -408,12 +410,17 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
|
|
||||||
/* Compute PrimID and InstanceID. */
|
/* Compute PrimID and InstanceID. */
|
||||||
LLVMValueRef global_thread_id =
|
LLVMValueRef global_thread_id =
|
||||||
ac_build_imad(&ctx->ac, block_id,
|
ac_build_imad(&ctx->ac, ac_get_arg(&ctx->ac, param_block_id),
|
||||||
LLVMConstInt(ctx->i32, THREADGROUP_SIZE, 0), local_id);
|
LLVMConstInt(ctx->i32, THREADGROUP_SIZE, 0),
|
||||||
|
ac_get_arg(&ctx->ac, param_local_id));
|
||||||
LLVMValueRef prim_id = global_thread_id; /* PrimID within an instance */
|
LLVMValueRef prim_id = global_thread_id; /* PrimID within an instance */
|
||||||
LLVMValueRef instance_id = ctx->i32_0;
|
LLVMValueRef instance_id = ctx->i32_0;
|
||||||
|
|
||||||
if (key->opt.cs_instancing) {
|
if (key->opt.cs_instancing) {
|
||||||
|
LLVMValueRef num_prims_udiv_terms =
|
||||||
|
ac_get_arg(&ctx->ac, param_num_prims_udiv_terms);
|
||||||
|
LLVMValueRef num_prims_udiv_multiplier =
|
||||||
|
ac_get_arg(&ctx->ac, param_num_prims_udiv_multiplier);
|
||||||
/* Unpack num_prims_udiv_terms. */
|
/* Unpack num_prims_udiv_terms. */
|
||||||
LLVMValueRef post_shift = LLVMBuildAnd(builder, num_prims_udiv_terms,
|
LLVMValueRef post_shift = LLVMBuildAnd(builder, num_prims_udiv_terms,
|
||||||
LLVMConstInt(ctx->i32, 0x1f, 0), "");
|
LLVMConstInt(ctx->i32, 0x1f, 0), "");
|
||||||
@@ -477,6 +484,8 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLVMValueRef ordered_wave_id = ac_get_arg(&ctx->ac, param_ordered_wave_id);
|
||||||
|
|
||||||
/* Extract the ordered wave ID. */
|
/* Extract the ordered wave ID. */
|
||||||
if (VERTEX_COUNTER_GDS_MODE == 2) {
|
if (VERTEX_COUNTER_GDS_MODE == 2) {
|
||||||
ordered_wave_id = LLVMBuildLShr(builder, ordered_wave_id,
|
ordered_wave_id = LLVMBuildLShr(builder, ordered_wave_id,
|
||||||
@@ -485,7 +494,8 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
LLVMConstInt(ctx->i32, 0xfff, 0), "");
|
LLVMConstInt(ctx->i32, 0xfff, 0), "");
|
||||||
}
|
}
|
||||||
LLVMValueRef thread_id =
|
LLVMValueRef thread_id =
|
||||||
LLVMBuildAnd(builder, local_id, LLVMConstInt(ctx->i32, 63, 0), "");
|
LLVMBuildAnd(builder, ac_get_arg(&ctx->ac, param_local_id),
|
||||||
|
LLVMConstInt(ctx->i32, 63, 0), "");
|
||||||
|
|
||||||
/* Every other triangle in a strip has a reversed vertex order, so we
|
/* Every other triangle in a strip has a reversed vertex order, so we
|
||||||
* need to swap vertices of odd primitives to get the correct primitive
|
* need to swap vertices of odd primitives to get the correct primitive
|
||||||
@@ -493,6 +503,7 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
* restart complicates it, because a strip can start anywhere.
|
* restart complicates it, because a strip can start anywhere.
|
||||||
*/
|
*/
|
||||||
LLVMValueRef prim_restart_accepted = ctx->i1true;
|
LLVMValueRef prim_restart_accepted = ctx->i1true;
|
||||||
|
LLVMValueRef vertex_counter = ac_get_arg(&ctx->ac, param_vertex_counter);
|
||||||
|
|
||||||
if (key->opt.cs_prim_type == PIPE_PRIM_TRIANGLE_STRIP) {
|
if (key->opt.cs_prim_type == PIPE_PRIM_TRIANGLE_STRIP) {
|
||||||
/* Without primitive restart, odd primitives have reversed orientation.
|
/* Without primitive restart, odd primitives have reversed orientation.
|
||||||
@@ -520,7 +531,8 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
|
|
||||||
for (unsigned i = 0; i < 3; i++) {
|
for (unsigned i = 0; i < 3; i++) {
|
||||||
LLVMValueRef not_reset = LLVMBuildICmp(builder, LLVMIntNE, index[i],
|
LLVMValueRef not_reset = LLVMBuildICmp(builder, LLVMIntNE, index[i],
|
||||||
restart_index, "");
|
ac_get_arg(&ctx->ac, param_restart_index),
|
||||||
|
"");
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
index0_is_reset = LLVMBuildNot(builder, not_reset, "");
|
index0_is_reset = LLVMBuildNot(builder, not_reset, "");
|
||||||
prim_restart_accepted = LLVMBuildAnd(builder, prim_restart_accepted,
|
prim_restart_accepted = LLVMBuildAnd(builder, prim_restart_accepted,
|
||||||
@@ -680,6 +692,7 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
LLVMValueRef vp = ac_build_load_invariant(&ctx->ac, index_buffers_and_constants,
|
LLVMValueRef vp = ac_build_load_invariant(&ctx->ac, index_buffers_and_constants,
|
||||||
LLVMConstInt(ctx->i32, 2, 0));
|
LLVMConstInt(ctx->i32, 2, 0));
|
||||||
vp = LLVMBuildBitCast(builder, vp, ctx->v4f32, "");
|
vp = LLVMBuildBitCast(builder, vp, ctx->v4f32, "");
|
||||||
|
LLVMValueRef vp_scale[2], vp_translate[2];
|
||||||
vp_scale[0] = ac_llvm_extract_elem(&ctx->ac, vp, 0);
|
vp_scale[0] = ac_llvm_extract_elem(&ctx->ac, vp, 0);
|
||||||
vp_scale[1] = ac_llvm_extract_elem(&ctx->ac, vp, 1);
|
vp_scale[1] = ac_llvm_extract_elem(&ctx->ac, vp, 1);
|
||||||
vp_translate[0] = ac_llvm_extract_elem(&ctx->ac, vp, 2);
|
vp_translate[0] = ac_llvm_extract_elem(&ctx->ac, vp, 2);
|
||||||
@@ -699,7 +712,8 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
|
|
||||||
LLVMValueRef accepted =
|
LLVMValueRef accepted =
|
||||||
ac_cull_triangle(&ctx->ac, pos, prim_restart_accepted,
|
ac_cull_triangle(&ctx->ac, pos, prim_restart_accepted,
|
||||||
vp_scale, vp_translate, smallprim_precision,
|
vp_scale, vp_translate,
|
||||||
|
ac_get_arg(&ctx->ac, param_smallprim_precision),
|
||||||
&options);
|
&options);
|
||||||
|
|
||||||
LLVMValueRef accepted_threadmask = ac_get_i1_sgpr_mask(&ctx->ac, accepted);
|
LLVMValueRef accepted_threadmask = ac_get_i1_sgpr_mask(&ctx->ac, accepted);
|
||||||
@@ -788,7 +802,8 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
if (VERTEX_COUNTER_GDS_MODE == 2) {
|
if (VERTEX_COUNTER_GDS_MODE == 2) {
|
||||||
ac_build_ifcc(&ctx->ac,
|
ac_build_ifcc(&ctx->ac,
|
||||||
LLVMBuildICmp(builder, LLVMIntEQ, global_thread_id,
|
LLVMBuildICmp(builder, LLVMIntEQ, global_thread_id,
|
||||||
last_wave_prim_id, ""), 12606);
|
ac_get_arg(&ctx->ac, param_last_wave_prim_id), ""),
|
||||||
|
12606);
|
||||||
LLVMValueRef count = LLVMBuildAdd(builder, start, num_prims_accepted, "");
|
LLVMValueRef count = LLVMBuildAdd(builder, start, num_prims_accepted, "");
|
||||||
count = LLVMBuildMul(builder, count,
|
count = LLVMBuildMul(builder, count,
|
||||||
LLVMConstInt(ctx->i32, vertices_per_prim, 0), "");
|
LLVMConstInt(ctx->i32, vertices_per_prim, 0), "");
|
||||||
@@ -798,7 +813,7 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
*/
|
*/
|
||||||
if (ctx->screen->info.chip_class <= GFX8) {
|
if (ctx->screen->info.chip_class <= GFX8) {
|
||||||
LLVMValueRef desc[] = {
|
LLVMValueRef desc[] = {
|
||||||
vertex_count_addr,
|
ac_get_arg(&ctx->ac, param_vertex_count_addr),
|
||||||
LLVMConstInt(ctx->i32,
|
LLVMConstInt(ctx->i32,
|
||||||
S_008F04_BASE_ADDRESS_HI(ctx->screen->info.address32_hi), 0),
|
S_008F04_BASE_ADDRESS_HI(ctx->screen->info.address32_hi), 0),
|
||||||
LLVMConstInt(ctx->i32, 4, 0),
|
LLVMConstInt(ctx->i32, 4, 0),
|
||||||
@@ -810,7 +825,9 @@ void si_build_prim_discard_compute_shader(struct si_shader_context *ctx)
|
|||||||
ctx->i32_0, 0, ac_glc | ac_slc, false);
|
ctx->i32_0, 0, ac_glc | ac_slc, false);
|
||||||
} else {
|
} else {
|
||||||
LLVMBuildStore(builder, count,
|
LLVMBuildStore(builder, count,
|
||||||
si_expand_32bit_pointer(ctx, vertex_count_addr));
|
si_expand_32bit_pointer(ctx,
|
||||||
|
ac_get_arg(&ctx->ac,
|
||||||
|
param_vertex_count_addr)));
|
||||||
}
|
}
|
||||||
ac_build_endif(&ctx->ac, 12606);
|
ac_build_endif(&ctx->ac, 12606);
|
||||||
} else {
|
} else {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -44,22 +44,6 @@ struct pipe_debug_callback;
|
|||||||
#define RADEON_LLVM_MAX_SYSTEM_VALUES 11
|
#define RADEON_LLVM_MAX_SYSTEM_VALUES 11
|
||||||
#define RADEON_LLVM_MAX_ADDRS 16
|
#define RADEON_LLVM_MAX_ADDRS 16
|
||||||
|
|
||||||
enum si_arg_regfile {
|
|
||||||
ARG_SGPR,
|
|
||||||
ARG_VGPR
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to collect types and other info about arguments of the LLVM function
|
|
||||||
* before the function is created.
|
|
||||||
*/
|
|
||||||
struct si_function_info {
|
|
||||||
LLVMTypeRef types[100];
|
|
||||||
LLVMValueRef *assign[100];
|
|
||||||
unsigned num_sgpr_params;
|
|
||||||
unsigned num_params;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct si_shader_output_values {
|
struct si_shader_output_values {
|
||||||
LLVMValueRef values[4];
|
LLVMValueRef values[4];
|
||||||
unsigned semantic_name;
|
unsigned semantic_name;
|
||||||
@@ -82,6 +66,7 @@ struct si_shader_context {
|
|||||||
unsigned num_images;
|
unsigned num_images;
|
||||||
unsigned num_samplers;
|
unsigned num_samplers;
|
||||||
|
|
||||||
|
struct ac_shader_args args;
|
||||||
struct ac_shader_abi abi;
|
struct ac_shader_abi abi;
|
||||||
|
|
||||||
/** This function is responsible for initilizing the inputs array and will be
|
/** This function is responsible for initilizing the inputs array and will be
|
||||||
@@ -123,19 +108,26 @@ struct si_shader_context {
|
|||||||
LLVMValueRef main_fn;
|
LLVMValueRef main_fn;
|
||||||
LLVMTypeRef return_type;
|
LLVMTypeRef return_type;
|
||||||
|
|
||||||
/* Parameter indices for LLVMGetParam. */
|
struct ac_arg const_and_shader_buffers;
|
||||||
int param_rw_buffers;
|
struct ac_arg samplers_and_images;
|
||||||
int param_const_and_shader_buffers;
|
|
||||||
int param_samplers_and_images;
|
/* For merged shaders, the per-stage descriptors for the stage other
|
||||||
int param_bindless_samplers_and_images;
|
* than the one we're processing, used to pass them through from the
|
||||||
|
* first stage to the second.
|
||||||
|
*/
|
||||||
|
struct ac_arg other_const_and_shader_buffers;
|
||||||
|
struct ac_arg other_samplers_and_images;
|
||||||
|
|
||||||
|
struct ac_arg rw_buffers;
|
||||||
|
struct ac_arg bindless_samplers_and_images;
|
||||||
/* Common inputs for merged shaders. */
|
/* Common inputs for merged shaders. */
|
||||||
int param_merged_wave_info;
|
struct ac_arg merged_wave_info;
|
||||||
int param_merged_scratch_offset;
|
struct ac_arg merged_scratch_offset;
|
||||||
/* API VS */
|
/* API VS */
|
||||||
int param_vertex_buffers;
|
struct ac_arg vertex_buffers;
|
||||||
int param_rel_auto_id;
|
struct ac_arg rel_auto_id;
|
||||||
int param_vs_prim_id;
|
struct ac_arg vs_prim_id;
|
||||||
int param_vertex_index0;
|
struct ac_arg vertex_index0;
|
||||||
/* VS states and layout of LS outputs / TCS inputs at the end
|
/* VS states and layout of LS outputs / TCS inputs at the end
|
||||||
* [0] = clamp vertex color
|
* [0] = clamp vertex color
|
||||||
* [1] = indexed
|
* [1] = indexed
|
||||||
@@ -144,12 +136,12 @@ struct si_shader_context {
|
|||||||
* [24:31] = stride between vertices in DW = num_inputs * 4
|
* [24:31] = stride between vertices in DW = num_inputs * 4
|
||||||
* max = 32*4
|
* max = 32*4
|
||||||
*/
|
*/
|
||||||
int param_vs_state_bits;
|
struct ac_arg vs_state_bits;
|
||||||
int param_vs_blit_inputs;
|
struct ac_arg vs_blit_inputs;
|
||||||
/* HW VS */
|
/* HW VS */
|
||||||
int param_streamout_config;
|
struct ac_arg streamout_config;
|
||||||
int param_streamout_write_index;
|
struct ac_arg streamout_write_index;
|
||||||
int param_streamout_offset[4];
|
struct ac_arg streamout_offset[4];
|
||||||
|
|
||||||
/* API TCS & TES */
|
/* API TCS & TES */
|
||||||
/* Layout of TCS outputs in the offchip buffer
|
/* Layout of TCS outputs in the offchip buffer
|
||||||
@@ -161,7 +153,7 @@ struct si_shader_context {
|
|||||||
* [12:31] = the offset of per patch attributes in the buffer in bytes.
|
* [12:31] = the offset of per patch attributes in the buffer in bytes.
|
||||||
* max = NUM_PATCHES*32*32*16
|
* max = NUM_PATCHES*32*32*16
|
||||||
*/
|
*/
|
||||||
int param_tcs_offchip_layout;
|
struct ac_arg tcs_offchip_layout;
|
||||||
|
|
||||||
/* API TCS */
|
/* API TCS */
|
||||||
/* Offsets where TCS outputs and TCS patch outputs live in LDS:
|
/* Offsets where TCS outputs and TCS patch outputs live in LDS:
|
||||||
@@ -169,41 +161,43 @@ struct si_shader_context {
|
|||||||
* [16:31] = TCS output patch0 offset for per-patch / 16
|
* [16:31] = TCS output patch0 offset for per-patch / 16
|
||||||
* max = (NUM_PATCHES + 1) * 32*32
|
* max = (NUM_PATCHES + 1) * 32*32
|
||||||
*/
|
*/
|
||||||
int param_tcs_out_lds_offsets;
|
struct ac_arg tcs_out_lds_offsets;
|
||||||
/* Layout of TCS outputs / TES inputs:
|
/* Layout of TCS outputs / TES inputs:
|
||||||
* [0:12] = stride between output patches in DW, num_outputs * num_vertices * 4
|
* [0:12] = stride between output patches in DW, num_outputs * num_vertices * 4
|
||||||
* max = 32*32*4 + 32*4
|
* max = 32*32*4 + 32*4
|
||||||
* [13:18] = gl_PatchVerticesIn, max = 32
|
* [13:18] = gl_PatchVerticesIn, max = 32
|
||||||
* [19:31] = high 13 bits of the 32-bit address of tessellation ring buffers
|
* [19:31] = high 13 bits of the 32-bit address of tessellation ring buffers
|
||||||
*/
|
*/
|
||||||
int param_tcs_out_lds_layout;
|
struct ac_arg tcs_out_lds_layout;
|
||||||
int param_tcs_offchip_offset;
|
struct ac_arg tcs_offchip_offset;
|
||||||
int param_tcs_factor_offset;
|
struct ac_arg tcs_factor_offset;
|
||||||
|
|
||||||
/* API TES */
|
/* API TES */
|
||||||
int param_tes_offchip_addr;
|
struct ac_arg tes_offchip_addr;
|
||||||
int param_tes_u;
|
struct ac_arg tes_u;
|
||||||
int param_tes_v;
|
struct ac_arg tes_v;
|
||||||
int param_tes_rel_patch_id;
|
struct ac_arg tes_rel_patch_id;
|
||||||
/* HW ES */
|
/* HW ES */
|
||||||
int param_es2gs_offset;
|
struct ac_arg es2gs_offset;
|
||||||
/* HW GS */
|
/* HW GS */
|
||||||
/* On gfx10:
|
/* On gfx10:
|
||||||
* - bits 0..10: ordered_wave_id
|
* - bits 0..10: ordered_wave_id
|
||||||
* - bits 12..20: number of vertices in group
|
* - bits 12..20: number of vertices in group
|
||||||
* - bits 22..30: number of primitives in group
|
* - bits 22..30: number of primitives in group
|
||||||
*/
|
*/
|
||||||
LLVMValueRef gs_tg_info;
|
struct ac_arg gs_tg_info;
|
||||||
/* API GS */
|
/* API GS */
|
||||||
int param_gs2vs_offset;
|
struct ac_arg gs2vs_offset;
|
||||||
int param_gs_wave_id; /* GFX6 */
|
struct ac_arg gs_wave_id; /* GFX6 */
|
||||||
LLVMValueRef gs_vtx_offset[6]; /* in dwords (GFX6) */
|
struct ac_arg gs_vtx_offset[6]; /* in dwords (GFX6) */
|
||||||
int param_gs_vtx01_offset; /* in dwords (GFX9) */
|
struct ac_arg gs_vtx01_offset; /* in dwords (GFX9) */
|
||||||
int param_gs_vtx23_offset; /* in dwords (GFX9) */
|
struct ac_arg gs_vtx23_offset; /* in dwords (GFX9) */
|
||||||
int param_gs_vtx45_offset; /* in dwords (GFX9) */
|
struct ac_arg gs_vtx45_offset; /* in dwords (GFX9) */
|
||||||
|
/* PS */
|
||||||
|
struct ac_arg pos_fixed_pt;
|
||||||
/* CS */
|
/* CS */
|
||||||
int param_block_size;
|
struct ac_arg block_size;
|
||||||
int param_cs_user_data;
|
struct ac_arg cs_user_data;
|
||||||
|
|
||||||
struct ac_llvm_compiler *compiler;
|
struct ac_llvm_compiler *compiler;
|
||||||
|
|
||||||
@@ -252,14 +246,9 @@ si_shader_context_from_abi(struct ac_shader_abi *abi)
|
|||||||
return container_of(abi, ctx, abi);
|
return container_of(abi, ctx, abi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void si_init_function_info(struct si_function_info *fninfo);
|
|
||||||
unsigned add_arg_assign(struct si_function_info *fninfo,
|
|
||||||
enum si_arg_regfile regfile, LLVMTypeRef type,
|
|
||||||
LLVMValueRef *assign);
|
|
||||||
void si_create_function(struct si_shader_context *ctx,
|
void si_create_function(struct si_shader_context *ctx,
|
||||||
const char *name,
|
const char *name,
|
||||||
LLVMTypeRef *returns, unsigned num_returns,
|
LLVMTypeRef *returns, unsigned num_returns,
|
||||||
struct si_function_info *fninfo,
|
|
||||||
unsigned max_workgroup_size);
|
unsigned max_workgroup_size);
|
||||||
unsigned si_llvm_compile(LLVMModuleRef M, struct si_shader_binary *binary,
|
unsigned si_llvm_compile(LLVMModuleRef M, struct si_shader_binary *binary,
|
||||||
struct ac_llvm_compiler *compiler,
|
struct ac_llvm_compiler *compiler,
|
||||||
@@ -287,8 +276,7 @@ void si_llvm_context_set_ir(struct si_shader_context *ctx,
|
|||||||
|
|
||||||
void si_llvm_create_func(struct si_shader_context *ctx,
|
void si_llvm_create_func(struct si_shader_context *ctx,
|
||||||
const char *name,
|
const char *name,
|
||||||
LLVMTypeRef *return_types, unsigned num_return_elems,
|
LLVMTypeRef *return_types, unsigned num_return_elems);
|
||||||
LLVMTypeRef *ParamTypes, unsigned ParamCount);
|
|
||||||
|
|
||||||
void si_llvm_dispose(struct si_shader_context *ctx);
|
void si_llvm_dispose(struct si_shader_context *ctx);
|
||||||
|
|
||||||
@@ -385,7 +373,7 @@ void si_llvm_load_input_fs(
|
|||||||
bool si_nir_build_llvm(struct si_shader_context *ctx, struct nir_shader *nir);
|
bool si_nir_build_llvm(struct si_shader_context *ctx, struct nir_shader *nir);
|
||||||
|
|
||||||
LLVMValueRef si_unpack_param(struct si_shader_context *ctx,
|
LLVMValueRef si_unpack_param(struct si_shader_context *ctx,
|
||||||
unsigned param, unsigned rshift,
|
struct ac_arg param, unsigned rshift,
|
||||||
unsigned bitwidth);
|
unsigned bitwidth);
|
||||||
|
|
||||||
void gfx10_emit_ngg_epilogue(struct ac_shader_abi *abi,
|
void gfx10_emit_ngg_epilogue(struct ac_shader_abi *abi,
|
||||||
|
@@ -1047,19 +1047,19 @@ si_nir_lookup_interp_param(struct ac_shader_abi *abi,
|
|||||||
case INTERP_MODE_SMOOTH:
|
case INTERP_MODE_SMOOTH:
|
||||||
case INTERP_MODE_NONE:
|
case INTERP_MODE_NONE:
|
||||||
if (location == INTERP_CENTER)
|
if (location == INTERP_CENTER)
|
||||||
return ctx->abi.persp_center;
|
return ac_get_arg(&ctx->ac, ctx->args.persp_center);
|
||||||
else if (location == INTERP_CENTROID)
|
else if (location == INTERP_CENTROID)
|
||||||
return ctx->abi.persp_centroid;
|
return ctx->abi.persp_centroid;
|
||||||
else if (location == INTERP_SAMPLE)
|
else if (location == INTERP_SAMPLE)
|
||||||
return ctx->abi.persp_sample;
|
return ac_get_arg(&ctx->ac, ctx->args.persp_sample);
|
||||||
break;
|
break;
|
||||||
case INTERP_MODE_NOPERSPECTIVE:
|
case INTERP_MODE_NOPERSPECTIVE:
|
||||||
if (location == INTERP_CENTER)
|
if (location == INTERP_CENTER)
|
||||||
return ctx->abi.linear_center;
|
return ac_get_arg(&ctx->ac, ctx->args.linear_center);
|
||||||
else if (location == INTERP_CENTROID)
|
else if (location == INTERP_CENTROID)
|
||||||
return ctx->abi.linear_centroid;
|
return ac_get_arg(&ctx->ac, ctx->args.linear_centroid);
|
||||||
else if (location == INTERP_SAMPLE)
|
else if (location == INTERP_SAMPLE)
|
||||||
return ctx->abi.linear_sample;
|
return ac_get_arg(&ctx->ac, ctx->args.linear_sample);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(!"Unhandled interpolation mode.");
|
assert(!"Unhandled interpolation mode.");
|
||||||
@@ -1082,8 +1082,7 @@ si_nir_load_sampler_desc(struct ac_shader_abi *abi,
|
|||||||
assert(desc_type <= AC_DESC_BUFFER);
|
assert(desc_type <= AC_DESC_BUFFER);
|
||||||
|
|
||||||
if (bindless) {
|
if (bindless) {
|
||||||
LLVMValueRef list =
|
LLVMValueRef list = ac_get_arg(&ctx->ac, ctx->bindless_samplers_and_images);
|
||||||
LLVMGetParam(ctx->main_fn, ctx->param_bindless_samplers_and_images);
|
|
||||||
|
|
||||||
/* dynamic_index is the bindless handle */
|
/* dynamic_index is the bindless handle */
|
||||||
if (image) {
|
if (image) {
|
||||||
@@ -1114,7 +1113,7 @@ si_nir_load_sampler_desc(struct ac_shader_abi *abi,
|
|||||||
unsigned num_slots = image ? ctx->num_images : ctx->num_samplers;
|
unsigned num_slots = image ? ctx->num_images : ctx->num_samplers;
|
||||||
assert(const_index < num_slots || dynamic_index);
|
assert(const_index < num_slots || dynamic_index);
|
||||||
|
|
||||||
LLVMValueRef list = LLVMGetParam(ctx->main_fn, ctx->param_samplers_and_images);
|
LLVMValueRef list = ac_get_arg(&ctx->ac, ctx->samplers_and_images);
|
||||||
LLVMValueRef index = LLVMConstInt(ctx->ac.i32, const_index, false);
|
LLVMValueRef index = LLVMConstInt(ctx->ac.i32, const_index, false);
|
||||||
|
|
||||||
if (dynamic_index) {
|
if (dynamic_index) {
|
||||||
@@ -1230,7 +1229,7 @@ bool si_nir_build_llvm(struct si_shader_context *ctx, struct nir_shader *nir)
|
|||||||
ctx->shader->key.mono.u.ps.interpolate_at_sample_force_center;
|
ctx->shader->key.mono.u.ps.interpolate_at_sample_force_center;
|
||||||
} else if (nir->info.stage == MESA_SHADER_COMPUTE) {
|
} else if (nir->info.stage == MESA_SHADER_COMPUTE) {
|
||||||
if (nir->info.cs.user_data_components_amd) {
|
if (nir->info.cs.user_data_components_amd) {
|
||||||
ctx->abi.user_data = LLVMGetParam(ctx->main_fn, ctx->param_cs_user_data);
|
ctx->abi.user_data = ac_get_arg(&ctx->ac, ctx->cs_user_data);
|
||||||
ctx->abi.user_data = ac_build_expand_to_vec4(&ctx->ac, ctx->abi.user_data,
|
ctx->abi.user_data = ac_build_expand_to_vec4(&ctx->ac, ctx->abi.user_data,
|
||||||
nir->info.cs.user_data_components_amd);
|
nir->info.cs.user_data_components_amd);
|
||||||
}
|
}
|
||||||
@@ -1248,7 +1247,7 @@ bool si_nir_build_llvm(struct si_shader_context *ctx, struct nir_shader *nir)
|
|||||||
assert(gl_shader_stage_is_compute(nir->info.stage));
|
assert(gl_shader_stage_is_compute(nir->info.stage));
|
||||||
si_declare_compute_memory(ctx);
|
si_declare_compute_memory(ctx);
|
||||||
}
|
}
|
||||||
ac_nir_translate(&ctx->ac, &ctx->abi, nir);
|
ac_nir_translate(&ctx->ac, &ctx->abi, &ctx->args, nir);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -224,8 +224,8 @@ image_fetch_rsrc(
|
|||||||
/* Bindless descriptors are accessible from a different pair of
|
/* Bindless descriptors are accessible from a different pair of
|
||||||
* user SGPR indices.
|
* user SGPR indices.
|
||||||
*/
|
*/
|
||||||
rsrc_ptr = LLVMGetParam(ctx->main_fn,
|
rsrc_ptr = ac_get_arg(&ctx->ac,
|
||||||
ctx->param_bindless_samplers_and_images);
|
ctx->bindless_samplers_and_images);
|
||||||
index = lp_build_emit_fetch_src(bld_base, image, TGSI_TYPE_UNSIGNED, 0);
|
index = lp_build_emit_fetch_src(bld_base, image, TGSI_TYPE_UNSIGNED, 0);
|
||||||
|
|
||||||
/* Bindless image descriptors use 16-dword slots. */
|
/* Bindless image descriptors use 16-dword slots. */
|
||||||
@@ -235,7 +235,7 @@ image_fetch_rsrc(
|
|||||||
if (fmask)
|
if (fmask)
|
||||||
index = LLVMBuildAdd(ctx->ac.builder, index, ctx->i32_1, "");
|
index = LLVMBuildAdd(ctx->ac.builder, index, ctx->i32_1, "");
|
||||||
} else {
|
} else {
|
||||||
rsrc_ptr = LLVMGetParam(ctx->main_fn, ctx->param_samplers_and_images);
|
rsrc_ptr = ac_get_arg(&ctx->ac, ctx->samplers_and_images);
|
||||||
|
|
||||||
if (!image->Register.Indirect) {
|
if (!image->Register.Indirect) {
|
||||||
index = LLVMConstInt(ctx->i32, image->Register.Index, 0);
|
index = LLVMConstInt(ctx->i32, image->Register.Index, 0);
|
||||||
@@ -1126,7 +1126,7 @@ static void tex_fetch_ptrs(struct lp_build_tgsi_context *bld_base,
|
|||||||
LLVMValueRef *fmask_ptr)
|
LLVMValueRef *fmask_ptr)
|
||||||
{
|
{
|
||||||
struct si_shader_context *ctx = si_shader_context(bld_base);
|
struct si_shader_context *ctx = si_shader_context(bld_base);
|
||||||
LLVMValueRef list = LLVMGetParam(ctx->main_fn, ctx->param_samplers_and_images);
|
LLVMValueRef list = ac_get_arg(&ctx->ac, ctx->samplers_and_images);
|
||||||
const struct tgsi_full_instruction *inst = emit_data->inst;
|
const struct tgsi_full_instruction *inst = emit_data->inst;
|
||||||
const struct tgsi_full_src_register *reg;
|
const struct tgsi_full_src_register *reg;
|
||||||
unsigned target = inst->Texture.Texture;
|
unsigned target = inst->Texture.Texture;
|
||||||
@@ -1152,8 +1152,7 @@ static void tex_fetch_ptrs(struct lp_build_tgsi_context *bld_base,
|
|||||||
/* Bindless descriptors are accessible from a different pair of
|
/* Bindless descriptors are accessible from a different pair of
|
||||||
* user SGPR indices.
|
* user SGPR indices.
|
||||||
*/
|
*/
|
||||||
list = LLVMGetParam(ctx->main_fn,
|
list = ac_get_arg(&ctx->ac, ctx->bindless_samplers_and_images);
|
||||||
ctx->param_bindless_samplers_and_images);
|
|
||||||
index = lp_build_emit_fetch_src(bld_base, reg,
|
index = lp_build_emit_fetch_src(bld_base, reg,
|
||||||
TGSI_TYPE_UNSIGNED, 0);
|
TGSI_TYPE_UNSIGNED, 0);
|
||||||
|
|
||||||
@@ -1735,7 +1734,7 @@ static LLVMValueRef si_llvm_emit_fbfetch(struct si_shader_context *ctx)
|
|||||||
|
|
||||||
/* Load the image descriptor. */
|
/* Load the image descriptor. */
|
||||||
STATIC_ASSERT(SI_PS_IMAGE_COLORBUF0 % 2 == 0);
|
STATIC_ASSERT(SI_PS_IMAGE_COLORBUF0 % 2 == 0);
|
||||||
ptr = LLVMGetParam(ctx->main_fn, ctx->param_rw_buffers);
|
ptr = ac_get_arg(&ctx->ac, ctx->rw_buffers);
|
||||||
ptr = LLVMBuildPointerCast(ctx->ac.builder, ptr,
|
ptr = LLVMBuildPointerCast(ctx->ac.builder, ptr,
|
||||||
ac_array_in_const32_addr_space(ctx->v8i32), "");
|
ac_array_in_const32_addr_space(ctx->v8i32), "");
|
||||||
image = ac_build_load_to_sgpr(&ctx->ac, ptr,
|
image = ac_build_load_to_sgpr(&ctx->ac, ptr,
|
||||||
@@ -1743,14 +1742,14 @@ static LLVMValueRef si_llvm_emit_fbfetch(struct si_shader_context *ctx)
|
|||||||
|
|
||||||
unsigned chan = 0;
|
unsigned chan = 0;
|
||||||
|
|
||||||
args.coords[chan++] = si_unpack_param(ctx, SI_PARAM_POS_FIXED_PT, 0, 16);
|
args.coords[chan++] = si_unpack_param(ctx, ctx->pos_fixed_pt, 0, 16);
|
||||||
|
|
||||||
if (!ctx->shader->key.mono.u.ps.fbfetch_is_1D)
|
if (!ctx->shader->key.mono.u.ps.fbfetch_is_1D)
|
||||||
args.coords[chan++] = si_unpack_param(ctx, SI_PARAM_POS_FIXED_PT, 16, 16);
|
args.coords[chan++] = si_unpack_param(ctx, ctx->pos_fixed_pt, 16, 16);
|
||||||
|
|
||||||
/* Get the current render target layer index. */
|
/* Get the current render target layer index. */
|
||||||
if (ctx->shader->key.mono.u.ps.fbfetch_layered)
|
if (ctx->shader->key.mono.u.ps.fbfetch_layered)
|
||||||
args.coords[chan++] = si_unpack_param(ctx, SI_PARAM_ANCILLARY, 16, 11);
|
args.coords[chan++] = si_unpack_param(ctx, ctx->args.ancillary, 16, 11);
|
||||||
|
|
||||||
if (ctx->shader->key.mono.u.ps.fbfetch_msaa)
|
if (ctx->shader->key.mono.u.ps.fbfetch_msaa)
|
||||||
args.coords[chan++] = si_get_sample_id(ctx);
|
args.coords[chan++] = si_get_sample_id(ctx);
|
||||||
|
@@ -27,14 +27,6 @@
|
|||||||
#include "ac_llvm_util.h"
|
#include "ac_llvm_util.h"
|
||||||
#include "util/u_memory.h"
|
#include "util/u_memory.h"
|
||||||
|
|
||||||
enum si_llvm_calling_convention {
|
|
||||||
RADEON_LLVM_AMDGPU_VS = 87,
|
|
||||||
RADEON_LLVM_AMDGPU_GS = 88,
|
|
||||||
RADEON_LLVM_AMDGPU_PS = 89,
|
|
||||||
RADEON_LLVM_AMDGPU_CS = 90,
|
|
||||||
RADEON_LLVM_AMDGPU_HS = 93,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct si_llvm_diagnostics {
|
struct si_llvm_diagnostics {
|
||||||
struct pipe_debug_callback *debug;
|
struct pipe_debug_callback *debug;
|
||||||
unsigned retval;
|
unsigned retval;
|
||||||
@@ -1091,12 +1083,10 @@ void si_llvm_context_set_ir(struct si_shader_context *ctx,
|
|||||||
|
|
||||||
void si_llvm_create_func(struct si_shader_context *ctx,
|
void si_llvm_create_func(struct si_shader_context *ctx,
|
||||||
const char *name,
|
const char *name,
|
||||||
LLVMTypeRef *return_types, unsigned num_return_elems,
|
LLVMTypeRef *return_types, unsigned num_return_elems)
|
||||||
LLVMTypeRef *ParamTypes, unsigned ParamCount)
|
|
||||||
{
|
{
|
||||||
LLVMTypeRef main_fn_type, ret_type;
|
LLVMTypeRef ret_type;
|
||||||
LLVMBasicBlockRef main_fn_body;
|
enum ac_llvm_calling_convention call_conv;
|
||||||
enum si_llvm_calling_convention call_conv;
|
|
||||||
enum pipe_shader_type real_shader_type;
|
enum pipe_shader_type real_shader_type;
|
||||||
|
|
||||||
if (num_return_elems)
|
if (num_return_elems)
|
||||||
@@ -1106,14 +1096,6 @@ void si_llvm_create_func(struct si_shader_context *ctx,
|
|||||||
else
|
else
|
||||||
ret_type = ctx->voidt;
|
ret_type = ctx->voidt;
|
||||||
|
|
||||||
/* Setup the function */
|
|
||||||
ctx->return_type = ret_type;
|
|
||||||
main_fn_type = LLVMFunctionType(ret_type, ParamTypes, ParamCount, 0);
|
|
||||||
ctx->main_fn = LLVMAddFunction(ctx->gallivm.module, name, main_fn_type);
|
|
||||||
main_fn_body = LLVMAppendBasicBlockInContext(ctx->ac.context,
|
|
||||||
ctx->main_fn, "main_body");
|
|
||||||
LLVMPositionBuilderAtEnd(ctx->ac.builder, main_fn_body);
|
|
||||||
|
|
||||||
real_shader_type = ctx->type;
|
real_shader_type = ctx->type;
|
||||||
|
|
||||||
/* LS is merged into HS (TCS), and ES is merged into GS. */
|
/* LS is merged into HS (TCS), and ES is merged into GS. */
|
||||||
@@ -1127,25 +1109,28 @@ void si_llvm_create_func(struct si_shader_context *ctx,
|
|||||||
switch (real_shader_type) {
|
switch (real_shader_type) {
|
||||||
case PIPE_SHADER_VERTEX:
|
case PIPE_SHADER_VERTEX:
|
||||||
case PIPE_SHADER_TESS_EVAL:
|
case PIPE_SHADER_TESS_EVAL:
|
||||||
call_conv = RADEON_LLVM_AMDGPU_VS;
|
call_conv = AC_LLVM_AMDGPU_VS;
|
||||||
break;
|
break;
|
||||||
case PIPE_SHADER_TESS_CTRL:
|
case PIPE_SHADER_TESS_CTRL:
|
||||||
call_conv = RADEON_LLVM_AMDGPU_HS;
|
call_conv = AC_LLVM_AMDGPU_HS;
|
||||||
break;
|
break;
|
||||||
case PIPE_SHADER_GEOMETRY:
|
case PIPE_SHADER_GEOMETRY:
|
||||||
call_conv = RADEON_LLVM_AMDGPU_GS;
|
call_conv = AC_LLVM_AMDGPU_GS;
|
||||||
break;
|
break;
|
||||||
case PIPE_SHADER_FRAGMENT:
|
case PIPE_SHADER_FRAGMENT:
|
||||||
call_conv = RADEON_LLVM_AMDGPU_PS;
|
call_conv = AC_LLVM_AMDGPU_PS;
|
||||||
break;
|
break;
|
||||||
case PIPE_SHADER_COMPUTE:
|
case PIPE_SHADER_COMPUTE:
|
||||||
call_conv = RADEON_LLVM_AMDGPU_CS;
|
call_conv = AC_LLVM_AMDGPU_CS;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
unreachable("Unhandle shader type");
|
unreachable("Unhandle shader type");
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVMSetFunctionCallConv(ctx->main_fn, call_conv);
|
/* Setup the function */
|
||||||
|
ctx->return_type = ret_type;
|
||||||
|
ctx->main_fn = ac_build_main(&ctx->args, &ctx->ac, call_conv, name,
|
||||||
|
ret_type, ctx->gallivm.module);
|
||||||
}
|
}
|
||||||
|
|
||||||
void si_llvm_optimize_module(struct si_shader_context *ctx)
|
void si_llvm_optimize_module(struct si_shader_context *ctx)
|
||||||
|
Reference in New Issue
Block a user