1 /********************************************************** 2 * Copyright 2008-2009 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 **********************************************************/ 25 26 #include "util/u_inlines.h" 27 #include "pipe/p_defines.h" 28 #include "util/u_format.h" 29 #include "util/u_math.h" 30 #include "util/u_memory.h" 31 #include "tgsi/tgsi_parse.h" 32 33 #include "svga_context.h" 34 #include "svga_resource_texture.h" 35 36 #include "svga_debug.h" 37 38 static INLINE unsigned 39 translate_wrap_mode(unsigned wrap) 40 { 41 switch (wrap) { 42 case PIPE_TEX_WRAP_REPEAT: 43 return SVGA3D_TEX_ADDRESS_WRAP; 44 45 case PIPE_TEX_WRAP_CLAMP: 46 return SVGA3D_TEX_ADDRESS_CLAMP; 47 48 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 49 /* Unfortunately SVGA3D_TEX_ADDRESS_EDGE not respected by 50 * hardware. 51 */ 52 return SVGA3D_TEX_ADDRESS_CLAMP; 53 54 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 55 return SVGA3D_TEX_ADDRESS_BORDER; 56 57 case PIPE_TEX_WRAP_MIRROR_REPEAT: 58 return SVGA3D_TEX_ADDRESS_MIRROR; 59 60 case PIPE_TEX_WRAP_MIRROR_CLAMP: 61 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 62 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 63 return SVGA3D_TEX_ADDRESS_MIRRORONCE; 64 65 default: 66 assert(0); 67 return SVGA3D_TEX_ADDRESS_WRAP; 68 } 69 } 70 71 static INLINE unsigned translate_img_filter( unsigned filter ) 72 { 73 switch (filter) { 74 case PIPE_TEX_FILTER_NEAREST: return SVGA3D_TEX_FILTER_NEAREST; 75 case PIPE_TEX_FILTER_LINEAR: return SVGA3D_TEX_FILTER_LINEAR; 76 default: 77 assert(0); 78 return SVGA3D_TEX_FILTER_NEAREST; 79 } 80 } 81 82 static INLINE unsigned translate_mip_filter( unsigned filter ) 83 { 84 switch (filter) { 85 case PIPE_TEX_MIPFILTER_NONE: return SVGA3D_TEX_FILTER_NONE; 86 case PIPE_TEX_MIPFILTER_NEAREST: return SVGA3D_TEX_FILTER_NEAREST; 87 case PIPE_TEX_MIPFILTER_LINEAR: return SVGA3D_TEX_FILTER_LINEAR; 88 default: 89 assert(0); 90 return SVGA3D_TEX_FILTER_NONE; 91 } 92 } 93 94 static void * 95 svga_create_sampler_state(struct pipe_context *pipe, 96 const struct pipe_sampler_state *sampler) 97 { 98 struct svga_context *svga = svga_context(pipe); 99 struct svga_sampler_state *cso = CALLOC_STRUCT( svga_sampler_state ); 100 101 if (!cso) 102 return NULL; 103 104 cso->mipfilter = translate_mip_filter(sampler->min_mip_filter); 105 cso->magfilter = translate_img_filter( sampler->mag_img_filter ); 106 cso->minfilter = translate_img_filter( sampler->min_img_filter ); 107 cso->aniso_level = MAX2( sampler->max_anisotropy, 1 ); 108 if(sampler->max_anisotropy) 109 cso->magfilter = cso->minfilter = SVGA3D_TEX_FILTER_ANISOTROPIC; 110 cso->lod_bias = sampler->lod_bias; 111 cso->addressu = translate_wrap_mode(sampler->wrap_s); 112 cso->addressv = translate_wrap_mode(sampler->wrap_t); 113 cso->addressw = translate_wrap_mode(sampler->wrap_r); 114 cso->normalized_coords = sampler->normalized_coords; 115 cso->compare_mode = sampler->compare_mode; 116 cso->compare_func = sampler->compare_func; 117 118 { 119 uint32 r = float_to_ubyte(sampler->border_color.f[0]); 120 uint32 g = float_to_ubyte(sampler->border_color.f[1]); 121 uint32 b = float_to_ubyte(sampler->border_color.f[2]); 122 uint32 a = float_to_ubyte(sampler->border_color.f[3]); 123 124 cso->bordercolor = (a << 24) | (r << 16) | (g << 8) | b; 125 } 126 127 /* No SVGA3D support for: 128 * - min/max LOD clamping 129 */ 130 cso->min_lod = 0; 131 cso->view_min_lod = MAX2((int) (sampler->min_lod + 0.5), 0); 132 cso->view_max_lod = MAX2((int) (sampler->max_lod + 0.5), 0); 133 134 /* Use min_mipmap */ 135 if (svga->debug.use_min_mipmap) { 136 if (cso->view_min_lod == cso->view_max_lod) { 137 cso->min_lod = cso->view_min_lod; 138 cso->view_min_lod = 0; 139 cso->view_max_lod = 1000; /* Just a high number */ 140 cso->mipfilter = SVGA3D_TEX_FILTER_NONE; 141 } 142 } 143 144 SVGA_DBG(DEBUG_VIEWS, "min %u, view(min %u, max %u) lod, mipfilter %s\n", 145 cso->min_lod, cso->view_min_lod, cso->view_max_lod, 146 cso->mipfilter == SVGA3D_TEX_FILTER_NONE ? "SVGA3D_TEX_FILTER_NONE" : "SOMETHING"); 147 148 return cso; 149 } 150 151 static void 152 svga_bind_sampler_states(struct pipe_context *pipe, 153 unsigned shader, 154 unsigned start, 155 unsigned num, 156 void **samplers) 157 { 158 struct svga_context *svga = svga_context(pipe); 159 unsigned i; 160 161 assert(shader < PIPE_SHADER_TYPES); 162 assert(start + num <= PIPE_MAX_SAMPLERS); 163 164 /* we only support fragment shader samplers at this time */ 165 if (shader != PIPE_SHADER_FRAGMENT) 166 return; 167 168 /* Check for no-op */ 169 if (start + num <= svga->curr.num_samplers && 170 !memcmp(svga->curr.sampler + start, samplers, num * sizeof(void *))) { 171 if (0) debug_printf("sampler noop\n"); 172 return; 173 } 174 175 for (i = 0; i < num; i++) 176 svga->curr.sampler[start + i] = samplers[i]; 177 178 /* find highest non-null sampler_views[] entry */ 179 { 180 unsigned j = MAX2(svga->curr.num_samplers, start + num); 181 while (j > 0 && svga->curr.sampler[j - 1] == NULL) 182 j--; 183 svga->curr.num_samplers = j; 184 } 185 186 svga->dirty |= SVGA_NEW_SAMPLER; 187 } 188 189 190 static void 191 svga_bind_fragment_sampler_states(struct pipe_context *pipe, 192 unsigned num, void **sampler) 193 { 194 svga_bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, num, sampler); 195 } 196 197 198 static void svga_delete_sampler_state(struct pipe_context *pipe, 199 void *sampler) 200 { 201 FREE(sampler); 202 } 203 204 205 static struct pipe_sampler_view * 206 svga_create_sampler_view(struct pipe_context *pipe, 207 struct pipe_resource *texture, 208 const struct pipe_sampler_view *templ) 209 { 210 struct pipe_sampler_view *view = CALLOC_STRUCT(pipe_sampler_view); 211 212 if (view) { 213 *view = *templ; 214 view->reference.count = 1; 215 view->texture = NULL; 216 pipe_resource_reference(&view->texture, texture); 217 view->context = pipe; 218 } 219 220 return view; 221 } 222 223 224 static void 225 svga_sampler_view_destroy(struct pipe_context *pipe, 226 struct pipe_sampler_view *view) 227 { 228 pipe_resource_reference(&view->texture, NULL); 229 FREE(view); 230 } 231 232 static void 233 svga_set_sampler_views(struct pipe_context *pipe, 234 unsigned shader, 235 unsigned start, 236 unsigned num, 237 struct pipe_sampler_view **views) 238 { 239 struct svga_context *svga = svga_context(pipe); 240 unsigned flag_1d = 0; 241 unsigned flag_srgb = 0; 242 uint i; 243 244 assert(shader < PIPE_SHADER_TYPES); 245 assert(start + num <= Elements(svga->curr.sampler_views)); 246 247 /* we only support fragment shader sampler views at this time */ 248 if (shader != PIPE_SHADER_FRAGMENT) 249 return; 250 251 /* Check for no-op */ 252 if (start + num <= svga->curr.num_sampler_views && 253 !memcmp(svga->curr.sampler_views + start, views, 254 num * sizeof(struct pipe_sampler_view *))) { 255 if (0) debug_printf("texture noop\n"); 256 return; 257 } 258 259 for (i = 0; i < num; i++) { 260 if (svga->curr.sampler_views[start + i] != views[i]) { 261 /* Note: we're using pipe_sampler_view_release() here to work around 262 * a possible crash when the old view belongs to another context that 263 * was already destroyed. 264 */ 265 pipe_sampler_view_release(pipe, &svga->curr.sampler_views[start + i]); 266 pipe_sampler_view_reference(&svga->curr.sampler_views[start + i], 267 views[i]); 268 } 269 270 if (!views[i]) 271 continue; 272 273 if (util_format_is_srgb(views[i]->format)) 274 flag_srgb |= 1 << (start + i); 275 276 if (views[i]->texture->target == PIPE_TEXTURE_1D) 277 flag_1d |= 1 << (start + i); 278 } 279 280 /* find highest non-null sampler_views[] entry */ 281 { 282 unsigned j = MAX2(svga->curr.num_sampler_views, start + num); 283 while (j > 0 && svga->curr.sampler_views[j - 1] == NULL) 284 j--; 285 svga->curr.num_sampler_views = j; 286 } 287 288 svga->dirty |= SVGA_NEW_TEXTURE_BINDING; 289 290 if (flag_srgb != svga->curr.tex_flags.flag_srgb || 291 flag_1d != svga->curr.tex_flags.flag_1d) 292 { 293 svga->dirty |= SVGA_NEW_TEXTURE_FLAGS; 294 svga->curr.tex_flags.flag_1d = flag_1d; 295 svga->curr.tex_flags.flag_srgb = flag_srgb; 296 } 297 } 298 299 300 static void 301 svga_set_fragment_sampler_views(struct pipe_context *pipe, 302 unsigned num, 303 struct pipe_sampler_view **views) 304 { 305 svga_set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, num, views); 306 } 307 308 309 void svga_init_sampler_functions( struct svga_context *svga ) 310 { 311 svga->pipe.create_sampler_state = svga_create_sampler_state; 312 svga->pipe.bind_fragment_sampler_states = svga_bind_fragment_sampler_states; 313 svga->pipe.delete_sampler_state = svga_delete_sampler_state; 314 svga->pipe.set_fragment_sampler_views = svga_set_fragment_sampler_views; 315 svga->pipe.create_sampler_view = svga_create_sampler_view; 316 svga->pipe.sampler_view_destroy = svga_sampler_view_destroy; 317 } 318 319 320 321