updated for hardware stencil support
[mesa.git] / src / mesa / main / stencil.c
1 /* $Id: stencil.c,v 1.12 1999/12/10 16:15:04 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.3
6 *
7 * Copyright (C) 1999 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 "mem.h"
34 #include "pb.h"
35 #include "stencil.h"
36 #include "types.h"
37 #include "enable.h"
38 #endif
39
40
41
42
43 void
44 _mesa_ClearStencil( GLint s )
45 {
46 GET_CURRENT_CONTEXT(ctx);
47 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearStencil");
48 ctx->Stencil.Clear = (GLstencil) s;
49
50 if (ctx->Driver.ClearStencil) {
51 (*ctx->Driver.ClearStencil)( ctx, s );
52 }
53 }
54
55
56
57 void
58 _mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
59 {
60 GET_CURRENT_CONTEXT(ctx);
61 GLint maxref;
62
63 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilFunc");
64
65 switch (func) {
66 case GL_NEVER:
67 case GL_LESS:
68 case GL_LEQUAL:
69 case GL_GREATER:
70 case GL_GEQUAL:
71 case GL_EQUAL:
72 case GL_NOTEQUAL:
73 case GL_ALWAYS:
74 ctx->Stencil.Function = func;
75 break;
76 default:
77 gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" );
78 return;
79 }
80
81 maxref = (1 << STENCIL_BITS) - 1;
82 ctx->Stencil.Ref = (GLstencil) CLAMP( ref, 0, maxref );
83 ctx->Stencil.ValueMask = (GLstencil) mask;
84
85 if (ctx->Driver.StencilFunc) {
86 (*ctx->Driver.StencilFunc)( ctx, func, ctx->Stencil.Ref, mask );
87 }
88 }
89
90
91
92 void
93 _mesa_StencilMask( GLuint mask )
94 {
95 GET_CURRENT_CONTEXT(ctx);
96 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilMask");
97 ctx->Stencil.WriteMask = (GLstencil) mask;
98
99 if (ctx->Driver.StencilMask) {
100 (*ctx->Driver.StencilMask)( ctx, mask );
101 }
102 }
103
104
105
106 void
107 _mesa_StencilOp( GLenum fail, GLenum zfail, GLenum zpass )
108 {
109 GET_CURRENT_CONTEXT(ctx);
110 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilOp");
111 switch (fail) {
112 case GL_KEEP:
113 case GL_ZERO:
114 case GL_REPLACE:
115 case GL_INCR:
116 case GL_DECR:
117 case GL_INVERT:
118 case GL_INCR_WRAP_EXT:
119 case GL_DECR_WRAP_EXT:
120 ctx->Stencil.FailFunc = fail;
121 break;
122 default:
123 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
124 return;
125 }
126 switch (zfail) {
127 case GL_KEEP:
128 case GL_ZERO:
129 case GL_REPLACE:
130 case GL_INCR:
131 case GL_DECR:
132 case GL_INVERT:
133 case GL_INCR_WRAP_EXT:
134 case GL_DECR_WRAP_EXT:
135 ctx->Stencil.ZFailFunc = zfail;
136 break;
137 default:
138 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
139 return;
140 }
141 switch (zpass) {
142 case GL_KEEP:
143 case GL_ZERO:
144 case GL_REPLACE:
145 case GL_INCR:
146 case GL_DECR:
147 case GL_INVERT:
148 case GL_INCR_WRAP_EXT:
149 case GL_DECR_WRAP_EXT:
150 ctx->Stencil.ZPassFunc = zpass;
151 break;
152 default:
153 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
154 return;
155 }
156
157 if (ctx->Driver.StencilOp) {
158 (*ctx->Driver.StencilOp)( ctx, fail, zfail, zpass );
159 }
160 }
161
162
163
164 /* Stencil Logic:
165
166 IF stencil test fails THEN
167 Apply fail-op to stencil value
168 Don't write the pixel (RGBA,Z)
169 ELSE
170 IF doing depth test && depth test fails THEN
171 Apply zfail-op to stencil value
172 Write RGBA and Z to appropriate buffers
173 ELSE
174 Apply zpass-op to stencil value
175 ENDIF
176
177 */
178
179
180
181
182 /*
183 * Return the address of a stencil buffer value given the window coords:
184 */
185 #define STENCIL_ADDRESS(X,Y) \
186 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
187
188
189
190 /*
191 * Apply the given stencil operator to the array of stencil values.
192 * Don't touch stencil[i] if mask[i] is zero.
193 * Input: n - size of stencil array
194 * oper - the stencil buffer operator
195 * stencil - array of stencil values
196 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
197 * Output: stencil - modified values
198 */
199 static void apply_stencil_op( const GLcontext *ctx, GLenum oper,
200 GLuint n, GLstencil stencil[],
201 const GLubyte mask[] )
202 {
203 const GLstencil ref = ctx->Stencil.Ref;
204 const GLstencil wrtmask = ctx->Stencil.WriteMask;
205 const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
206 GLuint i;
207
208 switch (oper) {
209 case GL_KEEP:
210 /* do nothing */
211 break;
212 case GL_ZERO:
213 if (invmask==0) {
214 for (i=0;i<n;i++) {
215 if (mask[i]) {
216 stencil[i] = 0;
217 }
218 }
219 }
220 else {
221 for (i=0;i<n;i++) {
222 if (mask[i]) {
223 stencil[i] = (GLstencil) (stencil[i] & invmask);
224 }
225 }
226 }
227 break;
228 case GL_REPLACE:
229 if (invmask==0) {
230 for (i=0;i<n;i++) {
231 if (mask[i]) {
232 stencil[i] = ref;
233 }
234 }
235 }
236 else {
237 for (i=0;i<n;i++) {
238 if (mask[i]) {
239 GLstencil s = stencil[i];
240 stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref));
241 }
242 }
243 }
244 break;
245 case GL_INCR:
246 if (invmask==0) {
247 for (i=0;i<n;i++) {
248 if (mask[i]) {
249 GLstencil s = stencil[i];
250 if (s < STENCIL_MAX) {
251 stencil[i] = (GLstencil) (s+1);
252 }
253 }
254 }
255 }
256 else {
257 for (i=0;i<n;i++) {
258 if (mask[i]) {
259 /* VERIFY logic of adding 1 to a write-masked value */
260 GLstencil s = stencil[i];
261 if (s < STENCIL_MAX) {
262 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
263 }
264 }
265 }
266 }
267 break;
268 case GL_DECR:
269 if (invmask==0) {
270 for (i=0;i<n;i++) {
271 if (mask[i]) {
272 GLstencil s = stencil[i];
273 if (s>0) {
274 stencil[i] = (GLstencil) (s-1);
275 }
276 }
277 }
278 }
279 else {
280 for (i=0;i<n;i++) {
281 if (mask[i]) {
282 /* VERIFY logic of subtracting 1 to a write-masked value */
283 GLstencil s = stencil[i];
284 if (s>0) {
285 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
286 }
287 }
288 }
289 }
290 break;
291 case GL_INCR_WRAP_EXT:
292 if (invmask==0) {
293 for (i=0;i<n;i++) {
294 if (mask[i]) {
295 stencil[i]++;
296 }
297 }
298 }
299 else {
300 for (i=0;i<n;i++) {
301 if (mask[i]) {
302 GLstencil s = stencil[i];
303 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
304 }
305 }
306 }
307 break;
308 case GL_DECR_WRAP_EXT:
309 if (invmask==0) {
310 for (i=0;i<n;i++) {
311 if (mask[i]) {
312 stencil[i]--;
313 }
314 }
315 }
316 else {
317 for (i=0;i<n;i++) {
318 if (mask[i]) {
319 GLstencil s = stencil[i];
320 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
321 }
322 }
323 }
324 break;
325 case GL_INVERT:
326 if (invmask==0) {
327 for (i=0;i<n;i++) {
328 if (mask[i]) {
329 GLstencil s = stencil[i];
330 stencil[i] = (GLstencil) ~s;
331 }
332 }
333 }
334 else {
335 for (i=0;i<n;i++) {
336 if (mask[i]) {
337 GLstencil s = stencil[i];
338 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s));
339 }
340 }
341 }
342 break;
343 default:
344 gl_problem(ctx, "Bad stencil op in apply_stencil_op");
345 }
346 }
347
348
349
350
351 /*
352 * Apply stencil test to an array of stencil values (before depth buffering).
353 * Input: n - number of pixels in the array
354 * stencil - array of [n] stencil values
355 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
356 * Output: mask - pixels which fail the stencil test will have their
357 * mask flag set to 0.
358 * stencil - updated stencil values (where the test passed)
359 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
360 */
361 static GLboolean
362 do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[],
363 GLubyte mask[] )
364 {
365 GLubyte fail[PB_SIZE];
366 GLboolean allfail = GL_FALSE;
367 GLuint i;
368 GLstencil r, s;
369
370 ASSERT(n <= PB_SIZE);
371
372 /*
373 * Perform stencil test. The results of this operation are stored
374 * in the fail[] array:
375 * IF fail[i] is non-zero THEN
376 * the stencil fail operator is to be applied
377 * ELSE
378 * the stencil fail operator is not to be applied
379 * ENDIF
380 */
381 switch (ctx->Stencil.Function) {
382 case GL_NEVER:
383 /* always fail */
384 for (i=0;i<n;i++) {
385 if (mask[i]) {
386 mask[i] = 0;
387 fail[i] = 1;
388 }
389 else {
390 fail[i] = 0;
391 }
392 }
393 allfail = GL_TRUE;
394 break;
395 case GL_LESS:
396 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
397 for (i=0;i<n;i++) {
398 if (mask[i]) {
399 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
400 if (r < s) {
401 /* passed */
402 fail[i] = 0;
403 }
404 else {
405 fail[i] = 1;
406 mask[i] = 0;
407 }
408 }
409 else {
410 fail[i] = 0;
411 }
412 }
413 break;
414 case GL_LEQUAL:
415 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
416 for (i=0;i<n;i++) {
417 if (mask[i]) {
418 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
419 if (r <= s) {
420 /* pass */
421 fail[i] = 0;
422 }
423 else {
424 fail[i] = 1;
425 mask[i] = 0;
426 }
427 }
428 else {
429 fail[i] = 0;
430 }
431 }
432 break;
433 case GL_GREATER:
434 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
435 for (i=0;i<n;i++) {
436 if (mask[i]) {
437 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
438 if (r > s) {
439 /* passed */
440 fail[i] = 0;
441 }
442 else {
443 fail[i] = 1;
444 mask[i] = 0;
445 }
446 }
447 else {
448 fail[i] = 0;
449 }
450 }
451 break;
452 case GL_GEQUAL:
453 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
454 for (i=0;i<n;i++) {
455 if (mask[i]) {
456 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
457 if (r >= s) {
458 /* passed */
459 fail[i] = 0;
460 }
461 else {
462 fail[i] = 1;
463 mask[i] = 0;
464 }
465 }
466 else {
467 fail[i] = 0;
468 }
469 }
470 break;
471 case GL_EQUAL:
472 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
473 for (i=0;i<n;i++) {
474 if (mask[i]) {
475 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
476 if (r == s) {
477 /* passed */
478 fail[i] = 0;
479 }
480 else {
481 fail[i] = 1;
482 mask[i] = 0;
483 }
484 }
485 else {
486 fail[i] = 0;
487 }
488 }
489 break;
490 case GL_NOTEQUAL:
491 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
492 for (i=0;i<n;i++) {
493 if (mask[i]) {
494 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
495 if (r != s) {
496 /* passed */
497 fail[i] = 0;
498 }
499 else {
500 fail[i] = 1;
501 mask[i] = 0;
502 }
503 }
504 else {
505 fail[i] = 0;
506 }
507 }
508 break;
509 case GL_ALWAYS:
510 /* always pass */
511 for (i=0;i<n;i++) {
512 fail[i] = 0;
513 }
514 break;
515 default:
516 gl_problem(ctx, "Bad stencil func in gl_stencil_span");
517 return 0;
518 }
519
520 if (ctx->Stencil.FailFunc != GL_KEEP) {
521 apply_stencil_op( ctx, ctx->Stencil.FailFunc, n, stencil, fail );
522 }
523
524 return !allfail;
525 }
526
527
528
529
530 /*
531 * Apply stencil and depth testing to an array of pixels.
532 * Hardware or software stencil buffer acceptable.
533 * Input: n - number of pixels in the span
534 * z - array [n] of z values
535 * stencil - array [n] of stencil values
536 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
537 * Output: stencil - modified stencil values
538 * mask - array [n] of flags (1=stencil and depth test passed)
539 * Return: GL_TRUE - all fragments failed the testing
540 * GL_FALSE - one or more fragments passed the testing
541 *
542 */
543 static GLboolean
544 stencil_and_depth_test_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
545 const GLdepth z[], GLstencil stencil[],
546 GLubyte mask[] )
547 {
548 ASSERT(ctx->Stencil.Enabled);
549 ASSERT(n <= PB_SIZE);
550
551 /*
552 * Apply the stencil test to the fragments.
553 * failMask[i] is 1 if the stencil test failed.
554 */
555 if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) {
556 /* all fragments failed the stencil test, we're done. */
557 return GL_FALSE;
558 }
559
560
561 /*
562 * Some fragments passed the stencil test, apply depth test to them
563 * and apply Zpass and Zfail stencil ops.
564 */
565 if (ctx->Depth.Test==GL_FALSE) {
566 /*
567 * No depth buffer, just apply zpass stencil function to active pixels.
568 */
569 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
570 }
571 else {
572 /*
573 * Perform depth buffering, then apply zpass or zfail stencil function.
574 */
575 GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
576 GLuint i;
577
578 /* save the current mask bits */
579 MEMCPY(oldmask, mask, n * sizeof(GLubyte));
580
581 /* apply the depth test */
582 if (ctx->Driver.DepthTestSpan)
583 (*ctx->Driver.DepthTestSpan)( 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 gl_stencil_and_depth_test_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_depth_test_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_depth_test_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 gl_stencil_and_depth_test_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 if (ctx->Driver.DepthTestPixels)
1063 (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask );
1064
1065 for (i=0;i<n;i++) {
1066 ASSERT(mask[i] == 0 || mask[i] == 1);
1067 passmask[i] = oldmask[i] & mask[i];
1068 failmask[i] = oldmask[i] & (mask[i] ^ 1);
1069 }
1070
1071 if (ctx->Stencil.ZFailFunc != GL_KEEP) {
1072 apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
1073 }
1074 if (ctx->Stencil.ZPassFunc != GL_KEEP) {
1075 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
1076 }
1077 }
1078
1079 /* Write updated stencil values into hardware stencil buffer */
1080 (ctx->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, mask );
1081
1082 return GL_TRUE;
1083
1084 }
1085 else {
1086 /*** Software stencil buffer ***/
1087
1088 if (stencil_test_pixels(ctx, n, x, y, mask) == GL_FALSE) {
1089 /* all fragments failed the stencil test, we're done. */
1090 return GL_FALSE;
1091 }
1092
1093
1094 if (ctx->Depth.Test==GL_FALSE) {
1095 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
1096 }
1097 else {
1098 GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
1099 GLuint i;
1100
1101 MEMCPY(oldmask, mask, n * sizeof(GLubyte));
1102
1103 if (ctx->Driver.DepthTestPixels)
1104 (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask );
1105
1106 for (i=0;i<n;i++) {
1107 ASSERT(mask[i] == 0 || mask[i] == 1);
1108 passmask[i] = oldmask[i] & mask[i];
1109 failmask[i] = oldmask[i] & (mask[i] ^ 1);
1110 }
1111
1112 if (ctx->Stencil.ZFailFunc != GL_KEEP) {
1113 apply_stencil_op_to_pixels( ctx, n, x, y,
1114 ctx->Stencil.ZFailFunc, failmask );
1115 }
1116 if (ctx->Stencil.ZPassFunc != GL_KEEP) {
1117 apply_stencil_op_to_pixels( ctx, n, x, y,
1118 ctx->Stencil.ZPassFunc, passmask );
1119 }
1120 }
1121
1122 return GL_TRUE; /* one or more fragments passed both tests */
1123 }
1124 }
1125
1126
1127
1128 /*
1129 * Return a span of stencil values from the stencil buffer.
1130 * Used for glRead/CopyPixels
1131 * Input: n - how many pixels
1132 * x,y - location of first pixel
1133 * Output: stencil - the array of stencil values
1134 */
1135 void gl_read_stencil_span( GLcontext *ctx,
1136 GLint n, GLint x, GLint y, GLstencil stencil[] )
1137 {
1138 ASSERT(n >= 0);
1139 if (ctx->DrawBuffer->Stencil) {
1140 if (ctx->Driver.ReadStencilSpan) {
1141 (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil );
1142 }
1143 else {
1144 const GLstencil *s = STENCIL_ADDRESS( x, y );
1145 #if STENCIL_BITS == 8
1146 MEMCPY( stencil, s, n * sizeof(GLstencil) );
1147 #else
1148 GLuint i;
1149 for (i=0;i<n;i++)
1150 stencil[i] = s[i];
1151 #endif
1152 }
1153 }
1154 }
1155
1156
1157
1158 /*
1159 * Write a span of stencil values to the stencil buffer.
1160 * Used for glDraw/CopyPixels
1161 * Input: n - how many pixels
1162 * x, y - location of first pixel
1163 * stencil - the array of stencil values
1164 */
1165 void gl_write_stencil_span( GLcontext *ctx,
1166 GLint n, GLint x, GLint y,
1167 const GLstencil stencil[] )
1168 {
1169 ASSERT(n >= 0);
1170 if (ctx->DrawBuffer->Stencil) {
1171 /* do clipping */
1172 if (y < ctx->DrawBuffer->Ymin || y > ctx->DrawBuffer->Ymax)
1173 return;
1174 if (x < ctx->DrawBuffer->Xmin) {
1175 GLint diff = ctx->DrawBuffer->Xmin - x;
1176 n -= diff;
1177 stencil += diff;
1178 x = ctx->DrawBuffer->Xmin;
1179 }
1180 if (x + n > ctx->DrawBuffer->Xmax) {
1181 GLint diff = x + n - ctx->DrawBuffer->Xmax;
1182 n -= diff;
1183 }
1184
1185 ASSERT( n >= 0);
1186
1187 if (ctx->Driver.WriteStencilSpan) {
1188 (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL );
1189 }
1190 else {
1191 GLstencil *s = STENCIL_ADDRESS( x, y );
1192 #if STENCIL_BITS == 8
1193 MEMCPY( s, stencil, n * sizeof(GLstencil) );
1194 #else
1195 GLuint i;
1196 for (i=0;i<n;i++)
1197 s[i] = stencil[i];
1198 #endif
1199 }
1200 }
1201 }
1202
1203
1204
1205 /*
1206 * Allocate a new stencil buffer. If there's an old one it will be
1207 * deallocated first. The new stencil buffer will be uninitialized.
1208 */
1209 void gl_alloc_stencil_buffer( GLcontext *ctx )
1210 {
1211 GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1212
1213 /* deallocate current stencil buffer if present */
1214 if (ctx->DrawBuffer->Stencil) {
1215 FREE(ctx->DrawBuffer->Stencil);
1216 ctx->DrawBuffer->Stencil = NULL;
1217 }
1218
1219 /* allocate new stencil buffer */
1220 ctx->DrawBuffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil));
1221 if (!ctx->DrawBuffer->Stencil) {
1222 /* out of memory */
1223 _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE );
1224 gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" );
1225 }
1226 }
1227
1228
1229
1230 /*
1231 * Clear the software (malloc'd) stencil buffer.
1232 */
1233 static void
1234 clear_software_stencil_buffer( GLcontext *ctx )
1235 {
1236 if (ctx->Visual->StencilBits==0 || !ctx->DrawBuffer->Stencil) {
1237 /* no stencil buffer */
1238 return;
1239 }
1240
1241 if (ctx->Scissor.Enabled) {
1242 /* clear scissor region only */
1243 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
1244 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1245 /* must apply mask to the clear */
1246 GLint y;
1247 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1248 const GLstencil mask = ctx->Stencil.WriteMask;
1249 const GLstencil invMask = ~mask;
1250 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1251 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
1252 GLint i;
1253 for (i = 0; i < width; i++) {
1254 stencil[i] = (stencil[i] & invMask) | clearVal;
1255 }
1256 }
1257 }
1258 else {
1259 /* no masking */
1260 GLint y;
1261 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1262 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
1263 #if STENCIL_BITS==8
1264 MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) );
1265 #else
1266 GLint i;
1267 for (i = 0; i < width; i++)
1268 stencil[x] = ctx->Stencil.Clear;
1269 #endif
1270 }
1271 }
1272 }
1273 else {
1274 /* clear whole stencil buffer */
1275 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1276 /* must apply mask to the clear */
1277 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1278 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1279 const GLstencil mask = ctx->Stencil.WriteMask;
1280 const GLstencil invMask = ~mask;
1281 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1282 GLuint i;
1283 for (i = 0; i < n; i++) {
1284 stencil[i] = (stencil[i] & invMask) | clearVal;
1285 }
1286 }
1287 else {
1288 /* clear whole buffer without masking */
1289 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1290 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1291
1292 #if STENCIL_BITS==8
1293 MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) );
1294 #else
1295 GLuint i;
1296 for (i = 0; i < n; i++) {
1297 stencil[i] = ctx->Stencil.Clear;
1298 }
1299 #endif
1300 }
1301 }
1302 }
1303
1304
1305
1306 /*
1307 * Clear the hardware (in graphics card) stencil buffer.
1308 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1309 * functions.
1310 * Actually, if there is a hardware stencil buffer it really should have
1311 * been cleared in Driver.Clear()! However, if the hardware does not
1312 * support scissored clears or masked clears (i.e. glStencilMask) then
1313 * we have to use the span-based functions.
1314 */
1315 static void
1316 clear_hardware_stencil_buffer( GLcontext *ctx )
1317 {
1318 ASSERT(ctx->Driver.WriteStencilSpan);
1319 ASSERT(ctx->Driver.ReadStencilSpan);
1320
1321 if (ctx->Scissor.Enabled) {
1322 /* clear scissor region only */
1323 const GLint x = ctx->DrawBuffer->Xmin;
1324 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
1325 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1326 /* must apply mask to the clear */
1327 GLint y;
1328 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1329 const GLstencil mask = ctx->Stencil.WriteMask;
1330 const GLstencil invMask = ~mask;
1331 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1332 GLstencil stencil[MAX_WIDTH];
1333 GLint i;
1334 (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
1335 for (i = 0; i < width; i++) {
1336 stencil[i] = (stencil[i] & invMask) | clearVal;
1337 }
1338 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1339 }
1340 }
1341 else {
1342 /* no masking */
1343 GLstencil stencil[MAX_WIDTH];
1344 GLint y, i;
1345 for (i = 0; i < width; i++) {
1346 stencil[i] = ctx->Stencil.Clear;
1347 }
1348 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1349 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1350 }
1351 }
1352 }
1353 else {
1354 /* clear whole stencil buffer */
1355 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1356 /* must apply mask to the clear */
1357 const GLstencil mask = ctx->Stencil.WriteMask;
1358 const GLstencil invMask = ~mask;
1359 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1360 const GLint width = ctx->DrawBuffer->Width;
1361 const GLint height = ctx->DrawBuffer->Height;
1362 const GLint x = ctx->DrawBuffer->Xmin;
1363 GLint y;
1364 for (y = 0; y < height; y++) {
1365 GLstencil stencil[MAX_WIDTH];
1366 GLuint i;
1367 (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
1368 for (i = 0; i < width; i++) {
1369 stencil[i] = (stencil[i] & invMask) | clearVal;
1370 }
1371 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1372 }
1373 }
1374 else {
1375 /* clear whole buffer without masking */
1376 const GLint width = ctx->DrawBuffer->Width;
1377 const GLint height = ctx->DrawBuffer->Width;
1378 const GLint x = ctx->DrawBuffer->Xmin;
1379 GLstencil stencil[MAX_WIDTH];
1380 GLint y, i;
1381 for (i = 0; i < width; i++) {
1382 stencil[i] = ctx->Stencil.Clear;
1383 }
1384 for (y = 0; y < height; y++) {
1385 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1386 }
1387 }
1388 }
1389 }
1390
1391
1392
1393 /*
1394 * Clear the stencil buffer.
1395 */
1396 void gl_clear_stencil_buffer( GLcontext *ctx )
1397 {
1398 if (ctx->Driver.WriteStencilSpan) {
1399 ASSERT(ctx->Driver.ReadStencilSpan);
1400 clear_hardware_stencil_buffer(ctx);
1401 }
1402 else {
1403 clear_software_stencil_buffer(ctx);
1404 }
1405 }
1406