s_stencil.c revision 01e04c3f
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26#include "main/glheader.h" 27#include "main/context.h" 28#include "main/imports.h" 29#include "main/format_pack.h" 30#include "main/format_unpack.h" 31#include "main/stencil.h" 32 33#include "s_context.h" 34#include "s_depth.h" 35#include "s_stencil.h" 36#include "s_span.h" 37 38 39 40/* Stencil Logic: 41 42IF stencil test fails THEN 43 Apply fail-op to stencil value 44 Don't write the pixel (RGBA,Z) 45ELSE 46 IF doing depth test && depth test fails THEN 47 Apply zfail-op to stencil value 48 Write RGBA and Z to appropriate buffers 49 ELSE 50 Apply zpass-op to stencil value 51ENDIF 52 53*/ 54 55 56 57/** 58 * Compute/return the offset of the stencil value in a pixel. 59 * For example, if the format is Z24+S8, the position of the stencil bits 60 * within the 4-byte pixel will be either 0 or 3. 61 */ 62static GLint 63get_stencil_offset(mesa_format format) 64{ 65 const GLubyte one = 1; 66 GLubyte pixel[MAX_PIXEL_BYTES]; 67 GLint bpp = _mesa_get_format_bytes(format); 68 GLint i; 69 70 assert(_mesa_get_format_bits(format, GL_STENCIL_BITS) == 8); 71 memset(pixel, 0, sizeof(pixel)); 72 _mesa_pack_ubyte_stencil_row(format, 1, &one, pixel); 73 74 for (i = 0; i < bpp; i++) { 75 if (pixel[i]) 76 return i; 77 } 78 79 _mesa_problem(NULL, "get_stencil_offset() failed\n"); 80 return 0; 81} 82 83 84/** Clamp the stencil value to [0, 255] */ 85static inline GLubyte 86clamp(GLint val) 87{ 88 if (val < 0) 89 return 0; 90 else if (val > 255) 91 return 255; 92 else 93 return val; 94} 95 96 97#define STENCIL_OP(NEW_VAL) \ 98 if (invmask == 0) { \ 99 for (i = j = 0; i < n; i++, j += stride) { \ 100 if (mask[i]) { \ 101 GLubyte s = stencil[j]; \ 102 (void) s; \ 103 stencil[j] = (GLubyte) (NEW_VAL); \ 104 } \ 105 } \ 106 } \ 107 else { \ 108 for (i = j = 0; i < n; i++, j += stride) { \ 109 if (mask[i]) { \ 110 GLubyte s = stencil[j]; \ 111 stencil[j] = (GLubyte) ((invmask & s) | (wrtmask & (NEW_VAL))); \ 112 } \ 113 } \ 114 } 115 116 117/** 118 * Apply the given stencil operator to the array of stencil values. 119 * Don't touch stencil[i] if mask[i] is zero. 120 * @param n number of stencil values 121 * @param oper the stencil buffer operator 122 * @param face 0 or 1 for front or back face operation 123 * @param stencil array of stencil values (in/out) 124 * @param mask array [n] of flag: 1=apply operator, 0=don't apply operator 125 * @param stride stride between stencil values 126 */ 127static void 128apply_stencil_op(const struct gl_context *ctx, GLenum oper, GLuint face, 129 GLuint n, GLubyte stencil[], const GLubyte mask[], 130 GLint stride) 131{ 132 const GLubyte ref = _mesa_get_stencil_ref(ctx, face); 133 const GLubyte wrtmask = ctx->Stencil.WriteMask[face]; 134 const GLubyte invmask = (GLubyte) (~wrtmask); 135 GLuint i, j; 136 137 switch (oper) { 138 case GL_KEEP: 139 /* do nothing */ 140 break; 141 case GL_ZERO: 142 /* replace stencil buf values with zero */ 143 STENCIL_OP(0); 144 break; 145 case GL_REPLACE: 146 /* replace stencil buf values with ref value */ 147 STENCIL_OP(ref); 148 break; 149 case GL_INCR: 150 /* increment stencil buf values, with clamping */ 151 STENCIL_OP(clamp(s + 1)); 152 break; 153 case GL_DECR: 154 /* increment stencil buf values, with clamping */ 155 STENCIL_OP(clamp(s - 1)); 156 break; 157 case GL_INCR_WRAP_EXT: 158 /* increment stencil buf values, without clamping */ 159 STENCIL_OP(s + 1); 160 break; 161 case GL_DECR_WRAP_EXT: 162 /* increment stencil buf values, without clamping */ 163 STENCIL_OP(s - 1); 164 break; 165 case GL_INVERT: 166 /* replace stencil buf values with inverted value */ 167 STENCIL_OP(~s); 168 break; 169 default: 170 _mesa_problem(ctx, "Bad stencil op in apply_stencil_op"); 171 } 172} 173 174 175 176#define STENCIL_TEST(FUNC) \ 177 for (i = j = 0; i < n; i++, j += stride) { \ 178 if (mask[i]) { \ 179 s = (GLubyte) (stencil[j] & valueMask); \ 180 if (FUNC) { \ 181 /* stencil pass */ \ 182 fail[i] = 0; \ 183 } \ 184 else { \ 185 /* stencil fail */ \ 186 fail[i] = 1; \ 187 mask[i] = 0; \ 188 } \ 189 } \ 190 else { \ 191 fail[i] = 0; \ 192 } \ 193 } 194 195 196 197/** 198 * Apply stencil test to an array of stencil values (before depth buffering). 199 * For the values that fail, we'll apply the GL_STENCIL_FAIL operator to 200 * the stencil values. 201 * 202 * @param face 0 or 1 for front or back-face polygons 203 * @param n number of pixels in the array 204 * @param stencil array of [n] stencil values (in/out) 205 * @param mask array [n] of flag: 0=skip the pixel, 1=stencil the pixel, 206 * values are set to zero where the stencil test fails. 207 * @param stride stride between stencil values 208 * @return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed. 209 */ 210static GLboolean 211do_stencil_test(struct gl_context *ctx, GLuint face, GLuint n, 212 GLubyte stencil[], GLubyte mask[], GLint stride) 213{ 214 SWcontext *swrast = SWRAST_CONTEXT(ctx); 215 GLubyte *fail = swrast->stencil_temp.buf2; 216 GLboolean allfail = GL_FALSE; 217 GLuint i, j; 218 const GLuint valueMask = ctx->Stencil.ValueMask[face]; 219 const GLubyte ref = (GLubyte) (_mesa_get_stencil_ref(ctx, face) & valueMask); 220 GLubyte s; 221 222 /* 223 * Perform stencil test. The results of this operation are stored 224 * in the fail[] array: 225 * IF fail[i] is non-zero THEN 226 * the stencil fail operator is to be applied 227 * ELSE 228 * the stencil fail operator is not to be applied 229 * ENDIF 230 */ 231 switch (ctx->Stencil.Function[face]) { 232 case GL_NEVER: 233 STENCIL_TEST(0); 234 allfail = GL_TRUE; 235 break; 236 case GL_LESS: 237 STENCIL_TEST(ref < s); 238 break; 239 case GL_LEQUAL: 240 STENCIL_TEST(ref <= s); 241 break; 242 case GL_GREATER: 243 STENCIL_TEST(ref > s); 244 break; 245 case GL_GEQUAL: 246 STENCIL_TEST(ref >= s); 247 break; 248 case GL_EQUAL: 249 STENCIL_TEST(ref == s); 250 break; 251 case GL_NOTEQUAL: 252 STENCIL_TEST(ref != s); 253 break; 254 case GL_ALWAYS: 255 STENCIL_TEST(1); 256 break; 257 default: 258 _mesa_problem(ctx, "Bad stencil func in gl_stencil_span"); 259 return 0; 260 } 261 262 if (ctx->Stencil.FailFunc[face] != GL_KEEP) { 263 apply_stencil_op(ctx, ctx->Stencil.FailFunc[face], face, n, stencil, 264 fail, stride); 265 } 266 267 return !allfail; 268} 269 270 271/** 272 * Compute the zpass/zfail masks by comparing the pre- and post-depth test 273 * masks. 274 */ 275static inline void 276compute_pass_fail_masks(GLuint n, const GLubyte origMask[], 277 const GLubyte newMask[], 278 GLubyte passMask[], GLubyte failMask[]) 279{ 280 GLuint i; 281 for (i = 0; i < n; i++) { 282 assert(newMask[i] == 0 || newMask[i] == 1); 283 passMask[i] = origMask[i] & newMask[i]; 284 failMask[i] = origMask[i] & (newMask[i] ^ 1); 285 } 286} 287 288 289/** 290 * Get 8-bit stencil values from random locations in the stencil buffer. 291 */ 292static void 293get_s8_values(struct gl_context *ctx, struct gl_renderbuffer *rb, 294 GLuint count, const GLint x[], const GLint y[], 295 GLubyte stencil[]) 296{ 297 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 298 const GLint w = rb->Width, h = rb->Height; 299 const GLubyte *map = _swrast_pixel_address(rb, 0, 0); 300 GLuint i; 301 302 if (rb->Format == MESA_FORMAT_S_UINT8) { 303 const GLint rowStride = srb->RowStride; 304 for (i = 0; i < count; i++) { 305 if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { 306 stencil[i] = *(map + y[i] * rowStride + x[i]); 307 } 308 } 309 } 310 else { 311 const GLint bpp = _mesa_get_format_bytes(rb->Format); 312 const GLint rowStride = srb->RowStride; 313 for (i = 0; i < count; i++) { 314 if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { 315 const GLubyte *src = map + y[i] * rowStride + x[i] * bpp; 316 _mesa_unpack_ubyte_stencil_row(rb->Format, 1, src, &stencil[i]); 317 } 318 } 319 } 320} 321 322 323/** 324 * Put 8-bit stencil values at random locations into the stencil buffer. 325 */ 326static void 327put_s8_values(struct gl_context *ctx, struct gl_renderbuffer *rb, 328 GLuint count, const GLint x[], const GLint y[], 329 const GLubyte stencil[]) 330{ 331 const GLint w = rb->Width, h = rb->Height; 332 gl_pack_ubyte_stencil_func pack_stencil = 333 _mesa_get_pack_ubyte_stencil_func(rb->Format); 334 GLuint i; 335 336 for (i = 0; i < count; i++) { 337 if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { 338 GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]); 339 pack_stencil(&stencil[i], dst); 340 } 341 } 342} 343 344 345/** 346 * /return GL_TRUE = one or more fragments passed, 347 * GL_FALSE = all fragments failed. 348 */ 349GLboolean 350_swrast_stencil_and_ztest_span(struct gl_context *ctx, SWspan *span) 351{ 352 SWcontext *swrast = SWRAST_CONTEXT(ctx); 353 struct gl_framebuffer *fb = ctx->DrawBuffer; 354 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 355 const GLint stencilOffset = get_stencil_offset(rb->Format); 356 const GLint stencilStride = _mesa_get_format_bytes(rb->Format); 357 const GLuint face = (span->facing == 0) ? 0 : ctx->Stencil._BackFace; 358 const GLuint count = span->end; 359 GLubyte *mask = span->array->mask; 360 GLubyte *stencilTemp = swrast->stencil_temp.buf1; 361 GLubyte *stencilBuf; 362 363 if (span->arrayMask & SPAN_XY) { 364 /* read stencil values from random locations */ 365 get_s8_values(ctx, rb, count, span->array->x, span->array->y, 366 stencilTemp); 367 stencilBuf = stencilTemp; 368 } 369 else { 370 /* Processing a horizontal run of pixels. Since stencil is always 371 * 8 bits for all MESA_FORMATs, we just need to use the right offset 372 * and stride to access them. 373 */ 374 stencilBuf = _swrast_pixel_address(rb, span->x, span->y) + stencilOffset; 375 } 376 377 /* 378 * Apply the stencil test to the fragments. 379 * failMask[i] is 1 if the stencil test failed. 380 */ 381 if (!do_stencil_test(ctx, face, count, stencilBuf, mask, stencilStride)) { 382 /* all fragments failed the stencil test, we're done. */ 383 span->writeAll = GL_FALSE; 384 if (span->arrayMask & SPAN_XY) { 385 /* need to write the updated stencil values back to the buffer */ 386 put_s8_values(ctx, rb, count, span->array->x, span->array->y, 387 stencilTemp); 388 } 389 return GL_FALSE; 390 } 391 392 /* 393 * Some fragments passed the stencil test, apply depth test to them 394 * and apply Zpass and Zfail stencil ops. 395 */ 396 if (ctx->Depth.Test == GL_FALSE || 397 ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer == NULL) { 398 /* 399 * No depth buffer, just apply zpass stencil function to active pixels. 400 */ 401 apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, count, 402 stencilBuf, mask, stencilStride); 403 } 404 else { 405 /* 406 * Perform depth buffering, then apply zpass or zfail stencil function. 407 */ 408 SWcontext *swrast = SWRAST_CONTEXT(ctx); 409 GLubyte *passMask = swrast->stencil_temp.buf2; 410 GLubyte *failMask = swrast->stencil_temp.buf3; 411 GLubyte *origMask = swrast->stencil_temp.buf4; 412 413 /* save the current mask bits */ 414 memcpy(origMask, mask, count * sizeof(GLubyte)); 415 416 /* apply the depth test */ 417 _swrast_depth_test_span(ctx, span); 418 419 compute_pass_fail_masks(count, origMask, mask, passMask, failMask); 420 421 /* apply the pass and fail operations */ 422 if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { 423 apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face, 424 count, stencilBuf, failMask, stencilStride); 425 } 426 if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { 427 apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, 428 count, stencilBuf, passMask, stencilStride); 429 } 430 } 431 432 /* Write updated stencil values back into hardware stencil buffer */ 433 if (span->arrayMask & SPAN_XY) { 434 put_s8_values(ctx, rb, count, span->array->x, span->array->y, 435 stencilBuf); 436 } 437 438 span->writeAll = GL_FALSE; 439 440 return GL_TRUE; /* one or more fragments passed both tests */ 441} 442 443 444 445 446/** 447 * Return a span of stencil values from the stencil buffer. 448 * Used for glRead/CopyPixels 449 * Input: n - how many pixels 450 * x,y - location of first pixel 451 * Output: stencil - the array of stencil values 452 */ 453void 454_swrast_read_stencil_span(struct gl_context *ctx, struct gl_renderbuffer *rb, 455 GLint n, GLint x, GLint y, GLubyte stencil[]) 456{ 457 GLubyte *src; 458 459 if (y < 0 || y >= (GLint) rb->Height || 460 x + n <= 0 || x >= (GLint) rb->Width) { 461 /* span is completely outside framebuffer */ 462 return; /* undefined values OK */ 463 } 464 465 if (x < 0) { 466 GLint dx = -x; 467 x = 0; 468 n -= dx; 469 stencil += dx; 470 } 471 if (x + n > (GLint) rb->Width) { 472 GLint dx = x + n - rb->Width; 473 n -= dx; 474 } 475 if (n <= 0) { 476 return; 477 } 478 479 src = _swrast_pixel_address(rb, x, y); 480 _mesa_unpack_ubyte_stencil_row(rb->Format, n, src, stencil); 481} 482 483 484 485/** 486 * Write a span of stencil values to the stencil buffer. This function 487 * applies the stencil write mask when needed. 488 * Used for glDraw/CopyPixels 489 * Input: n - how many pixels 490 * x, y - location of first pixel 491 * stencil - the array of stencil values 492 */ 493void 494_swrast_write_stencil_span(struct gl_context *ctx, GLint n, GLint x, GLint y, 495 const GLubyte stencil[] ) 496{ 497 SWcontext *swrast = SWRAST_CONTEXT(ctx); 498 struct gl_framebuffer *fb = ctx->DrawBuffer; 499 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 500 const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1; 501 const GLuint stencilMask = ctx->Stencil.WriteMask[0]; 502 GLubyte *stencilBuf; 503 504 if (y < 0 || y >= (GLint) rb->Height || 505 x + n <= 0 || x >= (GLint) rb->Width) { 506 /* span is completely outside framebuffer */ 507 return; /* undefined values OK */ 508 } 509 if (x < 0) { 510 GLint dx = -x; 511 x = 0; 512 n -= dx; 513 stencil += dx; 514 } 515 if (x + n > (GLint) rb->Width) { 516 GLint dx = x + n - rb->Width; 517 n -= dx; 518 } 519 if (n <= 0) { 520 return; 521 } 522 523 stencilBuf = _swrast_pixel_address(rb, x, y); 524 525 if ((stencilMask & stencilMax) != stencilMax) { 526 /* need to apply writemask */ 527 GLubyte *destVals = swrast->stencil_temp.buf1; 528 GLubyte *newVals = swrast->stencil_temp.buf2; 529 GLint i; 530 531 _mesa_unpack_ubyte_stencil_row(rb->Format, n, stencilBuf, destVals); 532 for (i = 0; i < n; i++) { 533 newVals[i] 534 = (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask); 535 } 536 _mesa_pack_ubyte_stencil_row(rb->Format, n, newVals, stencilBuf); 537 } 538 else { 539 _mesa_pack_ubyte_stencil_row(rb->Format, n, stencil, stencilBuf); 540 } 541} 542 543 544 545/** 546 * Clear the stencil buffer. If the buffer is a combined 547 * depth+stencil buffer, only the stencil bits will be touched. 548 */ 549void 550_swrast_clear_stencil_buffer(struct gl_context *ctx) 551{ 552 struct gl_renderbuffer *rb = 553 ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; 554 const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits; 555 const GLuint writeMask = ctx->Stencil.WriteMask[0]; 556 const GLuint stencilMax = (1 << stencilBits) - 1; 557 GLint x, y, width, height; 558 GLubyte *map; 559 GLint rowStride, i, j; 560 GLbitfield mapMode; 561 562 if (!rb || writeMask == 0) 563 return; 564 565 /* compute region to clear */ 566 x = ctx->DrawBuffer->_Xmin; 567 y = ctx->DrawBuffer->_Ymin; 568 width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; 569 height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; 570 571 mapMode = GL_MAP_WRITE_BIT; 572 if ((writeMask & stencilMax) != stencilMax) { 573 /* need to mask stencil values */ 574 mapMode |= GL_MAP_READ_BIT; 575 } 576 else if (_mesa_get_format_bits(rb->Format, GL_DEPTH_BITS) > 0) { 577 /* combined depth+stencil, need to mask Z values */ 578 mapMode |= GL_MAP_READ_BIT; 579 } 580 581 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, 582 mapMode, &map, &rowStride, 583 ctx->DrawBuffer->FlipY); 584 if (!map) { 585 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(stencil)"); 586 return; 587 } 588 589 switch (rb->Format) { 590 case MESA_FORMAT_S_UINT8: 591 { 592 GLubyte clear = ctx->Stencil.Clear & writeMask & 0xff; 593 GLubyte mask = (~writeMask) & 0xff; 594 if (mask != 0) { 595 /* masked clear */ 596 for (i = 0; i < height; i++) { 597 GLubyte *row = map; 598 for (j = 0; j < width; j++) { 599 row[j] = (row[j] & mask) | clear; 600 } 601 map += rowStride; 602 } 603 } 604 else if (rowStride == width) { 605 /* clear whole buffer */ 606 memset(map, clear, width * height); 607 } 608 else { 609 /* clear scissored */ 610 for (i = 0; i < height; i++) { 611 memset(map, clear, width); 612 map += rowStride; 613 } 614 } 615 } 616 break; 617 case MESA_FORMAT_Z24_UNORM_S8_UINT: 618 { 619 GLuint clear = (ctx->Stencil.Clear & writeMask & 0xff) << 24; 620 GLuint mask = (((~writeMask) & 0xff) << 24) | 0xffffff; 621 for (i = 0; i < height; i++) { 622 GLuint *row = (GLuint *) map; 623 for (j = 0; j < width; j++) { 624 row[j] = (row[j] & mask) | clear; 625 } 626 map += rowStride; 627 } 628 } 629 break; 630 case MESA_FORMAT_S8_UINT_Z24_UNORM: 631 { 632 GLuint clear = ctx->Stencil.Clear & writeMask & 0xff; 633 GLuint mask = 0xffffff00 | ((~writeMask) & 0xff); 634 for (i = 0; i < height; i++) { 635 GLuint *row = (GLuint *) map; 636 for (j = 0; j < width; j++) { 637 row[j] = (row[j] & mask) | clear; 638 } 639 map += rowStride; 640 } 641 } 642 break; 643 default: 644 _mesa_problem(ctx, "Unexpected stencil buffer format %s" 645 " in _swrast_clear_stencil_buffer()", 646 _mesa_get_format_name(rb->Format)); 647 } 648 649 ctx->Driver.UnmapRenderbuffer(ctx, rb); 650} 651