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
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
42 IF stencil test fails THEN
43 Apply fail-op to stencil value
44 Don't write the pixel (RGBA,Z)
45 ELSE
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
51 ENDIF
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 */
62 static GLint
get_stencil_offset(mesa_format format)63 get_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] */
85 static inline GLubyte
clamp(GLint val)86 clamp(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 */
127 static void
apply_stencil_op(const struct gl_context * ctx,GLenum oper,GLuint face,GLuint n,GLubyte stencil[],const GLubyte mask[],GLint stride)128 apply_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 */
210 static GLboolean
do_stencil_test(struct gl_context * ctx,GLuint face,GLuint n,GLubyte stencil[],GLubyte mask[],GLint stride)211 do_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 */
275 static inline void
compute_pass_fail_masks(GLuint n,const GLubyte origMask[],const GLubyte newMask[],GLubyte passMask[],GLubyte failMask[])276 compute_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 */
292 static void
get_s8_values(struct gl_context * ctx,struct gl_renderbuffer * rb,GLuint count,const GLint x[],const GLint y[],GLubyte stencil[])293 get_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 */
326 static void
put_s8_values(struct gl_context * ctx,struct gl_renderbuffer * rb,GLuint count,const GLint x[],const GLint y[],const GLubyte stencil[])327 put_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 mesa_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 */
349 GLboolean
_swrast_stencil_and_ztest_span(struct gl_context * ctx,SWspan * span)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 */
453 void
_swrast_read_stencil_span(struct gl_context * ctx,struct gl_renderbuffer * rb,GLint n,GLint x,GLint y,GLubyte stencil[])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 */
493 void
_swrast_write_stencil_span(struct gl_context * ctx,GLint n,GLint x,GLint y,const GLubyte stencil[])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 */
549 void
_swrast_clear_stencil_buffer(struct gl_context * ctx)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