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