changes in hardware depth buffer support
[mesa.git] / src / mesa / main / stencil.c
1 /* $Id: stencil.c,v 1.13 1999/12/10 19:09:22 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 "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_depth_test_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 gl_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 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 gl_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 gl_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 gl_read_stencil_span( GLcontext *ctx,
1134 GLint n, GLint x, GLint y, GLstencil stencil[] )
1135 {
1136 ASSERT(n >= 0);
1137 if (ctx->DrawBuffer->Stencil) {
1138 if (ctx->Driver.ReadStencilSpan) {
1139 (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil );
1140 }
1141 else {
1142 const GLstencil *s = STENCIL_ADDRESS( x, y );
1143 #if STENCIL_BITS == 8
1144 MEMCPY( stencil, s, n * sizeof(GLstencil) );
1145 #else
1146 GLuint i;
1147 for (i=0;i<n;i++)
1148 stencil[i] = s[i];
1149 #endif
1150 }
1151 }
1152 }
1153
1154
1155
1156 /*
1157 * Write a span of stencil values to the stencil buffer.
1158 * Used for glDraw/CopyPixels
1159 * Input: n - how many pixels
1160 * x, y - location of first pixel
1161 * stencil - the array of stencil values
1162 */
1163 void gl_write_stencil_span( GLcontext *ctx,
1164 GLint n, GLint x, GLint y,
1165 const GLstencil stencil[] )
1166 {
1167 ASSERT(n >= 0);
1168 if (ctx->DrawBuffer->Stencil) {
1169 /* do clipping */
1170 if (y < ctx->DrawBuffer->Ymin || y > ctx->DrawBuffer->Ymax)
1171 return;
1172 if (x < ctx->DrawBuffer->Xmin) {
1173 GLint diff = ctx->DrawBuffer->Xmin - x;
1174 n -= diff;
1175 stencil += diff;
1176 x = ctx->DrawBuffer->Xmin;
1177 }
1178 if (x + n > ctx->DrawBuffer->Xmax) {
1179 GLint diff = x + n - ctx->DrawBuffer->Xmax;
1180 n -= diff;
1181 }
1182
1183 ASSERT( n >= 0);
1184
1185 if (ctx->Driver.WriteStencilSpan) {
1186 (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL );
1187 }
1188 else {
1189 GLstencil *s = STENCIL_ADDRESS( x, y );
1190 #if STENCIL_BITS == 8
1191 MEMCPY( s, stencil, n * sizeof(GLstencil) );
1192 #else
1193 GLuint i;
1194 for (i=0;i<n;i++)
1195 s[i] = stencil[i];
1196 #endif
1197 }
1198 }
1199 }
1200
1201
1202
1203 /*
1204 * Allocate a new stencil buffer. If there's an old one it will be
1205 * deallocated first. The new stencil buffer will be uninitialized.
1206 */
1207 void gl_alloc_stencil_buffer( GLcontext *ctx )
1208 {
1209 GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1210
1211 /* deallocate current stencil buffer if present */
1212 if (ctx->DrawBuffer->Stencil) {
1213 FREE(ctx->DrawBuffer->Stencil);
1214 ctx->DrawBuffer->Stencil = NULL;
1215 }
1216
1217 /* allocate new stencil buffer */
1218 ctx->DrawBuffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil));
1219 if (!ctx->DrawBuffer->Stencil) {
1220 /* out of memory */
1221 _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE );
1222 gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" );
1223 }
1224 }
1225
1226
1227
1228 /*
1229 * Clear the software (malloc'd) stencil buffer.
1230 */
1231 static void
1232 clear_software_stencil_buffer( GLcontext *ctx )
1233 {
1234 if (ctx->Visual->StencilBits==0 || !ctx->DrawBuffer->Stencil) {
1235 /* no stencil buffer */
1236 return;
1237 }
1238
1239 if (ctx->Scissor.Enabled) {
1240 /* clear scissor region only */
1241 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
1242 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1243 /* must apply mask to the clear */
1244 GLint y;
1245 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1246 const GLstencil mask = ctx->Stencil.WriteMask;
1247 const GLstencil invMask = ~mask;
1248 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1249 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
1250 GLint i;
1251 for (i = 0; i < width; i++) {
1252 stencil[i] = (stencil[i] & invMask) | clearVal;
1253 }
1254 }
1255 }
1256 else {
1257 /* no masking */
1258 GLint y;
1259 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1260 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
1261 #if STENCIL_BITS==8
1262 MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) );
1263 #else
1264 GLint i;
1265 for (i = 0; i < width; i++)
1266 stencil[x] = ctx->Stencil.Clear;
1267 #endif
1268 }
1269 }
1270 }
1271 else {
1272 /* clear whole stencil buffer */
1273 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1274 /* must apply mask to the clear */
1275 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1276 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1277 const GLstencil mask = ctx->Stencil.WriteMask;
1278 const GLstencil invMask = ~mask;
1279 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1280 GLuint i;
1281 for (i = 0; i < n; i++) {
1282 stencil[i] = (stencil[i] & invMask) | clearVal;
1283 }
1284 }
1285 else {
1286 /* clear whole buffer without masking */
1287 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1288 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1289
1290 #if STENCIL_BITS==8
1291 MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) );
1292 #else
1293 GLuint i;
1294 for (i = 0; i < n; i++) {
1295 stencil[i] = ctx->Stencil.Clear;
1296 }
1297 #endif
1298 }
1299 }
1300 }
1301
1302
1303
1304 /*
1305 * Clear the hardware (in graphics card) stencil buffer.
1306 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1307 * functions.
1308 * Actually, if there is a hardware stencil buffer it really should have
1309 * been cleared in Driver.Clear()! However, if the hardware does not
1310 * support scissored clears or masked clears (i.e. glStencilMask) then
1311 * we have to use the span-based functions.
1312 */
1313 static void
1314 clear_hardware_stencil_buffer( GLcontext *ctx )
1315 {
1316 ASSERT(ctx->Driver.WriteStencilSpan);
1317 ASSERT(ctx->Driver.ReadStencilSpan);
1318
1319 if (ctx->Scissor.Enabled) {
1320 /* clear scissor region only */
1321 const GLint x = ctx->DrawBuffer->Xmin;
1322 const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
1323 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1324 /* must apply mask to the clear */
1325 GLint y;
1326 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1327 const GLstencil mask = ctx->Stencil.WriteMask;
1328 const GLstencil invMask = ~mask;
1329 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1330 GLstencil stencil[MAX_WIDTH];
1331 GLint i;
1332 (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
1333 for (i = 0; i < width; i++) {
1334 stencil[i] = (stencil[i] & invMask) | clearVal;
1335 }
1336 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1337 }
1338 }
1339 else {
1340 /* no masking */
1341 GLstencil stencil[MAX_WIDTH];
1342 GLint y, i;
1343 for (i = 0; i < width; i++) {
1344 stencil[i] = ctx->Stencil.Clear;
1345 }
1346 for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1347 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1348 }
1349 }
1350 }
1351 else {
1352 /* clear whole stencil buffer */
1353 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1354 /* must apply mask to the clear */
1355 const GLstencil mask = ctx->Stencil.WriteMask;
1356 const GLstencil invMask = ~mask;
1357 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1358 const GLint width = ctx->DrawBuffer->Width;
1359 const GLint height = ctx->DrawBuffer->Height;
1360 const GLint x = ctx->DrawBuffer->Xmin;
1361 GLint y;
1362 for (y = 0; y < height; y++) {
1363 GLstencil stencil[MAX_WIDTH];
1364 GLuint i;
1365 (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
1366 for (i = 0; i < width; i++) {
1367 stencil[i] = (stencil[i] & invMask) | clearVal;
1368 }
1369 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1370 }
1371 }
1372 else {
1373 /* clear whole buffer without masking */
1374 const GLint width = ctx->DrawBuffer->Width;
1375 const GLint height = ctx->DrawBuffer->Width;
1376 const GLint x = ctx->DrawBuffer->Xmin;
1377 GLstencil stencil[MAX_WIDTH];
1378 GLint y, i;
1379 for (i = 0; i < width; i++) {
1380 stencil[i] = ctx->Stencil.Clear;
1381 }
1382 for (y = 0; y < height; y++) {
1383 (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1384 }
1385 }
1386 }
1387 }
1388
1389
1390
1391 /*
1392 * Clear the stencil buffer.
1393 */
1394 void gl_clear_stencil_buffer( GLcontext *ctx )
1395 {
1396 if (ctx->Driver.WriteStencilSpan) {
1397 ASSERT(ctx->Driver.ReadStencilSpan);
1398 clear_hardware_stencil_buffer(ctx);
1399 }
1400 else {
1401 clear_software_stencil_buffer(ctx);
1402 }
1403 }
1404