radv/aco,aco: implement GS on GFX9+
v2: implement GFX10 v3: rebase v7: rebase after shader args MR v8: fix gs_vtx_offset usage on GFX9/GFX10 v8: use unreachable() instead of printing intrinsic v8: rename output_state to ge_output_state v8: fix formatting around nir_foreach_variable() v8: rename some helpers in the scheduler v8: rename p_memory_barrier_all to p_memory_barrier_common v8: fix assertion comparing ctx.stage against vertex_geometry_gs Signed-off-by: Rhys Perry <pendingchaos02@gmail.com> Reviewed-by: Daniel Schürmann <daniel@schuermann.dev> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/2421>
This commit is contained in:
@@ -39,7 +39,7 @@
|
||||
|
||||
namespace aco {
|
||||
|
||||
struct vs_output_state {
|
||||
struct ge_output_state {
|
||||
uint8_t mask[VARYING_SLOT_VAR31 + 1];
|
||||
Temp outputs[VARYING_SLOT_VAR31 + 1][4];
|
||||
};
|
||||
@@ -74,19 +74,22 @@ struct isel_context {
|
||||
|
||||
Temp arg_temps[AC_MAX_ARGS];
|
||||
|
||||
/* inputs common for merged stages */
|
||||
Temp merged_wave_info = Temp(0, s1);
|
||||
|
||||
/* FS inputs */
|
||||
Temp persp_centroid, linear_centroid;
|
||||
|
||||
/* VS inputs */
|
||||
bool needs_instance_id;
|
||||
|
||||
/* gathered information */
|
||||
uint64_t input_masks[MESA_SHADER_COMPUTE];
|
||||
uint64_t output_masks[MESA_SHADER_COMPUTE];
|
||||
|
||||
/* VS output information */
|
||||
unsigned num_clip_distances;
|
||||
unsigned num_cull_distances;
|
||||
vs_output_state vs_output;
|
||||
|
||||
/* VS or GS output information */
|
||||
ge_output_state vsgs_output;
|
||||
};
|
||||
|
||||
Temp get_arg(isel_context *ctx, struct ac_arg arg)
|
||||
@@ -298,6 +301,7 @@ void init_context(isel_context *ctx, nir_shader *shader)
|
||||
case nir_intrinsic_load_sample_id:
|
||||
case nir_intrinsic_load_sample_mask_in:
|
||||
case nir_intrinsic_load_input:
|
||||
case nir_intrinsic_load_per_vertex_input:
|
||||
case nir_intrinsic_load_vertex_id:
|
||||
case nir_intrinsic_load_vertex_id_zero_base:
|
||||
case nir_intrinsic_load_barycentric_sample:
|
||||
@@ -357,6 +361,8 @@ void init_context(isel_context *ctx, nir_shader *shader)
|
||||
case nir_intrinsic_shared_atomic_exchange:
|
||||
case nir_intrinsic_shared_atomic_comp_swap:
|
||||
case nir_intrinsic_load_scratch:
|
||||
case nir_intrinsic_load_invocation_id:
|
||||
case nir_intrinsic_load_primitive_id:
|
||||
type = RegType::vgpr;
|
||||
break;
|
||||
case nir_intrinsic_shuffle:
|
||||
@@ -664,63 +670,68 @@ setup_vs_variables(isel_context *ctx, nir_shader *nir)
|
||||
}
|
||||
nir_foreach_variable(variable, &nir->outputs)
|
||||
{
|
||||
variable->data.driver_location = variable->data.location * 4;
|
||||
if (ctx->stage == vertex_geometry_gs)
|
||||
variable->data.driver_location = util_bitcount64(ctx->output_masks[nir->info.stage] & ((1ull << variable->data.location) - 1ull)) * 4;
|
||||
else
|
||||
variable->data.driver_location = variable->data.location * 4;
|
||||
}
|
||||
|
||||
radv_vs_output_info *outinfo = &ctx->program->info->vs.outinfo;
|
||||
if (ctx->stage == vertex_vs) {
|
||||
radv_vs_output_info *outinfo = &ctx->program->info->vs.outinfo;
|
||||
|
||||
memset(outinfo->vs_output_param_offset, AC_EXP_PARAM_UNDEFINED,
|
||||
sizeof(outinfo->vs_output_param_offset));
|
||||
memset(outinfo->vs_output_param_offset, AC_EXP_PARAM_UNDEFINED,
|
||||
sizeof(outinfo->vs_output_param_offset));
|
||||
|
||||
ctx->needs_instance_id = ctx->program->info->vs.needs_instance_id;
|
||||
ctx->needs_instance_id = ctx->program->info->vs.needs_instance_id;
|
||||
|
||||
bool export_clip_dists = ctx->options->key.vs_common_out.export_clip_dists;
|
||||
bool export_clip_dists = ctx->options->key.vs_common_out.export_clip_dists;
|
||||
|
||||
outinfo->param_exports = 0;
|
||||
int pos_written = 0x1;
|
||||
if (outinfo->writes_pointsize || outinfo->writes_viewport_index || outinfo->writes_layer)
|
||||
pos_written |= 1 << 1;
|
||||
outinfo->param_exports = 0;
|
||||
int pos_written = 0x1;
|
||||
if (outinfo->writes_pointsize || outinfo->writes_viewport_index || outinfo->writes_layer)
|
||||
pos_written |= 1 << 1;
|
||||
|
||||
nir_foreach_variable(variable, &nir->outputs)
|
||||
{
|
||||
int idx = variable->data.location;
|
||||
unsigned slots = variable->type->count_attribute_slots(false);
|
||||
if (variable->data.compact) {
|
||||
unsigned component_count = variable->data.location_frac + variable->type->length;
|
||||
slots = (component_count + 3) / 4;
|
||||
}
|
||||
|
||||
if (idx >= VARYING_SLOT_VAR0 || idx == VARYING_SLOT_LAYER || idx == VARYING_SLOT_PRIMITIVE_ID ||
|
||||
((idx == VARYING_SLOT_CLIP_DIST0 || idx == VARYING_SLOT_CLIP_DIST1) && export_clip_dists)) {
|
||||
for (unsigned i = 0; i < slots; i++) {
|
||||
if (outinfo->vs_output_param_offset[idx + i] == AC_EXP_PARAM_UNDEFINED)
|
||||
outinfo->vs_output_param_offset[idx + i] = outinfo->param_exports++;
|
||||
uint64_t mask = ctx->output_masks[nir->info.stage];
|
||||
while (mask) {
|
||||
int idx = u_bit_scan64(&mask);
|
||||
if (idx >= VARYING_SLOT_VAR0 || idx == VARYING_SLOT_LAYER || idx == VARYING_SLOT_PRIMITIVE_ID ||
|
||||
((idx == VARYING_SLOT_CLIP_DIST0 || idx == VARYING_SLOT_CLIP_DIST1) && export_clip_dists)) {
|
||||
if (outinfo->vs_output_param_offset[idx] == AC_EXP_PARAM_UNDEFINED)
|
||||
outinfo->vs_output_param_offset[idx] = outinfo->param_exports++;
|
||||
}
|
||||
}
|
||||
if (outinfo->writes_layer &&
|
||||
outinfo->vs_output_param_offset[VARYING_SLOT_LAYER] == AC_EXP_PARAM_UNDEFINED) {
|
||||
/* when ctx->options->key.has_multiview_view_index = true, the layer
|
||||
* variable isn't declared in NIR and it's isel's job to get the layer */
|
||||
outinfo->vs_output_param_offset[VARYING_SLOT_LAYER] = outinfo->param_exports++;
|
||||
}
|
||||
|
||||
if (outinfo->export_prim_id) {
|
||||
assert(outinfo->vs_output_param_offset[VARYING_SLOT_PRIMITIVE_ID] == AC_EXP_PARAM_UNDEFINED);
|
||||
outinfo->vs_output_param_offset[VARYING_SLOT_PRIMITIVE_ID] = outinfo->param_exports++;
|
||||
}
|
||||
|
||||
ctx->num_clip_distances = util_bitcount(outinfo->clip_dist_mask);
|
||||
ctx->num_cull_distances = util_bitcount(outinfo->cull_dist_mask);
|
||||
|
||||
assert(ctx->num_clip_distances + ctx->num_cull_distances <= 8);
|
||||
|
||||
if (ctx->num_clip_distances + ctx->num_cull_distances > 0)
|
||||
pos_written |= 1 << 2;
|
||||
if (ctx->num_clip_distances + ctx->num_cull_distances > 4)
|
||||
pos_written |= 1 << 3;
|
||||
|
||||
outinfo->pos_exports = util_bitcount(pos_written);
|
||||
} else if (ctx->stage == vertex_geometry_gs) {
|
||||
/* TODO: radv_nir_shader_info_pass() already sets this but it's larger
|
||||
* than it needs to be in order to set it better, we have to improve
|
||||
* radv_nir_shader_info_pass() because gfx9_get_gs_info() uses
|
||||
* esgs_itemsize and has to be done before compilation
|
||||
*/
|
||||
/* radv_es_output_info *outinfo = &ctx->program->info->vs.es_info;
|
||||
outinfo->esgs_itemsize = util_bitcount64(ctx->output_masks[nir->info.stage]) * 16u; */
|
||||
}
|
||||
if (outinfo->writes_layer &&
|
||||
outinfo->vs_output_param_offset[VARYING_SLOT_LAYER] == AC_EXP_PARAM_UNDEFINED) {
|
||||
/* when ctx->options->key.has_multiview_view_index = true, the layer
|
||||
* variable isn't declared in NIR and it's isel's job to get the layer */
|
||||
outinfo->vs_output_param_offset[VARYING_SLOT_LAYER] = outinfo->param_exports++;
|
||||
}
|
||||
|
||||
if (outinfo->export_prim_id) {
|
||||
assert(outinfo->vs_output_param_offset[VARYING_SLOT_PRIMITIVE_ID] == AC_EXP_PARAM_UNDEFINED);
|
||||
outinfo->vs_output_param_offset[VARYING_SLOT_PRIMITIVE_ID] = outinfo->param_exports++;
|
||||
}
|
||||
|
||||
ctx->num_clip_distances = util_bitcount(outinfo->clip_dist_mask);
|
||||
ctx->num_cull_distances = util_bitcount(outinfo->cull_dist_mask);
|
||||
|
||||
assert(ctx->num_clip_distances + ctx->num_cull_distances <= 8);
|
||||
|
||||
if (ctx->num_clip_distances + ctx->num_cull_distances > 0)
|
||||
pos_written |= 1 << 2;
|
||||
if (ctx->num_clip_distances + ctx->num_cull_distances > 4)
|
||||
pos_written |= 1 << 3;
|
||||
|
||||
outinfo->pos_exports = util_bitcount(pos_written);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -744,11 +755,66 @@ setup_variables(isel_context *ctx, nir_shader *nir)
|
||||
setup_vs_variables(ctx, nir);
|
||||
break;
|
||||
}
|
||||
case MESA_SHADER_GEOMETRY: {
|
||||
assert(ctx->stage == vertex_geometry_gs);
|
||||
nir_foreach_variable(variable, &nir->inputs) {
|
||||
variable->data.driver_location = util_bitcount64(ctx->input_masks[nir->info.stage] & ((1ull << variable->data.location) - 1ull)) * 4;
|
||||
}
|
||||
nir_foreach_variable(variable, &nir->outputs) {
|
||||
variable->data.driver_location = variable->data.location * 4;
|
||||
}
|
||||
ctx->program->info->gs.es_type = MESA_SHADER_VERTEX; /* tesselation shaders are not yet supported */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
unreachable("Unhandled shader stage.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
get_io_masks(isel_context *ctx, unsigned shader_count, struct nir_shader *const *shaders)
|
||||
{
|
||||
for (unsigned i = 0; i < shader_count; i++) {
|
||||
nir_shader *nir = shaders[i];
|
||||
if (nir->info.stage == MESA_SHADER_COMPUTE)
|
||||
continue;
|
||||
|
||||
uint64_t output_mask = 0;
|
||||
nir_foreach_variable(variable, &nir->outputs) {
|
||||
const glsl_type *type = variable->type;
|
||||
if (nir_is_per_vertex_io(variable, nir->info.stage))
|
||||
type = type->fields.array;
|
||||
unsigned slots = type->count_attribute_slots(false);
|
||||
if (variable->data.compact) {
|
||||
unsigned component_count = variable->data.location_frac + type->length;
|
||||
slots = (component_count + 3) / 4;
|
||||
}
|
||||
output_mask |= ((1ull << slots) - 1) << variable->data.location;
|
||||
}
|
||||
|
||||
uint64_t input_mask = 0;
|
||||
nir_foreach_variable(variable, &nir->inputs) {
|
||||
const glsl_type *type = variable->type;
|
||||
if (nir_is_per_vertex_io(variable, nir->info.stage))
|
||||
type = type->fields.array;
|
||||
unsigned slots = type->count_attribute_slots(false);
|
||||
if (variable->data.compact) {
|
||||
unsigned component_count = variable->data.location_frac + type->length;
|
||||
slots = (component_count + 3) / 4;
|
||||
}
|
||||
input_mask |= ((1ull << slots) - 1) << variable->data.location;
|
||||
}
|
||||
|
||||
ctx->output_masks[nir->info.stage] |= output_mask;
|
||||
if (i + 1 < shader_count)
|
||||
ctx->input_masks[shaders[i + 1]->info.stage] |= output_mask;
|
||||
|
||||
ctx->input_masks[nir->info.stage] |= input_mask;
|
||||
if (i)
|
||||
ctx->output_masks[shaders[i - 1]->info.stage] |= input_mask;
|
||||
}
|
||||
}
|
||||
|
||||
isel_context
|
||||
setup_isel_context(Program* program,
|
||||
unsigned shader_count,
|
||||
@@ -781,12 +847,16 @@ setup_isel_context(Program* program,
|
||||
unreachable("Shader stage not implemented");
|
||||
}
|
||||
}
|
||||
bool gfx9_plus = args->options->chip_class >= GFX9;
|
||||
bool ngg = args->shader_info->is_ngg && args->options->chip_class >= GFX10;
|
||||
if (program->stage == sw_vs)
|
||||
program->stage |= hw_vs;
|
||||
else if (program->stage == sw_fs)
|
||||
program->stage |= hw_fs;
|
||||
else if (program->stage == sw_cs)
|
||||
program->stage |= hw_cs;
|
||||
else if (program->stage == (sw_vs | sw_gs) && gfx9_plus && !ngg)
|
||||
program->stage |= hw_gs;
|
||||
else
|
||||
unreachable("Shader stage not implemented");
|
||||
|
||||
@@ -833,6 +903,8 @@ setup_isel_context(Program* program,
|
||||
ctx.options = args->options;
|
||||
ctx.stage = program->stage;
|
||||
|
||||
get_io_masks(&ctx, shader_count, shaders);
|
||||
|
||||
for (unsigned i = 0; i < shader_count; i++) {
|
||||
nir_shader *nir = shaders[i];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user