#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_ureg.h"
#include "util/hash_table.h"
-#include "util/u_hash.h"
+#include "util/crc32.h"
#include "util/u_memory.h"
#include "util/u_prim.h"
if (!entry)
return false;
- return si_load_shader_binary(shader, entry->data);
+ if (!si_load_shader_binary(shader, entry->data))
+ return false;
+
+ p_atomic_inc(&sscreen->b.num_shader_cache_hits);
+ return true;
}
static uint32_t si_shader_cache_key_hash(const void *key)
* Calculate the appropriate setting of VGT_GS_MODE when \p shader is a
* geometry shader.
*/
-static uint32_t si_vgt_gs_mode(struct si_shader *shader)
+static uint32_t si_vgt_gs_mode(struct si_shader_selector *sel)
{
- unsigned gs_max_vert_out = shader->selector->gs_max_out_vertices;
+ unsigned gs_max_vert_out = sel->gs_max_out_vertices;
unsigned cut_mode;
if (gs_max_vert_out <= 128) {
static void si_shader_gs(struct si_shader *shader)
{
- unsigned gs_vert_itemsize = shader->selector->gsvs_vertex_size;
- unsigned gsvs_itemsize = shader->selector->max_gsvs_emit_size >> 2;
- unsigned gs_num_invocations = shader->selector->gs_num_invocations;
+ struct si_shader_selector *sel = shader->selector;
+ const ubyte *num_components = sel->info.num_stream_output_components;
+ unsigned gs_num_invocations = sel->gs_num_invocations;
struct si_pm4_state *pm4;
uint64_t va;
- unsigned max_stream = shader->selector->max_gs_stream;
-
- /* The GSVS_RING_ITEMSIZE register takes 15 bits */
- assert(gsvs_itemsize < (1 << 15));
+ unsigned max_stream = sel->max_gs_stream;
+ unsigned offset;
pm4 = si_get_shader_pm4_state(shader);
if (!pm4)
return;
- si_pm4_set_reg(pm4, R_028A40_VGT_GS_MODE, si_vgt_gs_mode(shader));
+ si_pm4_set_reg(pm4, R_028A40_VGT_GS_MODE, si_vgt_gs_mode(shader->selector));
- si_pm4_set_reg(pm4, R_028A60_VGT_GSVS_RING_OFFSET_1, gsvs_itemsize);
- si_pm4_set_reg(pm4, R_028A64_VGT_GSVS_RING_OFFSET_2, gsvs_itemsize * ((max_stream >= 2) ? 2 : 1));
- si_pm4_set_reg(pm4, R_028A68_VGT_GSVS_RING_OFFSET_3, gsvs_itemsize * ((max_stream >= 3) ? 3 : 1));
+ offset = num_components[0] * sel->gs_max_out_vertices;
+ si_pm4_set_reg(pm4, R_028A60_VGT_GSVS_RING_OFFSET_1, offset);
+ if (max_stream >= 1)
+ offset += num_components[1] * sel->gs_max_out_vertices;
+ si_pm4_set_reg(pm4, R_028A64_VGT_GSVS_RING_OFFSET_2, offset);
+ if (max_stream >= 2)
+ offset += num_components[2] * sel->gs_max_out_vertices;
+ si_pm4_set_reg(pm4, R_028A68_VGT_GSVS_RING_OFFSET_3, offset);
+ if (max_stream >= 3)
+ offset += num_components[3] * sel->gs_max_out_vertices;
+ si_pm4_set_reg(pm4, R_028AB0_VGT_GSVS_RING_ITEMSIZE, offset);
- si_pm4_set_reg(pm4, R_028AB0_VGT_GSVS_RING_ITEMSIZE, gsvs_itemsize * (max_stream + 1));
+ /* The GSVS_RING_ITEMSIZE register takes 15 bits */
+ assert(offset < (1 << 15));
si_pm4_set_reg(pm4, R_028B38_VGT_GS_MAX_VERT_OUT, shader->selector->gs_max_out_vertices);
- si_pm4_set_reg(pm4, R_028B5C_VGT_GS_VERT_ITEMSIZE, gs_vert_itemsize >> 2);
- si_pm4_set_reg(pm4, R_028B60_VGT_GS_VERT_ITEMSIZE_1, (max_stream >= 1) ? gs_vert_itemsize >> 2 : 0);
- si_pm4_set_reg(pm4, R_028B64_VGT_GS_VERT_ITEMSIZE_2, (max_stream >= 2) ? gs_vert_itemsize >> 2 : 0);
- si_pm4_set_reg(pm4, R_028B68_VGT_GS_VERT_ITEMSIZE_3, (max_stream >= 3) ? gs_vert_itemsize >> 2 : 0);
+ si_pm4_set_reg(pm4, R_028B5C_VGT_GS_VERT_ITEMSIZE, num_components[0]);
+ si_pm4_set_reg(pm4, R_028B60_VGT_GS_VERT_ITEMSIZE_1, (max_stream >= 1) ? num_components[1] : 0);
+ si_pm4_set_reg(pm4, R_028B64_VGT_GS_VERT_ITEMSIZE_2, (max_stream >= 2) ? num_components[2] : 0);
+ si_pm4_set_reg(pm4, R_028B68_VGT_GS_VERT_ITEMSIZE_3, (max_stream >= 3) ? num_components[3] : 0);
si_pm4_set_reg(pm4, R_028B90_VGT_GS_INSTANCE_CNT,
S_028B90_CNT(MIN2(gs_num_invocations, 127)) |
* is the copy shader.
*/
static void si_shader_vs(struct si_screen *sscreen, struct si_shader *shader,
- struct si_shader *gs)
+ struct si_shader_selector *gs)
{
struct si_pm4_state *pm4;
unsigned num_user_sgprs;
unsigned num_colors = !!(info->colors_read & 0x0f) +
!!(info->colors_read & 0xf0);
unsigned num_interp = ps->selector->info.num_inputs +
- (ps->key.ps.prolog.color_two_side ? num_colors : 0);
+ (ps->key.part.ps.prolog.color_two_side ? num_colors : 0);
assert(num_interp <= 32);
return MIN2(num_interp, 32);
static unsigned si_get_spi_shader_col_format(struct si_shader *shader)
{
- unsigned value = shader->key.ps.epilog.spi_shader_col_format;
+ unsigned value = shader->key.part.ps.epilog.spi_shader_col_format;
unsigned i, num_targets = (util_last_bit(value) + 3) / 4;
/* If the i-th target format is set, all previous target formats must
G_0286CC_LINEAR_CENTER_ENA(input_ena) ||
G_0286CC_LINEAR_CENTROID_ENA(input_ena) ||
G_0286CC_LINE_STIPPLE_TEX_ENA(input_ena));
+ /* POS_W_FLOAT_ENA requires one of the perspective weights. */
+ assert(!G_0286CC_POS_W_FLOAT_ENA(input_ena) ||
+ G_0286CC_PERSP_SAMPLE_ENA(input_ena) ||
+ G_0286CC_PERSP_CENTER_ENA(input_ena) ||
+ G_0286CC_PERSP_CENTROID_ENA(input_ena) ||
+ G_0286CC_PERSP_PULL_MODEL_ENA(input_ena));
+
+ /* Validate interpolation optimization flags (read as implications). */
+ assert(!shader->key.part.ps.prolog.bc_optimize_for_persp ||
+ (G_0286CC_PERSP_CENTER_ENA(input_ena) &&
+ G_0286CC_PERSP_CENTROID_ENA(input_ena)));
+ assert(!shader->key.part.ps.prolog.bc_optimize_for_linear ||
+ (G_0286CC_LINEAR_CENTER_ENA(input_ena) &&
+ G_0286CC_LINEAR_CENTROID_ENA(input_ena)));
+ assert(!shader->key.part.ps.prolog.force_persp_center_interp ||
+ (!G_0286CC_PERSP_SAMPLE_ENA(input_ena) &&
+ !G_0286CC_PERSP_CENTROID_ENA(input_ena)));
+ assert(!shader->key.part.ps.prolog.force_linear_center_interp ||
+ (!G_0286CC_LINEAR_SAMPLE_ENA(input_ena) &&
+ !G_0286CC_LINEAR_CENTROID_ENA(input_ena)));
+ assert(!shader->key.part.ps.prolog.force_persp_sample_interp ||
+ (!G_0286CC_PERSP_CENTER_ENA(input_ena) &&
+ !G_0286CC_PERSP_CENTROID_ENA(input_ena)));
+ assert(!shader->key.part.ps.prolog.force_linear_sample_interp ||
+ (!G_0286CC_LINEAR_CENTER_ENA(input_ena) &&
+ !G_0286CC_LINEAR_CENTROID_ENA(input_ena)));
+
+ /* Validate cases when the optimizations are off (read as implications). */
+ assert(shader->key.part.ps.prolog.bc_optimize_for_persp ||
+ !G_0286CC_PERSP_CENTER_ENA(input_ena) ||
+ !G_0286CC_PERSP_CENTROID_ENA(input_ena));
+ assert(shader->key.part.ps.prolog.bc_optimize_for_linear ||
+ !G_0286CC_LINEAR_CENTER_ENA(input_ena) ||
+ !G_0286CC_LINEAR_CENTROID_ENA(input_ena));
pm4 = si_get_shader_pm4_state(shader);
if (!pm4)
S_00B02C_EXTRA_LDS_SIZE(shader->config.lds_size) |
S_00B02C_USER_SGPR(SI_PS_NUM_USER_SGPR) |
S_00B32C_SCRATCH_EN(shader->config.scratch_bytes_per_wave > 0));
-
- /* Prefer RE_Z if the shader is complex enough. The requirement is either:
- * - the shader uses at least 2 VMEM instructions, or
- * - the code size is at least 50 2-dword instructions or 100 1-dword
- * instructions.
- *
- * Shaders with side effects that must execute independently of the
- * depth test require LATE_Z.
- */
- if (info->writes_memory &&
- !info->properties[TGSI_PROPERTY_FS_EARLY_DEPTH_STENCIL])
- shader->z_order = V_02880C_LATE_Z;
- else if (info->num_memory_instructions >= 2 ||
- shader->binary.code_size > 100*4)
- shader->z_order = V_02880C_EARLY_Z_THEN_RE_Z;
- else
- shader->z_order = V_02880C_EARLY_Z_THEN_LATE_Z;
}
static void si_shader_init_pm4_state(struct si_screen *sscreen,
{
switch (shader->selector->type) {
case PIPE_SHADER_VERTEX:
- if (shader->key.vs.as_ls)
+ if (shader->key.as_ls)
si_shader_ls(shader);
- else if (shader->key.vs.as_es)
+ else if (shader->key.as_es)
si_shader_es(sscreen, shader);
else
si_shader_vs(sscreen, shader, NULL);
si_shader_hs(shader);
break;
case PIPE_SHADER_TESS_EVAL:
- if (shader->key.tes.as_es)
+ if (shader->key.as_es)
si_shader_es(sscreen, shader);
else
si_shader_vs(sscreen, shader, NULL);
break;
case PIPE_SHADER_GEOMETRY:
si_shader_gs(shader);
- si_shader_vs(sscreen, shader->gs_copy_shader, shader);
break;
case PIPE_SHADER_FRAGMENT:
si_shader_ps(shader);
static unsigned si_get_alpha_test_func(struct si_context *sctx)
{
/* Alpha-test should be disabled if colorbuffer 0 is integer. */
- if (sctx->queued.named.dsa &&
- !sctx->framebuffer.cb0_is_integer)
+ if (sctx->queued.named.dsa)
return sctx->queued.named.dsa->alpha_func;
return PIPE_FUNC_ALWAYS;
}
+static void si_shader_selector_key_hw_vs(struct si_context *sctx,
+ struct si_shader_selector *vs,
+ struct si_shader_key *key)
+{
+ struct si_shader_selector *ps = sctx->ps_shader.cso;
+
+ key->opt.hw_vs.clip_disable =
+ sctx->queued.named.rasterizer->clip_plane_enable == 0 &&
+ (vs->info.clipdist_writemask ||
+ vs->info.writes_clipvertex) &&
+ !vs->info.culldist_writemask;
+
+ /* Find out if PS is disabled. */
+ bool ps_disabled = true;
+ if (ps) {
+ bool ps_modifies_zs = ps->info.uses_kill ||
+ ps->info.writes_z ||
+ ps->info.writes_stencil ||
+ ps->info.writes_samplemask ||
+ si_get_alpha_test_func(sctx) != PIPE_FUNC_ALWAYS;
+
+ unsigned ps_colormask = sctx->framebuffer.colorbuf_enabled_4bit &
+ sctx->queued.named.blend->cb_target_mask;
+ if (!ps->info.properties[TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS])
+ ps_colormask &= ps->colors_written_4bit;
+
+ ps_disabled = sctx->queued.named.rasterizer->rasterizer_discard ||
+ (!ps_colormask &&
+ !ps_modifies_zs &&
+ !ps->info.writes_memory);
+ }
+
+ /* Find out which VS outputs aren't used by the PS. */
+ uint64_t outputs_written = vs->outputs_written;
+ uint32_t outputs_written2 = vs->outputs_written2;
+ uint64_t inputs_read = 0;
+ uint32_t inputs_read2 = 0;
+
+ outputs_written &= ~0x3; /* ignore POSITION, PSIZE */
+
+ if (!ps_disabled) {
+ inputs_read = ps->inputs_read;
+ inputs_read2 = ps->inputs_read2;
+ }
+
+ uint64_t linked = outputs_written & inputs_read;
+ uint32_t linked2 = outputs_written2 & inputs_read2;
+
+ key->opt.hw_vs.kill_outputs = ~linked & outputs_written;
+ key->opt.hw_vs.kill_outputs2 = ~linked2 & outputs_written2;
+}
+
/* Compute the key for the hw shader variant */
static inline void si_shader_selector_key(struct pipe_context *ctx,
struct si_shader_selector *sel,
- union si_shader_key *key)
+ struct si_shader_key *key)
{
struct si_context *sctx = (struct si_context *)ctx;
unsigned i;
unsigned count = MIN2(sel->info.num_inputs,
sctx->vertex_elements->count);
for (i = 0; i < count; ++i)
- key->vs.prolog.instance_divisors[i] =
+ key->part.vs.prolog.instance_divisors[i] =
sctx->vertex_elements->elements[i].instance_divisor;
+
+ key->mono.vs.fix_fetch =
+ sctx->vertex_elements->fix_fetch &
+ u_bit_consecutive(0, 2 * count);
}
if (sctx->tes_shader.cso)
- key->vs.as_ls = 1;
+ key->as_ls = 1;
else if (sctx->gs_shader.cso)
- key->vs.as_es = 1;
+ key->as_es = 1;
+ else {
+ si_shader_selector_key_hw_vs(sctx, sel, key);
- if (!sctx->gs_shader.cso && sctx->ps_shader.cso &&
- sctx->ps_shader.cso->info.uses_primid)
- key->vs.epilog.export_prim_id = 1;
+ if (sctx->ps_shader.cso && sctx->ps_shader.cso->info.uses_primid)
+ key->part.vs.epilog.export_prim_id = 1;
+ }
break;
case PIPE_SHADER_TESS_CTRL:
- key->tcs.epilog.prim_mode =
+ key->part.tcs.epilog.prim_mode =
sctx->tes_shader.cso->info.properties[TGSI_PROPERTY_TES_PRIM_MODE];
if (sel == sctx->fixed_func_tcs_shader.cso)
- key->tcs.epilog.inputs_to_copy = sctx->vs_shader.cso->outputs_written;
+ key->mono.tcs.inputs_to_copy = sctx->vs_shader.cso->outputs_written;
break;
case PIPE_SHADER_TESS_EVAL:
if (sctx->gs_shader.cso)
- key->tes.as_es = 1;
- else if (sctx->ps_shader.cso && sctx->ps_shader.cso->info.uses_primid)
- key->tes.epilog.export_prim_id = 1;
+ key->as_es = 1;
+ else {
+ si_shader_selector_key_hw_vs(sctx, sel, key);
+
+ if (sctx->ps_shader.cso && sctx->ps_shader.cso->info.uses_primid)
+ key->part.tes.epilog.export_prim_id = 1;
+ }
break;
case PIPE_SHADER_GEOMETRY:
+ key->part.gs.prolog.tri_strip_adj_fix = sctx->gs_tri_strip_adj_fix;
break;
case PIPE_SHADER_FRAGMENT: {
struct si_state_rasterizer *rs = sctx->queued.named.rasterizer;
if (sel->info.properties[TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS] &&
sel->info.colors_written == 0x1)
- key->ps.epilog.last_cbuf = MAX2(sctx->framebuffer.state.nr_cbufs, 1) - 1;
+ key->part.ps.epilog.last_cbuf = MAX2(sctx->framebuffer.state.nr_cbufs, 1) - 1;
if (blend) {
/* Select the shader color format based on whether
* blending or alpha are needed.
*/
- key->ps.epilog.spi_shader_col_format =
+ key->part.ps.epilog.spi_shader_col_format =
(blend->blend_enable_4bit & blend->need_src_alpha_4bit &
sctx->framebuffer.spi_shader_col_format_blend_alpha) |
(blend->blend_enable_4bit & ~blend->need_src_alpha_4bit &
* the same format as the first output.
*/
if (blend->dual_src_blend)
- key->ps.epilog.spi_shader_col_format |=
- (key->ps.epilog.spi_shader_col_format & 0xf) << 4;
+ key->part.ps.epilog.spi_shader_col_format |=
+ (key->part.ps.epilog.spi_shader_col_format & 0xf) << 4;
} else
- key->ps.epilog.spi_shader_col_format = sctx->framebuffer.spi_shader_col_format;
+ key->part.ps.epilog.spi_shader_col_format = sctx->framebuffer.spi_shader_col_format;
/* If alpha-to-coverage is enabled, we have to export alpha
* even if there is no color buffer.
*/
- if (!(key->ps.epilog.spi_shader_col_format & 0xf) &&
+ if (!(key->part.ps.epilog.spi_shader_col_format & 0xf) &&
blend && blend->alpha_to_coverage)
- key->ps.epilog.spi_shader_col_format |= V_028710_SPI_SHADER_32_AR;
+ key->part.ps.epilog.spi_shader_col_format |= V_028710_SPI_SHADER_32_AR;
/* On SI and CIK except Hawaii, the CB doesn't clamp outputs
* to the range supported by the type if a channel has less
* than 16 bits and the export format is 16_ABGR.
*/
if (sctx->b.chip_class <= CIK && sctx->b.family != CHIP_HAWAII)
- key->ps.epilog.color_is_int8 = sctx->framebuffer.color_is_int8;
+ key->part.ps.epilog.color_is_int8 = sctx->framebuffer.color_is_int8;
/* Disable unwritten outputs (if WRITE_ALL_CBUFS isn't enabled). */
- if (!key->ps.epilog.last_cbuf) {
- key->ps.epilog.spi_shader_col_format &= sel->colors_written_4bit;
- key->ps.epilog.color_is_int8 &= sel->info.colors_written;
+ if (!key->part.ps.epilog.last_cbuf) {
+ key->part.ps.epilog.spi_shader_col_format &= sel->colors_written_4bit;
+ key->part.ps.epilog.color_is_int8 &= sel->info.colors_written;
}
if (rs) {
sctx->current_rast_prim >= PIPE_PRIM_TRIANGLES_ADJACENCY;
bool is_line = !is_poly && sctx->current_rast_prim != PIPE_PRIM_POINTS;
- key->ps.prolog.color_two_side = rs->two_side && sel->info.colors_read;
- key->ps.prolog.flatshade_colors = rs->flatshade && sel->info.colors_read;
+ key->part.ps.prolog.color_two_side = rs->two_side && sel->info.colors_read;
+ key->part.ps.prolog.flatshade_colors = rs->flatshade && sel->info.colors_read;
if (sctx->queued.named.blend) {
- key->ps.epilog.alpha_to_one = sctx->queued.named.blend->alpha_to_one &&
- rs->multisample_enable &&
- !sctx->framebuffer.cb0_is_integer;
+ key->part.ps.epilog.alpha_to_one = sctx->queued.named.blend->alpha_to_one &&
+ rs->multisample_enable;
}
- key->ps.prolog.poly_stipple = rs->poly_stipple_enable && is_poly;
- key->ps.epilog.poly_line_smoothing = ((is_poly && rs->poly_smooth) ||
+ key->part.ps.prolog.poly_stipple = rs->poly_stipple_enable && is_poly;
+ key->part.ps.epilog.poly_line_smoothing = ((is_poly && rs->poly_smooth) ||
(is_line && rs->line_smooth)) &&
sctx->framebuffer.nr_samples <= 1;
- key->ps.epilog.clamp_color = rs->clamp_fragment_color;
+ key->part.ps.epilog.clamp_color = rs->clamp_fragment_color;
if (rs->force_persample_interp &&
rs->multisample_enable &&
sctx->framebuffer.nr_samples > 1 &&
sctx->ps_iter_samples > 1) {
- key->ps.prolog.force_persp_sample_interp =
+ key->part.ps.prolog.force_persp_sample_interp =
sel->info.uses_persp_center ||
sel->info.uses_persp_centroid;
- key->ps.prolog.force_linear_sample_interp =
+ key->part.ps.prolog.force_linear_sample_interp =
sel->info.uses_linear_center ||
sel->info.uses_linear_centroid;
} else if (rs->multisample_enable &&
sctx->framebuffer.nr_samples > 1) {
- key->ps.prolog.bc_optimize_for_persp =
+ key->part.ps.prolog.bc_optimize_for_persp =
sel->info.uses_persp_center &&
sel->info.uses_persp_centroid;
- key->ps.prolog.bc_optimize_for_linear =
+ key->part.ps.prolog.bc_optimize_for_linear =
sel->info.uses_linear_center &&
sel->info.uses_linear_centroid;
} else {
/* Make sure SPI doesn't compute more than 1 pair
* of (i,j), which is the optimization here. */
- key->ps.prolog.force_persp_center_interp =
+ key->part.ps.prolog.force_persp_center_interp =
sel->info.uses_persp_center +
sel->info.uses_persp_centroid +
sel->info.uses_persp_sample > 1;
- key->ps.prolog.force_linear_center_interp =
+ key->part.ps.prolog.force_linear_center_interp =
sel->info.uses_linear_center +
sel->info.uses_linear_centroid +
sel->info.uses_linear_sample > 1;
}
}
- key->ps.epilog.alpha_func = si_get_alpha_test_func(sctx);
+ key->part.ps.epilog.alpha_func = si_get_alpha_test_func(sctx);
break;
}
default:
}
}
+static void si_build_shader_variant(void *job, int thread_index)
+{
+ struct si_shader *shader = (struct si_shader *)job;
+ struct si_shader_selector *sel = shader->selector;
+ struct si_screen *sscreen = sel->screen;
+ LLVMTargetMachineRef tm;
+ struct pipe_debug_callback *debug = &sel->debug;
+ int r;
+
+ if (thread_index >= 0) {
+ assert(thread_index < ARRAY_SIZE(sscreen->tm));
+ tm = sscreen->tm[thread_index];
+ if (!debug->async)
+ debug = NULL;
+ } else {
+ tm = sel->tm;
+ }
+
+ r = si_shader_create(sscreen, tm, shader, debug);
+ if (unlikely(r)) {
+ R600_ERR("Failed to build shader variant (type=%u) %d\n",
+ sel->type, r);
+ shader->compilation_failed = true;
+ return;
+ }
+
+ if (sel->is_debug_context) {
+ FILE *f = open_memstream(&shader->shader_log,
+ &shader->shader_log_size);
+ if (f) {
+ si_shader_dump(sscreen, shader, NULL, sel->type, f);
+ fclose(f);
+ }
+ }
+
+ si_shader_init_pm4_state(sscreen, shader);
+}
+
/* Select the hw shader variant depending on the current state. */
static int si_shader_select_with_key(struct si_screen *sscreen,
struct si_shader_ctx_state *state,
- union si_shader_key *key,
- LLVMTargetMachineRef tm,
- struct pipe_debug_callback *debug,
- bool wait,
- bool is_debug_context)
+ struct si_shader_key *key,
+ int thread_index)
{
+ static const struct si_shader_key zeroed;
struct si_shader_selector *sel = state->cso;
struct si_shader *current = state->current;
struct si_shader *iter, *shader = NULL;
- int r;
+ if (unlikely(sscreen->b.chip_class & DBG_NO_OPT_VARIANT)) {
+ memset(&key->opt, 0, sizeof(key->opt));
+ }
+
+again:
/* Check if we don't need to change anything.
* This path is also used for most shaders that don't need multiple
* variants, it will cost just a computation of the key and this
* test. */
- if (likely(current && memcmp(¤t->key, key, sizeof(*key)) == 0))
+ if (likely(current &&
+ memcmp(¤t->key, key, sizeof(*key)) == 0 &&
+ (!current->is_optimized ||
+ util_queue_fence_is_signalled(¤t->optimized_ready))))
return 0;
/* This must be done before the mutex is locked, because async GS
* compilation calls this function too, and therefore must enter
* the mutex first.
+ *
+ * Only wait if we are in a draw call. Don't wait if we are
+ * in a compiler thread.
*/
- if (wait)
+ if (thread_index < 0)
util_queue_job_wait(&sel->ready);
pipe_mutex_lock(sel->mutex);
/* Don't check the "current" shader. We checked it above. */
if (current != iter &&
memcmp(&iter->key, key, sizeof(*key)) == 0) {
+ /* If it's an optimized shader and its compilation has
+ * been started but isn't done, use the unoptimized
+ * shader so as not to cause a stall due to compilation.
+ */
+ if (iter->is_optimized &&
+ !util_queue_fence_is_signalled(&iter->optimized_ready)) {
+ memset(&key->opt, 0, sizeof(key->opt));
+ pipe_mutex_unlock(sel->mutex);
+ goto again;
+ }
+
+ if (iter->compilation_failed) {
+ pipe_mutex_unlock(sel->mutex);
+ return -1; /* skip the draw call */
+ }
+
state->current = iter;
pipe_mutex_unlock(sel->mutex);
return 0;
shader->selector = sel;
shader->key = *key;
- r = si_shader_create(sscreen, tm, shader, debug);
- if (unlikely(r)) {
- R600_ERR("Failed to build shader variant (type=%u) %d\n",
- sel->type, r);
- FREE(shader);
- pipe_mutex_unlock(sel->mutex);
- return r;
- }
-
- if (is_debug_context) {
- FILE *f = open_memstream(&shader->shader_log,
- &shader->shader_log_size);
- if (f) {
- si_shader_dump(sscreen, shader, NULL, sel->type, f);
- fclose(f);
- }
- }
-
- si_shader_init_pm4_state(sscreen, shader);
+ /* Monolithic-only shaders don't make a distinction between optimized
+ * and unoptimized. */
+ shader->is_monolithic =
+ !sel->main_shader_part ||
+ sel->main_shader_part->key.as_ls != key->as_ls ||
+ sel->main_shader_part->key.as_es != key->as_es ||
+ memcmp(&key->opt, &zeroed.opt, sizeof(key->opt)) != 0 ||
+ memcmp(&key->mono, &zeroed.mono, sizeof(key->mono)) != 0;
+
+ shader->is_optimized =
+ !sscreen->use_monolithic_shaders &&
+ memcmp(&key->opt, &zeroed.opt, sizeof(key->opt)) != 0;
+ if (shader->is_optimized)
+ util_queue_fence_init(&shader->optimized_ready);
if (!sel->last_variant) {
sel->first_variant = shader;
sel->last_variant->next_variant = shader;
sel->last_variant = shader;
}
- state->current = shader;
+
+ /* If it's an optimized shader, compile it asynchronously. */
+ if (shader->is_optimized &&
+ thread_index < 0) {
+ /* Compile it asynchronously. */
+ util_queue_add_job(&sscreen->shader_compiler_queue,
+ shader, &shader->optimized_ready,
+ si_build_shader_variant, NULL);
+
+ /* Use the default (unoptimized) shader for now. */
+ memset(&key->opt, 0, sizeof(key->opt));
+ pipe_mutex_unlock(sel->mutex);
+ goto again;
+ }
+
+ assert(!shader->is_optimized);
+ si_build_shader_variant(shader, thread_index);
+
+ if (!shader->compilation_failed)
+ state->current = shader;
+
pipe_mutex_unlock(sel->mutex);
- return 0;
+ return shader->compilation_failed ? -1 : 0;
}
static int si_shader_select(struct pipe_context *ctx,
struct si_shader_ctx_state *state)
{
struct si_context *sctx = (struct si_context *)ctx;
- union si_shader_key key;
+ struct si_shader_key key;
si_shader_selector_key(ctx, state->cso, &key);
- return si_shader_select_with_key(sctx->screen, state, &key,
- sctx->tm, &sctx->b.debug, true,
- sctx->is_debug);
+ return si_shader_select_with_key(sctx->screen, state, &key, -1);
}
static void si_parse_next_shader_property(const struct tgsi_shader_info *info,
- union si_shader_key *key)
+ struct si_shader_key *key)
{
unsigned next_shader = info->properties[TGSI_PROPERTY_NEXT_SHADER];
case PIPE_SHADER_VERTEX:
switch (next_shader) {
case PIPE_SHADER_GEOMETRY:
- key->vs.as_es = 1;
+ key->as_es = 1;
break;
case PIPE_SHADER_TESS_CTRL:
case PIPE_SHADER_TESS_EVAL:
- key->vs.as_ls = 1;
+ key->as_ls = 1;
break;
+ default:
+ /* If POSITION isn't written, it can't be a HW VS.
+ * Assume that it's a HW LS. (the next shader is TCS)
+ * This heuristic is needed for separate shader objects.
+ */
+ if (!info->writes_position)
+ key->as_ls = 1;
}
break;
case PIPE_SHADER_TESS_EVAL:
- if (next_shader == PIPE_SHADER_GEOMETRY)
- key->tes.as_es = 1;
+ if (next_shader == PIPE_SHADER_GEOMETRY ||
+ !info->writes_position)
+ key->as_es = 1;
break;
}
}
* If this fails, the driver will try to compile a monolithic shader
* on demand.
*/
- if (sel->type != PIPE_SHADER_GEOMETRY &&
- !sscreen->use_monolithic_shaders) {
+ if (!sscreen->use_monolithic_shaders) {
struct si_shader *shader = CALLOC_STRUCT(si_shader);
void *tgsi_binary;
}
sel->main_shader_part = shader;
+
+ /* Unset "outputs_written" flags for outputs converted to
+ * DEFAULT_VAL, so that later inter-shader optimizations don't
+ * try to eliminate outputs that don't exist in the final
+ * shader.
+ *
+ * This is only done if non-monolithic shaders are enabled.
+ */
+ if ((sel->type == PIPE_SHADER_VERTEX ||
+ sel->type == PIPE_SHADER_TESS_EVAL) &&
+ !shader->key.as_ls &&
+ !shader->key.as_es) {
+ unsigned i;
+
+ for (i = 0; i < sel->info.num_outputs; i++) {
+ unsigned offset = shader->info.vs_output_param_offset[i];
+
+ if (offset <= EXP_PARAM_OFFSET_31)
+ continue;
+
+ unsigned name = sel->info.output_semantic_name[i];
+ unsigned index = sel->info.output_semantic_index[i];
+ unsigned id;
+
+ switch (name) {
+ case TGSI_SEMANTIC_GENERIC:
+ /* don't process indices the function can't handle */
+ if (index >= 60)
+ break;
+ /* fall through */
+ case TGSI_SEMANTIC_CLIPDIST:
+ id = si_shader_io_get_unique_index(name, index);
+ sel->outputs_written &= ~(1ull << id);
+ break;
+ case TGSI_SEMANTIC_POSITION: /* ignore these */
+ case TGSI_SEMANTIC_PSIZE:
+ case TGSI_SEMANTIC_CLIPVERTEX:
+ case TGSI_SEMANTIC_EDGEFLAG:
+ break;
+ default:
+ id = si_shader_io_get_unique_index2(name, index);
+ sel->outputs_written2 &= ~(1u << id);
+ }
+ }
+ }
}
/* Pre-compilation. */
- if (sel->type == PIPE_SHADER_GEOMETRY ||
- sscreen->b.debug_flags & DBG_PRECOMPILE) {
+ if (sscreen->b.debug_flags & DBG_PRECOMPILE) {
struct si_shader_ctx_state state = {sel};
- union si_shader_key key;
+ struct si_shader_key key;
memset(&key, 0, sizeof(key));
si_parse_next_shader_property(&sel->info, &key);
*/
switch (sel->type) {
case PIPE_SHADER_TESS_CTRL:
- key.tcs.epilog.prim_mode = PIPE_PRIM_TRIANGLES;
+ key.part.tcs.epilog.prim_mode = PIPE_PRIM_TRIANGLES;
break;
case PIPE_SHADER_FRAGMENT:
- key.ps.epilog.alpha_func = PIPE_FUNC_ALWAYS;
+ key.part.ps.prolog.bc_optimize_for_persp =
+ sel->info.uses_persp_center &&
+ sel->info.uses_persp_centroid;
+ key.part.ps.prolog.bc_optimize_for_linear =
+ sel->info.uses_linear_center &&
+ sel->info.uses_linear_centroid;
+ key.part.ps.epilog.alpha_func = PIPE_FUNC_ALWAYS;
for (i = 0; i < 8; i++)
if (sel->info.colors_written & (1 << i))
- key.ps.epilog.spi_shader_col_format |=
+ key.part.ps.epilog.spi_shader_col_format |=
V_028710_SPI_SHADER_FP16_ABGR << (i * 4);
break;
}
- if (si_shader_select_with_key(sscreen, &state, &key, tm, debug,
- false, sel->is_debug_context))
+ if (si_shader_select_with_key(sscreen, &state, &key, thread_index))
fprintf(stderr, "radeonsi: can't create a monolithic shader\n");
}
+
+ /* The GS copy shader is always pre-compiled. */
+ if (sel->type == PIPE_SHADER_GEOMETRY) {
+ sel->gs_copy_shader = si_generate_gs_copy_shader(sscreen, tm, sel, debug);
+ if (!sel->gs_copy_shader) {
+ fprintf(stderr, "radeonsi: can't create GS copy shader\n");
+ return;
+ }
+
+ si_shader_vs(sscreen, sel->gs_copy_shader, sel);
+ }
}
static void *si_create_shader_selector(struct pipe_context *ctx,
sel->patch_outputs_written |=
1llu << si_shader_io_get_unique_index(name, index);
break;
- default:
+
+ case TGSI_SEMANTIC_GENERIC:
+ /* don't process indices the function can't handle */
+ if (index >= 60)
+ break;
+ /* fall through */
+ case TGSI_SEMANTIC_POSITION:
+ case TGSI_SEMANTIC_PSIZE:
+ case TGSI_SEMANTIC_CLIPDIST:
sel->outputs_written |=
1llu << si_shader_io_get_unique_index(name, index);
+ break;
+ case TGSI_SEMANTIC_CLIPVERTEX: /* ignore these */
+ case TGSI_SEMANTIC_EDGEFLAG:
+ break;
+ default:
+ sel->outputs_written2 |=
+ 1u << si_shader_io_get_unique_index2(name, index);
}
}
sel->esgs_itemsize = util_last_bit64(sel->outputs_written) * 16;
break;
case PIPE_SHADER_FRAGMENT:
+ 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];
+
+ switch (name) {
+ case TGSI_SEMANTIC_CLIPDIST:
+ case TGSI_SEMANTIC_GENERIC:
+ sel->inputs_read |=
+ 1llu << si_shader_io_get_unique_index(name, index);
+ break;
+ case TGSI_SEMANTIC_PCOORD: /* ignore this */
+ break;
+ default:
+ sel->inputs_read2 |=
+ 1u << si_shader_io_get_unique_index2(name, index);
+ }
+ }
+
for (i = 0; i < 8; i++)
if (sel->info.colors_written & (1 << i))
sel->colors_written_4bit |= 0xf << (4 * i);
break;
}
- if (sel->info.properties[TGSI_PROPERTY_FS_EARLY_DEPTH_STENCIL])
- sel->db_shader_control |= S_02880C_DEPTH_BEFORE_SHADER(1);
+ /* Z_ORDER, EXEC_ON_HIER_FAIL and EXEC_ON_NOOP should be set as following:
+ *
+ * | early Z/S | writes_mem | allow_ReZ? | Z_ORDER | EXEC_ON_HIER_FAIL | EXEC_ON_NOOP
+ * --|-----------|------------|------------|--------------------|-------------------|-------------
+ * 1a| false | false | true | EarlyZ_Then_ReZ | 0 | 0
+ * 1b| false | false | false | EarlyZ_Then_LateZ | 0 | 0
+ * 2 | false | true | n/a | LateZ | 1 | 0
+ * 3 | true | false | n/a | EarlyZ_Then_LateZ | 0 | 0
+ * 4 | true | true | n/a | EarlyZ_Then_LateZ | 0 | 1
+ *
+ * In cases 3 and 4, HW will force Z_ORDER to EarlyZ regardless of what's set in the register.
+ * In case 2, NOOP_CULL is a don't care field. In case 2, 3 and 4, ReZ doesn't make sense.
+ *
+ * Don't use ReZ without profiling !!!
+ *
+ * ReZ decreases performance by 15% in DiRT: Showdown on Ultra settings, which has pretty complex
+ * shaders.
+ */
+ if (sel->info.properties[TGSI_PROPERTY_FS_EARLY_DEPTH_STENCIL]) {
+ /* Cases 3, 4. */
+ sel->db_shader_control |= S_02880C_DEPTH_BEFORE_SHADER(1) |
+ S_02880C_Z_ORDER(V_02880C_EARLY_Z_THEN_LATE_Z) |
+ S_02880C_EXEC_ON_NOOP(sel->info.writes_memory);
+ } else if (sel->info.writes_memory) {
+ /* Case 2. */
+ sel->db_shader_control |= S_02880C_Z_ORDER(V_02880C_LATE_Z) |
+ S_02880C_EXEC_ON_HIER_FAIL(1);
+ } else {
+ /* Case 1. */
+ sel->db_shader_control |= S_02880C_Z_ORDER(V_02880C_EARLY_Z_THEN_LATE_Z);
+ }
- if (sel->info.writes_memory)
- sel->db_shader_control |= S_02880C_EXEC_ON_HIER_FAIL(1) |
- S_02880C_EXEC_ON_NOOP(1);
pipe_mutex_init(sel->mutex);
util_queue_fence_init(&sel->ready);
static void si_delete_shader(struct si_context *sctx, struct si_shader *shader)
{
+ if (shader->is_optimized) {
+ util_queue_job_wait(&shader->optimized_ready);
+ util_queue_fence_destroy(&shader->optimized_ready);
+ }
+
if (shader->pm4) {
switch (shader->selector->type) {
case PIPE_SHADER_VERTEX:
- if (shader->key.vs.as_ls)
+ if (shader->key.as_ls)
si_pm4_delete_state(sctx, ls, shader->pm4);
- else if (shader->key.vs.as_es)
+ else if (shader->key.as_es)
si_pm4_delete_state(sctx, es, shader->pm4);
else
si_pm4_delete_state(sctx, vs, shader->pm4);
si_pm4_delete_state(sctx, hs, shader->pm4);
break;
case PIPE_SHADER_TESS_EVAL:
- if (shader->key.tes.as_es)
+ if (shader->key.as_es)
si_pm4_delete_state(sctx, es, shader->pm4);
else
si_pm4_delete_state(sctx, vs, shader->pm4);
break;
case PIPE_SHADER_GEOMETRY:
- si_pm4_delete_state(sctx, gs, shader->pm4);
- si_pm4_delete_state(sctx, vs, shader->gs_copy_shader->pm4);
+ if (shader->is_gs_copy_shader)
+ si_pm4_delete_state(sctx, vs, shader->pm4);
+ else
+ si_pm4_delete_state(sctx, gs, shader->pm4);
break;
case PIPE_SHADER_FRAGMENT:
si_pm4_delete_state(sctx, ps, shader->pm4);
if (sel->main_shader_part)
si_delete_shader(sctx, sel->main_shader_part);
+ if (sel->gs_copy_shader)
+ si_delete_shader(sctx, sel->gs_copy_shader);
util_queue_fence_destroy(&sel->ready);
pipe_mutex_destroy(sel->mutex);
unsigned index, unsigned interpolate)
{
struct tgsi_shader_info *vsinfo = &vs->selector->info;
- unsigned j, ps_input_cntl = 0;
+ unsigned j, offset, ps_input_cntl = 0;
if (interpolate == TGSI_INTERPOLATE_CONSTANT ||
(interpolate == TGSI_INTERPOLATE_COLOR && sctx->flatshade))
for (j = 0; j < vsinfo->num_outputs; j++) {
if (name == vsinfo->output_semantic_name[j] &&
index == vsinfo->output_semantic_index[j]) {
- ps_input_cntl |= S_028644_OFFSET(vs->info.vs_output_param_offset[j]);
+ offset = vs->info.vs_output_param_offset[j];
+
+ if (offset <= EXP_PARAM_OFFSET_31) {
+ /* The input is loaded from parameter memory. */
+ ps_input_cntl |= S_028644_OFFSET(offset);
+ } else if (!G_028644_PT_SPRITE_TEX(ps_input_cntl)) {
+ if (offset == EXP_PARAM_UNDEFINED) {
+ /* This can happen with depth-only rendering. */
+ offset = 0;
+ } else {
+ /* The input is a DEFAULT_VAL constant. */
+ assert(offset >= EXP_PARAM_DEFAULT_VAL_0000 &&
+ offset <= EXP_PARAM_DEFAULT_VAL_1111);
+ offset -= EXP_PARAM_DEFAULT_VAL_0000;
+ }
+
+ ps_input_cntl = S_028644_OFFSET(0x20) |
+ S_028644_DEFAULT_VAL(offset);
+ }
break;
}
}
}
}
- if (ps->key.ps.prolog.color_two_side) {
+ if (ps->key.part.ps.prolog.color_two_side) {
unsigned bcol = TGSI_SEMANTIC_BCOLOR;
for (i = 0; i < 2; i++) {
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);
+ gs->max_gsvs_emit_size;
min_esgs_ring_size = align(min_esgs_ring_size, alignment);
esgs_ring_size = align(esgs_ring_size, alignment);
if (update_esgs) {
pipe_resource_reference(&sctx->esgs_ring, NULL);
- sctx->esgs_ring = pipe_buffer_create(sctx->b.b.screen, PIPE_BIND_CUSTOM,
+ sctx->esgs_ring = pipe_buffer_create(sctx->b.b.screen, 0,
PIPE_USAGE_DEFAULT,
esgs_ring_size);
if (!sctx->esgs_ring)
if (update_gsvs) {
pipe_resource_reference(&sctx->gsvs_ring, NULL);
- sctx->gsvs_ring = pipe_buffer_create(sctx->b.b.screen, PIPE_BIND_CUSTOM,
+ sctx->gsvs_ring = pipe_buffer_create(sctx->b.b.screen, 0,
PIPE_USAGE_DEFAULT,
gsvs_ring_size);
if (!sctx->gsvs_ring)
sctx->esgs_ring, 0, sctx->esgs_ring->width0,
false, false, 0, 0, 0);
}
- if (sctx->gsvs_ring)
- si_set_ring_buffer(&sctx->b.b, SI_VS_RING_GSVS,
+ if (sctx->gsvs_ring) {
+ si_set_ring_buffer(&sctx->b.b, 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)
-{
- unsigned gsvs_itemsize = sctx->gs_shader.cso->max_gsvs_emit_size;
- uint64_t offset;
-
- if (!sctx->gsvs_ring || gsvs_itemsize == sctx->last_gsvs_itemsize)
- return;
-
- sctx->last_gsvs_itemsize = gsvs_itemsize;
-
- si_set_ring_buffer(&sctx->b.b, SI_GS_RING_GSVS0,
- sctx->gsvs_ring, gsvs_itemsize,
- 64, true, true, 4, 16, 0);
-
- offset = gsvs_itemsize * 64;
- si_set_ring_buffer(&sctx->b.b, SI_GS_RING_GSVS1,
- sctx->gsvs_ring, gsvs_itemsize,
- 64, true, true, 4, 16, offset);
-
- offset = (gsvs_itemsize * 2) * 64;
- si_set_ring_buffer(&sctx->b.b, SI_GS_RING_GSVS2,
- sctx->gsvs_ring, gsvs_itemsize,
- 64, true, true, 4, 16, offset);
+ }
- offset = (gsvs_itemsize * 3) * 64;
- si_set_ring_buffer(&sctx->b.b, SI_GS_RING_GSVS3,
- sctx->gsvs_ring, gsvs_itemsize,
- 64, true, true, 4, 16, offset);
+ return true;
}
/**
/* Create a bigger scratch buffer */
r600_resource_reference(&sctx->scratch_buffer, NULL);
- sctx->scratch_buffer =
- si_resource_create_custom(&sctx->screen->b.b,
+ sctx->scratch_buffer = (struct r600_resource*)
+ pipe_buffer_create(&sctx->screen->b.b, 0,
PIPE_USAGE_DEFAULT, scratch_needed_size);
if (!sctx->scratch_buffer)
return false;
}
assert(!sctx->tf_ring);
- sctx->tf_ring = pipe_buffer_create(sctx->b.b.screen, PIPE_BIND_CUSTOM,
+ sctx->tf_ring = pipe_buffer_create(sctx->b.b.screen, 0,
PIPE_USAGE_DEFAULT,
32768 * sctx->screen->b.info.max_se);
if (!sctx->tf_ring)
assert(((sctx->tf_ring->width0 / 4) & C_030938_SIZE) == 0);
- sctx->tess_offchip_ring = pipe_buffer_create(sctx->b.b.screen,
- PIPE_BIND_CUSTOM,
+ sctx->tess_offchip_ring = pipe_buffer_create(sctx->b.b.screen, 0,
PIPE_USAGE_DEFAULT,
max_offchip_buffers *
sctx->screen->tess_offchip_block_dw_size * 4);
{
struct pipe_context *ctx = (struct pipe_context*)sctx;
struct si_state_rasterizer *rs = sctx->queued.named.rasterizer;
+ struct si_shader *old_vs = si_get_vs_state(sctx);
+ bool old_clip_disable = old_vs ? old_vs->key.opt.hw_vs.clip_disable : false;
int r;
/* Update stages before GS. */
if (r)
return false;
si_pm4_bind_state(sctx, gs, sctx->gs_shader.current->pm4);
- si_pm4_bind_state(sctx, vs, sctx->gs_shader.current->gs_copy_shader->pm4);
+ si_pm4_bind_state(sctx, vs, sctx->gs_shader.cso->gs_copy_shader->pm4);
si_update_so(sctx, sctx->gs_shader.cso);
if (!si_update_gs_ring_buffers(sctx))
return false;
-
- si_update_gsvs_ring_bindings(sctx);
} else {
si_pm4_bind_state(sctx, gs, NULL);
si_pm4_bind_state(sctx, es, NULL);
si_update_vgt_shader_config(sctx);
+ if (old_clip_disable != si_get_vs_state(sctx)->key.opt.hw_vs.clip_disable)
+ si_mark_atom_dirty(sctx, &sctx->clip_regs);
+
if (sctx->ps_shader.cso) {
unsigned db_shader_control;
db_shader_control =
sctx->ps_shader.cso->db_shader_control |
- S_02880C_KILL_ENABLE(si_get_alpha_test_func(sctx) != PIPE_FUNC_ALWAYS) |
- S_02880C_Z_ORDER(sctx->ps_shader.current->z_order);
+ S_02880C_KILL_ENABLE(si_get_alpha_test_func(sctx) != PIPE_FUNC_ALWAYS);
if (si_pm4_state_changed(sctx, ps) || si_pm4_state_changed(sctx, vs) ||
sctx->sprite_coord_enable != rs->sprite_coord_enable ||
si_mark_atom_dirty(sctx, &sctx->db_render_state);
}
- if (sctx->smoothing_enabled != sctx->ps_shader.current->key.ps.epilog.poly_line_smoothing) {
- sctx->smoothing_enabled = sctx->ps_shader.current->key.ps.epilog.poly_line_smoothing;
+ if (sctx->smoothing_enabled != sctx->ps_shader.current->key.part.ps.epilog.poly_line_smoothing) {
+ sctx->smoothing_enabled = sctx->ps_shader.current->key.part.ps.epilog.poly_line_smoothing;
si_mark_atom_dirty(sctx, &sctx->msaa_config);
if (sctx->b.chip_class == SI)