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 "pipe/p_defines.h" 27#include "util/u_bitmask.h" 28#include "util/u_inlines.h" 29#include "util/u_math.h" 30#include "util/u_memory.h" 31 32#include "svga_context.h" 33#include "svga_hw_reg.h" 34#include "svga_cmd.h" 35 36 37static inline unsigned 38svga_translate_compare_func(unsigned func) 39{ 40 switch (func) { 41 case PIPE_FUNC_NEVER: return SVGA3D_CMP_NEVER; 42 case PIPE_FUNC_LESS: return SVGA3D_CMP_LESS; 43 case PIPE_FUNC_LEQUAL: return SVGA3D_CMP_LESSEQUAL; 44 case PIPE_FUNC_GREATER: return SVGA3D_CMP_GREATER; 45 case PIPE_FUNC_GEQUAL: return SVGA3D_CMP_GREATEREQUAL; 46 case PIPE_FUNC_NOTEQUAL: return SVGA3D_CMP_NOTEQUAL; 47 case PIPE_FUNC_EQUAL: return SVGA3D_CMP_EQUAL; 48 case PIPE_FUNC_ALWAYS: return SVGA3D_CMP_ALWAYS; 49 default: 50 assert(0); 51 return SVGA3D_CMP_ALWAYS; 52 } 53} 54 55static inline unsigned 56svga_translate_stencil_op(unsigned op) 57{ 58 switch (op) { 59 case PIPE_STENCIL_OP_KEEP: return SVGA3D_STENCILOP_KEEP; 60 case PIPE_STENCIL_OP_ZERO: return SVGA3D_STENCILOP_ZERO; 61 case PIPE_STENCIL_OP_REPLACE: return SVGA3D_STENCILOP_REPLACE; 62 case PIPE_STENCIL_OP_INCR: return SVGA3D_STENCILOP_INCRSAT; 63 case PIPE_STENCIL_OP_DECR: return SVGA3D_STENCILOP_DECRSAT; 64 case PIPE_STENCIL_OP_INCR_WRAP: return SVGA3D_STENCILOP_INCR; 65 case PIPE_STENCIL_OP_DECR_WRAP: return SVGA3D_STENCILOP_DECR; 66 case PIPE_STENCIL_OP_INVERT: return SVGA3D_STENCILOP_INVERT; 67 default: 68 assert(0); 69 return SVGA3D_STENCILOP_KEEP; 70 } 71} 72 73 74/** 75 * Define a vgpu10 depth/stencil state object for the given 76 * svga depth/stencil state. 77 */ 78static void 79define_depth_stencil_state_object(struct svga_context *svga, 80 struct svga_depth_stencil_state *ds) 81{ 82 unsigned try; 83 84 assert(svga_have_vgpu10(svga)); 85 86 ds->id = util_bitmask_add(svga->ds_object_id_bm); 87 88 /* spot check that these comparision tokens are the same */ 89 STATIC_ASSERT(SVGA3D_COMPARISON_NEVER == SVGA3D_CMP_NEVER); 90 STATIC_ASSERT(SVGA3D_COMPARISON_LESS == SVGA3D_CMP_LESS); 91 STATIC_ASSERT(SVGA3D_COMPARISON_NOT_EQUAL == SVGA3D_CMP_NOTEQUAL); 92 93 /* Loop in case command buffer is full and we need to flush and retry */ 94 for (try = 0; try < 2; try++) { 95 enum pipe_error ret; 96 97 /* Note: we use the ds->stencil[0].enabled value for both the front 98 * and back-face enables. If single-side stencil is used, we'll have 99 * set the back state the same as the front state. 100 */ 101 ret = SVGA3D_vgpu10_DefineDepthStencilState(svga->swc, 102 ds->id, 103 /* depth/Z */ 104 ds->zenable, 105 ds->zwriteenable, 106 ds->zfunc, 107 /* Stencil */ 108 ds->stencil[0].enabled, /*f|b*/ 109 ds->stencil[0].enabled, /*f*/ 110 ds->stencil[0].enabled, /*b*/ 111 ds->stencil_mask, 112 ds->stencil_writemask, 113 /* front stencil */ 114 ds->stencil[0].fail, 115 ds->stencil[0].zfail, 116 ds->stencil[0].pass, 117 ds->stencil[0].func, 118 /* back stencil */ 119 ds->stencil[1].fail, 120 ds->stencil[1].zfail, 121 ds->stencil[1].pass, 122 ds->stencil[1].func); 123 if (ret == PIPE_OK) 124 return; 125 svga_context_flush(svga, NULL); 126 } 127} 128 129 130static void * 131svga_create_depth_stencil_state(struct pipe_context *pipe, 132 const struct pipe_depth_stencil_alpha_state *templ) 133{ 134 struct svga_context *svga = svga_context(pipe); 135 struct svga_depth_stencil_state *ds = CALLOC_STRUCT(svga_depth_stencil_state); 136 137 if (!ds) 138 return NULL; 139 140 /* Don't try to figure out CW/CCW correspondence with 141 * stencil[0]/[1] at this point. Presumably this can change as 142 * back/front face are modified. 143 */ 144 ds->stencil[0].enabled = templ->stencil[0].enabled; 145 if (ds->stencil[0].enabled) { 146 ds->stencil[0].func = svga_translate_compare_func(templ->stencil[0].func); 147 ds->stencil[0].fail = svga_translate_stencil_op(templ->stencil[0].fail_op); 148 ds->stencil[0].zfail = svga_translate_stencil_op(templ->stencil[0].zfail_op); 149 ds->stencil[0].pass = svga_translate_stencil_op(templ->stencil[0].zpass_op); 150 151 /* SVGA3D has one ref/mask/writemask triple shared between front & 152 * back face stencil. We really need two: 153 */ 154 ds->stencil_mask = templ->stencil[0].valuemask & 0xff; 155 ds->stencil_writemask = templ->stencil[0].writemask & 0xff; 156 } 157 else { 158 ds->stencil[0].func = SVGA3D_CMP_ALWAYS; 159 ds->stencil[0].fail = SVGA3D_STENCILOP_KEEP; 160 ds->stencil[0].zfail = SVGA3D_STENCILOP_KEEP; 161 ds->stencil[0].pass = SVGA3D_STENCILOP_KEEP; 162 } 163 164 ds->stencil[1].enabled = templ->stencil[1].enabled; 165 if (templ->stencil[1].enabled) { 166 assert(templ->stencil[0].enabled); 167 /* two-sided stencil */ 168 ds->stencil[1].func = svga_translate_compare_func(templ->stencil[1].func); 169 ds->stencil[1].fail = svga_translate_stencil_op(templ->stencil[1].fail_op); 170 ds->stencil[1].zfail = svga_translate_stencil_op(templ->stencil[1].zfail_op); 171 ds->stencil[1].pass = svga_translate_stencil_op(templ->stencil[1].zpass_op); 172 173 ds->stencil_mask = templ->stencil[1].valuemask & 0xff; 174 ds->stencil_writemask = templ->stencil[1].writemask & 0xff; 175 } 176 else { 177 /* back face state is same as front-face state */ 178 ds->stencil[1].func = ds->stencil[0].func; 179 ds->stencil[1].fail = ds->stencil[0].fail; 180 ds->stencil[1].zfail = ds->stencil[0].zfail; 181 ds->stencil[1].pass = ds->stencil[0].pass; 182 } 183 184 185 ds->zenable = templ->depth.enabled; 186 if (ds->zenable) { 187 ds->zfunc = svga_translate_compare_func(templ->depth.func); 188 ds->zwriteenable = templ->depth.writemask; 189 } 190 else { 191 ds->zfunc = SVGA3D_CMP_ALWAYS; 192 } 193 194 ds->alphatestenable = templ->alpha.enabled; 195 if (ds->alphatestenable) { 196 ds->alphafunc = svga_translate_compare_func(templ->alpha.func); 197 ds->alpharef = templ->alpha.ref_value; 198 } 199 else { 200 ds->alphafunc = SVGA3D_CMP_ALWAYS; 201 } 202 203 if (svga_have_vgpu10(svga)) { 204 define_depth_stencil_state_object(svga, ds); 205 } 206 207 svga->hud.num_depthstencil_objects++; 208 209 SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws, 210 SVGA_STATS_COUNT_DEPTHSTENCILSTATE); 211 212 return ds; 213} 214 215 216static void 217svga_bind_depth_stencil_state(struct pipe_context *pipe, void *depth_stencil) 218{ 219 struct svga_context *svga = svga_context(pipe); 220 221 if (svga_have_vgpu10(svga)) { 222 /* flush any previously queued drawing before changing state */ 223 svga_hwtnl_flush_retry(svga); 224 } 225 226 svga->curr.depth = (const struct svga_depth_stencil_state *)depth_stencil; 227 svga->dirty |= SVGA_NEW_DEPTH_STENCIL_ALPHA; 228} 229 230 231static void 232svga_delete_depth_stencil_state(struct pipe_context *pipe, void *depth_stencil) 233{ 234 struct svga_context *svga = svga_context(pipe); 235 struct svga_depth_stencil_state *ds = 236 (struct svga_depth_stencil_state *) depth_stencil; 237 238 if (svga_have_vgpu10(svga)) { 239 enum pipe_error ret; 240 241 svga_hwtnl_flush_retry(svga); 242 243 assert(ds->id != SVGA3D_INVALID_ID); 244 245 ret = SVGA3D_vgpu10_DestroyDepthStencilState(svga->swc, ds->id); 246 if (ret != PIPE_OK) { 247 svga_context_flush(svga, NULL); 248 ret = SVGA3D_vgpu10_DestroyDepthStencilState(svga->swc, ds->id); 249 assert(ret == PIPE_OK); 250 } 251 252 if (ds->id == svga->state.hw_draw.depth_stencil_id) 253 svga->state.hw_draw.depth_stencil_id = SVGA3D_INVALID_ID; 254 255 util_bitmask_clear(svga->ds_object_id_bm, ds->id); 256 ds->id = SVGA3D_INVALID_ID; 257 } 258 259 FREE(depth_stencil); 260 svga->hud.num_depthstencil_objects--; 261} 262 263 264static void 265svga_set_stencil_ref(struct pipe_context *pipe, 266 const struct pipe_stencil_ref *stencil_ref) 267{ 268 struct svga_context *svga = svga_context(pipe); 269 270 if (svga_have_vgpu10(svga)) { 271 /* flush any previously queued drawing before changing state */ 272 svga_hwtnl_flush_retry(svga); 273 } 274 275 svga->curr.stencil_ref = *stencil_ref; 276 277 svga->dirty |= SVGA_NEW_STENCIL_REF; 278} 279 280 281static void 282svga_set_sample_mask(struct pipe_context *pipe, 283 unsigned sample_mask) 284{ 285 struct svga_context *svga = svga_context(pipe); 286 287 svga->curr.sample_mask = sample_mask; 288 289 svga->dirty |= SVGA_NEW_BLEND; /* See emit_rss_vgpu10() */ 290} 291 292 293void 294svga_init_depth_stencil_functions(struct svga_context *svga) 295{ 296 svga->pipe.create_depth_stencil_alpha_state = svga_create_depth_stencil_state; 297 svga->pipe.bind_depth_stencil_alpha_state = svga_bind_depth_stencil_state; 298 svga->pipe.delete_depth_stencil_alpha_state = svga_delete_depth_stencil_state; 299 300 svga->pipe.set_stencil_ref = svga_set_stencil_ref; 301 svga->pipe.set_sample_mask = svga_set_sample_mask; 302} 303