radeonsi: optimize rendering to linear color buffers
[mesa.git] / src / gallium / drivers / radeonsi / si_state.c
index ab321ef0b8fe869bff1c9d76432aa9fe0a04be9f..d12c89b9401c185e770257e9418f4542d96bb268 100644 (file)
@@ -620,8 +620,7 @@ 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;
-       si_set_constant_buffer(sctx, &sctx->rw_buffers,
-                              SI_VS_CONST_CLIP_PLANES, &cb);
+       si_set_rw_buffer(sctx, SI_VS_CONST_CLIP_PLANES, &cb);
        pipe_resource_reference(&cb.buffer, NULL);
 }
 
@@ -743,7 +742,6 @@ static void *si_create_rs_state(struct pipe_context *ctx,
                                S_028A0C_LINE_PATTERN(state->line_stipple_pattern) |
                                S_028A0C_REPEAT_COUNT(state->line_stipple_factor) : 0;
        rs->pa_cl_clip_cntl =
-               S_028810_PS_UCP_MODE(3) |
                S_028810_DX_CLIP_SPACE_DEF(state->clip_halfz) |
                S_028810_ZCLIP_NEAR_DISABLE(!state->depth_clip) |
                S_028810_ZCLIP_FAR_DISABLE(!state->depth_clip) |
@@ -1785,13 +1783,16 @@ boolean si_is_format_supported(struct pipe_screen *screen,
                }
        }
 
