1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2017 Rob Clark <robclark@freedesktop.org>
3bf215546Sopenharmony_ci * Copyright © 2018 Google, Inc.
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
11bf215546Sopenharmony_ci *
12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
14bf215546Sopenharmony_ci * Software.
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22bf215546Sopenharmony_ci * SOFTWARE.
23bf215546Sopenharmony_ci *
24bf215546Sopenharmony_ci * Authors:
25bf215546Sopenharmony_ci *    Rob Clark <robclark@freedesktop.org>
26bf215546Sopenharmony_ci */
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "util/format_srgb.h"
29bf215546Sopenharmony_ci#include "util/half_float.h"
30bf215546Sopenharmony_ci#include "util/u_dump.h"
31bf215546Sopenharmony_ci#include "util/u_log.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "freedreno_blitter.h"
34bf215546Sopenharmony_ci#include "freedreno_fence.h"
35bf215546Sopenharmony_ci#include "freedreno_resource.h"
36bf215546Sopenharmony_ci#include "freedreno_tracepoints.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci#include "fd6_blitter.h"
39bf215546Sopenharmony_ci#include "fd6_emit.h"
40bf215546Sopenharmony_ci#include "fd6_resource.h"
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_cistatic inline enum a6xx_2d_ifmt
43bf215546Sopenharmony_cifd6_ifmt(enum a6xx_format fmt)
44bf215546Sopenharmony_ci{
45bf215546Sopenharmony_ci   switch (fmt) {
46bf215546Sopenharmony_ci   case FMT6_A8_UNORM:
47bf215546Sopenharmony_ci   case FMT6_8_UNORM:
48bf215546Sopenharmony_ci   case FMT6_8_SNORM:
49bf215546Sopenharmony_ci   case FMT6_8_8_UNORM:
50bf215546Sopenharmony_ci   case FMT6_8_8_SNORM:
51bf215546Sopenharmony_ci   case FMT6_8_8_8_8_UNORM:
52bf215546Sopenharmony_ci   case FMT6_8_8_8_X8_UNORM:
53bf215546Sopenharmony_ci   case FMT6_8_8_8_8_SNORM:
54bf215546Sopenharmony_ci   case FMT6_4_4_4_4_UNORM:
55bf215546Sopenharmony_ci   case FMT6_5_5_5_1_UNORM:
56bf215546Sopenharmony_ci   case FMT6_5_6_5_UNORM:
57bf215546Sopenharmony_ci      return R2D_UNORM8;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   case FMT6_32_UINT:
60bf215546Sopenharmony_ci   case FMT6_32_SINT:
61bf215546Sopenharmony_ci   case FMT6_32_32_UINT:
62bf215546Sopenharmony_ci   case FMT6_32_32_SINT:
63bf215546Sopenharmony_ci   case FMT6_32_32_32_32_UINT:
64bf215546Sopenharmony_ci   case FMT6_32_32_32_32_SINT:
65bf215546Sopenharmony_ci      return R2D_INT32;
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   case FMT6_16_UINT:
68bf215546Sopenharmony_ci   case FMT6_16_SINT:
69bf215546Sopenharmony_ci   case FMT6_16_16_UINT:
70bf215546Sopenharmony_ci   case FMT6_16_16_SINT:
71bf215546Sopenharmony_ci   case FMT6_16_16_16_16_UINT:
72bf215546Sopenharmony_ci   case FMT6_16_16_16_16_SINT:
73bf215546Sopenharmony_ci   case FMT6_10_10_10_2_UINT:
74bf215546Sopenharmony_ci      return R2D_INT16;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   case FMT6_8_UINT:
77bf215546Sopenharmony_ci   case FMT6_8_SINT:
78bf215546Sopenharmony_ci   case FMT6_8_8_UINT:
79bf215546Sopenharmony_ci   case FMT6_8_8_SINT:
80bf215546Sopenharmony_ci   case FMT6_8_8_8_8_UINT:
81bf215546Sopenharmony_ci   case FMT6_8_8_8_8_SINT:
82bf215546Sopenharmony_ci   case FMT6_Z24_UNORM_S8_UINT:
83bf215546Sopenharmony_ci   case FMT6_Z24_UNORM_S8_UINT_AS_R8G8B8A8:
84bf215546Sopenharmony_ci      return R2D_INT8;
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci   case FMT6_16_UNORM:
87bf215546Sopenharmony_ci   case FMT6_16_SNORM:
88bf215546Sopenharmony_ci   case FMT6_16_16_UNORM:
89bf215546Sopenharmony_ci   case FMT6_16_16_SNORM:
90bf215546Sopenharmony_ci   case FMT6_16_16_16_16_UNORM:
91bf215546Sopenharmony_ci   case FMT6_16_16_16_16_SNORM:
92bf215546Sopenharmony_ci   case FMT6_32_FLOAT:
93bf215546Sopenharmony_ci   case FMT6_32_32_FLOAT:
94bf215546Sopenharmony_ci   case FMT6_32_32_32_32_FLOAT:
95bf215546Sopenharmony_ci      return R2D_FLOAT32;
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   case FMT6_16_FLOAT:
98bf215546Sopenharmony_ci   case FMT6_16_16_FLOAT:
99bf215546Sopenharmony_ci   case FMT6_16_16_16_16_FLOAT:
100bf215546Sopenharmony_ci   case FMT6_11_11_10_FLOAT:
101bf215546Sopenharmony_ci   case FMT6_10_10_10_2_UNORM_DEST:
102bf215546Sopenharmony_ci      return R2D_FLOAT16;
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   default:
105bf215546Sopenharmony_ci      unreachable("bad format");
106bf215546Sopenharmony_ci      return 0;
107bf215546Sopenharmony_ci   }
108bf215546Sopenharmony_ci}
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci/* Make sure none of the requested dimensions extend beyond the size of the
111bf215546Sopenharmony_ci * resource.  Not entirely sure why this happens, but sometimes it does, and
112bf215546Sopenharmony_ci * w/ 2d blt doesn't have wrap modes like a sampler, so force those cases
113bf215546Sopenharmony_ci * back to u_blitter
114bf215546Sopenharmony_ci */
115bf215546Sopenharmony_cistatic bool
116bf215546Sopenharmony_ciok_dims(const struct pipe_resource *r, const struct pipe_box *b, int lvl)
117bf215546Sopenharmony_ci{
118bf215546Sopenharmony_ci   int last_layer =
119bf215546Sopenharmony_ci      r->target == PIPE_TEXTURE_3D ? u_minify(r->depth0, lvl) : r->array_size;
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   return (b->x >= 0) && (b->x + b->width <= u_minify(r->width0, lvl)) &&
122bf215546Sopenharmony_ci          (b->y >= 0) && (b->y + b->height <= u_minify(r->height0, lvl)) &&
123bf215546Sopenharmony_ci          (b->z >= 0) && (b->z + b->depth <= last_layer);
124bf215546Sopenharmony_ci}
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_cistatic bool
127bf215546Sopenharmony_ciok_format(enum pipe_format pfmt)
128bf215546Sopenharmony_ci{
129bf215546Sopenharmony_ci   enum a6xx_format fmt = fd6_color_format(pfmt, TILE6_LINEAR);
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci   if (util_format_is_compressed(pfmt))
132bf215546Sopenharmony_ci      return true;
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci   switch (pfmt) {
135bf215546Sopenharmony_ci   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
136bf215546Sopenharmony_ci   case PIPE_FORMAT_Z24X8_UNORM:
137bf215546Sopenharmony_ci   case PIPE_FORMAT_Z16_UNORM:
138bf215546Sopenharmony_ci   case PIPE_FORMAT_Z32_UNORM:
139bf215546Sopenharmony_ci   case PIPE_FORMAT_Z32_FLOAT:
140bf215546Sopenharmony_ci   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
141bf215546Sopenharmony_ci   case PIPE_FORMAT_S8_UINT:
142bf215546Sopenharmony_ci      return true;
143bf215546Sopenharmony_ci   default:
144bf215546Sopenharmony_ci      break;
145bf215546Sopenharmony_ci   }
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   if (fmt == FMT6_NONE)
148bf215546Sopenharmony_ci      return false;
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci   return true;
151bf215546Sopenharmony_ci}
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci#define DEBUG_BLIT          0
154bf215546Sopenharmony_ci#define DEBUG_BLIT_FALLBACK 0
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci#define fail_if(cond)                                                          \
157bf215546Sopenharmony_ci   do {                                                                        \
158bf215546Sopenharmony_ci      if (cond) {                                                              \
159bf215546Sopenharmony_ci         if (DEBUG_BLIT_FALLBACK) {                                            \
160bf215546Sopenharmony_ci            fprintf(stderr, "falling back: %s for blit:\n", #cond);            \
161bf215546Sopenharmony_ci            dump_blit_info(info);                                              \
162bf215546Sopenharmony_ci         }                                                                     \
163bf215546Sopenharmony_ci         return false;                                                         \
164bf215546Sopenharmony_ci      }                                                                        \
165bf215546Sopenharmony_ci   } while (0)
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_cistatic bool
168bf215546Sopenharmony_ciis_ubwc(struct pipe_resource *prsc, unsigned level)
169bf215546Sopenharmony_ci{
170bf215546Sopenharmony_ci   return fd_resource_ubwc_enabled(fd_resource(prsc), level);
171bf215546Sopenharmony_ci}
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_cistatic void
174bf215546Sopenharmony_cidump_blit_info(const struct pipe_blit_info *info)
175bf215546Sopenharmony_ci{
176bf215546Sopenharmony_ci   util_dump_blit_info(stderr, info);
177bf215546Sopenharmony_ci   fprintf(stderr, "\ndst resource: ");
178bf215546Sopenharmony_ci   util_dump_resource(stderr, info->dst.resource);
179bf215546Sopenharmony_ci   if (is_ubwc(info->dst.resource, info->dst.level))
180bf215546Sopenharmony_ci      fprintf(stderr, " (ubwc)");
181bf215546Sopenharmony_ci   fprintf(stderr, "\nsrc resource: ");
182bf215546Sopenharmony_ci   util_dump_resource(stderr, info->src.resource);
183bf215546Sopenharmony_ci   if (is_ubwc(info->src.resource, info->src.level))
184bf215546Sopenharmony_ci      fprintf(stderr, " (ubwc)");
185bf215546Sopenharmony_ci   fprintf(stderr, "\n");
186bf215546Sopenharmony_ci}
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_cistatic bool
189bf215546Sopenharmony_cican_do_blit(const struct pipe_blit_info *info)
190bf215546Sopenharmony_ci{
191bf215546Sopenharmony_ci   /* I think we can do scaling, but not in z dimension since that would
192bf215546Sopenharmony_ci    * require blending..
193bf215546Sopenharmony_ci    */
194bf215546Sopenharmony_ci   fail_if(info->dst.box.depth != info->src.box.depth);
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   /* Fail if unsupported format: */
197bf215546Sopenharmony_ci   fail_if(!ok_format(info->src.format));
198bf215546Sopenharmony_ci   fail_if(!ok_format(info->dst.format));
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   assert(!util_format_is_compressed(info->src.format));
201bf215546Sopenharmony_ci   assert(!util_format_is_compressed(info->dst.format));
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   fail_if(!ok_dims(info->src.resource, &info->src.box, info->src.level));
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci   fail_if(!ok_dims(info->dst.resource, &info->dst.box, info->dst.level));
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   assert(info->dst.box.width >= 0);
208bf215546Sopenharmony_ci   assert(info->dst.box.height >= 0);
209bf215546Sopenharmony_ci   assert(info->dst.box.depth >= 0);
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   fail_if(info->dst.resource->nr_samples > 1);
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci   fail_if(info->window_rectangle_include);
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci   const struct util_format_description *src_desc =
216bf215546Sopenharmony_ci      util_format_description(info->src.format);
217bf215546Sopenharmony_ci   const struct util_format_description *dst_desc =
218bf215546Sopenharmony_ci      util_format_description(info->dst.format);
219bf215546Sopenharmony_ci   const int common_channels =
220bf215546Sopenharmony_ci      MIN2(src_desc->nr_channels, dst_desc->nr_channels);
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci   if (info->mask & PIPE_MASK_RGBA) {
223bf215546Sopenharmony_ci      for (int i = 0; i < common_channels; i++) {
224bf215546Sopenharmony_ci         fail_if(memcmp(&src_desc->channel[i], &dst_desc->channel[i],
225bf215546Sopenharmony_ci                        sizeof(src_desc->channel[0])));
226bf215546Sopenharmony_ci      }
227bf215546Sopenharmony_ci   }
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci   fail_if(info->alpha_blend);
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   return true;
232bf215546Sopenharmony_ci}
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_cistatic void
235bf215546Sopenharmony_ciemit_setup(struct fd_batch *batch)
236bf215546Sopenharmony_ci{
237bf215546Sopenharmony_ci   struct fd_ringbuffer *ring = batch->draw;
238bf215546Sopenharmony_ci   struct fd_screen *screen = batch->ctx->screen;
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci   fd6_event_write(batch, ring, PC_CCU_FLUSH_COLOR_TS, true);
241bf215546Sopenharmony_ci   fd6_event_write(batch, ring, PC_CCU_FLUSH_DEPTH_TS, true);
242bf215546Sopenharmony_ci   fd6_event_write(batch, ring, PC_CCU_INVALIDATE_COLOR, false);
243bf215546Sopenharmony_ci   fd6_event_write(batch, ring, PC_CCU_INVALIDATE_DEPTH, false);
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   /* normal BLIT_OP_SCALE operation needs bypass RB_CCU_CNTL */
246bf215546Sopenharmony_ci   OUT_WFI5(ring);
247bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_RB_CCU_CNTL, 1);
248bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_RB_CCU_CNTL_COLOR_OFFSET(screen->ccu_offset_bypass));
249bf215546Sopenharmony_ci}
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_cistatic void
252bf215546Sopenharmony_ciemit_blit_setup(struct fd_ringbuffer *ring, enum pipe_format pfmt,
253bf215546Sopenharmony_ci                bool scissor_enable, union pipe_color_union *color,
254bf215546Sopenharmony_ci                uint32_t unknown_8c01)
255bf215546Sopenharmony_ci{
256bf215546Sopenharmony_ci   enum a6xx_format fmt = fd6_color_format(pfmt, TILE6_LINEAR);
257bf215546Sopenharmony_ci   bool is_srgb = util_format_is_srgb(pfmt);
258bf215546Sopenharmony_ci   enum a6xx_2d_ifmt ifmt = fd6_ifmt(fmt);
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   if (is_srgb) {
261bf215546Sopenharmony_ci      assert(ifmt == R2D_UNORM8);
262bf215546Sopenharmony_ci      ifmt = R2D_UNORM8_SRGB;
263bf215546Sopenharmony_ci   }
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   uint32_t blit_cntl = A6XX_RB_2D_BLIT_CNTL_MASK(0xf) |
266bf215546Sopenharmony_ci                        A6XX_RB_2D_BLIT_CNTL_COLOR_FORMAT(fmt) |
267bf215546Sopenharmony_ci                        A6XX_RB_2D_BLIT_CNTL_IFMT(ifmt) |
268bf215546Sopenharmony_ci                        COND(color, A6XX_RB_2D_BLIT_CNTL_SOLID_COLOR) |
269bf215546Sopenharmony_ci                        COND(scissor_enable, A6XX_RB_2D_BLIT_CNTL_SCISSOR);
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_RB_2D_BLIT_CNTL, 1);
272bf215546Sopenharmony_ci   OUT_RING(ring, blit_cntl);
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_GRAS_2D_BLIT_CNTL, 1);
275bf215546Sopenharmony_ci   OUT_RING(ring, blit_cntl);
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci   if (fmt == FMT6_10_10_10_2_UNORM_DEST)
278bf215546Sopenharmony_ci      fmt = FMT6_16_16_16_16_FLOAT;
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci   /* This register is probably badly named... it seems that it's
281bf215546Sopenharmony_ci    * controlling the internal/accumulator format or something like
282bf215546Sopenharmony_ci    * that. It's certainly not tied to only the src format.
283bf215546Sopenharmony_ci    */
284bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_SP_2D_DST_FORMAT, 1);
285bf215546Sopenharmony_ci   OUT_RING(
286bf215546Sopenharmony_ci      ring,
287bf215546Sopenharmony_ci      A6XX_SP_2D_DST_FORMAT_COLOR_FORMAT(fmt) |
288bf215546Sopenharmony_ci         COND(util_format_is_pure_sint(pfmt), A6XX_SP_2D_DST_FORMAT_SINT) |
289bf215546Sopenharmony_ci         COND(util_format_is_pure_uint(pfmt), A6XX_SP_2D_DST_FORMAT_UINT) |
290bf215546Sopenharmony_ci         COND(is_srgb, A6XX_SP_2D_DST_FORMAT_SRGB) |
291bf215546Sopenharmony_ci         A6XX_SP_2D_DST_FORMAT_MASK(0xf));
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_RB_2D_UNKNOWN_8C01, 1);
294bf215546Sopenharmony_ci   OUT_RING(ring, unknown_8c01);
295bf215546Sopenharmony_ci}
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci/* buffers need to be handled specially since x/width can exceed the bounds
298bf215546Sopenharmony_ci * supported by hw.. if necessary decompose into (potentially) two 2D blits
299bf215546Sopenharmony_ci */
300bf215546Sopenharmony_cistatic void
301bf215546Sopenharmony_ciemit_blit_buffer(struct fd_context *ctx, struct fd_ringbuffer *ring,
302bf215546Sopenharmony_ci                 const struct pipe_blit_info *info)
303bf215546Sopenharmony_ci{
304bf215546Sopenharmony_ci   const struct pipe_box *sbox = &info->src.box;
305bf215546Sopenharmony_ci   const struct pipe_box *dbox = &info->dst.box;
306bf215546Sopenharmony_ci   struct fd_resource *src, *dst;
307bf215546Sopenharmony_ci   unsigned sshift, dshift;
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci   if (DEBUG_BLIT) {
310bf215546Sopenharmony_ci      fprintf(stderr, "buffer blit: ");
311bf215546Sopenharmony_ci      dump_blit_info(info);
312bf215546Sopenharmony_ci   }
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci   src = fd_resource(info->src.resource);
315bf215546Sopenharmony_ci   dst = fd_resource(info->dst.resource);
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci   assert(src->layout.cpp == 1);
318bf215546Sopenharmony_ci   assert(dst->layout.cpp == 1);
319bf215546Sopenharmony_ci   assert(info->src.resource->format == info->dst.resource->format);
320bf215546Sopenharmony_ci   assert((sbox->y == 0) && (sbox->height == 1));
321bf215546Sopenharmony_ci   assert((dbox->y == 0) && (dbox->height == 1));
322bf215546Sopenharmony_ci   assert((sbox->z == 0) && (sbox->depth == 1));
323bf215546Sopenharmony_ci   assert((dbox->z == 0) && (dbox->depth == 1));
324bf215546Sopenharmony_ci   assert(sbox->width == dbox->width);
325bf215546Sopenharmony_ci   assert(info->src.level == 0);
326bf215546Sopenharmony_ci   assert(info->dst.level == 0);
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci   /*
329bf215546Sopenharmony_ci    * Buffers can have dimensions bigger than max width, remap into
330bf215546Sopenharmony_ci    * multiple 1d blits to fit within max dimension
331bf215546Sopenharmony_ci    *
332bf215546Sopenharmony_ci    * Note that blob uses .ARRAY_PITCH=128 for blitting buffers, which
333bf215546Sopenharmony_ci    * seems to prevent overfetch related faults.  Not quite sure what
334bf215546Sopenharmony_ci    * the deal is there.
335bf215546Sopenharmony_ci    *
336bf215546Sopenharmony_ci    * Low 6 bits of SRC/DST addresses need to be zero (ie. address
337bf215546Sopenharmony_ci    * aligned to 64) so we need to shift src/dst x1/x2 to make up the
338bf215546Sopenharmony_ci    * difference.  On top of already splitting up the blit so width
339bf215546Sopenharmony_ci    * isn't > 16k.
340bf215546Sopenharmony_ci    *
341bf215546Sopenharmony_ci    * We perhaps could do a bit better, if src and dst are aligned but
342bf215546Sopenharmony_ci    * in the worst case this means we have to split the copy up into
343bf215546Sopenharmony_ci    * 16k (0x4000) minus 64 (0x40).
344bf215546Sopenharmony_ci    */
345bf215546Sopenharmony_ci
346bf215546Sopenharmony_ci   sshift = sbox->x & 0x3f;
347bf215546Sopenharmony_ci   dshift = dbox->x & 0x3f;
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci   emit_blit_setup(ring, PIPE_FORMAT_R8_UNORM, false, NULL, 0);
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci   for (unsigned off = 0; off < sbox->width; off += (0x4000 - 0x40)) {
352bf215546Sopenharmony_ci      unsigned soff, doff, w, p;
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci      soff = (sbox->x + off) & ~0x3f;
355bf215546Sopenharmony_ci      doff = (dbox->x + off) & ~0x3f;
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci      w = MIN2(sbox->width - off, (0x4000 - 0x40));
358bf215546Sopenharmony_ci      p = align(w, 64);
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci      assert((soff + w) <= fd_bo_size(src->bo));
361bf215546Sopenharmony_ci      assert((doff + w) <= fd_bo_size(dst->bo));
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci      /*
364bf215546Sopenharmony_ci       * Emit source:
365bf215546Sopenharmony_ci       */
366bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 10);
367bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_SP_PS_2D_SRC_INFO_COLOR_FORMAT(FMT6_8_UNORM) |
368bf215546Sopenharmony_ci                        A6XX_SP_PS_2D_SRC_INFO_TILE_MODE(TILE6_LINEAR) |
369bf215546Sopenharmony_ci                        A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(WZYX) | 0x500000);
370bf215546Sopenharmony_ci      OUT_RING(ring,
371bf215546Sopenharmony_ci               A6XX_SP_PS_2D_SRC_SIZE_WIDTH(sshift + w) |
372bf215546Sopenharmony_ci                  A6XX_SP_PS_2D_SRC_SIZE_HEIGHT(1)); /* SP_PS_2D_SRC_SIZE */
373bf215546Sopenharmony_ci      OUT_RELOC(ring, src->bo, soff, 0, 0);          /* SP_PS_2D_SRC_LO/HI */
374bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_SP_PS_2D_SRC_PITCH_PITCH(p));
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
377bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
378bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
379bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
380bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_ci      /*
383bf215546Sopenharmony_ci       * Emit destination:
384bf215546Sopenharmony_ci       */
385bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_2D_DST_INFO, 9);
386bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_RB_2D_DST_INFO_COLOR_FORMAT(FMT6_8_UNORM) |
387bf215546Sopenharmony_ci                        A6XX_RB_2D_DST_INFO_TILE_MODE(TILE6_LINEAR) |
388bf215546Sopenharmony_ci                        A6XX_RB_2D_DST_INFO_COLOR_SWAP(WZYX));
389bf215546Sopenharmony_ci      OUT_RELOC(ring, dst->bo, doff, 0, 0); /* RB_2D_DST_LO/HI */
390bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_RB_2D_DST_PITCH(p));
391bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
392bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
393bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
394bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
395bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
396bf215546Sopenharmony_ci
397bf215546Sopenharmony_ci      /*
398bf215546Sopenharmony_ci       * Blit command:
399bf215546Sopenharmony_ci       */
400bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_GRAS_2D_SRC_TL_X, 4);
401bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_X(sshift));
402bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_X(sshift + w - 1));
403bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_Y(0));
404bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_Y(0));
405bf215546Sopenharmony_ci
406bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_GRAS_2D_DST_TL, 2);
407bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_GRAS_2D_DST_TL_X(dshift) | A6XX_GRAS_2D_DST_TL_Y(0));
408bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_GRAS_2D_DST_BR_X(dshift + w - 1) |
409bf215546Sopenharmony_ci                        A6XX_GRAS_2D_DST_BR_Y(0));
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci      OUT_PKT7(ring, CP_EVENT_WRITE, 1);
412bf215546Sopenharmony_ci      OUT_RING(ring, 0x3f);
413bf215546Sopenharmony_ci      OUT_WFI5(ring);
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
416bf215546Sopenharmony_ci      OUT_RING(ring, ctx->screen->info->a6xx.magic.RB_UNKNOWN_8E04_blit);
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci      OUT_PKT7(ring, CP_BLIT, 1);
419bf215546Sopenharmony_ci      OUT_RING(ring, CP_BLIT_0_OP(BLIT_OP_SCALE));
420bf215546Sopenharmony_ci
421bf215546Sopenharmony_ci      OUT_WFI5(ring);
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
424bf215546Sopenharmony_ci      OUT_RING(ring, 0); /* RB_UNKNOWN_8E04 */
425bf215546Sopenharmony_ci   }
426bf215546Sopenharmony_ci}
427bf215546Sopenharmony_ci
428bf215546Sopenharmony_cistatic void
429bf215546Sopenharmony_cifd6_clear_ubwc(struct fd_batch *batch, struct fd_resource *rsc) assert_dt
430bf215546Sopenharmony_ci{
431bf215546Sopenharmony_ci   struct fd_ringbuffer *ring = fd_batch_get_prologue(batch);
432bf215546Sopenharmony_ci   union pipe_color_union color = {};
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_ci   emit_blit_setup(ring, PIPE_FORMAT_R8_UNORM, false, &color, 0);
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 13);
437bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
438bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
439bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
440bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
441bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
442bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
443bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
444bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
445bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
446bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
447bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
448bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
449bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
450bf215546Sopenharmony_ci
451bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_RB_2D_SRC_SOLID_C0, 4);
452bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
453bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
454bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
455bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
456bf215546Sopenharmony_ci
457bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_GRAS_2D_SRC_TL_X, 4);
458bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_X(0));
459bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_X(0));
460bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_Y(0));
461bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_Y(0));
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci   unsigned size = rsc->layout.slices[0].offset;
464bf215546Sopenharmony_ci   unsigned offset = 0;
465bf215546Sopenharmony_ci
466bf215546Sopenharmony_ci   /* We could be more clever here and realize that we could use a
467bf215546Sopenharmony_ci    * larger width if the size is aligned to something more than a
468bf215546Sopenharmony_ci    * single page.. or even use a format larger than r8 in those
469bf215546Sopenharmony_ci    * cases. But for normal sized textures and even up to 16k x 16k
470bf215546Sopenharmony_ci    * at <= 4byte/pixel, we'll only go thru the loop once
471bf215546Sopenharmony_ci    */
472bf215546Sopenharmony_ci   const unsigned w = 0x1000;
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci   /* ubwc size should always be page aligned: */
475bf215546Sopenharmony_ci   assert((size % w) == 0);
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci   while (size > 0) {
478bf215546Sopenharmony_ci      const unsigned h = MIN2(0x4000, size / w);
479bf215546Sopenharmony_ci      /* width is already aligned to a suitable pitch: */
480bf215546Sopenharmony_ci      const unsigned p = w;
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_ci      /*
483bf215546Sopenharmony_ci       * Emit destination:
484bf215546Sopenharmony_ci       */
485bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_2D_DST_INFO, 9);
486bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_RB_2D_DST_INFO_COLOR_FORMAT(FMT6_8_UNORM) |
487bf215546Sopenharmony_ci                        A6XX_RB_2D_DST_INFO_TILE_MODE(TILE6_LINEAR) |
488bf215546Sopenharmony_ci                        A6XX_RB_2D_DST_INFO_COLOR_SWAP(WZYX));
489bf215546Sopenharmony_ci      OUT_RELOC(ring, rsc->bo, offset, 0, 0); /* RB_2D_DST_LO/HI */
490bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_RB_2D_DST_PITCH(p));
491bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
492bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
493bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
494bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
495bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci      /*
498bf215546Sopenharmony_ci       * Blit command:
499bf215546Sopenharmony_ci       */
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_GRAS_2D_DST_TL, 2);
502bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_GRAS_2D_DST_TL_X(0) | A6XX_GRAS_2D_DST_TL_Y(0));
503bf215546Sopenharmony_ci      OUT_RING(ring,
504bf215546Sopenharmony_ci               A6XX_GRAS_2D_DST_BR_X(w - 1) | A6XX_GRAS_2D_DST_BR_Y(h - 1));
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci      OUT_PKT7(ring, CP_EVENT_WRITE, 1);
507bf215546Sopenharmony_ci      OUT_RING(ring, 0x3f);
508bf215546Sopenharmony_ci      OUT_WFI5(ring);
509bf215546Sopenharmony_ci
510bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
511bf215546Sopenharmony_ci      OUT_RING(ring, batch->ctx->screen->info->a6xx.magic.RB_UNKNOWN_8E04_blit);
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci      OUT_PKT7(ring, CP_BLIT, 1);
514bf215546Sopenharmony_ci      OUT_RING(ring, CP_BLIT_0_OP(BLIT_OP_SCALE));
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_ci      OUT_WFI5(ring);
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
519bf215546Sopenharmony_ci      OUT_RING(ring, 0); /* RB_UNKNOWN_8E04 */
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_ci      offset += w * h;
522bf215546Sopenharmony_ci      size -= w * h;
523bf215546Sopenharmony_ci   }
524bf215546Sopenharmony_ci
525bf215546Sopenharmony_ci   fd6_event_write(batch, ring, PC_CCU_FLUSH_COLOR_TS, true);
526bf215546Sopenharmony_ci   fd6_event_write(batch, ring, PC_CCU_FLUSH_DEPTH_TS, true);
527bf215546Sopenharmony_ci   fd6_event_write(batch, ring, CACHE_FLUSH_TS, true);
528bf215546Sopenharmony_ci   fd_wfi(batch, ring);
529bf215546Sopenharmony_ci   fd6_cache_inv(batch, ring);
530bf215546Sopenharmony_ci}
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_cistatic void
533bf215546Sopenharmony_ciemit_blit_dst(struct fd_ringbuffer *ring, struct pipe_resource *prsc,
534bf215546Sopenharmony_ci              enum pipe_format pfmt, unsigned level, unsigned layer)
535bf215546Sopenharmony_ci{
536bf215546Sopenharmony_ci   struct fd_resource *dst = fd_resource(prsc);
537bf215546Sopenharmony_ci   enum a6xx_format fmt = fd6_color_format(pfmt, dst->layout.tile_mode);
538bf215546Sopenharmony_ci   enum a6xx_tile_mode tile = fd_resource_tile_mode(prsc, level);
539bf215546Sopenharmony_ci   enum a3xx_color_swap swap = fd6_color_swap(pfmt, dst->layout.tile_mode);
540bf215546Sopenharmony_ci   uint32_t pitch = fd_resource_pitch(dst, level);
541bf215546Sopenharmony_ci   bool ubwc_enabled = fd_resource_ubwc_enabled(dst, level);
542bf215546Sopenharmony_ci   unsigned off = fd_resource_offset(dst, level, layer);
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_ci   if (fmt == FMT6_Z24_UNORM_S8_UINT)
545bf215546Sopenharmony_ci      fmt = FMT6_Z24_UNORM_S8_UINT_AS_R8G8B8A8;
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_RB_2D_DST_INFO, 9);
548bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_RB_2D_DST_INFO_COLOR_FORMAT(fmt) |
549bf215546Sopenharmony_ci                     A6XX_RB_2D_DST_INFO_TILE_MODE(tile) |
550bf215546Sopenharmony_ci                     A6XX_RB_2D_DST_INFO_COLOR_SWAP(swap) |
551bf215546Sopenharmony_ci                     COND(util_format_is_srgb(pfmt), A6XX_RB_2D_DST_INFO_SRGB) |
552bf215546Sopenharmony_ci                     COND(ubwc_enabled, A6XX_RB_2D_DST_INFO_FLAGS));
553bf215546Sopenharmony_ci   OUT_RELOC(ring, dst->bo, off, 0, 0); /* RB_2D_DST_LO/HI */
554bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_RB_2D_DST_PITCH(pitch));
555bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
556bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
557bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
558bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
559bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci   if (ubwc_enabled) {
562bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_2D_DST_FLAGS, 6);
563bf215546Sopenharmony_ci      fd6_emit_flag_reference(ring, dst, level, layer);
564bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
565bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
566bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
567bf215546Sopenharmony_ci   }
568bf215546Sopenharmony_ci}
569bf215546Sopenharmony_ci
570bf215546Sopenharmony_cistatic void
571bf215546Sopenharmony_ciemit_blit_src(struct fd_ringbuffer *ring, const struct pipe_blit_info *info,
572bf215546Sopenharmony_ci              unsigned layer, unsigned nr_samples, bool sample_0)
573bf215546Sopenharmony_ci{
574bf215546Sopenharmony_ci   struct fd_resource *src = fd_resource(info->src.resource);
575bf215546Sopenharmony_ci   enum a6xx_format sfmt = fd6_texture_format(info->src.format, src->layout.tile_mode);
576bf215546Sopenharmony_ci   enum a6xx_tile_mode stile =
577bf215546Sopenharmony_ci      fd_resource_tile_mode(info->src.resource, info->src.level);
578bf215546Sopenharmony_ci   enum a3xx_color_swap sswap = fd6_texture_swap(info->src.format, src->layout.tile_mode);
579bf215546Sopenharmony_ci   uint32_t pitch = fd_resource_pitch(src, info->src.level);
580bf215546Sopenharmony_ci   bool subwc_enabled = fd_resource_ubwc_enabled(src, info->src.level);
581bf215546Sopenharmony_ci   unsigned soff = fd_resource_offset(src, info->src.level, layer);
582bf215546Sopenharmony_ci   uint32_t width = u_minify(src->b.b.width0, info->src.level) * nr_samples;
583bf215546Sopenharmony_ci   uint32_t height = u_minify(src->b.b.height0, info->src.level);
584bf215546Sopenharmony_ci   uint32_t filter = 0;
585bf215546Sopenharmony_ci
586bf215546Sopenharmony_ci   if (info->filter == PIPE_TEX_FILTER_LINEAR)
587bf215546Sopenharmony_ci      filter = A6XX_SP_PS_2D_SRC_INFO_FILTER;
588bf215546Sopenharmony_ci
589bf215546Sopenharmony_ci   enum a3xx_msaa_samples samples = fd_msaa_samples(src->b.b.nr_samples);
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci   if (info->src.format == PIPE_FORMAT_A8_UNORM)
592bf215546Sopenharmony_ci      sfmt = FMT6_A8_UNORM;
593bf215546Sopenharmony_ci
594bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 10);
595bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_SP_PS_2D_SRC_INFO_COLOR_FORMAT(sfmt) |
596bf215546Sopenharmony_ci                     A6XX_SP_PS_2D_SRC_INFO_TILE_MODE(stile) |
597bf215546Sopenharmony_ci                     A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(sswap) |
598bf215546Sopenharmony_ci                     A6XX_SP_PS_2D_SRC_INFO_SAMPLES(samples) |
599bf215546Sopenharmony_ci                     COND(samples > MSAA_ONE && !sample_0,
600bf215546Sopenharmony_ci                          A6XX_SP_PS_2D_SRC_INFO_SAMPLES_AVERAGE) |
601bf215546Sopenharmony_ci                     COND(subwc_enabled, A6XX_SP_PS_2D_SRC_INFO_FLAGS) |
602bf215546Sopenharmony_ci                     COND(util_format_is_srgb(info->src.format),
603bf215546Sopenharmony_ci                          A6XX_SP_PS_2D_SRC_INFO_SRGB) |
604bf215546Sopenharmony_ci                     0x500000 | filter);
605bf215546Sopenharmony_ci   OUT_RING(ring,
606bf215546Sopenharmony_ci            A6XX_SP_PS_2D_SRC_SIZE_WIDTH(width) |
607bf215546Sopenharmony_ci               A6XX_SP_PS_2D_SRC_SIZE_HEIGHT(height)); /* SP_PS_2D_SRC_SIZE */
608bf215546Sopenharmony_ci   OUT_RELOC(ring, src->bo, soff, 0, 0);               /* SP_PS_2D_SRC_LO/HI */
609bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_SP_PS_2D_SRC_PITCH_PITCH(pitch));
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
612bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
613bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
614bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
615bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
616bf215546Sopenharmony_ci
617bf215546Sopenharmony_ci   if (subwc_enabled) {
618bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_FLAGS, 6);
619bf215546Sopenharmony_ci      fd6_emit_flag_reference(ring, src, info->src.level, layer);
620bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
621bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
622bf215546Sopenharmony_ci      OUT_RING(ring, 0x00000000);
623bf215546Sopenharmony_ci   }
624bf215546Sopenharmony_ci}
625bf215546Sopenharmony_ci
626bf215546Sopenharmony_cistatic void
627bf215546Sopenharmony_ciemit_blit_texture(struct fd_context *ctx, struct fd_ringbuffer *ring,
628bf215546Sopenharmony_ci                  const struct pipe_blit_info *info, bool sample_0)
629bf215546Sopenharmony_ci{
630bf215546Sopenharmony_ci   const struct pipe_box *sbox = &info->src.box;
631bf215546Sopenharmony_ci   const struct pipe_box *dbox = &info->dst.box;
632bf215546Sopenharmony_ci   struct fd_resource *dst;
633bf215546Sopenharmony_ci   int sx1, sy1, sx2, sy2;
634bf215546Sopenharmony_ci   int dx1, dy1, dx2, dy2;
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   if (DEBUG_BLIT) {
637bf215546Sopenharmony_ci      fprintf(stderr, "texture blit: ");
638bf215546Sopenharmony_ci      dump_blit_info(info);
639bf215546Sopenharmony_ci   }
640bf215546Sopenharmony_ci
641bf215546Sopenharmony_ci   dst = fd_resource(info->dst.resource);
642bf215546Sopenharmony_ci
643bf215546Sopenharmony_ci   uint32_t nr_samples = fd_resource_nr_samples(&dst->b.b);
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci   sx1 = sbox->x * nr_samples;
646bf215546Sopenharmony_ci   sy1 = sbox->y;
647bf215546Sopenharmony_ci   sx2 = (sbox->x + sbox->width) * nr_samples - 1;
648bf215546Sopenharmony_ci   sy2 = sbox->y + sbox->height - 1;
649bf215546Sopenharmony_ci
650bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_GRAS_2D_SRC_TL_X, 4);
651bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_X(sx1));
652bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_X(sx2));
653bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_Y(sy1));
654bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_Y(sy2));
655bf215546Sopenharmony_ci
656bf215546Sopenharmony_ci   dx1 = dbox->x * nr_samples;
657bf215546Sopenharmony_ci   dy1 = dbox->y;
658bf215546Sopenharmony_ci   dx2 = (dbox->x + dbox->width) * nr_samples - 1;
659bf215546Sopenharmony_ci   dy2 = dbox->y + dbox->height - 1;
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_GRAS_2D_DST_TL, 2);
662bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_DST_TL_X(dx1) | A6XX_GRAS_2D_DST_TL_Y(dy1));
663bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_DST_BR_X(dx2) | A6XX_GRAS_2D_DST_BR_Y(dy2));
664bf215546Sopenharmony_ci
665bf215546Sopenharmony_ci   if (info->scissor_enable) {
666bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_GRAS_2D_RESOLVE_CNTL_1, 2);
667bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_GRAS_2D_RESOLVE_CNTL_1_X(info->scissor.minx) |
668bf215546Sopenharmony_ci                        A6XX_GRAS_2D_RESOLVE_CNTL_1_Y(info->scissor.miny));
669bf215546Sopenharmony_ci      OUT_RING(ring, A6XX_GRAS_2D_RESOLVE_CNTL_1_X(info->scissor.maxx - 1) |
670bf215546Sopenharmony_ci                        A6XX_GRAS_2D_RESOLVE_CNTL_1_Y(info->scissor.maxy - 1));
671bf215546Sopenharmony_ci   }
672bf215546Sopenharmony_ci
673bf215546Sopenharmony_ci   emit_blit_setup(ring, info->dst.format, info->scissor_enable, NULL, 0);
674bf215546Sopenharmony_ci
675bf215546Sopenharmony_ci   for (unsigned i = 0; i < info->dst.box.depth; i++) {
676bf215546Sopenharmony_ci
677bf215546Sopenharmony_ci      emit_blit_src(ring, info, sbox->z + i, nr_samples, sample_0);
678bf215546Sopenharmony_ci      emit_blit_dst(ring, info->dst.resource, info->dst.format, info->dst.level,
679bf215546Sopenharmony_ci                    dbox->z + i);
680bf215546Sopenharmony_ci
681bf215546Sopenharmony_ci      /*
682bf215546Sopenharmony_ci       * Blit command:
683bf215546Sopenharmony_ci       */
684bf215546Sopenharmony_ci      OUT_PKT7(ring, CP_EVENT_WRITE, 1);
685bf215546Sopenharmony_ci      OUT_RING(ring, 0x3f);
686bf215546Sopenharmony_ci      OUT_WFI5(ring);
687bf215546Sopenharmony_ci
688bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
689bf215546Sopenharmony_ci      OUT_RING(ring, ctx->screen->info->a6xx.magic.RB_UNKNOWN_8E04_blit);
690bf215546Sopenharmony_ci
691bf215546Sopenharmony_ci      OUT_PKT7(ring, CP_BLIT, 1);
692bf215546Sopenharmony_ci      OUT_RING(ring, CP_BLIT_0_OP(BLIT_OP_SCALE));
693bf215546Sopenharmony_ci
694bf215546Sopenharmony_ci      OUT_WFI5(ring);
695bf215546Sopenharmony_ci
696bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
697bf215546Sopenharmony_ci      OUT_RING(ring, 0); /* RB_UNKNOWN_8E04 */
698bf215546Sopenharmony_ci   }
699bf215546Sopenharmony_ci}
700bf215546Sopenharmony_ci
701bf215546Sopenharmony_cistatic void
702bf215546Sopenharmony_ciemit_clear_color(struct fd_ringbuffer *ring, enum pipe_format pfmt,
703bf215546Sopenharmony_ci                 union pipe_color_union *color)
704bf215546Sopenharmony_ci{
705bf215546Sopenharmony_ci   switch (pfmt) {
706bf215546Sopenharmony_ci   case PIPE_FORMAT_Z24X8_UNORM:
707bf215546Sopenharmony_ci   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
708bf215546Sopenharmony_ci   case PIPE_FORMAT_X24S8_UINT: {
709bf215546Sopenharmony_ci      uint32_t depth_unorm24 = color->f[0] * ((1u << 24) - 1);
710bf215546Sopenharmony_ci      uint8_t stencil = color->ui[1];
711bf215546Sopenharmony_ci      color->ui[0] = depth_unorm24 & 0xff;
712bf215546Sopenharmony_ci      color->ui[1] = (depth_unorm24 >> 8) & 0xff;
713bf215546Sopenharmony_ci      color->ui[2] = (depth_unorm24 >> 16) & 0xff;
714bf215546Sopenharmony_ci      color->ui[3] = stencil;
715bf215546Sopenharmony_ci      break;
716bf215546Sopenharmony_ci   }
717bf215546Sopenharmony_ci   default:
718bf215546Sopenharmony_ci      break;
719bf215546Sopenharmony_ci   }
720bf215546Sopenharmony_ci
721bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_RB_2D_SRC_SOLID_C0, 4);
722bf215546Sopenharmony_ci   switch (fd6_ifmt(fd6_color_format(pfmt, TILE6_LINEAR))) {
723bf215546Sopenharmony_ci   case R2D_UNORM8:
724bf215546Sopenharmony_ci   case R2D_UNORM8_SRGB:
725bf215546Sopenharmony_ci      /* The r2d ifmt is badly named, it also covers the signed case: */
726bf215546Sopenharmony_ci      if (util_format_is_snorm(pfmt)) {
727bf215546Sopenharmony_ci         OUT_RING(ring, float_to_byte_tex(color->f[0]));
728bf215546Sopenharmony_ci         OUT_RING(ring, float_to_byte_tex(color->f[1]));
729bf215546Sopenharmony_ci         OUT_RING(ring, float_to_byte_tex(color->f[2]));
730bf215546Sopenharmony_ci         OUT_RING(ring, float_to_byte_tex(color->f[3]));
731bf215546Sopenharmony_ci      } else {
732bf215546Sopenharmony_ci         OUT_RING(ring, float_to_ubyte(color->f[0]));
733bf215546Sopenharmony_ci         OUT_RING(ring, float_to_ubyte(color->f[1]));
734bf215546Sopenharmony_ci         OUT_RING(ring, float_to_ubyte(color->f[2]));
735bf215546Sopenharmony_ci         OUT_RING(ring, float_to_ubyte(color->f[3]));
736bf215546Sopenharmony_ci      }
737bf215546Sopenharmony_ci      break;
738bf215546Sopenharmony_ci   case R2D_FLOAT16:
739bf215546Sopenharmony_ci      OUT_RING(ring, _mesa_float_to_half(color->f[0]));
740bf215546Sopenharmony_ci      OUT_RING(ring, _mesa_float_to_half(color->f[1]));
741bf215546Sopenharmony_ci      OUT_RING(ring, _mesa_float_to_half(color->f[2]));
742bf215546Sopenharmony_ci      OUT_RING(ring, _mesa_float_to_half(color->f[3]));
743bf215546Sopenharmony_ci      break;
744bf215546Sopenharmony_ci   case R2D_FLOAT32:
745bf215546Sopenharmony_ci   case R2D_INT32:
746bf215546Sopenharmony_ci   case R2D_INT16:
747bf215546Sopenharmony_ci   case R2D_INT8:
748bf215546Sopenharmony_ci   default:
749bf215546Sopenharmony_ci      OUT_RING(ring, color->ui[0]);
750bf215546Sopenharmony_ci      OUT_RING(ring, color->ui[1]);
751bf215546Sopenharmony_ci      OUT_RING(ring, color->ui[2]);
752bf215546Sopenharmony_ci      OUT_RING(ring, color->ui[3]);
753bf215546Sopenharmony_ci      break;
754bf215546Sopenharmony_ci   }
755bf215546Sopenharmony_ci}
756bf215546Sopenharmony_ci
757bf215546Sopenharmony_ci/**
758bf215546Sopenharmony_ci * Handle conversion of clear color
759bf215546Sopenharmony_ci */
760bf215546Sopenharmony_cistatic union pipe_color_union
761bf215546Sopenharmony_ciconvert_color(enum pipe_format format, union pipe_color_union *pcolor)
762bf215546Sopenharmony_ci{
763bf215546Sopenharmony_ci   union pipe_color_union color = *pcolor;
764bf215546Sopenharmony_ci
765bf215546Sopenharmony_ci   /* For solid-fill blits, the hw isn't going to convert from
766bf215546Sopenharmony_ci    * linear to srgb for us:
767bf215546Sopenharmony_ci    */
768bf215546Sopenharmony_ci   if (util_format_is_srgb(format)) {
769bf215546Sopenharmony_ci      for (int i = 0; i < 3; i++)
770bf215546Sopenharmony_ci         color.f[i] = util_format_linear_to_srgb_float(color.f[i]);
771bf215546Sopenharmony_ci   }
772bf215546Sopenharmony_ci
773bf215546Sopenharmony_ci   if (util_format_is_snorm(format)) {
774bf215546Sopenharmony_ci      for (int i = 0; i < 3; i++)
775bf215546Sopenharmony_ci         color.f[i] = CLAMP(color.f[i], -1.0f, 1.0f);
776bf215546Sopenharmony_ci   }
777bf215546Sopenharmony_ci
778bf215546Sopenharmony_ci   /* Note that float_to_ubyte() already clamps, for the unorm case */
779bf215546Sopenharmony_ci
780bf215546Sopenharmony_ci   return color;
781bf215546Sopenharmony_ci}
782bf215546Sopenharmony_ci
783bf215546Sopenharmony_civoid
784bf215546Sopenharmony_cifd6_clear_surface(struct fd_context *ctx, struct fd_ringbuffer *ring,
785bf215546Sopenharmony_ci                  struct pipe_surface *psurf, uint32_t width, uint32_t height,
786bf215546Sopenharmony_ci                  union pipe_color_union *color, uint32_t unknown_8c01)
787bf215546Sopenharmony_ci{
788bf215546Sopenharmony_ci   if (DEBUG_BLIT) {
789bf215546Sopenharmony_ci      fprintf(stderr, "surface clear:\ndst resource: ");
790bf215546Sopenharmony_ci      util_dump_resource(stderr, psurf->texture);
791bf215546Sopenharmony_ci      fprintf(stderr, "\n");
792bf215546Sopenharmony_ci   }
793bf215546Sopenharmony_ci
794bf215546Sopenharmony_ci   uint32_t nr_samples = fd_resource_nr_samples(psurf->texture);
795bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_GRAS_2D_DST_TL, 2);
796bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_DST_TL_X(0) | A6XX_GRAS_2D_DST_TL_Y(0));
797bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_DST_BR_X(width * nr_samples - 1) |
798bf215546Sopenharmony_ci                     A6XX_GRAS_2D_DST_BR_Y(height - 1));
799bf215546Sopenharmony_ci
800bf215546Sopenharmony_ci   union pipe_color_union clear_color = convert_color(psurf->format, color);
801bf215546Sopenharmony_ci
802bf215546Sopenharmony_ci   emit_clear_color(ring, psurf->format, &clear_color);
803bf215546Sopenharmony_ci   emit_blit_setup(ring, psurf->format, false, &clear_color, unknown_8c01);
804bf215546Sopenharmony_ci
805bf215546Sopenharmony_ci   for (unsigned i = psurf->u.tex.first_layer; i <= psurf->u.tex.last_layer;
806bf215546Sopenharmony_ci        i++) {
807bf215546Sopenharmony_ci      emit_blit_dst(ring, psurf->texture, psurf->format, psurf->u.tex.level, i);
808bf215546Sopenharmony_ci
809bf215546Sopenharmony_ci      /*
810bf215546Sopenharmony_ci       * Blit command:
811bf215546Sopenharmony_ci       */
812bf215546Sopenharmony_ci      OUT_PKT7(ring, CP_EVENT_WRITE, 1);
813bf215546Sopenharmony_ci      OUT_RING(ring, 0x3f);
814bf215546Sopenharmony_ci      OUT_WFI5(ring);
815bf215546Sopenharmony_ci
816bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
817bf215546Sopenharmony_ci      OUT_RING(ring, ctx->screen->info->a6xx.magic.RB_UNKNOWN_8E04_blit);
818bf215546Sopenharmony_ci
819bf215546Sopenharmony_ci      OUT_PKT7(ring, CP_BLIT, 1);
820bf215546Sopenharmony_ci      OUT_RING(ring, CP_BLIT_0_OP(BLIT_OP_SCALE));
821bf215546Sopenharmony_ci
822bf215546Sopenharmony_ci      OUT_WFI5(ring);
823bf215546Sopenharmony_ci
824bf215546Sopenharmony_ci      OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
825bf215546Sopenharmony_ci      OUT_RING(ring, 0); /* RB_UNKNOWN_8E04 */
826bf215546Sopenharmony_ci   }
827bf215546Sopenharmony_ci}
828bf215546Sopenharmony_ci
829bf215546Sopenharmony_civoid
830bf215546Sopenharmony_cifd6_resolve_tile(struct fd_batch *batch, struct fd_ringbuffer *ring,
831bf215546Sopenharmony_ci                 uint32_t base, struct pipe_surface *psurf, uint32_t unknown_8c01)
832bf215546Sopenharmony_ci{
833bf215546Sopenharmony_ci   const struct fd_gmem_stateobj *gmem = batch->gmem_state;
834bf215546Sopenharmony_ci   uint64_t gmem_base = batch->ctx->screen->gmem_base + base;
835bf215546Sopenharmony_ci   uint32_t gmem_pitch = gmem->bin_w * batch->framebuffer.samples *
836bf215546Sopenharmony_ci                         util_format_get_blocksize(psurf->format);
837bf215546Sopenharmony_ci
838bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_GRAS_2D_DST_TL, 2);
839bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_DST_TL_X(0) | A6XX_GRAS_2D_DST_TL_Y(0));
840bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_DST_BR_X(psurf->width - 1) |
841bf215546Sopenharmony_ci                     A6XX_GRAS_2D_DST_BR_Y(psurf->height - 1));
842bf215546Sopenharmony_ci
843bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_GRAS_2D_SRC_TL_X, 4);
844bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_X(0));
845bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_X(psurf->width - 1));
846bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_TL_Y(0));
847bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_GRAS_2D_SRC_BR_Y(psurf->height - 1));
848bf215546Sopenharmony_ci
849bf215546Sopenharmony_ci   /* Enable scissor bit, which will take into account the window scissor
850bf215546Sopenharmony_ci    * which is set per-tile
851bf215546Sopenharmony_ci    */
852bf215546Sopenharmony_ci   emit_blit_setup(ring, psurf->format, true, NULL, unknown_8c01);
853bf215546Sopenharmony_ci
854bf215546Sopenharmony_ci   /* We shouldn't be using GMEM in the layered rendering case: */
855bf215546Sopenharmony_ci   assert(psurf->u.tex.first_layer == psurf->u.tex.last_layer);
856bf215546Sopenharmony_ci
857bf215546Sopenharmony_ci   emit_blit_dst(ring, psurf->texture, psurf->format, psurf->u.tex.level,
858bf215546Sopenharmony_ci                 psurf->u.tex.first_layer);
859bf215546Sopenharmony_ci
860bf215546Sopenharmony_ci   enum a6xx_format sfmt = fd6_color_format(psurf->format, TILE6_LINEAR);
861bf215546Sopenharmony_ci   enum a3xx_msaa_samples samples = fd_msaa_samples(batch->framebuffer.samples);
862bf215546Sopenharmony_ci
863bf215546Sopenharmony_ci   OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 10);
864bf215546Sopenharmony_ci   OUT_RING(ring,
865bf215546Sopenharmony_ci            A6XX_SP_PS_2D_SRC_INFO_COLOR_FORMAT(sfmt) |
866bf215546Sopenharmony_ci            A6XX_SP_PS_2D_SRC_INFO_TILE_MODE(TILE6_2) |
867bf215546Sopenharmony_ci            A6XX_SP_PS_2D_SRC_INFO_SAMPLES(samples) |
868bf215546Sopenharmony_ci            COND(samples > MSAA_ONE, A6XX_SP_PS_2D_SRC_INFO_SAMPLES_AVERAGE) |
869bf215546Sopenharmony_ci            COND(util_format_is_srgb(psurf->format), A6XX_SP_PS_2D_SRC_INFO_SRGB) |
870bf215546Sopenharmony_ci            A6XX_SP_PS_2D_SRC_INFO_UNK20 | A6XX_SP_PS_2D_SRC_INFO_UNK22);
871bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_SP_PS_2D_SRC_SIZE_WIDTH(psurf->width) |
872bf215546Sopenharmony_ci                  A6XX_SP_PS_2D_SRC_SIZE_HEIGHT(psurf->height));
873bf215546Sopenharmony_ci   OUT_RING(ring, gmem_base);       /* SP_PS_2D_SRC_LO */
874bf215546Sopenharmony_ci   OUT_RING(ring, gmem_base >> 32); /* SP_PS_2D_SRC_HI */
875bf215546Sopenharmony_ci   OUT_RING(ring, A6XX_SP_PS_2D_SRC_PITCH_PITCH(gmem_pitch));
876bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
877bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
878bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
879bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
880bf215546Sopenharmony_ci   OUT_RING(ring, 0x00000000);
881bf215546Sopenharmony_ci
882bf215546Sopenharmony_ci   /* sync GMEM writes with CACHE. */
883bf215546Sopenharmony_ci   fd6_cache_inv(batch, ring);
884bf215546Sopenharmony_ci
885bf215546Sopenharmony_ci   /* Wait for CACHE_INVALIDATE to land */
886bf215546Sopenharmony_ci   fd_wfi(batch, ring);
887bf215546Sopenharmony_ci
888bf215546Sopenharmony_ci   OUT_PKT7(ring, CP_BLIT, 1);
889bf215546Sopenharmony_ci   OUT_RING(ring, CP_BLIT_0_OP(BLIT_OP_SCALE));
890bf215546Sopenharmony_ci
891bf215546Sopenharmony_ci   OUT_WFI5(ring);
892bf215546Sopenharmony_ci
893bf215546Sopenharmony_ci   /* CP_BLIT writes to the CCU, unlike CP_EVENT_WRITE::BLIT which writes to
894bf215546Sopenharmony_ci    * sysmem, and we generally assume that GMEM renderpasses leave their
895bf215546Sopenharmony_ci    * results in sysmem, so we need to flush manually here.
896bf215546Sopenharmony_ci    */
897bf215546Sopenharmony_ci   fd6_event_write(batch, ring, PC_CCU_FLUSH_COLOR_TS, true);
898bf215546Sopenharmony_ci   fd_wfi(batch, ring);
899bf215546Sopenharmony_ci}
900bf215546Sopenharmony_ci
901bf215546Sopenharmony_cistatic bool
902bf215546Sopenharmony_cihandle_rgba_blit(struct fd_context *ctx,
903bf215546Sopenharmony_ci                 const struct pipe_blit_info *info, bool sample_0) assert_dt
904bf215546Sopenharmony_ci{
905bf215546Sopenharmony_ci   struct fd_batch *batch;
906bf215546Sopenharmony_ci
907bf215546Sopenharmony_ci   assert(!(info->mask & PIPE_MASK_ZS));
908bf215546Sopenharmony_ci
909bf215546Sopenharmony_ci   if (!can_do_blit(info))
910bf215546Sopenharmony_ci      return false;
911bf215546Sopenharmony_ci
912bf215546Sopenharmony_ci   struct fd_resource *src = fd_resource(info->src.resource);
913bf215546Sopenharmony_ci   struct fd_resource *dst = fd_resource(info->dst.resource);
914bf215546Sopenharmony_ci
915bf215546Sopenharmony_ci   fd6_validate_format(ctx, src, info->src.format);
916bf215546Sopenharmony_ci   fd6_validate_format(ctx, dst, info->dst.format);
917bf215546Sopenharmony_ci
918bf215546Sopenharmony_ci   batch = fd_bc_alloc_batch(ctx, true);
919bf215546Sopenharmony_ci
920bf215546Sopenharmony_ci   fd_screen_lock(ctx->screen);
921bf215546Sopenharmony_ci
922bf215546Sopenharmony_ci   fd_batch_resource_read(batch, src);
923bf215546Sopenharmony_ci   fd_batch_resource_write(batch, dst);
924bf215546Sopenharmony_ci
925bf215546Sopenharmony_ci   fd_screen_unlock(ctx->screen);
926bf215546Sopenharmony_ci
927bf215546Sopenharmony_ci   ASSERTED bool ret = fd_batch_lock_submit(batch);
928bf215546Sopenharmony_ci   assert(ret);
929bf215546Sopenharmony_ci
930bf215546Sopenharmony_ci   /* Marking the batch as needing flush must come after the batch
931bf215546Sopenharmony_ci    * dependency tracking (resource_read()/resource_write()), as that
932bf215546Sopenharmony_ci    * can trigger a flush
933bf215546Sopenharmony_ci    */
934bf215546Sopenharmony_ci   fd_batch_needs_flush(batch);
935bf215546Sopenharmony_ci
936bf215546Sopenharmony_ci   fd_batch_update_queries(batch);
937bf215546Sopenharmony_ci
938bf215546Sopenharmony_ci   emit_setup(batch);
939bf215546Sopenharmony_ci
940bf215546Sopenharmony_ci   DBG_BLIT(info, batch);
941bf215546Sopenharmony_ci
942bf215546Sopenharmony_ci   trace_start_blit(&batch->trace, batch->draw, info->src.resource->target,
943bf215546Sopenharmony_ci                    info->dst.resource->target);
944bf215546Sopenharmony_ci
945bf215546Sopenharmony_ci   if ((info->src.resource->target == PIPE_BUFFER) &&
946bf215546Sopenharmony_ci       (info->dst.resource->target == PIPE_BUFFER)) {
947bf215546Sopenharmony_ci      assert(src->layout.tile_mode == TILE6_LINEAR);
948bf215546Sopenharmony_ci      assert(dst->layout.tile_mode == TILE6_LINEAR);
949bf215546Sopenharmony_ci      emit_blit_buffer(ctx, batch->draw, info);
950bf215546Sopenharmony_ci   } else {
951bf215546Sopenharmony_ci      /* I don't *think* we need to handle blits between buffer <-> !buffer */
952bf215546Sopenharmony_ci      assert(info->src.resource->target != PIPE_BUFFER);
953bf215546Sopenharmony_ci      assert(info->dst.resource->target != PIPE_BUFFER);
954bf215546Sopenharmony_ci      emit_blit_texture(ctx, batch->draw, info, sample_0);
955bf215546Sopenharmony_ci   }
956bf215546Sopenharmony_ci
957bf215546Sopenharmony_ci   trace_end_blit(&batch->trace, batch->draw);
958bf215546Sopenharmony_ci
959bf215546Sopenharmony_ci   fd6_event_write(batch, batch->draw, PC_CCU_FLUSH_COLOR_TS, true);
960bf215546Sopenharmony_ci   fd6_event_write(batch, batch->draw, PC_CCU_FLUSH_DEPTH_TS, true);
961bf215546Sopenharmony_ci   fd6_event_write(batch, batch->draw, CACHE_FLUSH_TS, true);
962bf215546Sopenharmony_ci   fd_wfi(batch, batch->draw);
963bf215546Sopenharmony_ci   fd6_cache_inv(batch, batch->draw);
964bf215546Sopenharmony_ci
965bf215546Sopenharmony_ci   fd_batch_unlock_submit(batch);
966bf215546Sopenharmony_ci
967bf215546Sopenharmony_ci   fd_batch_flush(batch);
968bf215546Sopenharmony_ci   fd_batch_reference(&batch, NULL);
969bf215546Sopenharmony_ci
970bf215546Sopenharmony_ci   /* Acc query state will have been dirtied by our fd_batch_update_queries, so
971bf215546Sopenharmony_ci    * the ctx->batch may need to turn its queries back on.
972bf215546Sopenharmony_ci    */
973bf215546Sopenharmony_ci   ctx->update_active_queries = true;
974bf215546Sopenharmony_ci
975bf215546Sopenharmony_ci   return true;
976bf215546Sopenharmony_ci}
977bf215546Sopenharmony_ci
978bf215546Sopenharmony_ci/**
979bf215546Sopenharmony_ci * Re-written z/s blits can still fail for various reasons (for example MSAA).
980bf215546Sopenharmony_ci * But we want to do the fallback blit with the re-written pipe_blit_info,
981bf215546Sopenharmony_ci * in particular as u_blitter cannot blit stencil.  So handle the fallback
982bf215546Sopenharmony_ci * ourself and never "fail".
983bf215546Sopenharmony_ci */
984bf215546Sopenharmony_cistatic bool
985bf215546Sopenharmony_cido_rewritten_blit(struct fd_context *ctx,
986bf215546Sopenharmony_ci                  const struct pipe_blit_info *info, bool sample_0) assert_dt
987bf215546Sopenharmony_ci{
988bf215546Sopenharmony_ci   bool success = handle_rgba_blit(ctx, info, sample_0);
989bf215546Sopenharmony_ci   if (!success) {
990bf215546Sopenharmony_ci      if (sample_0 && !util_format_is_pure_integer(info->src.format))
991bf215546Sopenharmony_ci         mesa_logw("sample averaging on fallback blit when we shouldn't.");
992bf215546Sopenharmony_ci      success = fd_blitter_blit(ctx, info);
993bf215546Sopenharmony_ci   }
994bf215546Sopenharmony_ci   assert(success); /* fallback should never fail! */
995bf215546Sopenharmony_ci   return success;
996bf215546Sopenharmony_ci}
997bf215546Sopenharmony_ci
998bf215546Sopenharmony_ci/**
999bf215546Sopenharmony_ci * Handle depth/stencil blits either via u_blitter and/or re-writing the
1000bf215546Sopenharmony_ci * blit into an equivilant format that we can handle
1001bf215546Sopenharmony_ci */
1002bf215546Sopenharmony_cistatic bool
1003bf215546Sopenharmony_cihandle_zs_blit(struct fd_context *ctx,
1004bf215546Sopenharmony_ci               const struct pipe_blit_info *info) assert_dt
1005bf215546Sopenharmony_ci{
1006bf215546Sopenharmony_ci   struct pipe_blit_info blit = *info;
1007bf215546Sopenharmony_ci
1008bf215546Sopenharmony_ci   if (DEBUG_BLIT) {
1009bf215546Sopenharmony_ci      fprintf(stderr, "---- handle_zs_blit: ");
1010bf215546Sopenharmony_ci      dump_blit_info(info);
1011bf215546Sopenharmony_ci   }
1012bf215546Sopenharmony_ci
1013bf215546Sopenharmony_ci   if (info->src.format != info->dst.format)
1014bf215546Sopenharmony_ci      return false;
1015bf215546Sopenharmony_ci
1016bf215546Sopenharmony_ci   struct fd_resource *src = fd_resource(info->src.resource);
1017bf215546Sopenharmony_ci   struct fd_resource *dst = fd_resource(info->dst.resource);
1018bf215546Sopenharmony_ci
1019bf215546Sopenharmony_ci   switch (info->dst.format) {
1020bf215546Sopenharmony_ci   case PIPE_FORMAT_S8_UINT:
1021bf215546Sopenharmony_ci      assert(info->mask == PIPE_MASK_S);
1022bf215546Sopenharmony_ci      blit.mask = PIPE_MASK_R;
1023bf215546Sopenharmony_ci      blit.src.format = PIPE_FORMAT_R8_UINT;
1024bf215546Sopenharmony_ci      blit.dst.format = PIPE_FORMAT_R8_UINT;
1025bf215546Sopenharmony_ci      return do_rewritten_blit(ctx, &blit, true);
1026bf215546Sopenharmony_ci
1027bf215546Sopenharmony_ci   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
1028bf215546Sopenharmony_ci      if (info->mask & PIPE_MASK_Z) {
1029bf215546Sopenharmony_ci         blit.mask = PIPE_MASK_R;
1030bf215546Sopenharmony_ci         blit.src.format = PIPE_FORMAT_R32_FLOAT;
1031bf215546Sopenharmony_ci         blit.dst.format = PIPE_FORMAT_R32_FLOAT;
1032bf215546Sopenharmony_ci         do_rewritten_blit(ctx, &blit, true);
1033bf215546Sopenharmony_ci      }
1034bf215546Sopenharmony_ci
1035bf215546Sopenharmony_ci      if (info->mask & PIPE_MASK_S) {
1036bf215546Sopenharmony_ci         blit.mask = PIPE_MASK_R;
1037bf215546Sopenharmony_ci         blit.src.format = PIPE_FORMAT_R8_UINT;
1038bf215546Sopenharmony_ci         blit.dst.format = PIPE_FORMAT_R8_UINT;
1039bf215546Sopenharmony_ci         blit.src.resource = &src->stencil->b.b;
1040bf215546Sopenharmony_ci         blit.dst.resource = &dst->stencil->b.b;
1041bf215546Sopenharmony_ci         do_rewritten_blit(ctx, &blit, true);
1042bf215546Sopenharmony_ci      }
1043bf215546Sopenharmony_ci
1044bf215546Sopenharmony_ci      return true;
1045bf215546Sopenharmony_ci
1046bf215546Sopenharmony_ci   case PIPE_FORMAT_Z16_UNORM:
1047bf215546Sopenharmony_ci      blit.mask = PIPE_MASK_R;
1048bf215546Sopenharmony_ci      blit.src.format = PIPE_FORMAT_R16_UNORM;
1049bf215546Sopenharmony_ci      blit.dst.format = PIPE_FORMAT_R16_UNORM;
1050bf215546Sopenharmony_ci      return do_rewritten_blit(ctx, &blit, true);
1051bf215546Sopenharmony_ci
1052bf215546Sopenharmony_ci   case PIPE_FORMAT_Z32_UNORM:
1053bf215546Sopenharmony_ci   case PIPE_FORMAT_Z32_FLOAT:
1054bf215546Sopenharmony_ci      assert(info->mask == PIPE_MASK_Z);
1055bf215546Sopenharmony_ci      blit.mask = PIPE_MASK_R;
1056bf215546Sopenharmony_ci      blit.src.format = PIPE_FORMAT_R32_UINT;
1057bf215546Sopenharmony_ci      blit.dst.format = PIPE_FORMAT_R32_UINT;
1058bf215546Sopenharmony_ci      return do_rewritten_blit(ctx, &blit, true);
1059bf215546Sopenharmony_ci
1060bf215546Sopenharmony_ci   case PIPE_FORMAT_Z24X8_UNORM:
1061bf215546Sopenharmony_ci   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
1062bf215546Sopenharmony_ci      blit.mask = 0;
1063bf215546Sopenharmony_ci      if (info->mask & PIPE_MASK_Z)
1064bf215546Sopenharmony_ci         blit.mask |= PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B;
1065bf215546Sopenharmony_ci      if (info->mask & PIPE_MASK_S)
1066bf215546Sopenharmony_ci         blit.mask |= PIPE_MASK_A;
1067bf215546Sopenharmony_ci      blit.src.format = PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8;
1068bf215546Sopenharmony_ci      blit.dst.format = PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8;
1069bf215546Sopenharmony_ci      /* non-UBWC Z24_UNORM_S8_UINT_AS_R8G8B8A8 is broken on a630, fall back to
1070bf215546Sopenharmony_ci       * 8888_unorm.
1071bf215546Sopenharmony_ci       */
1072bf215546Sopenharmony_ci      if (!ctx->screen->info->a6xx.has_z24uint_s8uint) {
1073bf215546Sopenharmony_ci         if (!src->layout.ubwc && !dst->layout.ubwc) {
1074bf215546Sopenharmony_ci            blit.src.format = PIPE_FORMAT_RGBA8888_UINT;
1075bf215546Sopenharmony_ci            blit.dst.format = PIPE_FORMAT_RGBA8888_UINT;
1076bf215546Sopenharmony_ci         } else {
1077bf215546Sopenharmony_ci            if (!src->layout.ubwc)
1078bf215546Sopenharmony_ci               blit.src.format = PIPE_FORMAT_RGBA8888_UNORM;
1079bf215546Sopenharmony_ci            if (!dst->layout.ubwc)
1080bf215546Sopenharmony_ci               blit.dst.format = PIPE_FORMAT_RGBA8888_UNORM;
1081bf215546Sopenharmony_ci         }
1082bf215546Sopenharmony_ci      }
1083bf215546Sopenharmony_ci      if (info->src.resource->nr_samples > 1 && blit.src.format != PIPE_FORMAT_RGBA8888_UINT)
1084bf215546Sopenharmony_ci         mesa_logw("sample averaging on fallback z24s8 blit when we shouldn't.");
1085bf215546Sopenharmony_ci      return fd_blitter_blit(ctx, &blit);
1086bf215546Sopenharmony_ci
1087bf215546Sopenharmony_ci   default:
1088bf215546Sopenharmony_ci      return false;
1089bf215546Sopenharmony_ci   }
1090bf215546Sopenharmony_ci}
1091bf215546Sopenharmony_ci
1092bf215546Sopenharmony_cistatic bool
1093bf215546Sopenharmony_cihandle_compressed_blit(struct fd_context *ctx,
1094bf215546Sopenharmony_ci                       const struct pipe_blit_info *info) assert_dt
1095bf215546Sopenharmony_ci{
1096bf215546Sopenharmony_ci   struct pipe_blit_info blit = *info;
1097bf215546Sopenharmony_ci
1098bf215546Sopenharmony_ci   if (DEBUG_BLIT) {
1099bf215546Sopenharmony_ci      fprintf(stderr, "---- handle_compressed_blit: ");
1100bf215546Sopenharmony_ci      dump_blit_info(info);
1101bf215546Sopenharmony_ci   }
1102bf215546Sopenharmony_ci
1103bf215546Sopenharmony_ci   if (info->src.format != info->dst.format)
1104bf215546Sopenharmony_ci      return fd_blitter_blit(ctx, info);
1105bf215546Sopenharmony_ci
1106bf215546Sopenharmony_ci   if (util_format_get_blocksize(info->src.format) == 8) {
1107bf215546Sopenharmony_ci      blit.src.format = blit.dst.format = PIPE_FORMAT_R16G16B16A16_UINT;
1108bf215546Sopenharmony_ci   } else {
1109bf215546Sopenharmony_ci      assert(util_format_get_blocksize(info->src.format) == 16);
1110bf215546Sopenharmony_ci      blit.src.format = blit.dst.format = PIPE_FORMAT_R32G32B32A32_UINT;
1111bf215546Sopenharmony_ci   }
1112bf215546Sopenharmony_ci
1113bf215546Sopenharmony_ci   int bw = util_format_get_blockwidth(info->src.format);
1114bf215546Sopenharmony_ci   int bh = util_format_get_blockheight(info->src.format);
1115bf215546Sopenharmony_ci
1116bf215546Sopenharmony_ci   /* NOTE: x/y *must* be aligned to block boundary (ie. in
1117bf215546Sopenharmony_ci    * glCompressedTexSubImage2D()) but width/height may not
1118bf215546Sopenharmony_ci    * be:
1119bf215546Sopenharmony_ci    */
1120bf215546Sopenharmony_ci
1121bf215546Sopenharmony_ci   assert((blit.src.box.x % bw) == 0);
1122bf215546Sopenharmony_ci   assert((blit.src.box.y % bh) == 0);
1123bf215546Sopenharmony_ci
1124bf215546Sopenharmony_ci   blit.src.box.x /= bw;
1125bf215546Sopenharmony_ci   blit.src.box.y /= bh;
1126bf215546Sopenharmony_ci   blit.src.box.width = DIV_ROUND_UP(blit.src.box.width, bw);
1127bf215546Sopenharmony_ci   blit.src.box.height = DIV_ROUND_UP(blit.src.box.height, bh);
1128bf215546Sopenharmony_ci
1129bf215546Sopenharmony_ci   assert((blit.dst.box.x % bw) == 0);
1130bf215546Sopenharmony_ci   assert((blit.dst.box.y % bh) == 0);
1131bf215546Sopenharmony_ci
1132bf215546Sopenharmony_ci   blit.dst.box.x /= bw;
1133bf215546Sopenharmony_ci   blit.dst.box.y /= bh;
1134bf215546Sopenharmony_ci   blit.dst.box.width = DIV_ROUND_UP(blit.dst.box.width, bw);
1135bf215546Sopenharmony_ci   blit.dst.box.height = DIV_ROUND_UP(blit.dst.box.height, bh);
1136bf215546Sopenharmony_ci
1137bf215546Sopenharmony_ci   return do_rewritten_blit(ctx, &blit, false);
1138bf215546Sopenharmony_ci}
1139bf215546Sopenharmony_ci
1140bf215546Sopenharmony_ci/**
1141bf215546Sopenharmony_ci * For SNORM formats, copy them as the equivalent UNORM format.  If we treat
1142bf215546Sopenharmony_ci * them as snorm then the 0x80 (-1.0 snorm8) value will get clamped to 0x81
1143bf215546Sopenharmony_ci * (also -1.0), when we're supposed to be memcpying the bits. See
1144bf215546Sopenharmony_ci * https://gitlab.khronos.org/Tracker/vk-gl-cts/-/issues/2917 for discussion.
1145bf215546Sopenharmony_ci */
1146bf215546Sopenharmony_cistatic bool
1147bf215546Sopenharmony_cihandle_snorm_copy_blit(struct fd_context *ctx,
1148bf215546Sopenharmony_ci                       const struct pipe_blit_info *info)
1149bf215546Sopenharmony_ci   assert_dt
1150bf215546Sopenharmony_ci{
1151bf215546Sopenharmony_ci   /* If we're interpolating the pixels, we can't just treat the values as unorm. */
1152bf215546Sopenharmony_ci   if (info->filter == PIPE_TEX_FILTER_LINEAR)
1153bf215546Sopenharmony_ci      return false;
1154bf215546Sopenharmony_ci
1155bf215546Sopenharmony_ci   struct pipe_blit_info blit = *info;
1156bf215546Sopenharmony_ci
1157bf215546Sopenharmony_ci   blit.src.format = blit.dst.format = util_format_snorm_to_unorm(info->src.format);
1158bf215546Sopenharmony_ci
1159bf215546Sopenharmony_ci   return do_rewritten_blit(ctx, &blit, false);
1160bf215546Sopenharmony_ci}
1161bf215546Sopenharmony_ci
1162bf215546Sopenharmony_cistatic bool
1163bf215546Sopenharmony_cifd6_blit(struct fd_context *ctx, const struct pipe_blit_info *info) assert_dt
1164bf215546Sopenharmony_ci{
1165bf215546Sopenharmony_ci   if (info->mask & PIPE_MASK_ZS)
1166bf215546Sopenharmony_ci      return handle_zs_blit(ctx, info);
1167bf215546Sopenharmony_ci
1168bf215546Sopenharmony_ci   if (util_format_is_compressed(info->src.format) ||
1169bf215546Sopenharmony_ci       util_format_is_compressed(info->dst.format))
1170bf215546Sopenharmony_ci      return handle_compressed_blit(ctx, info);
1171bf215546Sopenharmony_ci
1172bf215546Sopenharmony_ci   if ((info->src.format == info->dst.format) &&
1173bf215546Sopenharmony_ci       util_format_is_snorm(info->src.format))
1174bf215546Sopenharmony_ci      return handle_snorm_copy_blit(ctx, info);
1175bf215546Sopenharmony_ci
1176bf215546Sopenharmony_ci   return handle_rgba_blit(ctx, info, false);
1177bf215546Sopenharmony_ci}
1178bf215546Sopenharmony_ci
1179bf215546Sopenharmony_civoid
1180bf215546Sopenharmony_cifd6_blitter_init(struct pipe_context *pctx) disable_thread_safety_analysis
1181bf215546Sopenharmony_ci{
1182bf215546Sopenharmony_ci   struct fd_context *ctx = fd_context(pctx);
1183bf215546Sopenharmony_ci
1184bf215546Sopenharmony_ci   ctx->clear_ubwc = fd6_clear_ubwc;
1185bf215546Sopenharmony_ci   ctx->validate_format = fd6_validate_format;
1186bf215546Sopenharmony_ci
1187bf215546Sopenharmony_ci   if (FD_DBG(NOBLIT))
1188bf215546Sopenharmony_ci      return;
1189bf215546Sopenharmony_ci
1190bf215546Sopenharmony_ci   ctx->blit = fd6_blit;
1191bf215546Sopenharmony_ci}
1192bf215546Sopenharmony_ci
1193bf215546Sopenharmony_ciunsigned
1194bf215546Sopenharmony_cifd6_tile_mode(const struct pipe_resource *tmpl)
1195bf215546Sopenharmony_ci{
1196bf215546Sopenharmony_ci   /* if the mipmap level 0 is still too small to be tiled, then don't
1197bf215546Sopenharmony_ci    * bother pretending:
1198bf215546Sopenharmony_ci    */
1199bf215546Sopenharmony_ci   if (fd_resource_level_linear(tmpl, 0))
1200bf215546Sopenharmony_ci      return TILE6_LINEAR;
1201bf215546Sopenharmony_ci
1202bf215546Sopenharmony_ci   /* basically just has to be a format we can blit, so uploads/downloads
1203bf215546Sopenharmony_ci    * via linear staging buffer works:
1204bf215546Sopenharmony_ci    */
1205bf215546Sopenharmony_ci   if (ok_format(tmpl->format))
1206bf215546Sopenharmony_ci      return TILE6_3;
1207bf215546Sopenharmony_ci
1208bf215546Sopenharmony_ci   return TILE6_LINEAR;
1209bf215546Sopenharmony_ci}
1210