radeonsi: handle non-clearable DCC buffers as MSAA resolve dst
[mesa.git] / src / gallium / drivers / radeonsi / si_clear.c
index 8ecd47fea9bda511fdb0efb8ab618eb8855dbd4e..53c255c58086c615c07fcf0590e1eadfe11b33be 100644 (file)
@@ -35,37 +35,37 @@ enum {
 };
 
 static void si_alloc_separate_cmask(struct si_screen *sscreen,
-                                   struct r600_texture *rtex)
+                                   struct si_texture *tex)
 {
-       if (rtex->cmask_buffer)
+       if (tex->cmask_buffer)
                 return;
 
-       assert(rtex->cmask.size == 0);
+       assert(tex->cmask.size == 0);
 
-       si_texture_get_cmask_info(sscreen, rtex, &rtex->cmask);
-       if (!rtex->cmask.size)
+       si_texture_get_cmask_info(sscreen, tex, &tex->cmask);
+       if (!tex->cmask.size)
                return;
 
-       rtex->cmask_buffer =
+       tex->cmask_buffer =
                si_aligned_buffer_create(&sscreen->b,
                                         SI_RESOURCE_FLAG_UNMAPPABLE,
                                         PIPE_USAGE_DEFAULT,
-                                        rtex->cmask.size,
-                                        rtex->cmask.alignment);
-       if (rtex->cmask_buffer == NULL) {
-               rtex->cmask.size = 0;
+                                        tex->cmask.size,
+                                        tex->cmask.alignment);
+       if (tex->cmask_buffer == NULL) {
+               tex->cmask.size = 0;
                return;
        }
 
        /* update colorbuffer state bits */
-       rtex->cmask.base_address_reg = rtex->cmask_buffer->gpu_address >> 8;
+       tex->cmask.base_address_reg = tex->cmask_buffer->gpu_address >> 8;
 
-       rtex->cb_color_info |= S_028C70_FAST_CLEAR(1);
+       tex->cb_color_info |= S_028C70_FAST_CLEAR(1);
 
        p_atomic_inc(&sscreen->compressed_colortex_counter);
 }
 
