1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2018 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 "drm-uapi/drm_fourcc.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "fd6_resource.h"
31bf215546Sopenharmony_ci#include "fdl/fd6_format_table.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "a6xx.xml.h"
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci/* A subset of the valid tiled formats can be compressed.  We do
36bf215546Sopenharmony_ci * already require tiled in order to be compressed, but just because
37bf215546Sopenharmony_ci * it can be tiled doesn't mean it can be compressed.
38bf215546Sopenharmony_ci */
39bf215546Sopenharmony_cistatic bool
40bf215546Sopenharmony_ciok_ubwc_format(struct pipe_screen *pscreen, enum pipe_format pfmt)
41bf215546Sopenharmony_ci{
42bf215546Sopenharmony_ci   const struct fd_dev_info *info = fd_screen(pscreen)->info;
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci   switch (pfmt) {
45bf215546Sopenharmony_ci   case PIPE_FORMAT_X24S8_UINT:
46bf215546Sopenharmony_ci   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
47bf215546Sopenharmony_ci      /* We can't sample stencil with UBWC on a630, and we may need to be able
48bf215546Sopenharmony_ci       * to sample stencil at some point.  We can't just use
49bf215546Sopenharmony_ci       * fd_resource_uncompress() at the point of stencil sampling because
50bf215546Sopenharmony_ci       * that itself uses stencil sampling in the fd_blitter_blit path.
51bf215546Sopenharmony_ci       */
52bf215546Sopenharmony_ci      return info->a6xx.has_z24uint_s8uint;
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci   case PIPE_FORMAT_R8_G8B8_420_UNORM:
55bf215546Sopenharmony_ci      return true;
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci   default:
58bf215546Sopenharmony_ci      break;
59bf215546Sopenharmony_ci   }
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   switch (fd6_color_format(pfmt, TILE6_LINEAR)) {
62bf215546Sopenharmony_ci   case FMT6_10_10_10_2_UINT:
63bf215546Sopenharmony_ci   case FMT6_10_10_10_2_UNORM_DEST:
64bf215546Sopenharmony_ci   case FMT6_11_11_10_FLOAT:
65bf215546Sopenharmony_ci   case FMT6_16_FLOAT:
66bf215546Sopenharmony_ci   case FMT6_16_16_16_16_FLOAT:
67bf215546Sopenharmony_ci   case FMT6_16_16_16_16_SINT:
68bf215546Sopenharmony_ci   case FMT6_16_16_16_16_UINT:
69bf215546Sopenharmony_ci   case FMT6_16_16_FLOAT:
70bf215546Sopenharmony_ci   case FMT6_16_16_SINT:
71bf215546Sopenharmony_ci   case FMT6_16_16_UINT:
72bf215546Sopenharmony_ci   case FMT6_16_SINT:
73bf215546Sopenharmony_ci   case FMT6_16_UINT:
74bf215546Sopenharmony_ci   case FMT6_32_32_32_32_SINT:
75bf215546Sopenharmony_ci   case FMT6_32_32_32_32_UINT:
76bf215546Sopenharmony_ci   case FMT6_32_32_SINT:
77bf215546Sopenharmony_ci   case FMT6_32_32_UINT:
78bf215546Sopenharmony_ci   case FMT6_5_6_5_UNORM:
79bf215546Sopenharmony_ci   case FMT6_5_5_5_1_UNORM:
80bf215546Sopenharmony_ci   case FMT6_8_8_8_8_SINT:
81bf215546Sopenharmony_ci   case FMT6_8_8_8_8_UINT:
82bf215546Sopenharmony_ci   case FMT6_8_8_8_8_UNORM:
83bf215546Sopenharmony_ci   case FMT6_8_8_8_X8_UNORM:
84bf215546Sopenharmony_ci   case FMT6_8_8_SINT:
85bf215546Sopenharmony_ci   case FMT6_8_8_UINT:
86bf215546Sopenharmony_ci   case FMT6_8_8_UNORM:
87bf215546Sopenharmony_ci   case FMT6_Z24_UNORM_S8_UINT:
88bf215546Sopenharmony_ci   case FMT6_Z24_UNORM_S8_UINT_AS_R8G8B8A8:
89bf215546Sopenharmony_ci      return true;
90bf215546Sopenharmony_ci   case FMT6_8_UNORM:
91bf215546Sopenharmony_ci      return info->a6xx.has_8bpp_ubwc;
92bf215546Sopenharmony_ci   default:
93bf215546Sopenharmony_ci      return false;
94bf215546Sopenharmony_ci   }
95bf215546Sopenharmony_ci}
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_cistatic bool
98bf215546Sopenharmony_cican_do_ubwc(struct pipe_resource *prsc)
99bf215546Sopenharmony_ci{
100bf215546Sopenharmony_ci   /* limit things to simple single level 2d for now: */
101bf215546Sopenharmony_ci   if ((prsc->depth0 != 1) || (prsc->array_size != 1) ||
102bf215546Sopenharmony_ci       (prsc->last_level != 0))
103bf215546Sopenharmony_ci      return false;
104bf215546Sopenharmony_ci   if (prsc->target != PIPE_TEXTURE_2D)
105bf215546Sopenharmony_ci      return false;
106bf215546Sopenharmony_ci   if (!ok_ubwc_format(prsc->screen, prsc->format))
107bf215546Sopenharmony_ci      return false;
108bf215546Sopenharmony_ci   return true;
109bf215546Sopenharmony_ci}
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_cistatic bool
112bf215546Sopenharmony_ciis_norm(enum pipe_format format)
113bf215546Sopenharmony_ci{
114bf215546Sopenharmony_ci   const struct util_format_description *desc = util_format_description(format);
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   return desc->is_snorm || desc->is_unorm;
117bf215546Sopenharmony_ci}
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_cistatic bool
120bf215546Sopenharmony_civalid_format_cast(struct fd_resource *rsc, enum pipe_format format)
121bf215546Sopenharmony_ci{
122bf215546Sopenharmony_ci   /* Special case "casting" format in hw: */
123bf215546Sopenharmony_ci   if (format == PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8)
124bf215546Sopenharmony_ci      return true;
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_ci   /* For some color values (just "solid white") compression metadata maps to
127bf215546Sopenharmony_ci    * different pixel values for uint/sint vs unorm/snorm, so we can't reliably
128bf215546Sopenharmony_ci    * "cast" u/snorm to u/sint and visa versa:
129bf215546Sopenharmony_ci    */
130bf215546Sopenharmony_ci   if (is_norm(format) != is_norm(rsc->b.b.format))
131bf215546Sopenharmony_ci      return false;
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   /* The UBWC formats can be re-interpreted so long as the components
134bf215546Sopenharmony_ci    * have the same # of bits
135bf215546Sopenharmony_ci    */
136bf215546Sopenharmony_ci   for (unsigned i = 0; i < 4; i++) {
137bf215546Sopenharmony_ci      unsigned sb, db;
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci      sb = util_format_get_component_bits(rsc->b.b.format, UTIL_FORMAT_COLORSPACE_RGB, i);
140bf215546Sopenharmony_ci      db = util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, i);
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci      if (sb != db)
143bf215546Sopenharmony_ci         return false;
144bf215546Sopenharmony_ci   }
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci   return true;
147bf215546Sopenharmony_ci}
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci/**
150bf215546Sopenharmony_ci * R8G8 have a different block width/height and height alignment from other
151bf215546Sopenharmony_ci * formats that would normally be compatible (like R16), and so if we are
152bf215546Sopenharmony_ci * trying to, for example, sample R16 as R8G8 we need to demote to linear.
153bf215546Sopenharmony_ci */
154bf215546Sopenharmony_cistatic bool
155bf215546Sopenharmony_ciis_r8g8(enum pipe_format format)
156bf215546Sopenharmony_ci{
157bf215546Sopenharmony_ci   return (util_format_get_blocksize(format) == 2) &&
158bf215546Sopenharmony_ci         (util_format_get_nr_components(format) == 2);
159bf215546Sopenharmony_ci}
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci/**
162bf215546Sopenharmony_ci * Ensure the rsc is in an ok state to be used with the specified format.
163bf215546Sopenharmony_ci * This handles the case of UBWC buffers used with non-UBWC compatible
164bf215546Sopenharmony_ci * formats, by triggering an uncompress.
165bf215546Sopenharmony_ci */
166bf215546Sopenharmony_civoid
167bf215546Sopenharmony_cifd6_validate_format(struct fd_context *ctx, struct fd_resource *rsc,
168bf215546Sopenharmony_ci                    enum pipe_format format)
169bf215546Sopenharmony_ci{
170bf215546Sopenharmony_ci   enum pipe_format orig_format = rsc->b.b.format;
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci   tc_assert_driver_thread(ctx->tc);
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci   if (orig_format == format)
175bf215546Sopenharmony_ci      return;
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   if (rsc->layout.tile_mode && (is_r8g8(orig_format) != is_r8g8(format))) {
178bf215546Sopenharmony_ci      perf_debug_ctx(ctx,
179bf215546Sopenharmony_ci                     "%" PRSC_FMT ": demoted to linear+uncompressed due to use as %s",
180bf215546Sopenharmony_ci                     PRSC_ARGS(&rsc->b.b), util_format_short_name(format));
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci      fd_resource_uncompress(ctx, rsc, true);
183bf215546Sopenharmony_ci      return;
184bf215546Sopenharmony_ci   }
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   if (!rsc->layout.ubwc)
187bf215546Sopenharmony_ci      return;
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   if (ok_ubwc_format(rsc->b.b.screen, format) && valid_format_cast(rsc, format))
190bf215546Sopenharmony_ci      return;
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   perf_debug_ctx(ctx,
193bf215546Sopenharmony_ci                  "%" PRSC_FMT ": demoted to uncompressed due to use as %s",
194bf215546Sopenharmony_ci                  PRSC_ARGS(&rsc->b.b), util_format_short_name(format));
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   fd_resource_uncompress(ctx, rsc, false);
197bf215546Sopenharmony_ci}
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_cistatic void
200bf215546Sopenharmony_cisetup_lrz(struct fd_resource *rsc)
201bf215546Sopenharmony_ci{
202bf215546Sopenharmony_ci   struct fd_screen *screen = fd_screen(rsc->b.b.screen);
203bf215546Sopenharmony_ci   unsigned width0 = rsc->b.b.width0;
204bf215546Sopenharmony_ci   unsigned height0 = rsc->b.b.height0;
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   /* LRZ buffer is super-sampled: */
207bf215546Sopenharmony_ci   switch (rsc->b.b.nr_samples) {
208bf215546Sopenharmony_ci   case 4:
209bf215546Sopenharmony_ci      width0 *= 2;
210bf215546Sopenharmony_ci      FALLTHROUGH;
211bf215546Sopenharmony_ci   case 2:
212bf215546Sopenharmony_ci      height0 *= 2;
213bf215546Sopenharmony_ci   }
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci   unsigned lrz_pitch = align(DIV_ROUND_UP(width0, 8), 32);
216bf215546Sopenharmony_ci   unsigned lrz_height = align(DIV_ROUND_UP(height0, 8), 16);
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci   unsigned size = lrz_pitch * lrz_height * 2;
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   rsc->lrz_height = lrz_height;
221bf215546Sopenharmony_ci   rsc->lrz_width = lrz_pitch;
222bf215546Sopenharmony_ci   rsc->lrz_pitch = lrz_pitch;
223bf215546Sopenharmony_ci   rsc->lrz = fd_bo_new(screen->dev, size, FD_BO_NOMAP, "lrz");
224bf215546Sopenharmony_ci}
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_cistatic uint32_t
227bf215546Sopenharmony_cifd6_setup_slices(struct fd_resource *rsc)
228bf215546Sopenharmony_ci{
229bf215546Sopenharmony_ci   struct pipe_resource *prsc = &rsc->b.b;
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   if (!FD_DBG(NOLRZ) && has_depth(rsc->b.b.format))
232bf215546Sopenharmony_ci      setup_lrz(rsc);
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ci   if (rsc->layout.ubwc && !ok_ubwc_format(rsc->b.b.screen, rsc->b.b.format))
235bf215546Sopenharmony_ci      rsc->layout.ubwc = false;
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci   fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc),
238bf215546Sopenharmony_ci               prsc->width0, prsc->height0, prsc->depth0, prsc->last_level + 1,
239bf215546Sopenharmony_ci               prsc->array_size, prsc->target == PIPE_TEXTURE_3D, NULL);
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci   return rsc->layout.size;
242bf215546Sopenharmony_ci}
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_cistatic int
245bf215546Sopenharmony_cifill_ubwc_buffer_sizes(struct fd_resource *rsc)
246bf215546Sopenharmony_ci{
247bf215546Sopenharmony_ci   struct pipe_resource *prsc = &rsc->b.b;
248bf215546Sopenharmony_ci   struct fdl_explicit_layout explicit = {
249bf215546Sopenharmony_ci      .offset = rsc->layout.slices[0].offset,
250bf215546Sopenharmony_ci      .pitch = rsc->layout.pitch0,
251bf215546Sopenharmony_ci   };
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci   if (!can_do_ubwc(prsc))
254bf215546Sopenharmony_ci      return -1;
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   rsc->layout.ubwc = true;
257bf215546Sopenharmony_ci   rsc->layout.tile_mode = TILE6_3;
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci   if (!fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc),
260bf215546Sopenharmony_ci                    prsc->width0, prsc->height0, prsc->depth0,
261bf215546Sopenharmony_ci                    prsc->last_level + 1, prsc->array_size, false, &explicit))
262bf215546Sopenharmony_ci      return -1;
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   if (rsc->layout.size > fd_bo_size(rsc->bo))
265bf215546Sopenharmony_ci      return -1;
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci   return 0;
268bf215546Sopenharmony_ci}
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_cistatic int
271bf215546Sopenharmony_cifd6_layout_resource_for_modifier(struct fd_resource *rsc, uint64_t modifier)
272bf215546Sopenharmony_ci{
273bf215546Sopenharmony_ci   switch (modifier) {
274bf215546Sopenharmony_ci   case DRM_FORMAT_MOD_QCOM_COMPRESSED:
275bf215546Sopenharmony_ci      return fill_ubwc_buffer_sizes(rsc);
276bf215546Sopenharmony_ci   case DRM_FORMAT_MOD_LINEAR:
277bf215546Sopenharmony_ci      if (can_do_ubwc(&rsc->b.b)) {
278bf215546Sopenharmony_ci         perf_debug("%" PRSC_FMT
279bf215546Sopenharmony_ci                    ": not UBWC: imported with DRM_FORMAT_MOD_LINEAR!",
280bf215546Sopenharmony_ci                    PRSC_ARGS(&rsc->b.b));
281bf215546Sopenharmony_ci      }
282bf215546Sopenharmony_ci      return 0;
283bf215546Sopenharmony_ci   case DRM_FORMAT_MOD_INVALID:
284bf215546Sopenharmony_ci      if (can_do_ubwc(&rsc->b.b)) {
285bf215546Sopenharmony_ci         perf_debug("%" PRSC_FMT
286bf215546Sopenharmony_ci                    ": not UBWC: imported with DRM_FORMAT_MOD_INVALID!",
287bf215546Sopenharmony_ci                    PRSC_ARGS(&rsc->b.b));
288bf215546Sopenharmony_ci      }
289bf215546Sopenharmony_ci      return 0;
290bf215546Sopenharmony_ci   default:
291bf215546Sopenharmony_ci      return -1;
292bf215546Sopenharmony_ci   }
293bf215546Sopenharmony_ci}
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_cistatic const uint64_t supported_modifiers[] = {
296bf215546Sopenharmony_ci   DRM_FORMAT_MOD_LINEAR,
297bf215546Sopenharmony_ci   DRM_FORMAT_MOD_QCOM_COMPRESSED,
298bf215546Sopenharmony_ci};
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_civoid
301bf215546Sopenharmony_cifd6_resource_screen_init(struct pipe_screen *pscreen)
302bf215546Sopenharmony_ci{
303bf215546Sopenharmony_ci   struct fd_screen *screen = fd_screen(pscreen);
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci   screen->setup_slices = fd6_setup_slices;
306bf215546Sopenharmony_ci   screen->layout_resource_for_modifier = fd6_layout_resource_for_modifier;
307bf215546Sopenharmony_ci   screen->supported_modifiers = supported_modifiers;
308bf215546Sopenharmony_ci   screen->num_supported_modifiers = ARRAY_SIZE(supported_modifiers);
309bf215546Sopenharmony_ci}
310