1/* 2 * Copyright (C) 2013 Rob Clark <robclark@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@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 "fd3_texture.h" 34#include "fd3_format.h" 35 36static enum a3xx_tex_clamp 37tex_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 A3XX_TEX_REPEAT; 48 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 49 return A3XX_TEX_CLAMP_TO_EDGE; 50 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 51 *needs_border = true; 52 return A3XX_TEX_CLAMP_TO_BORDER; 53 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 54 /* only works for PoT.. need to emulate otherwise! */ 55 return A3XX_TEX_MIRROR_CLAMP; 56 case PIPE_TEX_WRAP_MIRROR_REPEAT: 57 return A3XX_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 69static enum a3xx_tex_filter 70tex_filter(unsigned filter, bool aniso) 71{ 72 switch (filter) { 73 case PIPE_TEX_FILTER_NEAREST: 74 return A3XX_TEX_NEAREST; 75 case PIPE_TEX_FILTER_LINEAR: 76 return aniso ? A3XX_TEX_ANISO : A3XX_TEX_LINEAR; 77 default: 78 DBG("invalid filter: %u", filter); 79 return 0; 80 } 81} 82 83static void * 84fd3_sampler_state_create(struct pipe_context *pctx, 85 const struct pipe_sampler_state *cso) 86{ 87 struct fd3_sampler_stateobj *so = CALLOC_STRUCT(fd3_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 if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) 96 miplinear = true; 97 98 so->base = *cso; 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(!cso->normalized_coords, A3XX_TEX_SAMP_0_UNNORM_COORDS) | 118 COND(!cso->seamless_cube_map, A3XX_TEX_SAMP_0_CUBEMAPSEAMLESSFILTOFF) | 119 COND(miplinear, A3XX_TEX_SAMP_0_MIPFILTER_LINEAR) | 120 A3XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) | 121 A3XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) | 122 A3XX_TEX_SAMP_0_ANISO(aniso) | 123 A3XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, clamp_to_edge, &so->needs_border)) | 124 A3XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, clamp_to_edge, &so->needs_border)) | 125 A3XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, clamp_to_edge, &so->needs_border)); 126 127 if (cso->compare_mode) 128 so->texsamp0 |= A3XX_TEX_SAMP_0_COMPARE_FUNC(cso->compare_func); /* maps 1:1 */ 129 130 if (cso->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) { 131 so->texsamp1 = 132 A3XX_TEX_SAMP_1_LOD_BIAS(cso->lod_bias) | 133 A3XX_TEX_SAMP_1_MIN_LOD(cso->min_lod) | 134 A3XX_TEX_SAMP_1_MAX_LOD(cso->max_lod); 135 } else { 136 so->texsamp1 = 0x00000000; 137 } 138 139 return so; 140} 141 142static void 143fd3_sampler_states_bind(struct pipe_context *pctx, 144 enum pipe_shader_type shader, unsigned start, 145 unsigned nr, void **hwcso) 146{ 147 struct fd_context *ctx = fd_context(pctx); 148 struct fd3_context *fd3_ctx = fd3_context(ctx); 149 uint16_t saturate_s = 0, saturate_t = 0, saturate_r = 0; 150 unsigned i; 151 152 if (!hwcso) 153 nr = 0; 154 155 for (i = 0; i < nr; i++) { 156 if (hwcso[i]) { 157 struct fd3_sampler_stateobj *sampler = 158 fd3_sampler_stateobj(hwcso[i]); 159 if (sampler->saturate_s) 160 saturate_s |= (1 << i); 161 if (sampler->saturate_t) 162 saturate_t |= (1 << i); 163 if (sampler->saturate_r) 164 saturate_r |= (1 << i); 165 } 166 } 167 168 fd_sampler_states_bind(pctx, shader, start, nr, hwcso); 169 170 if (shader == PIPE_SHADER_FRAGMENT) { 171 fd3_ctx->fsaturate = 172 (saturate_s != 0) || 173 (saturate_t != 0) || 174 (saturate_r != 0); 175 fd3_ctx->fsaturate_s = saturate_s; 176 fd3_ctx->fsaturate_t = saturate_t; 177 fd3_ctx->fsaturate_r = saturate_r; 178 } else if (shader == PIPE_SHADER_VERTEX) { 179 fd3_ctx->vsaturate = 180 (saturate_s != 0) || 181 (saturate_t != 0) || 182 (saturate_r != 0); 183 fd3_ctx->vsaturate_s = saturate_s; 184 fd3_ctx->vsaturate_t = saturate_t; 185 fd3_ctx->vsaturate_r = saturate_r; 186 } 187} 188 189static enum a3xx_tex_type 190tex_type(unsigned target) 191{ 192 switch (target) { 193 default: 194 assert(0); 195 case PIPE_BUFFER: 196 case PIPE_TEXTURE_1D: 197 case PIPE_TEXTURE_1D_ARRAY: 198 return A3XX_TEX_1D; 199 case PIPE_TEXTURE_RECT: 200 case PIPE_TEXTURE_2D: 201 case PIPE_TEXTURE_2D_ARRAY: 202 return A3XX_TEX_2D; 203 case PIPE_TEXTURE_3D: 204 return A3XX_TEX_3D; 205 case PIPE_TEXTURE_CUBE: 206 case PIPE_TEXTURE_CUBE_ARRAY: 207 return A3XX_TEX_CUBE; 208 } 209} 210 211static struct pipe_sampler_view * 212fd3_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, 213 const struct pipe_sampler_view *cso) 214{ 215 struct fd3_pipe_sampler_view *so = CALLOC_STRUCT(fd3_pipe_sampler_view); 216 struct fd_resource *rsc = fd_resource(prsc); 217 unsigned lvl; 218 uint32_t sz2 = 0; 219 220 if (!so) 221 return NULL; 222 223 so->base = *cso; 224 pipe_reference(NULL, &prsc->reference); 225 so->base.texture = prsc; 226 so->base.reference.count = 1; 227 so->base.context = pctx; 228 229 so->texconst0 = 230 A3XX_TEX_CONST_0_TYPE(tex_type(prsc->target)) | 231 A3XX_TEX_CONST_0_FMT(fd3_pipe2tex(cso->format)) | 232 fd3_tex_swiz(cso->format, cso->swizzle_r, cso->swizzle_g, 233 cso->swizzle_b, cso->swizzle_a); 234 235 if (prsc->target == PIPE_BUFFER || util_format_is_pure_integer(cso->format)) 236 so->texconst0 |= A3XX_TEX_CONST_0_NOCONVERT; 237 if (util_format_is_srgb(cso->format)) 238 so->texconst0 |= A3XX_TEX_CONST_0_SRGB; 239 240 if (prsc->target == PIPE_BUFFER) { 241 lvl = 0; 242 so->texconst1 = 243 A3XX_TEX_CONST_1_FETCHSIZE(fd3_pipe2fetchsize(cso->format)) | 244 A3XX_TEX_CONST_1_WIDTH(cso->u.buf.size / util_format_get_blocksize(cso->format)) | 245 A3XX_TEX_CONST_1_HEIGHT(1); 246 } else { 247 unsigned miplevels; 248 249 lvl = fd_sampler_first_level(cso); 250 miplevels = fd_sampler_last_level(cso) - lvl; 251 252 so->texconst0 |= A3XX_TEX_CONST_0_MIPLVLS(miplevels); 253 so->texconst1 = 254 A3XX_TEX_CONST_1_FETCHSIZE(fd3_pipe2fetchsize(cso->format)) | 255 A3XX_TEX_CONST_1_WIDTH(u_minify(prsc->width0, lvl)) | 256 A3XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl)); 257 } 258 /* when emitted, A3XX_TEX_CONST_2_INDX() must be OR'd in: */ 259 so->texconst2 = 260 A3XX_TEX_CONST_2_PITCH(fd3_pipe2nblocksx(cso->format, rsc->slices[lvl].pitch) * rsc->cpp); 261 switch (prsc->target) { 262 case PIPE_TEXTURE_1D_ARRAY: 263 case PIPE_TEXTURE_2D_ARRAY: 264 so->texconst3 = 265 A3XX_TEX_CONST_3_DEPTH(prsc->array_size - 1) | 266 A3XX_TEX_CONST_3_LAYERSZ1(rsc->slices[0].size0); 267 break; 268 case PIPE_TEXTURE_3D: 269 so->texconst3 = 270 A3XX_TEX_CONST_3_DEPTH(u_minify(prsc->depth0, lvl)) | 271 A3XX_TEX_CONST_3_LAYERSZ1(rsc->slices[lvl].size0); 272 while (lvl < cso->u.tex.last_level && sz2 != rsc->slices[lvl+1].size0) 273 sz2 = rsc->slices[++lvl].size0; 274 so->texconst3 |= A3XX_TEX_CONST_3_LAYERSZ2(sz2); 275 break; 276 default: 277 so->texconst3 = 0x00000000; 278 break; 279 } 280 281 return &so->base; 282} 283 284void 285fd3_texture_init(struct pipe_context *pctx) 286{ 287 pctx->create_sampler_state = fd3_sampler_state_create; 288 pctx->bind_sampler_states = fd3_sampler_states_bind; 289 pctx->create_sampler_view = fd3_sampler_view_create; 290 pctx->set_sampler_views = fd_set_sampler_views; 291} 292