renamed stencil functions
[mesa.git] / src / mesa / main / stencil.c
1 /* $Id: stencil.c,v 1.16 2000/04/11 21:26:57 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.3
6 *
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 #ifdef PC_HEADER
29 #include "all.h"
30 #else
31 #include "glheader.h"
32 #include "context.h"
33 #include "depth.h"
34 #include "mem.h"
35 #include "pb.h"
36 #include "stencil.h"
37 #include "types.h"
38 #include "enable.h"
39 #endif
40
41
42
43
44 void
45 _mesa_ClearStencil( GLint s )
46 {
47 GET_CURRENT_CONTEXT(ctx);
48 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearStencil");
49 ctx->Stencil.Clear = (GLstencil) s;
50
51 if (ctx->Driver.ClearStencil) {
52 (*ctx->Driver.ClearStencil)( ctx, s );
53 }
54 }
55
56
57
58 void
59 _mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
60 {
61 GET_CURRENT_CONTEXT(ctx);
62 GLint maxref;
63
64 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilFunc");
65
66 switch (func) {
67 case GL_NEVER:
68 case GL_LESS:
69 case GL_LEQUAL:
70 case GL_GREATER:
71 case GL_GEQUAL:
72 case GL_EQUAL:
73 case GL_NOTEQUAL:
74 case GL_ALWAYS:
75 ctx->Stencil.Function = func;
76 break;
77 default:
78 gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" );
79 return;
80 }
81
82 maxref = (1 << STENCIL_BITS) - 1;
83 ctx->Stencil.Ref = (GLstencil) CLAMP( ref, 0, maxref );
84 ctx->Stencil.ValueMask = (GLstencil) mask;
85
86 if (ctx->Driver.StencilFunc) {
87 (*ctx->Driver.StencilFunc)( ctx, func, ctx->Stencil.Ref, mask );
88 }
89 }
90
91
92
93 void
94 _mesa_StencilMask( GLuint mask )
95 {
96 GET_CURRENT_CONTEXT(ctx);
97 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilMask");
98 ctx->Stencil.WriteMask = (GLstencil) mask;
99
100 if (ctx->Driver.StencilMask) {
101 (*ctx->Driver.StencilMask)( ctx, mask );
102 }
103 }
104
105
106
107 void
108 _mesa_StencilOp( GLenum fail, GLenum zfail, GLenum zpass )
109 {
110 GET_CURRENT_CONTEXT(ctx);
111 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilOp");
112 switch (fail) {
113 case GL_KEEP:
114 case GL_ZERO:
115 case GL_REPLACE:
116 case GL_INCR:
117 case GL_DECR:
118 case GL_INVERT:
119 case GL_INCR_WRAP_EXT:
120 case GL_DECR_WRAP_EXT:
121 ctx->Stencil.FailFunc = fail;
122 break;
123 default:
124 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
125 return;
126 }
127 switch (zfail) {
128 case GL_KEEP:
129 case GL_ZERO:
130 case GL_REPLACE:
131 case GL_INCR:
132 case GL_DECR:
133 case GL_INVERT:
134 case GL_INCR_WRAP_EXT:
135 case GL_DECR_WRAP_EXT:
136 ctx->Stencil.ZFailFunc = zfail;
137 break;
138 default:
139 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
140 return;
141 }
142 switch (zpass) {
143 case GL_KEEP:
144 case GL_ZERO:
145 case GL_REPLACE:
146 case GL_INCR:
147 case GL_DECR:
148 case GL_INVERT:
149 case GL_INCR_WRAP_EXT:
150 case GL_DECR_WRAP_EXT:
151 ctx->Stencil.ZPassFunc = zpass;
152 break;
153 default:
154 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
155 return;
156 }
157
158 if (ctx->Driver.StencilOp) {
159 (*ctx->Driver.StencilOp)( ctx, fail, zfail, zpass );
160 }
161 }
162
163
164
165 /* Stencil Logic:
166
167 IF stencil test fails THEN
168 Apply fail-op to stencil value
169 Don't write the pixel (RGBA,Z)
170 ELSE
171 IF doing depth test && depth test fails THEN
172 Apply zfail-op to stencil value
173 Write RGBA and Z to appropriate buffers
174 ELSE
175 Apply zpass-op to stencil value
176 ENDIF
177
178 */
179
180
181
182
183 /*
184 * Return the address of a stencil buffer value given the window coords:
185 */
186 #define STENCIL_ADDRESS(X,Y) \
187 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
188
189
190
191 /*
192 * Apply the given stencil operator to the array of stencil values.
193 * Don't touch stencil[i] if mask[i] is zero.
194 * Input: n - size of stencil array
195 * oper - the stencil buffer operator
196 * stencil - array of stencil values
197 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
198 * Output: stencil - modified values
199 */
200 static void apply_stencil_op( const GLcontext *ctx, GLenum oper,
201 GLuint n, GLstencil stencil[],
202 const GLubyte mask[] )
203 {
204 const GLstencil ref = ctx->Stencil.Ref;
205 const GLstencil wrtmask = ctx->Stencil.WriteMask;
206 const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
207 GLuint i;
208
209 switch (oper) {
210 case GL_KEEP:
211 /* do nothing */
212 break;
213 case GL_ZERO:
214 if (invmask==0) {
215 for (i=0;i<n;i++) {
216 if (mask[i]) {
217 stencil[i] = 0;
218 }
219 }
220 }
221 else {
222 for (i=0;i<n;i++) {
223 if (mask[i]) {
224 stencil[i] = (GLstencil) (stencil[i] & invmask);
225 }
226 }
227 }
228 break;
229 case GL_REPLACE:
230 if (invmask==0) {
231 for (i=0;i<n;i++) {
232 if (mask[i]) {
233 stencil[i] = ref;
234 }
235 }
236 }
237 else {
238 for (i=0;i<n;i++) {
239 if (mask[i]) {
240 GLstencil s = stencil[i];
241 stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref));
242 }
243 }
244 }
245 break;
246 case GL_INCR:
247 if (invmask==0) {
248 for (i=0;i<n;i++) {
249 if (mask[i]) {
250 GLstencil s = stencil[i];
251 if (s < STENCIL_MAX) {
252 stencil[i] = (GLstencil) (s+1);
253 }
254 }
255 }
256 }
257 else {
258 for (i=0;i<n;i++) {
259 if (mask[i]) {
260 /* VERIFY logic of adding 1 to a write-masked value */
261 GLstencil s = stencil[i];
262 if (s < STENCIL_MAX) {
263 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
264 }
265 }
266 }
267 }
268 break;
269 case GL_DECR:
270 if (invmask==0) {
271 for (i=0;i<n;i++) {
272 if (mask[i]) {
273 GLstencil s = stencil[i];
274 if (s>0) {
275 stencil[i] = (GLstencil) (s-1);
276 }
277 }
278 }
279 }
280 else {
281 for (i=0;i<n;i++) {
282 if (mask[i]) {
283 /* VERIFY logic of subtracting 1 to a write-masked value */
284 GLstencil s = stencil[i];
285 if (s>0) {
286 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
287 }
288 }
289 }
290 }
291 break;
292 case GL_INCR_WRAP_EXT:
293 if (invmask==0) {
294 for (i=0;i<n;i++) {
295 if (mask[i]) {
296 stencil[i]++;
297 }
298 }
299 }
300 else {
301 for (i=0;i<n;i++) {
302 if (mask[i]) {
303 GLstencil s = stencil[i];
304 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
305 }
306 }
307 }
308 break;
309 case GL_DECR_WRAP_EXT:
310 if (invmask==0) {
311 for (i=0;i<n;i++) {
312 if (mask[i]) {
313 stencil[i]--;
314 }
315 }
316 }
317 else {
318 for (i=0;i<n;i++) {
319 if (mask[i]) {
320 GLstencil s = stencil[i];
321 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
322 }
323 }
324 }
325 break;
326 case GL_INVERT:
327 if (invmask==0) {
328 for (i=0;i<n;i++) {
329 if (mask[i]) {
330 GLstencil s = stencil[i];
331 stencil[i] = (GLstencil) ~s;
332 }
333 }
334 }
335 else {
336 for (i=0;i<n;i++) {
337 if (mask[i]) {
338 GLstencil s = stencil[i];
339 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s));
340 }
341 }
342 }
343 break;
344 default:
345 gl_problem(ctx, "Bad stencil op in apply_stencil_op");
346 }
347 }
348
349
350
351
352 /*
353 * Apply stencil test to an array of stencil values (before depth buffering).
354 * Input: n - number of pixels in the array
355 * stencil - array of [n] stencil values
356 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
357 * Output: mask - pixels which fail the stencil test will have their
358 * mask flag set to 0.
359 * stencil - updated stencil values (where the test passed)
360 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
361 */
362 static GLboolean
363 do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[],
364 GLubyte mask[] )
365 {
366 GLubyte fail[PB_SIZE];
367 GLboolean allfail = GL_FALSE;
368 GLuint i;
369 GLstencil r, s;
370
371 ASSERT(n <= PB_SIZE);
372
373 /*
374 * Perform stencil test. The results of this operation are stored
375 * in the fail[] array:
376 * IF fail[i] is non-zero THEN
377 * the stencil fail operator is to be applied
378 * ELSE
379 * the stencil fail operator is not to be applied
380 * ENDIF
381 */
382 switch (ctx->Stencil.Function) {
383 case GL_NEVER:
384 /* always fail */
385 for (i=0;i<n;i++) {
386 if (mask[i]) {
387 mask[i] = 0;
388 fail[i] = 1;
389 }
390 else {
391 fail[i] = 0;
392 }
393 }
394 allfail = GL_TRUE;
395 break;
396 case GL_LESS:
397 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
398 for (i=0;i<n;i++) {
399 if (mask[i]) {
400 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
401 if (r < s) {
402 /* passed */
403 fail[i] = 0;
404 }
405 else {
406 fail[i] = 1;
407 mask[i] = 0;
408 }
409 }
410 else {
411 fail[i] = 0;
412 }
413 }
414 break;
415 case GL_LEQUAL:
416 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
417 for (i=0;i<n;i++) {
418 if (mask[i]) {
419 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
420 if (r <= s) {
421 /* pass */
422 fail[i] = 0;
423 }
424 else {
425 fail[i] = 1;
426 mask[i] = 0;
427 }
428 }
429 else {
430 fail[i] = 0;
431 }
432 }
433 break;
434 case GL_GREATER:
435 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
436 for (i=0;i<n;i++) {
437 if (mask[i]) {
438 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
439 if (r > s) {
440 /* passed */
441 fail[i] = 0;
442 }
443 else {
444 fail[i] = 1;
445 mask[i] = 0;
446 }
447 }
448 else {
449 fail[i] = 0;
450 }
451 }
452 break;
453 case GL_GEQUAL:
454 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
455 for (i=0;i<n;i++) {
456 if (mask[i]) {
457 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
458 if (r >= s) {
459 /* passed */
460 fail[i] = 0;
461 }
462 else {
463 fail[i] = 1;
464 mask[i] = 0;
465 }
466 }
467 else {
468 fail[i] = 0;
469 }
470 }
471 break;
472 case GL_EQUAL:
473 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
474 for (i=0;i<n;i++) {
475 if (mask[i]) {
476 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
477 if (r == s) {
478 /* passed */
479 fail[i] = 0;
480 }
481 else {
482 fail[i] = 1;
483 mask[i] = 0;
484 }
485 }
486 else {
487 fail[i] = 0;
488 }
489 }
490 break;
491 case GL_NOTEQUAL:
492 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
493 for (i=0;i<n;i++) {
494 if (mask[i]) {
495 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
496 if (r != s) {
497 /* passed */
498 fail[i] = 0;
499 }
500 else {
501 fail[i] = 1;
502 mask[i] = 0;
503 }
504 }
505 else {
506 fail[i] = 0;
507 }
508 }
509 break;
510 case GL_ALWAYS:
511 /* always pass */
512 for (i=0;i<n;i++) {
513 fail[i] = 0;
514 }
515 break;
516 default:
517 gl_problem(ctx, "Bad stencil func in gl_stencil_span");
518 return 0;
519 }
520
521 if (ctx->Stencil.FailFunc != GL_KEEP) {
522 apply_stencil_op( ctx, ctx->Stencil.FailFunc, n, stencil, fail );
523 }
524
525 return !allfail;
526 }
527
528
529
530
531 /*
532 * Apply stencil and depth testing to an array of pixels.
533 * Hardware or software stencil buffer acceptable.
534 * Input: n - number of pixels in the span
535 * z - array [n] of z values
536 * stencil - array [n] of stencil values
537 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
538 * Output: stencil - modified stencil values
539 * mask - array [n] of flags (1=stencil and depth test passed)
540 * Return: GL_TRUE - all fragments failed the testing
541 * GL_FALSE - one or more fragments passed the testing
542 *
543 */
544 static GLboolean
545 stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
546 const GLdepth z[], GLstencil stencil[],
547 GLubyte mask[] )
548 {
549 ASSERT(ctx->Stencil.Enabled);
550 ASSERT(n <= PB_SIZE);
551
552 /*
553 * Apply the stencil test to the fragments.
554 * failMask[i] is 1 if the stencil test failed.
555 */
556 if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) {
557 /* all fragments failed the stencil test, we're done. */
558 return GL_FALSE;
559 }
560
561
562 /*
563 * Some fragments passed the stencil test, apply depth test to them
564 * and apply Zpass and Zfail stencil ops.
565 */
566 if (ctx->Depth.Test==GL_FALSE) {
567 /*
568 * No depth buffer, just apply zpass stencil function to active pixels.
569 */
570 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
571 }
572 else {
573 /*
574 * Perform depth buffering, then apply zpass or zfail stencil function.
575 */
576 GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
577 GLuint i;
578
579 /* save the current mask bits */
580 MEMCPY(oldmask, mask, n * sizeof(GLubyte));
581
582 /* apply the depth test */
583 _mesa_depth_test_span(ctx, n, x, y, z, mask);
584
585 /* Set the stencil pass/fail flags according to result of depth testing.
586 * if oldmask[i] == 0 then
587 * Don't touch the stencil value
588 * else if oldmask[i] and newmask[i] then
589 * Depth test passed
590 * else
591 * assert(oldmask[i] && !newmask[i])
592 * Depth test failed
593 * endif
594 */
595 for (i=0;i<n;i++) {
596 ASSERT(mask[i] == 0 || mask[i] == 1);
597 passmask[i] = oldmask[i] & mask[i];
598 failmask[i] = oldmask[i] & (mask[i] ^ 1);
599 }
600
601 /* apply the pass and fail operations */
602 if (ctx->Stencil.ZFailFunc != GL_KEEP) {
603 apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
604 }
605 if (ctx->Stencil.ZPassFunc != GL_KEEP) {
606 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
607 }
608 }
609
610 return GL_TRUE; /* one or more fragments passed both tests */
611 }
612
613
614
615 /*
616 * Apply stencil and depth testing to the span of pixels.
617 * Both software and hardware stencil buffers are acceptable.
618 * Input: n - number of pixels in the span
619 * x, y - location of leftmost pixel in span
620 * z - array [n] of z values
621 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
622 * Output: mask - array [n] of flags (1=stencil and depth test passed)
623 * Return: GL_TRUE - all fragments failed the testing
624 * GL_FALSE - one or more fragments passed the testing
625 *
626 */
627 GLboolean
628 _mesa_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
629 const GLdepth z[], GLubyte mask[] )
630 {
631 GLstencil stencilRow[MAX_WIDTH];
632 GLstencil *stencil;
633 GLboolean result;
634
635 ASSERT(ctx->Stencil.Enabled);
636 ASSERT(n <= MAX_WIDTH);
637
638 /* Get initial stencil values */
639 if (ctx->Driver.WriteStencilSpan) {
640 ASSERT(ctx->Driver.ReadStencilSpan);
641 /* Get stencil values from the hardware stencil buffer */
642 (*ctx->Driver.ReadStencilSpan)(ctx, n, x, y, stencilRow);
643 stencil = stencilRow;
644 }
645 else {
646 /* software stencil buffer */
647 stencil = STENCIL_ADDRESS(x, y);
648 }
649
650 /* do all the stencil/depth testing/updating */
651 result = stencil_and_ztest_span( ctx, n, x, y, z, stencil, mask );
652
653 if (ctx->Driver.WriteStencilSpan) {
654 /* Write updated stencil values into hardware stencil buffer */
655 (ctx->Driver.WriteStencilSpan)(ctx, n, x, y, stencil, mask );
656 }
657
658 return result;
659 }
660
661
662
663
664 /*
665 * Apply the given stencil operator for each pixel in the array whose
666 * mask flag is set. This is for software stencil buffers only.
667 * Input: n - number of pixels in the span
668 * x, y - array of [n] pixels
669 * operator - the stencil buffer operator
670 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
671 */
672 static void
673 apply_stencil_op_to_pixels( const GLcontext *ctx,
674 GLuint n, const GLint x[], const GLint y[],
675 GLenum oper, const GLubyte mask[] )
676 {
677 const GLstencil ref = ctx->Stencil.Ref;
678 const GLstencil wrtmask = ctx->Stencil.WriteMask;
679 const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
680 GLuint i;
681
682 ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */
683
684 switch (oper) {
685 case GL_KEEP:
686 /* do nothing */
687 break;
688 case GL_ZERO:
689 if (invmask==0) {
690 for (i=0;i<n;i++) {
691 if (mask[i]) {
692 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
693 *sptr = 0;
694 }
695 }
696 }
697 else {
698 for (i=0;i<n;i++) {
699 if (mask[i]) {
700 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
701 *sptr = (GLstencil) (invmask & *sptr);
702 }
703 }
704 }
705 break;
706 case GL_REPLACE:
707 if (invmask==0) {
708 for (i=0;i<n;i++) {
709 if (mask[i]) {
710 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
711 *sptr = ref;
712 }
713 }
714 }
715 else {
716 for (i=0;i<n;i++) {
717 if (mask[i]) {
718 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
719 *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref));
720 }
721 }
722 }
723 break;
724 case GL_INCR:
725 if (invmask==0) {
726 for (i=0;i<n;i++) {
727 if (mask[i]) {
728 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
729 if (*sptr < STENCIL_MAX) {
730 *sptr = (GLstencil) (*sptr + 1);
731 }
732 }
733 }
734 }
735 else {
736 for (i=0;i<n;i++) {
737 if (mask[i]) {
738 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
739 if (*sptr < STENCIL_MAX) {
740 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
741 }
742 }
743 }
744 }
745 break;
746 case GL_DECR:
747 if (invmask==0) {
748 for (i=0;i<n;i++) {
749 if (mask[i]) {
750 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
751 if (*sptr>0) {
752 *sptr = (GLstencil) (*sptr - 1);
753 }
754 }
755 }
756 }
757 else {
758 for (i=0;i<n;i++) {
759 if (mask[i]) {
760 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
761 if (*sptr>0) {
762 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
763 }
764 }
765 }
766 }
767 break;
768 case GL_INCR_WRAP_EXT:
769 if (invmask==0) {
770 for (i=0;i<n;i++) {
771 if (mask[i]) {
772 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
773 *sptr = (GLstencil) (*sptr + 1);
774 }
775 }
776 }
777 else {
778 for (i=0;i<n;i++) {
779 if (mask[i]) {
780 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
781 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
782 }
783 }
784 }
785 break;
786 case GL_DECR_WRAP_EXT:
787 if (invmask==0) {
788 for (i=0;i<n;i++) {
789 if (mask[i]) {
790 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
791 *sptr = (GLstencil) (*sptr - 1);
792 }
793 }
794 }
795 else {
796 for (i=0;i<n;i++) {
797 if (mask[i]) {
798 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
799 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
800 }
801 }
802 }
803 break;
804 case GL_INVERT:
805 if (invmask==0) {
806 for (i=0;i<n;i++) {
807 if (mask[i]) {
808 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
809 *sptr = (GLstencil) (~*sptr);
810 }
811 }
812 }
813 else {
814 for (i=0;i<n;i++) {
815 if (mask[i]) {
816 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
817 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr));
818 }
819 }
820 }
821 break;
822 default:
823 gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
824 }
825 }
826
827
828
829 /*
830 * Apply stencil test to an array of pixels before depth buffering.
831 * Used for software stencil buffer only.
832 * Input: n - number of pixels in the span
833 * x, y - array of [n] pixels to stencil
834 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
835 * Output: mask - pixels which fail the stencil test will have their
836 * mask flag set to 0.
837 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
838 */
839 static GLboolean
840 stencil_test_pixels( GLcontext *ctx, GLuint n,
841 const GLint x[], const GLint y[], GLubyte mask[] )
842 {
843 GLubyte fail[PB_SIZE];
844 GLstencil r, s;
845 GLuint i;
846 GLboolean allfail = GL_FALSE;
847
848 ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */
849
850 /*
851 * Perform stencil test. The results of this operation are stored
852 * in the fail[] array:
853 * IF fail[i] is non-zero THEN
854 * the stencil fail operator is to be applied
855 * ELSE
856 * the stencil fail operator is not to be applied
857 * ENDIF
858 */
859
860 switch (ctx->Stencil.Function) {
861 case GL_NEVER:
862 /* always fail */
863 for (i=0;i<n;i++) {
864 if (mask[i]) {
865 mask[i] = 0;
866 fail[i] = 1;
867 }
868 else {
869 fail[i] = 0;
870 }
871 }
872 allfail = GL_TRUE;
873 break;
874 case GL_LESS:
875 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
876 for (i=0;i<n;i++) {
877 if (mask[i]) {
878 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
879 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
880 if (r < s) {
881 /* passed */
882 fail[i] = 0;
883 }
884 else {
885 fail[i] = 1;
886 mask[i] = 0;
887 }
888 }
889 else {
890 fail[i] = 0;
891 }
892 }
893 break;
894 case GL_LEQUAL:
895 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
896 for (i=0;i<n;i++) {
897 if (mask[i]) {
898 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
899 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
900 if (r <= s) {
901 /* pass */
902 fail[i] = 0;
903 }
904 else {
905 fail[i] = 1;
906 mask[i] = 0;
907 }
908 }
909 else {
910 fail[i] = 0;
911 }
912 }
913 break;
914 case GL_GREATER:
915 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
916 for (i=0;i<n;i++) {
917 if (mask[i]) {
918 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
919 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
920 if (r > s) {
921 /* passed */
922 fail[i] = 0;
923 }
924 else {
925 fail[i] = 1;
926 mask[i] = 0;
927 }
928 }
929 else {
930 fail[i] = 0;
931 }
932 }
933 break;
934 case GL_GEQUAL:
935 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
936 for (i=0;i<n;i++) {
937 if (mask[i]) {
938 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
939 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
940 if (r >= s) {
941 /* passed */
942 fail[i] = 0;
943 }
944 else {
945 fail[i] = 1;
946 mask[i] = 0;
947 }
948 }
949 else {
950 fail[i] = 0;
951 }
952 }
953 break;
954 case GL_EQUAL:
955 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
956 for (i=0;i<n;i++) {
957 if (mask[i]) {
958 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
959 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
960 if (r == s) {
961 /* passed */
962 fail[i] = 0;
963 }
964 else {
965 fail[i] = 1;
966 mask[i] = 0;
967 }
968 }
969 else {
970 fail[i] = 0;
971 }
972 }
973 break;
974 case GL_NOTEQUAL:
975 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
976 for (i=0;i<n;i++) {
977 if (mask[i]) {
978 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
979 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
980 if (r != s) {
981 /* passed */
982 fail[i] = 0;
983 }
984 else {
985 fail[i] = 1;
986 mask[i] = 0;
987 }
988 }
989 else {
990 fail[i] = 0;
991 }
992 }
993 break;
994 case GL_ALWAYS:
995 /* always pass */
996 for (i=0;i<n;i++) {
997 fail[i] = 0;
998 }
999 break;
1000 default:
1001 gl_problem(ctx, "Bad stencil func in gl_stencil_pixels");
1002 return 0;
1003 }
1004
1005 if (ctx->Stencil.FailFunc != GL_KEEP) {
1006 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
1007 }
1008
1009 return !allfail;
1010 }
1011
1012
1013
1014
1015 /*
1016 * Apply stencil and depth testing to an array of pixels.
1017 * This is used both for software and hardware stencil buffers.
1018 *
1019 * The comments in this function are a bit sparse but the code is
1020 * almost identical to stencil_and_ztest_span(), which is well
1021 * commented.
1022 *
1023 * Input: n - number of pixels in the array
1024 * x, y - array of [n] pixel positions
1025 * z - array [n] of z values
1026 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
1027 * Output: mask - array [n] of flags (1=stencil and depth test passed)
1028 * Return: GL_TRUE - all fragments failed the testing
1029 * GL_FALSE - one or more fragments passed the testing
1030 */
1031 GLboolean
1032 _mesa_stencil_and_ztest_pixels( GLcontext *ctx,
1033 GLuint n, const GLint x[], const GLint y[],
1034 const GLdepth z[], GLubyte mask[] )
1035 {
1036 ASSERT(ctx->Stencil.Enabled);
1037 ASSERT(n <= PB_SIZE);
1038
1039 if (ctx->Driver.WriteStencilPixels) {
1040 /*** Hardware stencil buffer ***/
1041 GLstencil stencil[PB_SIZE];
1042 GLubyte mask[PB_SIZE];
1043
1044 ASSERT(ctx->Driver.ReadStencilPixels);
1045 (*ctx->Driver.ReadStencilPixels)(ctx, n, x, y, stencil);
1046
1047
1048 if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) {
1049 /* all fragments failed the stencil test, we're done. */
1050 return GL_FALSE;
1051 }
1052
1053 if (ctx->Depth.Test == GL_FALSE) {
1054 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
1055 }
1056 else {
1057 GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
1058 GLuint i;
1059
1060 MEMCPY(oldmask, mask, n * sizeof(GLubyte));
1061
1062 _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
1063
1064 for (i=0;i<n;i++) {
1065 ASSERT(mask[i] == 0 || mask[i] == 1);
1066 passmask[i] = oldmask[i] & mask[i];
1067 failmask[i] = oldmask[i] & (mask[i] ^ 1);
1068 }
1069
1070 if (ctx->Stencil.ZFailFunc != GL_KEEP) {
1071 apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
1072 }
1073 if (ctx->Stencil.ZPassFunc != GL_KEEP) {
1074 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
1075 }
1076 }
1077
1078 /* Write updated stencil values into hardware stencil buffer */
1079 (ctx->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, mask );
1080
1081 return GL_TRUE;
1082
1083 }
1084 else {
1085 /*** Software stencil buffer ***/
1086
1087 if (stencil_test_pixels(ctx, n, x, y, mask) == GL_FALSE) {
1088 /* all fragments failed the stencil test, we're done. */
1089 return GL_FALSE;
1090 }
1091
1092
1093 if (ctx->Depth.Test==GL_FALSE) {
1094 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
1095 }
1096 else {
1097 GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
1098 GLuint i;
1099
1100 MEMCPY(oldmask, mask, n * sizeof(GLubyte));
1101
1102 _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
1103
1104 for (i=0;i<n;i++) {
1105 ASSERT(mask[i] == 0 || mask[i] == 1);
1106 passmask[i] = oldmask[i] & mask[i];
1107 failmask[i] = oldmask[i] & (mask[i] ^ 1);
1108 }
1109
1110 if (ctx->Stencil.ZFailFunc != GL_KEEP) {
1111 apply_stencil_op_to_pixels( ctx, n, x, y,
1112 ctx->Stencil.ZFailFunc, failmask );
1113 }
1114 if (ctx->Stencil.ZPassFunc != GL_KEEP) {
1115 apply_stencil_op_to_pixels( ctx, n, x, y,
1116 ctx->Stencil.ZPassFunc, passmask );
1117 }
1118 }
1119
1120 return GL_TRUE; /* one or more fragments passed both tests */
1121 }
1122 }
1123
1124
1125
1126 /*
1127 * Return a span of stencil values from the stencil buffer.
1128 * Used for glRead/CopyPixels
1129 * Input: n - how many pixels
1130 * x,y - location of first pixel
1131 * Output: stencil - the array of stencil values
1132 */
1133 void
1134 _mesa_read_stencil_span( GLcontext *ctx,
1135 GLint n, GLint x, GLint y, GLstencil stencil[] )
1136 {
1137 if (y < 0 || y >= ctx->DrawBuffer->Height ||
1138 x + n <= 0 || x >= ctx->DrawBuffer->Width) {
1139 /* span is completely outside framebuffer */
1140 return; /* undefined values OK */
1141 }
1142
1143 if (x < 0) {
1144 GLint dx = -x;
1145 x = 0;
1146 n -= dx;
1147 stencil += dx;
1148 }
1149 if (x + n > ctx->DrawBuffer->Width) {
1150 GLint dx = x + n - ctx->DrawBuffer->Width;
1151 n -= dx;
1152 }
1153 if (n <= 0) {
1154 return;
1155 }
1156
1157
1158 ASSERT(n >= 0);
1159 if (ctx->Driver.ReadStencilSpan) {
1160 (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil );
1161 }
1162 else if (ctx->DrawBuffer->Stencil) {
1163 const GLstencil *s = STENCIL_ADDRESS( x, y );
1164 #if STENCIL_BITS == 8
1165 MEMCPY( stencil, s, n * sizeof(GLstencil) );
1166 #else
1167 GLuint i;
1168 for (i=0;i<n;i++)
1169 stencil[i] = s[i];
1170 #endif
1171 }
1172 }
1173
1174
1175
1176 /*
1177 * Write a span of stencil values to the stencil buffer.
1178 * Used for glDraw/CopyPixels
1179 * Input: n - how many pixels
1180 * x, y - location of first pixel
1181 * stencil - the array of stencil values
1182 */
1183 void
1184 _mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
1185 const GLstencil stencil[] )
1186 {
1187 if (y < 0 || y >= ctx->DrawBuffer->Height ||
1188 x + n <= 0 || x >= ctx->DrawBuffer->Width) {
1189 /* span is completely outside framebuffer */
1190 return; /* undefined values OK */
1191 }
1192
1193 if (x < 0) {
1194 GLint dx = -x;
1195 x = 0;
1196 n -= dx;
1197 stencil += dx;
1198 }
1199 if (x + n > ctx->DrawBuffer->Width) {
1200 GLint dx = x + n - ctx->DrawBuffer->Width;
1201 n -= dx;
1202 }
1203 if (n <= 0) {
1204 return;
1205 }
1206
1207 if (ctx->Driver.WriteStencilSpan) {
1208 (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL );
1209 }
1210 else if (ctx->DrawBuffer->Stencil) {
1211 GLstencil *s = STENCIL_ADDRESS( x, y );
1212 #if STENCIL_BITS == 8
1213 MEMCPY( s, stencil, n * sizeof(GLstencil) );
1214 #else
1215 GLuint i;
1216 for (i=0;i<n;i++)
1217 s[i] = stencil[i];
1218 #endif
1219 }
1220 }
1221
1222
1223
1224 /*
1225 * Allocate a new stencil buffer. If there's an old one it will be
1226 * deallocated first. The new stencil buffer will be uninitialized.
1227 */
1228 void
1229 _mesa_alloc_stencil_buffer( GLcontext *ctx )
1230 {
1231 GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1232
1233 /* deallocate current stencil buffer if present */
1234 if (ctx->DrawBuffer->Stencil) {
1235 FREE(ctx->DrawBuffer->Stencil);
1236 ctx->DrawBuffer->Stencil = NULL;
1237 }
1238
1239 /* allocate new stencil buffer */
1240 ctx->DrawBuffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil));
1241 if (!ctx->DrawBuffer->Stencil) {
1242 /* out of memory */
1243 _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE );
1244 gl_error( ctx, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" );
1245 }
1246 }
1247
1248
1249
1250 /*
1251 * Clear the software (malloc'd) stencil buffer.
1252 */
1253 static void
1254 clear_software_stencil_buffer( GLcontext *ctx )
1255 {
1256 if (ctx->Visual->StencilBits==0 || !ctx->DrawBuffer->Stencil) {
1257 /* no stencil buffer */
1258 return;
1259 }
1260
1261 if (ctx->Scissor.Enabled) {
1262 /* clear scissor region only */
1263 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
1264 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1265 /* must apply mask to the clear */
1266 GLint y;
1267 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1268 const GLstencil mask = ctx->Stencil.WriteMask;
1269 const GLstencil invMask = ~mask;
1270 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1271 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
1272 GLint i;
1273 for (i = 0; i < width; i++) {
1274 stencil[i] = (stencil[i] & invMask) | clearVal;
1275 }
1276 }
1277 }
1278 else {
1279 /* no masking */
1280 GLint y;
1281 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1282 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
1283 #if STENCIL_BITS==8
1284 MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) );
1285 #else
1286 GLint i;
1287 for (i = 0; i < width; i++)
1288 stencil[x] = ctx->Stencil.Clear;
1289 #endif
1290 }
1291 }
1292 }
1293 else {
1294 /* clear whole stencil buffer */
1295 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1296 /* must apply mask to the clear */
1297 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1298 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1299 const GLstencil mask = ctx->Stencil.WriteMask;
1300 const GLstencil invMask = ~mask;
1301 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1302 GLuint i;
1303 for (i = 0; i < n; i++) {
1304 stencil[i] = (stencil[i] & invMask) | clearVal;
1305 }
1306 }
1307 else {
1308 /* clear whole buffer without masking */
1309 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1310 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1311
1312 #if STENCIL_BITS==8
1313 MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) );
1314 #else
1315 GLuint i;
1316 for (i = 0; i < n; i++) {
1317 stencil[i] = ctx->Stencil.Clear;
1318 }
1319 #endif
1320 }
1321 }
1322 }
1323
1324
1325
1326 /*
1327 * Clear the hardware (in graphics card) stencil buffer.
1328 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1329 * functions.
1330 * Actually, if there is a hardware stencil buffer it really should have
1331 * been cleared in Driver.Clear()! However, if the hardware does not
1332 * support scissored clears or masked clears (i.e. glStencilMask) then
1333 * we have to use the span-based functions.
1334 */
1335 static void
1336 clear_hardware_stencil_buffer( GLcontext *ctx )
1337 {
1338 ASSERT(ctx->Driver.WriteStencilSpan);
1339 ASSERT(ctx->Driver.ReadStencilSpan);
1340
1341 if (ctx->Scissor.Enabled) {
1342 /* clear scissor region only */
1343 const GLint x = ctx->DrawBuffer->Xmin;
1344 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
1345 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1346 /* must apply mask to the clear */
1347 GLint y;
1348 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1349 const GLstencil mask = ctx->Stencil.WriteMask;
1350 const GLstencil invMask = ~mask;
1351 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1352 GLstencil stencil[MAX_WIDTH];
1353 GLint i;
1354 (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
1355 for (i = 0; i < width; i++) {
1356 stencil[i] = (stencil[i] & invMask) | clearVal;
1357 }
1358 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1359 }
1360 }
1361 else {
1362 /* no masking */
1363 GLstencil stencil[MAX_WIDTH];
1364 GLint y, i;
1365 for (i = 0; i < width; i++) {
1366 stencil[i] = ctx->Stencil.Clear;
1367 }
1368 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1369 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1370 }
1371 }
1372 }
1373 else {
1374 /* clear whole stencil buffer */
1375 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1376 /* must apply mask to the clear */
1377 const GLstencil mask = ctx->Stencil.WriteMask;
1378 const GLstencil invMask = ~mask;
1379 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1380 const GLint width = ctx->DrawBuffer->Width;
1381 const GLint height = ctx->DrawBuffer->Height;
1382 const GLint x = ctx->DrawBuffer->Xmin;
1383 GLint y;
1384 for (y = 0; y < height; y++) {
1385 GLstencil stencil[MAX_WIDTH];
1386 GLuint i;
1387 (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
1388 for (i = 0; i < width; i++) {
1389 stencil[i] = (stencil[i] & invMask) | clearVal;
1390 }
1391 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1392 }
1393 }
1394 else {
1395 /* clear whole buffer without masking */
1396 const GLint width = ctx->DrawBuffer->Width;
1397 const GLint height = ctx->DrawBuffer->Width;
1398 const GLint x = ctx->DrawBuffer->Xmin;
1399 GLstencil stencil[MAX_WIDTH];
1400 GLint y, i;
1401 for (i = 0; i < width; i++) {
1402 stencil[i] = ctx->Stencil.Clear;
1403 }
1404 for (y = 0; y < height; y++) {
1405 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1406 }
1407 }
1408 }
1409 }
1410
1411
1412
1413 /*
1414 * Clear the stencil buffer.
1415 */
1416 void
1417 _mesa_clear_stencil_buffer( GLcontext *ctx )
1418 {
1419 if (ctx->Driver.WriteStencilSpan) {
1420 ASSERT(ctx->Driver.ReadStencilSpan);
1421 clear_hardware_stencil_buffer(ctx);
1422 }
1423 else {
1424 clear_software_stencil_buffer(ctx);
1425 }
1426 }
1427