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