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_debug.h" 27#include "pipe/p_defines.h" 28#include "util/u_memory.h" 29#include "draw/draw_context.h" 30 31#include "svga_context.h" 32#include "svga_screen.h" 33#include "svga_state.h" 34#include "svga_draw.h" 35#include "svga_cmd.h" 36#include "svga_hw_reg.h" 37 38/* This is just enough to decide whether we need to use the draw 39 * module (swtnl) or not. 40 */ 41static const struct svga_tracked_state *need_swtnl_state[] = 42{ 43 &svga_update_need_swvfetch, 44 &svga_update_need_pipeline, 45 &svga_update_need_swtnl, 46 NULL 47}; 48 49 50/* Atoms to update hardware state prior to emitting a clear or draw 51 * packet. 52 */ 53static const struct svga_tracked_state *hw_clear_state[] = 54{ 55 &svga_hw_scissor, 56 &svga_hw_viewport, 57 &svga_hw_framebuffer, 58 NULL 59}; 60 61 62/* Atoms to update hardware state prior to emitting a draw packet. 63 */ 64static const struct svga_tracked_state *hw_draw_state[] = 65{ 66 &svga_hw_fs, 67 &svga_hw_vs, 68 &svga_hw_rss, 69 &svga_hw_tss, 70 &svga_hw_tss_binding, 71 &svga_hw_clip_planes, 72 &svga_hw_vdecl, 73 &svga_hw_fs_constants, 74 &svga_hw_vs_constants, 75 NULL 76}; 77 78 79static const struct svga_tracked_state *swtnl_draw_state[] = 80{ 81 &svga_update_swtnl_draw, 82 &svga_update_swtnl_vdecl, 83 NULL 84}; 85 86/* Flattens the graph of state dependencies. Could swap the positions 87 * of hw_clear_state and need_swtnl_state without breaking anything. 88 */ 89static const struct svga_tracked_state **state_levels[] = 90{ 91 need_swtnl_state, 92 hw_clear_state, 93 hw_draw_state, 94 swtnl_draw_state 95}; 96 97 98 99static unsigned check_state( unsigned a, 100 unsigned b ) 101{ 102 return (a & b); 103} 104 105static void accumulate_state( unsigned *a, 106 unsigned b ) 107{ 108 *a |= b; 109} 110 111 112static void xor_states( unsigned *result, 113 unsigned a, 114 unsigned b ) 115{ 116 *result = a ^ b; 117} 118 119 120 121static enum pipe_error 122update_state(struct svga_context *svga, 123 const struct svga_tracked_state *atoms[], 124 unsigned *state) 125{ 126 boolean debug = TRUE; 127 enum pipe_error ret = PIPE_OK; 128 unsigned i; 129 130 ret = svga_hwtnl_flush( svga->hwtnl ); 131 if (ret != PIPE_OK) 132 return ret; 133 134 if (debug) { 135 /* Debug version which enforces various sanity checks on the 136 * state flags which are generated and checked to help ensure 137 * state atoms are ordered correctly in the list. 138 */ 139 unsigned examined, prev; 140 141 examined = 0; 142 prev = *state; 143 144 for (i = 0; atoms[i] != NULL; i++) { 145 unsigned generated; 146 147 assert(atoms[i]->dirty); 148 assert(atoms[i]->update); 149 150 if (check_state(*state, atoms[i]->dirty)) { 151 if (0) 152 debug_printf("update: %s\n", atoms[i]->name); 153 ret = atoms[i]->update( svga, *state ); 154 if (ret != PIPE_OK) 155 return ret; 156 } 157 158 /* generated = (prev ^ state) 159 * if (examined & generated) 160 * fail; 161 */ 162 xor_states(&generated, prev, *state); 163 if (check_state(examined, generated)) { 164 debug_printf("state atom %s generated state already examined\n", 165 atoms[i]->name); 166 assert(0); 167 } 168 169 prev = *state; 170 accumulate_state(&examined, atoms[i]->dirty); 171 } 172 } 173 else { 174 for (i = 0; atoms[i] != NULL; i++) { 175 if (check_state(*state, atoms[i]->dirty)) { 176 ret = atoms[i]->update( svga, *state ); 177 if (ret != PIPE_OK) 178 return ret; 179 } 180 } 181 } 182 183 return PIPE_OK; 184} 185 186 187 188enum pipe_error 189svga_update_state(struct svga_context *svga, unsigned max_level) 190{ 191 struct svga_screen *screen = svga_screen(svga->pipe.screen); 192 enum pipe_error ret = PIPE_OK; 193 int i; 194 195 /* Check for updates to bound textures. This can't be done in an 196 * atom as there is no flag which could provoke this test, and we 197 * cannot create one. 198 */ 199 if (svga->state.texture_timestamp != screen->texture_timestamp) { 200 svga->state.texture_timestamp = screen->texture_timestamp; 201 svga->dirty |= SVGA_NEW_TEXTURE; 202 } 203 204 for (i = 0; i <= max_level; i++) { 205 svga->dirty |= svga->state.dirty[i]; 206 207 if (svga->dirty) { 208 ret = update_state( svga, 209 state_levels[i], 210 &svga->dirty ); 211 if (ret != PIPE_OK) 212 return ret; 213 214 svga->state.dirty[i] = 0; 215 } 216 } 217 218 for (; i < SVGA_STATE_MAX; i++) 219 svga->state.dirty[i] |= svga->dirty; 220 221 svga->dirty = 0; 222 return PIPE_OK; 223} 224 225 226 227 228void svga_update_state_retry( struct svga_context *svga, 229 unsigned max_level ) 230{ 231 enum pipe_error ret; 232 233 ret = svga_update_state( svga, max_level ); 234 235 if (ret == PIPE_ERROR_OUT_OF_MEMORY) { 236 svga_context_flush(svga, NULL); 237 ret = svga_update_state( svga, max_level ); 238 } 239 240 assert( ret == PIPE_OK ); 241} 242 243 244 245#define EMIT_RS(_rs, _count, _name, _value) \ 246do { \ 247 _rs[_count].state = _name; \ 248 _rs[_count].uintValue = _value; \ 249 _count++; \ 250} while (0) 251 252 253/* Setup any hardware state which will be constant through the life of 254 * a context. 255 */ 256enum pipe_error svga_emit_initial_state( struct svga_context *svga ) 257{ 258 SVGA3dRenderState *rs; 259 unsigned count = 0; 260 const unsigned COUNT = 2; 261 enum pipe_error ret; 262 263 ret = SVGA3D_BeginSetRenderState( svga->swc, &rs, COUNT ); 264 if (ret != PIPE_OK) 265 return ret; 266 267 /* Always use D3D style coordinate space as this is the only one 268 * which is implemented on all backends. 269 */ 270 EMIT_RS(rs, count, SVGA3D_RS_COORDINATETYPE, SVGA3D_COORDINATE_LEFTHANDED ); 271 EMIT_RS(rs, count, SVGA3D_RS_FRONTWINDING, SVGA3D_FRONTWINDING_CW ); 272 273 assert( COUNT == count ); 274 SVGA_FIFOCommitAll( svga->swc ); 275 276 return PIPE_OK; 277} 278