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