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