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 "util/u_memory.h" 28 #include "pipe/p_defines.h" 29 #include "util/u_math.h" 30 31 #include "svga_sampler_view.h" 32 #include "svga_winsys.h" 33 #include "svga_context.h" 34 #include "svga_state.h" 35 #include "svga_cmd.h" 36 37 38 void svga_cleanup_tss_binding(struct svga_context *svga) 39 { 40 int i; 41 unsigned count = MAX2( svga->curr.num_sampler_views, 42 svga->state.hw_draw.num_views ); 43 44 for (i = 0; i < count; i++) { 45 struct svga_hw_view_state *view = &svga->state.hw_draw.views[i]; 46 47 svga_sampler_view_reference(&view->v, NULL); 48 pipe_sampler_view_reference( &svga->curr.sampler_views[i], NULL ); 49 pipe_resource_reference( &view->texture, NULL ); 50 51 view->dirty = 1; 52 } 53 } 54 55 56 struct bind_queue { 57 struct { 58 unsigned unit; 59 struct svga_hw_view_state *view; 60 } bind[PIPE_MAX_SAMPLERS]; 61 62 unsigned bind_count; 63 }; 64 65 66 static enum pipe_error 67 update_tss_binding(struct svga_context *svga, 68 unsigned dirty ) 69 { 70 boolean reemit = svga->rebind.texture_samplers; 71 unsigned i; 72 unsigned count = MAX2( svga->curr.num_sampler_views, 73 svga->state.hw_draw.num_views ); 74 unsigned min_lod; 75 unsigned max_lod; 76 77 struct bind_queue queue; 78 79 queue.bind_count = 0; 80 81 for (i = 0; i < count; i++) { 82 const struct svga_sampler_state *s = svga->curr.sampler[i]; 83 struct svga_hw_view_state *view = &svga->state.hw_draw.views[i]; 84 struct pipe_resource *texture = NULL; 85 struct pipe_sampler_view *sv = svga->curr.sampler_views[i]; 86 87 /* get min max lod */ 88 if (sv) { 89 min_lod = MAX2(0, (s->view_min_lod + sv->u.tex.first_level)); 90 max_lod = MIN2(s->view_max_lod + sv->u.tex.first_level, 91 sv->texture->last_level); 92 texture = sv->texture; 93 } else { 94 min_lod = 0; 95 max_lod = 0; 96 } 97 98 if (view->texture != texture || 99 view->min_lod != min_lod || 100 view->max_lod != max_lod) { 101 102 svga_sampler_view_reference(&view->v, NULL); 103 pipe_resource_reference( &view->texture, texture ); 104 105 view->dirty = TRUE; 106 view->min_lod = min_lod; 107 view->max_lod = max_lod; 108 109 if (texture) 110 view->v = svga_get_tex_sampler_view(&svga->pipe, 111 texture, 112 min_lod, 113 max_lod); 114 } 115 116 /* 117 * We need to reemit non-null texture bindings, even when they are not 118 * dirty, to ensure that the resources are paged in. 119 */ 120 121 if (view->dirty || 122 (reemit && view->v)) { 123 queue.bind[queue.bind_count].unit = i; 124 queue.bind[queue.bind_count].view = view; 125 queue.bind_count++; 126 } 127 if (!view->dirty && view->v) { 128 svga_validate_sampler_view(svga, view->v); 129 } 130 } 131 132 svga->state.hw_draw.num_views = svga->curr.num_sampler_views; 133 134 if (queue.bind_count) { 135 SVGA3dTextureState *ts; 136 137 if (SVGA3D_BeginSetTextureState( svga->swc, 138 &ts, 139 queue.bind_count ) != PIPE_OK) 140 goto fail; 141 142 for (i = 0; i < queue.bind_count; i++) { 143 struct svga_winsys_surface *handle; 144 145 ts[i].stage = queue.bind[i].unit; 146 ts[i].name = SVGA3D_TS_BIND_TEXTURE; 147 148 if (queue.bind[i].view->v) { 149 handle = queue.bind[i].view->v->handle; 150 } 151 else { 152 handle = NULL; 153 } 154 svga->swc->surface_relocation(svga->swc, 155 &ts[i].value, 156 handle, 157 SVGA_RELOC_READ); 158 159 queue.bind[i].view->dirty = FALSE; 160 } 161 162 SVGA_FIFOCommitAll( svga->swc ); 163 } 164 165 svga->rebind.texture_samplers = FALSE; 166 167 return 0; 168 169 fail: 170 return PIPE_ERROR_OUT_OF_MEMORY; 171 } 172 173 174 /* 175 * Rebind textures. 176 * 177 * Similar to update_tss_binding, but without any state checking/update. 178 * 179 * Called at the beginning of every new command buffer to ensure that 180 * non-dirty textures are properly paged-in. 181 */ 182 enum pipe_error 183 svga_reemit_tss_bindings(struct svga_context *svga) 184 { 185 unsigned i; 186 enum pipe_error ret; 187 struct bind_queue queue; 188 189 assert(svga->rebind.texture_samplers); 190 191 queue.bind_count = 0; 192 193 for (i = 0; i < svga->state.hw_draw.num_views; i++) { 194 struct svga_hw_view_state *view = &svga->state.hw_draw.views[i]; 195 196 if (view->v) { 197 queue.bind[queue.bind_count].unit = i; 198 queue.bind[queue.bind_count].view = view; 199 queue.bind_count++; 200 } 201 } 202 203 if (queue.bind_count) { 204 SVGA3dTextureState *ts; 205 206 ret = SVGA3D_BeginSetTextureState(svga->swc, 207 &ts, 208 queue.bind_count); 209 if (ret != PIPE_OK) { 210 return ret; 211 } 212 213 for (i = 0; i < queue.bind_count; i++) { 214 struct svga_winsys_surface *handle; 215 216 ts[i].stage = queue.bind[i].unit; 217 ts[i].name = SVGA3D_TS_BIND_TEXTURE; 218 219 assert(queue.bind[i].view->v); 220 handle = queue.bind[i].view->v->handle; 221 svga->swc->surface_relocation(svga->swc, 222 &ts[i].value, 223 handle, 224 SVGA_RELOC_READ); 225 } 226 227 SVGA_FIFOCommitAll(svga->swc); 228 } 229 230 svga->rebind.texture_samplers = FALSE; 231 232 return PIPE_OK; 233 } 234 235 236 struct svga_tracked_state svga_hw_tss_binding = { 237 "texture binding emit", 238 SVGA_NEW_TEXTURE_BINDING | 239 SVGA_NEW_SAMPLER, 240 update_tss_binding 241 }; 242 243 244 /*********************************************************************** 245 */ 246 247 struct ts_queue { 248 unsigned ts_count; 249 SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX]; 250 }; 251 252 253 #define EMIT_TS(svga, unit, val, token, fail) \ 254 do { \ 255 assert(unit < Elements(svga->state.hw_draw.ts)); \ 256 assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit])); \ 257 if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \ 258 svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \ 259 svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \ 260 } \ 261 } while (0) 262 263 #define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail) \ 264 do { \ 265 unsigned val = fui(fvalue); \ 266 assert(unit < Elements(svga->state.hw_draw.ts)); \ 267 assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit])); \ 268 if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \ 269 svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \ 270 svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \ 271 } \ 272 } while (0) 273 274 275 static INLINE void 276 svga_queue_tss( struct ts_queue *q, 277 unsigned unit, 278 unsigned tss, 279 unsigned value ) 280 { 281 assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0])); 282 q->ts[q->ts_count].stage = unit; 283 q->ts[q->ts_count].name = tss; 284 q->ts[q->ts_count].value = value; 285 q->ts_count++; 286 } 287 288 289 static enum pipe_error 290 update_tss(struct svga_context *svga, 291 unsigned dirty ) 292 { 293 unsigned i; 294 struct ts_queue queue; 295 296 queue.ts_count = 0; 297 for (i = 0; i < svga->curr.num_samplers; i++) { 298 if (svga->curr.sampler[i]) { 299 const struct svga_sampler_state *curr = svga->curr.sampler[i]; 300 301 EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail); 302 EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail); 303 EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail); 304 EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail); 305 EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail); 306 EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail); 307 EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail); 308 EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail); 309 EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail); 310 // TEXCOORDINDEX -- hopefully not needed 311 312 if (svga->curr.tex_flags.flag_1d & (1 << i)) { 313 EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail); 314 } 315 else 316 EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail); 317 318 if (svga->curr.tex_flags.flag_srgb & (1 << i)) 319 EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail); 320 else 321 EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail); 322 323 } 324 } 325 326 if (queue.ts_count) { 327 SVGA3dTextureState *ts; 328 329 if (SVGA3D_BeginSetTextureState( svga->swc, 330 &ts, 331 queue.ts_count ) != PIPE_OK) 332 goto fail; 333 334 memcpy( ts, 335 queue.ts, 336 queue.ts_count * sizeof queue.ts[0]); 337 338 SVGA_FIFOCommitAll( svga->swc ); 339 } 340 341 return PIPE_OK; 342 343 fail: 344 /* XXX: need to poison cached hardware state on failure to ensure 345 * dirty state gets re-emitted. Fix this by re-instating partial 346 * FIFOCommit command and only updating cached hw state once the 347 * initial allocation has succeeded. 348 */ 349 memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts)); 350 351 return PIPE_ERROR_OUT_OF_MEMORY; 352 } 353 354 355 struct svga_tracked_state svga_hw_tss = { 356 "texture state emit", 357 (SVGA_NEW_SAMPLER | 358 SVGA_NEW_TEXTURE_FLAGS), 359 update_tss 360 }; 361 362