radeonsi: Rename r600->si for structs in si_resource.h.
[mesa.git] / src / gallium / drivers / radeonsi / si_state.c
index dec535ca597218d86dca09be6407427b61b50d27..46fc36ee14efb214343274193c31414b3699d9fd 100644 (file)
@@ -24,8 +24,6 @@
  *      Christian König <christian.koenig@amd.com>
  */
 
-#include <byteswap.h>
-
 #include "util/u_memory.h"
 #include "util/u_framebuffer.h"
 #include "util/u_blitter.h"
 #include "util/u_upload_mgr.h"
 #include "util/u_format_s3tc.h"
 #include "tgsi/tgsi_parse.h"
-#include "radeonsi_pipe.h"
-#include "radeonsi_shader.h"
+#include "tgsi/tgsi_scan.h"
+#include "si_pipe.h"
+#include "si_shader.h"
 #include "si_state.h"
+#include "../radeon/r600_cs.h"
 #include "sid.h"
 
+static uint32_t cik_num_banks(struct si_screen *rscreen, unsigned bpe, unsigned tile_split)
+{
+       if (rscreen->b.info.cik_macrotile_mode_array_valid) {
+               unsigned index, tileb;
+
+               tileb = 8 * 8 * bpe;
+               tileb = MIN2(tile_split, tileb);
+
+               for (index = 0; tileb > 64; index++) {
+                       tileb >>= 1;
+               }
+
+               assert(index < 16);
+
+               return (rscreen->b.info.cik_macrotile_mode_array[index] >> 6) & 0x3;
+       }
+
+       /* The old way. */
+       switch (rscreen->b.tiling_info.num_banks) {
+       case 2:
+               return V_02803C_ADDR_SURF_2_BANK;
+       case 4:
+               return V_02803C_ADDR_SURF_4_BANK;
+       case 8:
+       default:
+               return V_02803C_ADDR_SURF_8_BANK;
+       case 16:
+               return V_02803C_ADDR_SURF_16_BANK;
+       }
+}
+
+static unsigned cik_tile_split(unsigned tile_split)
+{
+       switch (tile_split) {
+       case 64:
+               tile_split = V_028040_ADDR_SURF_TILE_SPLIT_64B;
+               break;
+       case 128:
+               tile_split = V_028040_ADDR_SURF_TILE_SPLIT_128B;
+               break;
+       case 256:
+               tile_split = V_028040_ADDR_SURF_TILE_SPLIT_256B;
+               break;
+       case 512:
+               tile_split = V_028040_ADDR_SURF_TILE_SPLIT_512B;
+               break;
+       default:
+       case 1024:
+               tile_split = V_028040_ADDR_SURF_TILE_SPLIT_1KB;
+               break;
+       case 2048:
+               tile_split = V_028040_ADDR_SURF_TILE_SPLIT_2KB;
+               break;
+       case 4096:
+               tile_split = V_028040_ADDR_SURF_TILE_SPLIT_4KB;
+               break;
+       }
+       return tile_split;
+}
+
+static unsigned cik_macro_tile_aspect(unsigned macro_tile_aspect)
+{
+       switch (macro_tile_aspect) {
+       default:
+       case 1:
+               macro_tile_aspect = V_02803C_ADDR_SURF_MACRO_ASPECT_1;
+               break;
+       case 2:
+               macro_tile_aspect = V_02803C_ADDR_SURF_MACRO_ASPECT_2;
+               break;
+       case 4:
+               macro_tile_aspect = V_02803C_ADDR_SURF_MACRO_ASPECT_4;
+               break;
+       case 8:
+               macro_tile_aspect = V_02803C_ADDR_SURF_MACRO_ASPECT_8;
+               break;
+       }
+       return macro_tile_aspect;
+}
+
+static unsigned cik_bank_wh(unsigned bankwh)
+{
+       switch (bankwh) {
+       default:
+       case 1:
+               bankwh = V_02803C_ADDR_SURF_BANK_WIDTH_1;
+               break;
+       case 2:
+               bankwh = V_02803C_ADDR_SURF_BANK_WIDTH_2;
+               break;
+       case 4:
+               bankwh = V_02803C_ADDR_SURF_BANK_WIDTH_4;
+               break;
+       case 8:
+               bankwh = V_02803C_ADDR_SURF_BANK_WIDTH_8;
+               break;
+       }
+       return bankwh;
+}
+
+static unsigned cik_db_pipe_config(struct si_screen *rscreen, unsigned tile_mode)
+{
+       if (rscreen->b.info.si_tile_mode_array_valid) {
+               uint32_t gb_tile_mode = rscreen->b.info.si_tile_mode_array[tile_mode];
+
+               return G_009910_PIPE_CONFIG(gb_tile_mode);
+       }
+
+       /* This is probably broken for a lot of chips, but it's only used
+        * if the kernel cannot return the tile mode array for CIK. */
+       switch (rscreen->b.info.r600_num_tile_pipes) {
+       case 16:
+               return V_02803C_X_ADDR_SURF_P16_32X32_16X16;
+       case 8:
+               return V_02803C_X_ADDR_SURF_P8_32X32_16X16;
+       case 4:
+       default:
+               if (rscreen->b.info.r600_num_backends == 4)
+                       return V_02803C_X_ADDR_SURF_P4_16X16;
+               else
+                       return V_02803C_X_ADDR_SURF_P4_8X16;
+       case 2:
+               return V_02803C_ADDR_SURF_P2;
+       }
+}
+
 /*
  * inferred framebuffer and blender state
  */
-static void si_update_fb_blend_state(struct r600_context *rctx)
+static void si_update_fb_blend_state(struct si_context *rctx)
 {
        struct si_pm4_state *pm4;
        struct si_state_blend *blend = rctx->queued.named.blend;
@@ -52,7 +178,7 @@ static void si_update_fb_blend_state(struct r600_context *rctx)
        if (blend == NULL)
                return;
 
-       pm4 = CALLOC_STRUCT(si_pm4_state);
+       pm4 = si_pm4_alloc_state(rctx);
        if (pm4 == NULL)
                return;
 
@@ -137,27 +263,32 @@ static uint32_t si_translate_blend_factor(int blend_fact)
        return 0;
 }
 
