radeonsi: try to fix IA_MULTI_VGT_PARAM programming
[mesa.git] / src / gallium / drivers / radeonsi / si_state_draw.c
index 47e64d8634e6caa002c786b6c526e1349749a8c0..1467bb69d4be90800d538ed5c347b73808c6cda4 100644 (file)
@@ -31,6 +31,7 @@
 #include "radeonsi_pipe.h"
 #include "radeonsi_shader.h"
 #include "si_state.h"
+#include "../radeon/r600_cs.h"
 #include "sid.h"
 
 /*
@@ -51,8 +52,6 @@ static void si_pipe_shader_vs(struct pipe_context *ctx, struct si_pipe_shader *s
        if (pm4 == NULL)
                return;
 
-       si_pm4_inval_shader_cache(pm4);
-
        /* Certain attributes (position, psize, etc.) don't count as params.
         * VS is required to export at least one param and r600_shader_from_tgsi()
         * takes care of adding a dummy export.
@@ -105,9 +104,14 @@ static void si_pipe_shader_vs(struct pipe_context *ctx, struct si_pipe_shader *s
                       S_00B128_SGPRS((num_sgprs - 1) / 8) |
                       S_00B128_VGPR_COMP_CNT(vgpr_comp_cnt));
        si_pm4_set_reg(pm4, R_00B12C_SPI_SHADER_PGM_RSRC2_VS,
-                      S_00B12C_USER_SGPR(num_user_sgprs));
-
-       if (rctx->chip_class >= CIK) {
+                      S_00B12C_USER_SGPR(num_user_sgprs) |
+                      S_00B12C_SO_BASE0_EN(!!shader->selector->so.stride[0]) |
+                      S_00B12C_SO_BASE1_EN(!!shader->selector->so.stride[1]) |
+                      S_00B12C_SO_BASE2_EN(!!shader->selector->so.stride[2]) |
+                      S_00B12C_SO_BASE3_EN(!!shader->selector->so.stride[3]) |
+                      S_00B12C_SO_EN(!!shader->selector->so.num_outputs));
+
+       if (rctx->b.chip_class >= CIK) {
                si_pm4_set_reg(pm4, R_00B118_SPI_SHADER_PGM_RSRC3_VS,
                               S_00B118_CU_EN(0xffff));
                si_pm4_set_reg(pm4, R_00B11C_SPI_SHADER_LATE_ALLOC_VS,
@@ -115,6 +119,7 @@ static void si_pipe_shader_vs(struct pipe_context *ctx, struct si_pipe_shader *s
        }
 
        si_pm4_bind_state(rctx, vs, shader->pm4);
+       rctx->b.flags |= R600_CONTEXT_INV_SHADER_CACHE;
 }
 
 static void si_pipe_shader_ps(struct pipe_context *ctx, struct si_pipe_shader *shader)
@@ -123,9 +128,7 @@ static void si_pipe_shader_ps(struct pipe_context *ctx, struct si_pipe_shader *s
        struct si_pm4_state *pm4;
        unsigned i, exports_ps, num_cout, spi_ps_in_control, db_shader_control;
        unsigned num_sgprs, num_user_sgprs;
-       boolean have_linear = FALSE, have_centroid = FALSE, have_perspective = FALSE;
-       unsigned fragcoord_interp_mode = 0;
-       unsigned spi_baryc_cntl, spi_ps_input_ena, spi_shader_z_format;
+       unsigned spi_baryc_cntl = 0, spi_ps_input_ena, spi_shader_z_format;
        uint64_t va;
 
        si_pm4_delete_state(rctx, ps, shader->pm4);
@@ -134,34 +137,26 @@ static void si_pipe_shader_ps(struct pipe_context *ctx, struct si_pipe_shader *s
        if (pm4 == NULL)
                return;
 
-       si_pm4_inval_shader_cache(pm4);
+       db_shader_control = S_02880C_Z_ORDER(V_02880C_EARLY_Z_THEN_LATE_Z) |
+                           S_02880C_ALPHA_TO_MASK_DISABLE(rctx->fb_cb0_is_integer);
 
-       db_shader_control = S_02880C_Z_ORDER(V_02880C_EARLY_Z_THEN_LATE_Z);
        for (i = 0; i < shader->shader.ninput; i++) {
                switch (shader->shader.input[i].name) {
                case TGSI_SEMANTIC_POSITION:
                        if (shader->shader.input[i].centroid) {
-                               /* fragcoord_interp_mode will be written to
-                                * SPI_BARYC_CNTL.POS_FLOAT_LOCATION
+                               /* SPI_BARYC_CNTL.POS_FLOAT_LOCATION
                                 * Possible vaules:
                                 * 0 -> Position = pixel center (default)
                                 * 1 -> Position = pixel centroid
                                 * 2 -> Position = iterated sample number XXX:
                                 *                        What does this mean?
                                 */
