s_stencil.c revision 7117f1b4
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2005 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 "glheader.h" 27#include "context.h" 28#include "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/** 397 * Apply stencil and depth testing to the span of pixels. 398 * Both software and hardware stencil buffers are acceptable. 399 * Input: n - number of pixels in the span 400 * x, y - location of leftmost pixel in span 401 * z - array [n] of z values 402 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 403 * Output: mask - array [n] of flags (1=stencil and depth test passed) 404 * Return: GL_FALSE - all fragments failed the testing 405 * GL_TRUE - one or more fragments passed the testing 406 * 407 */ 408static GLboolean 409stencil_and_ztest_span(GLcontext *ctx, SWspan *span, GLuint face) 410{ 411 struct gl_framebuffer *fb = ctx->DrawBuffer; 412 struct gl_renderbuffer *rb = fb->_StencilBuffer; 413 GLstencil stencilRow[MAX_WIDTH]; 414 GLstencil *stencil; 415 const GLuint n = span->end; 416 const GLint x = span->x; 417 const GLint y = span->y; 418 GLubyte *mask = span->array->mask; 419 420 ASSERT((span->arrayMask & SPAN_XY) == 0); 421 ASSERT(ctx->Stencil.Enabled); 422 ASSERT(n <= MAX_WIDTH); 423#ifdef DEBUG 424 if (ctx->Depth.Test) { 425 ASSERT(span->arrayMask & SPAN_Z); 426 } 427#endif 428 429 stencil = (GLstencil *) rb->GetPointer(ctx, rb, x, y); 430 if (!stencil) { 431 rb->GetRow(ctx, rb, n, x, y, stencilRow); 432 stencil = stencilRow; 433 } 434 435 /* 436 * Apply the stencil test to the fragments. 437 * failMask[i] is 1 if the stencil test failed. 438 */ 439 if (do_stencil_test( ctx, face, n, stencil, mask ) == GL_FALSE) { 440 /* all fragments failed the stencil test, we're done. */ 441 span->writeAll = GL_FALSE; 442 if (!rb->GetPointer(ctx, rb, 0, 0)) { 443 /* put updated stencil values into buffer */ 444 rb->PutRow(ctx, rb, n, x, y, stencil, NULL); 445 } 446 return GL_FALSE; 447 } 448 449 /* 450 * Some fragments passed the stencil test, apply depth test to them 451 * and apply Zpass and Zfail stencil ops. 452 */ 453 if (ctx->Depth.Test == GL_FALSE) { 454 /* 455 * No depth buffer, just apply zpass stencil function to active pixels. 456 */ 457 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask ); 458 } 459 else { 460 /* 461 * Perform depth buffering, then apply zpass or zfail stencil function. 462 */ 463 GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; 464 GLuint i; 465 466 /* save the current mask bits */ 467 _mesa_memcpy(oldmask, mask, n * sizeof(GLubyte)); 468 469 /* apply the depth test */ 470 _swrast_depth_test_span(ctx, span); 471 472 /* Set the stencil pass/fail flags according to result of depth testing. 473 * if oldmask[i] == 0 then 474 * Don't touch the stencil value 475 * else if oldmask[i] and newmask[i] then 476 * Depth test passed 477 * else 478 * assert(oldmask[i] && !newmask[i]) 479 * Depth test failed 480 * endif 481 */ 482 for (i=0;i<n;i++) { 483 ASSERT(mask[i] == 0 || mask[i] == 1); 484 passmask[i] = oldmask[i] & mask[i]; 485 failmask[i] = oldmask[i] & (mask[i] ^ 1); 486 } 487 488 /* apply the pass and fail operations */ 489 if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { 490 apply_stencil_op( ctx, ctx->Stencil.ZFailFunc[face], face, 491 n, stencil, failmask ); 492 } 493 if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { 494 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, 495 n, stencil, passmask ); 496 } 497 } 498 499 /* 500 * Write updated stencil values back into hardware stencil buffer. 501 */ 502 if (!rb->GetPointer(ctx, rb, 0, 0)) { 503 rb->PutRow(ctx, rb, n, x, y, stencil, NULL); 504 } 505 506 span->writeAll = GL_FALSE; 507 508 return GL_TRUE; /* one or more fragments passed both tests */ 509} 510 511 512 513/* 514 * Return the address of a stencil buffer value given the window coords: 515 */ 516#define STENCIL_ADDRESS(X, Y) (stencilStart + (Y) * stride + (X)) 517 518 519 520/** 521 * Apply the given stencil operator for each pixel in the array whose 522 * mask flag is set. 523 * \note This is for software stencil buffers only. 524 * Input: n - number of pixels in the span 525 * x, y - array of [n] pixels 526 * operator - the stencil buffer operator 527 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator 528 */ 529static void 530apply_stencil_op_to_pixels( GLcontext *ctx, 531 GLuint n, const GLint x[], const GLint y[], 532 GLenum oper, GLuint face, const GLubyte mask[] ) 533{ 534 struct gl_framebuffer *fb = ctx->DrawBuffer; 535 struct gl_renderbuffer *rb = fb->_StencilBuffer; 536 const GLstencil stencilMax = (1 << fb->Visual.stencilBits) - 1; 537 const GLstencil ref = ctx->Stencil.Ref[face]; 538 const GLstencil wrtmask = ctx->Stencil.WriteMask[face]; 539 const GLstencil invmask = (GLstencil) (~wrtmask); 540 GLuint i; 541 GLstencil *stencilStart = (GLubyte *) rb->Data; 542 const GLuint stride = rb->Width; 543 544 ASSERT(rb->GetPointer(ctx, rb, 0, 0)); 545 ASSERT(sizeof(GLstencil) == 1); 546 547 switch (oper) { 548 case GL_KEEP: 549 /* do nothing */ 550 break; 551 case GL_ZERO: 552 if (invmask==0) { 553 for (i=0;i<n;i++) { 554 if (mask[i]) { 555 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 556 *sptr = 0; 557 } 558 } 559 } 560 else { 561 for (i=0;i<n;i++) { 562 if (mask[i]) { 563 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 564 *sptr = (GLstencil) (invmask & *sptr); 565 } 566 } 567 } 568 break; 569 case GL_REPLACE: 570 if (invmask==0) { 571 for (i=0;i<n;i++) { 572 if (mask[i]) { 573 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 574 *sptr = ref; 575 } 576 } 577 } 578 else { 579 for (i=0;i<n;i++) { 580 if (mask[i]) { 581 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 582 *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref)); 583 } 584 } 585 } 586 break; 587 case GL_INCR: 588 if (invmask==0) { 589 for (i=0;i<n;i++) { 590 if (mask[i]) { 591 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 592 if (*sptr < stencilMax) { 593 *sptr = (GLstencil) (*sptr + 1); 594 } 595 } 596 } 597 } 598 else { 599 for (i=0;i<n;i++) { 600 if (mask[i]) { 601 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 602 if (*sptr < stencilMax) { 603 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); 604 } 605 } 606 } 607 } 608 break; 609 case GL_DECR: 610 if (invmask==0) { 611 for (i=0;i<n;i++) { 612 if (mask[i]) { 613 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 614 if (*sptr>0) { 615 *sptr = (GLstencil) (*sptr - 1); 616 } 617 } 618 } 619 } 620 else { 621 for (i=0;i<n;i++) { 622 if (mask[i]) { 623 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 624 if (*sptr>0) { 625 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); 626 } 627 } 628 } 629 } 630 break; 631 case GL_INCR_WRAP_EXT: 632 if (invmask==0) { 633 for (i=0;i<n;i++) { 634 if (mask[i]) { 635 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 636 *sptr = (GLstencil) (*sptr + 1); 637 } 638 } 639 } 640 else { 641 for (i=0;i<n;i++) { 642 if (mask[i]) { 643 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 644 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); 645 } 646 } 647 } 648 break; 649 case GL_DECR_WRAP_EXT: 650 if (invmask==0) { 651 for (i=0;i<n;i++) { 652 if (mask[i]) { 653 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 654 *sptr = (GLstencil) (*sptr - 1); 655 } 656 } 657 } 658 else { 659 for (i=0;i<n;i++) { 660 if (mask[i]) { 661 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 662 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); 663 } 664 } 665 } 666 break; 667 case GL_INVERT: 668 if (invmask==0) { 669 for (i=0;i<n;i++) { 670 if (mask[i]) { 671 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 672 *sptr = (GLstencil) (~*sptr); 673 } 674 } 675 } 676 else { 677 for (i=0;i<n;i++) { 678 if (mask[i]) { 679 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); 680 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr)); 681 } 682 } 683 } 684 break; 685 default: 686 _mesa_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels"); 687 } 688} 689 690 691 692/** 693 * Apply stencil test to an array of pixels before depth buffering. 694 * 695 * \note Used for software stencil buffer only. 696 * Input: n - number of pixels in the span 697 * x, y - array of [n] pixels to stencil 698 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel 699 * Output: mask - pixels which fail the stencil test will have their 700 * mask flag set to 0. 701 * \return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed. 702 */ 703static GLboolean 704stencil_test_pixels( GLcontext *ctx, GLuint face, GLuint n, 705 const GLint x[], const GLint y[], GLubyte mask[] ) 706{ 707 const struct gl_framebuffer *fb = ctx->DrawBuffer; 708 struct gl_renderbuffer *rb = fb->_StencilBuffer; 709 GLubyte fail[MAX_WIDTH]; 710 GLstencil r, s; 711 GLuint i; 712 GLboolean allfail = GL_FALSE; 713 const GLuint valueMask = ctx->Stencil.ValueMask[face]; 714 const GLstencil *stencilStart = (GLstencil *) rb->Data; 715 const GLuint stride = rb->Width; 716 717 ASSERT(rb->GetPointer(ctx, rb, 0, 0)); 718 ASSERT(sizeof(GLstencil) == 1); 719 720 /* 721 * Perform stencil test. The results of this operation are stored 722 * in the fail[] array: 723 * IF fail[i] is non-zero THEN 724 * the stencil fail operator is to be applied 725 * ELSE 726 * the stencil fail operator is not to be applied 727 * ENDIF 728 */ 729 730 switch (ctx->Stencil.Function[face]) { 731 case GL_NEVER: 732 /* always fail */ 733 for (i=0;i<n;i++) { 734 if (mask[i]) { 735 mask[i] = 0; 736 fail[i] = 1; 737 } 738 else { 739 fail[i] = 0; 740 } 741 } 742 allfail = GL_TRUE; 743 break; 744 case GL_LESS: 745 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 746 for (i=0;i<n;i++) { 747 if (mask[i]) { 748 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 749 s = (GLstencil) (*sptr & valueMask); 750 if (r < s) { 751 /* passed */ 752 fail[i] = 0; 753 } 754 else { 755 fail[i] = 1; 756 mask[i] = 0; 757 } 758 } 759 else { 760 fail[i] = 0; 761 } 762 } 763 break; 764 case GL_LEQUAL: 765 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 766 for (i=0;i<n;i++) { 767 if (mask[i]) { 768 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 769 s = (GLstencil) (*sptr & valueMask); 770 if (r <= s) { 771 /* pass */ 772 fail[i] = 0; 773 } 774 else { 775 fail[i] = 1; 776 mask[i] = 0; 777 } 778 } 779 else { 780 fail[i] = 0; 781 } 782 } 783 break; 784 case GL_GREATER: 785 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 786 for (i=0;i<n;i++) { 787 if (mask[i]) { 788 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 789 s = (GLstencil) (*sptr & valueMask); 790 if (r > s) { 791 /* passed */ 792 fail[i] = 0; 793 } 794 else { 795 fail[i] = 1; 796 mask[i] = 0; 797 } 798 } 799 else { 800 fail[i] = 0; 801 } 802 } 803 break; 804 case GL_GEQUAL: 805 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 806 for (i=0;i<n;i++) { 807 if (mask[i]) { 808 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 809 s = (GLstencil) (*sptr & valueMask); 810 if (r >= s) { 811 /* passed */ 812 fail[i] = 0; 813 } 814 else { 815 fail[i] = 1; 816 mask[i] = 0; 817 } 818 } 819 else { 820 fail[i] = 0; 821 } 822 } 823 break; 824 case GL_EQUAL: 825 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 826 for (i=0;i<n;i++) { 827 if (mask[i]) { 828 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 829 s = (GLstencil) (*sptr & valueMask); 830 if (r == s) { 831 /* passed */ 832 fail[i] = 0; 833 } 834 else { 835 fail[i] = 1; 836 mask[i] = 0; 837 } 838 } 839 else { 840 fail[i] = 0; 841 } 842 } 843 break; 844 case GL_NOTEQUAL: 845 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); 846 for (i=0;i<n;i++) { 847 if (mask[i]) { 848 const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); 849 s = (GLstencil) (*sptr & valueMask); 850 if (r != s) { 851 /* passed */ 852 fail[i] = 0; 853 } 854 else { 855 fail[i] = 1; 856 mask[i] = 0; 857 } 858 } 859 else { 860 fail[i] = 0; 861 } 862 } 863 break; 864 case GL_ALWAYS: 865 /* always pass */ 866 for (i=0;i<n;i++) { 867 fail[i] = 0; 868 } 869 break; 870 default: 871 _mesa_problem(ctx, "Bad stencil func in gl_stencil_pixels"); 872 return 0; 873 } 874 875 if (ctx->Stencil.FailFunc[face] != GL_KEEP) { 876 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc[face], 877 face, fail ); 878 } 879 880 return !allfail; 881} 882 883 884 885 886/** 887 * Apply stencil and depth testing to an array of pixels. 888 * This is used both for software and hardware stencil buffers. 889 * 890 * The comments in this function are a bit sparse but the code is 891 * almost identical to stencil_and_ztest_span(), which is well 892 * commented. 893 * 894 * Input: n - number of pixels in the array 895 * x, y - array of [n] pixel positions 896 * z - array [n] of z values 897 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel) 898 * Output: mask - array [n] of flags (1=stencil and depth test passed) 899 * Return: GL_FALSE - all fragments failed the testing 900 * GL_TRUE - one or more fragments passed the testing 901 */ 902static GLboolean 903stencil_and_ztest_pixels( GLcontext *ctx, SWspan *span, GLuint face ) 904{ 905 struct gl_framebuffer *fb = ctx->DrawBuffer; 906 struct gl_renderbuffer *rb = fb->_StencilBuffer; 907 const GLuint n = span->end; 908 const GLint *x = span->array->x; 909 const GLint *y = span->array->y; 910 GLubyte *mask = span->array->mask; 911 912 ASSERT(span->arrayMask & SPAN_XY); 913 ASSERT(ctx->Stencil.Enabled); 914 ASSERT(n <= MAX_WIDTH); 915 916 if (!rb->GetPointer(ctx, rb, 0, 0)) { 917 /* No direct access */ 918 GLstencil stencil[MAX_WIDTH]; 919 GLubyte origMask[MAX_WIDTH]; 920 921 ASSERT(rb->DataType == GL_UNSIGNED_BYTE); 922 _swrast_get_values(ctx, rb, n, x, y, stencil, sizeof(GLubyte)); 923 924 _mesa_memcpy(origMask, mask, n * sizeof(GLubyte)); 925 926 (void) do_stencil_test(ctx, face, n, stencil, mask); 927 928 if (ctx->Depth.Test == GL_FALSE) { 929 apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, 930 n, stencil, mask); 931 } 932 else { 933 _swrast_depth_test_span(ctx, span); 934 935 if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { 936 GLubyte failmask[MAX_WIDTH]; 937 GLuint i; 938 for (i = 0; i < n; i++) { 939 ASSERT(mask[i] == 0 || mask[i] == 1); 940 failmask[i] = origMask[i] & (mask[i] ^ 1); 941 } 942 apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face, 943 n, stencil, failmask); 944 } 945 if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { 946 GLubyte passmask[MAX_WIDTH]; 947 GLuint i; 948 for (i = 0; i < n; i++) { 949 ASSERT(mask[i] == 0 || mask[i] == 1); 950 passmask[i] = origMask[i] & mask[i]; 951 } 952 apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, 953 n, stencil, passmask); 954 } 955 } 956 957 /* Write updated stencil values into hardware stencil buffer */ 958 rb->PutValues(ctx, rb, n, x, y, stencil, origMask); 959 960 return GL_TRUE; 961 } 962 else { 963 /* Direct access to stencil buffer */ 964 965 if (stencil_test_pixels(ctx, face, n, x, y, mask) == GL_FALSE) { 966 /* all fragments failed the stencil test, we're done. */ 967 return GL_FALSE; 968 } 969 970 if (ctx->Depth.Test==GL_FALSE) { 971 apply_stencil_op_to_pixels(ctx, n, x, y, 972 ctx->Stencil.ZPassFunc[face], face, mask); 973 } 974 else { 975 GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH]; 976 GLuint i; 977 978 _mesa_memcpy(oldmask, mask, n * sizeof(GLubyte)); 979 980 _swrast_depth_test_span(ctx, span); 981 982 for (i=0;i<n;i++) { 983 ASSERT(mask[i] == 0 || mask[i] == 1); 984 passmask[i] = oldmask[i] & mask[i]; 985 failmask[i] = oldmask[i] & (mask[i] ^ 1); 986 } 987 988 if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { 989 apply_stencil_op_to_pixels(ctx, n, x, y, 990 ctx->Stencil.ZFailFunc[face], 991 face, failmask); 992 } 993 if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { 994 apply_stencil_op_to_pixels(ctx, n, x, y, 995 ctx->Stencil.ZPassFunc[face], 996 face, passmask); 997 } 998 } 999 1000 return GL_TRUE; /* one or more fragments passed both tests */ 1001 } 1002} 1003 1004 1005/** 1006 * /return GL_TRUE = one or more fragments passed, 1007 * GL_FALSE = all fragments failed. 1008 */ 1009GLboolean 1010_swrast_stencil_and_ztest_span(GLcontext *ctx, SWspan *span) 1011{ 1012 if (span->arrayMask & SPAN_XY) 1013 return stencil_and_ztest_pixels(ctx, span, span->facing); 1014 else 1015 return stencil_and_ztest_span(ctx, span, span->facing); 1016} 1017 1018 1019#if 0 1020GLuint 1021clip_span(GLuint bufferWidth, GLuint bufferHeight, 1022 GLint x, GLint y, GLuint *count) 1023{ 1024 GLuint n = *count; 1025 GLuint skipPixels = 0; 1026 1027 if (y < 0 || y >= bufferHeight || x + n <= 0 || x >= bufferWidth) { 1028 /* totally out of bounds */ 1029 n = 0; 1030 } 1031 else { 1032 /* left clip */ 1033 if (x < 0) { 1034 skipPixels = -x; 1035 x = 0; 1036 n -= skipPixels; 1037 } 1038 /* right clip */ 1039 if (x + n > bufferWidth) { 1040 GLint dx = x + n - bufferWidth; 1041 n -= dx; 1042 } 1043 } 1044 1045 *count = n; 1046 1047 return skipPixels; 1048} 1049#endif 1050 1051 1052/** 1053 * Return a span of stencil values from the stencil buffer. 1054 * Used for glRead/CopyPixels 1055 * Input: n - how many pixels 1056 * x,y - location of first pixel 1057 * Output: stencil - the array of stencil values 1058 */ 1059void 1060_swrast_read_stencil_span(GLcontext *ctx, struct gl_renderbuffer *rb, 1061 GLint n, GLint x, GLint y, GLstencil stencil[]) 1062{ 1063 if (y < 0 || y >= (GLint) rb->Height || 1064 x + n <= 0 || x >= (GLint) rb->Width) { 1065 /* span is completely outside framebuffer */ 1066 return; /* undefined values OK */ 1067 } 1068 1069 if (x < 0) { 1070 GLint dx = -x; 1071 x = 0; 1072 n -= dx; 1073 stencil += dx; 1074 } 1075 if (x + n > (GLint) rb->Width) { 1076 GLint dx = x + n - rb->Width; 1077 n -= dx; 1078 } 1079 if (n <= 0) { 1080 return; 1081 } 1082 1083 rb->GetRow(ctx, rb, n, x, y, stencil); 1084} 1085 1086 1087 1088/** 1089 * Write a span of stencil values to the stencil buffer. This function 1090 * applies the stencil write mask when needed. 1091 * Used for glDraw/CopyPixels 1092 * Input: n - how many pixels 1093 * x, y - location of first pixel 1094 * stencil - the array of stencil values 1095 */ 1096void 1097_swrast_write_stencil_span(GLcontext *ctx, GLint n, GLint x, GLint y, 1098 const GLstencil stencil[] ) 1099{ 1100 struct gl_framebuffer *fb = ctx->DrawBuffer; 1101 struct gl_renderbuffer *rb = fb->_StencilBuffer; 1102 const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1; 1103 const GLuint stencilMask = ctx->Stencil.WriteMask[0]; 1104 1105 if (y < 0 || y >= (GLint) rb->Height || 1106 x + n <= 0 || x >= (GLint) rb->Width) { 1107 /* span is completely outside framebuffer */ 1108 return; /* undefined values OK */ 1109 } 1110 if (x < 0) { 1111 GLint dx = -x; 1112 x = 0; 1113 n -= dx; 1114 stencil += dx; 1115 } 1116 if (x + n > (GLint) rb->Width) { 1117 GLint dx = x + n - rb->Width; 1118 n -= dx; 1119 } 1120 if (n <= 0) { 1121 return; 1122 } 1123 1124 if ((stencilMask & stencilMax) != stencilMax) { 1125 /* need to apply writemask */ 1126 GLstencil destVals[MAX_WIDTH], newVals[MAX_WIDTH]; 1127 GLint i; 1128 rb->GetRow(ctx, rb, n, x, y, destVals); 1129 for (i = 0; i < n; i++) { 1130 newVals[i] 1131 = (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask); 1132 } 1133 rb->PutRow(ctx, rb, n, x, y, newVals, NULL); 1134 } 1135 else { 1136 rb->PutRow(ctx, rb, n, x, y, stencil, NULL); 1137 } 1138} 1139 1140 1141 1142/** 1143 * Clear the stencil buffer. 1144 */ 1145void 1146_swrast_clear_stencil_buffer( GLcontext *ctx, struct gl_renderbuffer *rb ) 1147{ 1148 const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits; 1149 const GLuint mask = ctx->Stencil.WriteMask[0]; 1150 const GLuint invMask = ~mask; 1151 const GLuint clearVal = (ctx->Stencil.Clear & mask); 1152 const GLuint stencilMax = (1 << stencilBits) - 1; 1153 GLint x, y, width, height; 1154 1155 if (!rb || mask == 0) 1156 return; 1157 1158 ASSERT(rb->DataType == GL_UNSIGNED_BYTE || 1159 rb->DataType == GL_UNSIGNED_SHORT); 1160 1161 ASSERT(rb->_BaseFormat == GL_STENCIL_INDEX); 1162 1163 /* compute region to clear */ 1164 x = ctx->DrawBuffer->_Xmin; 1165 y = ctx->DrawBuffer->_Ymin; 1166 width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; 1167 height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; 1168 1169 if (rb->GetPointer(ctx, rb, 0, 0)) { 1170 /* Direct buffer access */ 1171 if ((mask & stencilMax) != stencilMax) { 1172 /* need to mask the clear */ 1173 if (rb->DataType == GL_UNSIGNED_BYTE) { 1174 GLint i, j; 1175 for (i = 0; i < height; i++) { 1176 GLubyte *stencil = (GLubyte*) rb->GetPointer(ctx, rb, x, y + i); 1177 for (j = 0; j < width; j++) { 1178 stencil[j] = (stencil[j] & invMask) | clearVal; 1179 } 1180 } 1181 } 1182 else { 1183 GLint i, j; 1184 for (i = 0; i < height; i++) { 1185 GLushort *stencil = (GLushort*) rb->GetPointer(ctx, rb, x, y + i); 1186 for (j = 0; j < width; j++) { 1187 stencil[j] = (stencil[j] & invMask) | clearVal; 1188 } 1189 } 1190 } 1191 } 1192 else { 1193 /* no bit masking */ 1194 if (width == (GLint) rb->Width && rb->DataType == GL_UNSIGNED_BYTE) { 1195 /* optimized case */ 1196 /* Note: bottom-to-top raster assumed! */ 1197 GLubyte *stencil = (GLubyte *) rb->GetPointer(ctx, rb, x, y); 1198 GLuint len = width * height * sizeof(GLubyte); 1199 _mesa_memset(stencil, clearVal, len); 1200 } 1201 else { 1202 /* general case */ 1203 GLint i; 1204 for (i = 0; i < height; i++) { 1205 GLvoid *stencil = rb->GetPointer(ctx, rb, x, y + i); 1206 if (rb->DataType == GL_UNSIGNED_BYTE) { 1207 _mesa_memset(stencil, clearVal, width); 1208 } 1209 else { 1210 _mesa_memset16((short unsigned int*) stencil, clearVal, width); 1211 } 1212 } 1213 } 1214 } 1215 } 1216 else { 1217 /* no direct access */ 1218 if ((mask & stencilMax) != stencilMax) { 1219 /* need to mask the clear */ 1220 if (rb->DataType == GL_UNSIGNED_BYTE) { 1221 GLint i, j; 1222 for (i = 0; i < height; i++) { 1223 GLubyte stencil[MAX_WIDTH]; 1224 rb->GetRow(ctx, rb, width, x, y + i, stencil); 1225 for (j = 0; j < width; j++) { 1226 stencil[j] = (stencil[j] & invMask) | clearVal; 1227 } 1228 rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL); 1229 } 1230 } 1231 else { 1232 GLint i, j; 1233 for (i = 0; i < height; i++) { 1234 GLushort stencil[MAX_WIDTH]; 1235 rb->GetRow(ctx, rb, width, x, y + i, stencil); 1236 for (j = 0; j < width; j++) { 1237 stencil[j] = (stencil[j] & invMask) | clearVal; 1238 } 1239 rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL); 1240 } 1241 } 1242 } 1243 else { 1244 /* no bit masking */ 1245 const GLubyte clear8 = (GLubyte) clearVal; 1246 const GLushort clear16 = (GLushort) clearVal; 1247 const void *clear; 1248 GLint i; 1249 if (rb->DataType == GL_UNSIGNED_BYTE) { 1250 clear = &clear8; 1251 } 1252 else { 1253 clear = &clear16; 1254 } 1255 for (i = 0; i < height; i++) { 1256 rb->PutMonoRow(ctx, rb, width, x, y + i, clear, NULL); 1257 } 1258 } 1259 } 1260} 1261