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