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 if (MESA_VERBOSE & VERBOSE_API) 113 _mesa_debug(ctx, "glClearStencil(%d)\n", s); 114 115 ctx->Stencil.Clear = (GLuint) s; 116} 117 118 119/** 120 * Set the function and reference value for stencil testing. 121 * 122 * \param frontfunc front test function. 123 * \param backfunc back test function. 124 * \param ref front and back reference value. 125 * \param mask front and back bitmask. 126 * 127 * \sa glStencilFunc(). 128 * 129 * Verifies the parameters and updates the respective values in 130 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies 131 * the driver via the dd_function_table::StencilFunc callback. 132 */ 133void GLAPIENTRY 134_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask ) 135{ 136 GET_CURRENT_CONTEXT(ctx); 137 138 if (MESA_VERBOSE & VERBOSE_API) 139 _mesa_debug(ctx, "glStencilFuncSeparateATI()\n"); 140 141 if (!validate_stencil_func(ctx, frontfunc)) { 142 _mesa_error(ctx, GL_INVALID_ENUM, 143 "glStencilFuncSeparateATI(frontfunc)"); 144 return; 145 } 146 if (!validate_stencil_func(ctx, backfunc)) { 147 _mesa_error(ctx, GL_INVALID_ENUM, 148 "glStencilFuncSeparateATI(backfunc)"); 149 return; 150 } 151 152 /* set both front and back state */ 153 if (ctx->Stencil.Function[0] == frontfunc && 154 ctx->Stencil.Function[1] == backfunc && 155 ctx->Stencil.ValueMask[0] == mask && 156 ctx->Stencil.ValueMask[1] == mask && 157 ctx->Stencil.Ref[0] == ref && 158 ctx->Stencil.Ref[1] == ref) 159 return; 160 FLUSH_VERTICES(ctx, _NEW_STENCIL); 161 ctx->Stencil.Function[0] = frontfunc; 162 ctx->Stencil.Function[1] = backfunc; 163 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 164 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 165 if (ctx->Driver.StencilFuncSeparate) { 166 ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT, 167 frontfunc, ref, mask); 168 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, 169 backfunc, ref, mask); 170 } 171} 172 173 174/** 175 * Set the function and reference value for stencil testing. 176 * 177 * \param func test function. 178 * \param ref reference value. 179 * \param mask bitmask. 180 * 181 * \sa glStencilFunc(). 182 * 183 * Verifies the parameters and updates the respective values in 184 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies 185 * the driver via the dd_function_table::StencilFunc callback. 186 */ 187void GLAPIENTRY 188_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask ) 189{ 190 GET_CURRENT_CONTEXT(ctx); 191 const GLint face = ctx->Stencil.ActiveFace; 192 193 if (MESA_VERBOSE & VERBOSE_API) 194 _mesa_debug(ctx, "glStencilFunc()\n"); 195 196 if (!validate_stencil_func(ctx, func)) { 197 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)"); 198 return; 199 } 200 201 if (face != 0) { 202 if (ctx->Stencil.Function[face] == func && 203 ctx->Stencil.ValueMask[face] == mask && 204 ctx->Stencil.Ref[face] == ref) 205 return; 206 FLUSH_VERTICES(ctx, _NEW_STENCIL); 207 ctx->Stencil.Function[face] = func; 208 ctx->Stencil.Ref[face] = ref; 209 ctx->Stencil.ValueMask[face] = mask; 210 211 /* Only propagate the change to the driver if EXT_stencil_two_side 212 * is enabled. 213 */ 214 if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) { 215 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask); 216 } 217 } 218 else { 219 /* set both front and back state */ 220 if (ctx->Stencil.Function[0] == func && 221 ctx->Stencil.Function[1] == func && 222 ctx->Stencil.ValueMask[0] == mask && 223 ctx->Stencil.ValueMask[1] == mask && 224 ctx->Stencil.Ref[0] == ref && 225 ctx->Stencil.Ref[1] == ref) 226 return; 227 FLUSH_VERTICES(ctx, _NEW_STENCIL); 228 ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func; 229 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 230 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 231 if (ctx->Driver.StencilFuncSeparate) { 232 ctx->Driver.StencilFuncSeparate(ctx, 233 ((ctx->Stencil.TestTwoSide) 234 ? GL_FRONT : GL_FRONT_AND_BACK), 235 func, ref, mask); 236 } 237 } 238} 239 240 241/** 242 * Set the stencil writing mask. 243 * 244 * \param mask bit-mask to enable/disable writing of individual bits in the 245 * stencil planes. 246 * 247 * \sa glStencilMask(). 248 * 249 * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and 250 * notifies the driver via the dd_function_table::StencilMask callback. 251 */ 252void GLAPIENTRY 253_mesa_StencilMask( GLuint mask ) 254{ 255 GET_CURRENT_CONTEXT(ctx); 256 const GLint face = ctx->Stencil.ActiveFace; 257 258 if (MESA_VERBOSE & VERBOSE_API) 259 _mesa_debug(ctx, "glStencilMask()\n"); 260 261 if (face != 0) { 262 /* Only modify the EXT_stencil_two_side back-face state. 263 */ 264 if (ctx->Stencil.WriteMask[face] == mask) 265 return; 266 FLUSH_VERTICES(ctx, _NEW_STENCIL); 267 ctx->Stencil.WriteMask[face] = mask; 268 269 /* Only propagate the change to the driver if EXT_stencil_two_side 270 * is enabled. 271 */ 272 if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) { 273 ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask); 274 } 275 } 276 else { 277 /* set both front and back state */ 278 if (ctx->Stencil.WriteMask[0] == mask && 279 ctx->Stencil.WriteMask[1] == mask) 280 return; 281 FLUSH_VERTICES(ctx, _NEW_STENCIL); 282 ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask; 283 if (ctx->Driver.StencilMaskSeparate) { 284 ctx->Driver.StencilMaskSeparate(ctx, 285 ((ctx->Stencil.TestTwoSide) 286 ? GL_FRONT : GL_FRONT_AND_BACK), 287 mask); 288 } 289 } 290} 291 292 293/** 294 * Set the stencil test actions. 295 * 296 * \param fail action to take when stencil test fails. 297 * \param zfail action to take when stencil test passes, but depth test fails. 298 * \param zpass action to take when stencil test passes and the depth test 299 * passes (or depth testing is not enabled). 300 * 301 * \sa glStencilOp(). 302 * 303 * Verifies the parameters and updates the respective fields in 304 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies 305 * the driver via the dd_function_table::StencilOp callback. 306 */ 307void GLAPIENTRY 308_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass) 309{ 310 GET_CURRENT_CONTEXT(ctx); 311 const GLint face = ctx->Stencil.ActiveFace; 312 313 if (MESA_VERBOSE & VERBOSE_API) 314 _mesa_debug(ctx, "glStencilOp()\n"); 315 316 if (!validate_stencil_op(ctx, fail)) { 317 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)"); 318 return; 319 } 320 if (!validate_stencil_op(ctx, zfail)) { 321 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)"); 322 return; 323 } 324 if (!validate_stencil_op(ctx, zpass)) { 325 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)"); 326 return; 327 } 328 329 if (face != 0) { 330 /* only set active face state */ 331 if (ctx->Stencil.ZFailFunc[face] == zfail && 332 ctx->Stencil.ZPassFunc[face] == zpass && 333 ctx->Stencil.FailFunc[face] == fail) 334 return; 335 FLUSH_VERTICES(ctx, _NEW_STENCIL); 336 ctx->Stencil.ZFailFunc[face] = zfail; 337 ctx->Stencil.ZPassFunc[face] = zpass; 338 ctx->Stencil.FailFunc[face] = fail; 339 340 /* Only propagate the change to the driver if EXT_stencil_two_side 341 * is enabled. 342 */ 343 if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) { 344 ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass); 345 } 346 } 347 else { 348 /* set both front and back state */ 349 if (ctx->Stencil.ZFailFunc[0] == zfail && 350 ctx->Stencil.ZFailFunc[1] == zfail && 351 ctx->Stencil.ZPassFunc[0] == zpass && 352 ctx->Stencil.ZPassFunc[1] == zpass && 353 ctx->Stencil.FailFunc[0] == fail && 354 ctx->Stencil.FailFunc[1] == fail) 355 return; 356 FLUSH_VERTICES(ctx, _NEW_STENCIL); 357 ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail; 358 ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass; 359 ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail; 360 if (ctx->Driver.StencilOpSeparate) { 361 ctx->Driver.StencilOpSeparate(ctx, 362 ((ctx->Stencil.TestTwoSide) 363 ? GL_FRONT : GL_FRONT_AND_BACK), 364 fail, zfail, zpass); 365 } 366 } 367} 368 369 370 371/* GL_EXT_stencil_two_side */ 372void GLAPIENTRY 373_mesa_ActiveStencilFaceEXT(GLenum face) 374{ 375 GET_CURRENT_CONTEXT(ctx); 376 377 if (MESA_VERBOSE & VERBOSE_API) 378 _mesa_debug(ctx, "glActiveStencilFaceEXT()\n"); 379 380 if (!ctx->Extensions.EXT_stencil_two_side) { 381 _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT"); 382 return; 383 } 384 385 if (face == GL_FRONT || face == GL_BACK) { 386 ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2; 387 } 388 else { 389 _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)"); 390 } 391} 392 393 394 395void GLAPIENTRY 396_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass) 397{ 398 GLboolean set = GL_FALSE; 399 GET_CURRENT_CONTEXT(ctx); 400 401 if (MESA_VERBOSE & VERBOSE_API) 402 _mesa_debug(ctx, "glStencilOpSeparate()\n"); 403 404 if (!validate_stencil_op(ctx, sfail)) { 405 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)"); 406 return; 407 } 408 if (!validate_stencil_op(ctx, zfail)) { 409 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)"); 410 return; 411 } 412 if (!validate_stencil_op(ctx, zpass)) { 413 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)"); 414 return; 415 } 416 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 417 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)"); 418 return; 419 } 420 421 if (face != GL_BACK) { 422 /* set front */ 423 if (ctx->Stencil.ZFailFunc[0] != zfail || 424 ctx->Stencil.ZPassFunc[0] != zpass || 425 ctx->Stencil.FailFunc[0] != sfail){ 426 FLUSH_VERTICES(ctx, _NEW_STENCIL); 427 ctx->Stencil.ZFailFunc[0] = zfail; 428 ctx->Stencil.ZPassFunc[0] = zpass; 429 ctx->Stencil.FailFunc[0] = sfail; 430 set = GL_TRUE; 431 } 432 } 433 if (face != GL_FRONT) { 434 /* set back */ 435 if (ctx->Stencil.ZFailFunc[1] != zfail || 436 ctx->Stencil.ZPassFunc[1] != zpass || 437 ctx->Stencil.FailFunc[1] != sfail) { 438 FLUSH_VERTICES(ctx, _NEW_STENCIL); 439 ctx->Stencil.ZFailFunc[1] = zfail; 440 ctx->Stencil.ZPassFunc[1] = zpass; 441 ctx->Stencil.FailFunc[1] = sfail; 442 set = GL_TRUE; 443 } 444 } 445 if (set && ctx->Driver.StencilOpSeparate) { 446 ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass); 447 } 448} 449 450 451/* OpenGL 2.0 */ 452void GLAPIENTRY 453_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) 454{ 455 GET_CURRENT_CONTEXT(ctx); 456 457 if (MESA_VERBOSE & VERBOSE_API) 458 _mesa_debug(ctx, "glStencilFuncSeparate()\n"); 459 460 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 461 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)"); 462 return; 463 } 464 if (!validate_stencil_func(ctx, func)) { 465 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)"); 466 return; 467 } 468 469 FLUSH_VERTICES(ctx, _NEW_STENCIL); 470 471 if (face != GL_BACK) { 472 /* set front */ 473 ctx->Stencil.Function[0] = func; 474 ctx->Stencil.Ref[0] = ref; 475 ctx->Stencil.ValueMask[0] = mask; 476 } 477 if (face != GL_FRONT) { 478 /* set back */ 479 ctx->Stencil.Function[1] = func; 480 ctx->Stencil.Ref[1] = ref; 481 ctx->Stencil.ValueMask[1] = mask; 482 } 483 if (ctx->Driver.StencilFuncSeparate) { 484 ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask); 485 } 486} 487 488 489/* OpenGL 2.0 */ 490void GLAPIENTRY 491_mesa_StencilMaskSeparate(GLenum face, GLuint mask) 492{ 493 GET_CURRENT_CONTEXT(ctx); 494 495 if (MESA_VERBOSE & VERBOSE_API) 496 _mesa_debug(ctx, "glStencilMaskSeparate()\n"); 497 498 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 499 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)"); 500 return; 501 } 502 503 FLUSH_VERTICES(ctx, _NEW_STENCIL); 504 505 if (face != GL_BACK) { 506 ctx->Stencil.WriteMask[0] = mask; 507 } 508 if (face != GL_FRONT) { 509 ctx->Stencil.WriteMask[1] = mask; 510 } 511 if (ctx->Driver.StencilMaskSeparate) { 512 ctx->Driver.StencilMaskSeparate(ctx, face, mask); 513 } 514} 515 516 517/** 518 * Update derived stencil state. 519 */ 520void 521_mesa_update_stencil(struct gl_context *ctx) 522{ 523 const GLint face = ctx->Stencil._BackFace; 524 525 ctx->Stencil._Enabled = (ctx->Stencil.Enabled && 526 ctx->DrawBuffer->Visual.stencilBits > 0); 527 528 ctx->Stencil._TestTwoSide = 529 ctx->Stencil._Enabled && 530 (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] || 531 ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] || 532 ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] || 533 ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] || 534 ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] || 535 ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] || 536 ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]); 537 538 ctx->Stencil._WriteEnabled = 539 ctx->Stencil._Enabled && 540 (ctx->Stencil.WriteMask[0] != 0 || 541 (ctx->Stencil._TestTwoSide && ctx->Stencil.WriteMask[face] != 0)); 542} 543 544 545/** 546 * Initialize the context stipple state. 547 * 548 * \param ctx GL context. 549 * 550 * Initializes __struct gl_contextRec::Stencil attribute group. 551 */ 552void 553_mesa_init_stencil(struct gl_context *ctx) 554{ 555 ctx->Stencil.Enabled = GL_FALSE; 556 ctx->Stencil.TestTwoSide = GL_FALSE; 557 ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */ 558 ctx->Stencil.Function[0] = GL_ALWAYS; 559 ctx->Stencil.Function[1] = GL_ALWAYS; 560 ctx->Stencil.Function[2] = GL_ALWAYS; 561 ctx->Stencil.FailFunc[0] = GL_KEEP; 562 ctx->Stencil.FailFunc[1] = GL_KEEP; 563 ctx->Stencil.FailFunc[2] = GL_KEEP; 564 ctx->Stencil.ZPassFunc[0] = GL_KEEP; 565 ctx->Stencil.ZPassFunc[1] = GL_KEEP; 566 ctx->Stencil.ZPassFunc[2] = GL_KEEP; 567 ctx->Stencil.ZFailFunc[0] = GL_KEEP; 568 ctx->Stencil.ZFailFunc[1] = GL_KEEP; 569 ctx->Stencil.ZFailFunc[2] = GL_KEEP; 570 ctx->Stencil.Ref[0] = 0; 571 ctx->Stencil.Ref[1] = 0; 572 ctx->Stencil.Ref[2] = 0; 573 574 /* 4.1.4 Stencil Test section of the GL-ES 3.0 specification says: 575 * 576 * "In the initial state, [...] the front and back stencil mask are both 577 * set to the value 2^s − 1, where s is greater than or equal to the 578 * number of bits in the deepest stencil buffer* supported by the GL 579 * implementation." 580 * 581 * Since the maximum supported precision for stencil buffers is 8 bits, 582 * mask values should be initialized to 2^8 - 1 = 0xFF. 583 */ 584 ctx->Stencil.ValueMask[0] = 0xFF; 585 ctx->Stencil.ValueMask[1] = 0xFF; 586 ctx->Stencil.ValueMask[2] = 0xFF; 587 ctx->Stencil.WriteMask[0] = 0xFF; 588 ctx->Stencil.WriteMask[1] = 0xFF; 589 ctx->Stencil.WriteMask[2] = 0xFF; 590 591 ctx->Stencil.Clear = 0; 592 ctx->Stencil._BackFace = 1; 593} 594