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