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