-static void si_set_clear_color(struct r600_texture *rtex,
+static bool si_set_clear_color(struct si_texture *tex,
                               enum pipe_format surface_format,
                               const union pipe_color_union *color)
 {
@@ -73,7 +73,7 @@ static void si_set_clear_color(struct r600_texture *rtex,
 
        memset(&uc, 0, sizeof(uc));
 
-       if (rtex->surface.bpe == 16) {
+       if (tex->surface.bpe == 16) {
                /* DCC fast clear only:
                 *   CLEAR_WORD0 = R = G = B
                 *   CLEAR_WORD1 = A
@@ -90,7 +90,11 @@ static void si_set_clear_color(struct r600_texture *rtex,
                util_pack_color(color->f, surface_format, &uc);
        }
 
-       memcpy(rtex->color_clear_value, &uc, 2 * sizeof(uint32_t));
+       if (memcmp(tex->color_clear_value, &uc, 2 * sizeof(uint32_t)) == 0)
+               return false;
+
+       memcpy(tex->color_clear_value, &uc, 2 * sizeof(uint32_t));
+       return true;
 }
 
 /** Linearize and convert luminace/intensity to red. */
@@ -222,42 +226,42 @@ static bool vi_get_fast_clear_parameters(enum pipe_format base_format,
 }
 
 void vi_dcc_clear_level(struct si_context *sctx,
-                       struct r600_texture *rtex,
+                       struct si_texture *tex,
                        unsigned level, unsigned clear_value)
 {
        struct pipe_resource *dcc_buffer;
        uint64_t dcc_offset, clear_size;
 
-       assert(vi_dcc_enabled(rtex, level));
+       assert(vi_dcc_enabled(tex, level));
 
-       if (rtex->dcc_separate_buffer) {
-               dcc_buffer = &rtex->dcc_separate_buffer->b.b;
+       if (tex->dcc_separate_buffer) {
+               dcc_buffer = &tex->dcc_separate_buffer->b.b;
                dcc_offset = 0;
        } else {
-               dcc_buffer = &rtex->buffer.b.b;
-               dcc_offset = rtex->dcc_offset;
+               dcc_buffer = &tex->buffer.b.b;
+               dcc_offset = tex->dcc_offset;
        }
 
        if (sctx->chip_class >= GFX9) {
                /* Mipmap level clears aren't implemented. */
-               assert(rtex->buffer.b.b.last_level == 0);
+               assert(tex->buffer.b.b.last_level == 0);
                /* 4x and 8x MSAA needs a sophisticated compute shader for
                 * the clear. See AMDVLK. */
-               assert(rtex->buffer.b.b.nr_samples <= 2);
-               clear_size = rtex->surface.dcc_size;
+               assert(tex->num_color_samples <= 2);
+               clear_size = tex->surface.dcc_size;
        } else {
-               unsigned num_layers = util_num_layers(&rtex->buffer.b.b, level);
+               unsigned num_layers = util_num_layers(&tex->buffer.b.b, level);
 
                /* If this is 0, fast clear isn't possible. (can occur with MSAA) */
-               assert(rtex->surface.u.legacy.level[level].dcc_fast_clear_size);
+               assert(tex->surface.u.legacy.level[level].dcc_fast_clear_size);
                /* Layered 4x and 8x MSAA DCC fast clears need to clear
                 * dcc_fast_clear_size bytes for each layer. A compute shader
                 * would be more efficient than separate per-layer clear operations.
                 */
-               assert(rtex->buffer.b.b.nr_samples <= 2 || num_layers == 1);
+               assert(tex->num_color_samples <= 2 || num_layers == 1);
 
-               dcc_offset += rtex->surface.u.legacy.level[level].dcc_offset;
-               clear_size = rtex->surface.u.legacy.level[level].dcc_fast_clear_size *
+               dcc_offset += tex->surface.u.legacy.level[level].dcc_offset;
+               clear_size = tex->surface.u.legacy.level[level].dcc_fast_clear_size *
                             num_layers;
        }
 
@@ -270,20 +274,20 @@ void vi_dcc_clear_level(struct si_context *sctx,
  * src and dst micro tile modes match.
  */
 static void si_set_optimal_micro_tile_mode(struct si_screen *sscreen,
-                                          struct r600_texture *rtex)
+                                          struct si_texture *tex)
 {
-       if (rtex->buffer.b.is_shared ||
-           rtex->buffer.b.b.nr_samples <= 1 ||
-           rtex->surface.micro_tile_mode == rtex->last_msaa_resolve_target_micro_mode)
+       if (tex->buffer.b.is_shared ||
+           tex->buffer.b.b.nr_samples <= 1 ||
+           tex->surface.micro_tile_mode == tex->last_msaa_resolve_target_micro_mode)
                return;
 
        assert(sscreen->info.chip_class >= GFX9 ||
-              rtex->surface.u.legacy.level[0].mode == RADEON_SURF_MODE_2D);
-       assert(rtex->buffer.b.b.last_level == 0);
+              tex->surface.u.legacy.level[0].mode == RADEON_SURF_MODE_2D);
+       assert(tex->buffer.b.b.last_level == 0);
 
        if (sscreen->info.chip_class >= GFX9) {
                /* 4K or larger tiles only. 0 is linear. 1-3 are 256B tiles. */
-               assert(rtex->surface.u.gfx9.surf.swizzle_mode >= 4);
+               assert(tex->surface.u.gfx9.surf.swizzle_mode >= 4);
 
                /* If you do swizzle_mode % 4, you'll get:
                 *   0 = Depth
@@ -293,20 +297,20 @@ static void si_set_optimal_micro_tile_mode(struct si_screen *sscreen,
                 *
                 * Depth-sample order isn't allowed:
                 */
-               assert(rtex->surface.u.gfx9.surf.swizzle_mode % 4 != 0);
+               assert(tex->surface.u.gfx9.surf.swizzle_mode % 4 != 0);
 
-               switch (rtex->last_msaa_resolve_target_micro_mode) {
+               switch (tex->last_msaa_resolve_target_micro_mode) {
                case RADEON_MICRO_MODE_DISPLAY:
-                       rtex->surface.u.gfx9.surf.swizzle_mode &= ~0x3;
-                       rtex->surface.u.gfx9.surf.swizzle_mode += 2; /* D */
+                       tex->surface.u.gfx9.surf.swizzle_mode &= ~0x3;
+                       tex->surface.u.gfx9.surf.swizzle_mode += 2; /* D */
                        break;
                case RADEON_MICRO_MODE_THIN:
-                       rtex->surface.u.gfx9.surf.swizzle_mode &= ~0x3;
-                       rtex->surface.u.gfx9.surf.swizzle_mode += 1; /* S */
+                       tex->surface.u.gfx9.surf.swizzle_mode &= ~0x3;
+                       tex->surface.u.gfx9.surf.swizzle_mode += 1; /* S */
                        break;
                case RADEON_MICRO_MODE_ROTATED:
-                       rtex->surface.u.gfx9.surf.swizzle_mode &= ~0x3;
-                       rtex->surface.u.gfx9.surf.swizzle_mode += 3; /* R */
+                       tex->surface.u.gfx9.surf.swizzle_mode &= ~0x3;
+                       tex->surface.u.gfx9.surf.swizzle_mode += 3; /* R */
                        break;
                default: /* depth */
                        assert(!"unexpected micro mode");
@@ -317,48 +321,48 @@ static void si_set_optimal_micro_tile_mode(struct si_screen *sscreen,
                 * any definitions for them either. They are all 2D_TILED_THIN1
                 * modes with different bpp and micro tile mode.
                 */
-               switch (rtex->last_msaa_resolve_target_micro_mode) {
+               switch (tex->last_msaa_resolve_target_micro_mode) {
                case RADEON_MICRO_MODE_DISPLAY:
-                       rtex->surface.u.legacy.tiling_index[0] = 10;
+                       tex->surface.u.legacy.tiling_index[0] = 10;
                        break;
                case RADEON_MICRO_MODE_THIN:
-                       rtex->surface.u.legacy.tiling_index[0] = 14;
+                       tex->surface.u.legacy.tiling_index[0] = 14;
                        break;
                case RADEON_MICRO_MODE_ROTATED:
-                       rtex->surface.u.legacy.tiling_index[0] = 28;
+                       tex->surface.u.legacy.tiling_index[0] = 28;
                        break;
                default: /* depth, thick */
                        assert(!"unexpected micro mode");
                        return;
                }
        } else { /* SI */
-               switch (rtex->last_msaa_resolve_target_micro_mode) {
+               switch (tex->last_msaa_resolve_target_micro_mode) {
                case RADEON_MICRO_MODE_DISPLAY:
-                       switch (rtex->surface.bpe) {
+                       switch (tex->surface.bpe) {
                        case 1:
-                            rtex->surface.u.legacy.tiling_index[0] = 10;
+                            tex->surface.u.legacy.tiling_index[0] = 10;
                             break;
                        case 2:
-                            rtex->surface.u.legacy.tiling_index[0] = 11;
+                            tex->surface.u.legacy.tiling_index[0] = 11;
                             break;
                        default: /* 4, 8 */
-                            rtex->surface.u.legacy.tiling_index[0] = 12;
+                            tex->surface.u.legacy.tiling_index[0] = 12;
                             break;
                        }
                        break;
                case RADEON_MICRO_MODE_THIN:
-                       switch (rtex->surface.bpe) {
+                       switch (tex->surface.bpe) {
                        case 1:
-                                rtex->surface.u.legacy.tiling_index[0] = 14;
+                                tex->surface.u.legacy.tiling_index[0] = 14;
                                 break;
                        case 2:
-                                rtex->surface.u.legacy.tiling_index[0] = 15;
+                                tex->surface.u.legacy.tiling_index[0] = 15;
                                 break;
                        case 4:
-                                rtex->surface.u.legacy.tiling_index[0] = 16;
+                                tex->surface.u.legacy.tiling_index[0] = 16;
                                 break;
                        default: /* 8, 16 */
-                                rtex->surface.u.legacy.tiling_index[0] = 17;
+                                tex->surface.u.legacy.tiling_index[0] = 17;
                                 break;
                        }
                        break;
@@ -368,7 +372,7 @@ static void si_set_optimal_micro_tile_mode(struct si_screen *sscreen,
                }
        }
 
-       rtex->surface.micro_tile_mode = rtex->last_msaa_resolve_target_micro_mode;
+       tex->surface.micro_tile_mode = tex->last_msaa_resolve_target_micro_mode;
 
        p_atomic_inc(&sscreen->dirty_tex_counter);
 }
@@ -389,7 +393,7 @@ static void si_do_fast_color_clear(struct si_context *sctx,
                return;
 
        for (i = 0; i < fb->nr_cbufs; i++) {
-               struct r600_texture *tex;
+               struct si_texture *tex;
                unsigned clear_bit = PIPE_CLEAR_COLOR0 << i;
 
                if (!fb->cbufs[i])
@@ -403,7 +407,7 @@ static void si_do_fast_color_clear(struct si_context *sctx,
                if (level > 0)
                        continue;
 
-               tex = (struct r600_texture *)fb->cbufs[i]->texture;
+               tex = (struct si_texture *)fb->cbufs[i]->texture;
 
                /* TODO: GFX9: Implement DCC fast clear for level 0 of
                 * mipmapped textures. Mipmapped DCC has to clear a rectangular
@@ -433,13 +437,10 @@ static void si_do_fast_color_clear(struct si_context *sctx,
                    !(tex->buffer.external_usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH))
                        continue;
 
-               /* fast color clear with 1D tiling doesn't work on old kernels and CIK */
-               if (sctx->chip_class == CIK &&
+               if (sctx->chip_class <= VI &&
                    tex->surface.u.legacy.level[0].mode == RADEON_SURF_MODE_1D &&
-                   sctx->screen->info.drm_major == 2 &&
-                   sctx->screen->info.drm_minor < 38) {
+                   !sctx->screen->info.htile_cmask_support_1d_tiling)
                        continue;
-               }
 
                /* Fast clear is the most appropriate place to enable DCC for
                 * displayable surfaces.
@@ -478,7 +479,7 @@ static void si_do_fast_color_clear(struct si_context *sctx,
                        if (sctx->screen->debug_flags & DBG(NO_DCC_CLEAR))
                                continue;
 
-                       /* This can only occur with MSAA. */
+                       /* This can happen with mipmapping or MSAA. */
                        if (sctx->chip_class == VI &&
                            !tex->surface.u.legacy.level[level].dcc_fast_clear_size)
                                continue;
@@ -545,10 +546,10 @@ static void si_do_fast_color_clear(struct si_context *sctx,
                /* We can change the micro tile mode before a full clear. */
                si_set_optimal_micro_tile_mode(sctx->screen, tex);
 
-               si_set_clear_color(tex, fb->cbufs[i]->format, color);
-
-               sctx->framebuffer.dirty_cbufs |= 1 << i;
-               si_mark_atom_dirty(sctx, &sctx->atoms.s.framebuffer);
+               if (si_set_clear_color(tex, fb->cbufs[i]->format, color)) {
+                       sctx->framebuffer.dirty_cbufs |= 1 << i;
+                       si_mark_atom_dirty(sctx, &sctx->atoms.s.framebuffer);
+               }
                *buffers &= ~clear_bit;
        }
 }
@@ -560,8 +561,8 @@ static void si_clear(struct pipe_context *ctx, unsigned buffers,
        struct si_context *sctx = (struct si_context *)ctx;
        struct pipe_framebuffer_state *fb = &sctx->framebuffer.state;
        struct pipe_surface *zsbuf = fb->zsbuf;
-       struct r600_texture *zstex =
-               zsbuf ? (struct r600_texture*)zsbuf->texture : NULL;
+       struct si_texture *zstex =
+               zsbuf ? (struct si_texture*)zsbuf->texture : NULL;
 
        if (buffers & PIPE_CLEAR_COLOR) {
                si_do_fast_color_clear(sctx, &buffers, color);
@@ -570,13 +571,13 @@ static void si_clear(struct pipe_context *ctx, unsigned buffers,
 
                /* These buffers cannot use fast clear, make sure to disable expansion. */
                for (unsigned i = 0; i < fb->nr_cbufs; i++) {
-                       struct r600_texture *tex;
+                       struct si_texture *tex;
 
                        /* If not clearing this buffer, skip. */
                        if (!(buffers & (PIPE_CLEAR_COLOR0 << i)) || !fb->cbufs[i])
                                continue;
 
-                       tex = (struct r600_texture *)fb->cbufs[i]->texture;
+                       tex = (struct si_texture *)fb->cbufs[i]->texture;
                        if (tex->surface.fmask_size == 0)
                                tex->dirty_level_mask &= ~(1 << fb->cbufs[i]->u.tex.level);
                }
@@ -596,9 +597,12 @@ static void si_clear(struct pipe_context *ctx, unsigned buffers,
                                sctx->db_depth_disable_expclear = true;
                        }
 
-                       zstex->depth_clear_value = depth;
-                       sctx->framebuffer.dirty_zsbuf = true;
-                       si_mark_atom_dirty(sctx, &sctx->atoms.s.framebuffer); /* updates DB_DEPTH_CLEAR */
+                       if (zstex->depth_clear_value != (float)depth) {
+                               /* Update DB_DEPTH_CLEAR. */
+                               zstex->depth_clear_value = depth;
+                               sctx->framebuffer.dirty_zsbuf = true;
+                               si_mark_atom_dirty(sctx, &sctx->atoms.s.framebuffer);
+                       }
                        sctx->db_depth_clear = true;
                        si_mark_atom_dirty(sctx, &sctx->atoms.s.db_render_state);
                }
@@ -614,9 +618,12 @@ static void si_clear(struct pipe_context *ctx, unsigned buffers,
                                sctx->db_stencil_disable_expclear = true;
                        }
 
-                       zstex->stencil_clear_value = stencil;
-                       sctx->framebuffer.dirty_zsbuf = true;
-                       si_mark_atom_dirty(sctx, &sctx->atoms.s.framebuffer); /* updates DB_STENCIL_CLEAR */
+                       if (zstex->stencil_clear_value != (uint8_t)stencil) {
+                               /* Update DB_STENCIL_CLEAR. */
+                               zstex->stencil_clear_value = stencil;
+                               sctx->framebuffer.dirty_zsbuf = true;
+                               si_mark_atom_dirty(sctx, &sctx->atoms.s.framebuffer);
+                       }
                        sctx->db_stencil_clear = true;
                        si_mark_atom_dirty(sctx, &sctx->atoms.s.db_render_state);
                }
@@ -699,7 +706,7 @@ static void si_clear_texture(struct pipe_context *pipe,
                             const void *data)
 {
        struct pipe_screen *screen = pipe->screen;
-       struct r600_texture *rtex = (struct r600_texture*)tex;
+       struct si_texture *stex = (struct si_texture*)tex;
        struct pipe_surface tmpl = {{0}};
        struct pipe_surface *sf;
        const struct util_format_description *desc =
@@ -713,7 +720,7 @@ static void si_clear_texture(struct pipe_context *pipe,
        if (!sf)
                return;
 
-       if (rtex->is_depth) {
+       if (stex->is_depth) {
                unsigned clear;
                float depth;
                uint8_t stencil = 0;
@@ -722,7 +729,7 @@ static void si_clear_texture(struct pipe_context *pipe,
                clear = PIPE_CLEAR_DEPTH;
                desc->unpack_z_float(&depth, 0, data, 0, 1, 1);
 
-               if (rtex->surface.has_stencil) {
+               if (stex->surface.has_stencil) {
                        clear |= PIPE_CLEAR_STENCIL;
                        desc->unpack_s_8uint(&stencil, 0, data, 0, 1, 1);
                }