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
43 IF stencil test fails THEN
44 Apply fail-op to stencil value
45 Don't write the pixel (RGBA,Z)
46 ELSE
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
52 ENDIF
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 */
63 static GLint
get_stencil_offset(mesa_format format)64 get_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] */
86 static inline GLubyte
clamp(GLint val)87 clamp(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 */
128 static void
apply_stencil_op(const struct gl_context * ctx,GLenum oper,GLuint face,GLuint n,GLubyte stencil[],const GLubyte mask[],GLint stride)129 apply_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 */
211 static GLboolean
do_stencil_test(struct gl_context * ctx,GLuint face,GLuint n,GLubyte stencil[],GLubyte mask[],GLint stride)212 do_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 */
276 static inline void
compute_pass_fail_masks(GLuint n,const GLubyte origMask[],const GLubyte newMask[],GLubyte passMask[],GLubyte failMask[])277 compute_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 */
293 static void
get_s8_values(struct gl_context * ctx,struct gl_renderbuffer * rb,GLuint count,const GLint x[],const GLint y[],GLubyte stencil[])294 get_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 */
327 static void
put_s8_values(struct gl_context * ctx,struct gl_renderbuffer * rb,GLuint count,const GLint x[],const GLint y[],const GLubyte stencil[])328 put_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 */
350 GLboolean
_swrast_stencil_and_ztest_span(struct gl_context * ctx,SWspan * span)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 */
454 void
_swrast_read_stencil_span(struct gl_context * ctx,struct gl_renderbuffer * rb,GLint n,GLint x,GLint y,GLubyte stencil[])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 */
494 void
_swrast_write_stencil_span(struct gl_context * ctx,GLint n,GLint x,GLint y,const GLubyte stencil[])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 */
550 void
_swrast_clear_stencil_buffer(struct gl_context * ctx)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