101e04c3fSmrg/*
201e04c3fSmrg * Copyright (c) 2012-2017 Etnaviv Project
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sub license,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the
1201e04c3fSmrg * next paragraph) shall be included in all copies or substantial portions
1301e04c3fSmrg * of the Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2101e04c3fSmrg * DEALINGS IN THE SOFTWARE.
2201e04c3fSmrg *
2301e04c3fSmrg * Authors:
2401e04c3fSmrg *    Wladimir J. van der Laan <laanwj@gmail.com>
2501e04c3fSmrg */
2601e04c3fSmrg
2701e04c3fSmrg#include "etnaviv_rs.h"
2801e04c3fSmrg
2901e04c3fSmrg#include "etnaviv_clear_blit.h"
3001e04c3fSmrg#include "etnaviv_context.h"
3101e04c3fSmrg#include "etnaviv_emit.h"
3201e04c3fSmrg#include "etnaviv_format.h"
3301e04c3fSmrg#include "etnaviv_resource.h"
3401e04c3fSmrg#include "etnaviv_screen.h"
3501e04c3fSmrg#include "etnaviv_surface.h"
3601e04c3fSmrg#include "etnaviv_tiling.h"
3701e04c3fSmrg#include "etnaviv_translate.h"
3801e04c3fSmrg#include "etnaviv_util.h"
3901e04c3fSmrg
4001e04c3fSmrg#include "pipe/p_defines.h"
4101e04c3fSmrg#include "pipe/p_state.h"
427ec681f3Smrg#include "util/compiler.h"
4301e04c3fSmrg#include "util/u_blitter.h"
4401e04c3fSmrg#include "util/u_inlines.h"
4501e04c3fSmrg#include "util/u_memory.h"
4601e04c3fSmrg#include "util/u_surface.h"
4701e04c3fSmrg
4801e04c3fSmrg#include "hw/common.xml.h"
4901e04c3fSmrg#include "hw/state.xml.h"
5001e04c3fSmrg#include "hw/state_3d.xml.h"
5101e04c3fSmrg
5201e04c3fSmrg#include <assert.h>
5301e04c3fSmrg
547ec681f3Smrg/* return a RS "compatible" format for use when copying */
557ec681f3Smrgstatic uint32_t
567ec681f3Smrgetna_compatible_rs_format(enum pipe_format fmt)
577ec681f3Smrg{
587ec681f3Smrg   /* YUYV and UYVY are blocksize 4, but 2 bytes per pixel */
597ec681f3Smrg   if (fmt == PIPE_FORMAT_YUYV || fmt == PIPE_FORMAT_UYVY)
607ec681f3Smrg      return RS_FORMAT_A4R4G4B4;
617ec681f3Smrg
627ec681f3Smrg   switch (util_format_get_blocksize(fmt)) {
637ec681f3Smrg   case 2: return RS_FORMAT_A4R4G4B4;
647ec681f3Smrg   case 4: return RS_FORMAT_A8R8G8B8;
657ec681f3Smrg   default: return ETNA_NO_MATCH;
667ec681f3Smrg   }
677ec681f3Smrg}
687ec681f3Smrg
6901e04c3fSmrgvoid
7001e04c3fSmrgetna_compile_rs_state(struct etna_context *ctx, struct compiled_rs_state *cs,
7101e04c3fSmrg                      const struct rs_state *rs)
7201e04c3fSmrg{
737ec681f3Smrg   struct etna_screen *screen = ctx->screen;
747ec681f3Smrg
7501e04c3fSmrg   memset(cs, 0, sizeof(*cs));
7601e04c3fSmrg
7701e04c3fSmrg   /* TILED and SUPERTILED layout have their strides multiplied with 4 in RS */
7801e04c3fSmrg   unsigned source_stride_shift = COND(rs->source_tiling != ETNA_LAYOUT_LINEAR, 2);
7901e04c3fSmrg   unsigned dest_stride_shift = COND(rs->dest_tiling != ETNA_LAYOUT_LINEAR, 2);
8001e04c3fSmrg
8101e04c3fSmrg   /* tiling == ETNA_LAYOUT_MULTI_TILED or ETNA_LAYOUT_MULTI_SUPERTILED? */
8201e04c3fSmrg   int source_multi = COND(rs->source_tiling & ETNA_LAYOUT_BIT_MULTI, 1);
8301e04c3fSmrg   int dest_multi = COND(rs->dest_tiling & ETNA_LAYOUT_BIT_MULTI, 1);
8401e04c3fSmrg
8501e04c3fSmrg   /* Vivante RS needs widths to be a multiple of 16 or bad things
8601e04c3fSmrg    * happen, such as scribbing over memory, or the GPU hanging,
8701e04c3fSmrg    * even for non-tiled formats.  As this is serious, use abort().
8801e04c3fSmrg    */
8901e04c3fSmrg   if (rs->width & ETNA_RS_WIDTH_MASK)
9001e04c3fSmrg      abort();
9101e04c3fSmrg
9201e04c3fSmrg   /* TODO could just pre-generate command buffer, would simply submit to one memcpy */
9301e04c3fSmrg   cs->RS_CONFIG = VIVS_RS_CONFIG_SOURCE_FORMAT(rs->source_format) |
9401e04c3fSmrg                   COND(rs->downsample_x, VIVS_RS_CONFIG_DOWNSAMPLE_X) |
9501e04c3fSmrg                   COND(rs->downsample_y, VIVS_RS_CONFIG_DOWNSAMPLE_Y) |
9601e04c3fSmrg                   COND(rs->source_tiling & 1, VIVS_RS_CONFIG_SOURCE_TILED) |
9701e04c3fSmrg                   VIVS_RS_CONFIG_DEST_FORMAT(rs->dest_format) |
9801e04c3fSmrg                   COND(rs->dest_tiling & 1, VIVS_RS_CONFIG_DEST_TILED) |
9901e04c3fSmrg                   COND(rs->swap_rb, VIVS_RS_CONFIG_SWAP_RB) |
10001e04c3fSmrg                   COND(rs->flip, VIVS_RS_CONFIG_FLIP);
10101e04c3fSmrg
10201e04c3fSmrg   cs->RS_SOURCE_STRIDE = (rs->source_stride << source_stride_shift) |
10301e04c3fSmrg                          COND(rs->source_tiling & 2, VIVS_RS_SOURCE_STRIDE_TILING) |
10401e04c3fSmrg                          COND(source_multi, VIVS_RS_SOURCE_STRIDE_MULTI);
10501e04c3fSmrg
10601e04c3fSmrg   /* Initially all pipes are set to the base address of the source and
10701e04c3fSmrg    * destination buffer respectively. This will be overridden below as
10801e04c3fSmrg    * necessary for the multi-pipe, multi-tiled case.
10901e04c3fSmrg    */
1107ec681f3Smrg   for (unsigned pipe = 0; pipe < screen->specs.pixel_pipes; ++pipe) {
11101e04c3fSmrg      cs->source[pipe].bo = rs->source;
11201e04c3fSmrg      cs->source[pipe].offset = rs->source_offset;
11301e04c3fSmrg      cs->source[pipe].flags = ETNA_RELOC_READ;
11401e04c3fSmrg
11501e04c3fSmrg      cs->dest[pipe].bo = rs->dest;
11601e04c3fSmrg      cs->dest[pipe].offset = rs->dest_offset;
11701e04c3fSmrg      cs->dest[pipe].flags = ETNA_RELOC_WRITE;
11801e04c3fSmrg
11901e04c3fSmrg      cs->RS_PIPE_OFFSET[pipe] = VIVS_RS_PIPE_OFFSET_X(0) | VIVS_RS_PIPE_OFFSET_Y(0);
12001e04c3fSmrg   }
12101e04c3fSmrg
12201e04c3fSmrg   cs->RS_DEST_STRIDE = (rs->dest_stride << dest_stride_shift) |
12301e04c3fSmrg                        COND(rs->dest_tiling & 2, VIVS_RS_DEST_STRIDE_TILING) |
12401e04c3fSmrg                        COND(dest_multi, VIVS_RS_DEST_STRIDE_MULTI);
12501e04c3fSmrg
12601e04c3fSmrg
1277ec681f3Smrg   if (source_multi)
1287ec681f3Smrg      cs->source[1].offset = rs->source_offset + rs->source_stride * rs->source_padded_height / 2;
12901e04c3fSmrg
1307ec681f3Smrg   if (dest_multi)
1317ec681f3Smrg      cs->dest[1].offset = rs->dest_offset + rs->dest_stride * rs->dest_padded_height / 2;
13201e04c3fSmrg
1337ec681f3Smrg   cs->RS_WINDOW_SIZE = VIVS_RS_WINDOW_SIZE_WIDTH(rs->width) |
1347ec681f3Smrg                        VIVS_RS_WINDOW_SIZE_HEIGHT(rs->height);
1357ec681f3Smrg
1367ec681f3Smrg   /* use dual pipe mode when required */
1377ec681f3Smrg   if (!screen->specs.single_buffer && screen->specs.pixel_pipes == 2 && !(rs->height & 7)) {
13801e04c3fSmrg      cs->RS_WINDOW_SIZE = VIVS_RS_WINDOW_SIZE_WIDTH(rs->width) |
1397ec681f3Smrg                              VIVS_RS_WINDOW_SIZE_HEIGHT(rs->height / 2);
14001e04c3fSmrg      cs->RS_PIPE_OFFSET[1] = VIVS_RS_PIPE_OFFSET_X(0) | VIVS_RS_PIPE_OFFSET_Y(rs->height / 2);
14101e04c3fSmrg   }
14201e04c3fSmrg
14301e04c3fSmrg   cs->RS_DITHER[0] = rs->dither[0];
14401e04c3fSmrg   cs->RS_DITHER[1] = rs->dither[1];
14501e04c3fSmrg   cs->RS_CLEAR_CONTROL = VIVS_RS_CLEAR_CONTROL_BITS(rs->clear_bits) | rs->clear_mode;
14601e04c3fSmrg   cs->RS_FILL_VALUE[0] = rs->clear_value[0];
14701e04c3fSmrg   cs->RS_FILL_VALUE[1] = rs->clear_value[1];
14801e04c3fSmrg   cs->RS_FILL_VALUE[2] = rs->clear_value[2];
14901e04c3fSmrg   cs->RS_FILL_VALUE[3] = rs->clear_value[3];
15001e04c3fSmrg   cs->RS_EXTRA_CONFIG = VIVS_RS_EXTRA_CONFIG_AA(rs->aa) |
15101e04c3fSmrg                         VIVS_RS_EXTRA_CONFIG_ENDIAN(rs->endian_mode);
15201e04c3fSmrg
15301e04c3fSmrg   /* If source the same as destination, and the hardware supports this,
15401e04c3fSmrg    * do an in-place resolve to fill in unrendered tiles.
15501e04c3fSmrg    */
1567ec681f3Smrg   if (screen->specs.single_buffer && rs->source == rs->dest &&
15701e04c3fSmrg         rs->source_offset == rs->dest_offset &&
15801e04c3fSmrg         rs->source_format == rs->dest_format &&
15901e04c3fSmrg         rs->source_tiling == rs->dest_tiling &&
16001e04c3fSmrg         (rs->source_tiling & ETNA_LAYOUT_BIT_SUPER) &&
16101e04c3fSmrg         rs->source_stride == rs->dest_stride &&
16201e04c3fSmrg         !rs->downsample_x && !rs->downsample_y &&
16301e04c3fSmrg         !rs->swap_rb && !rs->flip &&
1647ec681f3Smrg         !rs->clear_mode && rs->source_padded_width &&
1657ec681f3Smrg         !rs->source_ts_compressed) {
16601e04c3fSmrg      /* Total number of tiles (same as for autodisable) */
16701e04c3fSmrg      cs->RS_KICKER_INPLACE = rs->tile_count;
16801e04c3fSmrg   }
16901e04c3fSmrg   cs->source_ts_valid = rs->source_ts_valid;
17001e04c3fSmrg}
17101e04c3fSmrg
17201e04c3fSmrg/* modify the clear bits value in the compiled RS state */
17301e04c3fSmrgstatic void
17401e04c3fSmrgetna_modify_rs_clearbits(struct compiled_rs_state *cs, uint32_t clear_bits)
17501e04c3fSmrg{
17601e04c3fSmrg   cs->RS_CLEAR_CONTROL &= ~VIVS_RS_CLEAR_CONTROL_BITS__MASK;
17701e04c3fSmrg   cs->RS_CLEAR_CONTROL |= VIVS_RS_CLEAR_CONTROL_BITS(clear_bits);
17801e04c3fSmrg}
17901e04c3fSmrg
18001e04c3fSmrg#define EMIT_STATE(state_name, src_value) \
18101e04c3fSmrg   etna_coalsence_emit(stream, &coalesce, VIVS_##state_name, src_value)
18201e04c3fSmrg
18301e04c3fSmrg#define EMIT_STATE_FIXP(state_name, src_value) \
18401e04c3fSmrg   etna_coalsence_emit_fixp(stream, &coalesce, VIVS_##state_name, src_value)
18501e04c3fSmrg
18601e04c3fSmrg#define EMIT_STATE_RELOC(state_name, src_value) \
18701e04c3fSmrg   etna_coalsence_emit_reloc(stream, &coalesce, VIVS_##state_name, src_value)
18801e04c3fSmrg
18901e04c3fSmrg/* submit RS state, without any processing and no dependence on context
19001e04c3fSmrg * except TS if this is a source-to-destination blit. */
19101e04c3fSmrgstatic void
19201e04c3fSmrgetna_submit_rs_state(struct etna_context *ctx,
19301e04c3fSmrg                     const struct compiled_rs_state *cs)
19401e04c3fSmrg{
19501e04c3fSmrg   struct etna_screen *screen = etna_screen(ctx->base.screen);
19601e04c3fSmrg   struct etna_cmd_stream *stream = ctx->stream;
19701e04c3fSmrg   struct etna_coalesce coalesce;
19801e04c3fSmrg
19901e04c3fSmrg   if (cs->RS_KICKER_INPLACE && !cs->source_ts_valid)
20001e04c3fSmrg      /* Inplace resolve is no-op if TS is not configured */
20101e04c3fSmrg      return;
20201e04c3fSmrg
20301e04c3fSmrg   ctx->stats.rs_operations++;
20401e04c3fSmrg
20501e04c3fSmrg   if (cs->RS_KICKER_INPLACE) {
20601e04c3fSmrg      etna_cmd_stream_reserve(stream, 6);
20701e04c3fSmrg      etna_coalesce_start(stream, &coalesce);
20801e04c3fSmrg      /* 0/1 */ EMIT_STATE(RS_EXTRA_CONFIG, cs->RS_EXTRA_CONFIG);
20901e04c3fSmrg      /* 2/3 */ EMIT_STATE(RS_SOURCE_STRIDE, cs->RS_SOURCE_STRIDE);
21001e04c3fSmrg      /* 4/5 */ EMIT_STATE(RS_KICKER_INPLACE, cs->RS_KICKER_INPLACE);
21101e04c3fSmrg      etna_coalesce_end(stream, &coalesce);
21201e04c3fSmrg   } else if (screen->specs.pixel_pipes == 1) {
21301e04c3fSmrg      etna_cmd_stream_reserve(stream, 22);
21401e04c3fSmrg      etna_coalesce_start(stream, &coalesce);
21501e04c3fSmrg      /* 0/1 */ EMIT_STATE(RS_CONFIG, cs->RS_CONFIG);
21601e04c3fSmrg      /* 2   */ EMIT_STATE_RELOC(RS_SOURCE_ADDR, &cs->source[0]);
21701e04c3fSmrg      /* 3   */ EMIT_STATE(RS_SOURCE_STRIDE, cs->RS_SOURCE_STRIDE);
21801e04c3fSmrg      /* 4   */ EMIT_STATE_RELOC(RS_DEST_ADDR, &cs->dest[0]);
21901e04c3fSmrg      /* 5   */ EMIT_STATE(RS_DEST_STRIDE, cs->RS_DEST_STRIDE);
22001e04c3fSmrg      /* 6/7 */ EMIT_STATE(RS_WINDOW_SIZE, cs->RS_WINDOW_SIZE);
22101e04c3fSmrg      /* 8/9 */ EMIT_STATE(RS_DITHER(0), cs->RS_DITHER[0]);
22201e04c3fSmrg      /*10   */ EMIT_STATE(RS_DITHER(1), cs->RS_DITHER[1]);
22301e04c3fSmrg      /*11 - pad */
22401e04c3fSmrg      /*12/13*/ EMIT_STATE(RS_CLEAR_CONTROL, cs->RS_CLEAR_CONTROL);
22501e04c3fSmrg      /*14   */ EMIT_STATE(RS_FILL_VALUE(0), cs->RS_FILL_VALUE[0]);
22601e04c3fSmrg      /*15   */ EMIT_STATE(RS_FILL_VALUE(1), cs->RS_FILL_VALUE[1]);
22701e04c3fSmrg      /*16   */ EMIT_STATE(RS_FILL_VALUE(2), cs->RS_FILL_VALUE[2]);
22801e04c3fSmrg      /*17   */ EMIT_STATE(RS_FILL_VALUE(3), cs->RS_FILL_VALUE[3]);
22901e04c3fSmrg      /*18/19*/ EMIT_STATE(RS_EXTRA_CONFIG, cs->RS_EXTRA_CONFIG);
23001e04c3fSmrg      /*20/21*/ EMIT_STATE(RS_KICKER, 0xbeebbeeb);
23101e04c3fSmrg      etna_coalesce_end(stream, &coalesce);
23201e04c3fSmrg   } else if (screen->specs.pixel_pipes == 2) {
23301e04c3fSmrg      etna_cmd_stream_reserve(stream, 34); /* worst case - both pipes multi=1 */
23401e04c3fSmrg      etna_coalesce_start(stream, &coalesce);
23501e04c3fSmrg      /* 0/1 */ EMIT_STATE(RS_CONFIG, cs->RS_CONFIG);
23601e04c3fSmrg      /* 2/3 */ EMIT_STATE(RS_SOURCE_STRIDE, cs->RS_SOURCE_STRIDE);
23701e04c3fSmrg      /* 4/5 */ EMIT_STATE(RS_DEST_STRIDE, cs->RS_DEST_STRIDE);
23801e04c3fSmrg      /* 6/7 */ EMIT_STATE_RELOC(RS_PIPE_SOURCE_ADDR(0), &cs->source[0]);
23901e04c3fSmrg      if (cs->RS_SOURCE_STRIDE & VIVS_RS_SOURCE_STRIDE_MULTI) {
24001e04c3fSmrg         /*8 */ EMIT_STATE_RELOC(RS_PIPE_SOURCE_ADDR(1), &cs->source[1]);
24101e04c3fSmrg         /*9 - pad */
24201e04c3fSmrg      }
24301e04c3fSmrg      /*10/11*/ EMIT_STATE_RELOC(RS_PIPE_DEST_ADDR(0), &cs->dest[0]);
24401e04c3fSmrg      if (cs->RS_DEST_STRIDE & VIVS_RS_DEST_STRIDE_MULTI) {
24501e04c3fSmrg         /*12*/ EMIT_STATE_RELOC(RS_PIPE_DEST_ADDR(1), &cs->dest[1]);
24601e04c3fSmrg         /*13 - pad */
24701e04c3fSmrg      }
24801e04c3fSmrg      /*14/15*/ EMIT_STATE(RS_PIPE_OFFSET(0), cs->RS_PIPE_OFFSET[0]);
24901e04c3fSmrg      /*16   */ EMIT_STATE(RS_PIPE_OFFSET(1), cs->RS_PIPE_OFFSET[1]);
25001e04c3fSmrg      /*17 - pad */
25101e04c3fSmrg      /*18/19*/ EMIT_STATE(RS_WINDOW_SIZE, cs->RS_WINDOW_SIZE);
25201e04c3fSmrg      /*20/21*/ EMIT_STATE(RS_DITHER(0), cs->RS_DITHER[0]);
25301e04c3fSmrg      /*22   */ EMIT_STATE(RS_DITHER(1), cs->RS_DITHER[1]);
25401e04c3fSmrg      /*23 - pad */
25501e04c3fSmrg      /*24/25*/ EMIT_STATE(RS_CLEAR_CONTROL, cs->RS_CLEAR_CONTROL);
25601e04c3fSmrg      /*26   */ EMIT_STATE(RS_FILL_VALUE(0), cs->RS_FILL_VALUE[0]);
25701e04c3fSmrg      /*27   */ EMIT_STATE(RS_FILL_VALUE(1), cs->RS_FILL_VALUE[1]);
25801e04c3fSmrg      /*28   */ EMIT_STATE(RS_FILL_VALUE(2), cs->RS_FILL_VALUE[2]);
25901e04c3fSmrg      /*29   */ EMIT_STATE(RS_FILL_VALUE(3), cs->RS_FILL_VALUE[3]);
26001e04c3fSmrg      /*30/31*/ EMIT_STATE(RS_EXTRA_CONFIG, cs->RS_EXTRA_CONFIG);
26101e04c3fSmrg      /*32/33*/ EMIT_STATE(RS_KICKER, 0xbeebbeeb);
26201e04c3fSmrg      etna_coalesce_end(stream, &coalesce);
26301e04c3fSmrg   } else {
26401e04c3fSmrg      abort();
26501e04c3fSmrg   }
26601e04c3fSmrg}
26701e04c3fSmrg
26801e04c3fSmrg/* Generate clear command for a surface (non-fast clear case) */
26901e04c3fSmrgvoid
27001e04c3fSmrgetna_rs_gen_clear_surface(struct etna_context *ctx, struct etna_surface *surf,
2717ec681f3Smrg                          uint64_t clear_value)
27201e04c3fSmrg{
2737ec681f3Smrg   ASSERTED struct etna_screen *screen = ctx->screen;
27401e04c3fSmrg   struct etna_resource *dst = etna_resource(surf->base.texture);
2757ec681f3Smrg   uint32_t format;
27601e04c3fSmrg
2777ec681f3Smrg   switch (util_format_get_blocksizebits(surf->base.format)) {
2787ec681f3Smrg   case 16:
2797ec681f3Smrg      format = RS_FORMAT_A4R4G4B4;
2807ec681f3Smrg      break;
2817ec681f3Smrg   case 32:
28201e04c3fSmrg      format = RS_FORMAT_A8R8G8B8;
2837ec681f3Smrg      break;
2847ec681f3Smrg   case 64:
2857ec681f3Smrg      assert(screen->specs.halti >= 2);
2867ec681f3Smrg      format = RS_FORMAT_64BPP_CLEAR;
2877ec681f3Smrg      break;
2887ec681f3Smrg   default:
2897ec681f3Smrg      unreachable("bpp not supported for clear by RS");
2907ec681f3Smrg      break;
29101e04c3fSmrg   }
29201e04c3fSmrg
29301e04c3fSmrg   /* use tiled clear if width is multiple of 16 */
29401e04c3fSmrg   bool tiled_clear = (surf->surf.padded_width & ETNA_RS_WIDTH_MASK) == 0 &&
29501e04c3fSmrg                      (surf->surf.padded_height & ETNA_RS_HEIGHT_MASK) == 0;
29601e04c3fSmrg
29701e04c3fSmrg   etna_compile_rs_state( ctx, &surf->clear_command, &(struct rs_state) {
29801e04c3fSmrg      .source_format = format,
29901e04c3fSmrg      .dest_format = format,
30001e04c3fSmrg      .dest = dst->bo,
30101e04c3fSmrg      .dest_offset = surf->surf.offset,
30201e04c3fSmrg      .dest_stride = surf->surf.stride,
30301e04c3fSmrg      .dest_padded_height = surf->surf.padded_height,
30401e04c3fSmrg      .dest_tiling = tiled_clear ? dst->layout : ETNA_LAYOUT_LINEAR,
30501e04c3fSmrg      .dither = {0xffffffff, 0xffffffff},
30601e04c3fSmrg      .width = surf->surf.padded_width, /* These must be padded to 16x4 if !LINEAR, otherwise RS will hang */
30701e04c3fSmrg      .height = surf->surf.padded_height,
3087ec681f3Smrg      .clear_value = {clear_value, clear_value >> 32, clear_value, clear_value >> 32},
30901e04c3fSmrg      .clear_mode = VIVS_RS_CLEAR_CONTROL_MODE_ENABLED1,
31001e04c3fSmrg      .clear_bits = 0xffff
31101e04c3fSmrg   });
31201e04c3fSmrg}
31301e04c3fSmrg
31401e04c3fSmrgstatic void
31501e04c3fSmrgetna_blit_clear_color_rs(struct pipe_context *pctx, struct pipe_surface *dst,
31601e04c3fSmrg                      const union pipe_color_union *color)
31701e04c3fSmrg{
31801e04c3fSmrg   struct etna_context *ctx = etna_context(pctx);
31901e04c3fSmrg   struct etna_surface *surf = etna_surface(dst);
3207ec681f3Smrg   uint64_t new_clear_value = etna_clear_blit_pack_rgba(surf->base.format, color);
32101e04c3fSmrg
32201e04c3fSmrg   if (surf->surf.ts_size) { /* TS: use precompiled clear command */
32301e04c3fSmrg      ctx->framebuffer.TS_COLOR_CLEAR_VALUE = new_clear_value;
3247ec681f3Smrg      ctx->framebuffer.TS_COLOR_CLEAR_VALUE_EXT = new_clear_value >> 32;
32501e04c3fSmrg
32601e04c3fSmrg      if (VIV_FEATURE(ctx->screen, chipMinorFeatures1, AUTO_DISABLE)) {
32701e04c3fSmrg         /* Set number of color tiles to be filled */
32801e04c3fSmrg         etna_set_state(ctx->stream, VIVS_TS_COLOR_AUTO_DISABLE_COUNT,
32901e04c3fSmrg                        surf->surf.padded_width * surf->surf.padded_height / 16);
33001e04c3fSmrg         ctx->framebuffer.TS_MEM_CONFIG |= VIVS_TS_MEM_CONFIG_COLOR_AUTO_DISABLE;
33101e04c3fSmrg      }
33201e04c3fSmrg
33301e04c3fSmrg      surf->level->ts_valid = true;
33401e04c3fSmrg      ctx->dirty |= ETNA_DIRTY_TS | ETNA_DIRTY_DERIVE_TS;
33501e04c3fSmrg   } else if (unlikely(new_clear_value != surf->level->clear_value)) { /* Queue normal RS clear for non-TS surfaces */
33601e04c3fSmrg      /* If clear color changed, re-generate stored command */
33701e04c3fSmrg      etna_rs_gen_clear_surface(ctx, surf, new_clear_value);
33801e04c3fSmrg   }
33901e04c3fSmrg
34001e04c3fSmrg   etna_submit_rs_state(ctx, &surf->clear_command);
34101e04c3fSmrg
34201e04c3fSmrg   surf->level->clear_value = new_clear_value;
34301e04c3fSmrg   resource_written(ctx, surf->base.texture);
34401e04c3fSmrg   etna_resource(surf->base.texture)->seqno++;
34501e04c3fSmrg}
34601e04c3fSmrg
34701e04c3fSmrgstatic void
34801e04c3fSmrgetna_blit_clear_zs_rs(struct pipe_context *pctx, struct pipe_surface *dst,
34901e04c3fSmrg                   unsigned buffers, double depth, unsigned stencil)
35001e04c3fSmrg{
35101e04c3fSmrg   struct etna_context *ctx = etna_context(pctx);
35201e04c3fSmrg   struct etna_surface *surf = etna_surface(dst);
35301e04c3fSmrg   uint32_t new_clear_value = translate_clear_depth_stencil(surf->base.format, depth, stencil);
35401e04c3fSmrg   uint32_t new_clear_bits = 0, clear_bits_depth, clear_bits_stencil;
35501e04c3fSmrg
35601e04c3fSmrg   /* Get the channels to clear */
35701e04c3fSmrg   switch (surf->base.format) {
35801e04c3fSmrg   case PIPE_FORMAT_Z16_UNORM:
35901e04c3fSmrg      clear_bits_depth = 0xffff;
36001e04c3fSmrg      clear_bits_stencil = 0;
36101e04c3fSmrg      break;
36201e04c3fSmrg   case PIPE_FORMAT_X8Z24_UNORM:
36301e04c3fSmrg   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
36401e04c3fSmrg      clear_bits_depth = 0xeeee;
36501e04c3fSmrg      clear_bits_stencil = 0x1111;
36601e04c3fSmrg      break;
36701e04c3fSmrg   default:
36801e04c3fSmrg      clear_bits_depth = clear_bits_stencil = 0xffff;
36901e04c3fSmrg      break;
37001e04c3fSmrg   }
37101e04c3fSmrg
37201e04c3fSmrg   if (buffers & PIPE_CLEAR_DEPTH)
37301e04c3fSmrg      new_clear_bits |= clear_bits_depth;
37401e04c3fSmrg   if (buffers & PIPE_CLEAR_STENCIL)
37501e04c3fSmrg      new_clear_bits |= clear_bits_stencil;
37601e04c3fSmrg   /* FIXME: when tile status is enabled, this becomes more complex as
37701e04c3fSmrg    * we may separately clear the depth from the stencil.  In this case,
37801e04c3fSmrg    * we want to resolve the surface, and avoid using the tile status.
37901e04c3fSmrg    * We may be better off recording the pending clear operation,
38001e04c3fSmrg    * delaying the actual clear to the first use.  This way, we can merge
38101e04c3fSmrg    * consecutive clears together. */
38201e04c3fSmrg   if (surf->surf.ts_size) { /* TS: use precompiled clear command */
38301e04c3fSmrg      /* Set new clear depth value */
38401e04c3fSmrg      ctx->framebuffer.TS_DEPTH_CLEAR_VALUE = new_clear_value;
38501e04c3fSmrg      if (VIV_FEATURE(ctx->screen, chipMinorFeatures1, AUTO_DISABLE)) {
38601e04c3fSmrg         /* Set number of depth tiles to be filled */
38701e04c3fSmrg         etna_set_state(ctx->stream, VIVS_TS_DEPTH_AUTO_DISABLE_COUNT,
38801e04c3fSmrg                        surf->surf.padded_width * surf->surf.padded_height / 16);
38901e04c3fSmrg         ctx->framebuffer.TS_MEM_CONFIG |= VIVS_TS_MEM_CONFIG_DEPTH_AUTO_DISABLE;
39001e04c3fSmrg      }
39101e04c3fSmrg
39201e04c3fSmrg      surf->level->ts_valid = true;
39301e04c3fSmrg      ctx->dirty |= ETNA_DIRTY_TS | ETNA_DIRTY_DERIVE_TS;
39401e04c3fSmrg   } else {
39501e04c3fSmrg      if (unlikely(new_clear_value != surf->level->clear_value)) { /* Queue normal RS clear for non-TS surfaces */
39601e04c3fSmrg         /* If clear depth value changed, re-generate stored command */
39701e04c3fSmrg         etna_rs_gen_clear_surface(ctx, surf, new_clear_value);
39801e04c3fSmrg      }
39901e04c3fSmrg      /* Update the channels to be cleared */
40001e04c3fSmrg      etna_modify_rs_clearbits(&surf->clear_command, new_clear_bits);
40101e04c3fSmrg   }
40201e04c3fSmrg
40301e04c3fSmrg   etna_submit_rs_state(ctx, &surf->clear_command);
40401e04c3fSmrg
40501e04c3fSmrg   surf->level->clear_value = new_clear_value;
40601e04c3fSmrg   resource_written(ctx, surf->base.texture);
40701e04c3fSmrg   etna_resource(surf->base.texture)->seqno++;
40801e04c3fSmrg}
40901e04c3fSmrg
41001e04c3fSmrgstatic void
4117ec681f3Smrgetna_clear_rs(struct pipe_context *pctx, unsigned buffers, const struct pipe_scissor_state *scissor_state,
41201e04c3fSmrg           const union pipe_color_union *color, double depth, unsigned stencil)
41301e04c3fSmrg{
41401e04c3fSmrg   struct etna_context *ctx = etna_context(pctx);
4157ec681f3Smrg   mtx_lock(&ctx->lock);
41601e04c3fSmrg
41701e04c3fSmrg   /* Flush color and depth cache before clearing anything.
41801e04c3fSmrg    * This is especially important when coming from another surface, as
41901e04c3fSmrg    * otherwise it may clear part of the old surface instead. */
42001e04c3fSmrg   etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH);
42101e04c3fSmrg   etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE);
42201e04c3fSmrg
42301e04c3fSmrg   /* Preparation: Flush the TS if needed. This must be done after flushing
42401e04c3fSmrg    * color and depth, otherwise it can result in crashes */
42501e04c3fSmrg   bool need_ts_flush = false;
42601e04c3fSmrg   if ((buffers & PIPE_CLEAR_COLOR) && ctx->framebuffer_s.nr_cbufs) {
42701e04c3fSmrg      struct etna_surface *surf = etna_surface(ctx->framebuffer_s.cbufs[0]);
42801e04c3fSmrg      if (surf->surf.ts_size)
42901e04c3fSmrg         need_ts_flush = true;
43001e04c3fSmrg   }
43101e04c3fSmrg   if ((buffers & PIPE_CLEAR_DEPTHSTENCIL) && ctx->framebuffer_s.zsbuf != NULL) {
43201e04c3fSmrg      struct etna_surface *surf = etna_surface(ctx->framebuffer_s.zsbuf);
43301e04c3fSmrg
43401e04c3fSmrg      if (surf->surf.ts_size)
43501e04c3fSmrg         need_ts_flush = true;
43601e04c3fSmrg   }
43701e04c3fSmrg
43801e04c3fSmrg   if (need_ts_flush)
43901e04c3fSmrg      etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, VIVS_TS_FLUSH_CACHE_FLUSH);
44001e04c3fSmrg
44101e04c3fSmrg   /* No need to set up the TS here as RS clear operations (in contrast to
44201e04c3fSmrg    * resolve and copy) do not require the TS state.
44301e04c3fSmrg    */
44401e04c3fSmrg   if (buffers & PIPE_CLEAR_COLOR) {
44501e04c3fSmrg      for (int idx = 0; idx < ctx->framebuffer_s.nr_cbufs; ++idx) {
44601e04c3fSmrg         etna_blit_clear_color_rs(pctx, ctx->framebuffer_s.cbufs[idx],
44701e04c3fSmrg                               &color[idx]);
44801e04c3fSmrg      }
44901e04c3fSmrg   }
45001e04c3fSmrg
45101e04c3fSmrg   /* Flush the color and depth caches before each RS clear operation
45201e04c3fSmrg    * This fixes a hang on GC600. */
45301e04c3fSmrg   if (buffers & PIPE_CLEAR_DEPTHSTENCIL && buffers & PIPE_CLEAR_COLOR)
45401e04c3fSmrg      etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE,
45501e04c3fSmrg                     VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH);
45601e04c3fSmrg
45701e04c3fSmrg   if ((buffers & PIPE_CLEAR_DEPTHSTENCIL) && ctx->framebuffer_s.zsbuf != NULL)
45801e04c3fSmrg      etna_blit_clear_zs_rs(pctx, ctx->framebuffer_s.zsbuf, buffers, depth, stencil);
45901e04c3fSmrg
46001e04c3fSmrg   etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE);
4617ec681f3Smrg   mtx_unlock(&ctx->lock);
46201e04c3fSmrg}
46301e04c3fSmrg
46401e04c3fSmrgstatic bool
46501e04c3fSmrgetna_manual_blit(struct etna_resource *dst, struct etna_resource_level *dst_lev,
46601e04c3fSmrg                 unsigned int dst_offset, struct etna_resource *src,
46701e04c3fSmrg                 struct etna_resource_level *src_lev, unsigned int src_offset,
46801e04c3fSmrg                 const struct pipe_blit_info *blit_info)
46901e04c3fSmrg{
47001e04c3fSmrg   void *smap, *srow, *dmap, *drow;
47101e04c3fSmrg   size_t tile_size;
47201e04c3fSmrg
47301e04c3fSmrg   assert(src->layout == ETNA_LAYOUT_TILED);
47401e04c3fSmrg   assert(dst->layout == ETNA_LAYOUT_TILED);
47501e04c3fSmrg   assert(src->base.nr_samples == 0);
47601e04c3fSmrg   assert(dst->base.nr_samples == 0);
47701e04c3fSmrg
47801e04c3fSmrg   tile_size = util_format_get_blocksize(blit_info->src.format) * 4 * 4;
47901e04c3fSmrg
48001e04c3fSmrg   smap = etna_bo_map(src->bo);
48101e04c3fSmrg   if (!smap)
48201e04c3fSmrg      return false;
48301e04c3fSmrg
48401e04c3fSmrg   dmap = etna_bo_map(dst->bo);
48501e04c3fSmrg   if (!dmap)
48601e04c3fSmrg      return false;
48701e04c3fSmrg
48801e04c3fSmrg   srow = smap + src_offset;
48901e04c3fSmrg   drow = dmap + dst_offset;
49001e04c3fSmrg
49101e04c3fSmrg   etna_bo_cpu_prep(src->bo, DRM_ETNA_PREP_READ);
49201e04c3fSmrg   etna_bo_cpu_prep(dst->bo, DRM_ETNA_PREP_WRITE);
49301e04c3fSmrg
49401e04c3fSmrg   for (int y = 0; y < blit_info->src.box.height; y += 4) {
49501e04c3fSmrg      memcpy(drow, srow, tile_size * blit_info->src.box.width);
49601e04c3fSmrg      srow += src_lev->stride * 4;
49701e04c3fSmrg      drow += dst_lev->stride * 4;
49801e04c3fSmrg   }
49901e04c3fSmrg
50001e04c3fSmrg   etna_bo_cpu_fini(dst->bo);
50101e04c3fSmrg   etna_bo_cpu_fini(src->bo);
50201e04c3fSmrg
50301e04c3fSmrg   return true;
50401e04c3fSmrg}
50501e04c3fSmrg
50601e04c3fSmrgstatic inline size_t
50701e04c3fSmrgetna_compute_tileoffset(const struct pipe_box *box, enum pipe_format format,
50801e04c3fSmrg                        size_t stride, enum etna_surface_layout layout)
50901e04c3fSmrg{
51001e04c3fSmrg   size_t offset;
51101e04c3fSmrg   unsigned int x = box->x, y = box->y;
51201e04c3fSmrg   unsigned int blocksize = util_format_get_blocksize(format);
51301e04c3fSmrg
51401e04c3fSmrg   switch (layout) {
51501e04c3fSmrg   case ETNA_LAYOUT_LINEAR:
51601e04c3fSmrg      offset = y * stride + x * blocksize;
51701e04c3fSmrg      break;
51801e04c3fSmrg   case ETNA_LAYOUT_MULTI_TILED:
51901e04c3fSmrg      y >>= 1;
5207ec681f3Smrg      FALLTHROUGH;
52101e04c3fSmrg   case ETNA_LAYOUT_TILED:
52201e04c3fSmrg      assert(!(x & 0x03) && !(y & 0x03));
52301e04c3fSmrg      offset = (y & ~0x03) * stride + blocksize * ((x & ~0x03) << 2);
52401e04c3fSmrg      break;
52501e04c3fSmrg   case ETNA_LAYOUT_MULTI_SUPERTILED:
52601e04c3fSmrg      y >>= 1;
5277ec681f3Smrg      FALLTHROUGH;
52801e04c3fSmrg   case ETNA_LAYOUT_SUPER_TILED:
52901e04c3fSmrg      assert(!(x & 0x3f) && !(y & 0x3f));
53001e04c3fSmrg      offset = (y & ~0x3f) * stride + blocksize * ((x & ~0x3f) << 6);
53101e04c3fSmrg      break;
53201e04c3fSmrg   default:
53301e04c3fSmrg      unreachable("invalid resource layout");
53401e04c3fSmrg   }
53501e04c3fSmrg
53601e04c3fSmrg   return offset;
53701e04c3fSmrg}
53801e04c3fSmrg
53901e04c3fSmrgstatic inline void
54001e04c3fSmrgetna_get_rs_alignment_mask(const struct etna_context *ctx,
54101e04c3fSmrg                           const enum etna_surface_layout layout,
54201e04c3fSmrg                           unsigned int *width_mask, unsigned int *height_mask)
54301e04c3fSmrg{
5447ec681f3Smrg   struct etna_screen *screen = ctx->screen;
54501e04c3fSmrg   unsigned int h_align, w_align;
54601e04c3fSmrg
54701e04c3fSmrg   if (layout & ETNA_LAYOUT_BIT_SUPER) {
5487ec681f3Smrg      w_align = 64;
5497ec681f3Smrg      h_align = 64 * screen->specs.pixel_pipes;
55001e04c3fSmrg   } else {
55101e04c3fSmrg      w_align = ETNA_RS_WIDTH_MASK + 1;
55201e04c3fSmrg      h_align = ETNA_RS_HEIGHT_MASK + 1;
55301e04c3fSmrg   }
55401e04c3fSmrg
55501e04c3fSmrg   *width_mask = w_align - 1;
55601e04c3fSmrg   *height_mask = h_align -1;
55701e04c3fSmrg}
55801e04c3fSmrg
5597ec681f3Smrgstatic bool msaa_config(const struct pipe_resource *src,
5607ec681f3Smrg                        const struct pipe_resource *dst,
5617ec681f3Smrg                        int *msaa_xscale,
5627ec681f3Smrg                        int *msaa_yscale)
5637ec681f3Smrg{
5647ec681f3Smrg   int src_xscale = 1, src_yscale = 1;
5657ec681f3Smrg   int dst_xscale = 1, dst_yscale = 1;
5667ec681f3Smrg
5677ec681f3Smrg   assert(src->nr_samples <= 4);
5687ec681f3Smrg   assert(dst->nr_samples <= 4);
5697ec681f3Smrg
5707ec681f3Smrg   translate_samples_to_xyscale(src->nr_samples, &src_xscale, &src_yscale);
5717ec681f3Smrg   translate_samples_to_xyscale(dst->nr_samples, &dst_xscale, &dst_yscale);
5727ec681f3Smrg
5737ec681f3Smrg   /* RS does not support upscaling */
5747ec681f3Smrg   if ((src_xscale < dst_xscale) || (src_yscale < dst_yscale))
5757ec681f3Smrg      return false;
5767ec681f3Smrg
5777ec681f3Smrg   *msaa_xscale = src_xscale - dst_xscale + 1;
5787ec681f3Smrg   *msaa_yscale = src_yscale - dst_yscale + 1;
5797ec681f3Smrg
5807ec681f3Smrg   return true;
5817ec681f3Smrg}
5827ec681f3Smrg
58301e04c3fSmrgstatic bool
58401e04c3fSmrgetna_try_rs_blit(struct pipe_context *pctx,
58501e04c3fSmrg                 const struct pipe_blit_info *blit_info)
58601e04c3fSmrg{
58701e04c3fSmrg   struct etna_context *ctx = etna_context(pctx);
58801e04c3fSmrg   struct etna_resource *src = etna_resource(blit_info->src.resource);
58901e04c3fSmrg   struct etna_resource *dst = etna_resource(blit_info->dst.resource);
59001e04c3fSmrg   struct compiled_rs_state copy_to_screen;
59101e04c3fSmrg   int msaa_xscale = 1, msaa_yscale = 1;
59201e04c3fSmrg
59301e04c3fSmrg   /* Ensure that the level is valid */
59401e04c3fSmrg   assert(blit_info->src.level <= src->base.last_level);
59501e04c3fSmrg   assert(blit_info->dst.level <= dst->base.last_level);
59601e04c3fSmrg
5977ec681f3Smrg   if (!msaa_config(&src->base, &dst->base, &msaa_xscale, &msaa_yscale)) {
5987ec681f3Smrg      DBG("upsampling not supported");
5997ec681f3Smrg      return false;
6007ec681f3Smrg   }
60101e04c3fSmrg
60201e04c3fSmrg   /* The width/height are in pixels; they do not change as a result of
60301e04c3fSmrg    * multi-sampling. So, when blitting from a 4x multisampled surface
60401e04c3fSmrg    * to a non-multisampled surface, the width and height will be
60501e04c3fSmrg    * identical. As we do not support scaling, reject different sizes. */
60601e04c3fSmrg   if (blit_info->dst.box.width != blit_info->src.box.width ||
60701e04c3fSmrg       blit_info->dst.box.height != blit_info->src.box.height) {
60801e04c3fSmrg      DBG("scaling requested: source %dx%d destination %dx%d",
60901e04c3fSmrg          blit_info->src.box.width, blit_info->src.box.height,
61001e04c3fSmrg          blit_info->dst.box.width, blit_info->dst.box.height);
6117ec681f3Smrg      return false;
61201e04c3fSmrg   }
61301e04c3fSmrg
61401e04c3fSmrg   /* No masks - RS can't copy specific channels */
61501e04c3fSmrg   unsigned mask = util_format_get_mask(blit_info->dst.format);
61601e04c3fSmrg   if ((blit_info->mask & mask) != mask) {
61701e04c3fSmrg      DBG("sub-mask requested: 0x%02x vs format mask 0x%02x", blit_info->mask, mask);
6187ec681f3Smrg      return false;
61901e04c3fSmrg   }
62001e04c3fSmrg
6217ec681f3Smrg   /* Only support same format (used tiling/detiling) blits for now.
6227ec681f3Smrg    * TODO: figure out which different-format blits are possible and test them
6237ec681f3Smrg    *  - fail if swizzle needed
6247ec681f3Smrg    *  - avoid trying to convert between float/int formats?
6257ec681f3Smrg    */
6267ec681f3Smrg   if (blit_info->src.format != blit_info->dst.format)
6277ec681f3Smrg      return false;
6287ec681f3Smrg
6297ec681f3Smrg   uint32_t format = etna_compatible_rs_format(blit_info->dst.format);
6307ec681f3Smrg   if (format == ETNA_NO_MATCH)
6317ec681f3Smrg      return false;
6327ec681f3Smrg
6337ec681f3Smrg   if (blit_info->scissor_enable ||
63401e04c3fSmrg       blit_info->dst.box.depth != blit_info->src.box.depth ||
63501e04c3fSmrg       blit_info->dst.box.depth != 1) {
6367ec681f3Smrg      return false;
63701e04c3fSmrg   }
63801e04c3fSmrg
63901e04c3fSmrg   unsigned w_mask, h_mask;
64001e04c3fSmrg
64101e04c3fSmrg   etna_get_rs_alignment_mask(ctx, src->layout, &w_mask, &h_mask);
64201e04c3fSmrg   if ((blit_info->src.box.x & w_mask) || (blit_info->src.box.y & h_mask))
6437ec681f3Smrg      return false;
64401e04c3fSmrg
64501e04c3fSmrg   etna_get_rs_alignment_mask(ctx, dst->layout, &w_mask, &h_mask);
64601e04c3fSmrg   if ((blit_info->dst.box.x & w_mask) || (blit_info->dst.box.y & h_mask))
6477ec681f3Smrg      return false;
64801e04c3fSmrg
64901e04c3fSmrg   struct etna_resource_level *src_lev = &src->levels[blit_info->src.level];
65001e04c3fSmrg   struct etna_resource_level *dst_lev = &dst->levels[blit_info->dst.level];
65101e04c3fSmrg
65201e04c3fSmrg   /* we may be given coordinates up to the padded width to avoid
65301e04c3fSmrg    * any alignment issues with different tiling formats */
65401e04c3fSmrg   assert((blit_info->src.box.x + blit_info->src.box.width) * msaa_xscale <= src_lev->padded_width);
65501e04c3fSmrg   assert((blit_info->src.box.y + blit_info->src.box.height) * msaa_yscale <= src_lev->padded_height);
65601e04c3fSmrg   assert(blit_info->dst.box.x + blit_info->dst.box.width <= dst_lev->padded_width);
65701e04c3fSmrg   assert(blit_info->dst.box.y + blit_info->dst.box.height <= dst_lev->padded_height);
65801e04c3fSmrg
65901e04c3fSmrg   unsigned src_offset = src_lev->offset +
66001e04c3fSmrg                         blit_info->src.box.z * src_lev->layer_stride +
66101e04c3fSmrg                         etna_compute_tileoffset(&blit_info->src.box,
66201e04c3fSmrg                                                 blit_info->src.format,
66301e04c3fSmrg                                                 src_lev->stride,
66401e04c3fSmrg                                                 src->layout);
66501e04c3fSmrg   unsigned dst_offset = dst_lev->offset +
66601e04c3fSmrg                         blit_info->dst.box.z * dst_lev->layer_stride +
66701e04c3fSmrg                         etna_compute_tileoffset(&blit_info->dst.box,
66801e04c3fSmrg                                                 blit_info->dst.format,
66901e04c3fSmrg                                                 dst_lev->stride,
67001e04c3fSmrg                                                 dst->layout);
67101e04c3fSmrg
67201e04c3fSmrg   if (src_lev->padded_width <= ETNA_RS_WIDTH_MASK ||
67301e04c3fSmrg       dst_lev->padded_width <= ETNA_RS_WIDTH_MASK ||
67401e04c3fSmrg       src_lev->padded_height <= ETNA_RS_HEIGHT_MASK ||
67501e04c3fSmrg       dst_lev->padded_height <= ETNA_RS_HEIGHT_MASK)
67601e04c3fSmrg      goto manual;
67701e04c3fSmrg
67801e04c3fSmrg   /* If the width is not aligned to the RS width, but is within our
67901e04c3fSmrg    * padding, adjust the width to suite the RS width restriction.
68001e04c3fSmrg    * Note: the RS width/height are converted to source samples here. */
68101e04c3fSmrg   unsigned int width = blit_info->src.box.width * msaa_xscale;
68201e04c3fSmrg   unsigned int height = blit_info->src.box.height * msaa_yscale;
68301e04c3fSmrg   unsigned int w_align = ETNA_RS_WIDTH_MASK + 1;
6847ec681f3Smrg   unsigned int h_align = ETNA_RS_HEIGHT_MASK + 1;
68501e04c3fSmrg
68601e04c3fSmrg   if (width & (w_align - 1) && width >= src_lev->width * msaa_xscale && width >= dst_lev->width)
68701e04c3fSmrg      width = align(width, w_align);
68801e04c3fSmrg
68901e04c3fSmrg   if (height & (h_align - 1) && height >= src_lev->height * msaa_yscale && height >= dst_lev->height)
69001e04c3fSmrg      height = align(height, h_align);
69101e04c3fSmrg
69201e04c3fSmrg   /* The padded dimensions are in samples */
69301e04c3fSmrg   if (width > src_lev->padded_width ||
69401e04c3fSmrg       width > dst_lev->padded_width * msaa_xscale ||
69501e04c3fSmrg       height > src_lev->padded_height ||
69601e04c3fSmrg       height > dst_lev->padded_height * msaa_yscale ||
69701e04c3fSmrg       width & (w_align - 1) || height & (h_align - 1))
69801e04c3fSmrg      goto manual;
69901e04c3fSmrg
7007ec681f3Smrg   mtx_lock(&ctx->lock);
70101e04c3fSmrg
70201e04c3fSmrg   /* Always flush color and depth cache together before resolving. This works
70301e04c3fSmrg    * around artifacts that appear in some cases when scanning out a texture
70401e04c3fSmrg    * directly after it has been rendered to, such as rendering an animated web
70501e04c3fSmrg    * page in a QtWebEngine based WebView on GC2000. The artifacts look like
70601e04c3fSmrg    * the texture sampler samples zeroes instead of texture data in a small,
70701e04c3fSmrg    * irregular triangle in the lower right of each browser tile quad. Other
70801e04c3fSmrg    * attempts to avoid these artifacts, including a pipeline stall before the
70901e04c3fSmrg    * color flush or a TS cache flush afterwards, or flushing multiple times,
71001e04c3fSmrg    * with stalls before and after each flush, have shown no effect. */
71101e04c3fSmrg   if (src->base.bind & PIPE_BIND_RENDER_TARGET ||
71201e04c3fSmrg       src->base.bind & PIPE_BIND_DEPTH_STENCIL) {
71301e04c3fSmrg      etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE,
71401e04c3fSmrg		     VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH);
71501e04c3fSmrg      etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE);
71601e04c3fSmrg
7177ec681f3Smrg      if (src_lev->ts_size && src_lev->ts_valid)
71801e04c3fSmrg         etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, VIVS_TS_FLUSH_CACHE_FLUSH);
71901e04c3fSmrg   }
72001e04c3fSmrg
72101e04c3fSmrg   /* Set up color TS to source surface before blit, if needed */
72201e04c3fSmrg   bool source_ts_valid = false;
7237ec681f3Smrg   if (src_lev->ts_size && src_lev->ts_valid) {
72401e04c3fSmrg      struct etna_reloc reloc;
72501e04c3fSmrg      unsigned ts_offset =
72601e04c3fSmrg         src_lev->ts_offset + blit_info->src.box.z * src_lev->ts_layer_stride;
7277ec681f3Smrg      uint32_t ts_mem_config = 0;
7287ec681f3Smrg
7297ec681f3Smrg      if (src_lev->ts_compress_fmt >= 0) {
7307ec681f3Smrg         ts_mem_config |= VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION |
7317ec681f3Smrg                          VIVS_TS_MEM_CONFIG_COLOR_COMPRESSION_FORMAT(src_lev->ts_compress_fmt);
7327ec681f3Smrg      }
73301e04c3fSmrg
73401e04c3fSmrg      etna_set_state(ctx->stream, VIVS_TS_MEM_CONFIG,
73501e04c3fSmrg                     VIVS_TS_MEM_CONFIG_COLOR_FAST_CLEAR | ts_mem_config);
73601e04c3fSmrg
73701e04c3fSmrg      memset(&reloc, 0, sizeof(struct etna_reloc));
73801e04c3fSmrg      reloc.bo = src->ts_bo;
73901e04c3fSmrg      reloc.offset = ts_offset;
74001e04c3fSmrg      reloc.flags = ETNA_RELOC_READ;
74101e04c3fSmrg      etna_set_state_reloc(ctx->stream, VIVS_TS_COLOR_STATUS_BASE, &reloc);
74201e04c3fSmrg
74301e04c3fSmrg      memset(&reloc, 0, sizeof(struct etna_reloc));
74401e04c3fSmrg      reloc.bo = src->bo;
74501e04c3fSmrg      reloc.offset = src_lev->offset +
74601e04c3fSmrg                     blit_info->src.box.z * src_lev->layer_stride;
74701e04c3fSmrg      reloc.flags = ETNA_RELOC_READ;
74801e04c3fSmrg      etna_set_state_reloc(ctx->stream, VIVS_TS_COLOR_SURFACE_BASE, &reloc);
74901e04c3fSmrg
7507ec681f3Smrg      etna_set_state(ctx->stream, VIVS_TS_COLOR_CLEAR_VALUE, src_lev->clear_value);
7517ec681f3Smrg      etna_set_state(ctx->stream, VIVS_TS_COLOR_CLEAR_VALUE_EXT, src_lev->clear_value >> 32);
75201e04c3fSmrg
75301e04c3fSmrg      source_ts_valid = true;
75401e04c3fSmrg   } else {
7557ec681f3Smrg      etna_set_state(ctx->stream, VIVS_TS_MEM_CONFIG, 0);
75601e04c3fSmrg   }
75701e04c3fSmrg   ctx->dirty |= ETNA_DIRTY_TS;
75801e04c3fSmrg
75901e04c3fSmrg   /* Kick off RS here */
76001e04c3fSmrg   etna_compile_rs_state(ctx, &copy_to_screen, &(struct rs_state) {
7617ec681f3Smrg      .source_format = format,
76201e04c3fSmrg      .source_tiling = src->layout,
76301e04c3fSmrg      .source = src->bo,
76401e04c3fSmrg      .source_offset = src_offset,
76501e04c3fSmrg      .source_stride = src_lev->stride,
76601e04c3fSmrg      .source_padded_width = src_lev->padded_width,
76701e04c3fSmrg      .source_padded_height = src_lev->padded_height,
76801e04c3fSmrg      .source_ts_valid = source_ts_valid,
7697ec681f3Smrg      .source_ts_compressed = src_lev->ts_compress_fmt >= 0,
7707ec681f3Smrg      .dest_format = format,
77101e04c3fSmrg      .dest_tiling = dst->layout,
77201e04c3fSmrg      .dest = dst->bo,
77301e04c3fSmrg      .dest_offset = dst_offset,
77401e04c3fSmrg      .dest_stride = dst_lev->stride,
77501e04c3fSmrg      .dest_padded_height = dst_lev->padded_height,
77601e04c3fSmrg      .downsample_x = msaa_xscale > 1,
77701e04c3fSmrg      .downsample_y = msaa_yscale > 1,
77801e04c3fSmrg      .swap_rb = translate_rb_src_dst_swap(src->base.format, dst->base.format),
77901e04c3fSmrg      .dither = {0xffffffff, 0xffffffff}, // XXX dither when going from 24 to 16 bit?
78001e04c3fSmrg      .clear_mode = VIVS_RS_CLEAR_CONTROL_MODE_DISABLED,
78101e04c3fSmrg      .width = width,
78201e04c3fSmrg      .height = height,
78301e04c3fSmrg      .tile_count = src_lev->layer_stride / 64
78401e04c3fSmrg   });
78501e04c3fSmrg
78601e04c3fSmrg   etna_submit_rs_state(ctx, &copy_to_screen);
7879f464c52Smaya   resource_read(ctx, &src->base);
78801e04c3fSmrg   resource_written(ctx, &dst->base);
78901e04c3fSmrg   dst->seqno++;
7907ec681f3Smrg   dst_lev->ts_valid = false;
79101e04c3fSmrg   ctx->dirty |= ETNA_DIRTY_DERIVE_TS;
7927ec681f3Smrg   mtx_unlock(&ctx->lock);
79301e04c3fSmrg
7947ec681f3Smrg   return true;
79501e04c3fSmrg
79601e04c3fSmrgmanual:
79701e04c3fSmrg   if (src->layout == ETNA_LAYOUT_TILED && dst->layout == ETNA_LAYOUT_TILED) {
79801e04c3fSmrg      if ((src->status & ETNA_PENDING_WRITE) ||
79901e04c3fSmrg          (dst->status & ETNA_PENDING_WRITE))
80001e04c3fSmrg         pctx->flush(pctx, NULL, 0);
80101e04c3fSmrg      return etna_manual_blit(dst, dst_lev, dst_offset, src, src_lev, src_offset, blit_info);
80201e04c3fSmrg   }
80301e04c3fSmrg
8047ec681f3Smrg   return false;
80501e04c3fSmrg}
80601e04c3fSmrg
8077ec681f3Smrgstatic bool
80801e04c3fSmrgetna_blit_rs(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
80901e04c3fSmrg{
81001e04c3fSmrg   /* This is a more extended version of resource_copy_region */
81101e04c3fSmrg   /* TODO Some cases can be handled by RS; if not, fall back to rendering or
81201e04c3fSmrg    * even CPU copy block of pixels from info->src to info->dst
81301e04c3fSmrg    * (resource, level, box, format);
81401e04c3fSmrg    * function is used for scaling, flipping in x and y direction (negative
81501e04c3fSmrg    * width/height), format conversion, mask and filter and even a scissor rectangle
81601e04c3fSmrg    *
81701e04c3fSmrg    * What can the RS do for us:
81801e04c3fSmrg    *   convert between tiling formats (layouts)
81901e04c3fSmrg    *   downsample 2x in x and y
82001e04c3fSmrg    *   convert between a limited number of pixel formats
82101e04c3fSmrg    *
82201e04c3fSmrg    * For the rest, fall back to util_blitter
82301e04c3fSmrg    * XXX this goes wrong when source surface is supertiled. */
82401e04c3fSmrg
8257ec681f3Smrg   if (blit_info->src.resource->nr_samples > 1 &&
8267ec681f3Smrg       blit_info->dst.resource->nr_samples <= 1 &&
8277ec681f3Smrg       !util_format_is_depth_or_stencil(blit_info->src.resource->format) &&
8287ec681f3Smrg       !util_format_is_pure_integer(blit_info->src.resource->format)) {
82901e04c3fSmrg      DBG("color resolve unimplemented");
8307ec681f3Smrg      return false;
83101e04c3fSmrg   }
83201e04c3fSmrg
8337ec681f3Smrg   return etna_try_rs_blit(pctx, blit_info);
83401e04c3fSmrg}
83501e04c3fSmrg
83601e04c3fSmrgvoid
83701e04c3fSmrgetna_clear_blit_rs_init(struct pipe_context *pctx)
83801e04c3fSmrg{
8397ec681f3Smrg   struct etna_context *ctx = etna_context(pctx);
8407ec681f3Smrg
84101e04c3fSmrg   DBG("etnaviv: Using RS blit engine");
84201e04c3fSmrg   pctx->clear = etna_clear_rs;
8437ec681f3Smrg   ctx->blit = etna_blit_rs;
84401e04c3fSmrg}
845