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_format.h" 27 #include "util/u_inlines.h" 28 #include "util/u_memory.h" 29 #include "pipe/p_defines.h" 30 #include "util/u_math.h" 31 32 #include "svga_context.h" 33 #include "svga_screen.h" 34 #include "svga_state.h" 35 #include "svga_cmd.h" 36 37 38 struct rs_queue { 39 unsigned rs_count; 40 SVGA3dRenderState rs[SVGA3D_RS_MAX]; 41 }; 42 43 44 #define EMIT_RS(svga, value, token, fail) \ 45 do { \ 46 assert(SVGA3D_RS_##token < Elements(svga->state.hw_draw.rs)); \ 47 if (svga->state.hw_draw.rs[SVGA3D_RS_##token] != value) { \ 48 svga_queue_rs( &queue, SVGA3D_RS_##token, value ); \ 49 svga->state.hw_draw.rs[SVGA3D_RS_##token] = value; \ 50 } \ 51 } while (0) 52 53 #define EMIT_RS_FLOAT(svga, fvalue, token, fail) \ 54 do { \ 55 unsigned value = fui(fvalue); \ 56 assert(SVGA3D_RS_##token < Elements(svga->state.hw_draw.rs)); \ 57 if (svga->state.hw_draw.rs[SVGA3D_RS_##token] != value) { \ 58 svga_queue_rs( &queue, SVGA3D_RS_##token, value ); \ 59 svga->state.hw_draw.rs[SVGA3D_RS_##token] = value; \ 60 } \ 61 } while (0) 62 63 64 static INLINE void 65 svga_queue_rs( struct rs_queue *q, 66 unsigned rss, 67 unsigned value ) 68 { 69 q->rs[q->rs_count].state = rss; 70 q->rs[q->rs_count].uintValue = value; 71 q->rs_count++; 72 } 73 74 75 /* Compare old and new render states and emit differences between them 76 * to hardware. Simplest implementation would be to emit the whole of 77 * the "to" state. 78 */ 79 static enum pipe_error 80 emit_rss(struct svga_context *svga, unsigned dirty) 81 { 82 struct svga_screen *screen = svga_screen(svga->pipe.screen); 83 struct rs_queue queue; 84 float point_size_min; 85 86 queue.rs_count = 0; 87 88 if (dirty & SVGA_NEW_BLEND) { 89 const struct svga_blend_state *curr = svga->curr.blend; 90 91 EMIT_RS( svga, curr->rt[0].writemask, COLORWRITEENABLE, fail ); 92 EMIT_RS( svga, curr->rt[0].blend_enable, BLENDENABLE, fail ); 93 94 if (curr->rt[0].blend_enable) { 95 EMIT_RS( svga, curr->rt[0].srcblend, SRCBLEND, fail ); 96 EMIT_RS( svga, curr->rt[0].dstblend, DSTBLEND, fail ); 97 EMIT_RS( svga, curr->rt[0].blendeq, BLENDEQUATION, fail ); 98 99 EMIT_RS( svga, curr->rt[0].separate_alpha_blend_enable, 100 SEPARATEALPHABLENDENABLE, fail ); 101 102 if (curr->rt[0].separate_alpha_blend_enable) { 103 EMIT_RS( svga, curr->rt[0].srcblend_alpha, SRCBLENDALPHA, fail ); 104 EMIT_RS( svga, curr->rt[0].dstblend_alpha, DSTBLENDALPHA, fail ); 105 EMIT_RS( svga, curr->rt[0].blendeq_alpha, BLENDEQUATIONALPHA, fail ); 106 } 107 } 108 } 109 110 if (dirty & SVGA_NEW_BLEND_COLOR) { 111 uint32 color; 112 uint32 r = float_to_ubyte(svga->curr.blend_color.color[0]); 113 uint32 g = float_to_ubyte(svga->curr.blend_color.color[1]); 114 uint32 b = float_to_ubyte(svga->curr.blend_color.color[2]); 115 uint32 a = float_to_ubyte(svga->curr.blend_color.color[3]); 116 117 color = (a << 24) | (r << 16) | (g << 8) | b; 118 119 EMIT_RS( svga, color, BLENDCOLOR, fail ); 120 } 121 122 if (dirty & (SVGA_NEW_DEPTH_STENCIL | SVGA_NEW_RAST)) { 123 const struct svga_depth_stencil_state *curr = svga->curr.depth; 124 const struct svga_rasterizer_state *rast = svga->curr.rast; 125 126 if (!curr->stencil[0].enabled) 127 { 128 /* Stencil disabled 129 */ 130 EMIT_RS( svga, FALSE, STENCILENABLE, fail ); 131 EMIT_RS( svga, FALSE, STENCILENABLE2SIDED, fail ); 132 } 133 else if (curr->stencil[0].enabled && !curr->stencil[1].enabled) 134 { 135 /* Regular stencil 136 */ 137 EMIT_RS( svga, TRUE, STENCILENABLE, fail ); 138 EMIT_RS( svga, FALSE, STENCILENABLE2SIDED, fail ); 139 140 EMIT_RS( svga, curr->stencil[0].func, STENCILFUNC, fail ); 141 EMIT_RS( svga, curr->stencil[0].fail, STENCILFAIL, fail ); 142 EMIT_RS( svga, curr->stencil[0].zfail, STENCILZFAIL, fail ); 143 EMIT_RS( svga, curr->stencil[0].pass, STENCILPASS, fail ); 144 145 EMIT_RS( svga, curr->stencil_mask, STENCILMASK, fail ); 146 EMIT_RS( svga, curr->stencil_writemask, STENCILWRITEMASK, fail ); 147 } 148 else 149 { 150 int cw, ccw; 151 152 /* Hardware frontwinding is always CW, so if ours is also CW, 153 * then our definition of front face agrees with hardware. 154 * Otherwise need to flip. 155 */ 156 if (rast->templ.front_ccw) { 157 ccw = 0; 158 cw = 1; 159 } 160 else { 161 ccw = 1; 162 cw = 0; 163 } 164 165 /* Twoside stencil 166 */ 167 EMIT_RS( svga, TRUE, STENCILENABLE, fail ); 168 EMIT_RS( svga, TRUE, STENCILENABLE2SIDED, fail ); 169 170 EMIT_RS( svga, curr->stencil[cw].func, STENCILFUNC, fail ); 171 EMIT_RS( svga, curr->stencil[cw].fail, STENCILFAIL, fail ); 172 EMIT_RS( svga, curr->stencil[cw].zfail, STENCILZFAIL, fail ); 173 EMIT_RS( svga, curr->stencil[cw].pass, STENCILPASS, fail ); 174 175 EMIT_RS( svga, curr->stencil[ccw].func, CCWSTENCILFUNC, fail ); 176 EMIT_RS( svga, curr->stencil[ccw].fail, CCWSTENCILFAIL, fail ); 177 EMIT_RS( svga, curr->stencil[ccw].zfail, CCWSTENCILZFAIL, fail ); 178 EMIT_RS( svga, curr->stencil[ccw].pass, CCWSTENCILPASS, fail ); 179 180 EMIT_RS( svga, curr->stencil_mask, STENCILMASK, fail ); 181 EMIT_RS( svga, curr->stencil_writemask, STENCILWRITEMASK, fail ); 182 } 183 184 EMIT_RS( svga, curr->zenable, ZENABLE, fail ); 185 if (curr->zenable) { 186 EMIT_RS( svga, curr->zfunc, ZFUNC, fail ); 187 EMIT_RS( svga, curr->zwriteenable, ZWRITEENABLE, fail ); 188 } 189 190 EMIT_RS( svga, curr->alphatestenable, ALPHATESTENABLE, fail ); 191 if (curr->alphatestenable) { 192 EMIT_RS( svga, curr->alphafunc, ALPHAFUNC, fail ); 193 EMIT_RS_FLOAT( svga, curr->alpharef, ALPHAREF, fail ); 194 } 195 } 196 197 if (dirty & SVGA_NEW_STENCIL_REF) { 198 EMIT_RS( svga, svga->curr.stencil_ref.ref_value[0], STENCILREF, fail ); 199 } 200 201 if (dirty & (SVGA_NEW_RAST | SVGA_NEW_NEED_PIPELINE)) 202 { 203 const struct svga_rasterizer_state *curr = svga->curr.rast; 204 unsigned cullmode = curr->cullmode; 205 206 /* Shademode: still need to rearrange index list to move 207 * flat-shading PV first vertex. 208 */ 209 EMIT_RS( svga, curr->shademode, SHADEMODE, fail ); 210 211 /* Don't do culling while the software pipeline is active. It 212 * does it for us, and additionally introduces potentially 213 * back-facing triangles. 214 */ 215 if (svga->state.sw.need_pipeline) 216 cullmode = SVGA3D_FACE_NONE; 217 218 point_size_min = util_get_min_point_size(&curr->templ); 219 220 EMIT_RS( svga, cullmode, CULLMODE, fail ); 221 EMIT_RS( svga, curr->scissortestenable, SCISSORTESTENABLE, fail ); 222 EMIT_RS( svga, curr->multisampleantialias, MULTISAMPLEANTIALIAS, fail ); 223 EMIT_RS( svga, curr->lastpixel, LASTPIXEL, fail ); 224 EMIT_RS( svga, curr->linepattern, LINEPATTERN, fail ); 225 EMIT_RS_FLOAT( svga, curr->pointsize, POINTSIZE, fail ); 226 EMIT_RS_FLOAT( svga, point_size_min, POINTSIZEMIN, fail ); 227 EMIT_RS_FLOAT( svga, screen->maxPointSize, POINTSIZEMAX, fail ); 228 EMIT_RS( svga, curr->pointsprite, POINTSPRITEENABLE, fail); 229 } 230 231 if (dirty & (SVGA_NEW_RAST | SVGA_NEW_FRAME_BUFFER | SVGA_NEW_NEED_PIPELINE)) 232 { 233 const struct svga_rasterizer_state *curr = svga->curr.rast; 234 float slope = 0.0; 235 float bias = 0.0; 236 237 /* Need to modify depth bias according to bound depthbuffer 238 * format. Don't do hardware depthbias while the software 239 * pipeline is active. 240 */ 241 if (!svga->state.sw.need_pipeline && 242 svga->curr.framebuffer.zsbuf) 243 { 244 slope = curr->slopescaledepthbias; 245 bias = svga->curr.depthscale * curr->depthbias; 246 } 247 248 EMIT_RS_FLOAT( svga, slope, SLOPESCALEDEPTHBIAS, fail ); 249 EMIT_RS_FLOAT( svga, bias, DEPTHBIAS, fail ); 250 } 251 252 if (dirty & SVGA_NEW_FRAME_BUFFER) { 253 /* XXX: we only look at the first color buffer's sRGB state */ 254 float gamma = 1.0f; 255 if (svga->curr.framebuffer.cbufs[0] && 256 util_format_is_srgb(svga->curr.framebuffer.cbufs[0]->format)) { 257 gamma = 2.2f; 258 } 259 EMIT_RS_FLOAT(svga, gamma, OUTPUTGAMMA, fail); 260 } 261 262 if (dirty & SVGA_NEW_RAST) { 263 /* bitmask of the enabled clip planes */ 264 unsigned enabled = svga->curr.rast->templ.clip_plane_enable; 265 EMIT_RS( svga, enabled, CLIPPLANEENABLE, fail ); 266 } 267 268 if (queue.rs_count) { 269 SVGA3dRenderState *rs; 270 271 if (SVGA3D_BeginSetRenderState( svga->swc, 272 &rs, 273 queue.rs_count ) != PIPE_OK) 274 goto fail; 275 276 memcpy( rs, 277 queue.rs, 278 queue.rs_count * sizeof queue.rs[0]); 279 280 SVGA_FIFOCommitAll( svga->swc ); 281 } 282 283 return PIPE_OK; 284 285 fail: 286 /* XXX: need to poison cached hardware state on failure to ensure 287 * dirty state gets re-emitted. Fix this by re-instating partial 288 * FIFOCommit command and only updating cached hw state once the 289 * initial allocation has succeeded. 290 */ 291 memset(svga->state.hw_draw.rs, 0xcd, sizeof(svga->state.hw_draw.rs)); 292 293 return PIPE_ERROR_OUT_OF_MEMORY; 294 } 295 296 297 struct svga_tracked_state svga_hw_rss = 298 { 299 "hw rss state", 300 301 (SVGA_NEW_BLEND | 302 SVGA_NEW_BLEND_COLOR | 303 SVGA_NEW_DEPTH_STENCIL | 304 SVGA_NEW_STENCIL_REF | 305 SVGA_NEW_RAST | 306 SVGA_NEW_FRAME_BUFFER | 307 SVGA_NEW_NEED_PIPELINE), 308 309 emit_rss 310 }; 311