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