-static void *si_create_blend_state(struct pipe_context *ctx,
-                                  const struct pipe_blend_state *state)
+static void *si_create_blend_state_mode(struct pipe_context *ctx,
+                                       const struct pipe_blend_state *state,
+                                       unsigned mode)
 {
        struct si_state_blend *blend = CALLOC_STRUCT(si_state_blend);
        struct si_pm4_state *pm4 = &blend->pm4;
 
-       uint32_t color_control;
+       uint32_t color_control = 0;
 
        if (blend == NULL)
                return NULL;
 
-       color_control = S_028808_MODE(V_028808_CB_NORMAL);
+       blend->alpha_to_one = state->alpha_to_one;
+
        if (state->logicop_enable) {
                color_control |= S_028808_ROP3(state->logicop_func | (state->logicop_func << 4));
        } else {
                color_control |= S_028808_ROP3(0xcc);
        }
-       si_pm4_set_reg(pm4, R_028808_CB_COLOR_CONTROL, color_control);
 
-       si_pm4_set_reg(pm4, R_028C38_PA_SC_AA_MASK_X0Y0_X1Y0, ~0);
-       si_pm4_set_reg(pm4, R_028C3C_PA_SC_AA_MASK_X0Y1_X1Y1, ~0);
+       si_pm4_set_reg(pm4, R_028B70_DB_ALPHA_TO_MASK,
+                      S_028B70_ALPHA_TO_MASK_ENABLE(state->alpha_to_coverage) |
+                      S_028B70_ALPHA_TO_MASK_OFFSET0(2) |
+                      S_028B70_ALPHA_TO_MASK_OFFSET1(2) |
+                      S_028B70_ALPHA_TO_MASK_OFFSET2(2) |
+                      S_028B70_ALPHA_TO_MASK_OFFSET3(2));
 
        blend->cb_target_mask = 0;
        for (int i = 0; i < 8; i++) {
@@ -195,27 +326,40 @@ static void *si_create_blend_state(struct pipe_context *ctx,
                si_pm4_set_reg(pm4, R_028780_CB_BLEND0_CONTROL + i * 4, blend_cntl);
        }
 
+       if (blend->cb_target_mask) {
+               color_control |= S_028808_MODE(mode);
+       } else {
+               color_control |= S_028808_MODE(V_028808_CB_DISABLE);
+       }
+       si_pm4_set_reg(pm4, R_028808_CB_COLOR_CONTROL, color_control);
+
        return blend;
 }
 
+static void *si_create_blend_state(struct pipe_context *ctx,
+                                  const struct pipe_blend_state *state)
+{
+       return si_create_blend_state_mode(ctx, state, V_028808_CB_NORMAL);
+}
+
 static void si_bind_blend_state(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        si_pm4_bind_state(rctx, blend, (struct si_state_blend *)state);
        si_update_fb_blend_state(rctx);
 }
 
 static void si_delete_blend_state(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        si_pm4_delete_state(rctx, blend, (struct si_state_blend *)state);
 }
 
 static void si_set_blend_color(struct pipe_context *ctx,
                               const struct pipe_blend_color *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
-       struct si_pm4_state *pm4 = CALLOC_STRUCT(si_pm4_state);
+       struct si_context *rctx = (struct si_context *)ctx;
+       struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
 
         if (pm4 == NULL)
                 return;
@@ -235,8 +379,8 @@ static void si_set_blend_color(struct pipe_context *ctx,
 static void si_set_clip_state(struct pipe_context *ctx,
                              const struct pipe_clip_state *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
-       struct si_pm4_state *pm4 = CALLOC_STRUCT(si_pm4_state);
+       struct si_context *rctx = (struct si_context *)ctx;
+       struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
        struct pipe_constant_buffer cb;
 
        if (pm4 == NULL)
@@ -257,17 +401,19 @@ static void si_set_clip_state(struct pipe_context *ctx,
        cb.user_buffer = state->ucp;
        cb.buffer_offset = 0;
        cb.buffer_size = 4*4*8;
-       ctx->set_constant_buffer(ctx, PIPE_SHADER_VERTEX, 1, &cb);
+       ctx->set_constant_buffer(ctx, PIPE_SHADER_VERTEX, NUM_PIPE_CONST_BUFFERS, &cb);
        pipe_resource_reference(&cb.buffer, NULL);
 
        si_pm4_set_state(rctx, clip, pm4);
 }
 
-static void si_set_scissor_state(struct pipe_context *ctx,
-                                const struct pipe_scissor_state *state)
+static void si_set_scissor_states(struct pipe_context *ctx,
+                                  unsigned start_slot,
+                                  unsigned num_scissors,
+                                  const struct pipe_scissor_state *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
-       struct si_pm4_state *pm4 = CALLOC_STRUCT(si_pm4_state);
+       struct si_context *rctx = (struct si_context *)ctx;
+       struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
        uint32_t tl, br;
 
        if (pm4 == NULL)
@@ -287,10 +433,12 @@ static void si_set_scissor_state(struct pipe_context *ctx,
        si_pm4_set_state(rctx, scissor, pm4);
 }
 
-static void si_set_viewport_state(struct pipe_context *ctx,
-                                 const struct pipe_viewport_state *state)
+static void si_set_viewport_states(struct pipe_context *ctx,
+                                   unsigned start_slot,
+                                   unsigned num_viewports,
+                                   const struct pipe_viewport_state *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_state_viewport *viewport = CALLOC_STRUCT(si_state_viewport);
        struct si_pm4_state *pm4 = &viewport->pm4;
 
@@ -298,15 +446,12 @@ static void si_set_viewport_state(struct pipe_context *ctx,
                return;
 
        viewport->viewport = *state;
-       si_pm4_set_reg(pm4, R_0282D0_PA_SC_VPORT_ZMIN_0, 0x00000000);
-       si_pm4_set_reg(pm4, R_0282D4_PA_SC_VPORT_ZMAX_0, 0x3F800000);
        si_pm4_set_reg(pm4, R_02843C_PA_CL_VPORT_XSCALE_0, fui(state->scale[0]));
        si_pm4_set_reg(pm4, R_028440_PA_CL_VPORT_XOFFSET_0, fui(state->translate[0]));
        si_pm4_set_reg(pm4, R_028444_PA_CL_VPORT_YSCALE_0, fui(state->scale[1]));
        si_pm4_set_reg(pm4, R_028448_PA_CL_VPORT_YOFFSET_0, fui(state->translate[1]));
        si_pm4_set_reg(pm4, R_02844C_PA_CL_VPORT_ZSCALE_0, fui(state->scale[2]));
        si_pm4_set_reg(pm4, R_028450_PA_CL_VPORT_ZOFFSET_0, fui(state->translate[2]));
-       si_pm4_set_reg(pm4, R_028818_PA_CL_VTE_CNTL, 0x0000043F);
 
        si_pm4_set_state(rctx, viewport, viewport);
 }
@@ -314,7 +459,7 @@ static void si_set_viewport_state(struct pipe_context *ctx,
 /*
  * inferred state between framebuffer and rasterizer
  */
-static void si_update_fb_rs_state(struct r600_context *rctx)
+static void si_update_fb_rs_state(struct si_context *rctx)
 {
        struct si_state_rasterizer *rs = rctx->queued.named.rasterizer;
        struct si_pm4_state *pm4;
@@ -347,7 +492,11 @@ static void si_update_fb_rs_state(struct r600_context *rctx)
                return;
        }
 
-       pm4 = CALLOC_STRUCT(si_pm4_state);
+       pm4 = si_pm4_alloc_state(rctx);
+
+       if (pm4 == NULL)
+               return;
+
        /* FIXME some of those reg can be computed with cso */
        offset_db_fmt_cntl |= S_028B78_POLY_OFFSET_NEG_NUM_DB_BITS(depth);
        si_pm4_set_reg(pm4, R_028B80_PA_SU_POLY_OFFSET_FRONT_SCALE,
@@ -395,7 +544,9 @@ static void *si_create_rs_state(struct pipe_context *ctx,
        }
 
        rs->two_side = state->light_twoside;
+       rs->multisample_enable = state->multisample;
        rs->clip_plane_enable = state->clip_plane_enable;
+       rs->line_stipple_enable = state->line_stipple_enable;
 
        polygon_dual_mode = (state->fill_front != PIPE_POLYGON_MODE_FILL ||
                                state->fill_back != PIPE_POLYGON_MODE_FILL);
@@ -423,6 +574,7 @@ static void *si_create_rs_state(struct pipe_context *ctx,
                S_028810_PS_UCP_MODE(3) |
                S_028810_ZCLIP_NEAR_DISABLE(!state->depth_clip) |
                S_028810_ZCLIP_FAR_DISABLE(!state->depth_clip) |
+               S_028810_DX_RASTERIZATION_KILL(state->rasterizer_discard) |
                S_028810_DX_LINEAR_ATTR_CLIP_ENA(1);
 
        clip_rule = state->scissor ? 0xAAAA : 0xFFFF;
@@ -444,7 +596,6 @@ static void *si_create_rs_state(struct pipe_context *ctx,
        }
        si_pm4_set_reg(pm4, R_0286D4_SPI_INTERP_CONTROL_0, tmp);
 
-       si_pm4_set_reg(pm4, R_028820_PA_CL_NANINF_CNTL, 0x00000000);
        /* point size 12.4 fixed point */
        tmp = (unsigned)(state->point_size * 8.0);
        si_pm4_set_reg(pm4, R_028A00_PA_SU_POINT_SIZE, S_028A00_HEIGHT(tmp) | S_028A00_WIDTH(tmp));
@@ -465,15 +616,12 @@ static void *si_create_rs_state(struct pipe_context *ctx,
        tmp = (unsigned)state->line_width * 8;
        si_pm4_set_reg(pm4, R_028A08_PA_SU_LINE_CNTL, S_028A08_WIDTH(tmp));
        si_pm4_set_reg(pm4, R_028A48_PA_SC_MODE_CNTL_0,
-                       S_028A48_LINE_STIPPLE_ENABLE(state->line_stipple_enable));
+                      S_028A48_LINE_STIPPLE_ENABLE(state->line_stipple_enable) |
+                      S_028A48_MSAA_ENABLE(state->multisample));
 
-       si_pm4_set_reg(pm4, R_028BDC_PA_SC_LINE_CNTL, 0x00000400);
        si_pm4_set_reg(pm4, R_028BE4_PA_SU_VTX_CNTL,
-                       S_028BE4_PIX_CENTER(state->half_pixel_center));
-       si_pm4_set_reg(pm4, R_028BE8_PA_CL_GB_VERT_CLIP_ADJ, 0x3F800000);
-       si_pm4_set_reg(pm4, R_028BEC_PA_CL_GB_VERT_DISC_ADJ, 0x3F800000);
-       si_pm4_set_reg(pm4, R_028BF0_PA_CL_GB_HORZ_CLIP_ADJ, 0x3F800000);
-       si_pm4_set_reg(pm4, R_028BF4_PA_CL_GB_HORZ_DISC_ADJ, 0x3F800000);
+                      S_028BE4_PIX_CENTER(state->half_pixel_center) |
+                      S_028BE4_QUANT_MODE(V_028BE4_X_16_8_FIXED_POINT_1_256TH));
 
        si_pm4_set_reg(pm4, R_028B7C_PA_SU_POLY_OFFSET_CLAMP, fui(state->offset_clamp));
        si_pm4_set_reg(pm4, R_02820C_PA_SC_CLIPRECT_RULE, clip_rule);
@@ -483,7 +631,7 @@ static void *si_create_rs_state(struct pipe_context *ctx,
 
 static void si_bind_rs_state(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_state_rasterizer *rs = (struct si_state_rasterizer *)state;
 
        if (state == NULL)
@@ -500,16 +648,16 @@ static void si_bind_rs_state(struct pipe_context *ctx, void *state)
 
 static void si_delete_rs_state(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        si_pm4_delete_state(rctx, rasterizer, (struct si_state_rasterizer *)state);
 }
 
 /*
  * infeered state between dsa and stencil ref
  */
-static void si_update_dsa_stencil_ref(struct r600_context *rctx)
+static void si_update_dsa_stencil_ref(struct si_context *rctx)
 {
-       struct si_pm4_state *pm4 = CALLOC_STRUCT(si_pm4_state);
+       struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
        struct pipe_stencil_ref *ref = &rctx->stencil_ref;
         struct si_state_dsa *dsa = rctx->queued.named.dsa;
 
@@ -533,7 +681,7 @@ static void si_update_dsa_stencil_ref(struct r600_context *rctx)
 static void si_set_pipe_stencil_ref(struct pipe_context *ctx,
                                    const struct pipe_stencil_ref *state)
 {
-        struct r600_context *rctx = (struct r600_context *)ctx;
+        struct si_context *rctx = (struct si_context *)ctx;
         rctx->stencil_ref = *state;
        si_update_dsa_stencil_ref(rctx);
 }
@@ -576,7 +724,7 @@ static void *si_create_dsa_state(struct pipe_context *ctx,
        struct si_state_dsa *dsa = CALLOC_STRUCT(si_state_dsa);
        struct si_pm4_state *pm4 = &dsa->pm4;
        unsigned db_depth_control;
-       unsigned db_render_override, db_render_control;
+       unsigned db_render_control;
        uint32_t db_stencil_control = 0;
 
        if (dsa == NULL) {
@@ -613,37 +761,25 @@ static void *si_create_dsa_state(struct pipe_context *ctx,
        if (state->alpha.enabled) {
                dsa->alpha_func = state->alpha.func;
                dsa->alpha_ref = state->alpha.ref_value;
+
+               si_pm4_set_reg(pm4, R_00B030_SPI_SHADER_USER_DATA_PS_0 +
+                              SI_SGPR_ALPHA_REF * 4, fui(dsa->alpha_ref));
        } else {
                dsa->alpha_func = PIPE_FUNC_ALWAYS;
        }
 
        /* misc */
        db_render_control = 0;
-       db_render_override = S_02800C_FORCE_HIZ_ENABLE(V_02800C_FORCE_DISABLE) |
-               S_02800C_FORCE_HIS_ENABLE0(V_02800C_FORCE_DISABLE) |
-               S_02800C_FORCE_HIS_ENABLE1(V_02800C_FORCE_DISABLE);
-       /* TODO db_render_override depends on query */
-       si_pm4_set_reg(pm4, R_028020_DB_DEPTH_BOUNDS_MIN, 0x00000000);
-       si_pm4_set_reg(pm4, R_028024_DB_DEPTH_BOUNDS_MAX, 0x00000000);
-       si_pm4_set_reg(pm4, R_028028_DB_STENCIL_CLEAR, 0x00000000);
-       si_pm4_set_reg(pm4, R_02802C_DB_DEPTH_CLEAR, 0x3F800000);
-       //si_pm4_set_reg(pm4, R_028410_SX_ALPHA_TEST_CONTROL, alpha_test_control);
        si_pm4_set_reg(pm4, R_028800_DB_DEPTH_CONTROL, db_depth_control);
        si_pm4_set_reg(pm4, R_028000_DB_RENDER_CONTROL, db_render_control);
-       si_pm4_set_reg(pm4, R_02800C_DB_RENDER_OVERRIDE, db_render_override);
        si_pm4_set_reg(pm4, R_02842C_DB_STENCIL_CONTROL, db_stencil_control);
-       si_pm4_set_reg(pm4, R_028AC0_DB_SRESULTS_COMPARE_STATE0, 0x0);
-       si_pm4_set_reg(pm4, R_028AC4_DB_SRESULTS_COMPARE_STATE1, 0x0);
-       si_pm4_set_reg(pm4, R_028AC8_DB_PRELOAD_CONTROL, 0x0);
-       si_pm4_set_reg(pm4, R_028B70_DB_ALPHA_TO_MASK, 0x0000AA00);
-       dsa->db_render_override = db_render_override;
 
        return dsa;
 }
 
 static void si_bind_dsa_state(struct pipe_context *ctx, void *state)
 {
-        struct r600_context *rctx = (struct r600_context *)ctx;
+        struct si_context *rctx = (struct si_context *)ctx;
         struct si_state_dsa *dsa = state;
 
         if (state == NULL)
@@ -655,33 +791,29 @@ static void si_bind_dsa_state(struct pipe_context *ctx, void *state)
 
 static void si_delete_dsa_state(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        si_pm4_delete_state(rctx, dsa, (struct si_state_dsa *)state);
 }
 
-static void *si_create_db_flush_dsa(struct r600_context *rctx, bool copy_depth,
-                                   bool copy_stencil)
+static void *si_create_db_flush_dsa(struct si_context *rctx, bool copy_depth,
+                                   bool copy_stencil, int sample)
 {
        struct pipe_depth_stencil_alpha_state dsa;
         struct si_state_dsa *state;
 
        memset(&dsa, 0, sizeof(dsa));
 
-       state = rctx->context.create_depth_stencil_alpha_state(&rctx->context, &dsa);
+       state = rctx->b.b.create_depth_stencil_alpha_state(&rctx->b.b, &dsa);
        if (copy_depth || copy_stencil) {
                si_pm4_set_reg(&state->pm4, R_028000_DB_RENDER_CONTROL,
                               S_028000_DEPTH_COPY(copy_depth) |
                               S_028000_STENCIL_COPY(copy_stencil) |
-                              S_028000_COPY_CENTROID(1));
+                              S_028000_COPY_CENTROID(1) |
+                              S_028000_COPY_SAMPLE(sample));
        } else {
                si_pm4_set_reg(&state->pm4, R_028000_DB_RENDER_CONTROL,
                               S_028000_DEPTH_COMPRESS_DISABLE(1) |
                               S_028000_STENCIL_COMPRESS_DISABLE(1));
-               si_pm4_set_reg(&state->pm4, R_02800C_DB_RENDER_OVERRIDE,
-                              S_02800C_FORCE_HIZ_ENABLE(V_02800C_FORCE_DISABLE) |
-                              S_02800C_FORCE_HIS_ENABLE0(V_02800C_FORCE_DISABLE) |
-                              S_02800C_FORCE_HIS_ENABLE1(V_02800C_FORCE_DISABLE) |
-                              S_02800C_DISABLE_TILE_RATE_TILES(1));
        }
 
         return state;
@@ -692,366 +824,124 @@ static void *si_create_db_flush_dsa(struct r600_context *rctx, bool copy_depth,
  */
 static uint32_t si_translate_colorformat(enum pipe_format format)
 {
-       switch (format) {
-       /* 8-bit buffers. */
-       case PIPE_FORMAT_A8_UNORM:
-       case PIPE_FORMAT_A8_SNORM:
-       case PIPE_FORMAT_A8_UINT:
-       case PIPE_FORMAT_A8_SINT:
-       case PIPE_FORMAT_I8_UNORM:
-       case PIPE_FORMAT_I8_SNORM:
-       case PIPE_FORMAT_I8_UINT:
-       case PIPE_FORMAT_I8_SINT:
-       case PIPE_FORMAT_L8_UNORM:
-       case PIPE_FORMAT_L8_SNORM:
-       case PIPE_FORMAT_L8_UINT:
-       case PIPE_FORMAT_L8_SINT:
-       case PIPE_FORMAT_L8_SRGB:
-       case PIPE_FORMAT_R8_UNORM:
-       case PIPE_FORMAT_R8_SNORM:
-       case PIPE_FORMAT_R8_UINT:
-       case PIPE_FORMAT_R8_SINT:
-               return V_028C70_COLOR_8;
-
-       /* 16-bit buffers. */
-       case PIPE_FORMAT_B5G6R5_UNORM:
-               return V_028C70_COLOR_5_6_5;
-
-       case PIPE_FORMAT_B5G5R5A1_UNORM:
-       case PIPE_FORMAT_B5G5R5X1_UNORM:
-               return V_028C70_COLOR_1_5_5_5;
-
-       case PIPE_FORMAT_B4G4R4A4_UNORM:
-       case PIPE_FORMAT_B4G4R4X4_UNORM:
-               return V_028C70_COLOR_4_4_4_4;
-
-       case PIPE_FORMAT_L8A8_UNORM:
-       case PIPE_FORMAT_L8A8_SNORM:
-       case PIPE_FORMAT_L8A8_UINT:
-       case PIPE_FORMAT_L8A8_SINT:
-       case PIPE_FORMAT_R8G8_SNORM:
-       case PIPE_FORMAT_R8G8_UNORM:
-       case PIPE_FORMAT_R8G8_UINT:
-       case PIPE_FORMAT_R8G8_SINT:
-               return V_028C70_COLOR_8_8;
+       const struct util_format_description *desc = util_format_description(format);
 
-       case PIPE_FORMAT_Z16_UNORM:
-       case PIPE_FORMAT_R16_UNORM:
-       case PIPE_FORMAT_R16_SNORM:
-       case PIPE_FORMAT_R16_UINT:
-       case PIPE_FORMAT_R16_SINT:
-       case PIPE_FORMAT_R16_FLOAT:
-       case PIPE_FORMAT_L16_UNORM:
-       case PIPE_FORMAT_L16_SNORM:
-       case PIPE_FORMAT_L16_FLOAT:
-       case PIPE_FORMAT_I16_UNORM:
-       case PIPE_FORMAT_I16_SNORM:
-       case PIPE_FORMAT_I16_FLOAT:
-       case PIPE_FORMAT_A16_UNORM:
-       case PIPE_FORMAT_A16_SNORM:
-       case PIPE_FORMAT_A16_FLOAT:
-               return V_028C70_COLOR_16;
-
-       /* 32-bit buffers. */
-       case PIPE_FORMAT_A8B8G8R8_SRGB:
-       case PIPE_FORMAT_A8B8G8R8_UNORM:
-       case PIPE_FORMAT_A8R8G8B8_UNORM:
-       case PIPE_FORMAT_B8G8R8A8_SRGB:
-       case PIPE_FORMAT_B8G8R8A8_UNORM:
-       case PIPE_FORMAT_B8G8R8X8_UNORM:
-       case PIPE_FORMAT_R8G8B8A8_SNORM:
-       case PIPE_FORMAT_R8G8B8A8_UNORM:
-       case PIPE_FORMAT_R8G8B8X8_UNORM:
-       case PIPE_FORMAT_R8G8B8X8_SNORM:
-       case PIPE_FORMAT_R8G8B8X8_SRGB:
-       case PIPE_FORMAT_R8G8B8X8_UINT:
-       case PIPE_FORMAT_R8G8B8X8_SINT:
-       case PIPE_FORMAT_R8SG8SB8UX8U_NORM:
-       case PIPE_FORMAT_X8B8G8R8_UNORM:
-       case PIPE_FORMAT_X8R8G8B8_UNORM:
-       case PIPE_FORMAT_R8G8B8A8_SSCALED:
-       case PIPE_FORMAT_R8G8B8A8_USCALED:
-       case PIPE_FORMAT_R8G8B8A8_SINT:
-       case PIPE_FORMAT_R8G8B8A8_UINT:
-               return V_028C70_COLOR_8_8_8_8;
-
-       case PIPE_FORMAT_R10G10B10A2_UNORM:
-       case PIPE_FORMAT_R10G10B10X2_SNORM:
-       case PIPE_FORMAT_B10G10R10A2_UNORM:
-       case PIPE_FORMAT_B10G10R10A2_UINT:
-       case PIPE_FORMAT_B10G10R10X2_UNORM:
-       case PIPE_FORMAT_R10SG10SB10SA2U_NORM:
-               return V_028C70_COLOR_2_10_10_10;
-
-       case PIPE_FORMAT_Z24X8_UNORM:
-       case PIPE_FORMAT_Z24_UNORM_S8_UINT:
-               return V_028C70_COLOR_8_24;
-
-       case PIPE_FORMAT_S8X24_UINT:
-       case PIPE_FORMAT_X8Z24_UNORM:
-       case PIPE_FORMAT_S8_UINT_Z24_UNORM:
-               return V_028C70_COLOR_24_8;
+#define HAS_SIZE(x,y,z,w) \
+       (desc->channel[0].size == (x) && desc->channel[1].size == (y) && \
+         desc->channel[2].size == (z) && desc->channel[3].size == (w))
 
-       case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
-               return V_028C70_COLOR_X24_8_32_FLOAT;
-
-       case PIPE_FORMAT_I32_FLOAT:
-       case PIPE_FORMAT_L32_FLOAT:
-       case PIPE_FORMAT_R32_FLOAT:
-       case PIPE_FORMAT_A32_FLOAT:
-       case PIPE_FORMAT_Z32_FLOAT:
-               return V_028C70_COLOR_32;
-
-       case PIPE_FORMAT_L16A16_UNORM:
-       case PIPE_FORMAT_L16A16_SNORM:
-       case PIPE_FORMAT_L16A16_FLOAT:
-       case PIPE_FORMAT_R16G16_SSCALED:
-       case PIPE_FORMAT_R16G16_UNORM:
-       case PIPE_FORMAT_R16G16_SNORM:
-       case PIPE_FORMAT_R16G16_UINT:
-       case PIPE_FORMAT_R16G16_SINT:
-       case PIPE_FORMAT_R16G16_FLOAT:
-               return V_028C70_COLOR_16_16;
-
-       case PIPE_FORMAT_R11G11B10_FLOAT:
+       if (format == PIPE_FORMAT_R11G11B10_FLOAT) /* isn't plain */
                return V_028C70_COLOR_10_11_11;
 
-       /* 64-bit buffers. */
-       case PIPE_FORMAT_R16G16B16A16_UINT:
-       case PIPE_FORMAT_R16G16B16A16_SINT:
-       case PIPE_FORMAT_R16G16B16A16_USCALED:
-       case PIPE_FORMAT_R16G16B16A16_SSCALED:
-       case PIPE_FORMAT_R16G16B16A16_UNORM:
-       case PIPE_FORMAT_R16G16B16A16_SNORM:
-       case PIPE_FORMAT_R16G16B16A16_FLOAT:
-       case PIPE_FORMAT_R16G16B16X16_UNORM:
-       case PIPE_FORMAT_R16G16B16X16_SNORM:
-       case PIPE_FORMAT_R16G16B16X16_FLOAT:
-       case PIPE_FORMAT_R16G16B16X16_UINT:
-       case PIPE_FORMAT_R16G16B16X16_SINT:
-               return V_028C70_COLOR_16_16_16_16;
-
-       case PIPE_FORMAT_L32A32_FLOAT:
-       case PIPE_FORMAT_L32A32_UINT:
-       case PIPE_FORMAT_L32A32_SINT:
-       case PIPE_FORMAT_R32G32_FLOAT:
-       case PIPE_FORMAT_R32G32_USCALED:
-       case PIPE_FORMAT_R32G32_SSCALED:
-       case PIPE_FORMAT_R32G32_SINT:
-       case PIPE_FORMAT_R32G32_UINT:
-               return V_028C70_COLOR_32_32;
-
-       /* 128-bit buffers. */
-       case PIPE_FORMAT_R32G32B32A32_SNORM:
-       case PIPE_FORMAT_R32G32B32A32_UNORM:
-       case PIPE_FORMAT_R32G32B32A32_SSCALED:
-       case PIPE_FORMAT_R32G32B32A32_USCALED:
-       case PIPE_FORMAT_R32G32B32A32_SINT:
-       case PIPE_FORMAT_R32G32B32A32_UINT:
-       case PIPE_FORMAT_R32G32B32A32_FLOAT:
-       case PIPE_FORMAT_R32G32B32X32_FLOAT:
-       case PIPE_FORMAT_R32G32B32X32_UINT:
-       case PIPE_FORMAT_R32G32B32X32_SINT:
-               return V_028C70_COLOR_32_32_32_32;
-
-       /* YUV buffers. */
-       case PIPE_FORMAT_UYVY:
-       case PIPE_FORMAT_YUYV:
-       /* 96-bit buffers. */
-       case PIPE_FORMAT_R32G32B32_FLOAT:
-       /* 8-bit buffers. */
-       case PIPE_FORMAT_L4A4_UNORM:
-       case PIPE_FORMAT_R4A4_UNORM:
-       case PIPE_FORMAT_A4R4_UNORM:
-       default:
-               return V_028C70_COLOR_INVALID; /* Unsupported. */
+       if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN)
+               return V_028C70_COLOR_INVALID;
+
+       switch (desc->nr_channels) {
+       case 1:
+               switch (desc->channel[0].size) {
+               case 8:
+                       return V_028C70_COLOR_8;
+               case 16:
+                       return V_028C70_COLOR_16;
+               case 32:
+                       return V_028C70_COLOR_32;
+               }
+               break;
+       case 2:
+               if (desc->channel[0].size == desc->channel[1].size) {
+                       switch (desc->channel[0].size) {
+                       case 8:
+                               return V_028C70_COLOR_8_8;
+                       case 16:
+                               return V_028C70_COLOR_16_16;
+                       case 32:
+                               return V_028C70_COLOR_32_32;
+                       }
+               } else if (HAS_SIZE(8,24,0,0)) {
+                       return V_028C70_COLOR_24_8;
+               } else if (HAS_SIZE(24,8,0,0)) {
+                       return V_028C70_COLOR_8_24;
+               }
+               break;
+       case 3:
+               if (HAS_SIZE(5,6,5,0)) {
+                       return V_028C70_COLOR_5_6_5;
+               } else if (HAS_SIZE(32,8,24,0)) {
+                       return V_028C70_COLOR_X24_8_32_FLOAT;
+               }
+               break;
+       case 4:
+               if (desc->channel[0].size == desc->channel[1].size &&
+                   desc->channel[0].size == desc->channel[2].size &&
+                   desc->channel[0].size == desc->channel[3].size) {
+                       switch (desc->channel[0].size) {
+                       case 4:
+                               return V_028C70_COLOR_4_4_4_4;
+                       case 8:
+                               return V_028C70_COLOR_8_8_8_8;
+                       case 16:
+                               return V_028C70_COLOR_16_16_16_16;
+                       case 32:
+                               return V_028C70_COLOR_32_32_32_32;
+                       }
+               } else if (HAS_SIZE(5,5,5,1)) {
+                       return V_028C70_COLOR_1_5_5_5;
+               } else if (HAS_SIZE(10,10,10,2)) {
+                       return V_028C70_COLOR_2_10_10_10;
+               }
+               break;
        }
+       return V_028C70_COLOR_INVALID;
 }
 
 static uint32_t si_translate_colorswap(enum pipe_format format)
 {
-       switch (format) {
-       /* 8-bit buffers. */
-       case PIPE_FORMAT_L4A4_UNORM:
-       case PIPE_FORMAT_A4R4_UNORM:
-               return V_028C70_SWAP_ALT;
-
-       case PIPE_FORMAT_A8_UNORM:
-       case PIPE_FORMAT_A8_SNORM:
-       case PIPE_FORMAT_A8_UINT:
-       case PIPE_FORMAT_A8_SINT:
-       case PIPE_FORMAT_R4A4_UNORM:
-               return V_028C70_SWAP_ALT_REV;
-       case PIPE_FORMAT_I8_UNORM:
-       case PIPE_FORMAT_I8_SNORM:
-       case PIPE_FORMAT_L8_UNORM:
-       case PIPE_FORMAT_L8_SNORM:
-       case PIPE_FORMAT_I8_UINT:
-       case PIPE_FORMAT_I8_SINT:
-       case PIPE_FORMAT_L8_UINT:
-       case PIPE_FORMAT_L8_SINT:
-       case PIPE_FORMAT_L8_SRGB:
-       case PIPE_FORMAT_R8_UNORM:
-       case PIPE_FORMAT_R8_SNORM:
-       case PIPE_FORMAT_R8_UINT:
-       case PIPE_FORMAT_R8_SINT:
-               return V_028C70_SWAP_STD;
-
-       /* 16-bit buffers. */
-       case PIPE_FORMAT_B5G6R5_UNORM:
-               return V_028C70_SWAP_STD_REV;
-
-       case PIPE_FORMAT_B5G5R5A1_UNORM:
-       case PIPE_FORMAT_B5G5R5X1_UNORM:
-               return V_028C70_SWAP_ALT;
-
-       case PIPE_FORMAT_B4G4R4A4_UNORM:
-       case PIPE_FORMAT_B4G4R4X4_UNORM:
-               return V_028C70_SWAP_ALT;
-
-       case PIPE_FORMAT_Z16_UNORM:
-               return V_028C70_SWAP_STD;
-
-       case PIPE_FORMAT_L8A8_UNORM:
-       case PIPE_FORMAT_L8A8_SNORM:
-       case PIPE_FORMAT_L8A8_UINT:
-       case PIPE_FORMAT_L8A8_SINT:
-               return V_028C70_SWAP_ALT;
-       case PIPE_FORMAT_R8G8_SNORM:
-       case PIPE_FORMAT_R8G8_UNORM:
-       case PIPE_FORMAT_R8G8_UINT:
-       case PIPE_FORMAT_R8G8_SINT:
-               return V_028C70_SWAP_STD;
-
-       case PIPE_FORMAT_I16_UNORM:
-       case PIPE_FORMAT_I16_SNORM:
-       case PIPE_FORMAT_I16_FLOAT:
-       case PIPE_FORMAT_L16_UNORM:
-       case PIPE_FORMAT_L16_SNORM:
-       case PIPE_FORMAT_L16_FLOAT:
-       case PIPE_FORMAT_R16_UNORM:
-       case PIPE_FORMAT_R16_SNORM:
-       case PIPE_FORMAT_R16_UINT:
-       case PIPE_FORMAT_R16_SINT:
-       case PIPE_FORMAT_R16_FLOAT:
-               return V_028C70_SWAP_STD;
-
-       case PIPE_FORMAT_A16_UNORM:
-       case PIPE_FORMAT_A16_SNORM:
-       case PIPE_FORMAT_A16_FLOAT:
-               return V_028C70_SWAP_ALT_REV;
-
-       /* 32-bit buffers. */
-       case PIPE_FORMAT_A8B8G8R8_SRGB:
-               return V_028C70_SWAP_STD_REV;
-       case PIPE_FORMAT_B8G8R8A8_SRGB:
-               return V_028C70_SWAP_ALT;
-
-       case PIPE_FORMAT_B8G8R8A8_UNORM:
-       case PIPE_FORMAT_B8G8R8X8_UNORM:
-               return V_028C70_SWAP_ALT;
-
-       case PIPE_FORMAT_A8R8G8B8_UNORM:
-       case PIPE_FORMAT_X8R8G8B8_UNORM:
-               return V_028C70_SWAP_ALT_REV;
-       case PIPE_FORMAT_R8G8B8A8_SNORM:
-       case PIPE_FORMAT_R8G8B8A8_UNORM:
-       case PIPE_FORMAT_R8G8B8A8_SSCALED:
-       case PIPE_FORMAT_R8G8B8A8_USCALED:
-       case PIPE_FORMAT_R8G8B8A8_SINT:
-       case PIPE_FORMAT_R8G8B8A8_UINT:
-       case PIPE_FORMAT_R8G8B8X8_UNORM:
-       case PIPE_FORMAT_R8G8B8X8_SNORM:
-       case PIPE_FORMAT_R8G8B8X8_SRGB:
-       case PIPE_FORMAT_R8G8B8X8_UINT:
-       case PIPE_FORMAT_R8G8B8X8_SINT:
-               return V_028C70_SWAP_STD;
-
-       case PIPE_FORMAT_A8B8G8R8_UNORM:
-       case PIPE_FORMAT_X8B8G8R8_UNORM:
-       /* case PIPE_FORMAT_R8SG8SB8UX8U_NORM: */
-               return V_028C70_SWAP_STD_REV;
-
-       case PIPE_FORMAT_Z24X8_UNORM:
-       case PIPE_FORMAT_Z24_UNORM_S8_UINT:
-               return V_028C70_SWAP_STD;
+       const struct util_format_description *desc = util_format_description(format);
 
-       case PIPE_FORMAT_S8X24_UINT:
-       case PIPE_FORMAT_X8Z24_UNORM:
-       case PIPE_FORMAT_S8_UINT_Z24_UNORM:
-               return V_028C70_SWAP_STD_REV;
+#define HAS_SWIZZLE(chan,swz) (desc->swizzle[chan] == UTIL_FORMAT_SWIZZLE_##swz)
 
-       case PIPE_FORMAT_R10G10B10A2_UNORM:
-       case PIPE_FORMAT_R10G10B10X2_SNORM:
-       case PIPE_FORMAT_R10SG10SB10SA2U_NORM:
+       if (format == PIPE_FORMAT_R11G11B10_FLOAT) /* isn't plain */
                return V_028C70_SWAP_STD;
 
-       case PIPE_FORMAT_B10G10R10A2_UNORM:
-       case PIPE_FORMAT_B10G10R10A2_UINT:
-       case PIPE_FORMAT_B10G10R10X2_UNORM:
-               return V_028C70_SWAP_ALT;
-
-       case PIPE_FORMAT_R11G11B10_FLOAT:
-       case PIPE_FORMAT_I32_FLOAT:
-       case PIPE_FORMAT_L32_FLOAT:
-       case PIPE_FORMAT_R32_FLOAT:
-       case PIPE_FORMAT_R32_UINT:
-       case PIPE_FORMAT_R32_SINT:
-       case PIPE_FORMAT_Z32_FLOAT:
-       case PIPE_FORMAT_R16G16_FLOAT:
-       case PIPE_FORMAT_R16G16_UNORM:
-       case PIPE_FORMAT_R16G16_SNORM:
-       case PIPE_FORMAT_R16G16_UINT:
-       case PIPE_FORMAT_R16G16_SINT:
-               return V_028C70_SWAP_STD;
-
-       case PIPE_FORMAT_L16A16_UNORM:
-       case PIPE_FORMAT_L16A16_SNORM:
-       case PIPE_FORMAT_L16A16_FLOAT:
-               return V_028C70_SWAP_ALT;
-
-       case PIPE_FORMAT_A32_FLOAT:
-               return V_028C70_SWAP_ALT_REV;
-
-       /* 64-bit buffers. */
-       case PIPE_FORMAT_R32G32_FLOAT:
-       case PIPE_FORMAT_R32G32_UINT:
-       case PIPE_FORMAT_R32G32_SINT:
-       case PIPE_FORMAT_R16G16B16A16_UNORM:
-       case PIPE_FORMAT_R16G16B16A16_SNORM:
-       case PIPE_FORMAT_R16G16B16A16_USCALED:
-       case PIPE_FORMAT_R16G16B16A16_SSCALED:
-       case PIPE_FORMAT_R16G16B16A16_UINT:
-       case PIPE_FORMAT_R16G16B16A16_SINT:
-       case PIPE_FORMAT_R16G16B16A16_FLOAT:
-       case PIPE_FORMAT_R16G16B16X16_UNORM:
-       case PIPE_FORMAT_R16G16B16X16_SNORM:
-       case PIPE_FORMAT_R16G16B16X16_FLOAT:
-       case PIPE_FORMAT_R16G16B16X16_UINT:
-       case PIPE_FORMAT_R16G16B16X16_SINT:
-       case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
-               return V_028C70_SWAP_STD;
+       if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN)
+               return ~0;
 
-       case PIPE_FORMAT_L32A32_FLOAT:
-       case PIPE_FORMAT_L32A32_UINT:
-       case PIPE_FORMAT_L32A32_SINT:
-               return V_028C70_SWAP_ALT;
-
-       /* 128-bit buffers. */
-       case PIPE_FORMAT_R32G32B32A32_FLOAT:
-       case PIPE_FORMAT_R32G32B32A32_SNORM:
-       case PIPE_FORMAT_R32G32B32A32_UNORM:
-       case PIPE_FORMAT_R32G32B32A32_SSCALED:
-       case PIPE_FORMAT_R32G32B32A32_USCALED:
-       case PIPE_FORMAT_R32G32B32A32_SINT:
-       case PIPE_FORMAT_R32G32B32A32_UINT:
-       case PIPE_FORMAT_R32G32B32X32_FLOAT:
-       case PIPE_FORMAT_R32G32B32X32_UINT:
-       case PIPE_FORMAT_R32G32B32X32_SINT:
-               return V_028C70_SWAP_STD;
-       default:
-               R600_ERR("unsupported colorswap format %d\n", format);
-               return ~0U;
+       switch (desc->nr_channels) {
+       case 1:
+               if (HAS_SWIZZLE(0,X))
+                       return V_028C70_SWAP_STD; /* X___ */
+               else if (HAS_SWIZZLE(3,X))
+                       return V_028C70_SWAP_ALT_REV; /* ___X */
+               break;
+       case 2:
+               if ((HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,Y)) ||
+                   (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,NONE)) ||
+                   (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,Y)))
+                       return V_028C70_SWAP_STD; /* XY__ */
+               else if ((HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,X)) ||
+                        (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,NONE)) ||
+                        (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,X)))
+                       return V_028C70_SWAP_STD_REV; /* YX__ */
+               else if (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(3,Y))
+                       return V_028C70_SWAP_ALT; /* X__Y */
+               break;
+       case 3:
+               if (HAS_SWIZZLE(0,X))
+                       return V_028C70_SWAP_STD; /* XYZ */
+               else if (HAS_SWIZZLE(0,Z))
+                       return V_028C70_SWAP_STD_REV; /* ZYX */
+               break;
+       case 4:
+               /* check the middle channels, the 1st and 4th channel can be NONE */
+               if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,Z))
+                       return V_028C70_SWAP_STD; /* XYZW */
+               else if (HAS_SWIZZLE(1,Z) && HAS_SWIZZLE(2,Y))
+                       return V_028C70_SWAP_STD_REV; /* WZYX */
+               else if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,X))
+                       return V_028C70_SWAP_ALT; /* ZYXW */
+               else if (HAS_SWIZZLE(1,X) && HAS_SWIZZLE(2,Y))
+                       return V_028C70_SWAP_ALT_REV; /* WXYZ */
+               break;
        }
        return ~0U;
 }
@@ -1172,8 +1062,8 @@ static uint32_t si_translate_texformat(struct pipe_screen *screen,
                                       const struct util_format_description *desc,
                                       int first_non_void)
 {
-       struct r600_screen *rscreen = (struct r600_screen*)screen;
-       bool enable_s3tc = rscreen->info.drm_minor >= 31;
+       struct si_screen *rscreen = (struct si_screen*)screen;
+       bool enable_s3tc = rscreen->b.info.drm_minor >= 31;
        boolean uniform = TRUE;
        int i;
 
@@ -1427,7 +1317,7 @@ static unsigned si_tex_compare(unsigned compare)
        }
 }
 
-static unsigned si_tex_dim(unsigned dim)
+static unsigned si_tex_dim(unsigned dim, unsigned nr_samples)
 {
        switch (dim) {
        default:
@@ -1437,9 +1327,11 @@ static unsigned si_tex_dim(unsigned dim)
                return V_008F1C_SQ_RSRC_IMG_1D_ARRAY;
        case PIPE_TEXTURE_2D:
        case PIPE_TEXTURE_RECT:
-               return V_008F1C_SQ_RSRC_IMG_2D;
+               return nr_samples > 1 ? V_008F1C_SQ_RSRC_IMG_2D_MSAA :
+                                       V_008F1C_SQ_RSRC_IMG_2D;
        case PIPE_TEXTURE_2D_ARRAY:
-               return V_008F1C_SQ_RSRC_IMG_2D_ARRAY;
+               return nr_samples > 1 ? V_008F1C_SQ_RSRC_IMG_2D_MSAA_ARRAY :
+                                       V_008F1C_SQ_RSRC_IMG_2D_ARRAY;
        case PIPE_TEXTURE_3D:
                return V_008F1C_SQ_RSRC_IMG_3D;
        case PIPE_TEXTURE_CUBE:
@@ -1457,10 +1349,9 @@ static bool si_is_sampler_format_supported(struct pipe_screen *screen, enum pipe
                                      util_format_get_first_non_void_channel(format)) != ~0U;
 }
 
-static uint32_t si_translate_vertexformat(struct pipe_screen *screen,
-                                         enum pipe_format format,
-                                         const struct util_format_description *desc,
-                                         int first_non_void)
+static uint32_t si_translate_buffer_dataformat(struct pipe_screen *screen,
+                                              const struct util_format_description *desc,
+                                              int first_non_void)
 {
        unsigned type = desc->channel[first_non_void].type;
        int i;
@@ -1468,6 +1359,13 @@ static uint32_t si_translate_vertexformat(struct pipe_screen *screen,
        if (type == UTIL_FORMAT_TYPE_FIXED)
                return V_008F0C_BUF_DATA_FORMAT_INVALID;
 
+       if (desc->nr_channels == 4 &&
+           desc->channel[0].size == 10 &&
+           desc->channel[1].size == 10 &&
+           desc->channel[2].size == 10 &&
+           desc->channel[3].size == 2)
+               return V_008F0C_BUF_DATA_FORMAT_2_10_10_10;
+
        /* See whether the components are of the same size. */
        for (i = 0; i < desc->nr_channels; i++) {
                if (desc->channel[first_non_void].size != desc->channel[i].size)
@@ -1498,7 +1396,12 @@ static uint32_t si_translate_vertexformat(struct pipe_screen *screen,
                }
                break;
        case 32:
-               if (type != UTIL_FORMAT_TYPE_FLOAT)
+               /* From the Southern Islands ISA documentation about MTBUF:
+                * 'Memory reads of data in memory that is 32 or 64 bits do not
+                * undergo any format conversion.'
+                */
+               if (type != UTIL_FORMAT_TYPE_FLOAT &&
+                   !desc->channel[first_non_void].pure_integer)
                        return V_008F0C_BUF_DATA_FORMAT_INVALID;
 
                switch (desc->nr_channels) {
@@ -1517,6 +1420,33 @@ static uint32_t si_translate_vertexformat(struct pipe_screen *screen,
        return V_008F0C_BUF_DATA_FORMAT_INVALID;
 }
 
+static uint32_t si_translate_buffer_numformat(struct pipe_screen *screen,
+                                             const struct util_format_description *desc,
+                                             int first_non_void)
+{
+       switch (desc->channel[first_non_void].type) {
+       case UTIL_FORMAT_TYPE_SIGNED:
+               if (desc->channel[first_non_void].normalized)
+                       return V_008F0C_BUF_NUM_FORMAT_SNORM;
+               else if (desc->channel[first_non_void].pure_integer)
+                       return V_008F0C_BUF_NUM_FORMAT_SINT;
+               else
+                       return V_008F0C_BUF_NUM_FORMAT_SSCALED;
+               break;
+       case UTIL_FORMAT_TYPE_UNSIGNED:
+               if (desc->channel[first_non_void].normalized)
+                       return V_008F0C_BUF_NUM_FORMAT_UNORM;
+               else if (desc->channel[first_non_void].pure_integer)
+                       return V_008F0C_BUF_NUM_FORMAT_UINT;
+               else
+                       return V_008F0C_BUF_NUM_FORMAT_USCALED;
+               break;
+       case UTIL_FORMAT_TYPE_FLOAT:
+       default:
+               return V_008F0C_BUF_NUM_FORMAT_FLOAT;
+       }
+}
+
 static bool si_is_vertex_format_supported(struct pipe_screen *screen, enum pipe_format format)
 {
        const struct util_format_description *desc;
@@ -1525,7 +1455,7 @@ static bool si_is_vertex_format_supported(struct pipe_screen *screen, enum pipe_
 
        desc = util_format_description(format);
        first_non_void = util_format_get_first_non_void_channel(format);
-       data_format = si_translate_vertexformat(screen, format, desc, first_non_void);
+       data_format = si_translate_buffer_dataformat(screen, desc, first_non_void);
        return data_format != V_008F0C_BUF_DATA_FORMAT_INVALID;
 }
 
@@ -1546,6 +1476,7 @@ boolean si_is_format_supported(struct pipe_screen *screen,
                                unsigned sample_count,
                                unsigned usage)
 {
+       struct si_screen *rscreen = (struct si_screen *)screen;
        unsigned retval = 0;
 
        if (target >= PIPE_MAX_TEXTURE_TYPES) {
@@ -1556,13 +1487,32 @@ boolean si_is_format_supported(struct pipe_screen *screen,
        if (!util_format_is_supported(format, usage))
                return FALSE;
 
-       /* Multisample */
-       if (sample_count > 1)
-               return FALSE;
+       if (sample_count > 1) {
+               if (HAVE_LLVM < 0x0304)
+                       return FALSE;
 
-       if ((usage & PIPE_BIND_SAMPLER_VIEW) &&
-           si_is_sampler_format_supported(screen, format)) {
-               retval |= PIPE_BIND_SAMPLER_VIEW;
+               /* 2D tiling on CIK is supported since DRM 2.35.0 */
+               if (rscreen->b.chip_class >= CIK && rscreen->b.info.drm_minor < 35)
+                       return FALSE;
+
+               switch (sample_count) {
+               case 2:
+               case 4:
+               case 8:
+                       break;
+               default:
+                       return FALSE;
+               }
+       }
+
+       if (usage & PIPE_BIND_SAMPLER_VIEW) {
+               if (target == PIPE_BUFFER) {
+                       if (si_is_vertex_format_supported(screen, format))
+                               retval |= PIPE_BIND_SAMPLER_VIEW;
+               } else {
+                       if (si_is_sampler_format_supported(screen, format))
+                               retval |= PIPE_BIND_SAMPLER_VIEW;
+               }
        }
 
        if ((usage & (PIPE_BIND_RENDER_TARGET |
@@ -1595,7 +1545,7 @@ boolean si_is_format_supported(struct pipe_screen *screen,
        return retval == usage;
 }
 
-static unsigned si_tile_mode_index(struct r600_resource_texture *rtex, unsigned level, bool stencil)
+static unsigned si_tile_mode_index(struct r600_texture *rtex, unsigned level, bool stencil)
 {
        unsigned tile_mode_index = 0;
 
@@ -1611,14 +1561,14 @@ static unsigned si_tile_mode_index(struct r600_resource_texture *rtex, unsigned
  * framebuffer handling
  */
 
-static void si_cb(struct r600_context *rctx, struct si_pm4_state *pm4,
+static void si_cb(struct si_context *rctx, struct si_pm4_state *pm4,
                  const struct pipe_framebuffer_state *state, int cb)
 {
-       struct r600_resource_texture *rtex;
-       struct r600_surface *surf;
+       struct r600_texture *rtex;
+       struct si_surface *surf;
        unsigned level = state->cbufs[cb]->u.tex.level;
        unsigned pitch, slice;
-       unsigned color_info, color_attrib;
+       unsigned color_info, color_attrib, color_pitch, color_view;
        unsigned tile_mode_index;
        unsigned format, swap, ntype, endian;
        uint64_t offset;
@@ -1627,14 +1577,23 @@ static void si_cb(struct r600_context *rctx, struct si_pm4_state *pm4,
        unsigned blend_clamp = 0, blend_bypass = 0;
        unsigned max_comp_size;
 
-       surf = (struct r600_surface *)state->cbufs[cb];
-       rtex = (struct r600_resource_texture*)state->cbufs[cb]->texture;
+       surf = (struct si_surface *)state->cbufs[cb];
+       rtex = (struct r600_texture*)state->cbufs[cb]->texture;
 
        offset = rtex->surface.level[level].offset;
-       if (rtex->surface.level[level].mode < RADEON_SURF_MODE_1D) {
+
+       /* Layered rendering doesn't work with LINEAR_GENERAL.
+        * (LINEAR_ALIGNED and others work) */
+       if (rtex->surface.level[level].mode == RADEON_SURF_MODE_LINEAR) {
+               assert(state->cbufs[cb]->u.tex.first_layer == state->cbufs[cb]->u.tex.last_layer);
                offset += rtex->surface.level[level].slice_size *
                          state->cbufs[cb]->u.tex.first_layer;
+               color_view = 0;
+       } else {
+               color_view = S_028C6C_SLICE_START(state->cbufs[cb]->u.tex.first_layer) |
+                            S_028C6C_SLICE_MAX(state->cbufs[cb]->u.tex.last_layer);
        }
+
        pitch = (rtex->surface.level[level].nblk_x) / 8 - 1;
        slice = (rtex->surface.level[level].nblk_x * rtex->surface.level[level].nblk_y) / 64;
        if (slice) {
@@ -1706,28 +1665,67 @@ static void si_cb(struct r600_context *rctx, struct si_pm4_state *pm4,
                S_028C70_NUMBER_TYPE(ntype) |
                S_028C70_ENDIAN(endian);
 
+       color_pitch = S_028C64_TILE_MAX(pitch);
+
        color_attrib = S_028C74_TILE_MODE_INDEX(tile_mode_index) |
                S_028C74_FORCE_DST_ALPHA_1(desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1);
 
-       offset += r600_resource_va(rctx->context.screen, state->cbufs[cb]->texture);
+       if (rtex->resource.b.b.nr_samples > 1) {
+               unsigned log_samples = util_logbase2(rtex->resource.b.b.nr_samples);
+
+               color_attrib |= S_028C74_NUM_SAMPLES(log_samples) |
+                               S_028C74_NUM_FRAGMENTS(log_samples);
+
+               if (rtex->fmask.size) {
+                       color_info |= S_028C70_COMPRESSION(1);
+                       unsigned fmask_bankh = util_logbase2(rtex->fmask.bank_height);
+
+                       color_attrib |= S_028C74_FMASK_TILE_MODE_INDEX(rtex->fmask.tile_mode_index);
+
+                       if (rctx->b.chip_class == SI) {
+                               /* due to a hw bug, FMASK_BANK_HEIGHT must be set on SI too */
+                               color_attrib |= S_028C74_FMASK_BANK_HEIGHT(fmask_bankh);
+                       }
+                       if (rctx->b.chip_class >= CIK) {
+                               color_pitch |= S_028C64_FMASK_TILE_MAX(rtex->fmask.pitch / 8 - 1);
+                       }
+               }
+       }
+
+       if (rtex->cmask.size) {
+               color_info |= S_028C70_FAST_CLEAR(1);
+       }
+
+       offset += r600_resource_va(rctx->b.b.screen, state->cbufs[cb]->texture);
        offset >>= 8;
 
-       /* FIXME handle enabling of CB beyond BASE8 which has different offset */
        si_pm4_add_bo(pm4, &rtex->resource, RADEON_USAGE_READWRITE);
        si_pm4_set_reg(pm4, R_028C60_CB_COLOR0_BASE + cb * 0x3C, offset);
-       si_pm4_set_reg(pm4, R_028C64_CB_COLOR0_PITCH + cb * 0x3C, S_028C64_TILE_MAX(pitch));
+       si_pm4_set_reg(pm4, R_028C64_CB_COLOR0_PITCH + cb * 0x3C, color_pitch);
        si_pm4_set_reg(pm4, R_028C68_CB_COLOR0_SLICE + cb * 0x3C, S_028C68_TILE_MAX(slice));
-
-       if (rtex->surface.level[level].mode < RADEON_SURF_MODE_1D) {
-               si_pm4_set_reg(pm4, R_028C6C_CB_COLOR0_VIEW + cb * 0x3C, 0x00000000);
-       } else {
-               si_pm4_set_reg(pm4, R_028C6C_CB_COLOR0_VIEW + cb * 0x3C,
-                              S_028C6C_SLICE_START(state->cbufs[cb]->u.tex.first_layer) |
-                              S_028C6C_SLICE_MAX(state->cbufs[cb]->u.tex.last_layer));
-       }
+       si_pm4_set_reg(pm4, R_028C6C_CB_COLOR0_VIEW + cb * 0x3C, color_view);
        si_pm4_set_reg(pm4, R_028C70_CB_COLOR0_INFO + cb * 0x3C, color_info);
        si_pm4_set_reg(pm4, R_028C74_CB_COLOR0_ATTRIB + cb * 0x3C, color_attrib);
 
+       if (rtex->cmask.size) {
+               si_pm4_set_reg(pm4, R_028C7C_CB_COLOR0_CMASK + cb * 0x3C,
+                              offset + (rtex->cmask.offset >> 8));
+               si_pm4_set_reg(pm4, R_028C80_CB_COLOR0_CMASK_SLICE + cb * 0x3C,
+                              S_028C80_TILE_MAX(rtex->cmask.slice_tile_max));
+       }
+       if (rtex->fmask.size) {
+               si_pm4_set_reg(pm4, R_028C84_CB_COLOR0_FMASK + cb * 0x3C,
+                              offset + (rtex->fmask.offset >> 8));
+               si_pm4_set_reg(pm4, R_028C88_CB_COLOR0_FMASK_SLICE + cb * 0x3C,
+                              S_028C88_TILE_MAX(rtex->fmask.slice_tile_max));
+       }
+
+       /* set CB_COLOR1_INFO for possible dual-src blending */
+       if (state->nr_cbufs == 1) {
+               assert(cb == 0);
+               si_pm4_set_reg(pm4, R_028C70_CB_COLOR0_INFO + 1 * 0x3C, color_info);
+       }
+
        /* Determine pixel shader export format */
        max_comp_size = si_colorformat_max_comp_size(format);
        if (ntype == V_028C70_NUMBER_SRGB ||
@@ -1735,17 +1733,23 @@ static void si_cb(struct r600_context *rctx, struct si_pm4_state *pm4,
             max_comp_size <= 10) ||
            (ntype == V_028C70_NUMBER_FLOAT && max_comp_size <= 16)) {
                rctx->export_16bpc |= 1 << cb;
+               /* set SPI_SHADER_COL_FORMAT for possible dual-src blending */
+               if (state->nr_cbufs == 1)
+                       rctx->export_16bpc |= 1 << 1;
        }
 }
 
-static void si_db(struct r600_context *rctx, struct si_pm4_state *pm4,
+static void si_db(struct si_context *rctx, struct si_pm4_state *pm4,
                  const struct pipe_framebuffer_state *state)
 {
-       struct r600_resource_texture *rtex;
-       struct r600_surface *surf;
-       unsigned level, pitch, slice, format, tile_mode_index;
-       uint32_t z_info, s_info;
+       struct si_screen *rscreen = rctx->screen;
+       struct r600_texture *rtex;
+       struct si_surface *surf;
+       unsigned level, pitch, slice, format, tile_mode_index, array_mode;
+       unsigned macro_aspect, tile_split, stile_split, bankh, bankw, nbanks, pipe_config;
+       uint32_t z_info, s_info, db_depth_info;
        uint64_t z_offs, s_offs;
+       uint32_t db_htile_data_base, db_htile_surface;
 
        if (state->zsbuf == NULL) {
                si_pm4_set_reg(pm4, R_028040_DB_Z_INFO, S_028040_FORMAT(V_028040_Z_INVALID));
@@ -1753,18 +1757,18 @@ static void si_db(struct r600_context *rctx, struct si_pm4_state *pm4,
                return;
        }
 
-       surf = (struct r600_surface *)state->zsbuf;
+       surf = (struct si_surface *)state->zsbuf;
        level = surf->base.u.tex.level;
-       rtex = (struct r600_resource_texture*)surf->base.texture;
+       rtex = (struct r600_texture*)surf->base.texture;
 
-       format = si_translate_dbformat(rtex->real_format);
+       format = si_translate_dbformat(rtex->resource.b.b.format);
 
        if (format == V_028040_Z_INVALID) {
-               R600_ERR("Invalid DB format: %d, disabling DB.\n", rtex->real_format);
+               R600_ERR("Invalid DB format: %d, disabling DB.\n", rtex->resource.b.b.format);
        }
        assert(format != V_028040_Z_INVALID);
 
-       s_offs = z_offs = r600_resource_va(rctx->context.screen, surf->base.texture);
+       s_offs = z_offs = r600_resource_va(rctx->b.b.screen, surf->base.texture);
        z_offs += rtex->surface.level[level].offset;
        s_offs += rtex->surface.stencil_level[level].offset;
 
@@ -1777,22 +1781,94 @@ static void si_db(struct r600_context *rctx, struct si_pm4_state *pm4,
                slice = slice - 1;
        }
 
+       db_depth_info = S_02803C_ADDR5_SWIZZLE_MASK(1);
+
        z_info = S_028040_FORMAT(format);
+       if (rtex->resource.b.b.nr_samples > 1) {
+               z_info |= S_028040_NUM_SAMPLES(util_logbase2(rtex->resource.b.b.nr_samples));
+       }
+
        if (rtex->surface.flags & RADEON_SURF_SBUFFER)
                s_info = S_028044_FORMAT(V_028044_STENCIL_8);
        else
                s_info = S_028044_FORMAT(V_028044_STENCIL_INVALID);
 
-       tile_mode_index = si_tile_mode_index(rtex, level, false);
-       z_info |= S_028040_TILE_MODE_INDEX(tile_mode_index);
-       tile_mode_index = si_tile_mode_index(rtex, level, true);
-       s_info |= S_028044_TILE_MODE_INDEX(tile_mode_index);
+       if (rctx->b.chip_class >= CIK) {
+               switch (rtex->surface.level[level].mode) {
+               case RADEON_SURF_MODE_2D:
+                       array_mode = V_02803C_ARRAY_2D_TILED_THIN1;
+                       break;
+               case RADEON_SURF_MODE_1D:
+               case RADEON_SURF_MODE_LINEAR_ALIGNED:
+               case RADEON_SURF_MODE_LINEAR:
+               default:
+                       array_mode = V_02803C_ARRAY_1D_TILED_THIN1;
+                       break;
+               }
+               tile_split = rtex->surface.tile_split;
+               stile_split = rtex->surface.stencil_tile_split;
+               macro_aspect = rtex->surface.mtilea;
+               bankw = rtex->surface.bankw;
+               bankh = rtex->surface.bankh;
+               tile_split = cik_tile_split(tile_split);
+               stile_split = cik_tile_split(stile_split);
+               macro_aspect = cik_macro_tile_aspect(macro_aspect);
+               bankw = cik_bank_wh(bankw);
+               bankh = cik_bank_wh(bankh);
+               nbanks = cik_num_banks(rscreen, rtex->surface.bpe, rtex->surface.tile_split);
+               tile_mode_index = si_tile_mode_index(rtex, level, false);
+               pipe_config = cik_db_pipe_config(rscreen, tile_mode_index);
+
+               db_depth_info |= S_02803C_ARRAY_MODE(array_mode) |
+                       S_02803C_PIPE_CONFIG(pipe_config) |
+                       S_02803C_BANK_WIDTH(bankw) |
+                       S_02803C_BANK_HEIGHT(bankh) |
+                       S_02803C_MACRO_TILE_ASPECT(macro_aspect) |
+                       S_02803C_NUM_BANKS(nbanks);
+               z_info |= S_028040_TILE_SPLIT(tile_split);
+               s_info |= S_028044_TILE_SPLIT(stile_split);
+       } else {
+               tile_mode_index = si_tile_mode_index(rtex, level, false);
+               z_info |= S_028040_TILE_MODE_INDEX(tile_mode_index);
+               tile_mode_index = si_tile_mode_index(rtex, level, true);
+               s_info |= S_028044_TILE_MODE_INDEX(tile_mode_index);
+       }
+
+       /* HiZ aka depth buffer htile */
+       /* use htile only for first level */
+       if (rtex->htile_buffer && !level) {
+               const struct util_format_description *fmt_desc;
+
+               z_info |= S_028040_TILE_SURFACE_ENABLE(1);
+
+               /* This is optimal for the clear value of 1.0 and using
+                * the LESS and LEQUAL test functions. Set this to 0
+                * for the opposite case. This can only be changed when
+                * clearing. */
+               z_info |= S_028040_ZRANGE_PRECISION(1);
+
+               fmt_desc = util_format_description(rtex->resource.b.b.format);
+               if (!util_format_has_stencil(fmt_desc)) {
+                       /* Use all of the htile_buffer for depth */
+                       s_info |= S_028044_TILE_STENCIL_DISABLE(1);
+               }
+
+               uint64_t va = r600_resource_va(&rctx->screen->b.b, &rtex->htile_buffer->b.b);
+               db_htile_data_base = va >> 8;
+               db_htile_surface = S_028ABC_FULL_CACHE(1);
+
+               si_pm4_add_bo(pm4, rtex->htile_buffer, RADEON_USAGE_READWRITE);
+       } else {
+               db_htile_data_base = 0;
+               db_htile_surface = 0;
+       }
 
        si_pm4_set_reg(pm4, R_028008_DB_DEPTH_VIEW,
                       S_028008_SLICE_START(state->zsbuf->u.tex.first_layer) |
                       S_028008_SLICE_MAX(state->zsbuf->u.tex.last_layer));
+       si_pm4_set_reg(pm4, R_028014_DB_HTILE_DATA_BASE, db_htile_data_base);
 
-       si_pm4_set_reg(pm4, R_02803C_DB_DEPTH_INFO, S_02803C_ADDR5_SWIZZLE_MASK(1));
+       si_pm4_set_reg(pm4, R_02803C_DB_DEPTH_INFO, db_depth_info);
        si_pm4_set_reg(pm4, R_028040_DB_Z_INFO, z_info);
        si_pm4_set_reg(pm4, R_028044_DB_STENCIL_INFO, s_info);
 
@@ -1804,38 +1880,252 @@ static void si_db(struct r600_context *rctx, struct si_pm4_state *pm4,
 
        si_pm4_set_reg(pm4, R_028058_DB_DEPTH_SIZE, S_028058_PITCH_TILE_MAX(pitch));
        si_pm4_set_reg(pm4, R_02805C_DB_DEPTH_SLICE, S_02805C_SLICE_TILE_MAX(slice));
+
+       si_pm4_set_reg(pm4, R_028ABC_DB_HTILE_SURFACE, db_htile_surface);
+}
+
+#define FILL_SREG(s0x, s0y, s1x, s1y, s2x, s2y, s3x, s3y)  \
+       (((s0x) & 0xf) | (((s0y) & 0xf) << 4) |            \
+       (((s1x) & 0xf) << 8) | (((s1y) & 0xf) << 12) |     \
+       (((s2x) & 0xf) << 16) | (((s2y) & 0xf) << 20) |    \
+        (((s3x) & 0xf) << 24) | (((s3y) & 0xf) << 28))
+
+/* 2xMSAA
+ * There are two locations (-4, 4), (4, -4). */
+static uint32_t sample_locs_2x[] = {
+       FILL_SREG(-4, 4, 4, -4, -4, 4, 4, -4),
+       FILL_SREG(-4, 4, 4, -4, -4, 4, 4, -4),
+       FILL_SREG(-4, 4, 4, -4, -4, 4, 4, -4),
+       FILL_SREG(-4, 4, 4, -4, -4, 4, 4, -4),
+};
+static unsigned max_dist_2x = 4;
+/* 4xMSAA
+ * There are 4 locations: (-2, -2), (2, 2), (-6, 6), (6, -6). */
+static uint32_t sample_locs_4x[] = {
+       FILL_SREG(-2, -2, 2, 2, -6, 6, 6, -6),
+       FILL_SREG(-2, -2, 2, 2, -6, 6, 6, -6),
+       FILL_SREG(-2, -2, 2, 2, -6, 6, 6, -6),
+       FILL_SREG(-2, -2, 2, 2, -6, 6, 6, -6),
+};
+static unsigned max_dist_4x = 6;
+/* Cayman/SI 8xMSAA */
+static uint32_t cm_sample_locs_8x[] = {
+       FILL_SREG(-2, -5, 3, -4, -1, 5, -6, -2),
+       FILL_SREG(-2, -5, 3, -4, -1, 5, -6, -2),
+       FILL_SREG(-2, -5, 3, -4, -1, 5, -6, -2),
+       FILL_SREG(-2, -5, 3, -4, -1, 5, -6, -2),
+       FILL_SREG( 6,  0, 0,  0, -5, 3,  4,  4),
+       FILL_SREG( 6,  0, 0,  0, -5, 3,  4,  4),
+       FILL_SREG( 6,  0, 0,  0, -5, 3,  4,  4),
+       FILL_SREG( 6,  0, 0,  0, -5, 3,  4,  4),
+};
+static unsigned cm_max_dist_8x = 8;
+/* Cayman/SI 16xMSAA */
+static uint32_t cm_sample_locs_16x[] = {
+       FILL_SREG(-7, -3, 7, 3, 1, -5, -5, 5),
+       FILL_SREG(-7, -3, 7, 3, 1, -5, -5, 5),
+       FILL_SREG(-7, -3, 7, 3, 1, -5, -5, 5),
+       FILL_SREG(-7, -3, 7, 3, 1, -5, -5, 5),
+       FILL_SREG(-3, -7, 3, 7, 5, -1, -1, 1),
+       FILL_SREG(-3, -7, 3, 7, 5, -1, -1, 1),
+       FILL_SREG(-3, -7, 3, 7, 5, -1, -1, 1),
+       FILL_SREG(-3, -7, 3, 7, 5, -1, -1, 1),
+       FILL_SREG(-8, -6, 4, 2, 2, -8, -2, 6),
+       FILL_SREG(-8, -6, 4, 2, 2, -8, -2, 6),
+       FILL_SREG(-8, -6, 4, 2, 2, -8, -2, 6),
+       FILL_SREG(-8, -6, 4, 2, 2, -8, -2, 6),
+       FILL_SREG(-4, -2, 0, 4, 6, -4, -6, 0),
+       FILL_SREG(-4, -2, 0, 4, 6, -4, -6, 0),
+       FILL_SREG(-4, -2, 0, 4, 6, -4, -6, 0),
+       FILL_SREG(-4, -2, 0, 4, 6, -4, -6, 0),
+};
+static unsigned cm_max_dist_16x = 8;
+
+static void si_get_sample_position(struct pipe_context *ctx,
+                                  unsigned sample_count,
+                                  unsigned sample_index,
+                                  float *out_value)
+{
+       int offset, index;
+       struct {
+               int idx:4;
+       } val;
+       switch (sample_count) {
+       case 1:
+       default:
+               out_value[0] = out_value[1] = 0.5;
+               break;
+       case 2:
+               offset = 4 * (sample_index * 2);
+               val.idx = (sample_locs_2x[0] >> offset) & 0xf;
+               out_value[0] = (float)(val.idx + 8) / 16.0f;
+               val.idx = (sample_locs_2x[0] >> (offset + 4)) & 0xf;
+               out_value[1] = (float)(val.idx + 8) / 16.0f;
+               break;
+       case 4:
+               offset = 4 * (sample_index * 2);
+               val.idx = (sample_locs_4x[0] >> offset) & 0xf;
+               out_value[0] = (float)(val.idx + 8) / 16.0f;
+               val.idx = (sample_locs_4x[0] >> (offset + 4)) & 0xf;
+               out_value[1] = (float)(val.idx + 8) / 16.0f;
+               break;
+       case 8:
+               offset = 4 * (sample_index % 4 * 2);
+               index = (sample_index / 4) * 4;
+               val.idx = (cm_sample_locs_8x[index] >> offset) & 0xf;
+               out_value[0] = (float)(val.idx + 8) / 16.0f;
+               val.idx = (cm_sample_locs_8x[index] >> (offset + 4)) & 0xf;
+               out_value[1] = (float)(val.idx + 8) / 16.0f;
+               break;
+       case 16:
+               offset = 4 * (sample_index % 4 * 2);
+               index = (sample_index / 4) * 4;
+               val.idx = (cm_sample_locs_16x[index] >> offset) & 0xf;
+               out_value[0] = (float)(val.idx + 8) / 16.0f;
+               val.idx = (cm_sample_locs_16x[index] >> (offset + 4)) & 0xf;
+               out_value[1] = (float)(val.idx + 8) / 16.0f;
+               break;
+       }
+}
+
+static void si_set_msaa_state(struct si_context *rctx, struct si_pm4_state *pm4, int nr_samples)
+{
+       unsigned max_dist = 0;
+
+       switch (nr_samples) {
+       default:
+               nr_samples = 0;
+               break;
+       case 2:
+               si_pm4_set_reg(pm4, R_028BF8_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0, sample_locs_2x[0]);
+               si_pm4_set_reg(pm4, R_028C08_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0, sample_locs_2x[1]);
+               si_pm4_set_reg(pm4, R_028C18_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0, sample_locs_2x[2]);
+               si_pm4_set_reg(pm4, R_028C28_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0, sample_locs_2x[3]);
+               max_dist = max_dist_2x;
+               break;
+       case 4:
+               si_pm4_set_reg(pm4, R_028BF8_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0, sample_locs_4x[0]);
+               si_pm4_set_reg(pm4, R_028C08_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0, sample_locs_4x[1]);
+               si_pm4_set_reg(pm4, R_028C18_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0, sample_locs_4x[2]);
+               si_pm4_set_reg(pm4, R_028C28_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0, sample_locs_4x[3]);
+               max_dist = max_dist_4x;
+               break;
+       case 8:
+               si_pm4_set_reg(pm4, R_028BF8_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0, cm_sample_locs_8x[0]);
+               si_pm4_set_reg(pm4, R_028BFC_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_1, cm_sample_locs_8x[4]);
+               si_pm4_set_reg(pm4, R_028C00_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_2, 0);
+               si_pm4_set_reg(pm4, R_028C04_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_3, 0);
+               si_pm4_set_reg(pm4, R_028C08_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0, cm_sample_locs_8x[1]);
+               si_pm4_set_reg(pm4, R_028C0C_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_1, cm_sample_locs_8x[5]);
+               si_pm4_set_reg(pm4, R_028C10_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_2, 0);
+               si_pm4_set_reg(pm4, R_028C14_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_3, 0);
+               si_pm4_set_reg(pm4, R_028C18_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0, cm_sample_locs_8x[2]);
+               si_pm4_set_reg(pm4, R_028C1C_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_1, cm_sample_locs_8x[6]);
+               si_pm4_set_reg(pm4, R_028C20_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_2, 0);
+               si_pm4_set_reg(pm4, R_028C24_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_3, 0);
+               si_pm4_set_reg(pm4, R_028C28_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0, cm_sample_locs_8x[3]);
+               si_pm4_set_reg(pm4, R_028C2C_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_1, cm_sample_locs_8x[7]);
+               max_dist = cm_max_dist_8x;
+               break;
+       case 16:
+               si_pm4_set_reg(pm4, R_028BF8_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0, cm_sample_locs_16x[0]);
+               si_pm4_set_reg(pm4, R_028BFC_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_1, cm_sample_locs_16x[4]);
+               si_pm4_set_reg(pm4, R_028C00_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_2, cm_sample_locs_16x[8]);
+               si_pm4_set_reg(pm4, R_028C04_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_3, cm_sample_locs_16x[12]);
+               si_pm4_set_reg(pm4, R_028C08_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0, cm_sample_locs_16x[1]);
+               si_pm4_set_reg(pm4, R_028C0C_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_1, cm_sample_locs_16x[5]);
+               si_pm4_set_reg(pm4, R_028C10_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_2, cm_sample_locs_16x[9]);
+               si_pm4_set_reg(pm4, R_028C14_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_3, cm_sample_locs_16x[13]);
+               si_pm4_set_reg(pm4, R_028C18_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0, cm_sample_locs_16x[2]);
+               si_pm4_set_reg(pm4, R_028C1C_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_1, cm_sample_locs_16x[6]);
+               si_pm4_set_reg(pm4, R_028C20_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_2, cm_sample_locs_16x[10]);
+               si_pm4_set_reg(pm4, R_028C24_PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_3, cm_sample_locs_16x[14]);
+               si_pm4_set_reg(pm4, R_028C28_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0, cm_sample_locs_16x[3]);
+               si_pm4_set_reg(pm4, R_028C2C_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_1, cm_sample_locs_16x[7]);
+               si_pm4_set_reg(pm4, R_028C30_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_2, cm_sample_locs_16x[11]);
+               si_pm4_set_reg(pm4, R_028C34_PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_3, cm_sample_locs_16x[15]);
+               max_dist = cm_max_dist_16x;
+               break;
+       }
+
+       if (nr_samples > 1) {
+               unsigned log_samples = util_logbase2(nr_samples);
+
+               si_pm4_set_reg(pm4, R_028BDC_PA_SC_LINE_CNTL,
+                              S_028BDC_LAST_PIXEL(1) |
+                              S_028BDC_EXPAND_LINE_WIDTH(1));
+               si_pm4_set_reg(pm4, R_028BE0_PA_SC_AA_CONFIG,
+                              S_028BE0_MSAA_NUM_SAMPLES(log_samples) |
+                              S_028BE0_MAX_SAMPLE_DIST(max_dist) |
+                              S_028BE0_MSAA_EXPOSED_SAMPLES(log_samples));
+
+               si_pm4_set_reg(pm4, R_028804_DB_EQAA,
+                              S_028804_MAX_ANCHOR_SAMPLES(log_samples) |
+                              S_028804_PS_ITER_SAMPLES(log_samples) |
+                              S_028804_MASK_EXPORT_NUM_SAMPLES(log_samples) |
+                              S_028804_ALPHA_TO_MASK_NUM_SAMPLES(log_samples) |
+                              S_028804_HIGH_QUALITY_INTERSECTIONS(1) |
+                              S_028804_STATIC_ANCHOR_ASSOCIATIONS(1));
+       } else {
+               si_pm4_set_reg(pm4, R_028BDC_PA_SC_LINE_CNTL, S_028BDC_LAST_PIXEL(1));
+               si_pm4_set_reg(pm4, R_028BE0_PA_SC_AA_CONFIG, 0);
+
+               si_pm4_set_reg(pm4, R_028804_DB_EQAA,
+                              S_028804_HIGH_QUALITY_INTERSECTIONS(1) |
+                              S_028804_STATIC_ANCHOR_ASSOCIATIONS(1));
+       }
 }
 
 static void si_set_framebuffer_state(struct pipe_context *ctx,
                                     const struct pipe_framebuffer_state *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
-       struct si_pm4_state *pm4 = CALLOC_STRUCT(si_pm4_state);
-       uint32_t shader_mask, tl, br;
-       int tl_x, tl_y, br_x, br_y;
+       struct si_context *rctx = (struct si_context *)ctx;
+       struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
+       uint32_t tl, br;
+       int tl_x, tl_y, br_x, br_y, nr_samples, i;
 
        if (pm4 == NULL)
                return;
 
-       si_pm4_inval_fb_cache(pm4, state->nr_cbufs);
-
-       if (state->zsbuf)
-               si_pm4_inval_zsbuf_cache(pm4);
+       if (rctx->framebuffer.nr_cbufs) {
+               rctx->b.flags |= R600_CONTEXT_FLUSH_AND_INV_CB |
+                                R600_CONTEXT_FLUSH_AND_INV_CB_META;
+       }
+       if (rctx->framebuffer.zsbuf) {
+               rctx->b.flags |= R600_CONTEXT_FLUSH_AND_INV_DB |
+                                R600_CONTEXT_FLUSH_AND_INV_DB_META;
+       }
 
        util_copy_framebuffer_state(&rctx->framebuffer, state);
 
        /* build states */
        rctx->export_16bpc = 0;
-       for (int i = 0; i < state->nr_cbufs; i++) {
+       rctx->fb_compressed_cb_mask = 0;
+       for (i = 0; i < state->nr_cbufs; i++) {
+               struct r600_texture *rtex;
+
+               if (!state->cbufs[i]) {
+                       si_pm4_set_reg(pm4, R_028C70_CB_COLOR0_INFO + i * 0x3C,
+                                      S_028C70_FORMAT(V_028C70_COLOR_INVALID));
+                       continue;
+               }
+
+               rtex = (struct r600_texture*)state->cbufs[i]->texture;
+
                si_cb(rctx, pm4, state, i);
+
+               if (rtex->fmask.size || rtex->cmask.size) {
+                       rctx->fb_compressed_cb_mask |= 1 << i;
+               }
        }
+       for (; i < 8; i++) {
+               si_pm4_set_reg(pm4, R_028C70_CB_COLOR0_INFO + i * 0x3C,
+                              S_028C70_FORMAT(V_028C70_COLOR_INVALID));
+       }
+
        assert(!(rctx->export_16bpc & ~0xff));
        si_db(rctx, pm4, state);
 
-       shader_mask = 0;
-       for (int i = 0; i < state->nr_cbufs; i++) {
-               shader_mask |= 0xf << (i * 4);
-       }
        tl_x = 0;
        tl_y = 0;
        br_x = state->width;
@@ -1852,10 +2142,13 @@ static void si_set_framebuffer_state(struct pipe_context *ctx,
        si_pm4_set_reg(pm4, R_028034_PA_SC_SCREEN_SCISSOR_BR, br);
        si_pm4_set_reg(pm4, R_028204_PA_SC_WINDOW_SCISSOR_TL, tl);
        si_pm4_set_reg(pm4, R_028208_PA_SC_WINDOW_SCISSOR_BR, br);
-       si_pm4_set_reg(pm4, R_028200_PA_SC_WINDOW_OFFSET, 0x00000000);
-       si_pm4_set_reg(pm4, R_028230_PA_SC_EDGERULE, 0xAAAAAAAA);
-       si_pm4_set_reg(pm4, R_02823C_CB_SHADER_MASK, shader_mask);
-       si_pm4_set_reg(pm4, R_028BE0_PA_SC_AA_CONFIG, 0x00000000);
+
+       nr_samples = util_framebuffer_get_num_samples(state);
+
+       si_set_msaa_state(rctx, pm4, nr_samples);
+       rctx->fb_log_samples = util_logbase2(nr_samples);
+       rctx->fb_cb0_is_integer = state->nr_cbufs && state->cbufs[0] &&
+                                 util_format_is_pure_integer(state->cbufs[0]->format);
 
        si_pm4_set_state(rctx, framebuffer, pm4);
        si_update_fb_rs_state(rctx);
@@ -1871,7 +2164,7 @@ static INLINE void si_shader_selector_key(struct pipe_context *ctx,
                                          struct si_pipe_shader_selector *sel,
                                          union si_shader_key *key)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        memset(key, 0, sizeof(*key));
 
        if (sel->type == PIPE_SHADER_VERTEX) {
@@ -1882,17 +2175,33 @@ static INLINE void si_shader_selector_key(struct pipe_context *ctx,
                for (i = 0; i < rctx->vertex_elements->count; ++i)
                        key->vs.instance_divisors[i] = rctx->vertex_elements->elements[i].instance_divisor;
 
+               if (rctx->queued.named.rasterizer->clip_plane_enable & 0xf0)
+                       key->vs.ucps_enabled |= 0x2;
+               if (rctx->queued.named.rasterizer->clip_plane_enable & 0xf)
+                       key->vs.ucps_enabled |= 0x1;
        } else if (sel->type == PIPE_SHADER_FRAGMENT) {
                if (sel->fs_write_all)
                        key->ps.nr_cbufs = rctx->framebuffer.nr_cbufs;
                key->ps.export_16bpc = rctx->export_16bpc;
+
                if (rctx->queued.named.rasterizer) {
                        key->ps.color_two_side = rctx->queued.named.rasterizer->two_side;
                        key->ps.flatshade = rctx->queued.named.rasterizer->flatshade;
+
+                       if (rctx->queued.named.blend) {
+                               key->ps.alpha_to_one = rctx->queued.named.blend->alpha_to_one &&
+                                                      rctx->queued.named.rasterizer->multisample_enable &&
+                                                      !rctx->fb_cb0_is_integer;
+                       }
                }
                if (rctx->queued.named.dsa) {
                        key->ps.alpha_func = rctx->queued.named.dsa->alpha_func;
-                       key->ps.alpha_ref = rctx->queued.named.dsa->alpha_ref;
+
+                       /* Alpha-test should be disabled if colorbuffer 0 is integer. */
+                       if (rctx->framebuffer.nr_cbufs &&
+                           rctx->framebuffer.cbufs[0] &&
+                           util_format_is_pure_integer(rctx->framebuffer.cbufs[0]->texture->format))
+                               key->ps.alpha_func = PIPE_FUNC_ALWAYS;
                } else {
                        key->ps.alpha_func = PIPE_FUNC_ALWAYS;
                }
@@ -1947,17 +2256,6 @@ int si_shader_select(struct pipe_context *ctx,
                        FREE(shader);
                        return r;
                }
-
-               /* We don't know the value of fs_write_all property until we built
-                * at least one variant, so we may need to recompute the key (include
-                * rctx->framebuffer.nr_cbufs) after building first variant. */
-               if (sel->type == PIPE_SHADER_FRAGMENT &&
-                   sel->num_shaders == 0 &&
-                   shader->shader.fs_write_all) {
-                       sel->fs_write_all = 1;
-                       si_shader_selector_key(ctx, sel, &shader->key);
-               }
-
                sel->num_shaders++;
        }
 
@@ -1981,6 +2279,13 @@ static void *si_create_shader_state(struct pipe_context *ctx,
        sel->tokens = tgsi_dup_tokens(state->tokens);
        sel->so = state->stream_output;
 
+       if (pipe_shader_type == PIPE_SHADER_FRAGMENT) {
+               struct tgsi_shader_info info;
+
+               tgsi_scan_shader(state->tokens, &info);
+               sel->fs_write_all = info.color0_writes_all_cbufs;
+       }
+
        r = si_shader_select(ctx, sel, NULL);
        if (r) {
            free(sel);
@@ -2004,40 +2309,41 @@ static void *si_create_vs_state(struct pipe_context *ctx,
 
 static void si_bind_vs_shader(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_pipe_shader_selector *sel = state;
 
        if (rctx->vs_shader == sel)
                return;
 
-       rctx->vs_shader = sel;
+       if (!sel || !sel->current)
+               return;
 
-       if (sel && sel->current)
-               si_pm4_bind_state(rctx, vs, sel->current->pm4);
-       else
-               si_pm4_bind_state(rctx, vs, rctx->dummy_pixel_shader->pm4);
+       rctx->vs_shader = sel;
+       si_pm4_bind_state(rctx, vs, sel->current->pm4);
+       rctx->b.streamout.stride_in_dw = sel->so.stride;
+       rctx->b.flags |= R600_CONTEXT_INV_SHADER_CACHE;
 }
 
 static void si_bind_ps_shader(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_pipe_shader_selector *sel = state;
 
        if (rctx->ps_shader == sel)
                return;
 
-       rctx->ps_shader = sel;
+       if (!sel || !sel->current)
+               sel = rctx->dummy_pixel_shader;
 
-       if (sel && sel->current)
-               si_pm4_bind_state(rctx, ps, sel->current->pm4);
-       else
-               si_pm4_bind_state(rctx, ps, rctx->dummy_pixel_shader->pm4);
+       rctx->ps_shader = sel;
+       si_pm4_bind_state(rctx, ps, sel->current->pm4);
+       rctx->b.flags |= R600_CONTEXT_INV_SHADER_CACHE;
 }
 
 static void si_delete_shader_selector(struct pipe_context *ctx,
                                      struct si_pipe_shader_selector *sel)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_pipe_shader *p = sel->current, *c;
 
        while (p) {
@@ -2054,7 +2360,7 @@ static void si_delete_shader_selector(struct pipe_context *ctx,
 
 static void si_delete_vs_shader(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_pipe_shader_selector *sel = (struct si_pipe_shader_selector *)state;
 
        if (rctx->vs_shader == sel) {
@@ -2066,7 +2372,7 @@ static void si_delete_vs_shader(struct pipe_context *ctx, void *state)
 
 static void si_delete_ps_shader(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_pipe_shader_selector *sel = (struct si_pipe_shader_selector *)state;
 
        if (rctx->ps_shader == sel) {
@@ -2085,7 +2391,7 @@ static struct pipe_sampler_view *si_create_sampler_view(struct pipe_context *ctx
                                                        const struct pipe_sampler_view *state)
 {
        struct si_pipe_sampler_view *view = CALLOC_STRUCT(si_pipe_sampler_view);
-       struct r600_resource_texture *tmp = (struct r600_resource_texture*)texture;
+       struct r600_texture *tmp = (struct r600_texture*)texture;
        const struct util_format_description *desc;
        unsigned format, num_format;
        uint32_t pitch = 0;
@@ -2102,10 +2408,34 @@ static struct pipe_sampler_view *si_create_sampler_view(struct pipe_context *ctx
        /* initialize base object */
        view->base = *state;
        view->base.texture = NULL;
-       pipe_reference(NULL, &texture->reference);
-       view->base.texture = texture;
+       pipe_resource_reference(&view->base.texture, texture);
        view->base.reference.count = 1;
        view->base.context = ctx;
+       view->resource = &tmp->resource;
+
+       /* Buffer resource. */
+       if (texture->target == PIPE_BUFFER) {
+               unsigned stride;
+
+               desc = util_format_description(state->format);
+               first_non_void = util_format_get_first_non_void_channel(state->format);
+               stride = desc->block.bits / 8;
+               va = r600_resource_va(ctx->screen, texture) + state->u.buf.first_element*stride;
+               format = si_translate_buffer_dataformat(ctx->screen, desc, first_non_void);
+               num_format = si_translate_buffer_numformat(ctx->screen, desc, first_non_void);
+
+               view->state[0] = va;
+               view->state[1] = S_008F04_BASE_ADDRESS_HI(va >> 32) |
+                                S_008F04_STRIDE(stride);
+               view->state[2] = state->u.buf.last_element + 1 - state->u.buf.first_element;
+               view->state[3] = S_008F0C_DST_SEL_X(si_map_swizzle(desc->swizzle[0])) |
+                                S_008F0C_DST_SEL_Y(si_map_swizzle(desc->swizzle[1])) |
+                                S_008F0C_DST_SEL_Z(si_map_swizzle(desc->swizzle[2])) |
+                                S_008F0C_DST_SEL_W(si_map_swizzle(desc->swizzle[3])) |
+                                S_008F0C_NUM_FORMAT(num_format) |
+                                S_008F0C_DATA_FORMAT(format);
+               return &view->base;
+       }
 
        state_swizzle[0] = state->swizzle_r;
        state_swizzle[1] = state->swizzle_g;
@@ -2217,8 +2547,6 @@ static struct pipe_sampler_view *si_create_sampler_view(struct pipe_context *ctx
                format = 0;
        }
 
-       view->resource = &tmp->resource;
-
        /* not supported any more */
        //endian = si_colorformat_endian_swap(format);
 
@@ -2236,6 +2564,7 @@ static struct pipe_sampler_view *si_create_sampler_view(struct pipe_context *ctx
 
        va = r600_resource_va(ctx->screen, texture);
        va += surflevel[0].offset;
+       va += tmp->mipmap_shift * surflevel[texture->last_level].slice_size;
        view->state[0] = va >> 8;
        view->state[1] = (S_008F14_BASE_ADDRESS_HI(va >> 40) |
                          S_008F14_DATA_FORMAT(format) |
@@ -2246,17 +2575,60 @@ static struct pipe_sampler_view *si_create_sampler_view(struct pipe_context *ctx
                          S_008F1C_DST_SEL_Y(si_map_swizzle(swizzle[1])) |
                          S_008F1C_DST_SEL_Z(si_map_swizzle(swizzle[2])) |
                          S_008F1C_DST_SEL_W(si_map_swizzle(swizzle[3])) |
-                         S_008F1C_BASE_LEVEL(state->u.tex.first_level) |
-                         S_008F1C_LAST_LEVEL(state->u.tex.last_level) |
+                         S_008F1C_BASE_LEVEL(texture->nr_samples > 1 ?
+                                                     0 : state->u.tex.first_level - tmp->mipmap_shift) |
+                         S_008F1C_LAST_LEVEL(texture->nr_samples > 1 ?
+                                                     util_logbase2(texture->nr_samples) :
+                                                     state->u.tex.last_level - tmp->mipmap_shift) |
                          S_008F1C_TILING_INDEX(si_tile_mode_index(tmp, 0, false)) |
                          S_008F1C_POW2_PAD(texture->last_level > 0) |
-                         S_008F1C_TYPE(si_tex_dim(texture->target)));
+                         S_008F1C_TYPE(si_tex_dim(texture->target, texture->nr_samples)));
        view->state[4] = (S_008F20_DEPTH(depth - 1) | S_008F20_PITCH(pitch - 1));
        view->state[5] = (S_008F24_BASE_ARRAY(state->u.tex.first_layer) |
                          S_008F24_LAST_ARRAY(state->u.tex.last_layer));
        view->state[6] = 0;
        view->state[7] = 0;
 
+       /* Initialize the sampler view for FMASK. */
+       if (tmp->fmask.size) {
+               uint64_t va = r600_resource_va(ctx->screen, texture) + tmp->fmask.offset;
+               uint32_t fmask_format;
+
+               switch (texture->nr_samples) {
+               case 2:
+                       fmask_format = V_008F14_IMG_DATA_FORMAT_FMASK8_S2_F2;
+                       break;
+               case 4:
+                       fmask_format = V_008F14_IMG_DATA_FORMAT_FMASK8_S4_F4;
+                       break;
+               case 8:
+                       fmask_format = V_008F14_IMG_DATA_FORMAT_FMASK32_S8_F8;
+                       break;
+               default:
+                       assert(0);
+                       fmask_format = V_008F14_IMG_DATA_FORMAT_INVALID;
+               }
+
+               view->fmask_state[0] = va >> 8;
+               view->fmask_state[1] = S_008F14_BASE_ADDRESS_HI(va >> 40) |
+                                      S_008F14_DATA_FORMAT(fmask_format) |
+                                      S_008F14_NUM_FORMAT(V_008F14_IMG_NUM_FORMAT_UINT);
+               view->fmask_state[2] = S_008F18_WIDTH(width - 1) |
+                                      S_008F18_HEIGHT(height - 1);
+               view->fmask_state[3] = S_008F1C_DST_SEL_X(V_008F1C_SQ_SEL_X) |
+                                      S_008F1C_DST_SEL_Y(V_008F1C_SQ_SEL_X) |
+                                      S_008F1C_DST_SEL_Z(V_008F1C_SQ_SEL_X) |
+                                      S_008F1C_DST_SEL_W(V_008F1C_SQ_SEL_X) |
+                                      S_008F1C_TILING_INDEX(tmp->fmask.tile_mode_index) |
+                                      S_008F1C_TYPE(si_tex_dim(texture->target, 0));
+               view->fmask_state[4] = S_008F20_DEPTH(depth - 1) |
+                                      S_008F20_PITCH(tmp->fmask.pitch - 1);
+               view->fmask_state[5] = S_008F24_BASE_ARRAY(state->u.tex.first_layer) |
+                                      S_008F24_LAST_ARRAY(state->u.tex.last_layer);
+               view->fmask_state[6] = 0;
+               view->fmask_state[7] = 0;
+       }
+
        return &view->base;
 }
 
@@ -2269,11 +2641,31 @@ static void si_sampler_view_destroy(struct pipe_context *ctx,
        FREE(resource);
 }
 
+static bool wrap_mode_uses_border_color(unsigned wrap, bool linear_filter)
+{
+       return wrap == PIPE_TEX_WRAP_CLAMP_TO_BORDER ||
+              wrap == PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER ||
+              (linear_filter &&
+               (wrap == PIPE_TEX_WRAP_CLAMP ||
+                wrap == PIPE_TEX_WRAP_MIRROR_CLAMP));
+}
+
+static bool sampler_state_needs_border_color(const struct pipe_sampler_state *state)
+{
+       bool linear_filter = state->min_img_filter != PIPE_TEX_FILTER_NEAREST ||
+                            state->mag_img_filter != PIPE_TEX_FILTER_NEAREST;
+
+       return (state->border_color.ui[0] || state->border_color.ui[1] ||
+               state->border_color.ui[2] || state->border_color.ui[3]) &&
+              (wrap_mode_uses_border_color(state->wrap_s, linear_filter) ||
+               wrap_mode_uses_border_color(state->wrap_t, linear_filter) ||
+               wrap_mode_uses_border_color(state->wrap_r, linear_filter));
+}
+
 static void *si_create_sampler_state(struct pipe_context *ctx,
                                     const struct pipe_sampler_state *state)
 {
        struct si_pipe_sampler_state *rstate = CALLOC_STRUCT(si_pipe_sampler_state);
-       union util_color uc;
        unsigned aniso_flag_offset = state->max_anisotropy > 1 ? 2 : 0;
        unsigned border_color_type;
 
@@ -2281,20 +2673,10 @@ static void *si_create_sampler_state(struct pipe_context *ctx,
                return NULL;
        }
 
-       util_pack_color(state->border_color.f, PIPE_FORMAT_A8R8G8B8_UNORM, &uc);
-       switch (uc.ui) {
-       case 0x000000FF:
-               border_color_type = V_008F3C_SQ_TEX_BORDER_COLOR_OPAQUE_BLACK;
-               break;
-       case 0x00000000:
-               border_color_type = V_008F3C_SQ_TEX_BORDER_COLOR_TRANS_BLACK;
-               break;
-       case 0xFFFFFFFF:
-               border_color_type = V_008F3C_SQ_TEX_BORDER_COLOR_OPAQUE_WHITE;
-               break;
-       default: /* Use border color pointer */
+       if (sampler_state_needs_border_color(state))
                border_color_type = V_008F3C_SQ_TEX_BORDER_COLOR_REGISTER;
-       }
+       else
+               border_color_type = V_008F3C_SQ_TEX_BORDER_COLOR_TRANS_BLACK;
 
        rstate->val[0] = (S_008F30_CLAMP_X(si_tex_wrap(state->wrap_s)) |
                          S_008F30_CLAMP_Y(si_tex_wrap(state->wrap_t)) |
@@ -2313,102 +2695,92 @@ static void *si_create_sampler_state(struct pipe_context *ctx,
        rstate->val[3] = S_008F3C_BORDER_COLOR_TYPE(border_color_type);
 
        if (border_color_type == V_008F3C_SQ_TEX_BORDER_COLOR_REGISTER) {
-               memcpy(rstate->border_color, state->border_color.f,
+               memcpy(rstate->border_color, state->border_color.ui,
                       sizeof(rstate->border_color));
        }
 
        return rstate;
 }
 
-static struct si_pm4_state *si_set_sampler_view(struct r600_context *rctx,
-                                               unsigned count,
-                                               struct pipe_sampler_view **views,
-                                               struct r600_textures_info *samplers,
-                                               unsigned user_data_reg)
+/* XXX consider moving this function to si_descriptors.c for gcc to inline
+ *     the si_set_sampler_view calls. LTO might help too. */
+static void si_set_sampler_views(struct pipe_context *ctx,
+                                unsigned shader, unsigned start,
+                                 unsigned count,
+                                struct pipe_sampler_view **views)
 {
-       struct si_pipe_sampler_view **resource = (struct si_pipe_sampler_view **)views;
-       struct si_pm4_state *pm4 = CALLOC_STRUCT(si_pm4_state);
-       int i, j;
+       struct si_context *rctx = (struct si_context *)ctx;
+       struct si_textures_info *samplers = &rctx->samplers[shader];
+       struct si_pipe_sampler_view **rviews = (struct si_pipe_sampler_view **)views;
+       int i;
 
-       if (!count)
-               goto out;
+       if (shader != PIPE_SHADER_VERTEX && shader != PIPE_SHADER_FRAGMENT)
+               return;
 
-       si_pm4_inval_texture_cache(pm4);
+       assert(start == 0);
 
-       si_pm4_sh_data_begin(pm4);
        for (i = 0; i < count; i++) {
-               pipe_sampler_view_reference(
-                       (struct pipe_sampler_view **)&samplers->views[i],
-                       views[i]);
+               if (!views[i]) {
+                       samplers->depth_texture_mask &= ~(1 << i);
+                       samplers->compressed_colortex_mask &= ~(1 << i);
+                       si_set_sampler_view(rctx, shader, i, NULL, NULL);
+                       si_set_sampler_view(rctx, shader, FMASK_TEX_OFFSET + i,
+                                           NULL, NULL);
+                       continue;
+               }
 
-               if (views[i]) {
-                       struct r600_resource_texture *rtex =
-                               (struct r600_resource_texture*)views[i]->texture;
+               si_set_sampler_view(rctx, shader, i, views[i], rviews[i]->state);
+
+               if (views[i]->texture->target != PIPE_BUFFER) {
+                       struct r600_texture *rtex =
+                               (struct r600_texture*)views[i]->texture;
 
                        if (rtex->is_depth && !rtex->is_flushing_texture) {
                                samplers->depth_texture_mask |= 1 << i;
                        } else {
                                samplers->depth_texture_mask &= ~(1 << i);
                        }
+                       if (rtex->cmask.size || rtex->fmask.size) {
+                               samplers->compressed_colortex_mask |= 1 << i;
+                       } else {
+                               samplers->compressed_colortex_mask &= ~(1 << i);
+                       }
 
-                       si_pm4_add_bo(pm4, resource[i]->resource, RADEON_USAGE_READ);
-               } else {
-                       samplers->depth_texture_mask &= ~(1 << i);
-               }
-
-               for (j = 0; j < Elements(resource[i]->state); ++j) {
-                       si_pm4_sh_data_add(pm4, resource[i] ? resource[i]->state[j] : 0);
+                       if (rtex->fmask.size) {
+                               si_set_sampler_view(rctx, shader, FMASK_TEX_OFFSET + i,
+                                                   views[i], rviews[i]->fmask_state);
+                       } else {
+                               si_set_sampler_view(rctx, shader, FMASK_TEX_OFFSET + i,
+                                                   NULL, NULL);
+                       }
                }
        }
-
-       for (i = count; i < NUM_TEX_UNITS; i++) {
-               if (samplers->views[i])
-                       pipe_sampler_view_reference((struct pipe_sampler_view **)&samplers->views[i], NULL);
+       for (; i < samplers->n_views; i++) {
+               samplers->depth_texture_mask &= ~(1 << i);
+               samplers->compressed_colortex_mask &= ~(1 << i);
+               si_set_sampler_view(rctx, shader, i, NULL, NULL);
+               si_set_sampler_view(rctx, shader, FMASK_TEX_OFFSET + i,
+                                   NULL, NULL);
        }
 
-       si_pm4_sh_data_end(pm4, user_data_reg, SI_SGPR_RESOURCE);
-
-out:
-       rctx->ps_samplers.n_views = count;
-       return pm4;
-}
-
-static void si_set_vs_sampler_view(struct pipe_context *ctx, unsigned count,
-                                  struct pipe_sampler_view **views)
-{
-       struct r600_context *rctx = (struct r600_context *)ctx;
-       struct si_pm4_state *pm4;
-
-       pm4 = si_set_sampler_view(rctx, count, views, &rctx->vs_samplers,
-                           R_00B130_SPI_SHADER_USER_DATA_VS_0);
-       si_pm4_set_state(rctx, vs_sampler_views, pm4);
-}
-
-static void si_set_ps_sampler_view(struct pipe_context *ctx, unsigned count,
-                                  struct pipe_sampler_view **views)
-{
-       struct r600_context *rctx = (struct r600_context *)ctx;
-       struct si_pm4_state *pm4;
-
-       pm4 = si_set_sampler_view(rctx, count, views, &rctx->ps_samplers,
-                                 R_00B030_SPI_SHADER_USER_DATA_PS_0);
-       si_pm4_set_state(rctx, ps_sampler_views, pm4);
+       samplers->n_views = count;
+       rctx->b.flags |= R600_CONTEXT_INV_TEX_CACHE;
 }
 
-static struct si_pm4_state *si_bind_sampler(struct r600_context *rctx, unsigned count,
-                                           void **states,
-                                           struct r600_textures_info *samplers,
-                                           unsigned user_data_reg)
+static struct si_pm4_state *si_set_sampler_states(struct si_context *rctx, unsigned count,
+                                                  void **states,
+                                                  struct si_textures_info *samplers,
+                                                  unsigned user_data_reg)
 {
        struct si_pipe_sampler_state **rstates = (struct si_pipe_sampler_state **)states;
-       struct si_pm4_state *pm4 = CALLOC_STRUCT(si_pm4_state);
+       struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
        uint32_t *border_color_table = NULL;
        int i, j;
 
        if (!count)
                goto out;
 
-       si_pm4_inval_texture_cache(pm4);
+       rctx->b.flags |= R600_CONTEXT_INV_TEX_CACHE;
 
        si_pm4_sh_data_begin(pm4);
        for (i = 0; i < count; i++) {
@@ -2418,29 +2790,26 @@ static struct si_pm4_state *si_bind_sampler(struct r600_context *rctx, unsigned
                        if (!rctx->border_color_table ||
                            ((rctx->border_color_offset + count - i) &
                             C_008F3C_BORDER_COLOR_PTR)) {
-                               si_resource_reference(&rctx->border_color_table, NULL);
+                               r600_resource_reference(&rctx->border_color_table, NULL);
                                rctx->border_color_offset = 0;
 
                                rctx->border_color_table =
-                                       si_resource_create_custom(&rctx->screen->screen,
+                                       r600_resource_create_custom(&rctx->screen->b.b,
                                                                  PIPE_USAGE_STAGING,
                                                                  4096 * 4 * 4);
                        }
 
                        if (!border_color_table) {
                                border_color_table =
-                                       rctx->ws->buffer_map(rctx->border_color_table->cs_buf,
-                                                            rctx->cs,
+                                       rctx->b.ws->buffer_map(rctx->border_color_table->cs_buf,
+                                                            rctx->b.rings.gfx.cs,
                                                             PIPE_TRANSFER_WRITE |
                                                             PIPE_TRANSFER_UNSYNCHRONIZED);
                        }
 
                        for (j = 0; j < 4; j++) {
-                               union fi border_color;
-
-                               border_color.f = rstates[i]->border_color[j];
                                border_color_table[4 * rctx->border_color_offset + j] =
-                                       util_le32_to_cpu(border_color.i);
+                                       util_le32_to_cpu(rstates[i]->border_color[j]);
                        }
 
                        rstates[i]->val[3] &= C_008F3C_BORDER_COLOR_PTR;
@@ -2455,11 +2824,13 @@ static struct si_pm4_state *si_bind_sampler(struct r600_context *rctx, unsigned
 
        if (border_color_table) {
                uint64_t va_offset =
-                       r600_resource_va(&rctx->screen->screen,
+                       r600_resource_va(&rctx->screen->b.b,
                                         (void*)rctx->border_color_table);
 
                si_pm4_set_reg(pm4, R_028080_TA_BC_BASE_ADDR, va_offset >> 8);
-               rctx->ws->buffer_unmap(rctx->border_color_table->cs_buf);
+               if (rctx->b.chip_class >= CIK)
+                       si_pm4_set_reg(pm4, R_028084_TA_BC_BASE_ADDR_HI, va_offset >> 40);
+               rctx->b.ws->buffer_unmap(rctx->border_color_table->cs_buf);
                si_pm4_add_bo(pm4, rctx->border_color_table, RADEON_USAGE_READ);
        }
 
@@ -2470,89 +2841,65 @@ out:
        return pm4;
 }
 
-static void si_bind_vs_sampler(struct pipe_context *ctx, unsigned count, void **states)
+static void si_bind_vs_sampler_states(struct pipe_context *ctx, unsigned count, void **states)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_pm4_state *pm4;
 
-       pm4 = si_bind_sampler(rctx, count, states, &rctx->vs_samplers,
+       pm4 = si_set_sampler_states(rctx, count, states, &rctx->samplers[PIPE_SHADER_VERTEX],
                              R_00B130_SPI_SHADER_USER_DATA_VS_0);
        si_pm4_set_state(rctx, vs_sampler, pm4);
 }
 
-static void si_bind_ps_sampler(struct pipe_context *ctx, unsigned count, void **states)
+static void si_bind_ps_sampler_states(struct pipe_context *ctx, unsigned count, void **states)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_pm4_state *pm4;
 
-       pm4 = si_bind_sampler(rctx, count, states, &rctx->ps_samplers,
+       pm4 = si_set_sampler_states(rctx, count, states, &rctx->samplers[PIPE_SHADER_FRAGMENT],
                              R_00B030_SPI_SHADER_USER_DATA_PS_0);
        si_pm4_set_state(rctx, ps_sampler, pm4);
 }
 
-static void si_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask)
-{
-}
 
-static void si_delete_sampler_state(struct pipe_context *ctx, void *state)
+static void si_bind_sampler_states(struct pipe_context *ctx, unsigned shader,
+                                   unsigned start, unsigned count,
+                                   void **states)
 {
-       free(state);
-}
+   assert(start == 0);
 
-/*
- * Constants
- */
-static void si_set_constant_buffer(struct pipe_context *ctx, uint shader, uint index,
-                                  struct pipe_constant_buffer *input)
-{
-       struct r600_context *rctx = (struct r600_context *)ctx;
-       struct r600_constbuf_state *state = &rctx->constbuf_state[shader];
-       struct pipe_constant_buffer *cb;
-       const uint8_t *ptr;
-
-       /* Note that the state tracker can unbind constant buffers by
-        * passing NULL here.
-        */
-       if (unlikely(!input || (!input->buffer && !input->user_buffer))) {
-               state->enabled_mask &= ~(1 << index);
-               state->dirty_mask &= ~(1 << index);
-               pipe_resource_reference(&state->cb[index].buffer, NULL);
-               return;
-       }
+   switch (shader) {
+   case PIPE_SHADER_VERTEX:
+      si_bind_vs_sampler_states(ctx, count, states);
+      break;
+   case PIPE_SHADER_FRAGMENT:
+      si_bind_ps_sampler_states(ctx, count, states);
+      break;
+   default:
+      ;
+   }
+}
 
-       cb = &state->cb[index];
-       cb->buffer_size = input->buffer_size;
 
-       ptr = input->user_buffer;
 
-       if (ptr) {
-               /* Upload the user buffer. */
-               if (R600_BIG_ENDIAN) {
-                       uint32_t *tmpPtr;
-                       unsigned i, size = input->buffer_size;
+static void si_set_sample_mask(struct pipe_context *ctx, unsigned sample_mask)
+{
+       struct si_context *rctx = (struct si_context *)ctx;
+       struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
+       uint16_t mask = sample_mask;
 
-                       if (!(tmpPtr = malloc(size))) {
-                               R600_ERR("Failed to allocate BE swap buffer.\n");
-                               return;
-                       }
+        if (pm4 == NULL)
+                return;
 
-                       for (i = 0; i < size / 4; ++i) {
-                               tmpPtr[i] = bswap_32(((uint32_t *)ptr)[i]);
-                       }
+       si_pm4_set_reg(pm4, R_028C38_PA_SC_AA_MASK_X0Y0_X1Y0, mask | (mask << 16));
+       si_pm4_set_reg(pm4, R_028C3C_PA_SC_AA_MASK_X0Y1_X1Y1, mask | (mask << 16));
 
-                       u_upload_data(rctx->uploader, 0, size, tmpPtr, &cb->buffer_offset, &cb->buffer);
-                       free(tmpPtr);
-               } else {
-                       u_upload_data(rctx->uploader, 0, input->buffer_size, ptr, &cb->buffer_offset, &cb->buffer);
-               }
-       } else {
-               /* Setup the hw buffer. */
-               cb->buffer_offset = input->buffer_offset;
-               pipe_resource_reference(&cb->buffer, input->buffer);
-       }
+       si_pm4_set_state(rctx, sample_mask, pm4);
+}
 
-       state->enabled_mask |= 1 << index;
-       state->dirty_mask |= 1 << index;
+static void si_delete_sampler_state(struct pipe_context *ctx, void *state)
+{
+       free(state);
 }
 
 /*
@@ -2578,33 +2925,8 @@ static void *si_create_vertex_elements(struct pipe_context *ctx,
 
                desc = util_format_description(elements[i].src_format);
                first_non_void = util_format_get_first_non_void_channel(elements[i].src_format);
-               data_format = si_translate_vertexformat(ctx->screen, elements[i].src_format,
-                                                       desc, first_non_void);
-
-               switch (desc->channel[first_non_void].type) {
-               case UTIL_FORMAT_TYPE_FIXED:
-                       num_format = V_008F0C_BUF_NUM_FORMAT_USCALED; /* XXX */
-                       break;
-               case UTIL_FORMAT_TYPE_SIGNED:
-                       if (desc->channel[first_non_void].normalized)
-                               num_format = V_008F0C_BUF_NUM_FORMAT_SNORM;
-                       else if (desc->channel[first_non_void].pure_integer)
-                               num_format = V_008F0C_BUF_NUM_FORMAT_SINT;
-                       else
-                               num_format = V_008F0C_BUF_NUM_FORMAT_SSCALED;
-                       break;
-               case UTIL_FORMAT_TYPE_UNSIGNED:
-                       if (desc->channel[first_non_void].normalized)
-                               num_format = V_008F0C_BUF_NUM_FORMAT_UNORM;
-                       else if (desc->channel[first_non_void].pure_integer)
-                               num_format = V_008F0C_BUF_NUM_FORMAT_UINT;
-                       else
-                               num_format = V_008F0C_BUF_NUM_FORMAT_USCALED;
-                       break;
-               case UTIL_FORMAT_TYPE_FLOAT:
-               default:
-                       num_format = V_008F14_IMG_NUM_FORMAT_FLOAT;
-               }
+               data_format = si_translate_buffer_dataformat(ctx->screen, desc, first_non_void);
+               num_format = si_translate_buffer_numformat(ctx->screen, desc, first_non_void);
 
                v->rsrc_word3[i] = S_008F0C_DST_SEL_X(si_map_swizzle(desc->swizzle[0])) |
                                   S_008F0C_DST_SEL_Y(si_map_swizzle(desc->swizzle[1])) |
@@ -2620,7 +2942,7 @@ static void *si_create_vertex_elements(struct pipe_context *ctx,
 
 static void si_bind_vertex_elements(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
        struct si_vertex_element *v = (struct si_vertex_element*)state;
 
        rctx->vertex_elements = v;
@@ -2628,7 +2950,7 @@ static void si_bind_vertex_elements(struct pipe_context *ctx, void *state)
 
 static void si_delete_vertex_element(struct pipe_context *ctx, void *state)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
 
        if (rctx->vertex_elements == state)
                rctx->vertex_elements = NULL;
@@ -2638,7 +2960,7 @@ static void si_delete_vertex_element(struct pipe_context *ctx, void *state)
 static void si_set_vertex_buffers(struct pipe_context *ctx, unsigned start_slot, unsigned count,
                                  const struct pipe_vertex_buffer *buffers)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
 
        util_set_vertex_buffers_count(rctx->vertex_buffer, &rctx->nr_vertex_buffers, buffers, start_slot, count);
 }
@@ -2646,7 +2968,7 @@ static void si_set_vertex_buffers(struct pipe_context *ctx, unsigned start_slot,
 static void si_set_index_buffer(struct pipe_context *ctx,
                                const struct pipe_index_buffer *ib)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
+       struct si_context *rctx = (struct si_context *)ctx;
 
        if (ib) {
                pipe_resource_reference(&rctx->index_buffer.buffer, ib->buffer);
@@ -2666,80 +2988,141 @@ static void si_set_polygon_stipple(struct pipe_context *ctx,
 
 static void si_texture_barrier(struct pipe_context *ctx)
 {
-       struct r600_context *rctx = (struct r600_context *)ctx;
-       struct si_pm4_state *pm4 = CALLOC_STRUCT(si_pm4_state);
+       struct si_context *rctx = (struct si_context *)ctx;
 
-       si_pm4_inval_texture_cache(pm4);
-       si_pm4_inval_fb_cache(pm4, rctx->framebuffer.nr_cbufs);
-       si_pm4_set_state(rctx, texture_barrier, pm4);
+       rctx->b.flags |= R600_CONTEXT_INV_TEX_CACHE |
+                        R600_CONTEXT_FLUSH_AND_INV_CB;
 }
 
-void si_init_state_functions(struct r600_context *rctx)
+static void *si_create_blend_custom(struct si_context *rctx, unsigned mode)
 {
-       rctx->context.create_blend_state = si_create_blend_state;
-       rctx->context.bind_blend_state = si_bind_blend_state;
-       rctx->context.delete_blend_state = si_delete_blend_state;
-       rctx->context.set_blend_color = si_set_blend_color;
+       struct pipe_blend_state blend;
 
-       rctx->context.create_rasterizer_state = si_create_rs_state;
-       rctx->context.bind_rasterizer_state = si_bind_rs_state;
-       rctx->context.delete_rasterizer_state = si_delete_rs_state;
+       memset(&blend, 0, sizeof(blend));
+       blend.independent_blend_enable = true;
+       blend.rt[0].colormask = 0xf;
+       return si_create_blend_state_mode(&rctx->b.b, &blend, mode);
+}
 
-       rctx->context.create_depth_stencil_alpha_state = si_create_dsa_state;
-       rctx->context.bind_depth_stencil_alpha_state = si_bind_dsa_state;
-       rctx->context.delete_depth_stencil_alpha_state = si_delete_dsa_state;
-       rctx->custom_dsa_flush_depth_stencil = si_create_db_flush_dsa(rctx, true, true);
-       rctx->custom_dsa_flush_depth = si_create_db_flush_dsa(rctx, true, false);
-       rctx->custom_dsa_flush_stencil = si_create_db_flush_dsa(rctx, false, true);
-       rctx->custom_dsa_flush_inplace = si_create_db_flush_dsa(rctx, false, false);
+static struct pipe_surface *r600_create_surface(struct pipe_context *pipe,
+                                               struct pipe_resource *texture,
+                                               const struct pipe_surface *surf_tmpl)
+{
+       struct r600_texture *rtex = (struct r600_texture*)texture;
+       struct si_surface *surface = CALLOC_STRUCT(si_surface);
+       unsigned level = surf_tmpl->u.tex.level;
 
-       rctx->context.set_clip_state = si_set_clip_state;
-       rctx->context.set_scissor_state = si_set_scissor_state;
-       rctx->context.set_viewport_state = si_set_viewport_state;
-       rctx->context.set_stencil_ref = si_set_pipe_stencil_ref;
+       if (surface == NULL)
+               return NULL;
 
-       rctx->context.set_framebuffer_state = si_set_framebuffer_state;
+       assert(surf_tmpl->u.tex.first_layer <= util_max_layer(texture, surf_tmpl->u.tex.level));
+       assert(surf_tmpl->u.tex.last_layer <= util_max_layer(texture, surf_tmpl->u.tex.level));
 
-       rctx->context.create_vs_state = si_create_vs_state;
-       rctx->context.create_fs_state = si_create_fs_state;
-       rctx->context.bind_vs_state = si_bind_vs_shader;
-       rctx->context.bind_fs_state = si_bind_ps_shader;
-       rctx->context.delete_vs_state = si_delete_vs_shader;
-       rctx->context.delete_fs_state = si_delete_ps_shader;
+       pipe_reference_init(&surface->base.reference, 1);
+       pipe_resource_reference(&surface->base.texture, texture);
+       surface->base.context = pipe;
+       surface->base.format = surf_tmpl->format;
+       surface->base.width = rtex->surface.level[level].npix_x;
+       surface->base.height = rtex->surface.level[level].npix_y;
+       surface->base.texture = texture;
+       surface->base.u.tex.first_layer = surf_tmpl->u.tex.first_layer;
+       surface->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer;
+       surface->base.u.tex.level = level;
 
-       rctx->context.create_sampler_state = si_create_sampler_state;
-       rctx->context.bind_vertex_sampler_states = si_bind_vs_sampler;
-       rctx->context.bind_fragment_sampler_states = si_bind_ps_sampler;
-       rctx->context.delete_sampler_state = si_delete_sampler_state;
+       return &surface->base;
+}
 
-       rctx->context.create_sampler_view = si_create_sampler_view;
-       rctx->context.set_vertex_sampler_views = si_set_vs_sampler_view;
-       rctx->context.set_fragment_sampler_views = si_set_ps_sampler_view;
-       rctx->context.sampler_view_destroy = si_sampler_view_destroy;
+static void r600_surface_destroy(struct pipe_context *pipe,
+                                struct pipe_surface *surface)
+{
+       pipe_resource_reference(&surface->texture, NULL);
+       FREE(surface);
+}
 
-       rctx->context.set_sample_mask = si_set_sample_mask;
+static boolean si_dma_copy(struct pipe_context *ctx,
+                          struct pipe_resource *dst,
+                          unsigned dst_level,
+                          unsigned dst_x, unsigned dst_y, unsigned dst_z,
+                          struct pipe_resource *src,
+                          unsigned src_level,
+                          const struct pipe_box *src_box)
+{
+       /* XXX implement this or share evergreen_dma_blit with r600g */
+       return FALSE;
+}
 
-       rctx->context.set_constant_buffer = si_set_constant_buffer;
+void si_init_state_functions(struct si_context *rctx)
+{
+       int i;
 
-       rctx->context.create_vertex_elements_state = si_create_vertex_elements;
-       rctx->context.bind_vertex_elements_state = si_bind_vertex_elements;
-       rctx->context.delete_vertex_elements_state = si_delete_vertex_element;
-       rctx->context.set_vertex_buffers = si_set_vertex_buffers;
-       rctx->context.set_index_buffer = si_set_index_buffer;
+       rctx->b.b.create_blend_state = si_create_blend_state;
+       rctx->b.b.bind_blend_state = si_bind_blend_state;
+       rctx->b.b.delete_blend_state = si_delete_blend_state;
+       rctx->b.b.set_blend_color = si_set_blend_color;
 
-       rctx->context.create_stream_output_target = si_create_so_target;
-       rctx->context.stream_output_target_destroy = si_so_target_destroy;
-       rctx->context.set_stream_output_targets = si_set_so_targets;
+       rctx->b.b.create_rasterizer_state = si_create_rs_state;
+       rctx->b.b.bind_rasterizer_state = si_bind_rs_state;
+       rctx->b.b.delete_rasterizer_state = si_delete_rs_state;
 
-       rctx->context.texture_barrier = si_texture_barrier;
-       rctx->context.set_polygon_stipple = si_set_polygon_stipple;
+       rctx->b.b.create_depth_stencil_alpha_state = si_create_dsa_state;
+       rctx->b.b.bind_depth_stencil_alpha_state = si_bind_dsa_state;
+       rctx->b.b.delete_depth_stencil_alpha_state = si_delete_dsa_state;
 
-       rctx->context.draw_vbo = si_draw_vbo;
+       for (i = 0; i < 8; i++) {
+               rctx->custom_dsa_flush_depth_stencil[i] = si_create_db_flush_dsa(rctx, true, true, i);
+               rctx->custom_dsa_flush_depth[i] = si_create_db_flush_dsa(rctx, true, false, i);
+               rctx->custom_dsa_flush_stencil[i] = si_create_db_flush_dsa(rctx, false, true, i);
+       }
+       rctx->custom_dsa_flush_inplace = si_create_db_flush_dsa(rctx, false, false, 0);
+       rctx->custom_blend_resolve = si_create_blend_custom(rctx, V_028808_CB_RESOLVE);
+       rctx->custom_blend_decompress = si_create_blend_custom(rctx, V_028808_CB_FMASK_DECOMPRESS);
+
+       rctx->b.b.set_clip_state = si_set_clip_state;
+       rctx->b.b.set_scissor_states = si_set_scissor_states;
+       rctx->b.b.set_viewport_states = si_set_viewport_states;
+       rctx->b.b.set_stencil_ref = si_set_pipe_stencil_ref;
+
+       rctx->b.b.set_framebuffer_state = si_set_framebuffer_state;
+       rctx->b.b.get_sample_position = si_get_sample_position;
+
+       rctx->b.b.create_vs_state = si_create_vs_state;
+       rctx->b.b.create_fs_state = si_create_fs_state;
+       rctx->b.b.bind_vs_state = si_bind_vs_shader;
+       rctx->b.b.bind_fs_state = si_bind_ps_shader;
+       rctx->b.b.delete_vs_state = si_delete_vs_shader;
+       rctx->b.b.delete_fs_state = si_delete_ps_shader;
+
+       rctx->b.b.create_sampler_state = si_create_sampler_state;
+       rctx->b.b.bind_sampler_states = si_bind_sampler_states;
+       rctx->b.b.delete_sampler_state = si_delete_sampler_state;
+
+       rctx->b.b.create_sampler_view = si_create_sampler_view;
+       rctx->b.b.set_sampler_views = si_set_sampler_views;
+       rctx->b.b.sampler_view_destroy = si_sampler_view_destroy;
+
+       rctx->b.b.set_sample_mask = si_set_sample_mask;
+
+       rctx->b.b.create_vertex_elements_state = si_create_vertex_elements;
+       rctx->b.b.bind_vertex_elements_state = si_bind_vertex_elements;
+       rctx->b.b.delete_vertex_elements_state = si_delete_vertex_element;
+       rctx->b.b.set_vertex_buffers = si_set_vertex_buffers;
+       rctx->b.b.set_index_buffer = si_set_index_buffer;
+
+       rctx->b.b.texture_barrier = si_texture_barrier;
+       rctx->b.b.set_polygon_stipple = si_set_polygon_stipple;
+       rctx->b.b.create_surface = r600_create_surface;
+       rctx->b.b.surface_destroy = r600_surface_destroy;
+       rctx->b.dma_copy = si_dma_copy;
+
+       rctx->b.b.draw_vbo = si_draw_vbo;
 }
 
-void si_init_config(struct r600_context *rctx)
+void si_init_config(struct si_context *rctx)
 {
-       struct si_pm4_state *pm4 = CALLOC_STRUCT(si_pm4_state);
+       struct si_pm4_state *pm4 = si_pm4_alloc_state(rctx);
+
+       if (pm4 == NULL)
+               return;
 
        si_cmd_context_control(pm4);
 
@@ -2760,42 +3143,94 @@ void si_init_config(struct r600_context *rctx)
        si_pm4_set_reg(pm4, R_028A40_VGT_GS_MODE, 0x0);
        si_pm4_set_reg(pm4, R_028A84_VGT_PRIMITIVEID_EN, 0x0);
        si_pm4_set_reg(pm4, R_028A8C_VGT_PRIMITIVEID_RESET, 0x0);
+       si_pm4_set_reg(pm4, R_028B28_VGT_STRMOUT_DRAW_OPAQUE_OFFSET, 0);
        si_pm4_set_reg(pm4, R_028B94_VGT_STRMOUT_CONFIG, 0x0);
        si_pm4_set_reg(pm4, R_028B98_VGT_STRMOUT_BUFFER_CONFIG, 0x0);
-       si_pm4_set_reg(pm4, R_028AA8_IA_MULTI_VGT_PARAM,
-                      S_028AA8_SWITCH_ON_EOP(1) |
-                      S_028AA8_PARTIAL_VS_WAVE_ON(1) |
-                      S_028AA8_PRIMGROUP_SIZE(63));
+       if (rctx->b.chip_class == SI) {
+               si_pm4_set_reg(pm4, R_028AA8_IA_MULTI_VGT_PARAM,
+                              S_028AA8_SWITCH_ON_EOP(1) |
+                              S_028AA8_PARTIAL_VS_WAVE_ON(1) |
+                              S_028AA8_PRIMGROUP_SIZE(63));
+       }
        si_pm4_set_reg(pm4, R_028AB4_VGT_REUSE_OFF, 0x00000000);
        si_pm4_set_reg(pm4, R_028AB8_VGT_VTX_CNT_EN, 0x0);
-       si_pm4_set_reg(pm4, R_008A14_PA_CL_ENHANCE, S_008A14_NUM_CLIP_SEQ(3) |
-                      S_008A14_CLIP_VTX_REORDER_ENA(1));
+       if (rctx->b.chip_class < CIK)
+               si_pm4_set_reg(pm4, R_008A14_PA_CL_ENHANCE, S_008A14_NUM_CLIP_SEQ(3) |
+                              S_008A14_CLIP_VTX_REORDER_ENA(1));
 
        si_pm4_set_reg(pm4, R_028B54_VGT_SHADER_STAGES_EN, 0);
        si_pm4_set_reg(pm4, R_028BD4_PA_SC_CENTROID_PRIORITY_0, 0x76543210);
        si_pm4_set_reg(pm4, R_028BD8_PA_SC_CENTROID_PRIORITY_1, 0xfedcba98);
 
-       si_pm4_set_reg(pm4, R_028804_DB_EQAA, 0x110000);
-
        si_pm4_set_reg(pm4, R_02882C_PA_SU_PRIM_FILTER_CNTL, 0);
 
-       switch (rctx->screen->family) {
-       case CHIP_TAHITI:
-       case CHIP_PITCAIRN:
-               si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x2a00126a);
-               break;
-       case CHIP_VERDE:
-               si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x0000124a);
-               break;
-       case CHIP_OLAND:
-               si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x00000082);
-               break;
-       case CHIP_HAINAN:
-               si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x00000000);
-               break;
-       default:
-               si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x00000000);
-               break;
+       if (rctx->b.chip_class >= CIK) {
+               switch (rctx->screen->b.family) {
+               case CHIP_BONAIRE:
+                       si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x16000012);
+                       si_pm4_set_reg(pm4, R_028354_PA_SC_RASTER_CONFIG_1, 0x00000000);
+                       break;
+               case CHIP_HAWAII:
+                       si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x3a00161a);
+                       si_pm4_set_reg(pm4, R_028354_PA_SC_RASTER_CONFIG_1, 0x0000002e);
+                       break;
+               case CHIP_KAVERI:
+                       /* XXX todo */
+               case CHIP_KABINI:
+                       /* XXX todo */
+               default:
+                       si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x00000000);
+                       si_pm4_set_reg(pm4, R_028354_PA_SC_RASTER_CONFIG_1, 0x00000000);
+                       break;
+               }
+       } else {
+               switch (rctx->screen->b.family) {
+               case CHIP_TAHITI:
+               case CHIP_PITCAIRN:
+                       si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x2a00126a);
+                       break;
+               case CHIP_VERDE:
+                       si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x0000124a);
+                       break;
+               case CHIP_OLAND:
+                       si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x00000082);
+                       break;
+               case CHIP_HAINAN:
+                       si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x00000000);
+                       break;
+               default:
+                       si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, 0x00000000);
+                       break;
+               }
+       }
+
+       si_pm4_set_reg(pm4, R_028200_PA_SC_WINDOW_OFFSET, 0x00000000);
+       si_pm4_set_reg(pm4, R_028230_PA_SC_EDGERULE, 0xAAAAAAAA);
+       si_pm4_set_reg(pm4, R_0282D0_PA_SC_VPORT_ZMIN_0, 0x00000000);
+       si_pm4_set_reg(pm4, R_0282D4_PA_SC_VPORT_ZMAX_0, 0x3F800000);
+       si_pm4_set_reg(pm4, R_028818_PA_CL_VTE_CNTL, 0x0000043F);
+       si_pm4_set_reg(pm4, R_028820_PA_CL_NANINF_CNTL, 0x00000000);
+       si_pm4_set_reg(pm4, R_028BE8_PA_CL_GB_VERT_CLIP_ADJ, 0x3F800000);
+       si_pm4_set_reg(pm4, R_028BEC_PA_CL_GB_VERT_DISC_ADJ, 0x3F800000);
+       si_pm4_set_reg(pm4, R_028BF0_PA_CL_GB_HORZ_CLIP_ADJ, 0x3F800000);
+       si_pm4_set_reg(pm4, R_028BF4_PA_CL_GB_HORZ_DISC_ADJ, 0x3F800000);
+       si_pm4_set_reg(pm4, R_028020_DB_DEPTH_BOUNDS_MIN, 0x00000000);
+       si_pm4_set_reg(pm4, R_028024_DB_DEPTH_BOUNDS_MAX, 0x00000000);
+       si_pm4_set_reg(pm4, R_028028_DB_STENCIL_CLEAR, 0x00000000);
+       si_pm4_set_reg(pm4, R_02802C_DB_DEPTH_CLEAR, 0x3F800000);
+       si_pm4_set_reg(pm4, R_028AC0_DB_SRESULTS_COMPARE_STATE0, 0x0);
+       si_pm4_set_reg(pm4, R_028AC4_DB_SRESULTS_COMPARE_STATE1, 0x0);
+       si_pm4_set_reg(pm4, R_028AC8_DB_PRELOAD_CONTROL, 0x0);
+       si_pm4_set_reg(pm4, R_02800C_DB_RENDER_OVERRIDE,
+                      S_02800C_FORCE_HIS_ENABLE0(V_02800C_FORCE_DISABLE) |
+                      S_02800C_FORCE_HIS_ENABLE1(V_02800C_FORCE_DISABLE));
+       si_pm4_set_reg(pm4, R_028400_VGT_MAX_VTX_INDX, ~0);
+       si_pm4_set_reg(pm4, R_028404_VGT_MIN_VTX_INDX, 0);
+
+       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, S_00B11C_LIMIT(0));
+               si_pm4_set_reg(pm4, R_00B01C_SPI_SHADER_PGM_RSRC3_PS, S_00B01C_CU_EN(0xffff));
        }
 
        si_pm4_set_state(rctx, init, pm4);