stencil.c revision b1394fa92aaaf859ce9efc8b5fc194397921320c
1/* $Id: stencil.c,v 1.19 2000/09/26 20:53:53 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28#ifdef PC_HEADER 29#include "all.h" 30#else 31#include "glheader.h" 32#include "context.h" 33#include "depth.h" 34#include "mem.h" 35#include "pb.h" 36#include "stencil.h" 37#include "types.h" 38#include "enable.h" 39#endif 40 41 42 43 44void 45_mesa_ClearStencil( GLint s ) 46{ 47 GET_CURRENT_CONTEXT(ctx); 48 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearStencil"); 49 ctx->Stencil.Clear = (GLstencil) s; 50 51 if (ctx->Driver.ClearStencil) { 52 (*ctx->Driver.ClearStencil)( ctx, s ); 53 } 54} 55 56 57 58void 59_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask ) 60{ 61 GET_CURRENT_CONTEXT(ctx); 62 GLint maxref; 63 64 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilFunc"); 65 66 switch (func) { 67 case GL_NEVER: 68 case GL_LESS: 69 case GL_LEQUAL: 70 case GL_GREATER: 71 case GL_GEQUAL: 72 case GL_EQUAL: 73 case GL_NOTEQUAL: 74 case GL_ALWAYS: 75 ctx->Stencil.Function = func; 76 break; 77 default: 78 gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" ); 79 return; 80 } 81 82 maxref = (1 << STENCIL_BITS) - 1; 83 ctx->Stencil.Ref = (GLstencil) CLAMP( ref, 0, maxref ); 84 ctx->Stencil.ValueMask = (GLstencil) mask; 85 86 if (ctx->Driver.StencilFunc) { 87 (*ctx->Driver.StencilFunc)( ctx, func, ctx->Stencil.Ref, mask ); 88 } 89} 90 91 92 93void 94_mesa_StencilMask( GLuint mask ) 95{ 96 GET_CURRENT_CONTEXT(ctx); 97 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilMask"); 98 ctx->Stencil.WriteMask = (GLstencil) mask; 99 100 if (ctx->Driver.StencilMask) { 101 (*ctx->Driver.StencilMask)( ctx, mask ); 102 } 103} 104 105 106 107void 108_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass) 109{ 110 GET_CURRENT_CONTEXT(ctx); 111 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilOp"); 112 switch (fail) { 113 case GL_KEEP: 114 case GL_ZERO: 115 case GL_REPLACE: 116 case GL_INCR: 117 case GL_DECR: 118 case GL_INVERT: 119 ctx->Stencil.FailFunc = fail; 120 break; 121 case GL_INCR_WRAP_EXT: 122 case GL_DECR_WRAP_EXT: 123 if (ctx->Extensions.HaveStencilWrap) { 124 ctx->Stencil.FailFunc = fail; 125 break; 126 } 127 /* FALL-THROUGH */ 128 default: 129 gl_error(ctx, GL_INVALID_ENUM, "glStencilOp"); 130 return; 131 } 132 switch (zfail) { 133 case GL_KEEP: 134 case GL_ZERO: 135 case GL_REPLACE: 136 case GL_INCR: 137 case GL_DECR: 138 case GL_INVERT: 139 ctx->Stencil.ZFailFunc = zfail; 140 break; 141 case GL_INCR_WRAP_EXT: 142 case GL_DECR_WRAP_EXT: 143 if (ctx->Extensions.HaveStencilWrap) { 144 ctx->Stencil.ZFailFunc = zfail; 145 break; 146 } 147 /* FALL-THROUGH */ 148 default: 149 gl_error(ctx, GL_INVALID_ENUM, "glStencilOp"); 150 return; 151 } 152 switch (zpass) { 153 case GL_KEEP: 154 case GL_ZERO: 155 case GL_REPLACE: 156 case GL_INCR: 157 case GL_DECR: 158 case GL_INVERT: 159 ctx->Stencil.ZPassFunc = zpass; 160 break; 161 case GL_INCR_WRAP_EXT: 162 case GL_DECR_WRAP_EXT: 163 if (ctx->Extensions.HaveStencilWrap) { 164 ctx->Stencil.ZPassFunc = zpass; 165 break; 166 } 167 /* FALL-THROUGH */ 168 default: 169 gl_error(ctx, GL_INVALID_ENUM, "glStencilOp"); 170 return; 171 } 172 173 if (ctx->Driver.StencilOp) { 174 (*ctx->Driver.StencilOp)(ctx, fail, zfail, zpass); 175 } 176} 177 178 179 180/* Stencil Logic: 181 182IF stencil test fails THEN 183 Apply fail-op to stencil value 184 Don't write the pixel (RGBA,Z) 185ELSE 186 IF doing depth test && depth test fails THEN 187 Apply zfail-op to stencil value 188 Write RGBA and Z to appropriate buffers 189 ELSE 190 Apply zpass-op to stencil value 191ENDIF 192 193*/ 194 195 196 197 198/* 199 * Return the address of a stencil buffer value given the window coords: 200 */ 201#define STENCIL_ADDRESS(X,Y) \ 202 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X)) 203 204 205 206/* 207 * Apply the given stencil operator to the array of stencil values. 208 * Don't touch stencil[i] if mask[i] is zero. 209 * Input: n - size of stencil array 210 * oper - the stencil buffer operator 211 * stencil - array of stencil values 212 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator 213 * Output: stencil - modified values 214 */ 215static void apply_stencil_op( const GLcontext *ctx, GLenum oper, 216 GLuint n, GLstencil stencil[], 217 const GLubyte mask[] ) 218{ 219 const GLstencil ref = ctx->Stencil.Ref; 220 const GLstencil wrtmask = ctx->Stencil.WriteMask; 221 const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask); 222 GLuint i; 223 224 switch (oper) { 225 case GL_KEEP: 226 /* do nothing */ 227 break; 228 case GL_ZERO: 229 if (invmask==0) { 230 for (i=0;i<n;i++) { 231 if (mask[i]) { 232 stencil[i] = 0; 233 } 234 } 235 } 236 else { 237 for (i=0;i<n;i++) { 238 if (mask[i]) { 239 stencil[i] = (GLstencil) (stencil[i] & invmask); 240 } 241 } 242 } 243 break; 244 case GL_REPLACE: 245 if (invmask==0) { 246 for (i=0;i<n;i++) { 247 if (mask[i]) { 248 stencil[i] = ref; 249 } 250 } 251 } 252 else { 253 for (i=0;i<n;i++) { 254 if (mask[i]) { 255 GLstencil s = stencil[i]; 256 stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref)); 257 } 258 } 259 } 260 break; 261 case GL_INCR: 262 if (invmask==0) { 263 for (i=0;i<n;i++) { 264 if (mask[i]) { 265 GLstencil s = stencil[i]; 266 if (s < STENCIL_MAX) { 267 stencil[i] = (GLstencil) (s+1); 268 } 269 } 270 } 271 } 272 else { 273 for (i=0;i<n;i++) { 274 if (mask[i]) { 275 /* VERIFY logic of adding 1 to a write-masked value */ 276 GLstencil s = stencil[i]; 277 if (s < STENCIL_MAX) { 278 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1))); 279 } 280 } 281 } 282 } 283 break; 284 case GL_DECR: 285 if (invmask==0) { 286 for (i=0;i<n;i++) { 287 if (mask[i]) { 288 GLstencil s = stencil[i]; 289 if (s>0) { 290 stencil[i] = (GLstencil) (s-1); 291 } 292 } 293 } 294 } 295 else { 296 for (i=0;i<n;i++) { 297 if (mask[i]) { 298 /* VERIFY logic of subtracting 1 to a write-masked value */ 299 GLstencil s = stencil[i]; 300 if (s>0) { 301 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1))); 302 } 303 } 304 } 305 } 306 break; 307 case GL_INCR_WRAP_EXT: 308 if (invmask==0) { 309 for (i=0;i<n;i++) { 310 if (mask[i]) { 311 stencil[i]++; 312 } 313 } 314 } 315 else { 316 for (i=0;i<n;i++) { 317 if (mask[i]) { 318 GLstencil s = stencil[i]; 319 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1))); 320 } 321 } 322 } 323 break; 324 case GL_DECR_WRAP_EXT: 325 if (invmask==0) { 326 for (i=0;i<n;i++) { 327 if (mask[i]) { 328 stencil[i]--; 329 } 330 } 331 } 332 else { 333 for (i=0;i<n;i++) { 334 if (mask[i]) { 335 GLstencil s = stencil[i]; 336 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1))); 337 } 338 } 339 } 340 break; 341 case GL_INVERT: 342 if (invmask==0) { 343 for (i=0;i<n;i++) { 344 if (mask[i]) { 345 GLstencil s = stencil[i]; 346 stencil[i] = (GLstencil) ~s; 347 } 348 } 349 } 350 else { 351 for (i=0;i<n;i++) { 352 if (mask[i]) { 353 GLstencil s = stencil[i]; 354 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s)); 355 } 356 } 357 } 358 break; 359 default: 360 gl_problem(ctx, "Bad stencil op in apply_stencil_op"); 361 } 362} 363 364 365 366 367/* 368 * Apply stencil test to an array of stencil values (before depth buffering). 369 * Input: n - number of pixels in the array 370 * stencil - array of [n] stencil values 371 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel 372 * Output: mask - pixels which fail the stencil test will have their 373 * mask flag set to 0. 374 * stencil - updated stencil values (where the test passed) 375 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed. 376 */ 377static GLboolean 378do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[], 379 GLubyte mask[] ) 380{ 381 GLubyte fail[PB_SIZE]; 382 GLboolean allfail = GL_FALSE; 383 GLuint i; 384 GLstencil r, s; 385 386 ASSERT(n <= PB_SIZE); 387 388 /* 389 * Perform stencil test. The results of this operation are stored 390 * in the fail[] array: 391 * IF fail[i] is non-zero THEN 392 * the stencil fail operator is to be applied 393 * ELSE 394 * the stencil fail operator is not to be applied 395 * ENDIF 396 */ 397 switch (ctx->Stencil.Function) { 398 case GL_NEVER: 399 /* always fail */ 400 for (i=0;i<n;i++) { 401 if (mask[i]) { 402 mask[i] = 0; 403 fail[i] = 1; 404 } 405 else { 406 fail[i] = 0; 407 } 408 } 409 allfail = GL_TRUE; 410 break; 411 case GL_LESS: 412 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 413 for (i=0;i<n;i++) { 414 if (mask[i]) { 415 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); 416 if (r < s) { 417 /* passed */ 418 fail[i] = 0; 419 } 420 else { 421 fail[i] = 1; 422 mask[i] = 0; 423 } 424 } 425 else { 426 fail[i] = 0; 427 } 428 } 429 break; 430 case GL_LEQUAL: 431 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 432 for (i=0;i<n;i++) { 433 if (mask[i]) { 434 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); 435 if (r <= s) { 436 /* pass */ 437 fail[i] = 0; 438 } 439 else { 440 fail[i] = 1; 441 mask[i] = 0; 442 } 443 } 444 else { 445 fail[i] = 0; 446 } 447 } 448 break; 449 case GL_GREATER: 450 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 451 for (i=0;i<n;i++) { 452 if (mask[i]) { 453 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); 454 if (r > s) { 455 /* passed */ 456 fail[i] = 0; 457 } 458 else { 459 fail[i] = 1; 460 mask[i] = 0; 461 } 462 } 463 else { 464 fail[i] = 0; 465 } 466 } 467 break; 468 case GL_GEQUAL: 469 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 470 for (i=0;i<n;i++) { 471 if (mask[i]) { 472 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); 473 if (r >= s) { 474 /* passed */ 475 fail[i] = 0; 476 } 477 else { 478 fail[i] = 1; 479 mask[i] = 0; 480 } 481 } 482 else { 483 fail[i] = 0; 484 } 485 } 486 break; 487 case GL_EQUAL: 488 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 489 for (i=0;i<n;i++) { 490 if (mask[i]) { 491 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); 492 if (r == s) { 493 /* passed */ 494 fail[i] = 0; 495 } 496 else { 497 fail[i] = 1; 498 mask[i] = 0; 499 } 500 } 501 else { 502 fail[i] = 0; 503 } 504 } 505 break; 506 case GL_NOTEQUAL: 507 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 508 for (i=0;i<n;i++) { 509 if (mask[i]) { 510 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask); 511 if (r != s) { 512 /* passed */ 513 fail[i] = 0; 514 } 515 else { 516 fail[i] = 1; 517 mask[i] = 0; 518 } 519 } 520 else { 521 fail[i] = 0; 522 } 523 } 524 break; 525 case GL_ALWAYS: 526 /* always pass */ 527 for (i=0;i<n;i++) { 528 fail[i] = 0; 529 } 530 break; 531 default: 532 gl_problem(ctx, "Bad stencil func in gl_stencil_span"); 533 return 0; 534 } 535 536 if (ctx->Stencil.FailFunc != GL_KEEP) { 537 apply_stencil_op( ctx, ctx->Stencil.FailFunc, n, stencil, fail ); 538 } 539 540 return !allfail; 541} 542 543 544 545 546/* 547 * Apply stencil and depth testing to an array of pixels. 548 * Hardware or software stencil buffer acceptable. 549 * Input: n - number of pixels in the span 550 * z - array [n] of z values 551 * stencil - array [n] of stencil values 552 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 553 * Output: stencil - modified stencil values 554 * mask - array [n] of flags (1=stencil and depth test passed) 555 * Return: GL_TRUE - all fragments failed the testing 556 * GL_FALSE - one or more fragments passed the testing 557 * 558 */ 559static GLboolean 560stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 561 const GLdepth z[], GLstencil stencil[], 562 GLubyte mask[] ) 563{ 564 ASSERT(ctx->Stencil.Enabled); 565 ASSERT(n <= PB_SIZE); 566 567 /* 568 * Apply the stencil test to the fragments. 569 * failMask[i] is 1 if the stencil test failed. 570 */ 571 if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) { 572 /* all fragments failed the stencil test, we're done. */ 573 return GL_FALSE; 574 } 575 576 577 /* 578 * Some fragments passed the stencil test, apply depth test to them 579 * and apply Zpass and Zfail stencil ops. 580 */ 581 if (ctx->Depth.Test==GL_FALSE) { 582 /* 583 * No depth buffer, just apply zpass stencil function to active pixels. 584 */ 585 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask ); 586 } 587 else { 588 /* 589 * Perform depth buffering, then apply zpass or zfail stencil function. 590 */ 591 GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; 592 GLuint i; 593 594 /* save the current mask bits */ 595 MEMCPY(oldmask, mask, n * sizeof(GLubyte)); 596 597 /* apply the depth test */ 598 _mesa_depth_test_span(ctx, n, x, y, z, mask); 599 600 /* Set the stencil pass/fail flags according to result of depth testing. 601 * if oldmask[i] == 0 then 602 * Don't touch the stencil value 603 * else if oldmask[i] and newmask[i] then 604 * Depth test passed 605 * else 606 * assert(oldmask[i] && !newmask[i]) 607 * Depth test failed 608 * endif 609 */ 610 for (i=0;i<n;i++) { 611 ASSERT(mask[i] == 0 || mask[i] == 1); 612 passmask[i] = oldmask[i] & mask[i]; 613 failmask[i] = oldmask[i] & (mask[i] ^ 1); 614 } 615 616 /* apply the pass and fail operations */ 617 if (ctx->Stencil.ZFailFunc != GL_KEEP) { 618 apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask ); 619 } 620 if (ctx->Stencil.ZPassFunc != GL_KEEP) { 621 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask ); 622 } 623 } 624 625 return GL_TRUE; /* one or more fragments passed both tests */ 626} 627 628 629 630/* 631 * Apply stencil and depth testing to the span of pixels. 632 * Both software and hardware stencil buffers are acceptable. 633 * Input: n - number of pixels in the span 634 * x, y - location of leftmost pixel in span 635 * z - array [n] of z values 636 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 637 * Output: mask - array [n] of flags (1=stencil and depth test passed) 638 * Return: GL_TRUE - all fragments failed the testing 639 * GL_FALSE - one or more fragments passed the testing 640 * 641 */ 642GLboolean 643_mesa_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y, 644 const GLdepth z[], GLubyte mask[] ) 645{ 646 GLstencil stencilRow[MAX_WIDTH]; 647 GLstencil *stencil; 648 GLboolean result; 649 650 ASSERT(ctx->Stencil.Enabled); 651 ASSERT(n <= MAX_WIDTH); 652 653 /* Get initial stencil values */ 654 if (ctx->Driver.WriteStencilSpan) { 655 ASSERT(ctx->Driver.ReadStencilSpan); 656 /* Get stencil values from the hardware stencil buffer */ 657 (*ctx->Driver.ReadStencilSpan)(ctx, n, x, y, stencilRow); 658 stencil = stencilRow; 659 } 660 else { 661 /* software stencil buffer */ 662 stencil = STENCIL_ADDRESS(x, y); 663 } 664 665 /* do all the stencil/depth testing/updating */ 666 result = stencil_and_ztest_span( ctx, n, x, y, z, stencil, mask ); 667 668 if (ctx->Driver.WriteStencilSpan) { 669 /* Write updated stencil values into hardware stencil buffer */ 670 (ctx->Driver.WriteStencilSpan)(ctx, n, x, y, stencil, mask ); 671 } 672 673 return result; 674} 675 676 677 678 679/* 680 * Apply the given stencil operator for each pixel in the array whose 681 * mask flag is set. This is for software stencil buffers only. 682 * Input: n - number of pixels in the span 683 * x, y - array of [n] pixels 684 * operator - the stencil buffer operator 685 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator 686 */ 687static void 688apply_stencil_op_to_pixels( const GLcontext *ctx, 689 GLuint n, const GLint x[], const GLint y[], 690 GLenum oper, const GLubyte mask[] ) 691{ 692 const GLstencil ref = ctx->Stencil.Ref; 693 const GLstencil wrtmask = ctx->Stencil.WriteMask; 694 const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask); 695 GLuint i; 696 697 ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */ 698 699 switch (oper) { 700 case GL_KEEP: 701 /* do nothing */ 702 break; 703 case GL_ZERO: 704 if (invmask==0) { 705 for (i=0;i<n;i++) { 706 if (mask[i]) { 707 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 708 *sptr = 0; 709 } 710 } 711 } 712 else { 713 for (i=0;i<n;i++) { 714 if (mask[i]) { 715 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 716 *sptr = (GLstencil) (invmask & *sptr); 717 } 718 } 719 } 720 break; 721 case GL_REPLACE: 722 if (invmask==0) { 723 for (i=0;i<n;i++) { 724 if (mask[i]) { 725 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 726 *sptr = ref; 727 } 728 } 729 } 730 else { 731 for (i=0;i<n;i++) { 732 if (mask[i]) { 733 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 734 *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref)); 735 } 736 } 737 } 738 break; 739 case GL_INCR: 740 if (invmask==0) { 741 for (i=0;i<n;i++) { 742 if (mask[i]) { 743 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 744 if (*sptr < STENCIL_MAX) { 745 *sptr = (GLstencil) (*sptr + 1); 746 } 747 } 748 } 749 } 750 else { 751 for (i=0;i<n;i++) { 752 if (mask[i]) { 753 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 754 if (*sptr < STENCIL_MAX) { 755 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); 756 } 757 } 758 } 759 } 760 break; 761 case GL_DECR: 762 if (invmask==0) { 763 for (i=0;i<n;i++) { 764 if (mask[i]) { 765 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 766 if (*sptr>0) { 767 *sptr = (GLstencil) (*sptr - 1); 768 } 769 } 770 } 771 } 772 else { 773 for (i=0;i<n;i++) { 774 if (mask[i]) { 775 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 776 if (*sptr>0) { 777 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); 778 } 779 } 780 } 781 } 782 break; 783 case GL_INCR_WRAP_EXT: 784 if (invmask==0) { 785 for (i=0;i<n;i++) { 786 if (mask[i]) { 787 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 788 *sptr = (GLstencil) (*sptr + 1); 789 } 790 } 791 } 792 else { 793 for (i=0;i<n;i++) { 794 if (mask[i]) { 795 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 796 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); 797 } 798 } 799 } 800 break; 801 case GL_DECR_WRAP_EXT: 802 if (invmask==0) { 803 for (i=0;i<n;i++) { 804 if (mask[i]) { 805 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 806 *sptr = (GLstencil) (*sptr - 1); 807 } 808 } 809 } 810 else { 811 for (i=0;i<n;i++) { 812 if (mask[i]) { 813 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 814 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); 815 } 816 } 817 } 818 break; 819 case GL_INVERT: 820 if (invmask==0) { 821 for (i=0;i<n;i++) { 822 if (mask[i]) { 823 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 824 *sptr = (GLstencil) (~*sptr); 825 } 826 } 827 } 828 else { 829 for (i=0;i<n;i++) { 830 if (mask[i]) { 831 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 832 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr)); 833 } 834 } 835 } 836 break; 837 default: 838 gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels"); 839 } 840} 841 842 843 844/* 845 * Apply stencil test to an array of pixels before depth buffering. 846 * Used for software stencil buffer only. 847 * Input: n - number of pixels in the span 848 * x, y - array of [n] pixels to stencil 849 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel 850 * Output: mask - pixels which fail the stencil test will have their 851 * mask flag set to 0. 852 * Return: 0 = all pixels failed, 1 = zero or more pixels passed. 853 */ 854static GLboolean 855stencil_test_pixels( GLcontext *ctx, GLuint n, 856 const GLint x[], const GLint y[], GLubyte mask[] ) 857{ 858 GLubyte fail[PB_SIZE]; 859 GLstencil r, s; 860 GLuint i; 861 GLboolean allfail = GL_FALSE; 862 863 ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */ 864 865 /* 866 * Perform stencil test. The results of this operation are stored 867 * in the fail[] array: 868 * IF fail[i] is non-zero THEN 869 * the stencil fail operator is to be applied 870 * ELSE 871 * the stencil fail operator is not to be applied 872 * ENDIF 873 */ 874 875 switch (ctx->Stencil.Function) { 876 case GL_NEVER: 877 /* always fail */ 878 for (i=0;i<n;i++) { 879 if (mask[i]) { 880 mask[i] = 0; 881 fail[i] = 1; 882 } 883 else { 884 fail[i] = 0; 885 } 886 } 887 allfail = GL_TRUE; 888 break; 889 case GL_LESS: 890 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 891 for (i=0;i<n;i++) { 892 if (mask[i]) { 893 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 894 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); 895 if (r < s) { 896 /* passed */ 897 fail[i] = 0; 898 } 899 else { 900 fail[i] = 1; 901 mask[i] = 0; 902 } 903 } 904 else { 905 fail[i] = 0; 906 } 907 } 908 break; 909 case GL_LEQUAL: 910 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 911 for (i=0;i<n;i++) { 912 if (mask[i]) { 913 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 914 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); 915 if (r <= s) { 916 /* pass */ 917 fail[i] = 0; 918 } 919 else { 920 fail[i] = 1; 921 mask[i] = 0; 922 } 923 } 924 else { 925 fail[i] = 0; 926 } 927 } 928 break; 929 case GL_GREATER: 930 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 931 for (i=0;i<n;i++) { 932 if (mask[i]) { 933 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 934 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); 935 if (r > s) { 936 /* passed */ 937 fail[i] = 0; 938 } 939 else { 940 fail[i] = 1; 941 mask[i] = 0; 942 } 943 } 944 else { 945 fail[i] = 0; 946 } 947 } 948 break; 949 case GL_GEQUAL: 950 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 951 for (i=0;i<n;i++) { 952 if (mask[i]) { 953 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 954 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); 955 if (r >= s) { 956 /* passed */ 957 fail[i] = 0; 958 } 959 else { 960 fail[i] = 1; 961 mask[i] = 0; 962 } 963 } 964 else { 965 fail[i] = 0; 966 } 967 } 968 break; 969 case GL_EQUAL: 970 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 971 for (i=0;i<n;i++) { 972 if (mask[i]) { 973 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 974 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); 975 if (r == s) { 976 /* passed */ 977 fail[i] = 0; 978 } 979 else { 980 fail[i] = 1; 981 mask[i] = 0; 982 } 983 } 984 else { 985 fail[i] = 0; 986 } 987 } 988 break; 989 case GL_NOTEQUAL: 990 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask); 991 for (i=0;i<n;i++) { 992 if (mask[i]) { 993 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 994 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask); 995 if (r != s) { 996 /* passed */ 997 fail[i] = 0; 998 } 999 else { 1000 fail[i] = 1; 1001 mask[i] = 0; 1002 } 1003 } 1004 else { 1005 fail[i] = 0; 1006 } 1007 } 1008 break; 1009 case GL_ALWAYS: 1010 /* always pass */ 1011 for (i=0;i<n;i++) { 1012 fail[i] = 0; 1013 } 1014 break; 1015 default: 1016 gl_problem(ctx, "Bad stencil func in gl_stencil_pixels"); 1017 return 0; 1018 } 1019 1020 if (ctx->Stencil.FailFunc != GL_KEEP) { 1021 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail ); 1022 } 1023 1024 return !allfail; 1025} 1026 1027 1028 1029 1030/* 1031 * Apply stencil and depth testing to an array of pixels. 1032 * This is used both for software and hardware stencil buffers. 1033 * 1034 * The comments in this function are a bit sparse but the code is 1035 * almost identical to stencil_and_ztest_span(), which is well 1036 * commented. 1037 * 1038 * Input: n - number of pixels in the array 1039 * x, y - array of [n] pixel positions 1040 * z - array [n] of z values 1041 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 1042 * Output: mask - array [n] of flags (1=stencil and depth test passed) 1043 * Return: GL_TRUE - all fragments failed the testing 1044 * GL_FALSE - one or more fragments passed the testing 1045 */ 1046GLboolean 1047_mesa_stencil_and_ztest_pixels( GLcontext *ctx, 1048 GLuint n, const GLint x[], const GLint y[], 1049 const GLdepth z[], GLubyte mask[] ) 1050{ 1051 ASSERT(ctx->Stencil.Enabled); 1052 ASSERT(n <= PB_SIZE); 1053 1054 if (ctx->Driver.WriteStencilPixels) { 1055 /*** Hardware stencil buffer ***/ 1056 GLstencil stencil[PB_SIZE]; 1057 GLubyte mask[PB_SIZE]; 1058 1059 ASSERT(ctx->Driver.ReadStencilPixels); 1060 (*ctx->Driver.ReadStencilPixels)(ctx, n, x, y, stencil); 1061 1062 1063 if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) { 1064 /* all fragments failed the stencil test, we're done. */ 1065 return GL_FALSE; 1066 } 1067 1068 if (ctx->Depth.Test == GL_FALSE) { 1069 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask ); 1070 } 1071 else { 1072 GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE]; 1073 GLuint i; 1074 1075 MEMCPY(oldmask, mask, n * sizeof(GLubyte)); 1076 1077 _mesa_depth_test_pixels(ctx, n, x, y, z, mask); 1078 1079 for (i=0;i<n;i++) { 1080 ASSERT(mask[i] == 0 || mask[i] == 1); 1081 passmask[i] = oldmask[i] & mask[i]; 1082 failmask[i] = oldmask[i] & (mask[i] ^ 1); 1083 } 1084 1085 if (ctx->Stencil.ZFailFunc != GL_KEEP) { 1086 apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask ); 1087 } 1088 if (ctx->Stencil.ZPassFunc != GL_KEEP) { 1089 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask ); 1090 } 1091 } 1092 1093 /* Write updated stencil values into hardware stencil buffer */ 1094 (ctx->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, mask ); 1095 1096 return GL_TRUE; 1097 1098 } 1099 else { 1100 /*** Software stencil buffer ***/ 1101 1102 if (stencil_test_pixels(ctx, n, x, y, mask) == GL_FALSE) { 1103 /* all fragments failed the stencil test, we're done. */ 1104 return GL_FALSE; 1105 } 1106 1107 1108 if (ctx->Depth.Test==GL_FALSE) { 1109 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask ); 1110 } 1111 else { 1112 GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE]; 1113 GLuint i; 1114 1115 MEMCPY(oldmask, mask, n * sizeof(GLubyte)); 1116 1117 _mesa_depth_test_pixels(ctx, n, x, y, z, mask); 1118 1119 for (i=0;i<n;i++) { 1120 ASSERT(mask[i] == 0 || mask[i] == 1); 1121 passmask[i] = oldmask[i] & mask[i]; 1122 failmask[i] = oldmask[i] & (mask[i] ^ 1); 1123 } 1124 1125 if (ctx->Stencil.ZFailFunc != GL_KEEP) { 1126 apply_stencil_op_to_pixels( ctx, n, x, y, 1127 ctx->Stencil.ZFailFunc, failmask ); 1128 } 1129 if (ctx->Stencil.ZPassFunc != GL_KEEP) { 1130 apply_stencil_op_to_pixels( ctx, n, x, y, 1131 ctx->Stencil.ZPassFunc, passmask ); 1132 } 1133 } 1134 1135 return GL_TRUE; /* one or more fragments passed both tests */ 1136 } 1137} 1138 1139 1140 1141/* 1142 * Return a span of stencil values from the stencil buffer. 1143 * Used for glRead/CopyPixels 1144 * Input: n - how many pixels 1145 * x,y - location of first pixel 1146 * Output: stencil - the array of stencil values 1147 */ 1148void 1149_mesa_read_stencil_span( GLcontext *ctx, 1150 GLint n, GLint x, GLint y, GLstencil stencil[] ) 1151{ 1152 if (y < 0 || y >= ctx->DrawBuffer->Height || 1153 x + n <= 0 || x >= ctx->DrawBuffer->Width) { 1154 /* span is completely outside framebuffer */ 1155 return; /* undefined values OK */ 1156 } 1157 1158 if (x < 0) { 1159 GLint dx = -x; 1160 x = 0; 1161 n -= dx; 1162 stencil += dx; 1163 } 1164 if (x + n > ctx->DrawBuffer->Width) { 1165 GLint dx = x + n - ctx->DrawBuffer->Width; 1166 n -= dx; 1167 } 1168 if (n <= 0) { 1169 return; 1170 } 1171 1172 1173 ASSERT(n >= 0); 1174 if (ctx->Driver.ReadStencilSpan) { 1175 (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil ); 1176 } 1177 else if (ctx->DrawBuffer->Stencil) { 1178 const GLstencil *s = STENCIL_ADDRESS( x, y ); 1179#if STENCIL_BITS == 8 1180 MEMCPY( stencil, s, n * sizeof(GLstencil) ); 1181#else 1182 GLuint i; 1183 for (i=0;i<n;i++) 1184 stencil[i] = s[i]; 1185#endif 1186 } 1187} 1188 1189 1190 1191/* 1192 * Write a span of stencil values to the stencil buffer. 1193 * Used for glDraw/CopyPixels 1194 * Input: n - how many pixels 1195 * x, y - location of first pixel 1196 * stencil - the array of stencil values 1197 */ 1198void 1199_mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y, 1200 const GLstencil stencil[] ) 1201{ 1202 if (y < 0 || y >= ctx->DrawBuffer->Height || 1203 x + n <= 0 || x >= ctx->DrawBuffer->Width) { 1204 /* span is completely outside framebuffer */ 1205 return; /* undefined values OK */ 1206 } 1207 1208 if (x < 0) { 1209 GLint dx = -x; 1210 x = 0; 1211 n -= dx; 1212 stencil += dx; 1213 } 1214 if (x + n > ctx->DrawBuffer->Width) { 1215 GLint dx = x + n - ctx->DrawBuffer->Width; 1216 n -= dx; 1217 } 1218 if (n <= 0) { 1219 return; 1220 } 1221 1222 if (ctx->Driver.WriteStencilSpan) { 1223 (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL ); 1224 } 1225 else if (ctx->DrawBuffer->Stencil) { 1226 GLstencil *s = STENCIL_ADDRESS( x, y ); 1227#if STENCIL_BITS == 8 1228 MEMCPY( s, stencil, n * sizeof(GLstencil) ); 1229#else 1230 GLuint i; 1231 for (i=0;i<n;i++) 1232 s[i] = stencil[i]; 1233#endif 1234 } 1235} 1236 1237 1238 1239/* 1240 * Allocate a new stencil buffer. If there's an old one it will be 1241 * deallocated first. The new stencil buffer will be uninitialized. 1242 */ 1243void 1244_mesa_alloc_stencil_buffer( GLcontext *ctx ) 1245{ 1246 GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height; 1247 1248 /* deallocate current stencil buffer if present */ 1249 if (ctx->DrawBuffer->Stencil) { 1250 FREE(ctx->DrawBuffer->Stencil); 1251 ctx->DrawBuffer->Stencil = NULL; 1252 } 1253 1254 /* allocate new stencil buffer */ 1255 ctx->DrawBuffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil)); 1256 if (!ctx->DrawBuffer->Stencil) { 1257 /* out of memory */ 1258 _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); 1259 gl_error( ctx, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" ); 1260 } 1261} 1262 1263 1264 1265/* 1266 * Clear the software (malloc'd) stencil buffer. 1267 */ 1268static void 1269clear_software_stencil_buffer( GLcontext *ctx ) 1270{ 1271 if (ctx->Visual.StencilBits==0 || !ctx->DrawBuffer->Stencil) { 1272 /* no stencil buffer */ 1273 return; 1274 } 1275 1276 if (ctx->Scissor.Enabled) { 1277 /* clear scissor region only */ 1278 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin; 1279 if (ctx->Stencil.WriteMask != STENCIL_MAX) { 1280 /* must apply mask to the clear */ 1281 GLint y; 1282 for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) { 1283 const GLstencil mask = ctx->Stencil.WriteMask; 1284 const GLstencil invMask = ~mask; 1285 const GLstencil clearVal = (ctx->Stencil.Clear & mask); 1286 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y ); 1287 GLint i; 1288 for (i = 0; i < width; i++) { 1289 stencil[i] = (stencil[i] & invMask) | clearVal; 1290 } 1291 } 1292 } 1293 else { 1294 /* no masking */ 1295 GLint y; 1296 for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) { 1297 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y ); 1298#if STENCIL_BITS==8 1299 MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) ); 1300#else 1301 GLint i; 1302 for (i = 0; i < width; i++) 1303 stencil[x] = ctx->Stencil.Clear; 1304#endif 1305 } 1306 } 1307 } 1308 else { 1309 /* clear whole stencil buffer */ 1310 if (ctx->Stencil.WriteMask != STENCIL_MAX) { 1311 /* must apply mask to the clear */ 1312 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height; 1313 GLstencil *stencil = ctx->DrawBuffer->Stencil; 1314 const GLstencil mask = ctx->Stencil.WriteMask; 1315 const GLstencil invMask = ~mask; 1316 const GLstencil clearVal = (ctx->Stencil.Clear & mask); 1317 GLuint i; 1318 for (i = 0; i < n; i++) { 1319 stencil[i] = (stencil[i] & invMask) | clearVal; 1320 } 1321 } 1322 else { 1323 /* clear whole buffer without masking */ 1324 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height; 1325 GLstencil *stencil = ctx->DrawBuffer->Stencil; 1326 1327#if STENCIL_BITS==8 1328 MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) ); 1329#else 1330 GLuint i; 1331 for (i = 0; i < n; i++) { 1332 stencil[i] = ctx->Stencil.Clear; 1333 } 1334#endif 1335 } 1336 } 1337} 1338 1339 1340 1341/* 1342 * Clear the hardware (in graphics card) stencil buffer. 1343 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan() 1344 * functions. 1345 * Actually, if there is a hardware stencil buffer it really should have 1346 * been cleared in Driver.Clear()! However, if the hardware does not 1347 * support scissored clears or masked clears (i.e. glStencilMask) then 1348 * we have to use the span-based functions. 1349 */ 1350static void 1351clear_hardware_stencil_buffer( GLcontext *ctx ) 1352{ 1353 ASSERT(ctx->Driver.WriteStencilSpan); 1354 ASSERT(ctx->Driver.ReadStencilSpan); 1355 1356 if (ctx->Scissor.Enabled) { 1357 /* clear scissor region only */ 1358 const GLint x = ctx->DrawBuffer->Xmin; 1359 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin; 1360 if (ctx->Stencil.WriteMask != STENCIL_MAX) { 1361 /* must apply mask to the clear */ 1362 GLint y; 1363 for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) { 1364 const GLstencil mask = ctx->Stencil.WriteMask; 1365 const GLstencil invMask = ~mask; 1366 const GLstencil clearVal = (ctx->Stencil.Clear & mask); 1367 GLstencil stencil[MAX_WIDTH]; 1368 GLint i; 1369 (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil); 1370 for (i = 0; i < width; i++) { 1371 stencil[i] = (stencil[i] & invMask) | clearVal; 1372 } 1373 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL); 1374 } 1375 } 1376 else { 1377 /* no masking */ 1378 GLstencil stencil[MAX_WIDTH]; 1379 GLint y, i; 1380 for (i = 0; i < width; i++) { 1381 stencil[i] = ctx->Stencil.Clear; 1382 } 1383 for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) { 1384 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL); 1385 } 1386 } 1387 } 1388 else { 1389 /* clear whole stencil buffer */ 1390 if (ctx->Stencil.WriteMask != STENCIL_MAX) { 1391 /* must apply mask to the clear */ 1392 const GLstencil mask = ctx->Stencil.WriteMask; 1393 const GLstencil invMask = ~mask; 1394 const GLstencil clearVal = (ctx->Stencil.Clear & mask); 1395 const GLint width = ctx->DrawBuffer->Width; 1396 const GLint height = ctx->DrawBuffer->Height; 1397 const GLint x = ctx->DrawBuffer->Xmin; 1398 GLint y; 1399 for (y = 0; y < height; y++) { 1400 GLstencil stencil[MAX_WIDTH]; 1401 GLuint i; 1402 (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil); 1403 for (i = 0; i < width; i++) { 1404 stencil[i] = (stencil[i] & invMask) | clearVal; 1405 } 1406 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL); 1407 } 1408 } 1409 else { 1410 /* clear whole buffer without masking */ 1411 const GLint width = ctx->DrawBuffer->Width; 1412 const GLint height = ctx->DrawBuffer->Width; 1413 const GLint x = ctx->DrawBuffer->Xmin; 1414 GLstencil stencil[MAX_WIDTH]; 1415 GLint y, i; 1416 for (i = 0; i < width; i++) { 1417 stencil[i] = ctx->Stencil.Clear; 1418 } 1419 for (y = 0; y < height; y++) { 1420 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL); 1421 } 1422 } 1423 } 1424} 1425 1426 1427 1428/* 1429 * Clear the stencil buffer. 1430 */ 1431void 1432_mesa_clear_stencil_buffer( GLcontext *ctx ) 1433{ 1434 if (ctx->Driver.WriteStencilSpan) { 1435 ASSERT(ctx->Driver.ReadStencilSpan); 1436 clear_hardware_stencil_buffer(ctx); 1437 } 1438 else { 1439 clear_software_stencil_buffer(ctx); 1440 } 1441} 1442 1443