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/format/u_format.h" 29#include "util/u_inlines.h" 30#include "util/u_memory.h" 31#include "util/u_string.h" 32 33#include "fd3_format.h" 34#include "fd3_texture.h" 35 36static enum a3xx_tex_clamp 37tex_clamp(unsigned wrap, bool *needs_border) 38{ 39 switch (wrap) { 40 case PIPE_TEX_WRAP_REPEAT: 41 return A3XX_TEX_REPEAT; 42 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 43 return A3XX_TEX_CLAMP_TO_EDGE; 44 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 45 *needs_border = true; 46 return A3XX_TEX_CLAMP_TO_BORDER; 47 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 48 /* only works for PoT.. need to emulate otherwise! */ 49 return A3XX_TEX_MIRROR_CLAMP; 50 case PIPE_TEX_WRAP_MIRROR_REPEAT: 51 return A3XX_TEX_MIRROR_REPEAT; 52 case PIPE_TEX_WRAP_MIRROR_CLAMP: 53 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 54 /* these two we could perhaps emulate, but we currently 55 * just don't advertise PIPE_CAP_TEXTURE_MIRROR_CLAMP 56 */ 57 default: 58 DBG("invalid wrap: %u", wrap); 59 return 0; 60 } 61} 62 63static enum a3xx_tex_filter 64tex_filter(unsigned filter, bool aniso) 65{ 66 switch (filter) { 67 case PIPE_TEX_FILTER_NEAREST: 68 return A3XX_TEX_NEAREST; 69 case PIPE_TEX_FILTER_LINEAR: 70 return aniso ? A3XX_TEX_ANISO : A3XX_TEX_LINEAR; 71 default: 72 DBG("invalid filter: %u", filter); 73 return 0; 74 } 75} 76 77static void * 78fd3_sampler_state_create(struct pipe_context *pctx, 79 const struct pipe_sampler_state *cso) 80{ 81 struct fd3_sampler_stateobj *so = CALLOC_STRUCT(fd3_sampler_stateobj); 82 unsigned aniso = util_last_bit(MIN2(cso->max_anisotropy >> 1, 8)); 83 bool miplinear = false; 84 85 if (!so) 86 return NULL; 87 88 if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) 89 miplinear = true; 90 91 so->base = *cso; 92 93 so->needs_border = false; 94 so->texsamp0 = 95 COND(!cso->normalized_coords, A3XX_TEX_SAMP_0_UNNORM_COORDS) | 96 COND(!cso->seamless_cube_map, A3XX_TEX_SAMP_0_CUBEMAPSEAMLESSFILTOFF) | 97 COND(miplinear, A3XX_TEX_SAMP_0_MIPFILTER_LINEAR) | 98 A3XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) | 99 A3XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) | 100 A3XX_TEX_SAMP_0_ANISO(aniso) | 101 A3XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, &so->needs_border)) | 102 A3XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, &so->needs_border)) | 103 A3XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, &so->needs_border)); 104 105 if (cso->compare_mode) 106 so->texsamp0 |= 107 A3XX_TEX_SAMP_0_COMPARE_FUNC(cso->compare_func); /* maps 1:1 */ 108 109 so->texsamp1 = A3XX_TEX_SAMP_1_LOD_BIAS(cso->lod_bias); 110 111 if (cso->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) { 112 so->texsamp1 |= A3XX_TEX_SAMP_1_MIN_LOD(cso->min_lod) | 113 A3XX_TEX_SAMP_1_MAX_LOD(cso->max_lod); 114 } else { 115 /* If we're not doing mipmap filtering, we still need a slightly > 0 116 * LOD clamp so the HW can decide between min and mag filtering of 117 * level 0. 118 */ 119 so->texsamp1 |= A3XX_TEX_SAMP_1_MIN_LOD(MIN2(cso->min_lod, 0.125f)) | 120 A3XX_TEX_SAMP_1_MAX_LOD(MIN2(cso->max_lod, 0.125f)); 121 } 122 123 return so; 124} 125 126static enum a3xx_tex_type 127tex_type(unsigned target) 128{ 129 switch (target) { 130 default: 131 assert(0); 132 case PIPE_BUFFER: 133 case PIPE_TEXTURE_1D: 134 case PIPE_TEXTURE_1D_ARRAY: 135 return A3XX_TEX_1D; 136 case PIPE_TEXTURE_RECT: 137 case PIPE_TEXTURE_2D: 138 case PIPE_TEXTURE_2D_ARRAY: 139 return A3XX_TEX_2D; 140 case PIPE_TEXTURE_3D: 141 return A3XX_TEX_3D; 142 case PIPE_TEXTURE_CUBE: 143 case PIPE_TEXTURE_CUBE_ARRAY: 144 return A3XX_TEX_CUBE; 145 } 146} 147 148static struct pipe_sampler_view * 149fd3_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, 150 const struct pipe_sampler_view *cso) 151{ 152 struct fd3_pipe_sampler_view *so = CALLOC_STRUCT(fd3_pipe_sampler_view); 153 struct fd_resource *rsc = fd_resource(prsc); 154 unsigned lvl; 155 156 if (!so) 157 return NULL; 158 159 so->base = *cso; 160 pipe_reference(NULL, &prsc->reference); 161 so->base.texture = prsc; 162 so->base.reference.count = 1; 163 so->base.context = pctx; 164 165 so->texconst0 = A3XX_TEX_CONST_0_TILE_MODE(rsc->layout.tile_mode) | 166 A3XX_TEX_CONST_0_TYPE(tex_type(prsc->target)) | 167 A3XX_TEX_CONST_0_FMT(fd3_pipe2tex(cso->format)) | 168 fd3_tex_swiz(cso->format, cso->swizzle_r, cso->swizzle_g, 169 cso->swizzle_b, cso->swizzle_a); 170 171 if (prsc->target == PIPE_BUFFER || util_format_is_pure_integer(cso->format)) 172 so->texconst0 |= A3XX_TEX_CONST_0_NOCONVERT; 173 if (util_format_is_srgb(cso->format)) 174 so->texconst0 |= A3XX_TEX_CONST_0_SRGB; 175 176 if (prsc->target == PIPE_BUFFER) { 177 lvl = 0; 178 so->texconst1 = 179 A3XX_TEX_CONST_1_WIDTH(cso->u.buf.size / 180 util_format_get_blocksize(cso->format)) | 181 A3XX_TEX_CONST_1_HEIGHT(1); 182 } else { 183 unsigned miplevels; 184 185 lvl = fd_sampler_first_level(cso); 186 miplevels = fd_sampler_last_level(cso) - lvl; 187 188 so->texconst0 |= A3XX_TEX_CONST_0_MIPLVLS(miplevels); 189 so->texconst1 = A3XX_TEX_CONST_1_PITCHALIGN(rsc->layout.pitchalign - 4) | 190 A3XX_TEX_CONST_1_WIDTH(u_minify(prsc->width0, lvl)) | 191 A3XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl)); 192 } 193 /* when emitted, A3XX_TEX_CONST_2_INDX() must be OR'd in: */ 194 struct fdl_slice *slice = fd_resource_slice(rsc, lvl); 195 so->texconst2 = A3XX_TEX_CONST_2_PITCH(fd_resource_pitch(rsc, lvl)); 196 switch (prsc->target) { 197 case PIPE_TEXTURE_1D_ARRAY: 198 case PIPE_TEXTURE_2D_ARRAY: 199 so->texconst3 = A3XX_TEX_CONST_3_DEPTH(prsc->array_size - 1) | 200 A3XX_TEX_CONST_3_LAYERSZ1(slice->size0); 201 break; 202 case PIPE_TEXTURE_3D: 203 so->texconst3 = A3XX_TEX_CONST_3_DEPTH(u_minify(prsc->depth0, lvl)) | 204 A3XX_TEX_CONST_3_LAYERSZ1(slice->size0); 205 so->texconst3 |= A3XX_TEX_CONST_3_LAYERSZ2( 206 fd_resource_slice(rsc, prsc->last_level)->size0); 207 break; 208 default: 209 so->texconst3 = 0x00000000; 210 break; 211 } 212 213 return &so->base; 214} 215 216void 217fd3_texture_init(struct pipe_context *pctx) 218{ 219 pctx->create_sampler_state = fd3_sampler_state_create; 220 pctx->bind_sampler_states = fd_sampler_states_bind; 221 pctx->create_sampler_view = fd3_sampler_view_create; 222 pctx->set_sampler_views = fd_set_sampler_views; 223} 224