s_stencil.c revision c1f859d4
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26#include "main/glheader.h" 27#include "main/context.h" 28#include "main/imports.h" 29 30#include "s_context.h" 31#include "s_depth.h" 32#include "s_stencil.h" 33#include "s_span.h" 34 35 36 37/* Stencil Logic: 38 39IF stencil test fails THEN 40 Apply fail-op to stencil value 41 Don't write the pixel (RGBA,Z) 42ELSE 43 IF doing depth test && depth test fails THEN 44 Apply zfail-op to stencil value 45 Write RGBA and Z to appropriate buffers 46 ELSE 47 Apply zpass-op to stencil value 48ENDIF 49 50*/ 51 52 53/** 54 * Apply the given stencil operator to the array of stencil values. 55 * Don't touch stencil[i] if mask[i] is zero. 56 * Input: n - size of stencil array 57 * oper - the stencil buffer operator 58 * face - 0 or 1 for front or back face operation 59 * stencil - array of stencil values 60 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator 61 * Output: stencil - modified values 62 */ 63static void 64apply_stencil_op( const GLcontext *ctx, GLenum oper, GLuint face, 65 GLuint n, GLstencil stencil[], const GLubyte mask[] ) 66{ 67 const GLstencil ref = ctx->Stencil.Ref[face]; 68 const GLstencil wrtmask = ctx->Stencil.WriteMask[face]; 69 const GLstencil invmask = (GLstencil) (~wrtmask); 70 const GLstencil stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; 71 GLuint i; 72 73 switch (oper) { 74 case GL_KEEP: 75 /* do nothing */ 76 break; 77 case GL_ZERO: 78 if (invmask==0) { 79 for (i=0;i<n;i++) { 80 if (mask[i]) { 81 stencil[i] = 0; 82 } 83 } 84 } 85 else { 86 for (i=0;i<n;i++) { 87 if (mask[i]) { 88 stencil[i] = (GLstencil) (stencil[i] & invmask); 89 } 90 } 91 } 92 break; 93 case GL_REPLACE: 94 if (invmask==0) { 95 for (i=0;i<n;i++) { 96 if (mask[i]) { 97 stencil[i] = ref; 98 } 99 } 100 } 101 else { 102 for (i=0;i<n;i++) { 103 if (mask[i]) { 104 GLstencil s = stencil[i]; 105 stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref)); 106 } 107 } 108 } 109 break; 110 case GL_INCR: 111 if (invmask==0) { 112 for (i=0;i<n;i++) { 113 if (mask[i]) { 114 GLstencil s = stencil[i]; 115 if (s < stencilMax) { 116 stencil[i] = (GLstencil) (s+1); 117 } 118 } 119 } 120 } 121 else { 122 for (i=0;i<n;i++) { 123 if (mask[i]) { 124 /* VERIFY logic of adding 1 to a write-masked value */ 125 GLstencil s = stencil[i]; 126 if (s < stencilMax) { 127 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1))); 128 } 129 } 130 } 131 } 132 break; 133 case GL_DECR: 134 if (invmask==0) { 135 for (i=0;i<n;i++) { 136 if (mask[i]) { 137 GLstencil s = stencil[i]; 138 if (s>0) { 139 stencil[i] = (GLstencil) (s-1); 140 } 141 } 142 } 143 } 144 else { 145 for (i=0;i<n;i++) { 146 if (mask[i]) { 147 /* VERIFY logic of subtracting 1 to a write-masked value */ 148 GLstencil s = stencil[i]; 149 if (s>0) { 150 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1))); 151 } 152 } 153 } 154 } 155 break; 156 case GL_INCR_WRAP_EXT: 157 if (invmask==0) { 158 for (i=0;i<n;i++) { 159 if (mask[i]) { 160 stencil[i]++; 161 } 162 } 163 } 164 else { 165 for (i=0;i<n;i++) { 166 if (mask[i]) { 167 GLstencil s = stencil[i]; 168 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1))); 169 } 170 } 171 } 172 break; 173 case GL_DECR_WRAP_EXT: 174 if (invmask==0) { 175 for (i=0;i<n;i++) { 176 if (mask[i]) { 177 stencil[i]--; 178 } 179 } 180 } 181 else { 182 for (i=0;i<n;i++) { 183 if (mask[i]) { 184 GLstencil s = stencil[i]; 185 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1))); 186 } 187 } 188 } 189 break; 190 case GL_INVERT: 191 if (invmask==0) { 192 for (i=0;i<n;i++) { 193 if (mask[i]) { 194 GLstencil s = stencil[i]; 195 stencil[i] = (GLstencil) ~s; 196 } 197 } 198 } 199 else { 200 for (i=0;i<n;i++) { 201 if (mask[i]) { 202 GLstencil s = stencil[i]; 203 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s)); 204 } 205 } 206 } 207 break; 208 default: 209 _mesa_problem(ctx, "Bad stencil op in apply_stencil_op"); 210 } 211} 212 213 214 215 216/** 217 * Apply stencil test to an array of stencil values (before depth buffering). 218 * Input: face - 0 or 1 for front or back-face polygons 219 * n - number of pixels in the array 220 * stencil - array of [n] stencil values 221 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel 222 * Output: mask - pixels which fail the stencil test will have their 223 * mask flag set to 0. 224 * stencil - updated stencil values (where the test passed) 225 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed. 226 */ 227static GLboolean 228do_stencil_test( GLcontext *ctx, GLuint face, GLuint n, GLstencil stencil[], 229 GLubyte mask[] ) 230{ 231 GLubyte fail[MAX_WIDTH]; 232 GLboolean allfail = GL_FALSE; 233 GLuint i; 234 GLstencil r, s; 235 const GLuint valueMask = ctx->Stencil.ValueMask[face]; 236 237 ASSERT(n <= MAX_WIDTH); 238 239 /* 240 * Perform stencil test. The results of this operation are stored 241 * in the fail[] array: 242 * IF fail[i] is non-zero THEN 243 * the stencil fail operator is to be applied 244 * ELSE 245 * the stencil fail operator is not to be applied 246 * ENDIF 247 */ 248 switch (ctx->Stencil.Function[face]) { 249 case GL_NEVER: 250 /* never pass; always fail */ 251 for (i=0;i<n;i++) { 252 if (mask[i]) { 253 mask[i] = 0; 254 fail[i] = 1; 255 } 256 else { 257 fail[i] = 0; 258 } 259 } 260 allfail = GL_TRUE; 261 break; 262 case GL_LESS: 263 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 264 for (i=0;i<n;i++) { 265 if (mask[i]) { 266 s = (GLstencil) (stencil[i] & valueMask); 267 if (r < s) { 268 /* passed */ 269 fail[i] = 0; 270 } 271 else { 272 fail[i] = 1; 273 mask[i] = 0; 274 } 275 } 276 else { 277 fail[i] = 0; 278 } 279 } 280 break; 281 case GL_LEQUAL: 282 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 283 for (i=0;i<n;i++) { 284 if (mask[i]) { 285 s = (GLstencil) (stencil[i] & valueMask); 286 if (r <= s) { 287 /* pass */ 288 fail[i] = 0; 289 } 290 else { 291 fail[i] = 1; 292 mask[i] = 0; 293 } 294 } 295 else { 296 fail[i] = 0; 297 } 298 } 299 break; 300 case GL_GREATER: 301 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 302 for (i=0;i<n;i++) { 303 if (mask[i]) { 304 s = (GLstencil) (stencil[i] & valueMask); 305 if (r > s) { 306 /* passed */ 307 fail[i] = 0; 308 } 309 else { 310 fail[i] = 1; 311 mask[i] = 0; 312 } 313 } 314 else { 315 fail[i] = 0; 316 } 317 } 318 break; 319 case GL_GEQUAL: 320 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 321 for (i=0;i<n;i++) { 322 if (mask[i]) { 323 s = (GLstencil) (stencil[i] & valueMask); 324 if (r >= s) { 325 /* passed */ 326 fail[i] = 0; 327 } 328 else { 329 fail[i] = 1; 330 mask[i] = 0; 331 } 332 } 333 else { 334 fail[i] = 0; 335 } 336 } 337 break; 338 case GL_EQUAL: 339 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 340 for (i=0;i<n;i++) { 341 if (mask[i]) { 342 s = (GLstencil) (stencil[i] & valueMask); 343 if (r == s) { 344 /* passed */ 345 fail[i] = 0; 346 } 347 else { 348 fail[i] = 1; 349 mask[i] = 0; 350 } 351 } 352 else { 353 fail[i] = 0; 354 } 355 } 356 break; 357 case GL_NOTEQUAL: 358 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 359 for (i=0;i<n;i++) { 360 if (mask[i]) { 361 s = (GLstencil) (stencil[i] & valueMask); 362 if (r != s) { 363 /* passed */ 364 fail[i] = 0; 365 } 366 else { 367 fail[i] = 1; 368 mask[i] = 0; 369 } 370 } 371 else { 372 fail[i] = 0; 373 } 374 } 375 break; 376 case GL_ALWAYS: 377 /* always pass */ 378 for (i=0;i<n;i++) { 379 fail[i] = 0; 380 } 381 break; 382 default: 383 _mesa_problem(ctx, "Bad stencil func in gl_stencil_span"); 384 return 0; 385 } 386 387 if (ctx->Stencil.FailFunc[face] != GL_KEEP) { 388 apply_stencil_op( ctx, ctx->Stencil.FailFunc[face], face, n, stencil, fail ); 389 } 390 391 return !allfail; 392} 393 394 395/** 396 * Compute the zpass/zfail masks by comparing the pre- and post-depth test 397 * masks. 398 */ 399static INLINE void 400compute_pass_fail_masks(GLuint n, const GLubyte origMask[], 401 const GLubyte newMask[], 402 GLubyte passMask[], GLubyte failMask[]) 403{ 404 GLuint i; 405 for (i = 0; i < n; i++) { 406 ASSERT(newMask[i] == 0 || newMask[i] == 1); 407 passMask[i] = origMask[i] & newMask[i]; 408 failMask[i] = origMask[i] & (newMask[i] ^ 1); 409 } 410} 411 412 413/** 414 * Apply stencil and depth testing to the span of pixels. 415 * Both software and hardware stencil buffers are acceptable. 416 * Input: n - number of pixels in the span 417 * x, y - location of leftmost pixel in span 418 * z - array [n] of z values 419 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 420 * Output: mask - array [n] of flags (1=stencil and depth test passed) 421 * Return: GL_FALSE - all fragments failed the testing 422 * GL_TRUE - one or more fragments passed the testing 423 * 424 */ 425static GLboolean 426stencil_and_ztest_span(GLcontext *ctx, SWspan *span, GLuint face) 427{ 428 struct gl_framebuffer *fb = ctx->DrawBuffer; 429 struct gl_renderbuffer *rb = fb->_StencilBuffer; 430 GLstencil stencilRow[MAX_WIDTH]; 431 GLstencil *stencil; 432 const GLuint n = span->end; 433 const GLint x = span->x; 434 const GLint y = span->y; 435 GLubyte *mask = span->array->mask; 436 437 ASSERT((span->arrayMask & SPAN_XY) == 0); 438 ASSERT(ctx->Stencil.Enabled); 439 ASSERT(n <= MAX_WIDTH); 440#ifdef DEBUG 441 if (ctx->Depth.Test) { 442 ASSERT(span->arrayMask & SPAN_Z); 443 } 444#endif 445 446 stencil = (GLstencil *) rb->GetPointer(ctx, rb, x, y); 447 if (!stencil) { 448 rb->GetRow(ctx, rb, n, x, y, stencilRow); 449 stencil = stencilRow; 450 } 451 452 /* 453 * Apply the stencil test to the fragments. 454 * failMask[i] is 1 if the stencil test failed. 455 */ 456 if (do_stencil_test( ctx, face, n, stencil, mask ) == GL_FALSE) { 457 /* all fragments failed the stencil test, we're done. */ 458 span->writeAll = GL_FALSE; 459 if (!rb->GetPointer(ctx, rb, 0, 0)) { 460 /* put updated stencil values into buffer */ 461 rb->PutRow(ctx, rb, n, x, y, stencil, NULL); 462 } 463 return GL_FALSE; 464 } 465 466 /* 467 * Some fragments passed the stencil test, apply depth test to them 468 * and apply Zpass and Zfail stencil ops. 469 */ 470 if (ctx->Depth.Test == GL_FALSE) { 471 /* 472 * No depth buffer, just apply zpass stencil function to active pixels. 473 */ 474 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask ); 475 } 476 else { 477 /* 478 * Perform depth buffering, then apply zpass or zfail stencil function. 479 */ 480 GLubyte passMask[MAX_WIDTH], failMask[MAX_WIDTH], origMask[MAX_WIDTH]; 481 482 /* save the current mask bits */ 483 _mesa_memcpy(origMask, mask, n * sizeof(GLubyte)); 484 485 /* apply the depth test */ 486 _swrast_depth_test_span(ctx, span); 487 488 compute_pass_fail_masks(n, origMask, mask, passMask, failMask); 489 490 /* apply the pass and fail operations */ 491 if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { 492 apply_stencil_op( ctx, ctx->Stencil.ZFailFunc[face], face, 493 n, stencil, failMask ); 494 } 495 if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { 496 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, 497 n, stencil, passMask ); 498 } 499 } 500 501 /* 502 * Write updated stencil values back into hardware stencil buffer. 503 */ 504 if (!rb->GetPointer(ctx, rb, 0, 0)) { 505 rb->PutRow(ctx, rb, n, x, y, stencil, NULL); 506 } 507 508 span->writeAll = GL_FALSE; 509 510 return GL_TRUE; /* one or more fragments passed both tests */ 511} 512 513 514 515/* 516 * Return the address of a stencil buffer value given the window coords: 517 */ 518#define STENCIL_ADDRESS(X, Y) (stencilStart + (Y) * stride + (X)) 519 520 521 522/** 523 * Apply the given stencil operator for each pixel in the array whose 524 * mask flag is set. 525 * \note This is for software stencil buffers only. 526 * Input: n - number of pixels in the span 527 * x, y - array of [n] pixels 528 * operator - the stencil buffer operator 529 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator 530 */ 531static void 532apply_stencil_op_to_pixels( GLcontext *ctx, 533 GLuint n, const GLint x[], const GLint y[], 534 GLenum oper, GLuint face, const GLubyte mask[] ) 535{ 536 struct gl_framebuffer *fb = ctx->DrawBuffer; 537 struct gl_renderbuffer *rb = fb->_StencilBuffer; 538 const GLstencil stencilMax = (1 << fb->Visual.stencilBits) - 1; 539 const GLstencil ref = ctx->Stencil.Ref[face]; 540 const GLstencil wrtmask = ctx->Stencil.WriteMask[face]; 541 const GLstencil invmask = (GLstencil) (~wrtmask); 542 GLuint i; 543 GLstencil *stencilStart = (GLubyte *) rb->Data; 544 const GLuint stride = rb->Width; 545 546 ASSERT(rb->GetPointer(ctx, rb, 0, 0)); 547 ASSERT(sizeof(GLstencil) == 1); 548 549 switch (oper) { 550 case GL_KEEP: 551 /* do nothing */ 552 break; 553 case GL_ZERO: 554 if (invmask==0) { 555 for (i=0;i<n;i++) { 556 if (mask[i]) { 557 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 558 *sptr = 0; 559 } 560 } 561 } 562 else { 563 for (i=0;i<n;i++) { 564 if (mask[i]) { 565 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 566 *sptr = (GLstencil) (invmask & *sptr); 567 } 568 } 569 } 570 break; 571 case GL_REPLACE: 572 if (invmask==0) { 573 for (i=0;i<n;i++) { 574 if (mask[i]) { 575 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 576 *sptr = ref; 577 } 578 } 579 } 580 else { 581 for (i=0;i<n;i++) { 582 if (mask[i]) { 583 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 584 *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref)); 585 } 586 } 587 } 588 break; 589 case GL_INCR: 590 if (invmask==0) { 591 for (i=0;i<n;i++) { 592 if (mask[i]) { 593 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 594 if (*sptr < stencilMax) { 595 *sptr = (GLstencil) (*sptr + 1); 596 } 597 } 598 } 599 } 600 else { 601 for (i=0;i<n;i++) { 602 if (mask[i]) { 603 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 604 if (*sptr < stencilMax) { 605 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); 606 } 607 } 608 } 609 } 610 break; 611 case GL_DECR: 612 if (invmask==0) { 613 for (i=0;i<n;i++) { 614 if (mask[i]) { 615 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 616 if (*sptr>0) { 617 *sptr = (GLstencil) (*sptr - 1); 618 } 619 } 620 } 621 } 622 else { 623 for (i=0;i<n;i++) { 624 if (mask[i]) { 625 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 626 if (*sptr>0) { 627 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); 628 } 629 } 630 } 631 } 632 break; 633 case GL_INCR_WRAP_EXT: 634 if (invmask==0) { 635 for (i=0;i<n;i++) { 636 if (mask[i]) { 637 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 638 *sptr = (GLstencil) (*sptr + 1); 639 } 640 } 641 } 642 else { 643 for (i=0;i<n;i++) { 644 if (mask[i]) { 645 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 646 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); 647 } 648 } 649 } 650 break; 651 case GL_DECR_WRAP_EXT: 652 if (invmask==0) { 653 for (i=0;i<n;i++) { 654 if (mask[i]) { 655 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 656 *sptr = (GLstencil) (*sptr - 1); 657 } 658 } 659 } 660 else { 661 for (i=0;i<n;i++) { 662 if (mask[i]) { 663 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 664 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); 665 } 666 } 667 } 668 break; 669 case GL_INVERT: 670 if (invmask==0) { 671 for (i=0;i<n;i++) { 672 if (mask[i]) { 673 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 674 *sptr = (GLstencil) (~*sptr); 675 } 676 } 677 } 678 else { 679 for (i=0;i<n;i++) { 680 if (mask[i]) { 681 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 682 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr)); 683 } 684 } 685 } 686 break; 687 default: 688 _mesa_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels"); 689 } 690} 691 692 693 694/** 695 * Apply stencil test to an array of pixels before depth buffering. 696 * 697 * \note Used for software stencil buffer only. 698 * Input: n - number of pixels in the span 699 * x, y - array of [n] pixels to stencil 700 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel 701 * Output: mask - pixels which fail the stencil test will have their 702 * mask flag set to 0. 703 * \return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed. 704 */ 705static GLboolean 706stencil_test_pixels( GLcontext *ctx, GLuint face, GLuint n, 707 const GLint x[], const GLint y[], GLubyte mask[] ) 708{ 709 const struct gl_framebuffer *fb = ctx->DrawBuffer; 710 struct gl_renderbuffer *rb = fb->_StencilBuffer; 711 GLubyte fail[MAX_WIDTH]; 712 GLstencil r, s; 713 GLuint i; 714 GLboolean allfail = GL_FALSE; 715 const GLuint valueMask = ctx->Stencil.ValueMask[face]; 716 const GLstencil *stencilStart = (GLstencil *) rb->Data; 717 const GLuint stride = rb->Width; 718 719 ASSERT(rb->GetPointer(ctx, rb, 0, 0)); 720 ASSERT(sizeof(GLstencil) == 1); 721 722 /* 723 * Perform stencil test. The results of this operation are stored 724 * in the fail[] array: 725 * IF fail[i] is non-zero THEN 726 * the stencil fail operator is to be applied 727 * ELSE 728 * the stencil fail operator is not to be applied 729 * ENDIF 730 */ 731 732 switch (ctx->Stencil.Function[face]) { 733 case GL_NEVER: 734 /* always fail */ 735 for (i=0;i<n;i++) { 736 if (mask[i]) { 737 mask[i] = 0; 738 fail[i] = 1; 739 } 740 else { 741 fail[i] = 0; 742 } 743 } 744 allfail = GL_TRUE; 745 break; 746 case GL_LESS: 747 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 748 for (i=0;i<n;i++) { 749 if (mask[i]) { 750 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 751 s = (GLstencil) (*sptr & valueMask); 752 if (r < s) { 753 /* passed */ 754 fail[i] = 0; 755 } 756 else { 757 fail[i] = 1; 758 mask[i] = 0; 759 } 760 } 761 else { 762 fail[i] = 0; 763 } 764 } 765 break; 766 case GL_LEQUAL: 767 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 768 for (i=0;i<n;i++) { 769 if (mask[i]) { 770 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 771 s = (GLstencil) (*sptr & valueMask); 772 if (r <= s) { 773 /* pass */ 774 fail[i] = 0; 775 } 776 else { 777 fail[i] = 1; 778 mask[i] = 0; 779 } 780 } 781 else { 782 fail[i] = 0; 783 } 784 } 785 break; 786 case GL_GREATER: 787 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 788 for (i=0;i<n;i++) { 789 if (mask[i]) { 790 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 791 s = (GLstencil) (*sptr & valueMask); 792 if (r > s) { 793 /* passed */ 794 fail[i] = 0; 795 } 796 else { 797 fail[i] = 1; 798 mask[i] = 0; 799 } 800 } 801 else { 802 fail[i] = 0; 803 } 804 } 805 break; 806 case GL_GEQUAL: 807 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 808 for (i=0;i<n;i++) { 809 if (mask[i]) { 810 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 811 s = (GLstencil) (*sptr & valueMask); 812 if (r >= s) { 813 /* passed */ 814 fail[i] = 0; 815 } 816 else { 817 fail[i] = 1; 818 mask[i] = 0; 819 } 820 } 821 else { 822 fail[i] = 0; 823 } 824 } 825 break; 826 case GL_EQUAL: 827 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 828 for (i=0;i<n;i++) { 829 if (mask[i]) { 830 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 831 s = (GLstencil) (*sptr & valueMask); 832 if (r == s) { 833 /* passed */ 834 fail[i] = 0; 835 } 836 else { 837 fail[i] = 1; 838 mask[i] = 0; 839 } 840 } 841 else { 842 fail[i] = 0; 843 } 844 } 845 break; 846 case GL_NOTEQUAL: 847 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 848 for (i=0;i<n;i++) { 849 if (mask[i]) { 850 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 851 s = (GLstencil) (*sptr & valueMask); 852 if (r != s) { 853 /* passed */ 854 fail[i] = 0; 855 } 856 else { 857 fail[i] = 1; 858 mask[i] = 0; 859 } 860 } 861 else { 862 fail[i] = 0; 863 } 864 } 865 break; 866 case GL_ALWAYS: 867 /* always pass */ 868 for (i=0;i<n;i++) { 869 fail[i] = 0; 870 } 871 break; 872 default: 873 _mesa_problem(ctx, "Bad stencil func in gl_stencil_pixels"); 874 return 0; 875 } 876 877 if (ctx->Stencil.FailFunc[face] != GL_KEEP) { 878 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc[face], 879 face, fail ); 880 } 881 882 return !allfail; 883} 884 885 886 887 888/** 889 * Apply stencil and depth testing to an array of pixels. 890 * This is used both for software and hardware stencil buffers. 891 * 892 * The comments in this function are a bit sparse but the code is 893 * almost identical to stencil_and_ztest_span(), which is well 894 * commented. 895 * 896 * Input: n - number of pixels in the array 897 * x, y - array of [n] pixel positions 898 * z - array [n] of z values 899 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 900 * Output: mask - array [n] of flags (1=stencil and depth test passed) 901 * Return: GL_FALSE - all fragments failed the testing 902 * GL_TRUE - one or more fragments passed the testing 903 */ 904static GLboolean 905stencil_and_ztest_pixels( GLcontext *ctx, SWspan *span, GLuint face ) 906{ 907 GLubyte passMask[MAX_WIDTH], failMask[MAX_WIDTH], origMask[MAX_WIDTH]; 908 struct gl_framebuffer *fb = ctx->DrawBuffer; 909 struct gl_renderbuffer *rb = fb->_StencilBuffer; 910 const GLuint n = span->end; 911 const GLint *x = span->array->x; 912 const GLint *y = span->array->y; 913 GLubyte *mask = span->array->mask; 914 915 ASSERT(span->arrayMask & SPAN_XY); 916 ASSERT(ctx->Stencil.Enabled); 917 ASSERT(n <= MAX_WIDTH); 918 919 if (!rb->GetPointer(ctx, rb, 0, 0)) { 920 /* No direct access */ 921 GLstencil stencil[MAX_WIDTH]; 922 923 ASSERT(rb->DataType == GL_UNSIGNED_BYTE); 924 _swrast_get_values(ctx, rb, n, x, y, stencil, sizeof(GLubyte)); 925 926 _mesa_memcpy(origMask, mask, n * sizeof(GLubyte)); 927 928 (void) do_stencil_test(ctx, face, n, stencil, mask); 929 930 if (ctx->Depth.Test == GL_FALSE) { 931 apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, 932 n, stencil, mask); 933 } 934 else { 935 GLubyte tmpMask[MAX_WIDTH]; 936 _mesa_memcpy(tmpMask, mask, n * sizeof(GLubyte)); 937 938 _swrast_depth_test_span(ctx, span); 939 940 compute_pass_fail_masks(n, tmpMask, mask, passMask, failMask); 941 942 if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { 943 apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face, 944 n, stencil, failMask); 945 } 946 if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { 947 apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, 948 n, stencil, passMask); 949 } 950 } 951 952 /* Write updated stencil values into hardware stencil buffer */ 953 rb->PutValues(ctx, rb, n, x, y, stencil, origMask); 954 955 return GL_TRUE; 956 } 957 else { 958 /* Direct access to stencil buffer */ 959 960 if (stencil_test_pixels(ctx, face, n, x, y, mask) == GL_FALSE) { 961 /* all fragments failed the stencil test, we're done. */ 962 return GL_FALSE; 963 } 964 965 if (ctx->Depth.Test==GL_FALSE) { 966 apply_stencil_op_to_pixels(ctx, n, x, y, 967 ctx->Stencil.ZPassFunc[face], face, mask); 968 } 969 else { 970 _mesa_memcpy(origMask, mask, n * sizeof(GLubyte)); 971 972 _swrast_depth_test_span(ctx, span); 973 974 compute_pass_fail_masks(n, origMask, mask, passMask, failMask); 975 976 if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { 977 apply_stencil_op_to_pixels(ctx, n, x, y, 978 ctx->Stencil.ZFailFunc[face], 979 face, failMask); 980 } 981 if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { 982 apply_stencil_op_to_pixels(ctx, n, x, y, 983 ctx->Stencil.ZPassFunc[face], 984 face, passMask); 985 } 986 } 987 988 return GL_TRUE; /* one or more fragments passed both tests */ 989 } 990} 991 992 993/** 994 * /return GL_TRUE = one or more fragments passed, 995 * GL_FALSE = all fragments failed. 996 */ 997GLboolean 998_swrast_stencil_and_ztest_span(GLcontext *ctx, SWspan *span) 999{ 1000 const GLuint face = (span->facing == 0) ? 0 : ctx->Stencil._BackFace; 1001 1002 if (span->arrayMask & SPAN_XY) 1003 return stencil_and_ztest_pixels(ctx, span, face); 1004 else 1005 return stencil_and_ztest_span(ctx, span, face); 1006} 1007 1008 1009#if 0 1010GLuint 1011clip_span(GLuint bufferWidth, GLuint bufferHeight, 1012 GLint x, GLint y, GLuint *count) 1013{ 1014 GLuint n = *count; 1015 GLuint skipPixels = 0; 1016 1017 if (y < 0 || y >= bufferHeight || x + n <= 0 || x >= bufferWidth) { 1018 /* totally out of bounds */ 1019 n = 0; 1020 } 1021 else { 1022 /* left clip */ 1023 if (x < 0) { 1024 skipPixels = -x; 1025 x = 0; 1026 n -= skipPixels; 1027 } 1028 /* right clip */ 1029 if (x + n > bufferWidth) { 1030 GLint dx = x + n - bufferWidth; 1031 n -= dx; 1032 } 1033 } 1034 1035 *count = n; 1036 1037 return skipPixels; 1038} 1039#endif 1040 1041 1042/** 1043 * Return a span of stencil values from the stencil buffer. 1044 * Used for glRead/CopyPixels 1045 * Input: n - how many pixels 1046 * x,y - location of first pixel 1047 * Output: stencil - the array of stencil values 1048 */ 1049void 1050_swrast_read_stencil_span(GLcontext *ctx, struct gl_renderbuffer *rb, 1051 GLint n, GLint x, GLint y, GLstencil stencil[]) 1052{ 1053 if (y < 0 || y >= (GLint) rb->Height || 1054 x + n <= 0 || x >= (GLint) rb->Width) { 1055 /* span is completely outside framebuffer */ 1056 return; /* undefined values OK */ 1057 } 1058 1059 if (x < 0) { 1060 GLint dx = -x; 1061 x = 0; 1062 n -= dx; 1063 stencil += dx; 1064 } 1065 if (x + n > (GLint) rb->Width) { 1066 GLint dx = x + n - rb->Width; 1067 n -= dx; 1068 } 1069 if (n <= 0) { 1070 return; 1071 } 1072 1073 rb->GetRow(ctx, rb, n, x, y, stencil); 1074} 1075 1076 1077 1078/** 1079 * Write a span of stencil values to the stencil buffer. This function 1080 * applies the stencil write mask when needed. 1081 * Used for glDraw/CopyPixels 1082 * Input: n - how many pixels 1083 * x, y - location of first pixel 1084 * stencil - the array of stencil values 1085 */ 1086void 1087_swrast_write_stencil_span(GLcontext *ctx, GLint n, GLint x, GLint y, 1088 const GLstencil stencil[] ) 1089{ 1090 struct gl_framebuffer *fb = ctx->DrawBuffer; 1091 struct gl_renderbuffer *rb = fb->_StencilBuffer; 1092 const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1; 1093 const GLuint stencilMask = ctx->Stencil.WriteMask[0]; 1094 1095 if (y < 0 || y >= (GLint) rb->Height || 1096 x + n <= 0 || x >= (GLint) rb->Width) { 1097 /* span is completely outside framebuffer */ 1098 return; /* undefined values OK */ 1099 } 1100 if (x < 0) { 1101 GLint dx = -x; 1102 x = 0; 1103 n -= dx; 1104 stencil += dx; 1105 } 1106 if (x + n > (GLint) rb->Width) { 1107 GLint dx = x + n - rb->Width; 1108 n -= dx; 1109 } 1110 if (n <= 0) { 1111 return; 1112 } 1113 1114 if ((stencilMask & stencilMax) != stencilMax) { 1115 /* need to apply writemask */ 1116 GLstencil destVals[MAX_WIDTH], newVals[MAX_WIDTH]; 1117 GLint i; 1118 rb->GetRow(ctx, rb, n, x, y, destVals); 1119 for (i = 0; i < n; i++) { 1120 newVals[i] 1121 = (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask); 1122 } 1123 rb->PutRow(ctx, rb, n, x, y, newVals, NULL); 1124 } 1125 else { 1126 rb->PutRow(ctx, rb, n, x, y, stencil, NULL); 1127 } 1128} 1129 1130 1131 1132/** 1133 * Clear the stencil buffer. 1134 */ 1135void 1136_swrast_clear_stencil_buffer( GLcontext *ctx, struct gl_renderbuffer *rb ) 1137{ 1138 const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits; 1139 const GLuint mask = ctx->Stencil.WriteMask[0]; 1140 const GLuint invMask = ~mask; 1141 const GLuint clearVal = (ctx->Stencil.Clear & mask); 1142 const GLuint stencilMax = (1 << stencilBits) - 1; 1143 GLint x, y, width, height; 1144 1145 if (!rb || mask == 0) 1146 return; 1147 1148 ASSERT(rb->DataType == GL_UNSIGNED_BYTE || 1149 rb->DataType == GL_UNSIGNED_SHORT); 1150 1151 ASSERT(rb->_BaseFormat == GL_STENCIL_INDEX); 1152 1153 /* compute region to clear */ 1154 x = ctx->DrawBuffer->_Xmin; 1155 y = ctx->DrawBuffer->_Ymin; 1156 width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; 1157 height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; 1158 1159 if (rb->GetPointer(ctx, rb, 0, 0)) { 1160 /* Direct buffer access */ 1161 if ((mask & stencilMax) != stencilMax) { 1162 /* need to mask the clear */ 1163 if (rb->DataType == GL_UNSIGNED_BYTE) { 1164 GLint i, j; 1165 for (i = 0; i < height; i++) { 1166 GLubyte *stencil = (GLubyte*) rb->GetPointer(ctx, rb, x, y + i); 1167 for (j = 0; j < width; j++) { 1168 stencil[j] = (stencil[j] & invMask) | clearVal; 1169 } 1170 } 1171 } 1172 else { 1173 GLint i, j; 1174 for (i = 0; i < height; i++) { 1175 GLushort *stencil = (GLushort*) rb->GetPointer(ctx, rb, x, y + i); 1176 for (j = 0; j < width; j++) { 1177 stencil[j] = (stencil[j] & invMask) | clearVal; 1178 } 1179 } 1180 } 1181 } 1182 else { 1183 /* no bit masking */ 1184 if (width == (GLint) rb->Width && rb->DataType == GL_UNSIGNED_BYTE) { 1185 /* optimized case */ 1186 /* Note: bottom-to-top raster assumed! */ 1187 GLubyte *stencil = (GLubyte *) rb->GetPointer(ctx, rb, x, y); 1188 GLuint len = width * height * sizeof(GLubyte); 1189 _mesa_memset(stencil, clearVal, len); 1190 } 1191 else { 1192 /* general case */ 1193 GLint i; 1194 for (i = 0; i < height; i++) { 1195 GLvoid *stencil = rb->GetPointer(ctx, rb, x, y + i); 1196 if (rb->DataType == GL_UNSIGNED_BYTE) { 1197 _mesa_memset(stencil, clearVal, width); 1198 } 1199 else { 1200 _mesa_memset16((short unsigned int*) stencil, clearVal, width); 1201 } 1202 } 1203 } 1204 } 1205 } 1206 else { 1207 /* no direct access */ 1208 if ((mask & stencilMax) != stencilMax) { 1209 /* need to mask the clear */ 1210 if (rb->DataType == GL_UNSIGNED_BYTE) { 1211 GLint i, j; 1212 for (i = 0; i < height; i++) { 1213 GLubyte stencil[MAX_WIDTH]; 1214 rb->GetRow(ctx, rb, width, x, y + i, stencil); 1215 for (j = 0; j < width; j++) { 1216 stencil[j] = (stencil[j] & invMask) | clearVal; 1217 } 1218 rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL); 1219 } 1220 } 1221 else { 1222 GLint i, j; 1223 for (i = 0; i < height; i++) { 1224 GLushort stencil[MAX_WIDTH]; 1225 rb->GetRow(ctx, rb, width, x, y + i, stencil); 1226 for (j = 0; j < width; j++) { 1227 stencil[j] = (stencil[j] & invMask) | clearVal; 1228 } 1229 rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL); 1230 } 1231 } 1232 } 1233 else { 1234 /* no bit masking */ 1235 const GLubyte clear8 = (GLubyte) clearVal; 1236 const GLushort clear16 = (GLushort) clearVal; 1237 const void *clear; 1238 GLint i; 1239 if (rb->DataType == GL_UNSIGNED_BYTE) { 1240 clear = &clear8; 1241 } 1242 else { 1243 clear = &clear16; 1244 } 1245 for (i = 0; i < height; i++) { 1246 rb->PutMonoRow(ctx, rb, width, x, y + i, clear, NULL); 1247 } 1248 } 1249 } 1250} 1251