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