-                               fragcoord_interp_mode = 1;
+                               spi_baryc_cntl |= S_0286E0_POS_FLOAT_LOCATION(1);
                        }
                        /* Fall through */
                case TGSI_SEMANTIC_FACE:
                        continue;
                }
-
-               if (shader->shader.input[i].interpolate == TGSI_INTERPOLATE_LINEAR)
-                       have_linear = TRUE;
-               if (shader->shader.input[i].interpolate == TGSI_INTERPOLATE_PERSPECTIVE)
-                       have_perspective = TRUE;
-               if (shader->shader.input[i].centroid)
-                       have_centroid = TRUE;
        }
 
        for (i = 0; i < shader->shader.noutput; i++) {
@@ -191,16 +186,8 @@ static void si_pipe_shader_ps(struct pipe_context *ctx, struct si_pipe_shader *s
                exports_ps = 2;
        }
 
-       spi_ps_in_control = S_0286D8_NUM_INTERP(shader->shader.ninterp);
-
-       spi_baryc_cntl = 0;
-       if (have_perspective)
-               spi_baryc_cntl |= have_centroid ?
-                       S_0286E0_PERSP_CENTROID_CNTL(1) : S_0286E0_PERSP_CENTER_CNTL(1);
-       if (have_linear)
-               spi_baryc_cntl |= have_centroid ?
-                       S_0286E0_LINEAR_CENTROID_CNTL(1) : S_0286E0_LINEAR_CENTER_CNTL(1);
-       spi_baryc_cntl |= S_0286E0_POS_FLOAT_LOCATION(fragcoord_interp_mode);
+       spi_ps_in_control = S_0286D8_NUM_INTERP(shader->shader.ninterp) |
+               S_0286D8_BC_OPTIMIZE_DISABLE(1);
 
        si_pm4_set_reg(pm4, R_0286E0_SPI_BARYC_CNTL, spi_baryc_cntl);
        spi_ps_input_ena = shader->spi_ps_input_ena;
@@ -249,15 +236,17 @@ static void si_pipe_shader_ps(struct pipe_context *ctx, struct si_pipe_shader *s
        si_pm4_set_reg(pm4, R_00B02C_SPI_SHADER_PGM_RSRC2_PS,
                       S_00B02C_EXTRA_LDS_SIZE(shader->lds_size) |
                       S_00B02C_USER_SGPR(num_user_sgprs));
-       if (rctx->chip_class >= CIK) {
+       if (rctx->b.chip_class >= CIK) {
                si_pm4_set_reg(pm4, R_00B01C_SPI_SHADER_PGM_RSRC3_PS,
                               S_00B01C_CU_EN(0xffff));
        }
 
        si_pm4_set_reg(pm4, R_02880C_DB_SHADER_CONTROL, db_shader_control);
 
+       shader->cb0_is_integer = rctx->fb_cb0_is_integer;
        shader->sprite_coord_enable = rctx->sprite_coord_enable;
        si_pm4_bind_state(rctx, ps, shader->pm4);
+       rctx->b.flags |= R600_CONTEXT_INV_SHADER_CACHE;
 }
 
 /*
@@ -289,12 +278,37 @@ static unsigned si_conv_pipe_prim(unsigned pprim)
        return result;
 }
 
+static unsigned r600_conv_prim_to_gs_out(unsigned mode)
+{
+       static const int prim_conv[] = {
+               [PIPE_PRIM_POINTS]                      = V_028A6C_OUTPRIM_TYPE_POINTLIST,
+               [PIPE_PRIM_LINES]                       = V_028A6C_OUTPRIM_TYPE_LINESTRIP,
+               [PIPE_PRIM_LINE_LOOP]                   = V_028A6C_OUTPRIM_TYPE_LINESTRIP,
+               [PIPE_PRIM_LINE_STRIP]                  = V_028A6C_OUTPRIM_TYPE_LINESTRIP,
+               [PIPE_PRIM_TRIANGLES]                   = V_028A6C_OUTPRIM_TYPE_TRISTRIP,
+               [PIPE_PRIM_TRIANGLE_STRIP]              = V_028A6C_OUTPRIM_TYPE_TRISTRIP,
+               [PIPE_PRIM_TRIANGLE_FAN]                = V_028A6C_OUTPRIM_TYPE_TRISTRIP,
+               [PIPE_PRIM_QUADS]                       = V_028A6C_OUTPRIM_TYPE_TRISTRIP,
+               [PIPE_PRIM_QUAD_STRIP]                  = V_028A6C_OUTPRIM_TYPE_TRISTRIP,
+               [PIPE_PRIM_POLYGON]                     = V_028A6C_OUTPRIM_TYPE_TRISTRIP,
+               [PIPE_PRIM_LINES_ADJACENCY]             = V_028A6C_OUTPRIM_TYPE_LINESTRIP,
+               [PIPE_PRIM_LINE_STRIP_ADJACENCY]        = V_028A6C_OUTPRIM_TYPE_LINESTRIP,
+               [PIPE_PRIM_TRIANGLES_ADJACENCY]         = V_028A6C_OUTPRIM_TYPE_TRISTRIP,
+               [PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY]    = V_028A6C_OUTPRIM_TYPE_TRISTRIP
+       };
+       assert(mode < Elements(prim_conv));
+
+       return prim_conv[mode];
+}
+
 static bool si_update_draw_info_state(struct r600_context *rctx,
-                              const struct pipe_draw_info *info)
+                                     const struct pipe_draw_info *info,
+                                     const struct pipe_index_buffer *ib)
 {
        struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
        struct si_shader *vs = &rctx->vs_shader->current->shader;
        unsigned prim = si_conv_pipe_prim(info->mode);
+       unsigned gs_out_prim = r600_conv_prim_to_gs_out(info->mode);
        unsigned ls_mask = 0;
 
        if (pm4 == NULL)
@@ -305,10 +319,31 @@ static bool si_update_draw_info_state(struct r600_context *rctx,
                return false;
        }
 
-       if (rctx->chip_class >= CIK)
+       if (rctx->b.chip_class >= CIK) {
+               struct si_state_rasterizer *rs = rctx->queued.named.rasterizer;
+               bool wd_switch_on_eop = prim == V_008958_DI_PT_POLYGON ||
+                                       prim == V_008958_DI_PT_LINELOOP ||
+                                       prim == V_008958_DI_PT_TRIFAN ||
+                                       prim == V_008958_DI_PT_TRISTRIP_ADJ ||
+                                       info->primitive_restart ||
+                                       (rs ? rs->line_stipple_enable : false);
+               /* If the WD switch is false, the IA switch must be false too. */
+               bool ia_switch_on_eop = wd_switch_on_eop;
+
+               si_pm4_set_reg(pm4, R_028AA8_IA_MULTI_VGT_PARAM,
+                              S_028AA8_SWITCH_ON_EOP(ia_switch_on_eop) |
+                              S_028AA8_PARTIAL_VS_WAVE_ON(1) |
+                              S_028AA8_PRIMGROUP_SIZE(63) |
+                              S_028AA8_WD_SWITCH_ON_EOP(wd_switch_on_eop));
+               si_pm4_set_reg(pm4, R_028B74_VGT_DISPATCH_DRAW_INDEX,
+                              ib->index_size == 4 ? 0xFC000000 : 0xFC00);
+
                si_pm4_set_reg(pm4, R_030908_VGT_PRIMITIVE_TYPE, prim);
-       else
+       } else {
                si_pm4_set_reg(pm4, R_008958_VGT_PRIMITIVE_TYPE, prim);
+       }
+
+       si_pm4_set_reg(pm4, R_028A6C_VGT_GS_OUT_PRIM_TYPE, gs_out_prim);
        si_pm4_set_reg(pm4, R_028400_VGT_MAX_VTX_INDX, ~0);
        si_pm4_set_reg(pm4, R_028404_VGT_MIN_VTX_INDX, 0);
        si_pm4_set_reg(pm4, R_028408_VGT_INDX_OFFSET,
@@ -412,11 +447,13 @@ static void si_update_derived_state(struct r600_context *rctx)
 
        if (!rctx->blitter->running) {
                /* Flush depth textures which need to be flushed. */
-               if (rctx->vs_samplers.depth_texture_mask) {
-                       si_flush_depth_textures(rctx, &rctx->vs_samplers);
-               }
-               if (rctx->ps_samplers.depth_texture_mask) {
-                       si_flush_depth_textures(rctx, &rctx->ps_samplers);
+               for (int i = 0; i < SI_NUM_SHADERS; i++) {
+                       if (rctx->samplers[i].depth_texture_mask) {
+                               si_flush_depth_textures(rctx, &rctx->samplers[i]);
+                       }
+                       if (rctx->samplers[i].compressed_colortex_mask) {
+                               r600_decompress_color_textures(rctx, &rctx->samplers[i]);
+                       }
                }
        }
 
@@ -446,6 +483,10 @@ static void si_update_derived_state(struct r600_context *rctx)
 
                ps_dirty = 0;
        }
+       if (rctx->ps_shader->current->cb0_is_integer != rctx->fb_cb0_is_integer) {
+               si_pipe_shader_ps(ctx, rctx->ps_shader->current);
+               ps_dirty = 1;
+       }
 
        if (ps_dirty) {
                si_pm4_bind_state(rctx, ps, rctx->ps_shader->current->pm4);
@@ -461,89 +502,16 @@ static void si_update_derived_state(struct r600_context *rctx)
        }
 }
 
-static void si_constant_buffer_update(struct r600_context *rctx)
-{
-       struct pipe_context *ctx = &rctx->context;
-       struct si_pm4_state *pm4;
-       unsigned shader, i;
-       uint64_t va;
-
-       if (!rctx->constbuf_state[PIPE_SHADER_VERTEX].dirty_mask &&
-           !rctx->constbuf_state[PIPE_SHADER_FRAGMENT].dirty_mask)
-               return;
-
-       for (shader = PIPE_SHADER_VERTEX ; shader <= PIPE_SHADER_FRAGMENT; shader++) {
-               struct r600_constbuf_state *state = &rctx->constbuf_state[shader];
-
-               pm4 = CALLOC_STRUCT(si_pm4_state);
-               if (!pm4)
-                       continue;
-
-               si_pm4_inval_shader_cache(pm4);
-               si_pm4_sh_data_begin(pm4);
-
-               for (i = 0; i < 2; i++) {
-                       if (state->enabled_mask & (1 << i)) {
-                               struct pipe_constant_buffer *cb = &state->cb[i];
-                               struct si_resource *rbuffer = si_resource(cb->buffer);
-
-                               va = r600_resource_va(ctx->screen, (void*)rbuffer);
-                               va += cb->buffer_offset;
-
-                               si_pm4_add_bo(pm4, rbuffer, RADEON_USAGE_READ);
-
-                               /* Fill in a T# buffer resource description */
-                               si_pm4_sh_data_add(pm4, va);
-                               si_pm4_sh_data_add(pm4, (S_008F04_BASE_ADDRESS_HI(va >> 32) |
-                                                        S_008F04_STRIDE(0)));
-                               si_pm4_sh_data_add(pm4, cb->buffer_size);
-                               si_pm4_sh_data_add(pm4, S_008F0C_DST_SEL_X(V_008F0C_SQ_SEL_X) |
-                                                  S_008F0C_DST_SEL_Y(V_008F0C_SQ_SEL_Y) |
-                                                  S_008F0C_DST_SEL_Z(V_008F0C_SQ_SEL_Z) |
-                                                  S_008F0C_DST_SEL_W(V_008F0C_SQ_SEL_W) |
-                                                  S_008F0C_NUM_FORMAT(V_008F0C_BUF_NUM_FORMAT_FLOAT) |
-                                                  S_008F0C_DATA_FORMAT(V_008F0C_BUF_DATA_FORMAT_32));
-                       } else {
-                               /* Fill in an empty T# buffer resource description */
-                               si_pm4_sh_data_add(pm4, 0);
-                               si_pm4_sh_data_add(pm4, 0);
-                               si_pm4_sh_data_add(pm4, 0);
-                               si_pm4_sh_data_add(pm4, 0);
-                       }
-               }
-
-               switch (shader) {
-               case PIPE_SHADER_VERTEX:
-                       si_pm4_sh_data_end(pm4, R_00B130_SPI_SHADER_USER_DATA_VS_0, SI_SGPR_CONST);
-                       si_pm4_set_state(rctx, vs_const, pm4);
-                       break;
-
-               case PIPE_SHADER_FRAGMENT:
-                       si_pm4_sh_data_end(pm4, R_00B030_SPI_SHADER_USER_DATA_PS_0, SI_SGPR_CONST);
-                       si_pm4_set_state(rctx, ps_const, pm4);
-                       break;
-
-               default:
-                       R600_ERR("unsupported %d\n", shader);
-                       FREE(pm4);
-                       return;
-               }
-
-               state->dirty_mask = 0;
-       }
-}
-
 static void si_vertex_buffer_update(struct r600_context *rctx)
 {
-       struct pipe_context *ctx = &rctx->context;
+       struct pipe_context *ctx = &rctx->b.b;
        struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
        bool bound[PIPE_MAX_ATTRIBS] = {};
        unsigned i, count;
        uint64_t va;
 
-       si_pm4_inval_texture_cache(pm4);
+       rctx->b.flags |= R600_CONTEXT_INV_TEX_CACHE;
 
-       /* bind vertex buffer once */
        count = rctx->vertex_elements->count;
        assert(count <= 256 / 4);
 
@@ -551,14 +519,14 @@ static void si_vertex_buffer_update(struct r600_context *rctx)
        for (i = 0 ; i < count; i++) {
                struct pipe_vertex_element *ve = &rctx->vertex_elements->elements[i];
                struct pipe_vertex_buffer *vb;
-               struct si_resource *rbuffer;
+               struct r600_resource *rbuffer;
                unsigned offset;
 
                if (ve->vertex_buffer_index >= rctx->nr_vertex_buffers)
                        continue;
 
                vb = &rctx->vertex_buffer[ve->vertex_buffer_index];
-               rbuffer = (struct si_resource*)vb->buffer;
+               rbuffer = (struct r600_resource*)vb->buffer;
                if (rbuffer == NULL)
                        continue;
 
@@ -603,16 +571,49 @@ static void si_state_draw(struct r600_context *rctx,
 
        /* queries need some special values
         * (this is non-zero if any query is active) */
-       if (rctx->num_cs_dw_queries_suspend) {
+       if (rctx->num_cs_dw_nontimer_queries_suspend) {
                struct si_state_dsa *dsa = rctx->queued.named.dsa;
 
-               si_pm4_set_reg(pm4, R_028004_DB_COUNT_CONTROL,
-                              S_028004_PERFECT_ZPASS_COUNTS(1));
+               if (rctx->b.chip_class >= CIK) {
+                       si_pm4_set_reg(pm4, R_028004_DB_COUNT_CONTROL,
+                                      S_028004_PERFECT_ZPASS_COUNTS(1) |
+                                      S_028004_SAMPLE_RATE(rctx->fb_log_samples) |
+                                      S_028004_ZPASS_ENABLE(1) |
+                                      S_028004_SLICE_EVEN_ENABLE(1) |
+                                      S_028004_SLICE_ODD_ENABLE(1));
+               } else {
+                       si_pm4_set_reg(pm4, R_028004_DB_COUNT_CONTROL,
+                                      S_028004_PERFECT_ZPASS_COUNTS(1) |
+                                      S_028004_SAMPLE_RATE(rctx->fb_log_samples));
+               }
                si_pm4_set_reg(pm4, R_02800C_DB_RENDER_OVERRIDE,
                               dsa->db_render_override |
                               S_02800C_NOOP_CULL_DISABLE(1));
        }
 
+       if (info->count_from_stream_output) {
+               struct r600_so_target *t =
+                       (struct r600_so_target*)info->count_from_stream_output;
+               uint64_t va = r600_resource_va(&rctx->screen->b.b,
+                                              &t->buf_filled_size->b.b);
+               va += t->buf_filled_size_offset;
+
+               si_pm4_set_reg(pm4, R_028B30_VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE,
+                              t->stride_in_dw);
+
+               si_pm4_cmd_begin(pm4, PKT3_COPY_DATA);
+               si_pm4_cmd_add(pm4,
+                              COPY_DATA_SRC_SEL(COPY_DATA_MEM) |
+                              COPY_DATA_DST_SEL(COPY_DATA_REG) |
+                              COPY_DATA_WR_CONFIRM);
+               si_pm4_cmd_add(pm4, va);     /* src address lo */
+               si_pm4_cmd_add(pm4, va >> 32UL); /* src address hi */
+               si_pm4_cmd_add(pm4, R_028B2C_VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE >> 2);
+               si_pm4_cmd_add(pm4, 0); /* unused */
+               si_pm4_add_bo(pm4, t->buf_filled_size, RADEON_USAGE_READ);
+               si_pm4_cmd_end(pm4, true);
+       }
+
        /* draw packet */
        si_pm4_cmd_begin(pm4, PKT3_INDEX_TYPE);
        if (ib->index_size == 4) {
@@ -632,10 +633,10 @@ static void si_state_draw(struct r600_context *rctx,
                uint32_t max_size = (ib->buffer->width0 - ib->offset) /
                                 rctx->index_buffer.index_size;
                uint64_t va;
-               va = r600_resource_va(&rctx->screen->screen, ib->buffer);
+               va = r600_resource_va(&rctx->screen->b.b, ib->buffer);
                va += ib->offset;
 
-               si_pm4_add_bo(pm4, (struct si_resource *)ib->buffer, RADEON_USAGE_READ);
+               si_pm4_add_bo(pm4, (struct r600_resource *)ib->buffer, RADEON_USAGE_READ);
                si_cmd_draw_index_2(pm4, max_size, va, info->count,
                                    V_0287F0_DI_SRC_SEL_DMA,
                                    rctx->predicate_drawing);
@@ -647,11 +648,83 @@ static void si_state_draw(struct r600_context *rctx,
        si_pm4_set_state(rctx, draw, pm4);
 }
 
+void si_emit_cache_flush(struct r600_common_context *rctx, struct r600_atom *atom)
+{
+       struct radeon_winsys_cs *cs = rctx->rings.gfx.cs;
+       uint32_t cp_coher_cntl = 0;
+
+       /* XXX SI flushes both ICACHE and KCACHE if either flag is set.
+        * XXX CIK shouldn't have this issue. Test CIK before separating the flags
+        * XXX to ensure there is no regression. Also find out if there is another
+        * XXX way to flush either ICACHE or KCACHE but not both for SI. */
+       if (rctx->flags & (R600_CONTEXT_INV_SHADER_CACHE |
+                          R600_CONTEXT_INV_CONST_CACHE)) {
+               cp_coher_cntl |= S_0085F0_SH_ICACHE_ACTION_ENA(1) |
+                                S_0085F0_SH_KCACHE_ACTION_ENA(1);
+       }
+       if (rctx->flags & (R600_CONTEXT_INV_TEX_CACHE |
+                          R600_CONTEXT_STREAMOUT_FLUSH)) {
+               cp_coher_cntl |= S_0085F0_TC_ACTION_ENA(1) |
+                                S_0085F0_TCL1_ACTION_ENA(1);
+       }
+       if (rctx->flags & R600_CONTEXT_FLUSH_AND_INV_CB) {
+               cp_coher_cntl |= S_0085F0_CB_ACTION_ENA(1) |
+                                S_0085F0_CB0_DEST_BASE_ENA(1) |
+                                S_0085F0_CB1_DEST_BASE_ENA(1) |
+                                S_0085F0_CB2_DEST_BASE_ENA(1) |
+                                S_0085F0_CB3_DEST_BASE_ENA(1) |
+                                S_0085F0_CB4_DEST_BASE_ENA(1) |
+                                S_0085F0_CB5_DEST_BASE_ENA(1) |
+                                S_0085F0_CB6_DEST_BASE_ENA(1) |
+                                S_0085F0_CB7_DEST_BASE_ENA(1);
+       }
+       if (rctx->flags & R600_CONTEXT_FLUSH_AND_INV_DB) {
+               cp_coher_cntl |= S_0085F0_DB_ACTION_ENA(1) |
+                                S_0085F0_DB_DEST_BASE_ENA(1);
+       }
+
+       if (cp_coher_cntl) {
+               if (rctx->chip_class >= CIK) {
+                       radeon_emit(cs, PKT3(PKT3_ACQUIRE_MEM, 5, 0));
+                       radeon_emit(cs, cp_coher_cntl);   /* CP_COHER_CNTL */
+                       radeon_emit(cs, 0xffffffff);      /* CP_COHER_SIZE */
+                       radeon_emit(cs, 0xff);            /* CP_COHER_SIZE_HI */
+                       radeon_emit(cs, 0);               /* CP_COHER_BASE */
+                       radeon_emit(cs, 0);               /* CP_COHER_BASE_HI */
+                       radeon_emit(cs, 0x0000000A);      /* POLL_INTERVAL */
+               } else {
+                       radeon_emit(cs, PKT3(PKT3_SURFACE_SYNC, 3, 0));
+                       radeon_emit(cs, cp_coher_cntl);   /* CP_COHER_CNTL */
+                       radeon_emit(cs, 0xffffffff);      /* CP_COHER_SIZE */
+                       radeon_emit(cs, 0);               /* CP_COHER_BASE */
+                       radeon_emit(cs, 0x0000000A);      /* POLL_INTERVAL */
+               }
+       }
+
+       if (rctx->flags & R600_CONTEXT_FLUSH_AND_INV_CB_META) {
+               radeon_emit(cs, PKT3(PKT3_EVENT_WRITE, 0, 0));
+               radeon_emit(cs, EVENT_TYPE(V_028A90_FLUSH_AND_INV_CB_META) | EVENT_INDEX(0));
+       }
+
+       if (rctx->flags & R600_CONTEXT_WAIT_3D_IDLE) {
+               radeon_emit(cs, PKT3(PKT3_EVENT_WRITE, 0, 0));
+               radeon_emit(cs, EVENT_TYPE(V_028A90_PS_PARTIAL_FLUSH) | EVENT_INDEX(4));
+       } else if (rctx->flags & R600_CONTEXT_STREAMOUT_FLUSH) {
+               /* Needed if streamout buffers are going to be used as a source. */
+               radeon_emit(cs, PKT3(PKT3_EVENT_WRITE, 0, 0));
+               radeon_emit(cs, EVENT_TYPE(V_028A90_VS_PARTIAL_FLUSH) | EVENT_INDEX(4));
+       }
+
+       rctx->flags = 0;
+}
+
+const struct r600_atom si_atom_cache_flush = { si_emit_cache_flush, 11 }; /* number of CS dwords */
+
 void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
 {
        struct r600_context *rctx = (struct r600_context *)ctx;
        struct pipe_index_buffer ib = {};
-       uint32_t cp_coher_cntl;
+       uint32_t i;
 
        if (!info->count && (info->indexed || !info->count_from_stream_output))
                return;
@@ -660,7 +733,6 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
                return;
 
        si_update_derived_state(rctx);
-       si_constant_buffer_update(rctx);
        si_vertex_buffer_update(rctx);
 
        if (info->indexed) {
@@ -676,33 +748,28 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
                if (ib.user_buffer && !ib.buffer) {
                        r600_upload_index_buffer(rctx, &ib, info->count);
                }
-
-       } else if (info->count_from_stream_output) {
-               r600_context_draw_opaque_count(rctx, (struct r600_so_target*)info->count_from_stream_output);
        }
 
-       rctx->vs_shader_so_strides = rctx->vs_shader->current->so_strides;
-
-       if (!si_update_draw_info_state(rctx, info))
+       if (!si_update_draw_info_state(rctx, info, &ib))
                return;
 
        si_state_draw(rctx, info, &ib);
 
-       cp_coher_cntl = si_pm4_sync_flags(rctx);
-       if (cp_coher_cntl) {
-               struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
+       rctx->pm4_dirty_cdwords += si_pm4_dirty_dw(rctx);
 
-               if (pm4 == NULL)
-                       return;
+       /* Check flush flags. */
+       if (rctx->b.flags)
+               rctx->atoms.cache_flush->dirty = true;
 
-               si_cmd_surface_sync(pm4, cp_coher_cntl);
-               si_pm4_set_state(rctx, sync, pm4);
-       }
+       si_need_cs_space(rctx, 0, TRUE);
 
        /* Emit states. */
-       rctx->pm4_dirty_cdwords += si_pm4_dirty_dw(rctx);
-
-       si_need_cs_space(rctx, 0, TRUE);
+       for (i = 0; i < SI_NUM_ATOMS(rctx); i++) {
+               if (rctx->atoms.array[i]->dirty) {
+                       rctx->atoms.array[i]->emit(&rctx->b, rctx->atoms.array[i]);
+                       rctx->atoms.array[i]->dirty = false;
+               }
+       }
 
        si_pm4_emit_dirty(rctx);
        rctx->pm4_dirty_cdwords = 0;
@@ -713,16 +780,6 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
        }
 #endif
 
-#if 0
-       /* Enable stream out if needed. */
-       if (rctx->streamout_start) {
-               r600_context_streamout_begin(rctx);
-               rctx->streamout_start = FALSE;
-       }
-#endif
-
-       rctx->flags |= R600_CONTEXT_DST_CACHES_DIRTY;
-
        /* Set the depth buffer as dirty. */
        if (rctx->framebuffer.zsbuf) {
                struct pipe_surface *surf = rctx->framebuffer.zsbuf;
@@ -730,6 +787,19 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
 
                rtex->dirty_level_mask |= 1 << surf->u.tex.level;
        }
+       if (rctx->fb_compressed_cb_mask) {
+               struct pipe_surface *surf;
+               struct r600_texture *rtex;
+               unsigned mask = rctx->fb_compressed_cb_mask;
+
+               do {
+                       unsigned i = u_bit_scan(&mask);
+                       surf = rctx->framebuffer.cbufs[i];
+                       rtex = (struct r600_texture*)surf->texture;
+
+                       rtex->dirty_level_mask |= 1 << surf->u.tex.level;
+               } while (mask);
+       }
 
        pipe_resource_reference(&ib.buffer, NULL);
 }