summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Olšák <[email protected]>2015-11-08 13:34:44 +0100
committerMarek Olšák <[email protected]>2015-11-13 19:54:42 +0100
commitb1c5f3faa9d7a227150b677469df1a5832236541 (patch)
tree98630efa0fd53ffe5c0dc7140d9939400cc87a70
parent2f5d911ba2b0d477bce80e4dd3ae4d9748c6f784 (diff)
radeonsi: calculate optimal GS ring sizes to fix GS hangs on Tonga
I discovered that increasing the ESGS ring size fixes GS hangs on Tonga, so let's do it properly. There is now a separate init_config_gs_rings state that is not immutable, because GS rings are resized when needed. This also saves some memory. Most apps won't need more than 1MB per ring per shader engine. Reviewed-by: Michel Dänzer <[email protected]> Reviewed-by: Nicolai Hähnle <[email protected]>
-rw-r--r--src/gallium/drivers/radeonsi/si_hw_context.c2
-rw-r--r--src/gallium/drivers/radeonsi/si_pipe.c2
-rw-r--r--src/gallium/drivers/radeonsi/si_pipe.h1
-rw-r--r--src/gallium/drivers/radeonsi/si_shader.h1
-rw-r--r--src/gallium/drivers/radeonsi/si_state_shaders.c154
5 files changed, 113 insertions, 47 deletions
diff --git a/src/gallium/drivers/radeonsi/si_hw_context.c b/src/gallium/drivers/radeonsi/si_hw_context.c
index f28c11cb1d2..baa02293c41 100644
--- a/src/gallium/drivers/radeonsi/si_hw_context.c
+++ b/src/gallium/drivers/radeonsi/si_hw_context.c
@@ -165,6 +165,8 @@ void si_begin_new_cs(struct si_context *ctx)
/* The CS initialization should be emitted before everything else. */
si_pm4_emit(ctx, ctx->init_config);
+ if (ctx->init_config_gs_rings)
+ si_pm4_emit(ctx, ctx->init_config_gs_rings);
ctx->framebuffer.dirty_cbufs = (1 << 8) - 1;
ctx->framebuffer.dirty_zsbuf = true;
diff --git a/src/gallium/drivers/radeonsi/si_pipe.c b/src/gallium/drivers/radeonsi/si_pipe.c
index 6c13fcdf5d7..9a0fe808ee3 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.c
+++ b/src/gallium/drivers/radeonsi/si_pipe.c
@@ -50,6 +50,8 @@ static void si_destroy_context(struct pipe_context *context)
sctx->b.ws->fence_reference(&sctx->last_gfx_fence, NULL);
si_pm4_free_state(sctx, sctx->init_config, ~0);
+ if (sctx->init_config_gs_rings)
+ si_pm4_free_state(sctx, sctx->init_config_gs_rings, ~0);
for (i = 0; i < Elements(sctx->vgt_shader_config); i++)
si_pm4_delete_state(sctx, vgt_shader_config, sctx->vgt_shader_config[i]);
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index 6e742fc1342..05d52fe19dc 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -202,6 +202,7 @@ struct si_context {
/* Precomputed states. */
struct si_pm4_state *init_config;
+ struct si_pm4_state *init_config_gs_rings;
bool init_config_has_vgt_flush;
struct si_pm4_state *vgt_shader_config[4];
diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h
index b87fb715aac..d815ce27e6a 100644
--- a/src/gallium/drivers/radeonsi/si_shader.h
+++ b/src/gallium/drivers/radeonsi/si_shader.h
@@ -203,6 +203,7 @@ struct si_shader_selector {
bool forces_persample_interp_for_linear;
unsigned esgs_itemsize;
+ unsigned gs_input_verts_per_prim;
unsigned gs_output_prim;
unsigned gs_max_out_vertices;
unsigned gs_num_invocations;
diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c
index 6206dc62c1b..007a0ecb476 100644
--- a/src/gallium/drivers/radeonsi/si_state_shaders.c
+++ b/src/gallium/drivers/radeonsi/si_state_shaders.c
@@ -33,6 +33,7 @@
#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_ureg.h"
#include "util/u_memory.h"
+#include "util/u_prim.h"
#include "util/u_simple_shaders.h"
static void si_set_tesseval_regs(struct si_shader *shader,
@@ -707,6 +708,9 @@ static void *si_create_shader_selector(struct pipe_context *ctx,
sel->max_gs_stream = MAX2(sel->max_gs_stream,
sel->so.output[i].stream);
+ sel->gs_input_verts_per_prim =
+ u_vertices_per_prim(sel->info.properties[TGSI_PROPERTY_GS_INPUT_PRIM]);
+
for (i = 0; i < sel->info.num_inputs; i++) {
unsigned name = sel->info.input_semantic_name[i];
unsigned index = sel->info.input_semantic_index[i];
@@ -723,6 +727,7 @@ static void *si_create_shader_selector(struct pipe_context *ctx,
case PIPE_SHADER_VERTEX:
case PIPE_SHADER_TESS_CTRL:
+ case PIPE_SHADER_TESS_EVAL:
for (i = 0; i < sel->info.num_outputs; i++) {
unsigned name = sel->info.output_semantic_name[i];
unsigned index = sel->info.output_semantic_index[i];
@@ -1069,6 +1074,7 @@ static void si_init_config_add_vgt_flush(struct si_context *sctx)
if (sctx->init_config_has_vgt_flush)
return;
+ /* VGT_FLUSH is required even if VGT is idle. It resets VGT pointers. */
si_pm4_cmd_begin(sctx->init_config, PKT3_EVENT_WRITE);
si_pm4_cmd_add(sctx->init_config, EVENT_TYPE(V_028A90_VGT_FLUSH) | EVENT_INDEX(0));
si_pm4_cmd_end(sctx->init_config, false);
@@ -1076,62 +1082,119 @@ static void si_init_config_add_vgt_flush(struct si_context *sctx)
}
/* Initialize state related to ESGS / GSVS ring buffers */
-static void si_init_gs_rings(struct si_context *sctx)
+static bool si_update_gs_ring_buffers(struct si_context *sctx)
{
- unsigned esgs_ring_size = 128 * 1024;
- unsigned gsvs_ring_size = 60 * 1024 * 1024;
+ struct si_shader_selector *es =
+ sctx->tes_shader.cso ? sctx->tes_shader.cso : sctx->vs_shader.cso;
+ struct si_shader_selector *gs = sctx->gs_shader.cso;
+ struct si_pm4_state *pm4;
- assert(!sctx->esgs_ring && !sctx->gsvs_ring);
+ /* Chip constants. */
+ unsigned num_se = sctx->screen->b.info.max_se;
+ unsigned wave_size = 64;
+ unsigned max_gs_waves = 32 * num_se; /* max 32 per SE on GCN */
+ unsigned gs_vertex_reuse = 16 * num_se; /* GS_VERTEX_REUSE register (per SE) */
+ unsigned alignment = 256 * num_se;
+ /* The maximum size is 63.999 MB per SE. */
+ unsigned max_size = ((unsigned)(63.999 * 1024 * 1024) & ~255) * num_se;
+
+ /* Calculate the minimum size. */
+ unsigned min_esgs_ring_size = align(es->esgs_itemsize * gs_vertex_reuse *
+ wave_size, alignment);
+
+ /* These are recommended sizes, not minimum sizes. */
+ unsigned esgs_ring_size = max_gs_waves * 2 * wave_size *
+ es->esgs_itemsize * gs->gs_input_verts_per_prim;
+ unsigned gsvs_ring_size = max_gs_waves * 2 * wave_size *
+ gs->max_gsvs_emit_size * (gs->max_gs_stream + 1);
+
+ min_esgs_ring_size = align(min_esgs_ring_size, alignment);
+ esgs_ring_size = align(esgs_ring_size, alignment);
+ gsvs_ring_size = align(gsvs_ring_size, alignment);
+
+ esgs_ring_size = CLAMP(esgs_ring_size, min_esgs_ring_size, max_size);
+ gsvs_ring_size = MIN2(gsvs_ring_size, max_size);
+
+ /* Some rings don't have to be allocated if shaders don't use them.
+ * (e.g. no varyings between ES and GS or GS and VS)
+ */
+ bool update_esgs = esgs_ring_size &&
+ (!sctx->esgs_ring ||
+ sctx->esgs_ring->width0 < esgs_ring_size);
+ bool update_gsvs = gsvs_ring_size &&
+ (!sctx->gsvs_ring ||
+ sctx->gsvs_ring->width0 < gsvs_ring_size);
- sctx->esgs_ring = pipe_buffer_create(sctx->b.b.screen, PIPE_BIND_CUSTOM,
- PIPE_USAGE_DEFAULT, esgs_ring_size);
- if (!sctx->esgs_ring)
- return;
+ if (!update_esgs && !update_gsvs)
+ return true;
- sctx->gsvs_ring = pipe_buffer_create(sctx->b.b.screen, PIPE_BIND_CUSTOM,
- PIPE_USAGE_DEFAULT, gsvs_ring_size);
- if (!sctx->gsvs_ring) {
+ if (update_esgs) {
pipe_resource_reference(&sctx->esgs_ring, NULL);
- return;
+ sctx->esgs_ring = pipe_buffer_create(sctx->b.b.screen, PIPE_BIND_CUSTOM,
+ PIPE_USAGE_DEFAULT,
+ esgs_ring_size);
+ if (!sctx->esgs_ring)
+ return false;
}
- si_init_config_add_vgt_flush(sctx);
+ if (update_gsvs) {
+ pipe_resource_reference(&sctx->gsvs_ring, NULL);
+ sctx->gsvs_ring = pipe_buffer_create(sctx->b.b.screen, PIPE_BIND_CUSTOM,
+ PIPE_USAGE_DEFAULT,
+ gsvs_ring_size);
+ if (!sctx->gsvs_ring)
+ return false;
+ }
+
+ /* Create the "init_config_gs_rings" state. */
+ pm4 = CALLOC_STRUCT(si_pm4_state);
+ if (!pm4)
+ return false;
- /* Append these registers to the init config state. */
if (sctx->b.chip_class >= CIK) {
- if (sctx->b.chip_class >= VI) {
- /* The maximum sizes are 63.999 MB on VI, because
- * the register fields only have 18 bits. */
- assert(esgs_ring_size / 256 < (1 << 18));
- assert(gsvs_ring_size / 256 < (1 << 18));
- }
- si_pm4_set_reg(sctx->init_config, R_030900_VGT_ESGS_RING_SIZE,
- esgs_ring_size / 256);
- si_pm4_set_reg(sctx->init_config, R_030904_VGT_GSVS_RING_SIZE,
- gsvs_ring_size / 256);
+ if (sctx->esgs_ring)
+ si_pm4_set_reg(pm4, R_030900_VGT_ESGS_RING_SIZE,
+ sctx->esgs_ring->width0 / 256);
+ if (sctx->gsvs_ring)
+ si_pm4_set_reg(pm4, R_030904_VGT_GSVS_RING_SIZE,
+ sctx->gsvs_ring->width0 / 256);
} else {
- si_pm4_set_reg(sctx->init_config, R_0088C8_VGT_ESGS_RING_SIZE,
- esgs_ring_size / 256);
- si_pm4_set_reg(sctx->init_config, R_0088CC_VGT_GSVS_RING_SIZE,
- gsvs_ring_size / 256);
+ if (sctx->esgs_ring)
+ si_pm4_set_reg(pm4, R_0088C8_VGT_ESGS_RING_SIZE,
+ sctx->esgs_ring->width0 / 256);
+ if (sctx->gsvs_ring)
+ si_pm4_set_reg(pm4, R_0088CC_VGT_GSVS_RING_SIZE,
+ sctx->gsvs_ring->width0 / 256);
}
- /* Flush the context to re-emit the init_config state.
- * This is done only once in a lifetime of a context.
- */
- si_pm4_upload_indirect_buffer(sctx, sctx->init_config);
+ /* Set the state. */
+ if (sctx->init_config_gs_rings)
+ si_pm4_free_state(sctx, sctx->init_config_gs_rings, ~0);
+ sctx->init_config_gs_rings = pm4;
+
+ if (!sctx->init_config_has_vgt_flush) {
+ si_init_config_add_vgt_flush(sctx);
+ si_pm4_upload_indirect_buffer(sctx, sctx->init_config);
+ }
+
+ /* Flush the context to re-emit both init_config states. */
sctx->b.initial_gfx_cs_size = 0; /* force flush */
si_context_gfx_flush(sctx, RADEON_FLUSH_ASYNC, NULL);
- si_set_ring_buffer(&sctx->b.b, PIPE_SHADER_VERTEX, SI_RING_ESGS,
- sctx->esgs_ring, 0, esgs_ring_size,
- true, true, 4, 64, 0);
- si_set_ring_buffer(&sctx->b.b, PIPE_SHADER_GEOMETRY, SI_RING_ESGS,
- sctx->esgs_ring, 0, esgs_ring_size,
- false, false, 0, 0, 0);
- si_set_ring_buffer(&sctx->b.b, PIPE_SHADER_VERTEX, SI_RING_GSVS,
- sctx->gsvs_ring, 0, gsvs_ring_size,
- false, false, 0, 0, 0);
+ /* Set ring bindings. */
+ if (sctx->esgs_ring) {
+ si_set_ring_buffer(&sctx->b.b, PIPE_SHADER_VERTEX, SI_RING_ESGS,
+ sctx->esgs_ring, 0, sctx->esgs_ring->width0,
+ true, true, 4, 64, 0);
+ si_set_ring_buffer(&sctx->b.b, PIPE_SHADER_GEOMETRY, SI_RING_ESGS,
+ sctx->esgs_ring, 0, sctx->esgs_ring->width0,
+ false, false, 0, 0, 0);
+ }
+ if (sctx->gsvs_ring)
+ si_set_ring_buffer(&sctx->b.b, PIPE_SHADER_VERTEX, SI_RING_GSVS,
+ sctx->gsvs_ring, 0, sctx->gsvs_ring->width0,
+ false, false, 0, 0, 0);
+ return true;
}
static void si_update_gsvs_ring_bindings(struct si_context *sctx)
@@ -1139,7 +1202,7 @@ static void si_update_gsvs_ring_bindings(struct si_context *sctx)
unsigned gsvs_itemsize = sctx->gs_shader.cso->max_gsvs_emit_size;
uint64_t offset;
- if (gsvs_itemsize == sctx->last_gsvs_itemsize)
+ if (!sctx->gsvs_ring || gsvs_itemsize == sctx->last_gsvs_itemsize)
return;
sctx->last_gsvs_itemsize = gsvs_itemsize;
@@ -1500,11 +1563,8 @@ bool si_update_shaders(struct si_context *sctx)
si_pm4_bind_state(sctx, vs, sctx->gs_shader.current->gs_copy_shader->pm4);
si_update_so(sctx, sctx->gs_shader.cso);
- if (!sctx->gsvs_ring) {
- si_init_gs_rings(sctx);
- if (!sctx->gsvs_ring)
- return false;
- }
+ if (!si_update_gs_ring_buffers(sctx))
+ return false;
si_update_gsvs_ring_bindings(sctx);
} else {