Home | History | Annotate | Download | only in a5xx
      1 /*
      2  * Copyright (C) 2016 Rob Clark <robclark (at) freedesktop.org>
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  *
     23  * Authors:
     24  *    Rob Clark <robclark (at) freedesktop.org>
     25  */
     26 
     27 #include "pipe/p_state.h"
     28 #include "util/u_string.h"
     29 #include "util/u_memory.h"
     30 #include "util/u_inlines.h"
     31 #include "util/u_format.h"
     32 
     33 #include "fd5_texture.h"
     34 #include "fd5_format.h"
     35 
     36 static enum a5xx_tex_clamp
     37 tex_clamp(unsigned wrap, bool clamp_to_edge, bool *needs_border)
     38 {
     39 	/* Hardware does not support _CLAMP, but we emulate it: */
     40 	if (wrap == PIPE_TEX_WRAP_CLAMP) {
     41 		wrap = (clamp_to_edge) ?
     42 			PIPE_TEX_WRAP_CLAMP_TO_EDGE : PIPE_TEX_WRAP_CLAMP_TO_BORDER;
     43 	}
     44 
     45 	switch (wrap) {
     46 	case PIPE_TEX_WRAP_REPEAT:
     47 		return A5XX_TEX_REPEAT;
     48 	case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
     49 		return A5XX_TEX_CLAMP_TO_EDGE;
     50 	case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
     51 		*needs_border = true;
     52 		return A5XX_TEX_CLAMP_TO_BORDER;
     53 	case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
     54 		/* only works for PoT.. need to emulate otherwise! */
     55 		return A5XX_TEX_MIRROR_CLAMP;
     56 	case PIPE_TEX_WRAP_MIRROR_REPEAT:
     57 		return A5XX_TEX_MIRROR_REPEAT;
     58 	case PIPE_TEX_WRAP_MIRROR_CLAMP:
     59 	case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
     60 		/* these two we could perhaps emulate, but we currently
     61 		 * just don't advertise PIPE_CAP_TEXTURE_MIRROR_CLAMP
     62 		 */
     63 	default:
     64 		DBG("invalid wrap: %u", wrap);
     65 		return 0;
     66 	}
     67 }
     68 
     69 static enum a5xx_tex_filter
     70 tex_filter(unsigned filter, bool aniso)
     71 {
     72 	switch (filter) {
     73 	case PIPE_TEX_FILTER_NEAREST:
     74 		return A5XX_TEX_NEAREST;
     75 	case PIPE_TEX_FILTER_LINEAR:
     76 		return aniso ? A5XX_TEX_ANISO : A5XX_TEX_LINEAR;
     77 	default:
     78 		DBG("invalid filter: %u", filter);
     79 		return 0;
     80 	}
     81 }
     82 
     83 static void *
     84 fd5_sampler_state_create(struct pipe_context *pctx,
     85 		const struct pipe_sampler_state *cso)
     86 {
     87 	struct fd5_sampler_stateobj *so = CALLOC_STRUCT(fd5_sampler_stateobj);
     88 	unsigned aniso = util_last_bit(MIN2(cso->max_anisotropy >> 1, 8));
     89 	bool miplinear = false;
     90 	bool clamp_to_edge;
     91 
     92 	if (!so)
     93 		return NULL;
     94 
     95 	so->base = *cso;
     96 
     97 	if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR)
     98 		miplinear = true;
     99 
    100 	/*
    101 	 * For nearest filtering, _CLAMP means _CLAMP_TO_EDGE;  for linear
    102 	 * filtering, _CLAMP means _CLAMP_TO_BORDER while additionally
    103 	 * clamping the texture coordinates to [0.0, 1.0].
    104 	 *
    105 	 * The clamping will be taken care of in the shaders.  There are two
    106 	 * filters here, but let the minification one has a say.
    107 	 */
    108 	clamp_to_edge = (cso->min_img_filter == PIPE_TEX_FILTER_NEAREST);
    109 	if (!clamp_to_edge) {
    110 		so->saturate_s = (cso->wrap_s == PIPE_TEX_WRAP_CLAMP);
    111 		so->saturate_t = (cso->wrap_t == PIPE_TEX_WRAP_CLAMP);
    112 		so->saturate_r = (cso->wrap_r == PIPE_TEX_WRAP_CLAMP);
    113 	}
    114 
    115 	so->needs_border = false;
    116 	so->texsamp0 =
    117 		COND(miplinear, A5XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR) |
    118 		A5XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) |
    119 		A5XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) |
    120 		A5XX_TEX_SAMP_0_ANISO(aniso) |
    121 		A5XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, clamp_to_edge, &so->needs_border)) |
    122 		A5XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, clamp_to_edge, &so->needs_border)) |
    123 		A5XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, clamp_to_edge, &so->needs_border));
    124 
    125 	so->texsamp1 =
    126 		COND(miplinear, A5XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR) |
    127 		COND(!cso->seamless_cube_map, A5XX_TEX_SAMP_1_CUBEMAPSEAMLESSFILTOFF) |
    128 		COND(!cso->normalized_coords, A5XX_TEX_SAMP_1_UNNORM_COORDS);
    129 
    130 	if (cso->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) {
    131 		so->texsamp0 |= A5XX_TEX_SAMP_0_LOD_BIAS(cso->lod_bias);
    132 		so->texsamp1 |=
    133 			A5XX_TEX_SAMP_1_MIN_LOD(cso->min_lod) |
    134 			A5XX_TEX_SAMP_1_MAX_LOD(cso->max_lod);
    135 	}
    136 
    137 	if (cso->compare_mode)
    138 		so->texsamp1 |= A5XX_TEX_SAMP_1_COMPARE_FUNC(cso->compare_func); /* maps 1:1 */
    139 
    140 	return so;
    141 }
    142 
    143 static void
    144 fd5_sampler_states_bind(struct pipe_context *pctx,
    145 		enum pipe_shader_type shader, unsigned start,
    146 		unsigned nr, void **hwcso)
    147 {
    148 	struct fd_context *ctx = fd_context(pctx);
    149 	struct fd5_context *fd5_ctx = fd5_context(ctx);
    150 	uint16_t saturate_s = 0, saturate_t = 0, saturate_r = 0;
    151 	unsigned i;
    152 
    153 	if (!hwcso)
    154 		nr = 0;
    155 
    156 	for (i = 0; i < nr; i++) {
    157 		if (hwcso[i]) {
    158 			struct fd5_sampler_stateobj *sampler =
    159 					fd5_sampler_stateobj(hwcso[i]);
    160 			if (sampler->saturate_s)
    161 				saturate_s |= (1 << i);
    162 			if (sampler->saturate_t)
    163 				saturate_t |= (1 << i);
    164 			if (sampler->saturate_r)
    165 				saturate_r |= (1 << i);
    166 		}
    167 	}
    168 
    169 	fd_sampler_states_bind(pctx, shader, start, nr, hwcso);
    170 
    171 	if (shader == PIPE_SHADER_FRAGMENT) {
    172 		fd5_ctx->fsaturate =
    173 			(saturate_s != 0) ||
    174 			(saturate_t != 0) ||
    175 			(saturate_r != 0);
    176 		fd5_ctx->fsaturate_s = saturate_s;
    177 		fd5_ctx->fsaturate_t = saturate_t;
    178 		fd5_ctx->fsaturate_r = saturate_r;
    179 	} else if (shader == PIPE_SHADER_VERTEX) {
    180 		fd5_ctx->vsaturate =
    181 			(saturate_s != 0) ||
    182 			(saturate_t != 0) ||
    183 			(saturate_r != 0);
    184 		fd5_ctx->vsaturate_s = saturate_s;
    185 		fd5_ctx->vsaturate_t = saturate_t;
    186 		fd5_ctx->vsaturate_r = saturate_r;
    187 	}
    188 }
    189 
    190 static enum a5xx_tex_type
    191 tex_type(unsigned target)
    192 {
    193 	switch (target) {
    194 	default:
    195 		assert(0);
    196 	case PIPE_BUFFER:
    197 	case PIPE_TEXTURE_1D:
    198 	case PIPE_TEXTURE_1D_ARRAY:
    199 		return A5XX_TEX_1D;
    200 	case PIPE_TEXTURE_RECT:
    201 	case PIPE_TEXTURE_2D:
    202 	case PIPE_TEXTURE_2D_ARRAY:
    203 		return A5XX_TEX_2D;
    204 	case PIPE_TEXTURE_3D:
    205 		return A5XX_TEX_3D;
    206 	case PIPE_TEXTURE_CUBE:
    207 	case PIPE_TEXTURE_CUBE_ARRAY:
    208 		return A5XX_TEX_CUBE;
    209 	}
    210 }
    211 
    212 static bool
    213 use_astc_srgb_workaround(struct pipe_context *pctx, enum pipe_format format)
    214 {
    215 	return (fd_screen(pctx->screen)->gpu_id == 420) &&
    216 		(util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_ASTC);
    217 }
    218 
    219 static struct pipe_sampler_view *
    220 fd5_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc,
    221 		const struct pipe_sampler_view *cso)
    222 {
    223 	struct fd5_pipe_sampler_view *so = CALLOC_STRUCT(fd5_pipe_sampler_view);
    224 	struct fd_resource *rsc = fd_resource(prsc);
    225 	unsigned lvl, layers;
    226 	uint32_t sz2 = 0;
    227 
    228 	if (!so)
    229 		return NULL;
    230 
    231 	so->base = *cso;
    232 	pipe_reference(NULL, &prsc->reference);
    233 	so->base.texture = prsc;
    234 	so->base.reference.count = 1;
    235 	so->base.context = pctx;
    236 
    237 	so->texconst0 =
    238 		A5XX_TEX_CONST_0_FMT(fd5_pipe2tex(cso->format)) |
    239 		fd5_tex_swiz(cso->format, cso->swizzle_r, cso->swizzle_g,
    240 				cso->swizzle_b, cso->swizzle_a);
    241 
    242 	if (util_format_is_srgb(cso->format)) {
    243 		if (use_astc_srgb_workaround(pctx, cso->format))
    244 			so->astc_srgb = true;
    245 		so->texconst0 |= A5XX_TEX_CONST_0_SRGB;
    246 	}
    247 
    248 	if (cso->target == PIPE_BUFFER) {
    249 		unsigned elements = cso->u.buf.size / util_format_get_blocksize(cso->format);
    250 
    251 		lvl = 0;
    252 		so->texconst1 =
    253 			A5XX_TEX_CONST_1_WIDTH(elements) |
    254 			A5XX_TEX_CONST_1_HEIGHT(1);
    255 		so->texconst2 =
    256 			A5XX_TEX_CONST_2_FETCHSIZE(fd5_pipe2fetchsize(cso->format)) |
    257 			A5XX_TEX_CONST_2_PITCH(elements * rsc->cpp);
    258 		so->offset = cso->u.buf.offset;
    259 	} else {
    260 		unsigned miplevels;
    261 
    262 		lvl = fd_sampler_first_level(cso);
    263 		miplevels = fd_sampler_last_level(cso) - lvl;
    264 		layers = cso->u.tex.last_layer - cso->u.tex.first_layer + 1;
    265 
    266 		so->texconst0 |= A5XX_TEX_CONST_0_MIPLVLS(miplevels);
    267 		so->texconst1 =
    268 			A5XX_TEX_CONST_1_WIDTH(u_minify(prsc->width0, lvl)) |
    269 			A5XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl));
    270 		so->texconst2 =
    271 			A5XX_TEX_CONST_2_FETCHSIZE(fd5_pipe2fetchsize(cso->format)) |
    272 			A5XX_TEX_CONST_2_PITCH(
    273 					util_format_get_nblocksx(
    274 							cso->format, rsc->slices[lvl].pitch) * rsc->cpp);
    275 		so->offset = fd_resource_offset(rsc, lvl, cso->u.tex.first_layer);
    276 	}
    277 
    278 	so->texconst2 |= A5XX_TEX_CONST_2_TYPE(tex_type(cso->target));
    279 
    280 	switch (cso->target) {
    281 	case PIPE_TEXTURE_1D:
    282 	case PIPE_TEXTURE_2D:
    283 		so->texconst3 =
    284 			A5XX_TEX_CONST_3_ARRAY_PITCH(rsc->layer_size);
    285 		so->texconst5 =
    286 			A5XX_TEX_CONST_5_DEPTH(1);
    287 		break;
    288 	case PIPE_TEXTURE_1D_ARRAY:
    289 	case PIPE_TEXTURE_2D_ARRAY:
    290 		so->texconst3 =
    291 			A5XX_TEX_CONST_3_ARRAY_PITCH(rsc->layer_size);
    292 		so->texconst5 =
    293 			A5XX_TEX_CONST_5_DEPTH(layers);
    294 		break;
    295 	case PIPE_TEXTURE_CUBE:
    296 	case PIPE_TEXTURE_CUBE_ARRAY:
    297 		so->texconst3 =
    298 			A5XX_TEX_CONST_3_ARRAY_PITCH(rsc->layer_size);
    299 		so->texconst5 =
    300 			A5XX_TEX_CONST_5_DEPTH(layers / 6);
    301 		break;
    302 	case PIPE_TEXTURE_3D:
    303 		while (lvl < cso->u.tex.last_level && sz2 != rsc->slices[lvl+1].size0)
    304 			sz2 = rsc->slices[++lvl].size0;
    305 		so->texconst3 =
    306 			A5XX_TEX_CONST_3_ARRAY_PITCH(rsc->slices[lvl].size0);
    307 		so->texconst5 =
    308 			A5XX_TEX_CONST_5_DEPTH(u_minify(prsc->depth0, lvl));
    309 		break;
    310 	default:
    311 		so->texconst3 = 0x00000000;
    312 		break;
    313 	}
    314 
    315 	return &so->base;
    316 }
    317 
    318 static void
    319 fd5_set_sampler_views(struct pipe_context *pctx, enum pipe_shader_type shader,
    320 		unsigned start, unsigned nr,
    321 		struct pipe_sampler_view **views)
    322 {
    323 	struct fd_context *ctx = fd_context(pctx);
    324 	struct fd5_context *fd5_ctx = fd5_context(ctx);
    325 	uint16_t astc_srgb = 0;
    326 	unsigned i;
    327 
    328 	for (i = 0; i < nr; i++) {
    329 		if (views[i]) {
    330 			struct fd5_pipe_sampler_view *view =
    331 					fd5_pipe_sampler_view(views[i]);
    332 			if (view->astc_srgb)
    333 				astc_srgb |= (1 << i);
    334 		}
    335 	}
    336 
    337 	fd_set_sampler_views(pctx, shader, start, nr, views);
    338 
    339 	if (shader == PIPE_SHADER_FRAGMENT) {
    340 		fd5_ctx->fastc_srgb = astc_srgb;
    341 	} else if (shader == PIPE_SHADER_VERTEX) {
    342 		fd5_ctx->vastc_srgb = astc_srgb;
    343 	}
    344 }
    345 
    346 void
    347 fd5_texture_init(struct pipe_context *pctx)
    348 {
    349 	pctx->create_sampler_state = fd5_sampler_state_create;
    350 	pctx->bind_sampler_states = fd5_sampler_states_bind;
    351 	pctx->create_sampler_view = fd5_sampler_view_create;
    352 	pctx->set_sampler_views = fd5_set_sampler_views;
    353 }
    354