-       if (usage & PIPE_BIND_SAMPLER_VIEW) {
+       if (usage & (PIPE_BIND_SAMPLER_VIEW |
+                    PIPE_BIND_SHADER_IMAGE)) {
                if (target == PIPE_BUFFER) {
                        if (si_is_vertex_format_supported(screen, format))
-                               retval |= PIPE_BIND_SAMPLER_VIEW;
+                               retval |= usage & (PIPE_BIND_SAMPLER_VIEW |
+                                                  PIPE_BIND_SHADER_IMAGE);
                } else {
                        if (si_is_sampler_format_supported(screen, format))
-                               retval |= PIPE_BIND_SAMPLER_VIEW;
+                               retval |= usage & (PIPE_BIND_SAMPLER_VIEW |
+                                                  PIPE_BIND_SHADER_IMAGE);
                }
        }
 
@@ -1834,19 +1835,6 @@ boolean si_is_format_supported(struct pipe_screen *screen,
        return retval == usage;
 }
 
-static unsigned si_tile_mode_index(struct r600_texture *rtex, unsigned level,
-                                  bool stencil)
-{
-       unsigned tile_mode_index = 0;
-
-       if (stencil) {
-               tile_mode_index = rtex->surface.stencil_tiling_index[level];
-       } else {
-               tile_mode_index = rtex->surface.tiling_index[level];
-       }
-       return tile_mode_index;
-}
-
 /*
  * framebuffer handling
  */
@@ -1972,11 +1960,7 @@ static void si_initialize_color_surface(struct si_context *sctx,
                                        struct r600_surface *surf)
 {
        struct r600_texture *rtex = (struct r600_texture*)surf->base.texture;
-       unsigned level = surf->base.u.tex.level;
-       uint64_t offset = rtex->surface.level[level].offset;
-       unsigned pitch, slice;
-       unsigned color_info, color_attrib, color_pitch, color_view;
-       unsigned tile_mode_index;
+       unsigned color_info, color_attrib, color_view;
        unsigned format, swap, ntype, endian;
        const struct util_format_description *desc;
        int i;
@@ -1985,14 +1969,6 @@ static void si_initialize_color_surface(struct si_context *sctx,
        color_view = S_028C6C_SLICE_START(surf->base.u.tex.first_layer) |
                     S_028C6C_SLICE_MAX(surf->base.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) {
-               slice = slice - 1;
-       }
-
-       tile_mode_index = si_tile_mode_index(rtex, level, false);
-
        desc = util_format_description(surf->base.format);
        for (i = 0; i < 4; i++) {
                if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) {
@@ -2058,12 +2034,9 @@ static void si_initialize_color_surface(struct si_context *sctx,
                S_028C70_NUMBER_TYPE(ntype) |
                S_028C70_ENDIAN(endian);
 
-       color_pitch = S_028C64_TILE_MAX(pitch);
-
        /* Intensity is implemented as Red, so treat it that way. */
-       color_attrib = S_028C74_TILE_MODE_INDEX(tile_mode_index) |
-               S_028C74_FORCE_DST_ALPHA_1(desc->swizzle[3] == PIPE_SWIZZLE_1 ||
-                                          util_format_is_intensity(surf->base.format));
+       color_attrib = S_028C74_FORCE_DST_ALPHA_1(desc->swizzle[3] == PIPE_SWIZZLE_1 ||
+                                                 util_format_is_intensity(surf->base.format));
 
        if (rtex->resource.b.b.nr_samples > 1) {
                unsigned log_samples = util_logbase2(rtex->resource.b.b.nr_samples);
@@ -2075,28 +2048,18 @@ static void si_initialize_color_surface(struct si_context *sctx,
                        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 (sctx->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 (sctx->b.chip_class >= CIK) {
-                               color_pitch |= S_028C64_FMASK_TILE_MAX(rtex->fmask.pitch_in_pixels / 8 - 1);
-                       }
                }
        }
 
-       offset += rtex->resource.gpu_address;
-
-       surf->cb_color_base = offset >> 8;
-       surf->cb_color_pitch = color_pitch;
-       surf->cb_color_slice = S_028C68_TILE_MAX(slice);
        surf->cb_color_view = color_view;
        surf->cb_color_info = color_info;
        surf->cb_color_attrib = color_attrib;
 
-       if (sctx->b.chip_class >= VI && rtex->dcc_offset) {
+       if (sctx->b.chip_class >= VI) {
                unsigned max_uncompressed_block_size = 2;
 
                if (rtex->surface.nsamples > 1) {
@@ -2108,28 +2071,12 @@ static void si_initialize_color_surface(struct si_context *sctx,
 
                surf->cb_dcc_control = S_028C78_MAX_UNCOMPRESSED_BLOCK_SIZE(max_uncompressed_block_size) |
                                       S_028C78_INDEPENDENT_64B_BLOCKS(1);
-               surf->cb_dcc_base = (rtex->resource.gpu_address +
-                                    rtex->dcc_offset +
-                                    rtex->surface.level[level].dcc_offset) >> 8;
        }
 
-       if (rtex->fmask.size) {
-               surf->cb_color_fmask = (offset + rtex->fmask.offset) >> 8;
-               surf->cb_color_fmask_slice = S_028C88_TILE_MAX(rtex->fmask.slice_tile_max);
-       } else {
-               /* This must be set for fast clear to work without FMASK. */
-               surf->cb_color_fmask = surf->cb_color_base;
-               surf->cb_color_fmask_slice = surf->cb_color_slice;
-               surf->cb_color_attrib |= S_028C74_FMASK_TILE_MODE_INDEX(tile_mode_index);
-
-               if (sctx->b.chip_class == SI) {
-                       unsigned bankh = util_logbase2(rtex->surface.bankh);
-                       surf->cb_color_attrib |= S_028C74_FMASK_BANK_HEIGHT(bankh);
-               }
-
-               if (sctx->b.chip_class >= CIK) {
-                       surf->cb_color_pitch |= S_028C64_FMASK_TILE_MAX(pitch);
-               }
+       /* This must be set for fast clear to work without FMASK. */
+       if (!rtex->fmask.size && sctx->b.chip_class == SI) {
+               unsigned bankh = util_logbase2(rtex->surface.bankh);
+               surf->cb_color_attrib |= S_028C74_FMASK_BANK_HEIGHT(bankh);
        }
 
        /* Determine pixel shader export format */
@@ -2268,6 +2215,21 @@ static void si_init_depth_surface(struct si_context *sctx,
        surf->depth_initialized = true;
 }
 
+void si_dec_framebuffer_counters(const struct pipe_framebuffer_state *state)
+{
+       for (int i = 0; i < state->nr_cbufs; ++i) {
+               struct r600_surface *surf = NULL;
+               struct r600_texture *rtex;
+
+               if (!state->cbufs[i])
+                       continue;
+               surf = (struct r600_surface*)state->cbufs[i];
+               rtex = (struct r600_texture*)surf->base.texture;
+
+               p_atomic_dec(&rtex->framebuffers_bound);
+       }
+}
+
 static void si_set_framebuffer_state(struct pipe_context *ctx,
                                     const struct pipe_framebuffer_state *state)
 {
@@ -2276,6 +2238,7 @@ static void si_set_framebuffer_state(struct pipe_context *ctx,
        struct r600_surface *surf = NULL;
        struct r600_texture *rtex;
        bool old_cb0_is_integer = sctx->framebuffer.cb0_is_integer;
+       bool old_any_dst_linear = sctx->framebuffer.any_dst_linear;
        unsigned old_nr_samples = sctx->framebuffer.nr_samples;
        int i;
 
@@ -2298,6 +2261,7 @@ static void si_set_framebuffer_state(struct pipe_context *ctx,
                (1 << MAX2(sctx->framebuffer.state.nr_cbufs, state->nr_cbufs)) - 1;
        sctx->framebuffer.dirty_zsbuf |= sctx->framebuffer.state.zsbuf != state->zsbuf;
 
+       si_dec_framebuffer_counters(&sctx->framebuffer.state);
        util_copy_framebuffer_state(&sctx->framebuffer.state, state);
 
        sctx->framebuffer.spi_shader_col_format = 0;
@@ -2311,6 +2275,7 @@ static void si_set_framebuffer_state(struct pipe_context *ctx,
        sctx->framebuffer.log_samples = util_logbase2(sctx->framebuffer.nr_samples);
        sctx->framebuffer.cb0_is_integer = state->nr_cbufs && state->cbufs[0] &&
                                  util_format_is_pure_integer(state->cbufs[0]->format);
+       sctx->framebuffer.any_dst_linear = false;
 
        if (sctx->framebuffer.cb0_is_integer != old_cb0_is_integer)
                si_mark_atom_dirty(sctx, &sctx->db_render_state);
@@ -2341,7 +2306,13 @@ static void si_set_framebuffer_state(struct pipe_context *ctx,
                if (rtex->fmask.size && rtex->cmask.size) {
                        sctx->framebuffer.compressed_cb_mask |= 1 << i;
                }
+
+               if (surf->level_info->mode == RADEON_SURF_MODE_LINEAR_ALIGNED)
+                       sctx->framebuffer.any_dst_linear = true;
+
                r600_context_add_resource_size(ctx, surf->base.texture);
+
+               p_atomic_inc(&rtex->framebuffers_bound);
        }
        /* Set the second SPI format for possible dual-src blending. */
        if (i == 1 && surf) {
@@ -2368,6 +2339,9 @@ static void si_set_framebuffer_state(struct pipe_context *ctx,
        si_mark_atom_dirty(sctx, &sctx->cb_render_state);
        si_mark_atom_dirty(sctx, &sctx->framebuffer.atom);
 
+       if (sctx->framebuffer.any_dst_linear != old_any_dst_linear)
+               si_mark_atom_dirty(sctx, &sctx->msaa_config);
+
        if (sctx->framebuffer.nr_samples != old_nr_samples) {
                si_mark_atom_dirty(sctx, &sctx->msaa_config);
                si_mark_atom_dirty(sctx, &sctx->db_render_state);
@@ -2395,8 +2369,7 @@ static void si_set_framebuffer_state(struct pipe_context *ctx,
                        assert(0);
                }
                constbuf.buffer_size = sctx->framebuffer.nr_samples * 2 * 4;
-               si_set_constant_buffer(sctx, &sctx->rw_buffers,
-                                      SI_PS_CONST_SAMPLE_POSITIONS, &constbuf);
+               si_set_rw_buffer(sctx, SI_PS_CONST_SAMPLE_POSITIONS, &constbuf);
 
                /* Smoothing (only possible with nr_samples == 1) uses the same
                 * sample locations as the MSAA it simulates.
@@ -2411,6 +2384,8 @@ static void si_set_framebuffer_state(struct pipe_context *ctx,
                     old_nr_samples != 1))
                        si_mark_atom_dirty(sctx, &sctx->msaa_sample_locs);
        }
+
+       sctx->need_check_render_feedback = true;
 }
 
 static void si_emit_framebuffer_state(struct si_context *sctx, struct r600_atom *atom)
@@ -2420,9 +2395,14 @@ static void si_emit_framebuffer_state(struct si_context *sctx, struct r600_atom
        unsigned i, nr_cbufs = state->nr_cbufs;
        struct r600_texture *tex = NULL;
        struct r600_surface *cb = NULL;
+       unsigned cb_color_info = 0;
 
        /* Colorbuffers. */
        for (i = 0; i < nr_cbufs; i++) {
+               unsigned pitch_tile_max, slice_tile_max, tile_mode_index;
+               unsigned cb_color_base, cb_color_fmask, cb_color_attrib;
+               unsigned cb_color_pitch, cb_color_slice, cb_color_fmask_slice;
+
                if (!(sctx->framebuffer.dirty_cbufs & (1 << i)))
                        continue;
 
@@ -2446,30 +2426,71 @@ static void si_emit_framebuffer_state(struct si_context *sctx, struct r600_atom
                                RADEON_PRIO_CMASK);
                }
 
+               /* Compute mutable surface parameters. */
+               pitch_tile_max = cb->level_info->nblk_x / 8 - 1;
+               slice_tile_max = cb->level_info->nblk_x *
+                                cb->level_info->nblk_y / 64 - 1;
+               tile_mode_index = si_tile_mode_index(tex, cb->base.u.tex.level, false);
+
+               cb_color_base = (tex->resource.gpu_address + cb->level_info->offset) >> 8;
+               cb_color_pitch = S_028C64_TILE_MAX(pitch_tile_max);
+               cb_color_slice = S_028C68_TILE_MAX(slice_tile_max);
+               cb_color_attrib = cb->cb_color_attrib |
+                                 S_028C74_TILE_MODE_INDEX(tile_mode_index);
+
+               if (tex->fmask.size) {
+                       if (sctx->b.chip_class >= CIK)
+                               cb_color_pitch |= S_028C64_FMASK_TILE_MAX(tex->fmask.pitch_in_pixels / 8 - 1);
+                       cb_color_attrib |= S_028C74_FMASK_TILE_MODE_INDEX(tex->fmask.tile_mode_index);
+                       cb_color_fmask = (tex->resource.gpu_address + tex->fmask.offset) >> 8;
+                       cb_color_fmask_slice = S_028C88_TILE_MAX(tex->fmask.slice_tile_max);
+               } else {
+                       /* This must be set for fast clear to work without FMASK. */
+                       if (sctx->b.chip_class >= CIK)
+                               cb_color_pitch |= S_028C64_FMASK_TILE_MAX(pitch_tile_max);
+                       cb_color_attrib |= S_028C74_FMASK_TILE_MODE_INDEX(tile_mode_index);
+                       cb_color_fmask = cb_color_base;
+                       cb_color_fmask_slice = S_028C88_TILE_MAX(slice_tile_max);
+               }
+
+               cb_color_info = cb->cb_color_info | tex->cb_color_info;
+
+               if (tex->dcc_offset && cb->level_info->dcc_enabled) {
+                       bool is_msaa_resolve_dst = state->cbufs[0] &&
+                                                  state->cbufs[0]->texture->nr_samples > 1 &&
+                                                  state->cbufs[1] == &cb->base &&
+                                                  state->cbufs[1]->texture->nr_samples <= 1;
+
+                       if (!is_msaa_resolve_dst)
+                               cb_color_info |= S_028C70_DCC_ENABLE(1);
+               }
+
                radeon_set_context_reg_seq(cs, R_028C60_CB_COLOR0_BASE + i * 0x3C,
                                           sctx->b.chip_class >= VI ? 14 : 13);
-               radeon_emit(cs, cb->cb_color_base);     /* R_028C60_CB_COLOR0_BASE */
-               radeon_emit(cs, cb->cb_color_pitch);    /* R_028C64_CB_COLOR0_PITCH */
-               radeon_emit(cs, cb->cb_color_slice);    /* R_028C68_CB_COLOR0_SLICE */
+               radeon_emit(cs, cb_color_base);         /* R_028C60_CB_COLOR0_BASE */
+               radeon_emit(cs, cb_color_pitch);        /* R_028C64_CB_COLOR0_PITCH */
+               radeon_emit(cs, cb_color_slice);        /* R_028C68_CB_COLOR0_SLICE */
                radeon_emit(cs, cb->cb_color_view);     /* R_028C6C_CB_COLOR0_VIEW */
-               radeon_emit(cs, cb->cb_color_info | tex->cb_color_info); /* R_028C70_CB_COLOR0_INFO */
-               radeon_emit(cs, cb->cb_color_attrib);   /* R_028C74_CB_COLOR0_ATTRIB */
+               radeon_emit(cs, cb_color_info);         /* R_028C70_CB_COLOR0_INFO */
+               radeon_emit(cs, cb_color_attrib);       /* R_028C74_CB_COLOR0_ATTRIB */
                radeon_emit(cs, cb->cb_dcc_control);    /* R_028C78_CB_COLOR0_DCC_CONTROL */
                radeon_emit(cs, tex->cmask.base_address_reg);   /* R_028C7C_CB_COLOR0_CMASK */
                radeon_emit(cs, tex->cmask.slice_tile_max);     /* R_028C80_CB_COLOR0_CMASK_SLICE */
-               radeon_emit(cs, cb->cb_color_fmask);            /* R_028C84_CB_COLOR0_FMASK */
-               radeon_emit(cs, cb->cb_color_fmask_slice);      /* R_028C88_CB_COLOR0_FMASK_SLICE */
+               radeon_emit(cs, cb_color_fmask);                /* R_028C84_CB_COLOR0_FMASK */
+               radeon_emit(cs, cb_color_fmask_slice);          /* R_028C88_CB_COLOR0_FMASK_SLICE */
                radeon_emit(cs, tex->color_clear_value[0]);     /* R_028C8C_CB_COLOR0_CLEAR_WORD0 */
                radeon_emit(cs, tex->color_clear_value[1]);     /* R_028C90_CB_COLOR0_CLEAR_WORD1 */
 
-               if (sctx->b.chip_class >= VI)
-                       radeon_emit(cs, cb->cb_dcc_base);       /* R_028C94_CB_COLOR0_DCC_BASE */
+               if (sctx->b.chip_class >= VI) /* R_028C94_CB_COLOR0_DCC_BASE */
+                       radeon_emit(cs, (tex->resource.gpu_address +
+                                        tex->dcc_offset +
+                                        tex->surface.level[cb->base.u.tex.level].dcc_offset) >> 8);
        }
        /* set CB_COLOR1_INFO for possible dual-src blending */
        if (i == 1 && state->cbufs[0] &&
            sctx->framebuffer.dirty_cbufs & (1 << 0)) {
                radeon_set_context_reg(cs, R_028C70_CB_COLOR0_INFO + 1 * 0x3C,
-                                      cb->cb_color_info | tex->cb_color_info);
+                                      cb_color_info);
                i++;
        }
        for (; i < 8 ; i++)
@@ -2543,13 +2564,27 @@ static void si_emit_msaa_sample_locs(struct si_context *sctx,
 static void si_emit_msaa_config(struct si_context *sctx, struct r600_atom *atom)
 {
        struct radeon_winsys_cs *cs = sctx->b.gfx.cs;
+       unsigned num_tile_pipes = sctx->screen->b.info.num_tile_pipes;
+       /* 33% faster rendering to linear color buffers */
+       bool dst_is_linear = sctx->framebuffer.any_dst_linear;
+       unsigned sc_mode_cntl_1 =
+               S_028A4C_WALK_SIZE(dst_is_linear) |
+               S_028A4C_WALK_FENCE_ENABLE(!dst_is_linear) |
+               S_028A4C_WALK_FENCE_SIZE(num_tile_pipes == 2 ? 2 : 3) |
+               /* always 1: */
+               S_028A4C_WALK_ALIGN8_PRIM_FITS_ST(1) |
+               S_028A4C_SUPERTILE_WALK_ORDER_ENABLE(1) |
+               S_028A4C_TILE_WALK_ORDER_ENABLE(1) |
+               S_028A4C_MULTI_SHADER_ENGINE_PRIM_DISCARD_ENABLE(1) |
+               S_028A4C_FORCE_EOV_CNTDWN_ENABLE(1) |
+               S_028A4C_FORCE_EOV_REZ_ENABLE(1);
 
        cayman_emit_msaa_config(cs, sctx->framebuffer.nr_samples,
                                sctx->ps_iter_samples,
-                               sctx->smoothing_enabled ? SI_NUM_SMOOTH_AA_SAMPLES : 0);
+                               sctx->smoothing_enabled ? SI_NUM_SMOOTH_AA_SAMPLES : 0,
+                               sc_mode_cntl_1);
 }
 
-
 static void si_set_min_samples(struct pipe_context *ctx, unsigned min_samples)
 {
        struct si_context *sctx = (struct si_context *)ctx;
@@ -2619,42 +2654,19 @@ si_make_texture_descriptor(struct si_screen *screen,
                           enum pipe_texture_target target,
                           enum pipe_format pipe_format,
                           const unsigned char state_swizzle[4],
-                          unsigned base_level, unsigned first_level, unsigned last_level,
+                          unsigned first_level, unsigned last_level,
                           unsigned first_layer, unsigned last_layer,
                           unsigned width, unsigned height, unsigned depth,
                           uint32_t *state,
                           uint32_t *fmask_state)
 {
        struct pipe_resource *res = &tex->resource.b.b;
-       const struct radeon_surf_level *surflevel = tex->surface.level;
        const struct util_format_description *desc;
        unsigned char swizzle[4];
        int first_non_void;
        unsigned num_format, data_format, type;
-       uint32_t pitch;
        uint64_t va;
 
-       /* Texturing with separate depth and stencil. */
-       if (tex->is_depth && !tex->is_flushing_texture) {
-               switch (pipe_format) {
-               case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
-                       pipe_format = PIPE_FORMAT_Z32_FLOAT;
-                       break;
-               case PIPE_FORMAT_X8Z24_UNORM:
-               case PIPE_FORMAT_S8_UINT_Z24_UNORM:
-                       /* Z24 is always stored like this. */
-                       pipe_format = PIPE_FORMAT_Z24X8_UNORM;
-                       break;
-               case PIPE_FORMAT_X24S8_UINT:
-               case PIPE_FORMAT_S8X24_UINT:
-               case PIPE_FORMAT_X32_S8X24_UINT:
-                       pipe_format = PIPE_FORMAT_S8_UINT;
-                       surflevel = tex->surface.stencil_level;
-                       break;
-               default:;
-               }
-       }
-
        desc = util_format_description(pipe_format);
 
        if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
@@ -2774,12 +2786,8 @@ si_make_texture_descriptor(struct si_screen *screen,
        } else if (type == V_008F1C_SQ_RSRC_IMG_CUBE)
                depth = res->array_size / 6;
 
-       pitch = surflevel[base_level].nblk_x * util_format_get_blockwidth(pipe_format);
-       va = tex->resource.gpu_address + surflevel[base_level].offset;
-
-       state[0] = va >> 8;
-       state[1] = (S_008F14_BASE_ADDRESS_HI(va >> 40) |
-                   S_008F14_DATA_FORMAT(data_format) |
+       state[0] = 0;
+       state[1] = (S_008F14_DATA_FORMAT(data_format) |
                    S_008F14_NUM_FORMAT(num_format));
        state[2] = (S_008F18_WIDTH(width - 1) |
                    S_008F18_HEIGHT(height - 1));
@@ -2792,24 +2800,19 @@ si_make_texture_descriptor(struct si_screen *screen,
                    S_008F1C_LAST_LEVEL(res->nr_samples > 1 ?
                                        util_logbase2(res->nr_samples) :
                                        last_level) |
-                   S_008F1C_TILING_INDEX(si_tile_mode_index(tex, base_level, false)) |
                    S_008F1C_POW2_PAD(res->last_level > 0) |
                    S_008F1C_TYPE(type));
-       state[4] = (S_008F20_DEPTH(depth - 1) | S_008F20_PITCH(pitch - 1));
+       state[4] = S_008F20_DEPTH(depth - 1);
        state[5] = (S_008F24_BASE_ARRAY(first_layer) |
                    S_008F24_LAST_ARRAY(last_layer));
+       state[6] = 0;
+       state[7] = 0;
 
        if (tex->dcc_offset) {
                unsigned swap = r600_translate_colorswap(pipe_format, FALSE);
 
-               state[6] = S_008F28_COMPRESSION_EN(1) | S_008F28_ALPHA_IS_ON_MSB(swap <= 1);
-               state[7] = (tex->resource.gpu_address +
-                           tex->dcc_offset +
-                           surflevel[base_level].dcc_offset) >> 8;
+               state[6] = S_008F28_ALPHA_IS_ON_MSB(swap <= 1);
        } else {
-               state[6] = 0;
-               state[7] = 0;
-
                /* The last dword is unused by hw. The shader uses it to clear
                 * bits in the first dword of sampler state.
                 */
@@ -2887,6 +2890,8 @@ si_create_sampler_view_custom(struct pipe_context *ctx,
        unsigned char state_swizzle[4];
        unsigned height, depth, width;
        unsigned last_layer = state->u.tex.last_layer;
+       enum pipe_format pipe_format;
+       const struct radeon_surf_level *surflevel;
 
        if (!view)
                return NULL;
@@ -2958,13 +2963,40 @@ si_create_sampler_view_custom(struct pipe_context *ctx,
            state->target == PIPE_TEXTURE_CUBE)
                last_layer = state->u.tex.first_layer;
 
-       si_make_texture_descriptor(sctx->screen, tmp, true, state->target,
-                                  state->format, state_swizzle,
-                                  base_level, first_level, last_level,
+       /* Texturing with separate depth and stencil. */
+       pipe_format = state->format;
+       surflevel = tmp->surface.level;
+
+       if (tmp->is_depth && !tmp->is_flushing_texture) {
+               switch (pipe_format) {
+               case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
+                       pipe_format = PIPE_FORMAT_Z32_FLOAT;
+                       break;
+               case PIPE_FORMAT_X8Z24_UNORM:
+               case PIPE_FORMAT_S8_UINT_Z24_UNORM:
+                       /* Z24 is always stored like this. */
+                       pipe_format = PIPE_FORMAT_Z24X8_UNORM;
+                       break;
+               case PIPE_FORMAT_X24S8_UINT:
+               case PIPE_FORMAT_S8X24_UINT:
+               case PIPE_FORMAT_X32_S8X24_UINT:
+                       pipe_format = PIPE_FORMAT_S8_UINT;
+                       surflevel = tmp->surface.stencil_level;
+                       break;
+               default:;
+               }
+       }
+
+       si_make_texture_descriptor(sctx->screen, tmp, true,
+                                  state->target, pipe_format, state_swizzle,
+                                  first_level, last_level,
                                   state->u.tex.first_layer, last_layer,
                                   width, height, depth,
                                   view->state, view->fmask_state);
 
+       view->base_level_info = &surflevel[base_level];
+       view->base_level = base_level;
+       view->block_width = util_format_get_blockwidth(pipe_format);
        return &view->base;
 }
 
@@ -3246,8 +3278,7 @@ static void si_set_tess_state(struct pipe_context *ctx,
                               (void*)array, sizeof(array),
                               &cb.buffer_offset);
 
-       si_set_constant_buffer(sctx, &sctx->rw_buffers,
-                              SI_HS_CONST_DEFAULT_TESS_LEVELS, &cb);
+       si_set_rw_buffer(sctx, SI_HS_CONST_DEFAULT_TESS_LEVELS, &cb);
        pipe_resource_reference(&cb.buffer, NULL);
 }
 
@@ -3400,6 +3431,11 @@ void si_init_state_functions(struct si_context *sctx)
        si_init_config(sctx);
 }
 
+static uint32_t si_get_bo_metadata_word1(struct r600_common_screen *rscreen)
+{
+       return (ATI_VENDOR_ID << 16) | rscreen->info.pci_id;
+}
+
 static void si_query_opaque_metadata(struct r600_common_screen *rscreen,
                                     struct r600_texture *rtex,
                                     struct radeon_bo_metadata *md)
@@ -3434,15 +3470,18 @@ static void si_query_opaque_metadata(struct r600_common_screen *rscreen,
        md->metadata[0] = 1; /* metadata image format version 1 */
 
        /* TILE_MODE_INDEX is ambiguous without a PCI ID. */
-       md->metadata[1] = (ATI_VENDOR_ID << 16) | rscreen->info.pci_id;
+       md->metadata[1] = si_get_bo_metadata_word1(rscreen);
 
        si_make_texture_descriptor(sscreen, rtex, true,
                                   res->target, res->format,
-                                  swizzle, 0, 0, res->last_level, 0,
+                                  swizzle, 0, res->last_level, 0,
                                   is_array ? res->array_size - 1 : 0,
                                   res->width0, res->height0, res->depth0,
                                   desc, NULL);
 
+       si_set_mutable_tex_desc_fields(rtex, &rtex->surface.level[0], 0, 0,
+                                      rtex->surface.blk_w, false, desc);
+
        /* Clear the base address and set the relative DCC offset. */
        desc[0] = 0;
        desc[1] &= C_008F14_BASE_ADDRESS_HI;
@@ -3458,9 +3497,36 @@ static void si_query_opaque_metadata(struct r600_common_screen *rscreen,
        md->size_metadata = (11 + res->last_level) * 4;
 }
 
+static void si_apply_opaque_metadata(struct r600_common_screen *rscreen,
+                                    struct r600_texture *rtex,
+                                    struct radeon_bo_metadata *md)
+{
+       uint32_t *desc = &md->metadata[2];
+
+       if (rscreen->chip_class < VI)
+               return;
+
+       /* Return if DCC is enabled. The texture should be set up with it
+        * already.
+        */
+       if (md->size_metadata >= 11 * 4 &&
+           md->metadata[0] != 0 &&
+           md->metadata[1] == si_get_bo_metadata_word1(rscreen) &&
+           G_008F28_COMPRESSION_EN(desc[6])) {
+               assert(rtex->dcc_offset == ((uint64_t)desc[7] << 8));
+               return;
+       }
+
+       /* Disable DCC. These are always set by texture_from_handle and must
+        * be cleared here.
+        */
+       rtex->dcc_offset = 0;
+}
+
 void si_init_screen_state_functions(struct si_screen *sscreen)
 {
        sscreen->b.query_opaque_metadata = si_query_opaque_metadata;
+       sscreen->b.apply_opaque_metadata = si_apply_opaque_metadata;
 }
 
 static void
@@ -3478,10 +3544,15 @@ si_write_harvested_raster_configs(struct si_context *sctx,
        unsigned se_mask[4];
        unsigned se;
 
-       se_mask[0] = ((1 << rb_per_se) - 1) & rb_mask;
-       se_mask[1] = (se_mask[0] << rb_per_se) & rb_mask;
-       se_mask[2] = (se_mask[1] << rb_per_se) & rb_mask;
-       se_mask[3] = (se_mask[2] << rb_per_se) & rb_mask;
+       se_mask[0] = ((1 << rb_per_se) - 1);
+       se_mask[1] = (se_mask[0] << rb_per_se);
+       se_mask[2] = (se_mask[1] << rb_per_se);
+       se_mask[3] = (se_mask[2] << rb_per_se);
+
+       se_mask[0] &= rb_mask;
+       se_mask[1] &= rb_mask;
+       se_mask[2] &= rb_mask;
+       se_mask[3] &= rb_mask;
 
        assert(num_se == 1 || num_se == 2 || num_se == 4);
        assert(sh_per_se == 1 || sh_per_se == 2);
@@ -3491,19 +3562,6 @@ si_write_harvested_raster_configs(struct si_context *sctx,
         * fields are for, so I'm leaving them as their default
         * values. */
 
-       if ((num_se > 2) && ((!se_mask[0] && !se_mask[1]) ||
-                            (!se_mask[2] && !se_mask[3]))) {
-               raster_config_1 &= C_028354_SE_PAIR_MAP;
-
-               if (!se_mask[0] && !se_mask[1]) {
-                       raster_config_1 |=
-                               S_028354_SE_PAIR_MAP(V_028354_RASTER_CONFIG_SE_PAIR_MAP_3);
-               } else {
-                       raster_config_1 |=
-                               S_028354_SE_PAIR_MAP(V_028354_RASTER_CONFIG_SE_PAIR_MAP_0);
-               }
-       }
-
        for (se = 0; se < num_se; se++) {
                unsigned raster_config_se = raster_config;
                unsigned pkr0_mask = ((1 << rb_per_pkr) - 1) << (se * rb_per_se);
@@ -3583,8 +3641,6 @@ si_write_harvested_raster_configs(struct si_context *sctx,
                                       S_030800_SE_INDEX(se) | S_030800_SH_BROADCAST_WRITES(1) |
                                       S_030800_INSTANCE_BROADCAST_WRITES(1));
                si_pm4_set_reg(pm4, R_028350_PA_SC_RASTER_CONFIG, raster_config_se);
-               if (sctx->b.chip_class >= CIK)
-                       si_pm4_set_reg(pm4, R_028354_PA_SC_RASTER_CONFIG_1, raster_config_1);
        }
 
        /* GRBM_GFX_INDEX has a different offset on SI and CI+ */
@@ -3592,10 +3648,26 @@ si_write_harvested_raster_configs(struct si_context *sctx,
                si_pm4_set_reg(pm4, GRBM_GFX_INDEX,
                               SE_BROADCAST_WRITES | SH_BROADCAST_WRITES |
                               INSTANCE_BROADCAST_WRITES);
-       else
+       else {
                si_pm4_set_reg(pm4, R_030800_GRBM_GFX_INDEX,
                               S_030800_SE_BROADCAST_WRITES(1) | S_030800_SH_BROADCAST_WRITES(1) |
                               S_030800_INSTANCE_BROADCAST_WRITES(1));
+
+               if ((num_se > 2) && ((!se_mask[0] && !se_mask[1]) ||
+                                    (!se_mask[2] && !se_mask[3]))) {
+                       raster_config_1 &= C_028354_SE_PAIR_MAP;
+
+                       if (!se_mask[0] && !se_mask[1]) {
+                               raster_config_1 |=
+                                       S_028354_SE_PAIR_MAP(V_028354_RASTER_CONFIG_SE_PAIR_MAP_3);
+                       } else {
+                               raster_config_1 |=
+                                       S_028354_SE_PAIR_MAP(V_028354_RASTER_CONFIG_SE_PAIR_MAP_0);
+                       }
+               }
+
+               si_pm4_set_reg(pm4, R_028354_PA_SC_RASTER_CONFIG_1, raster_config_1);
+       }
 }
 
 static void si_init_config(struct si_context *sctx)
@@ -3692,7 +3764,10 @@ static void si_init_config(struct si_context *sctx)
                raster_config_1 = 0x0000002a;
                break;
        case CHIP_ICELAND:
-               raster_config = 0x00000002;
+               if (num_rb == 1)
+                       raster_config = 0x00000000;
+               else
+                       raster_config = 0x00000002;
                raster_config_1 = 0x00000000;
                break;
        case CHIP_CARRIZO:
@@ -3786,16 +3861,28 @@ static void si_init_config(struct si_context *sctx)
        }
 
        if (sctx->b.chip_class >= VI) {
+               unsigned vgt_tess_distribution;
+
                si_pm4_set_reg(pm4, R_028424_CB_DCC_CONTROL,
                               S_028424_OVERWRITE_COMBINER_MRT_SHARING_DISABLE(1) |
                               S_028424_OVERWRITE_COMBINER_WATERMARK(4));
                si_pm4_set_reg(pm4, R_028C58_VGT_VERTEX_REUSE_BLOCK_CNTL, 30);
                si_pm4_set_reg(pm4, R_028C5C_VGT_OUT_DEALLOC_CNTL, 32);
-               si_pm4_set_reg(pm4, R_028B50_VGT_TESS_DISTRIBUTION,
-                              S_028B50_ACCUM_ISOLINE(32) |
-                              S_028B50_ACCUM_TRI(11) |
-                              S_028B50_ACCUM_QUAD(11) |
-                              S_028B50_DONUT_SPLIT(16));
+
+               vgt_tess_distribution =
+                       S_028B50_ACCUM_ISOLINE(32) |
+                       S_028B50_ACCUM_TRI(11) |
+                       S_028B50_ACCUM_QUAD(11) |
+                       S_028B50_DONUT_SPLIT(16);
+
+               /* Testing with Unigine Heaven extreme tesselation yielded best results
+                * with TRAP_SPLIT = 3.
+                */
+               if (sctx->b.family == CHIP_FIJI ||
+                   sctx->b.family >= CHIP_POLARIS10)
+                       vgt_tess_distribution |= S_028B50_TRAP_SPLIT(3);
+
+               si_pm4_set_reg(pm4, R_028B50_VGT_TESS_DISTRIBUTION, vgt_tess_distribution);
        }
 
        if (sctx->b.family == CHIP_STONEY)