1b8e80941Smrg/*
2b8e80941Smrg * Copyright (c) 2017 Etnaviv Project
3b8e80941Smrg * Copyright (C) 2017 Zodiac Inflight Innovations
4b8e80941Smrg *
5b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
7b8e80941Smrg * to deal in the Software without restriction, including without limitation
8b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sub license,
9b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
10b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
11b8e80941Smrg *
12b8e80941Smrg * The above copyright notice and this permission notice (including the
13b8e80941Smrg * next paragraph) shall be included in all copies or substantial portions
14b8e80941Smrg * of the Software.
15b8e80941Smrg *
16b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22b8e80941Smrg * DEALINGS IN THE SOFTWARE.
23b8e80941Smrg *
24b8e80941Smrg * Authors:
25b8e80941Smrg *    Wladimir J. van der Laan <laanwj@gmail.com>
26b8e80941Smrg */
27b8e80941Smrg#include "etnaviv_blt.h"
28b8e80941Smrg
29b8e80941Smrg#include "etnaviv_emit.h"
30b8e80941Smrg#include "etnaviv_clear_blit.h"
31b8e80941Smrg#include "etnaviv_context.h"
32b8e80941Smrg#include "etnaviv_emit.h"
33b8e80941Smrg#include "etnaviv_format.h"
34b8e80941Smrg#include "etnaviv_resource.h"
35b8e80941Smrg#include "etnaviv_surface.h"
36b8e80941Smrg#include "etnaviv_translate.h"
37b8e80941Smrg
38b8e80941Smrg#include "util/u_math.h"
39b8e80941Smrg#include "pipe/p_defines.h"
40b8e80941Smrg#include "pipe/p_state.h"
41b8e80941Smrg#include "util/u_blitter.h"
42b8e80941Smrg#include "util/u_inlines.h"
43b8e80941Smrg#include "util/u_memory.h"
44b8e80941Smrg#include "util/u_surface.h"
45b8e80941Smrg
46b8e80941Smrg#include "hw/common_3d.xml.h"
47b8e80941Smrg#include "hw/state_blt.xml.h"
48b8e80941Smrg#include "hw/common.xml.h"
49b8e80941Smrg
50b8e80941Smrg#include <assert.h>
51b8e80941Smrg
52b8e80941Smrg/* Currently, used BLT formats overlap 100% with RS formats */
53b8e80941Smrg#define translate_blt_format translate_rs_format
54b8e80941Smrg
55b8e80941Smrgstatic inline uint32_t
56b8e80941Smrgblt_compute_stride_bits(const struct blt_imginfo *img)
57b8e80941Smrg{
58b8e80941Smrg   return VIVS_BLT_DEST_STRIDE_TILING(img->tiling == ETNA_LAYOUT_LINEAR ? 0 : 3) | /* 1/3? */
59b8e80941Smrg          VIVS_BLT_DEST_STRIDE_FORMAT(img->format) |
60b8e80941Smrg          VIVS_BLT_DEST_STRIDE_STRIDE(img->stride);
61b8e80941Smrg}
62b8e80941Smrg
63b8e80941Smrgstatic inline uint32_t
64b8e80941Smrgblt_compute_img_config_bits(const struct blt_imginfo *img, bool for_dest)
65b8e80941Smrg{
66b8e80941Smrg   uint32_t tiling_bits = 0;
67b8e80941Smrg   if (img->tiling == ETNA_LAYOUT_SUPER_TILED) {
68b8e80941Smrg      tiling_bits |= for_dest ? BLT_IMAGE_CONFIG_TO_SUPER_TILED : BLT_IMAGE_CONFIG_FROM_SUPER_TILED;
69b8e80941Smrg   }
70b8e80941Smrg
71b8e80941Smrg   return BLT_IMAGE_CONFIG_CACHE_MODE(img->cache_mode) |
72b8e80941Smrg          COND(img->use_ts, BLT_IMAGE_CONFIG_TS) |
73b8e80941Smrg          COND(img->compressed, BLT_IMAGE_CONFIG_COMPRESSION) |
74b8e80941Smrg          BLT_IMAGE_CONFIG_COMPRESSION_FORMAT(img->compress_fmt) |
75b8e80941Smrg          COND(for_dest, BLT_IMAGE_CONFIG_UNK22) |
76b8e80941Smrg          BLT_IMAGE_CONFIG_SWIZ_R(0) | /* not used? */
77b8e80941Smrg          BLT_IMAGE_CONFIG_SWIZ_G(1) |
78b8e80941Smrg          BLT_IMAGE_CONFIG_SWIZ_B(2) |
79b8e80941Smrg          BLT_IMAGE_CONFIG_SWIZ_A(3) |
80b8e80941Smrg          tiling_bits;
81b8e80941Smrg}
82b8e80941Smrg
83b8e80941Smrgstatic inline uint32_t
84b8e80941Smrgblt_compute_swizzle_bits(const struct blt_imginfo *img, bool for_dest)
85b8e80941Smrg{
86b8e80941Smrg   uint32_t swiz = VIVS_BLT_SWIZZLE_SRC_R(img->swizzle[0]) |
87b8e80941Smrg                   VIVS_BLT_SWIZZLE_SRC_G(img->swizzle[1]) |
88b8e80941Smrg                   VIVS_BLT_SWIZZLE_SRC_B(img->swizzle[2]) |
89b8e80941Smrg                   VIVS_BLT_SWIZZLE_SRC_A(img->swizzle[3]);
90b8e80941Smrg   return for_dest ? (swiz << 12) : swiz;
91b8e80941Smrg}
92b8e80941Smrg
93b8e80941Smrg/* Clear (part of) an image */
94b8e80941Smrgstatic void
95b8e80941Smrgemit_blt_clearimage(struct etna_cmd_stream *stream, const struct blt_clear_op *op)
96b8e80941Smrg{
97b8e80941Smrg   etna_cmd_stream_reserve(stream, 64*2); /* Make sure BLT op doesn't get broken up */
98b8e80941Smrg
99b8e80941Smrg   etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001);
100b8e80941Smrg   assert(op->dest.bpp);
101b8e80941Smrg   etna_set_state(stream, VIVS_BLT_CONFIG, VIVS_BLT_CONFIG_CLEAR_BPP(op->dest.bpp-1));
102b8e80941Smrg   /* NB: blob sets format to 1 in dest/src config for clear, and the swizzle to RRRR.
103b8e80941Smrg    * does this matter? It seems to just be ignored. But if we run into issues with BLT
104b8e80941Smrg    * behaving stragely, it's something to look at.
105b8e80941Smrg    */
106b8e80941Smrg   etna_set_state(stream, VIVS_BLT_DEST_STRIDE, blt_compute_stride_bits(&op->dest));
107b8e80941Smrg   etna_set_state(stream, VIVS_BLT_DEST_CONFIG, blt_compute_img_config_bits(&op->dest, true));
108b8e80941Smrg   etna_set_state_reloc(stream, VIVS_BLT_DEST_ADDR, &op->dest.addr);
109b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SRC_STRIDE, blt_compute_stride_bits(&op->dest));
110b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SRC_CONFIG, blt_compute_img_config_bits(&op->dest, false));
111b8e80941Smrg   etna_set_state_reloc(stream, VIVS_BLT_SRC_ADDR, &op->dest.addr);
112b8e80941Smrg   etna_set_state(stream, VIVS_BLT_DEST_POS, VIVS_BLT_DEST_POS_X(op->rect_x) | VIVS_BLT_DEST_POS_Y(op->rect_y));
113b8e80941Smrg   etna_set_state(stream, VIVS_BLT_IMAGE_SIZE, VIVS_BLT_IMAGE_SIZE_WIDTH(op->rect_w) | VIVS_BLT_IMAGE_SIZE_HEIGHT(op->rect_h));
114b8e80941Smrg   etna_set_state(stream, VIVS_BLT_CLEAR_COLOR0, op->clear_value[0]);
115b8e80941Smrg   etna_set_state(stream, VIVS_BLT_CLEAR_COLOR1, op->clear_value[1]);
116b8e80941Smrg   etna_set_state(stream, VIVS_BLT_CLEAR_BITS0, op->clear_bits[0]);
117b8e80941Smrg   etna_set_state(stream, VIVS_BLT_CLEAR_BITS1, op->clear_bits[1]);
118b8e80941Smrg   if (op->dest.use_ts) {
119b8e80941Smrg      etna_set_state_reloc(stream, VIVS_BLT_DEST_TS, &op->dest.ts_addr);
120b8e80941Smrg      etna_set_state_reloc(stream, VIVS_BLT_SRC_TS, &op->dest.ts_addr);
121b8e80941Smrg      etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE0, op->dest.ts_clear_value[0]);
122b8e80941Smrg      etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE1, op->dest.ts_clear_value[1]);
123b8e80941Smrg      etna_set_state(stream, VIVS_BLT_SRC_TS_CLEAR_VALUE0, op->dest.ts_clear_value[0]);
124b8e80941Smrg      etna_set_state(stream, VIVS_BLT_SRC_TS_CLEAR_VALUE1, op->dest.ts_clear_value[1]);
125b8e80941Smrg   }
126b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003);
127b8e80941Smrg   etna_set_state(stream, VIVS_BLT_COMMAND, VIVS_BLT_COMMAND_COMMAND_CLEAR_IMAGE);
128b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003);
129b8e80941Smrg   etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000);
130b8e80941Smrg}
131b8e80941Smrg
132b8e80941Smrg/* Copy (a subset of) an image to another image. */
133b8e80941Smrgstatic void
134b8e80941Smrgemit_blt_copyimage(struct etna_cmd_stream *stream, const struct blt_imgcopy_op *op)
135b8e80941Smrg{
136b8e80941Smrg   etna_cmd_stream_reserve(stream, 64*2); /* Never allow BLT sequences to be broken up */
137b8e80941Smrg
138b8e80941Smrg   etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001);
139b8e80941Smrg   etna_set_state(stream, VIVS_BLT_CONFIG,
140b8e80941Smrg           VIVS_BLT_CONFIG_SRC_ENDIAN(op->src.endian_mode) |
141b8e80941Smrg           VIVS_BLT_CONFIG_DEST_ENDIAN(op->dest.endian_mode));
142b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SRC_STRIDE, blt_compute_stride_bits(&op->src));
143b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SRC_CONFIG, blt_compute_img_config_bits(&op->src, false));
144b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SWIZZLE,
145b8e80941Smrg           blt_compute_swizzle_bits(&op->src, false) |
146b8e80941Smrg           blt_compute_swizzle_bits(&op->dest, true));
147b8e80941Smrg   etna_set_state(stream, VIVS_BLT_UNK140A0, 0x00040004);
148b8e80941Smrg   etna_set_state(stream, VIVS_BLT_UNK1409C, 0x00400040);
149b8e80941Smrg   if (op->src.use_ts) {
150b8e80941Smrg      etna_set_state_reloc(stream, VIVS_BLT_SRC_TS, &op->src.ts_addr);
151b8e80941Smrg      etna_set_state(stream, VIVS_BLT_SRC_TS_CLEAR_VALUE0, op->src.ts_clear_value[0]);
152b8e80941Smrg      etna_set_state(stream, VIVS_BLT_SRC_TS_CLEAR_VALUE1, op->src.ts_clear_value[1]);
153b8e80941Smrg   }
154b8e80941Smrg   etna_set_state_reloc(stream, VIVS_BLT_SRC_ADDR, &op->src.addr);
155b8e80941Smrg   etna_set_state(stream, VIVS_BLT_DEST_STRIDE, blt_compute_stride_bits(&op->dest));
156b8e80941Smrg   etna_set_state(stream, VIVS_BLT_DEST_CONFIG,
157b8e80941Smrg         blt_compute_img_config_bits(&op->dest, true) |
158b8e80941Smrg         COND(op->flip_y, BLT_IMAGE_CONFIG_FLIP_Y));
159b8e80941Smrg   assert(!op->dest.use_ts); /* Dest TS path doesn't work for copies? */
160b8e80941Smrg   if (op->dest.use_ts) {
161b8e80941Smrg      etna_set_state_reloc(stream, VIVS_BLT_DEST_TS, &op->dest.ts_addr);
162b8e80941Smrg      etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE0, op->dest.ts_clear_value[0]);
163b8e80941Smrg      etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE1, op->dest.ts_clear_value[1]);
164b8e80941Smrg   }
165b8e80941Smrg   etna_set_state_reloc(stream, VIVS_BLT_DEST_ADDR, &op->dest.addr);
166b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SRC_POS, VIVS_BLT_DEST_POS_X(op->src_x) | VIVS_BLT_DEST_POS_Y(op->src_y));
167b8e80941Smrg   etna_set_state(stream, VIVS_BLT_DEST_POS, VIVS_BLT_DEST_POS_X(op->dest_x) | VIVS_BLT_DEST_POS_Y(op->dest_y));
168b8e80941Smrg   etna_set_state(stream, VIVS_BLT_IMAGE_SIZE, VIVS_BLT_IMAGE_SIZE_WIDTH(op->rect_w) | VIVS_BLT_IMAGE_SIZE_HEIGHT(op->rect_h));
169b8e80941Smrg   etna_set_state(stream, VIVS_BLT_UNK14058, 0xffffffff);
170b8e80941Smrg   etna_set_state(stream, VIVS_BLT_UNK1405C, 0xffffffff);
171b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003);
172b8e80941Smrg   etna_set_state(stream, VIVS_BLT_COMMAND, VIVS_BLT_COMMAND_COMMAND_COPY_IMAGE);
173b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003);
174b8e80941Smrg   etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000);
175b8e80941Smrg}
176b8e80941Smrg
177b8e80941Smrg/* Emit in-place resolve using BLT. */
178b8e80941Smrgstatic void
179b8e80941Smrgemit_blt_inplace(struct etna_cmd_stream *stream, const struct blt_inplace_op *op)
180b8e80941Smrg{
181b8e80941Smrg   assert(op->bpp > 0 && util_is_power_of_two_nonzero(op->bpp));
182b8e80941Smrg   etna_cmd_stream_reserve(stream, 64*2); /* Never allow BLT sequences to be broken up */
183b8e80941Smrg   etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000001);
184b8e80941Smrg   etna_set_state(stream, VIVS_BLT_CONFIG,
185b8e80941Smrg         VIVS_BLT_CONFIG_INPLACE_CACHE_MODE(op->cache_mode) |
186b8e80941Smrg         VIVS_BLT_CONFIG_INPLACE_BOTH |
187b8e80941Smrg         (util_logbase2(op->bpp) << VIVS_BLT_CONFIG_INPLACE_BPP__SHIFT));
188b8e80941Smrg   etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE0, op->ts_clear_value[0]);
189b8e80941Smrg   etna_set_state(stream, VIVS_BLT_DEST_TS_CLEAR_VALUE1, op->ts_clear_value[1]);
190b8e80941Smrg   etna_set_state_reloc(stream, VIVS_BLT_DEST_ADDR, &op->addr);
191b8e80941Smrg   etna_set_state_reloc(stream, VIVS_BLT_DEST_TS, &op->ts_addr);
192b8e80941Smrg   etna_set_state(stream, 0x14068, op->num_tiles);
193b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003);
194b8e80941Smrg   etna_set_state(stream, VIVS_BLT_COMMAND, 0x00000004);
195b8e80941Smrg   etna_set_state(stream, VIVS_BLT_SET_COMMAND, 0x00000003);
196b8e80941Smrg   etna_set_state(stream, VIVS_BLT_ENABLE, 0x00000000);
197b8e80941Smrg}
198b8e80941Smrg
199b8e80941Smrgstatic void
200b8e80941Smrgetna_blit_clear_color_blt(struct pipe_context *pctx, struct pipe_surface *dst,
201b8e80941Smrg                      const union pipe_color_union *color)
202b8e80941Smrg{
203b8e80941Smrg   struct etna_context *ctx = etna_context(pctx);
204b8e80941Smrg   struct etna_surface *surf = etna_surface(dst);
205b8e80941Smrg   uint32_t new_clear_value = etna_clear_blit_pack_rgba(surf->base.format, color->f);
206b8e80941Smrg
207b8e80941Smrg   struct etna_resource *res = etna_resource(surf->base.texture);
208b8e80941Smrg   struct blt_clear_op clr = {};
209b8e80941Smrg   clr.dest.addr.bo = res->bo;
210b8e80941Smrg   clr.dest.addr.offset = surf->surf.offset;
211b8e80941Smrg   clr.dest.addr.flags = ETNA_RELOC_WRITE;
212b8e80941Smrg   clr.dest.bpp = util_format_get_blocksize(surf->base.format);
213b8e80941Smrg   clr.dest.stride = surf->surf.stride;
214b8e80941Smrg   /* TODO: color compression
215b8e80941Smrg   clr.dest.compressed = 1;
216b8e80941Smrg   clr.dest.compress_fmt = 3;
217b8e80941Smrg   */
218b8e80941Smrg   clr.dest.tiling = res->layout;
219b8e80941Smrg   clr.dest.cache_mode = TS_CACHE_MODE_128; /* TODO: cache modes */
220b8e80941Smrg
221b8e80941Smrg   if (surf->surf.ts_size) {
222b8e80941Smrg      clr.dest.use_ts = 1;
223b8e80941Smrg      clr.dest.ts_addr.bo = res->ts_bo;
224b8e80941Smrg      clr.dest.ts_addr.offset = 0;
225b8e80941Smrg      clr.dest.ts_addr.flags = ETNA_RELOC_WRITE;
226b8e80941Smrg      clr.dest.ts_clear_value[0] = new_clear_value;
227b8e80941Smrg      clr.dest.ts_clear_value[1] = new_clear_value;
228b8e80941Smrg   }
229b8e80941Smrg
230b8e80941Smrg   clr.clear_value[0] = new_clear_value;
231b8e80941Smrg   clr.clear_value[1] = new_clear_value;
232b8e80941Smrg   clr.clear_bits[0] = 0xffffffff; /* TODO: Might want to clear only specific channels? */
233b8e80941Smrg   clr.clear_bits[1] = 0xffffffff;
234b8e80941Smrg   clr.rect_x = 0; /* What about scissors? */
235b8e80941Smrg   clr.rect_y = 0;
236b8e80941Smrg   clr.rect_w = surf->surf.width;
237b8e80941Smrg   clr.rect_h = surf->surf.height;
238b8e80941Smrg
239b8e80941Smrg   emit_blt_clearimage(ctx->stream, &clr);
240b8e80941Smrg
241b8e80941Smrg   /* This made the TS valid */
242b8e80941Smrg   if (surf->surf.ts_size) {
243b8e80941Smrg      ctx->framebuffer.TS_COLOR_CLEAR_VALUE = new_clear_value;
244b8e80941Smrg      surf->level->ts_valid = true;
245b8e80941Smrg   }
246b8e80941Smrg
247b8e80941Smrg   surf->level->clear_value = new_clear_value;
248b8e80941Smrg   resource_written(ctx, surf->base.texture);
249b8e80941Smrg   etna_resource(surf->base.texture)->seqno++;
250b8e80941Smrg}
251b8e80941Smrg
252b8e80941Smrgstatic void
253b8e80941Smrgetna_blit_clear_zs_blt(struct pipe_context *pctx, struct pipe_surface *dst,
254b8e80941Smrg                   unsigned buffers, double depth, unsigned stencil)
255b8e80941Smrg{
256b8e80941Smrg   struct etna_context *ctx = etna_context(pctx);
257b8e80941Smrg   struct etna_surface *surf = etna_surface(dst);
258b8e80941Smrg   uint32_t new_clear_value = translate_clear_depth_stencil(surf->base.format, depth, stencil);
259b8e80941Smrg   uint32_t new_clear_bits = 0, clear_bits_depth, clear_bits_stencil;
260b8e80941Smrg
261b8e80941Smrg   /* Get the channels to clear */
262b8e80941Smrg   switch (surf->base.format) {
263b8e80941Smrg   case PIPE_FORMAT_Z16_UNORM:
264b8e80941Smrg      clear_bits_depth = 0xffffffff;
265b8e80941Smrg      clear_bits_stencil = 0x00000000;
266b8e80941Smrg      break;
267b8e80941Smrg   case PIPE_FORMAT_X8Z24_UNORM:
268b8e80941Smrg   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
269b8e80941Smrg      clear_bits_depth = 0xffffff00;
270b8e80941Smrg      clear_bits_stencil = 0x000000ff;
271b8e80941Smrg      break;
272b8e80941Smrg   default:
273b8e80941Smrg      clear_bits_depth = clear_bits_stencil = 0xffffffff;
274b8e80941Smrg      break;
275b8e80941Smrg   }
276b8e80941Smrg
277b8e80941Smrg   if (buffers & PIPE_CLEAR_DEPTH)
278b8e80941Smrg      new_clear_bits |= clear_bits_depth;
279b8e80941Smrg   if (buffers & PIPE_CLEAR_STENCIL)
280b8e80941Smrg      new_clear_bits |= clear_bits_stencil;
281b8e80941Smrg
282b8e80941Smrg   /* TODO unduplicate this */
283b8e80941Smrg   struct etna_resource *res = etna_resource(surf->base.texture);
284b8e80941Smrg   struct blt_clear_op clr = {};
285b8e80941Smrg   clr.dest.addr.bo = res->bo;
286b8e80941Smrg   clr.dest.addr.offset = surf->surf.offset;
287b8e80941Smrg   clr.dest.addr.flags = ETNA_RELOC_WRITE;
288b8e80941Smrg   clr.dest.bpp = util_format_get_blocksize(surf->base.format);
289b8e80941Smrg   clr.dest.stride = surf->surf.stride;
290b8e80941Smrg#if 0 /* TODO depth compression */
291b8e80941Smrg   clr.dest.compressed = 1;
292b8e80941Smrg   clr.dest.compress_fmt = COLOR_COMPRESSION_FORMAT_D24S8;
293b8e80941Smrg#endif
294b8e80941Smrg   clr.dest.tiling = res->layout;
295b8e80941Smrg   clr.dest.cache_mode = TS_CACHE_MODE_128; /* TODO: cache modes */
296b8e80941Smrg
297b8e80941Smrg   if (surf->surf.ts_size) {
298b8e80941Smrg      clr.dest.use_ts = 1;
299b8e80941Smrg      clr.dest.ts_addr.bo = res->ts_bo;
300b8e80941Smrg      clr.dest.ts_addr.offset = 0;
301b8e80941Smrg      clr.dest.ts_addr.flags = ETNA_RELOC_WRITE;
302b8e80941Smrg      clr.dest.ts_clear_value[0] = new_clear_value;
303b8e80941Smrg      clr.dest.ts_clear_value[1] = new_clear_value;
304b8e80941Smrg   }
305b8e80941Smrg
306b8e80941Smrg   clr.clear_value[0] = new_clear_value;
307b8e80941Smrg   clr.clear_value[1] = new_clear_value;
308b8e80941Smrg   clr.clear_bits[0] = new_clear_bits;
309b8e80941Smrg   clr.clear_bits[1] = new_clear_bits;
310b8e80941Smrg   clr.rect_x = 0; /* What about scissors? */
311b8e80941Smrg   clr.rect_y = 0;
312b8e80941Smrg   clr.rect_w = surf->surf.width;
313b8e80941Smrg   clr.rect_h = surf->surf.height;
314b8e80941Smrg
315b8e80941Smrg   emit_blt_clearimage(ctx->stream, &clr);
316b8e80941Smrg
317b8e80941Smrg   /* This made the TS valid */
318b8e80941Smrg   if (surf->surf.ts_size) {
319b8e80941Smrg      ctx->framebuffer.TS_DEPTH_CLEAR_VALUE = new_clear_value;
320b8e80941Smrg      surf->level->ts_valid = true;
321b8e80941Smrg   }
322b8e80941Smrg
323b8e80941Smrg   surf->level->clear_value = new_clear_value;
324b8e80941Smrg   resource_written(ctx, surf->base.texture);
325b8e80941Smrg   etna_resource(surf->base.texture)->seqno++;
326b8e80941Smrg}
327b8e80941Smrg
328b8e80941Smrgstatic void
329b8e80941Smrgetna_clear_blt(struct pipe_context *pctx, unsigned buffers,
330b8e80941Smrg           const union pipe_color_union *color, double depth, unsigned stencil)
331b8e80941Smrg{
332b8e80941Smrg   struct etna_context *ctx = etna_context(pctx);
333b8e80941Smrg
334b8e80941Smrg   etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23);
335b8e80941Smrg   etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, VIVS_TS_FLUSH_CACHE_FLUSH);
336b8e80941Smrg
337b8e80941Smrg   if (buffers & PIPE_CLEAR_COLOR) {
338b8e80941Smrg      for (int idx = 0; idx < ctx->framebuffer_s.nr_cbufs; ++idx) {
339b8e80941Smrg         etna_blit_clear_color_blt(pctx, ctx->framebuffer_s.cbufs[idx],
340b8e80941Smrg                               &color[idx]);
341b8e80941Smrg      }
342b8e80941Smrg   }
343b8e80941Smrg
344b8e80941Smrg   if ((buffers & PIPE_CLEAR_DEPTHSTENCIL) && ctx->framebuffer_s.zsbuf != NULL)
345b8e80941Smrg      etna_blit_clear_zs_blt(pctx, ctx->framebuffer_s.zsbuf, buffers, depth, stencil);
346b8e80941Smrg
347b8e80941Smrg   etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_BLT);
348b8e80941Smrg
349b8e80941Smrg   if ((buffers & PIPE_CLEAR_COLOR) && (buffers & PIPE_CLEAR_DEPTH))
350b8e80941Smrg      etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23);
351b8e80941Smrg   else
352b8e80941Smrg      etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000002);
353b8e80941Smrg}
354b8e80941Smrg
355b8e80941Smrg
356b8e80941Smrgstatic bool
357b8e80941Smrgetna_try_blt_blit(struct pipe_context *pctx,
358b8e80941Smrg                 const struct pipe_blit_info *blit_info)
359b8e80941Smrg{
360b8e80941Smrg   struct etna_context *ctx = etna_context(pctx);
361b8e80941Smrg   struct etna_resource *src = etna_resource(blit_info->src.resource);
362b8e80941Smrg   struct etna_resource *dst = etna_resource(blit_info->dst.resource);
363b8e80941Smrg   int msaa_xscale = 1, msaa_yscale = 1;
364b8e80941Smrg
365b8e80941Smrg   /* Ensure that the level is valid */
366b8e80941Smrg   assert(blit_info->src.level <= src->base.last_level);
367b8e80941Smrg   assert(blit_info->dst.level <= dst->base.last_level);
368b8e80941Smrg
369b8e80941Smrg   if (!translate_samples_to_xyscale(src->base.nr_samples, &msaa_xscale, &msaa_yscale, NULL))
370b8e80941Smrg      return FALSE;
371b8e80941Smrg
372b8e80941Smrg   /* The width/height are in pixels; they do not change as a result of
373b8e80941Smrg    * multi-sampling. So, when blitting from a 4x multisampled surface
374b8e80941Smrg    * to a non-multisampled surface, the width and height will be
375b8e80941Smrg    * identical. As we do not support scaling, reject different sizes.
376b8e80941Smrg    * TODO: could handle 2x downsample here with emit_blt_genmipmaps */
377b8e80941Smrg   if (blit_info->dst.box.width != blit_info->src.box.width ||
378b8e80941Smrg       blit_info->dst.box.height != abs(blit_info->src.box.height)) { /* allow y flip for glTexImage2D */
379b8e80941Smrg      DBG("scaling requested: source %dx%d destination %dx%d",
380b8e80941Smrg          blit_info->src.box.width, blit_info->src.box.height,
381b8e80941Smrg          blit_info->dst.box.width, blit_info->dst.box.height);
382b8e80941Smrg      return FALSE;
383b8e80941Smrg   }
384b8e80941Smrg
385b8e80941Smrg   /* No masks - not sure if BLT can copy individual channels */
386b8e80941Smrg   unsigned mask = util_format_get_mask(blit_info->dst.format);
387b8e80941Smrg   if ((blit_info->mask & mask) != mask) {
388b8e80941Smrg      DBG("sub-mask requested: 0x%02x vs format mask 0x%02x", blit_info->mask, mask);
389b8e80941Smrg      return FALSE;
390b8e80941Smrg   }
391b8e80941Smrg
392b8e80941Smrg   /* TODO: 1 byte per pixel formats aren't handled by etna_compatible_rs_format nor
393b8e80941Smrg    * translate_rs_format.
394b8e80941Smrg    * Also this should be smarter about format conversions; etna_compatible_rs_format
395b8e80941Smrg    * assumes all 2-byte pixel format are laid out as 4444, all 4-byte pixel formats
396b8e80941Smrg    * are 8888.
397b8e80941Smrg    */
398b8e80941Smrg   unsigned src_format = etna_compatible_rs_format(blit_info->src.format);
399b8e80941Smrg   unsigned dst_format = etna_compatible_rs_format(blit_info->dst.format);
400b8e80941Smrg   if (translate_blt_format(src_format) == ETNA_NO_MATCH ||
401b8e80941Smrg       translate_blt_format(dst_format) == ETNA_NO_MATCH ||
402b8e80941Smrg       blit_info->scissor_enable ||
403b8e80941Smrg       blit_info->dst.box.depth != blit_info->src.box.depth ||
404b8e80941Smrg       blit_info->dst.box.depth != 1) {
405b8e80941Smrg      return FALSE;
406b8e80941Smrg   }
407b8e80941Smrg
408b8e80941Smrg   /* Ensure that the Z coordinate is sane */
409b8e80941Smrg   assert(dst->base.target == PIPE_TEXTURE_CUBE || blit_info->dst.box.z == 0);
410b8e80941Smrg   assert(src->base.target == PIPE_TEXTURE_CUBE || blit_info->src.box.z == 0);
411b8e80941Smrg   assert(blit_info->src.box.z < src->base.array_size);
412b8e80941Smrg   assert(blit_info->dst.box.z < dst->base.array_size);
413b8e80941Smrg
414b8e80941Smrg   struct etna_resource_level *src_lev = &src->levels[blit_info->src.level];
415b8e80941Smrg   struct etna_resource_level *dst_lev = &dst->levels[blit_info->dst.level];
416b8e80941Smrg
417b8e80941Smrg   /* Kick off BLT here */
418b8e80941Smrg   if (src == dst) {
419b8e80941Smrg      /* Resolve-in-place */
420b8e80941Smrg      assert(!memcmp(&blit_info->src, &blit_info->dst, sizeof(blit_info->src)));
421b8e80941Smrg      if (!src_lev->ts_size || !src_lev->ts_valid) /* No TS, no worries */
422b8e80941Smrg         return TRUE;
423b8e80941Smrg      struct blt_inplace_op op = {};
424b8e80941Smrg
425b8e80941Smrg      op.addr.bo = src->bo;
426b8e80941Smrg      op.addr.offset = src_lev->offset + blit_info->src.box.z * src_lev->layer_stride;
427b8e80941Smrg      op.addr.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
428b8e80941Smrg      op.ts_addr.bo = src->ts_bo;
429b8e80941Smrg      op.ts_addr.offset = src_lev->ts_offset + blit_info->src.box.z * src_lev->ts_layer_stride;
430b8e80941Smrg      op.ts_addr.flags = ETNA_RELOC_READ;
431b8e80941Smrg      op.ts_clear_value[0] = src_lev->clear_value;
432b8e80941Smrg      op.ts_clear_value[1] = src_lev->clear_value;
433b8e80941Smrg      op.cache_mode = TS_CACHE_MODE_128; /* TODO: cache modes */
434b8e80941Smrg      op.num_tiles = src_lev->size / 128; /* TODO: cache modes */
435b8e80941Smrg      op.bpp = util_format_get_blocksize(src->base.format);
436b8e80941Smrg
437b8e80941Smrg      etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23);
438b8e80941Smrg      etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, 0x00000001);
439b8e80941Smrg      emit_blt_inplace(ctx->stream, &op);
440b8e80941Smrg   } else {
441b8e80941Smrg      /* Copy op */
442b8e80941Smrg      struct blt_imgcopy_op op = {};
443b8e80941Smrg
444b8e80941Smrg      op.src.addr.bo = src->bo;
445b8e80941Smrg      op.src.addr.offset = src_lev->offset + blit_info->src.box.z * src_lev->layer_stride;
446b8e80941Smrg      op.src.addr.flags = ETNA_RELOC_READ;
447b8e80941Smrg      op.src.format = translate_blt_format(src_format);
448b8e80941Smrg      op.src.stride = src_lev->stride;
449b8e80941Smrg      op.src.tiling = src->layout;
450b8e80941Smrg      op.src.cache_mode = TS_CACHE_MODE_128; /* TODO: cache modes */
451b8e80941Smrg      const struct util_format_description *src_format_desc =
452b8e80941Smrg         util_format_description(blit_info->src.format);
453b8e80941Smrg      for (unsigned x=0; x<4; ++x)
454b8e80941Smrg         op.src.swizzle[x] = src_format_desc->swizzle[x];
455b8e80941Smrg
456b8e80941Smrg      if (src_lev->ts_size && src_lev->ts_valid) {
457b8e80941Smrg         op.src.use_ts = 1;
458b8e80941Smrg         op.src.ts_addr.bo = src->ts_bo;
459b8e80941Smrg         op.src.ts_addr.offset = src_lev->ts_offset + blit_info->src.box.z * src_lev->ts_layer_stride;
460b8e80941Smrg         op.src.ts_addr.flags = ETNA_RELOC_READ;
461b8e80941Smrg         op.src.ts_clear_value[0] = src_lev->clear_value;
462b8e80941Smrg         op.src.ts_clear_value[1] = src_lev->clear_value;
463b8e80941Smrg      }
464b8e80941Smrg
465b8e80941Smrg      op.dest.addr.bo = dst->bo;
466b8e80941Smrg      op.dest.addr.offset = dst_lev->offset + blit_info->dst.box.z * dst_lev->layer_stride;
467b8e80941Smrg      op.dest.addr.flags = ETNA_RELOC_WRITE;
468b8e80941Smrg      op.dest.format = translate_blt_format(dst_format);
469b8e80941Smrg      op.dest.stride = dst_lev->stride;
470b8e80941Smrg      /* TODO color compression
471b8e80941Smrg      op.dest.compressed = 1;
472b8e80941Smrg      op.dest.compress_fmt = 3;
473b8e80941Smrg      */
474b8e80941Smrg      op.dest.tiling = dst->layout;
475b8e80941Smrg      op.dest.cache_mode = TS_CACHE_MODE_128; /* TODO cache modes */
476b8e80941Smrg      const struct util_format_description *dst_format_desc =
477b8e80941Smrg         util_format_description(blit_info->dst.format);
478b8e80941Smrg      for (unsigned x=0; x<4; ++x)
479b8e80941Smrg         op.dest.swizzle[x] = dst_format_desc->swizzle[x];
480b8e80941Smrg
481b8e80941Smrg      op.dest_x = blit_info->dst.box.x;
482b8e80941Smrg      op.dest_y = blit_info->dst.box.y;
483b8e80941Smrg      op.src_x = blit_info->src.box.x;
484b8e80941Smrg      op.src_y = blit_info->src.box.y;
485b8e80941Smrg      op.rect_w = blit_info->dst.box.width;
486b8e80941Smrg      op.rect_h = blit_info->dst.box.height;
487b8e80941Smrg
488b8e80941Smrg      if (blit_info->src.box.height < 0) { /* flipped? fix up base y */
489b8e80941Smrg         op.flip_y = 1;
490b8e80941Smrg         op.src_y += blit_info->src.box.height;
491b8e80941Smrg      }
492b8e80941Smrg
493b8e80941Smrg      assert(op.src_x < src_lev->padded_width);
494b8e80941Smrg      assert(op.src_y < src_lev->padded_height);
495b8e80941Smrg      assert((op.src_x + op.rect_w) <= src_lev->padded_width);
496b8e80941Smrg      assert((op.src_y + op.rect_h) <= src_lev->padded_height);
497b8e80941Smrg      assert(op.dest_x < dst_lev->padded_width);
498b8e80941Smrg      assert(op.dest_y < dst_lev->padded_height);
499b8e80941Smrg      assert((op.dest_x + op.rect_w) <= dst_lev->padded_width);
500b8e80941Smrg      assert((op.dest_y + op.rect_h) <= dst_lev->padded_height);
501b8e80941Smrg
502b8e80941Smrg      etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23);
503b8e80941Smrg      etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, 0x00000001);
504b8e80941Smrg      emit_blt_copyimage(ctx->stream, &op);
505b8e80941Smrg   }
506b8e80941Smrg
507b8e80941Smrg   /* Make FE wait for BLT, in case we want to do something with the image next.
508b8e80941Smrg    * This probably shouldn't be here, and depend on what is done with the resource.
509b8e80941Smrg    */
510b8e80941Smrg   etna_stall(ctx->stream, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
511b8e80941Smrg   etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, 0x00000c23);
512b8e80941Smrg
513b8e80941Smrg   resource_read(ctx, &src->base);
514b8e80941Smrg   resource_written(ctx, &dst->base);
515b8e80941Smrg
516b8e80941Smrg   dst->seqno++;
517b8e80941Smrg   dst_lev->ts_valid = false;
518b8e80941Smrg
519b8e80941Smrg   return TRUE;
520b8e80941Smrg}
521b8e80941Smrg
522b8e80941Smrgstatic void
523b8e80941Smrgetna_blit_blt(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
524b8e80941Smrg{
525b8e80941Smrg   struct etna_context *ctx = etna_context(pctx);
526b8e80941Smrg   struct pipe_blit_info info = *blit_info;
527b8e80941Smrg
528b8e80941Smrg   if (info.src.resource->nr_samples > 1 &&
529b8e80941Smrg       info.dst.resource->nr_samples <= 1 &&
530b8e80941Smrg       !util_format_is_depth_or_stencil(info.src.resource->format) &&
531b8e80941Smrg       !util_format_is_pure_integer(info.src.resource->format)) {
532b8e80941Smrg      DBG("color resolve unimplemented");
533b8e80941Smrg      return;
534b8e80941Smrg   }
535b8e80941Smrg
536b8e80941Smrg   if (etna_try_blt_blit(pctx, blit_info))
537b8e80941Smrg      return;
538b8e80941Smrg
539b8e80941Smrg   if (util_try_blit_via_copy_region(pctx, blit_info))
540b8e80941Smrg      return;
541b8e80941Smrg
542b8e80941Smrg   if (info.mask & PIPE_MASK_S) {
543b8e80941Smrg      DBG("cannot blit stencil, skipping");
544b8e80941Smrg      info.mask &= ~PIPE_MASK_S;
545b8e80941Smrg   }
546b8e80941Smrg
547b8e80941Smrg   if (!util_blitter_is_blit_supported(ctx->blitter, &info)) {
548b8e80941Smrg      DBG("blit unsupported %s -> %s",
549b8e80941Smrg          util_format_short_name(info.src.resource->format),
550b8e80941Smrg          util_format_short_name(info.dst.resource->format));
551b8e80941Smrg      return;
552b8e80941Smrg   }
553b8e80941Smrg
554b8e80941Smrg   etna_blit_save_state(ctx);
555b8e80941Smrg   util_blitter_blit(ctx->blitter, &info);
556b8e80941Smrg}
557b8e80941Smrg
558b8e80941Smrgvoid
559b8e80941Smrgetna_clear_blit_blt_init(struct pipe_context *pctx)
560b8e80941Smrg{
561b8e80941Smrg   DBG("etnaviv: Using BLT blit engine");
562b8e80941Smrg   pctx->clear = etna_clear_blt;
563b8e80941Smrg   pctx->blit = etna_blit_blt;
564b8e80941Smrg}
565