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