#include "r600_shader.h"
#include "r600d.h"
-#include "util/u_format_s3tc.h"
+#include "util/format/u_format_s3tc.h"
#include "util/u_index_modify.h"
#include "util/u_memory.h"
#include "util/u_upload_mgr.h"
#include "tgsi/tgsi_scan.h"
#include "tgsi/tgsi_ureg.h"
+#include "nir.h"
+#include "nir/nir_to_tgsi_info.h"
+#include "tgsi/tgsi_from_mesa.h"
+
void r600_init_command_buffer(struct r600_command_buffer *cb, unsigned num_dw)
{
assert(!cb->buf);
void r600_emit_alphatest_state(struct r600_context *rctx, struct r600_atom *atom)
{
- struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
+ struct radeon_cmdbuf *cs = rctx->b.gfx.cs;
struct r600_alphatest_state *a = (struct r600_alphatest_state*)atom;
unsigned alpha_ref = a->sx_alpha_ref;
static void r600_memory_barrier(struct pipe_context *ctx, unsigned flags)
{
struct r600_context *rctx = (struct r600_context *)ctx;
+
+ if (!(flags & ~PIPE_BARRIER_UPDATE))
+ return;
+
if (flags & PIPE_BARRIER_CONSTANT_BUFFER)
rctx->b.flags |= R600_CONTEXT_INV_CONST_CACHE;
void r600_emit_blend_color(struct r600_context *rctx, struct r600_atom *atom)
{
- struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
+ struct radeon_cmdbuf *cs = rctx->b.gfx.cs;
struct pipe_blend_color *state = &rctx->blend_color.state;
radeon_set_context_reg_seq(cs, R_028414_CB_BLEND_RED, 4);
void r600_emit_vgt_state(struct r600_context *rctx, struct r600_atom *atom)
{
- struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
+ struct radeon_cmdbuf *cs = rctx->b.gfx.cs;
struct r600_vgt_state *a = (struct r600_vgt_state *)atom;
radeon_set_context_reg(cs, R_028A94_VGT_MULTI_PRIM_IB_RESET_EN, a->vgt_multi_prim_ib_reset_en);
void r600_emit_stencil_ref(struct r600_context *rctx, struct r600_atom *atom)
{
- struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
+ struct radeon_cmdbuf *cs = rctx->b.gfx.cs;
struct r600_stencil_ref_state *a = (struct r600_stencil_ref_state*)atom;
radeon_set_context_reg_seq(cs, R_028430_DB_STENCILREFMASK, 2);
if (view->tex_resource->gpu_address &&
view->tex_resource->b.b.target == PIPE_BUFFER)
- LIST_DELINIT(&view->list);
+ list_delinit(&view->list);
pipe_resource_reference(&state->texture, NULL);
FREE(view);
static void r600_delete_vertex_elements(struct pipe_context *ctx, void *state)
{
struct r600_fetch_shader *shader = (struct r600_fetch_shader*)state;
- r600_resource_reference(&shader->buffer, NULL);
+ if (shader)
+ r600_resource_reference(&shader->buffer, NULL);
FREE(shader);
}
/* Set vertex buffers. */
if (input) {
for (i = 0; i < count; i++) {
- if (memcmp(&input[i], &vb[i], sizeof(struct pipe_vertex_buffer))) {
+ if ((input[i].buffer.resource != vb[i].buffer.resource) ||
+ (vb[i].stride != input[i].stride) ||
+ (vb[i].buffer_offset != input[i].buffer_offset) ||
+ (vb[i].is_user_buffer != input[i].is_user_buffer)) {
if (input[i].buffer.resource) {
vb[i].stride = input[i].stride;
vb[i].buffer_offset = input[i].buffer_offset;
}
struct r600_pipe_shader_selector *r600_create_shader_state_tokens(struct pipe_context *ctx,
- const struct tgsi_token *tokens,
+ const void *prog, enum pipe_shader_ir ir,
unsigned pipe_shader_type)
{
struct r600_pipe_shader_selector *sel = CALLOC_STRUCT(r600_pipe_shader_selector);
sel->type = pipe_shader_type;
- sel->tokens = tgsi_dup_tokens(tokens);
- tgsi_scan_shader(tokens, &sel->info);
+ if (ir == PIPE_SHADER_IR_TGSI) {
+ sel->tokens = tgsi_dup_tokens((const struct tgsi_token *)prog);
+ tgsi_scan_shader(sel->tokens, &sel->info);
+ } else if (ir == PIPE_SHADER_IR_NIR){
+ sel->nir = nir_shader_clone(NULL, (const nir_shader *)prog);
+ nir_tgsi_scan_shader(sel->nir, &sel->info, true);
+ }
return sel;
}
unsigned pipe_shader_type)
{
int i;
- struct r600_pipe_shader_selector *sel = r600_create_shader_state_tokens(ctx, state->tokens, pipe_shader_type);
-
+ struct r600_pipe_shader_selector *sel;
+
+ if (state->type == PIPE_SHADER_IR_TGSI)
+ sel = r600_create_shader_state_tokens(ctx, state->tokens, state->type, pipe_shader_type);
+ else if (state->type == PIPE_SHADER_IR_NIR) {
+ sel = r600_create_shader_state_tokens(ctx, state->ir.nir, state->type, pipe_shader_type);
+ } else
+ assert(0 && "Unknown shader type\n");
+
+ sel->ir_type = state->type;
sel->so = state->stream_output;
switch (pipe_shader_type) {
rctx->vs_shader = (struct r600_pipe_shader_selector *)state;
r600_update_vs_writes_viewport_index(&rctx->b, r600_get_vs_info(rctx));
- rctx->b.streamout.stride_in_dw = rctx->vs_shader->so.stride;
+
+ if (rctx->vs_shader->so.num_outputs)
+ rctx->b.streamout.stride_in_dw = rctx->vs_shader->so.stride;
}
static void r600_bind_gs_state(struct pipe_context *ctx, void *state)
if (!state)
return;
- rctx->b.streamout.stride_in_dw = rctx->gs_shader->so.stride;
+
+ if (rctx->gs_shader->so.num_outputs)
+ rctx->b.streamout.stride_in_dw = rctx->gs_shader->so.stride;
}
static void r600_bind_tcs_state(struct pipe_context *ctx, void *state)
if (!state)
return;
- rctx->b.streamout.stride_in_dw = rctx->tes_shader->so.stride;
+
+ if (rctx->tes_shader->so.num_outputs)
+ rctx->b.streamout.stride_in_dw = rctx->tes_shader->so.stride;
}
void r600_delete_shader_selector(struct pipe_context *ctx,
p = c;
}
- free(sel->tokens);
+ if (sel->ir_type == PIPE_SHADER_IR_TGSI) {
+ free(sel->tokens);
+ /* We might have converted the TGSI shader to a NIR shader */
+ if (sel->nir)
+ ralloc_free(sel->nir);
+ }
+ else if (sel->ir_type == PIPE_SHADER_IR_NIR)
+ ralloc_free(sel->nir);
free(sel);
}
}
static void *r600_alloc_buf_consts(struct r600_context *rctx, int shader_type,
- int array_size, uint32_t *base_offset)
+ unsigned array_size, uint32_t *base_offset)
{
struct r600_shader_driver_constants_info *info = &rctx->driver_consts[shader_type];
if (array_size + R600_UCP_SIZE > info->alloc_size) {
int idx = i - sview_bits;
if (images->enabled_mask & (1 << idx)) {
uint32_t offset = (base_offset / 4) + i;
- constants[offset] = images->views[i].base.resource->array_size / 6;
+ constants[offset] = images->views[idx].base.resource->array_size / 6;
}
}
}
/* set sample xy locations as array of fragment shader constants */
void r600_set_sample_locations_constant_buffer(struct r600_context *rctx)
{
- int i;
struct pipe_context *ctx = &rctx->b.b;
assert(rctx->framebuffer.nr_samples < R600_UCP_SIZE);
assert(rctx->framebuffer.nr_samples <= ARRAY_SIZE(rctx->sample_positions)/4);
memset(rctx->sample_positions, 0, 4 * 4 * 16);
- for (i = 0; i < rctx->framebuffer.nr_samples; i++) {
+ for (unsigned i = 0; i < rctx->framebuffer.nr_samples; i++) {
ctx->get_sample_position(ctx, rctx->framebuffer.nr_samples, i, &rctx->sample_positions[4*i]);
/* Also fill in center-zeroed positions used for interpolateAtSample */
rctx->sample_positions[4*i + 2] = rctx->sample_positions[4*i + 0] - 0.5f;
}
}
+/* update MEM_SCRATCH buffers if needed */
+void r600_setup_scratch_area_for_shader(struct r600_context *rctx,
+ struct r600_pipe_shader *shader, struct r600_scratch_buffer *scratch,
+ unsigned ring_base_reg, unsigned item_size_reg, unsigned ring_size_reg)
+{
+ unsigned num_ses = rctx->screen->b.info.max_se;
+ unsigned num_pipes = rctx->screen->b.info.r600_max_quad_pipes;
+ unsigned nthreads = 128;
+
+ unsigned itemsize = shader->scratch_space_needed * 4;
+ unsigned size = align(itemsize * nthreads * num_pipes * num_ses * 4, 256);
+
+ if (scratch->dirty ||
+ unlikely(shader->scratch_space_needed != scratch->item_size ||
+ size > scratch->size)) {
+ struct radeon_cmdbuf *cs = rctx->b.gfx.cs;
+
+ scratch->dirty = false;
+
+ if (size > scratch->size) {
+ // Release prior one if any
+ if (scratch->buffer) {
+ pipe_resource_reference((struct pipe_resource**)&scratch->buffer, NULL);
+ }
+
+ scratch->buffer = (struct r600_resource *)pipe_buffer_create(rctx->b.b.screen, PIPE_BIND_CUSTOM,
+ PIPE_USAGE_DEFAULT, size);
+ if (scratch->buffer) {
+ scratch->size = size;
+ }
+ }
+
+ scratch->item_size = shader->scratch_space_needed;
+
+ radeon_set_config_reg(cs, R_008040_WAIT_UNTIL, S_008040_WAIT_3D_IDLE(1));
+ radeon_emit(cs, PKT3(PKT3_EVENT_WRITE, 0, 0));
+ radeon_emit(cs, EVENT_TYPE(EVENT_TYPE_VGT_FLUSH));
+
+ // multi-SE chips need programming per SE
+ for (unsigned se = 0; se < num_ses; se++) {
+ struct r600_resource *rbuffer = scratch->buffer;
+ unsigned size_per_se = size / num_ses;
+
+ // Direct to particular SE
+ if (num_ses > 1) {
+ radeon_set_config_reg(cs, EG_0802C_GRBM_GFX_INDEX,
+ S_0802C_INSTANCE_INDEX(0) |
+ S_0802C_SE_INDEX(se) |
+ S_0802C_INSTANCE_BROADCAST_WRITES(1) |
+ S_0802C_SE_BROADCAST_WRITES(0));
+ }
+
+ radeon_set_config_reg(cs, ring_base_reg, (rbuffer->gpu_address + size_per_se * se) >> 8);
+ radeon_emit(cs, PKT3(PKT3_NOP, 0, 0));
+ radeon_emit(cs, radeon_add_to_buffer_list(&rctx->b, &rctx->b.gfx, rbuffer,
+ RADEON_USAGE_READWRITE,
+ RADEON_PRIO_SCRATCH_BUFFER));
+ radeon_set_context_reg(cs, item_size_reg, itemsize);
+ radeon_set_config_reg(cs, ring_size_reg, size_per_se >> 8);
+ }
+
+ // Restore broadcast mode
+ if (num_ses > 1) {
+ radeon_set_config_reg(cs, EG_0802C_GRBM_GFX_INDEX,
+ S_0802C_INSTANCE_INDEX(0) |
+ S_0802C_SE_INDEX(0) |
+ S_0802C_INSTANCE_BROADCAST_WRITES(1) |
+ S_0802C_SE_BROADCAST_WRITES(1));
+ }
+
+ radeon_set_config_reg(cs, R_008040_WAIT_UNTIL, S_008040_WAIT_3D_IDLE(1));
+ radeon_emit(cs, PKT3(PKT3_EVENT_WRITE, 0, 0));
+ radeon_emit(cs, EVENT_TYPE(EVENT_TYPE_VGT_FLUSH));
+ }
+}
+
+void r600_setup_scratch_buffers(struct r600_context *rctx) {
+ static const struct {
+ unsigned ring_base;
+ unsigned item_size;
+ unsigned ring_size;
+ } regs[R600_NUM_HW_STAGES] = {
+ [R600_HW_STAGE_PS] = { R_008C68_SQ_PSTMP_RING_BASE, R_0288BC_SQ_PSTMP_RING_ITEMSIZE, R_008C6C_SQ_PSTMP_RING_SIZE },
+ [R600_HW_STAGE_VS] = { R_008C60_SQ_VSTMP_RING_BASE, R_0288B8_SQ_VSTMP_RING_ITEMSIZE, R_008C64_SQ_VSTMP_RING_SIZE },
+ [R600_HW_STAGE_GS] = { R_008C58_SQ_GSTMP_RING_BASE, R_0288B4_SQ_GSTMP_RING_ITEMSIZE, R_008C5C_SQ_GSTMP_RING_SIZE },
+ [R600_HW_STAGE_ES] = { R_008C50_SQ_ESTMP_RING_BASE, R_0288B0_SQ_ESTMP_RING_ITEMSIZE, R_008C54_SQ_ESTMP_RING_SIZE }
+ };
+
+ for (unsigned i = 0; i < R600_NUM_HW_STAGES; i++) {
+ struct r600_pipe_shader *stage = rctx->hw_shader_stages[i].shader;
+
+ if (stage && unlikely(stage->scratch_space_needed)) {
+ r600_setup_scratch_area_for_shader(rctx, stage,
+ &rctx->scratch_buffers[i], regs[i].ring_base, regs[i].item_size, regs[i].ring_size);
+ }
+ }
+}
+
#define SELECT_SHADER_OR_FAIL(x) do { \
r600_shader_select(ctx, rctx->x##_shader, &x##_dirty); \
if (unlikely(!rctx->x##_shader->current)) \
}
}
+ /*
+ * XXX: I believe there's some fatal flaw in the dirty state logic when
+ * enabling/disabling tes.
+ * VS/ES share all buffer/resource/sampler slots. If TES is enabled,
+ * it will therefore overwrite the VS slots. If it now gets disabled,
+ * the VS needs to rebind all buffer/resource/sampler slots - not only
+ * has TES overwritten the corresponding slots, but when the VS was
+ * operating as LS the things with correpsonding dirty bits got bound
+ * to LS slots and won't reflect what is dirty as VS stage even if the
+ * TES didn't overwrite it. The story for re-enabled TES is similar.
+ * In any case, we're not allowed to submit any TES state when
+ * TES is disabled (the state tracker may not do this but this looks
+ * like an optimization to me, not something which can be relied on).
+ */
+
/* Update clip misc state. */
if (clip_so_current) {
r600_update_clip_state(rctx, clip_so_current);
rctx->rasterizer->sprite_coord_enable != rctx->ps_shader->current->sprite_coord_enable ||
rctx->rasterizer->flatshade != rctx->ps_shader->current->flatshade)) {
- if (rctx->cb_misc_state.nr_ps_color_outputs != rctx->ps_shader->current->nr_ps_color_outputs) {
+ if (rctx->cb_misc_state.nr_ps_color_outputs != rctx->ps_shader->current->nr_ps_color_outputs ||
+ rctx->cb_misc_state.ps_color_export_mask != rctx->ps_shader->current->ps_color_export_mask) {
rctx->cb_misc_state.nr_ps_color_outputs = rctx->ps_shader->current->nr_ps_color_outputs;
+ rctx->cb_misc_state.ps_color_export_mask = rctx->ps_shader->current->ps_color_export_mask;
r600_mark_atom_dirty(rctx, &rctx->cb_misc_state.atom);
}
r600_update_db_shader_control(rctx);
}
+ /* For each shader stage that needs to spill, set up buffer for MEM_SCRATCH */
+ if (rctx->b.chip_class >= EVERGREEN) {
+ evergreen_setup_scratch_buffers(rctx);
+ } else {
+ r600_setup_scratch_buffers(rctx);
+ }
+
/* on R600 we stuff masks + txq info into one constant buffer */
/* on evergreen we only need a txq info one */
if (rctx->ps_shader) {
void r600_emit_clip_misc_state(struct r600_context *rctx, struct r600_atom *atom)
{
- struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
+ struct radeon_cmdbuf *cs = rctx->b.gfx.cs;
struct r600_clip_misc_state *state = &rctx->clip_misc_state;
radeon_set_context_reg(cs, R_028810_PA_CL_CLIP_CNTL,
/* rast_prim is the primitive type after GS. */
static inline void r600_emit_rasterizer_prim_state(struct r600_context *rctx)
{
- struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
+ struct radeon_cmdbuf *cs = rctx->b.gfx.cs;
enum pipe_prim_type rast_prim = rctx->current_rast_prim;
/* Skip this if not rendering lines. */
{
struct r600_context *rctx = (struct r600_context *)ctx;
struct pipe_resource *indexbuf = info->has_user_indices ? NULL : info->index.resource;
- struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
+ struct radeon_cmdbuf *cs = rctx->b.gfx.cs;
bool render_cond_bit = rctx->b.render_cond && !rctx->b.render_cond_force_off;
bool has_user_indices = info->has_user_indices;
uint64_t mask;
: (rctx->tes_shader)? rctx->tes_shader->info.properties[TGSI_PROPERTY_TES_PRIM_MODE]
: info->mode;
- if (rctx->b.chip_class >= EVERGREEN)
- evergreen_emit_atomic_buffer_setup(rctx, NULL, combined_atomics, &atomic_used_mask);
+ if (rctx->b.chip_class >= EVERGREEN) {
+ evergreen_emit_atomic_buffer_setup_count(rctx, NULL, combined_atomics, &atomic_used_mask);
+ }
if (index_size) {
index_offset += info->start * index_size;
evergreen_setup_tess_constants(rctx, info, &num_patches);
/* Emit states. */
- r600_need_cs_space(rctx, has_user_indices ? 5 : 0, TRUE);
+ r600_need_cs_space(rctx, has_user_indices ? 5 : 0, TRUE, util_bitcount(atomic_used_mask));
r600_flush_emit(rctx);
mask = rctx->dirty_atoms;
r600_emit_atom(rctx, rctx->atoms[u_bit_scan64(&mask)]);
}
+ if (rctx->b.chip_class >= EVERGREEN) {
+ evergreen_emit_atomic_buffer_setup(rctx, false, combined_atomics, atomic_used_mask);
+ }
+
if (rctx->b.chip_class == CAYMAN) {
/* Copied from radeonsi. */
unsigned primgroup_size = 128; /* recommended without a GS */
void r600_emit_shader(struct r600_context *rctx, struct r600_atom *a)
{
- struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
+ struct radeon_cmdbuf *cs = rctx->b.gfx.cs;
struct r600_pipe_shader *shader = ((struct r600_shader_state*)a)->shader;
if (!shader)
switch (desc->nr_channels) {
case 1:
result = FMT_8;
+ is_srgb_valid = TRUE;
goto out_word4;
case 2:
result = FMT_8_8;
}
-static void r600_set_active_query_state(struct pipe_context *ctx, boolean enable)
+static void r600_set_active_query_state(struct pipe_context *ctx, bool enable)
{
struct r600_context *rctx = (struct r600_context*)ctx;
static void r600_need_gfx_cs_space(struct pipe_context *ctx, unsigned num_dw,
bool include_draw_vbo)
{
- r600_need_cs_space((struct r600_context*)ctx, num_dw, include_draw_vbo);
+ r600_need_cs_space((struct r600_context*)ctx, num_dw, include_draw_vbo, 0);
}
/* keep this at the end of this file, please */
rctx->b.b.texture_barrier = r600_texture_barrier;
rctx->b.b.set_stream_output_targets = r600_set_streamout_targets;
rctx->b.b.set_active_query_state = r600_set_active_query_state;
+
rctx->b.b.draw_vbo = r600_draw_vbo;
rctx->b.invalidate_buffer = r600_invalidate_buffer;
rctx->b.need_gfx_cs_space = r600_need_gfx_cs_space;