stencil.c revision af69d88d
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/** 27 * \file stencil.c 28 * Stencil operations. 29 * 30 * Note: There's some conflict between GL_EXT_stencil_two_side and 31 * OpenGL 2.0's two-sided stencil feature. 32 * 33 * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the 34 * front OR back face state (as set by glActiveStencilFaceEXT) is set. 35 * 36 * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the 37 * front AND back state. 38 * 39 * Also, note that GL_ATI_separate_stencil is different as well: 40 * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs. 41 * glStencilFuncSeparate(GLenum face, GLenum func, ...). 42 * 43 * This problem is solved by keeping three sets of stencil state: 44 * state[0] = GL_FRONT state. 45 * state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state. 46 * state[2] = GL_EXT_stencil_two_side GL_BACK state. 47 */ 48 49 50#include "glheader.h" 51#include "imports.h" 52#include "context.h" 53#include "macros.h" 54#include "stencil.h" 55#include "mtypes.h" 56 57 58static GLboolean 59validate_stencil_op(struct gl_context *ctx, GLenum op) 60{ 61 switch (op) { 62 case GL_KEEP: 63 case GL_ZERO: 64 case GL_REPLACE: 65 case GL_INCR: 66 case GL_DECR: 67 case GL_INVERT: 68 case GL_INCR_WRAP: 69 case GL_DECR_WRAP: 70 return GL_TRUE; 71 default: 72 return GL_FALSE; 73 } 74} 75 76 77static GLboolean 78validate_stencil_func(struct gl_context *ctx, GLenum func) 79{ 80 switch (func) { 81 case GL_NEVER: 82 case GL_LESS: 83 case GL_LEQUAL: 84 case GL_GREATER: 85 case GL_GEQUAL: 86 case GL_EQUAL: 87 case GL_NOTEQUAL: 88 case GL_ALWAYS: 89 return GL_TRUE; 90 default: 91 return GL_FALSE; 92 } 93} 94 95 96/** 97 * Set the clear value for the stencil buffer. 98 * 99 * \param s clear value. 100 * 101 * \sa glClearStencil(). 102 * 103 * Updates gl_stencil_attrib::Clear. On change 104 * flushes the vertices and notifies the driver via 105 * the dd_function_table::ClearStencil callback. 106 */ 107void GLAPIENTRY 108_mesa_ClearStencil( GLint s ) 109{ 110 GET_CURRENT_CONTEXT(ctx); 111 112 ctx->Stencil.Clear = (GLuint) s; 113} 114 115 116/** 117 * Set the function and reference value for stencil testing. 118 * 119 * \param frontfunc front test function. 120 * \param backfunc back test function. 121 * \param ref front and back reference value. 122 * \param mask front and back bitmask. 123 * 124 * \sa glStencilFunc(). 125 * 126 * Verifies the parameters and updates the respective values in 127 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the 128 * driver via the dd_function_table::StencilFunc callback. 129 */ 130void GLAPIENTRY 131_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask ) 132{ 133 GET_CURRENT_CONTEXT(ctx); 134 135 if (MESA_VERBOSE & VERBOSE_API) 136 _mesa_debug(ctx, "glStencilFuncSeparateATI()\n"); 137 138 if (!validate_stencil_func(ctx, frontfunc)) { 139 _mesa_error(ctx, GL_INVALID_ENUM, 140 "glStencilFuncSeparateATI(frontfunc)"); 141 return; 142 } 143 if (!validate_stencil_func(ctx, backfunc)) { 144 _mesa_error(ctx, GL_INVALID_ENUM, 145 "glStencilFuncSeparateATI(backfunc)"); 146 return; 147 } 148 149 /* set both front and back state */ 150 if (ctx->Stencil.Function[0] == frontfunc && 151 ctx->Stencil.Function[1] == backfunc && 152 ctx->Stencil.ValueMask[0] == mask && 153 ctx->Stencil.ValueMask[1] == mask && 154 ctx->Stencil.Ref[0] == ref && 155 ctx->Stencil.Ref[1] == ref) 156 return; 157 FLUSH_VERTICES(ctx, _NEW_STENCIL); 158 ctx->Stencil.Function[0] = frontfunc; 159 ctx->Stencil.Function[1] = backfunc; 160 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 161 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 162 if (ctx->Driver.StencilFuncSeparate) { 163 ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT, 164 frontfunc, ref, mask); 165 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, 166 backfunc, ref, mask); 167 } 168} 169 170 171/** 172 * Set the function and reference value for stencil testing. 173 * 174 * \param func test function. 175 * \param ref reference value. 176 * \param mask bitmask. 177 * 178 * \sa glStencilFunc(). 179 * 180 * Verifies the parameters and updates the respective values in 181 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the 182 * driver via the dd_function_table::StencilFunc callback. 183 */ 184void GLAPIENTRY 185_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask ) 186{ 187 GET_CURRENT_CONTEXT(ctx); 188 const GLint face = ctx->Stencil.ActiveFace; 189 190 if (MESA_VERBOSE & VERBOSE_API) 191 _mesa_debug(ctx, "glStencilFunc()\n"); 192 193 if (!validate_stencil_func(ctx, func)) { 194 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)"); 195 return; 196 } 197 198 if (face != 0) { 199 if (ctx->Stencil.Function[face] == func && 200 ctx->Stencil.ValueMask[face] == mask && 201 ctx->Stencil.Ref[face] == ref) 202 return; 203 FLUSH_VERTICES(ctx, _NEW_STENCIL); 204 ctx->Stencil.Function[face] = func; 205 ctx->Stencil.Ref[face] = ref; 206 ctx->Stencil.ValueMask[face] = mask; 207 208 /* Only propagate the change to the driver if EXT_stencil_two_side 209 * is enabled. 210 */ 211 if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) { 212 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask); 213 } 214 } 215 else { 216 /* set both front and back state */ 217 if (ctx->Stencil.Function[0] == func && 218 ctx->Stencil.Function[1] == func && 219 ctx->Stencil.ValueMask[0] == mask && 220 ctx->Stencil.ValueMask[1] == mask && 221 ctx->Stencil.Ref[0] == ref && 222 ctx->Stencil.Ref[1] == ref) 223 return; 224 FLUSH_VERTICES(ctx, _NEW_STENCIL); 225 ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func; 226 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 227 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 228 if (ctx->Driver.StencilFuncSeparate) { 229 ctx->Driver.StencilFuncSeparate(ctx, 230 ((ctx->Stencil.TestTwoSide) 231 ? GL_FRONT : GL_FRONT_AND_BACK), 232 func, ref, mask); 233 } 234 } 235} 236 237 238/** 239 * Set the stencil writing mask. 240 * 241 * \param mask bit-mask to enable/disable writing of individual bits in the 242 * stencil planes. 243 * 244 * \sa glStencilMask(). 245 * 246 * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and 247 * notifies the driver via the dd_function_table::StencilMask callback. 248 */ 249void GLAPIENTRY 250_mesa_StencilMask( GLuint mask ) 251{ 252 GET_CURRENT_CONTEXT(ctx); 253 const GLint face = ctx->Stencil.ActiveFace; 254 255 if (MESA_VERBOSE & VERBOSE_API) 256 _mesa_debug(ctx, "glStencilMask()\n"); 257 258 if (face != 0) { 259 /* Only modify the EXT_stencil_two_side back-face state. 260 */ 261 if (ctx->Stencil.WriteMask[face] == mask) 262 return; 263 FLUSH_VERTICES(ctx, _NEW_STENCIL); 264 ctx->Stencil.WriteMask[face] = mask; 265 266 /* Only propagate the change to the driver if EXT_stencil_two_side 267 * is enabled. 268 */ 269 if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) { 270 ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask); 271 } 272 } 273 else { 274 /* set both front and back state */ 275 if (ctx->Stencil.WriteMask[0] == mask && 276 ctx->Stencil.WriteMask[1] == mask) 277 return; 278 FLUSH_VERTICES(ctx, _NEW_STENCIL); 279 ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask; 280 if (ctx->Driver.StencilMaskSeparate) { 281 ctx->Driver.StencilMaskSeparate(ctx, 282 ((ctx->Stencil.TestTwoSide) 283 ? GL_FRONT : GL_FRONT_AND_BACK), 284 mask); 285 } 286 } 287} 288 289 290/** 291 * Set the stencil test actions. 292 * 293 * \param fail action to take when stencil test fails. 294 * \param zfail action to take when stencil test passes, but depth test fails. 295 * \param zpass action to take when stencil test passes and the depth test 296 * passes (or depth testing is not enabled). 297 * 298 * \sa glStencilOp(). 299 * 300 * Verifies the parameters and updates the respective fields in 301 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies the 302 * driver via the dd_function_table::StencilOp callback. 303 */ 304void GLAPIENTRY 305_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass) 306{ 307 GET_CURRENT_CONTEXT(ctx); 308 const GLint face = ctx->Stencil.ActiveFace; 309 310 if (MESA_VERBOSE & VERBOSE_API) 311 _mesa_debug(ctx, "glStencilOp()\n"); 312 313 if (!validate_stencil_op(ctx, fail)) { 314 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)"); 315 return; 316 } 317 if (!validate_stencil_op(ctx, zfail)) { 318 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)"); 319 return; 320 } 321 if (!validate_stencil_op(ctx, zpass)) { 322 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)"); 323 return; 324 } 325 326 if (face != 0) { 327 /* only set active face state */ 328 if (ctx->Stencil.ZFailFunc[face] == zfail && 329 ctx->Stencil.ZPassFunc[face] == zpass && 330 ctx->Stencil.FailFunc[face] == fail) 331 return; 332 FLUSH_VERTICES(ctx, _NEW_STENCIL); 333 ctx->Stencil.ZFailFunc[face] = zfail; 334 ctx->Stencil.ZPassFunc[face] = zpass; 335 ctx->Stencil.FailFunc[face] = fail; 336 337 /* Only propagate the change to the driver if EXT_stencil_two_side 338 * is enabled. 339 */ 340 if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) { 341 ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass); 342 } 343 } 344 else { 345 /* set both front and back state */ 346 if (ctx->Stencil.ZFailFunc[0] == zfail && 347 ctx->Stencil.ZFailFunc[1] == zfail && 348 ctx->Stencil.ZPassFunc[0] == zpass && 349 ctx->Stencil.ZPassFunc[1] == zpass && 350 ctx->Stencil.FailFunc[0] == fail && 351 ctx->Stencil.FailFunc[1] == fail) 352 return; 353 FLUSH_VERTICES(ctx, _NEW_STENCIL); 354 ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail; 355 ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass; 356 ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail; 357 if (ctx->Driver.StencilOpSeparate) { 358 ctx->Driver.StencilOpSeparate(ctx, 359 ((ctx->Stencil.TestTwoSide) 360 ? GL_FRONT : GL_FRONT_AND_BACK), 361 fail, zfail, zpass); 362 } 363 } 364} 365 366 367 368/* GL_EXT_stencil_two_side */ 369void GLAPIENTRY 370_mesa_ActiveStencilFaceEXT(GLenum face) 371{ 372 GET_CURRENT_CONTEXT(ctx); 373 374 if (MESA_VERBOSE & VERBOSE_API) 375 _mesa_debug(ctx, "glActiveStencilFaceEXT()\n"); 376 377 if (!ctx->Extensions.EXT_stencil_two_side) { 378 _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT"); 379 return; 380 } 381 382 if (face == GL_FRONT || face == GL_BACK) { 383 ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2; 384 } 385 else { 386 _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)"); 387 } 388} 389 390 391 392/** 393 * OpenGL 2.0 function. 394 * \todo Make StencilOp() call this function. And eventually remove the 395 * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate 396 * instead. 397 */ 398void GLAPIENTRY 399_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass) 400{ 401 GLboolean set = GL_FALSE; 402 GET_CURRENT_CONTEXT(ctx); 403 404 if (MESA_VERBOSE & VERBOSE_API) 405 _mesa_debug(ctx, "glStencilOpSeparate()\n"); 406 407 if (!validate_stencil_op(ctx, sfail)) { 408 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)"); 409 return; 410 } 411 if (!validate_stencil_op(ctx, zfail)) { 412 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)"); 413 return; 414 } 415 if (!validate_stencil_op(ctx, zpass)) { 416 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)"); 417 return; 418 } 419 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 420 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)"); 421 return; 422 } 423 424 if (face != GL_BACK) { 425 /* set front */ 426 if (ctx->Stencil.ZFailFunc[0] != zfail || 427 ctx->Stencil.ZPassFunc[0] != zpass || 428 ctx->Stencil.FailFunc[0] != sfail){ 429 FLUSH_VERTICES(ctx, _NEW_STENCIL); 430 ctx->Stencil.ZFailFunc[0] = zfail; 431 ctx->Stencil.ZPassFunc[0] = zpass; 432 ctx->Stencil.FailFunc[0] = sfail; 433 set = GL_TRUE; 434 } 435 } 436 if (face != GL_FRONT) { 437 /* set back */ 438 if (ctx->Stencil.ZFailFunc[1] != zfail || 439 ctx->Stencil.ZPassFunc[1] != zpass || 440 ctx->Stencil.FailFunc[1] != sfail) { 441 FLUSH_VERTICES(ctx, _NEW_STENCIL); 442 ctx->Stencil.ZFailFunc[1] = zfail; 443 ctx->Stencil.ZPassFunc[1] = zpass; 444 ctx->Stencil.FailFunc[1] = sfail; 445 set = GL_TRUE; 446 } 447 } 448 if (set && ctx->Driver.StencilOpSeparate) { 449 ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass); 450 } 451} 452 453 454/* OpenGL 2.0 */ 455void GLAPIENTRY 456_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) 457{ 458 GET_CURRENT_CONTEXT(ctx); 459 460 if (MESA_VERBOSE & VERBOSE_API) 461 _mesa_debug(ctx, "glStencilFuncSeparate()\n"); 462 463 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 464 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)"); 465 return; 466 } 467 if (!validate_stencil_func(ctx, func)) { 468 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)"); 469 return; 470 } 471 472 FLUSH_VERTICES(ctx, _NEW_STENCIL); 473 474 if (face != GL_BACK) { 475 /* set front */ 476 ctx->Stencil.Function[0] = func; 477 ctx->Stencil.Ref[0] = ref; 478 ctx->Stencil.ValueMask[0] = mask; 479 } 480 if (face != GL_FRONT) { 481 /* set back */ 482 ctx->Stencil.Function[1] = func; 483 ctx->Stencil.Ref[1] = ref; 484 ctx->Stencil.ValueMask[1] = mask; 485 } 486 if (ctx->Driver.StencilFuncSeparate) { 487 ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask); 488 } 489} 490 491 492/* OpenGL 2.0 */ 493void GLAPIENTRY 494_mesa_StencilMaskSeparate(GLenum face, GLuint mask) 495{ 496 GET_CURRENT_CONTEXT(ctx); 497 498 if (MESA_VERBOSE & VERBOSE_API) 499 _mesa_debug(ctx, "glStencilMaskSeparate()\n"); 500 501 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 502 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)"); 503 return; 504 } 505 506 FLUSH_VERTICES(ctx, _NEW_STENCIL); 507 508 if (face != GL_BACK) { 509 ctx->Stencil.WriteMask[0] = mask; 510 } 511 if (face != GL_FRONT) { 512 ctx->Stencil.WriteMask[1] = mask; 513 } 514 if (ctx->Driver.StencilMaskSeparate) { 515 ctx->Driver.StencilMaskSeparate(ctx, face, mask); 516 } 517} 518 519 520/** 521 * Update derived stencil state. 522 */ 523void 524_mesa_update_stencil(struct gl_context *ctx) 525{ 526 const GLint face = ctx->Stencil._BackFace; 527 528 ctx->Stencil._Enabled = (ctx->Stencil.Enabled && 529 ctx->DrawBuffer->Visual.stencilBits > 0); 530 531 ctx->Stencil._TestTwoSide = 532 ctx->Stencil._Enabled && 533 (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] || 534 ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] || 535 ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] || 536 ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] || 537 ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] || 538 ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] || 539 ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]); 540 541 ctx->Stencil._WriteEnabled = 542 ctx->Stencil._Enabled && 543 (ctx->Stencil.WriteMask[0] != 0 || 544 (ctx->Stencil._TestTwoSide && ctx->Stencil.WriteMask[face] != 0)); 545} 546 547 548/** 549 * Initialize the context stipple state. 550 * 551 * \param ctx GL context. 552 * 553 * Initializes __struct gl_contextRec::Stencil attribute group. 554 */ 555void 556_mesa_init_stencil(struct gl_context *ctx) 557{ 558 ctx->Stencil.Enabled = GL_FALSE; 559 ctx->Stencil.TestTwoSide = GL_FALSE; 560 ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */ 561 ctx->Stencil.Function[0] = GL_ALWAYS; 562 ctx->Stencil.Function[1] = GL_ALWAYS; 563 ctx->Stencil.Function[2] = GL_ALWAYS; 564 ctx->Stencil.FailFunc[0] = GL_KEEP; 565 ctx->Stencil.FailFunc[1] = GL_KEEP; 566 ctx->Stencil.FailFunc[2] = GL_KEEP; 567 ctx->Stencil.ZPassFunc[0] = GL_KEEP; 568 ctx->Stencil.ZPassFunc[1] = GL_KEEP; 569 ctx->Stencil.ZPassFunc[2] = GL_KEEP; 570 ctx->Stencil.ZFailFunc[0] = GL_KEEP; 571 ctx->Stencil.ZFailFunc[1] = GL_KEEP; 572 ctx->Stencil.ZFailFunc[2] = GL_KEEP; 573 ctx->Stencil.Ref[0] = 0; 574 ctx->Stencil.Ref[1] = 0; 575 ctx->Stencil.Ref[2] = 0; 576 ctx->Stencil.ValueMask[0] = ~0U; 577 ctx->Stencil.ValueMask[1] = ~0U; 578 ctx->Stencil.ValueMask[2] = ~0U; 579 ctx->Stencil.WriteMask[0] = ~0U; 580 ctx->Stencil.WriteMask[1] = ~0U; 581 ctx->Stencil.WriteMask[2] = ~0U; 582 ctx->Stencil.Clear = 0; 583 ctx->Stencil._BackFace = 1; 584} 585