1/*
2 * Copyright (c) 2017 Etnaviv Project
3 * Copyright (C) 2017 Zodiac Inflight Innovations
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Wladimir J. van der Laan <laanwj@gmail.com>
26 */
27
28#include "etnaviv_texture_desc.h"
29
30#include "hw/common.xml.h"
31#include "hw/texdesc_3d.xml.h"
32
33#include "etnaviv_clear_blit.h"
34#include "etnaviv_context.h"
35#include "etnaviv_emit.h"
36#include "etnaviv_format.h"
37#include "etnaviv_translate.h"
38#include "etnaviv_texture.h"
39#include "util/u_inlines.h"
40#include "util/u_memory.h"
41
42#include <drm_fourcc.h>
43
44struct etna_sampler_state_desc {
45   struct pipe_sampler_state base;
46   uint32_t SAMP_CTRL0;
47   uint32_t SAMP_CTRL1;
48   uint32_t SAMP_LOD_MINMAX;
49   uint32_t SAMP_LOD_BIAS;
50   uint32_t SAMP_ANISOTROPY;
51};
52
53static inline struct etna_sampler_state_desc *
54etna_sampler_state_desc(struct pipe_sampler_state *samp)
55{
56   return (struct etna_sampler_state_desc *)samp;
57}
58
59struct etna_sampler_view_desc {
60   struct pipe_sampler_view base;
61   /* format-dependent merged with sampler state */
62   uint32_t SAMP_CTRL0;
63   uint32_t SAMP_CTRL1;
64
65   struct etna_bo *bo;
66   struct etna_reloc DESC_ADDR;
67   struct etna_sampler_ts ts;
68};
69
70static inline struct etna_sampler_view_desc *
71etna_sampler_view_desc(struct pipe_sampler_view *view)
72{
73   return (struct etna_sampler_view_desc *)view;
74}
75
76static void *
77etna_create_sampler_state_desc(struct pipe_context *pipe,
78                          const struct pipe_sampler_state *ss)
79{
80   struct etna_sampler_state_desc *cs = CALLOC_STRUCT(etna_sampler_state_desc);
81   const bool ansio = ss->max_anisotropy > 1;
82
83   if (!cs)
84      return NULL;
85
86   cs->base = *ss;
87
88   cs->SAMP_CTRL0 =
89      VIVS_NTE_DESCRIPTOR_SAMP_CTRL0_UWRAP(translate_texture_wrapmode(ss->wrap_s)) |
90      VIVS_NTE_DESCRIPTOR_SAMP_CTRL0_VWRAP(translate_texture_wrapmode(ss->wrap_t)) |
91      VIVS_NTE_DESCRIPTOR_SAMP_CTRL0_WWRAP(translate_texture_wrapmode(ss->wrap_r)) |
92      VIVS_NTE_DESCRIPTOR_SAMP_CTRL0_MIN(translate_texture_filter(ss->min_img_filter)) |
93      VIVS_NTE_DESCRIPTOR_SAMP_CTRL0_MIP(translate_texture_mipfilter(ss->min_mip_filter)) |
94      VIVS_NTE_DESCRIPTOR_SAMP_CTRL0_MAG(translate_texture_filter(ss->mag_img_filter)) |
95      VIVS_NTE_DESCRIPTOR_SAMP_CTRL0_UNK21;
96      /* no ROUND_UV bit? */
97   cs->SAMP_CTRL1 = VIVS_NTE_DESCRIPTOR_SAMP_CTRL1_UNK1;
98   uint32_t min_lod_fp8 = MIN2(etna_float_to_fixp88(ss->min_lod), 0xfff);
99   uint32_t max_lod_fp8 = MIN2(etna_float_to_fixp88(ss->max_lod), 0xfff);
100   uint32_t max_lod_min = ss->min_img_filter != ss->mag_img_filter ? 4 : 0;
101
102   if (ss->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) {
103      cs->SAMP_LOD_MINMAX =
104         VIVS_NTE_DESCRIPTOR_SAMP_LOD_MINMAX_MAX(MAX2(max_lod_fp8, max_lod_min)) |
105         VIVS_NTE_DESCRIPTOR_SAMP_LOD_MINMAX_MIN(min_lod_fp8);
106   } else {
107      cs->SAMP_LOD_MINMAX =
108         VIVS_NTE_DESCRIPTOR_SAMP_LOD_MINMAX_MAX(MAX2(max_lod_fp8, max_lod_min)) |
109         VIVS_NTE_DESCRIPTOR_SAMP_LOD_MINMAX_MIN(min_lod_fp8);
110   }
111   cs->SAMP_LOD_BIAS =
112      VIVS_NTE_DESCRIPTOR_SAMP_LOD_BIAS_BIAS(etna_float_to_fixp88(ss->lod_bias)) |
113      COND(ss->lod_bias != 0.0, VIVS_NTE_DESCRIPTOR_SAMP_LOD_BIAS_ENABLE);
114   cs->SAMP_ANISOTROPY = COND(ansio, etna_log2_fixp88(ss->max_anisotropy));
115
116   return cs;
117}
118
119static void
120etna_delete_sampler_state_desc(struct pipe_context *pctx, void *ss)
121{
122   FREE(ss);
123}
124
125static struct pipe_sampler_view *
126etna_create_sampler_view_desc(struct pipe_context *pctx, struct pipe_resource *prsc,
127                         const struct pipe_sampler_view *so)
128{
129   const struct util_format_description *desc = util_format_description(so->format);
130   struct etna_sampler_view_desc *sv = CALLOC_STRUCT(etna_sampler_view_desc);
131   struct etna_context *ctx = etna_context(pctx);
132   const uint32_t format = translate_texture_format(so->format);
133   const bool ext = !!(format & EXT_FORMAT);
134   const bool astc = !!(format & ASTC_FORMAT);
135   const uint32_t swiz = get_texture_swiz(so->format, so->swizzle_r,
136                                          so->swizzle_g, so->swizzle_b,
137                                          so->swizzle_a);
138
139   if (!sv)
140      return NULL;
141
142   struct etna_resource *res = etna_texture_handle_incompatible(pctx, prsc);
143   if (!res) {
144      free(sv);
145      return NULL;
146   }
147
148   sv->base = *so;
149   pipe_reference_init(&sv->base.reference, 1);
150   sv->base.texture = NULL;
151   pipe_resource_reference(&sv->base.texture, prsc);
152   sv->base.context = pctx;
153
154   /* Determine whether target supported */
155   uint32_t target_hw = translate_texture_target(sv->base.target);
156   if (target_hw == ETNA_NO_MATCH) {
157      BUG("Unhandled texture target");
158      free(sv);
159      return NULL;
160   }
161
162   /* Texture descriptor sampler bits */
163   if (util_format_is_srgb(so->format))
164      sv->SAMP_CTRL1 |= VIVS_NTE_DESCRIPTOR_SAMP_CTRL1_SRGB;
165
166   /* Create texture descriptor */
167   sv->bo = etna_bo_new(ctx->screen->dev, 0x100, DRM_ETNA_GEM_CACHE_WC);
168   if (!sv->bo)
169      goto error;
170
171   uint32_t *buf = etna_bo_map(sv->bo);
172   etna_bo_cpu_prep(sv->bo, DRM_ETNA_PREP_WRITE);
173   memset(buf, 0, 0x100);
174
175   /** GC7000 needs the size of the BASELOD level */
176   uint32_t base_width = u_minify(res->base.width0, sv->base.u.tex.first_level);
177   uint32_t base_height = u_minify(res->base.height0, sv->base.u.tex.first_level);
178   uint32_t base_depth = u_minify(res->base.depth0, sv->base.u.tex.first_level);
179   bool is_array = false;
180   bool sint = util_format_is_pure_sint(so->format);
181
182   if (sv->base.target == PIPE_TEXTURE_1D_ARRAY) {
183      is_array = true;
184      base_height = res->base.array_size;
185   } else if (sv->base.target == PIPE_TEXTURE_2D_ARRAY) {
186      is_array = true;
187      base_depth = res->base.array_size;
188   }
189
190#define DESC_SET(x, y) buf[(TEXDESC_##x)>>2] = (y)
191   DESC_SET(CONFIG0, COND(!ext && !astc, VIVS_TE_SAMPLER_CONFIG0_FORMAT(format))
192                   | VIVS_TE_SAMPLER_CONFIG0_TYPE(target_hw) |
193                   COND(res->layout == ETNA_LAYOUT_LINEAR && !util_format_is_compressed(so->format),
194                        VIVS_TE_SAMPLER_CONFIG0_ADDRESSING_MODE(TEXTURE_ADDRESSING_MODE_LINEAR)));
195   DESC_SET(CONFIG1, COND(ext, VIVS_TE_SAMPLER_CONFIG1_FORMAT_EXT(format)) |
196                     COND(astc, VIVS_TE_SAMPLER_CONFIG1_FORMAT_EXT(TEXTURE_FORMAT_EXT_ASTC)) |
197                     COND(is_array, VIVS_TE_SAMPLER_CONFIG1_TEXTURE_ARRAY) |
198                     VIVS_TE_SAMPLER_CONFIG1_HALIGN(res->halign) | swiz);
199   DESC_SET(CONFIG2, 0x00030000 |
200         COND(sint && desc->channel[0].size == 8, TE_SAMPLER_CONFIG2_SIGNED_INT8) |
201         COND(sint && desc->channel[0].size == 16, TE_SAMPLER_CONFIG2_SIGNED_INT16));
202   DESC_SET(LINEAR_STRIDE, res->levels[0].stride);
203   DESC_SET(VOLUME, etna_log2_fixp88(base_depth));
204   DESC_SET(SLICE, res->levels[0].layer_stride);
205   DESC_SET(3D_CONFIG, VIVS_TE_SAMPLER_3D_CONFIG_DEPTH(base_depth));
206   DESC_SET(ASTC0, COND(astc, VIVS_NTE_SAMPLER_ASTC0_ASTC_FORMAT(format)) |
207                   VIVS_NTE_SAMPLER_ASTC0_UNK8(0xc) |
208                   VIVS_NTE_SAMPLER_ASTC0_UNK16(0xc) |
209                   VIVS_NTE_SAMPLER_ASTC0_UNK24(0xc));
210   DESC_SET(BASELOD, TEXDESC_BASELOD_BASELOD(sv->base.u.tex.first_level) |
211                     TEXDESC_BASELOD_MAXLOD(MIN2(sv->base.u.tex.last_level, res->base.last_level)));
212   DESC_SET(LOG_SIZE_EXT, TEXDESC_LOG_SIZE_EXT_WIDTH(etna_log2_fixp88(base_width)) |
213                          TEXDESC_LOG_SIZE_EXT_HEIGHT(etna_log2_fixp88(base_height)));
214   DESC_SET(SIZE, VIVS_TE_SAMPLER_SIZE_WIDTH(base_width) |
215                  VIVS_TE_SAMPLER_SIZE_HEIGHT(base_height));
216   for (int lod = 0; lod <= res->base.last_level; ++lod)
217      DESC_SET(LOD_ADDR(lod), etna_bo_gpu_va(res->bo) + res->levels[lod].offset);
218#undef DESC_SET
219
220   etna_bo_cpu_fini(sv->bo);
221
222   sv->DESC_ADDR.bo = sv->bo;
223   sv->DESC_ADDR.offset = 0;
224   sv->DESC_ADDR.flags = ETNA_RELOC_READ;
225
226   return &sv->base;
227error:
228   free(sv);
229   return NULL;
230}
231
232static void
233etna_sampler_view_update_descriptor(struct etna_context *ctx,
234                                    struct etna_cmd_stream *stream,
235                                    struct etna_sampler_view_desc *sv)
236{
237   /* TODO: this should instruct the kernel to update the descriptor when the
238    * bo is submitted. For now, just prevent the bo from being freed
239    * while it is in use indirectly.
240    */
241   struct etna_resource *res = etna_resource(sv->base.texture);
242   if (res->texture) {
243      res = etna_resource(res->texture);
244   }
245   /* No need to ref LOD levels individually as they'll always come from the same bo */
246   etna_cmd_stream_ref_bo(stream, res->bo, ETNA_RELOC_READ);
247}
248
249static void
250etna_sampler_view_desc_destroy(struct pipe_context *pctx,
251                          struct pipe_sampler_view *so)
252{
253   struct etna_sampler_view_desc *sv = etna_sampler_view_desc(so);
254   pipe_resource_reference(&sv->base.texture, NULL);
255   etna_bo_del(sv->bo);
256   FREE(sv);
257}
258
259static void
260etna_emit_texture_desc(struct etna_context *ctx)
261{
262   struct etna_cmd_stream *stream = ctx->stream;
263   uint32_t active_samplers = active_samplers_bits(ctx);
264   uint32_t dirty = ctx->dirty;
265
266   if (unlikely(dirty & ETNA_DIRTY_SAMPLER_VIEWS)) {
267      for (int x = 0; x < VIVS_TS_SAMPLER__LEN; ++x) {
268         if ((1 << x) & active_samplers) {
269            struct etna_sampler_view_desc *sv = etna_sampler_view_desc(ctx->sampler_view[x]);
270            struct etna_resource *res = etna_resource(sv->base.texture);
271            struct etna_reloc LOD_ADDR_0;
272
273            if (!sv->ts.enable)
274               continue;
275
276            etna_set_state(stream, VIVS_TS_SAMPLER_CONFIG(x), sv->ts.TS_SAMPLER_CONFIG);
277            etna_set_state_reloc(stream, VIVS_TS_SAMPLER_STATUS_BASE(x), &sv->ts.TS_SAMPLER_STATUS_BASE);
278            etna_set_state(stream, VIVS_TS_SAMPLER_CLEAR_VALUE(x), sv->ts.TS_SAMPLER_CLEAR_VALUE);
279            etna_set_state(stream, VIVS_TS_SAMPLER_CLEAR_VALUE2(x), sv->ts.TS_SAMPLER_CLEAR_VALUE2);
280
281            LOD_ADDR_0.bo = res->bo;
282            LOD_ADDR_0.offset = res->levels[0].offset;
283            LOD_ADDR_0.flags = ETNA_RELOC_READ;
284
285            etna_set_state_reloc(stream, VIVS_TS_SAMPLER_SURFACE_BASE(x), &LOD_ADDR_0);
286         }
287      }
288   }
289
290   if (unlikely(dirty & (ETNA_DIRTY_SAMPLERS | ETNA_DIRTY_SAMPLER_VIEWS))) {
291      for (int x = 0; x < PIPE_MAX_SAMPLERS; ++x) {
292         if ((1 << x) & active_samplers) {
293            struct etna_sampler_state_desc *ss = etna_sampler_state_desc(ctx->sampler[x]);
294            struct etna_sampler_view_desc *sv = etna_sampler_view_desc(ctx->sampler_view[x]);
295            uint32_t SAMP_CTRL0 = ss->SAMP_CTRL0 | sv->SAMP_CTRL0;
296
297            if (texture_use_int_filter(&sv->base, &ss->base, true))
298               SAMP_CTRL0 |= VIVS_NTE_DESCRIPTOR_SAMP_CTRL0_INT_FILTER;
299
300            etna_set_state(stream, VIVS_NTE_DESCRIPTOR_TX_CTRL(x),
301               COND(sv->ts.enable, VIVS_NTE_DESCRIPTOR_TX_CTRL_TS_ENABLE) |
302               VIVS_NTE_DESCRIPTOR_TX_CTRL_TS_MODE(sv->ts.mode) |
303               VIVS_NTE_DESCRIPTOR_TX_CTRL_TS_INDEX(x)|
304               COND(sv->ts.comp, VIVS_NTE_DESCRIPTOR_TX_CTRL_COMPRESSION));
305            etna_set_state(stream, VIVS_NTE_DESCRIPTOR_SAMP_CTRL0(x), SAMP_CTRL0);
306            etna_set_state(stream, VIVS_NTE_DESCRIPTOR_SAMP_CTRL1(x), ss->SAMP_CTRL1 | sv->SAMP_CTRL1);
307            etna_set_state(stream, VIVS_NTE_DESCRIPTOR_SAMP_LOD_MINMAX(x), ss->SAMP_LOD_MINMAX);
308            etna_set_state(stream, VIVS_NTE_DESCRIPTOR_SAMP_LOD_BIAS(x), ss->SAMP_LOD_BIAS);
309            etna_set_state(stream, VIVS_NTE_DESCRIPTOR_SAMP_ANISOTROPY(x), ss->SAMP_ANISOTROPY);
310         }
311      }
312   }
313
314   if (unlikely(dirty & ETNA_DIRTY_SAMPLER_VIEWS)) {
315      /* Set texture descriptors */
316      for (int x = 0; x < PIPE_MAX_SAMPLERS; ++x) {
317         if ((1 << x) & ctx->dirty_sampler_views) {
318            if ((1 << x) & active_samplers) {
319               struct etna_sampler_view_desc *sv = etna_sampler_view_desc(ctx->sampler_view[x]);
320               etna_sampler_view_update_descriptor(ctx, stream, sv);
321               etna_set_state_reloc(stream, VIVS_NTE_DESCRIPTOR_ADDR(x), &sv->DESC_ADDR);
322            } else {
323               /* dummy texture descriptors for unused samplers */
324               etna_set_state_reloc(stream, VIVS_NTE_DESCRIPTOR_ADDR(x), &ctx->DUMMY_DESC_ADDR);
325            }
326         }
327      }
328   }
329
330   if (unlikely(dirty & ETNA_DIRTY_SAMPLER_VIEWS)) {
331      /* Invalidate all dirty sampler views.
332       */
333      for (int x = 0; x < PIPE_MAX_SAMPLERS; ++x) {
334         if ((1 << x) & ctx->dirty_sampler_views) {
335            etna_set_state(stream, VIVS_NTE_DESCRIPTOR_INVALIDATE,
336                  VIVS_NTE_DESCRIPTOR_INVALIDATE_UNK29 |
337                  VIVS_NTE_DESCRIPTOR_INVALIDATE_IDX(x));
338         }
339      }
340   }
341}
342
343static struct etna_sampler_ts*
344etna_ts_for_sampler_view_state(struct pipe_sampler_view *pview)
345{
346   struct etna_sampler_view_desc *sv = etna_sampler_view_desc(pview);
347   return &sv->ts;
348}
349
350void
351etna_texture_desc_init(struct pipe_context *pctx)
352{
353   struct etna_context *ctx = etna_context(pctx);
354   DBG("etnaviv: Using descriptor-based texturing\n");
355   ctx->base.create_sampler_state = etna_create_sampler_state_desc;
356   ctx->base.delete_sampler_state = etna_delete_sampler_state_desc;
357   ctx->base.create_sampler_view = etna_create_sampler_view_desc;
358   ctx->base.sampler_view_destroy = etna_sampler_view_desc_destroy;
359   ctx->emit_texture_state = etna_emit_texture_desc;
360   ctx->ts_for_sampler_view = etna_ts_for_sampler_view_state;
361}
362
363