488ccc0559ff2c76275fbd9e8f859bc4de887413
[mesa.git] / src / mesa / swrast / s_stencil.c
1 /* $Id: s_stencil.c,v 1.13 2001/12/17 04:54:35 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 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 _mesa_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 _mesa_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 _old_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 _old_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
506 const GLdepth z[], GLubyte mask[] )
507 {
508 SWcontext *swrast = SWRAST_CONTEXT(ctx);
509 GLstencil stencilRow[MAX_WIDTH];
510 GLstencil *stencil;
511 GLboolean result;
512
513 ASSERT(ctx->Stencil.Enabled);
514 ASSERT(n <= MAX_WIDTH);
515
516 /* Get initial stencil values */
517 if (swrast->Driver.WriteStencilSpan) {
518 ASSERT(swrast->Driver.ReadStencilSpan);
519 /* Get stencil values from the hardware stencil buffer */
520 (*swrast->Driver.ReadStencilSpan)(ctx, n, x, y, stencilRow);
521 stencil = stencilRow;
522 }
523 else {
524 /* software stencil buffer */
525 stencil = STENCIL_ADDRESS(x, y);
526 }
527
528 /* do all the stencil/depth testing/updating */
529 result = stencil_and_ztest_span( ctx, n, x, y, z, stencil, mask );
530
531 if (swrast->Driver.WriteStencilSpan) {
532 /* Write updated stencil values into hardware stencil buffer */
533 (swrast->Driver.WriteStencilSpan)(ctx, n, x, y, stencil, mask );
534 }
535
536 return result;
537 }
538
539 /*
540 * Apply stencil and depth testing to the span of pixels.
541 * Both software and hardware stencil buffers are acceptable.
542 * Input: n - number of pixels in the span
543 * x, y - location of leftmost pixel in span
544 * z - array [n] of z values
545 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
546 * Output: mask - array [n] of flags (1=stencil and depth test passed)
547 * Return: GL_TRUE - all fragments failed the testing
548 * GL_FALSE - one or more fragments passed the testing
549 *
550 */
551 GLboolean
552 _mesa_stencil_and_ztest_span(GLcontext *ctx, struct sw_span *span)
553 {
554 SWcontext *swrast = SWRAST_CONTEXT(ctx);
555
556 GLstencil stencilRow[MAX_WIDTH];
557 GLstencil *stencil;
558 GLboolean result;
559
560 ASSERT(ctx->Stencil.Enabled);
561 ASSERT(span->end <= MAX_WIDTH);
562 ASSERT(span->filledMask == GL_TRUE);
563 ASSERT(span->filledDepth == GL_TRUE);
564 SW_SPAN_SET_FLAG(span->testedDepth);
565
566
567 /* Get initial stencil values */
568 if (swrast->Driver.WriteStencilSpan) {
569 ASSERT(swrast->Driver.ReadStencilSpan);
570 /* Get stencil values from the hardware stencil buffer */
571 (*swrast->Driver.ReadStencilSpan)(ctx, span->end, span->x, span->y, stencilRow);
572 stencil = stencilRow;
573 }
574 else {
575 /* software stencil buffer */
576 stencil = STENCIL_ADDRESS(span->x, span->y);
577 }
578
579 /* do all the stencil/depth testing/updating */
580 result = stencil_and_ztest_span( ctx, span->end, span->x, span->y,
581 span->depth, stencil, span->mask );
582
583 if (swrast->Driver.WriteStencilSpan) {
584 /* Write updated stencil values into hardware stencil buffer */
585 (swrast->Driver.WriteStencilSpan)(ctx, span->end, span->x,
586 span->y, stencil, span->mask );
587 }
588
589 span->write_all = GL_FALSE;
590
591 return result;
592 }
593
594
595
596
597 /*
598 * Apply the given stencil operator for each pixel in the array whose
599 * mask flag is set. This is for software stencil buffers only.
600 * Input: n - number of pixels in the span
601 * x, y - array of [n] pixels
602 * operator - the stencil buffer operator
603 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
604 */
605 static void
606 apply_stencil_op_to_pixels( const GLcontext *ctx,
607 GLuint n, const GLint x[], const GLint y[],
608 GLenum oper, const GLubyte mask[] )
609 {
610 const GLstencil ref = ctx->Stencil.Ref;
611 const GLstencil wrtmask = ctx->Stencil.WriteMask;
612 const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
613 GLuint i;
614
615 ASSERT(!SWRAST_CONTEXT(ctx)->Driver.WriteStencilSpan); /* software stencil buffer only! */
616
617 switch (oper) {
618 case GL_KEEP:
619 /* do nothing */
620 break;
621 case GL_ZERO:
622 if (invmask==0) {
623 for (i=0;i<n;i++) {
624 if (mask[i]) {
625 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
626 *sptr = 0;
627 }
628 }
629 }
630 else {
631 for (i=0;i<n;i++) {
632 if (mask[i]) {
633 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
634 *sptr = (GLstencil) (invmask & *sptr);
635 }
636 }
637 }
638 break;
639 case GL_REPLACE:
640 if (invmask==0) {
641 for (i=0;i<n;i++) {
642 if (mask[i]) {
643 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
644 *sptr = ref;
645 }
646 }
647 }
648 else {
649 for (i=0;i<n;i++) {
650 if (mask[i]) {
651 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
652 *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref));
653 }
654 }
655 }
656 break;
657 case GL_INCR:
658 if (invmask==0) {
659 for (i=0;i<n;i++) {
660 if (mask[i]) {
661 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
662 if (*sptr < STENCIL_MAX) {
663 *sptr = (GLstencil) (*sptr + 1);
664 }
665 }
666 }
667 }
668 else {
669 for (i=0;i<n;i++) {
670 if (mask[i]) {
671 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
672 if (*sptr < STENCIL_MAX) {
673 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
674 }
675 }
676 }
677 }
678 break;
679 case GL_DECR:
680 if (invmask==0) {
681 for (i=0;i<n;i++) {
682 if (mask[i]) {
683 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
684 if (*sptr>0) {
685 *sptr = (GLstencil) (*sptr - 1);
686 }
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 if (*sptr>0) {
695 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
696 }
697 }
698 }
699 }
700 break;
701 case GL_INCR_WRAP_EXT:
702 if (invmask==0) {
703 for (i=0;i<n;i++) {
704 if (mask[i]) {
705 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
706 *sptr = (GLstencil) (*sptr + 1);
707 }
708 }
709 }
710 else {
711 for (i=0;i<n;i++) {
712 if (mask[i]) {
713 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
714 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
715 }
716 }
717 }
718 break;
719 case GL_DECR_WRAP_EXT:
720 if (invmask==0) {
721 for (i=0;i<n;i++) {
722 if (mask[i]) {
723 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
724 *sptr = (GLstencil) (*sptr - 1);
725 }
726 }
727 }
728 else {
729 for (i=0;i<n;i++) {
730 if (mask[i]) {
731 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
732 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
733 }
734 }
735 }
736 break;
737 case GL_INVERT:
738 if (invmask==0) {
739 for (i=0;i<n;i++) {
740 if (mask[i]) {
741 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
742 *sptr = (GLstencil) (~*sptr);
743 }
744 }
745 }
746 else {
747 for (i=0;i<n;i++) {
748 if (mask[i]) {
749 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
750 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr));
751 }
752 }
753 }
754 break;
755 default:
756 _mesa_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
757 }
758 }
759
760
761
762 /*
763 * Apply stencil test to an array of pixels before depth buffering.
764 * Used for software stencil buffer only.
765 * Input: n - number of pixels in the span
766 * x, y - array of [n] pixels to stencil
767 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
768 * Output: mask - pixels which fail the stencil test will have their
769 * mask flag set to 0.
770 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
771 */
772 static GLboolean
773 stencil_test_pixels( GLcontext *ctx, GLuint n,
774 const GLint x[], const GLint y[], GLubyte mask[] )
775 {
776 GLubyte fail[PB_SIZE];
777 GLstencil r, s;
778 GLuint i;
779 GLboolean allfail = GL_FALSE;
780
781 ASSERT(!SWRAST_CONTEXT(ctx)->Driver.WriteStencilSpan); /* software stencil buffer only! */
782
783 /*
784 * Perform stencil test. The results of this operation are stored
785 * in the fail[] array:
786 * IF fail[i] is non-zero THEN
787 * the stencil fail operator is to be applied
788 * ELSE
789 * the stencil fail operator is not to be applied
790 * ENDIF
791 */
792
793 switch (ctx->Stencil.Function) {
794 case GL_NEVER:
795 /* always fail */
796 for (i=0;i<n;i++) {
797 if (mask[i]) {
798 mask[i] = 0;
799 fail[i] = 1;
800 }
801 else {
802 fail[i] = 0;
803 }
804 }
805 allfail = GL_TRUE;
806 break;
807 case GL_LESS:
808 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
809 for (i=0;i<n;i++) {
810 if (mask[i]) {
811 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
812 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
813 if (r < s) {
814 /* passed */
815 fail[i] = 0;
816 }
817 else {
818 fail[i] = 1;
819 mask[i] = 0;
820 }
821 }
822 else {
823 fail[i] = 0;
824 }
825 }
826 break;
827 case GL_LEQUAL:
828 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
829 for (i=0;i<n;i++) {
830 if (mask[i]) {
831 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
832 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
833 if (r <= s) {
834 /* pass */
835 fail[i] = 0;
836 }
837 else {
838 fail[i] = 1;
839 mask[i] = 0;
840 }
841 }
842 else {
843 fail[i] = 0;
844 }
845 }
846 break;
847 case GL_GREATER:
848 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
849 for (i=0;i<n;i++) {
850 if (mask[i]) {
851 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
852 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
853 if (r > s) {
854 /* passed */
855 fail[i] = 0;
856 }
857 else {
858 fail[i] = 1;
859 mask[i] = 0;
860 }
861 }
862 else {
863 fail[i] = 0;
864 }
865 }
866 break;
867 case GL_GEQUAL:
868 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
869 for (i=0;i<n;i++) {
870 if (mask[i]) {
871 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
872 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
873 if (r >= s) {
874 /* passed */
875 fail[i] = 0;
876 }
877 else {
878 fail[i] = 1;
879 mask[i] = 0;
880 }
881 }
882 else {
883 fail[i] = 0;
884 }
885 }
886 break;
887 case GL_EQUAL:
888 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
889 for (i=0;i<n;i++) {
890 if (mask[i]) {
891 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
892 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
893 if (r == s) {
894 /* passed */
895 fail[i] = 0;
896 }
897 else {
898 fail[i] = 1;
899 mask[i] = 0;
900 }
901 }
902 else {
903 fail[i] = 0;
904 }
905 }
906 break;
907 case GL_NOTEQUAL:
908 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
909 for (i=0;i<n;i++) {
910 if (mask[i]) {
911 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
912 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
913 if (r != s) {
914 /* passed */
915 fail[i] = 0;
916 }
917 else {
918 fail[i] = 1;
919 mask[i] = 0;
920 }
921 }
922 else {
923 fail[i] = 0;
924 }
925 }
926 break;
927 case GL_ALWAYS:
928 /* always pass */
929 for (i=0;i<n;i++) {
930 fail[i] = 0;
931 }
932 break;
933 default:
934 _mesa_problem(ctx, "Bad stencil func in gl_stencil_pixels");
935 return 0;
936 }
937
938 if (ctx->Stencil.FailFunc != GL_KEEP) {
939 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
940 }
941
942 return !allfail;
943 }
944
945
946
947
948 /*
949 * Apply stencil and depth testing to an array of pixels.
950 * This is used both for software and hardware stencil buffers.
951 *
952 * The comments in this function are a bit sparse but the code is
953 * almost identical to stencil_and_ztest_span(), which is well
954 * commented.
955 *
956 * Input: n - number of pixels in the array
957 * x, y - array of [n] pixel positions
958 * z - array [n] of z values
959 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
960 * Output: mask - array [n] of flags (1=stencil and depth test passed)
961 * Return: GL_TRUE - all fragments failed the testing
962 * GL_FALSE - one or more fragments passed the testing
963 */
964 GLboolean
965 _mesa_stencil_and_ztest_pixels( GLcontext *ctx,
966 GLuint n, const GLint x[], const GLint y[],
967 const GLdepth z[], GLubyte mask[] )
968 {
969 SWcontext *swrast = SWRAST_CONTEXT(ctx);
970 ASSERT(ctx->Stencil.Enabled);
971 ASSERT(n <= PB_SIZE);
972
973 if (swrast->Driver.WriteStencilPixels) {
974 /*** Hardware stencil buffer ***/
975 GLstencil stencil[PB_SIZE];
976 GLubyte origMask[PB_SIZE];
977
978 ASSERT(swrast->Driver.ReadStencilPixels);
979 (*swrast->Driver.ReadStencilPixels)(ctx, n, x, y, stencil);
980
981 MEMCPY(origMask, mask, n * sizeof(GLubyte));
982
983 (void) do_stencil_test(ctx, n, stencil, mask);
984
985 if (ctx->Depth.Test == GL_FALSE) {
986 apply_stencil_op(ctx, ctx->Stencil.ZPassFunc, n, stencil, mask);
987 }
988 else {
989 _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
990
991 if (ctx->Stencil.ZFailFunc != GL_KEEP) {
992 GLubyte failmask[PB_SIZE];
993 GLuint i;
994 for (i = 0; i < n; i++) {
995 ASSERT(mask[i] == 0 || mask[i] == 1);
996 failmask[i] = origMask[i] & (mask[i] ^ 1);
997 }
998 apply_stencil_op(ctx, ctx->Stencil.ZFailFunc,
999 n, stencil, failmask);
1000 }
1001 if (ctx->Stencil.ZPassFunc != GL_KEEP) {
1002 GLubyte passmask[PB_SIZE];
1003 GLuint i;
1004 for (i = 0; i < n; i++) {
1005 ASSERT(mask[i] == 0 || mask[i] == 1);
1006 passmask[i] = origMask[i] & mask[i];
1007 }
1008 apply_stencil_op(ctx, ctx->Stencil.ZPassFunc,
1009 n, stencil, passmask);
1010 }
1011 }
1012
1013 /* Write updated stencil values into hardware stencil buffer */
1014 (swrast->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, origMask);
1015
1016 return GL_TRUE;
1017 }
1018 else {
1019 /*** Software stencil buffer ***/
1020
1021 if (stencil_test_pixels(ctx, n, x, y, mask) == GL_FALSE) {
1022 /* all fragments failed the stencil test, we're done. */
1023 return GL_FALSE;
1024 }
1025
1026 if (ctx->Depth.Test==GL_FALSE) {
1027 apply_stencil_op_to_pixels(ctx, n, x, y,
1028 ctx->Stencil.ZPassFunc, mask);
1029 }
1030 else {
1031 GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
1032 GLuint i;
1033
1034 MEMCPY(oldmask, mask, n * sizeof(GLubyte));
1035
1036 _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
1037
1038 for (i=0;i<n;i++) {
1039 ASSERT(mask[i] == 0 || mask[i] == 1);
1040 passmask[i] = oldmask[i] & mask[i];
1041 failmask[i] = oldmask[i] & (mask[i] ^ 1);
1042 }
1043
1044 if (ctx->Stencil.ZFailFunc != GL_KEEP) {
1045 apply_stencil_op_to_pixels(ctx, n, x, y,
1046 ctx->Stencil.ZFailFunc, failmask);
1047 }
1048 if (ctx->Stencil.ZPassFunc != GL_KEEP) {
1049 apply_stencil_op_to_pixels(ctx, n, x, y,
1050 ctx->Stencil.ZPassFunc, passmask);
1051 }
1052 }
1053
1054 return GL_TRUE; /* one or more fragments passed both tests */
1055 }
1056 }
1057
1058
1059
1060 /*
1061 * Return a span of stencil values from the stencil buffer.
1062 * Used for glRead/CopyPixels
1063 * Input: n - how many pixels
1064 * x,y - location of first pixel
1065 * Output: stencil - the array of stencil values
1066 */
1067 void
1068 _mesa_read_stencil_span( GLcontext *ctx,
1069 GLint n, GLint x, GLint y, GLstencil stencil[] )
1070 {
1071 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1072 if (y < 0 || y >= ctx->DrawBuffer->Height ||
1073 x + n <= 0 || x >= ctx->DrawBuffer->Width) {
1074 /* span is completely outside framebuffer */
1075 return; /* undefined values OK */
1076 }
1077
1078 if (x < 0) {
1079 GLint dx = -x;
1080 x = 0;
1081 n -= dx;
1082 stencil += dx;
1083 }
1084 if (x + n > ctx->DrawBuffer->Width) {
1085 GLint dx = x + n - ctx->DrawBuffer->Width;
1086 n -= dx;
1087 }
1088 if (n <= 0) {
1089 return;
1090 }
1091
1092
1093 ASSERT(n >= 0);
1094 if (swrast->Driver.ReadStencilSpan) {
1095 (*swrast->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil );
1096 }
1097 else if (ctx->DrawBuffer->Stencil) {
1098 const GLstencil *s = STENCIL_ADDRESS( x, y );
1099 #if STENCIL_BITS == 8
1100 MEMCPY( stencil, s, n * sizeof(GLstencil) );
1101 #else
1102 GLuint i;
1103 for (i=0;i<n;i++)
1104 stencil[i] = s[i];
1105 #endif
1106 }
1107 }
1108
1109
1110
1111 /*
1112 * Write a span of stencil values to the stencil buffer.
1113 * Used for glDraw/CopyPixels
1114 * Input: n - how many pixels
1115 * x, y - location of first pixel
1116 * stencil - the array of stencil values
1117 */
1118 void
1119 _mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
1120 const GLstencil stencil[] )
1121 {
1122 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1123 if (y < 0 || y >= ctx->DrawBuffer->Height ||
1124 x + n <= 0 || x >= ctx->DrawBuffer->Width) {
1125 /* span is completely outside framebuffer */
1126 return; /* undefined values OK */
1127 }
1128
1129 if (x < 0) {
1130 GLint dx = -x;
1131 x = 0;
1132 n -= dx;
1133 stencil += dx;
1134 }
1135 if (x + n > ctx->DrawBuffer->Width) {
1136 GLint dx = x + n - ctx->DrawBuffer->Width;
1137 n -= dx;
1138 }
1139 if (n <= 0) {
1140 return;
1141 }
1142
1143 if (swrast->Driver.WriteStencilSpan) {
1144 (*swrast->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL );
1145 }
1146 else if (ctx->DrawBuffer->Stencil) {
1147 GLstencil *s = STENCIL_ADDRESS( x, y );
1148 #if STENCIL_BITS == 8
1149 MEMCPY( s, stencil, n * sizeof(GLstencil) );
1150 #else
1151 GLuint i;
1152 for (i=0;i<n;i++)
1153 s[i] = stencil[i];
1154 #endif
1155 }
1156 }
1157
1158
1159
1160 /*
1161 * Allocate a new stencil buffer. If there's an old one it will be
1162 * deallocated first. The new stencil buffer will be uninitialized.
1163 */
1164 void
1165 _mesa_alloc_stencil_buffer( GLcontext *ctx )
1166 {
1167 GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1168
1169 /* deallocate current stencil buffer if present */
1170 if (ctx->DrawBuffer->Stencil) {
1171 FREE(ctx->DrawBuffer->Stencil);
1172 ctx->DrawBuffer->Stencil = NULL;
1173 }
1174
1175 /* allocate new stencil buffer */
1176 ctx->DrawBuffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil));
1177 if (!ctx->DrawBuffer->Stencil) {
1178 /* out of memory */
1179 /* _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); */
1180 _mesa_error( ctx, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" );
1181 }
1182 }
1183
1184
1185
1186 /*
1187 * Clear the software (malloc'd) stencil buffer.
1188 */
1189 static void
1190 clear_software_stencil_buffer( GLcontext *ctx )
1191 {
1192 if (ctx->Visual.stencilBits==0 || !ctx->DrawBuffer->Stencil) {
1193 /* no stencil buffer */
1194 return;
1195 }
1196
1197 if (ctx->Scissor.Enabled) {
1198 /* clear scissor region only */
1199 const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
1200 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1201 /* must apply mask to the clear */
1202 GLint y;
1203 for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) {
1204 const GLstencil mask = ctx->Stencil.WriteMask;
1205 const GLstencil invMask = ~mask;
1206 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1207 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->_Xmin, y );
1208 GLint i;
1209 for (i = 0; i < width; i++) {
1210 stencil[i] = (stencil[i] & invMask) | clearVal;
1211 }
1212 }
1213 }
1214 else {
1215 /* no masking */
1216 GLint y;
1217 for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) {
1218 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->_Xmin, y );
1219 #if STENCIL_BITS==8
1220 MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) );
1221 #else
1222 GLint i;
1223 for (i = 0; i < width; i++)
1224 stencil[x] = ctx->Stencil.Clear;
1225 #endif
1226 }
1227 }
1228 }
1229 else {
1230 /* clear whole stencil buffer */
1231 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1232 /* must apply mask to the clear */
1233 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1234 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1235 const GLstencil mask = ctx->Stencil.WriteMask;
1236 const GLstencil invMask = ~mask;
1237 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1238 GLuint i;
1239 for (i = 0; i < n; i++) {
1240 stencil[i] = (stencil[i] & invMask) | clearVal;
1241 }
1242 }
1243 else {
1244 /* clear whole buffer without masking */
1245 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1246 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1247
1248 #if STENCIL_BITS==8
1249 MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) );
1250 #else
1251 GLuint i;
1252 for (i = 0; i < n; i++) {
1253 stencil[i] = ctx->Stencil.Clear;
1254 }
1255 #endif
1256 }
1257 }
1258 }
1259
1260
1261
1262 /*
1263 * Clear the hardware (in graphics card) stencil buffer.
1264 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1265 * functions.
1266 * Actually, if there is a hardware stencil buffer it really should have
1267 * been cleared in Driver.Clear()! However, if the hardware does not
1268 * support scissored clears or masked clears (i.e. glStencilMask) then
1269 * we have to use the span-based functions.
1270 */
1271 static void
1272 clear_hardware_stencil_buffer( GLcontext *ctx )
1273 {
1274 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1275 ASSERT(swrast->Driver.WriteStencilSpan);
1276 ASSERT(swrast->Driver.ReadStencilSpan);
1277
1278 if (ctx->Scissor.Enabled) {
1279 /* clear scissor region only */
1280 const GLint x = ctx->DrawBuffer->_Xmin;
1281 const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
1282 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1283 /* must apply mask to the clear */
1284 GLint y;
1285 for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) {
1286 const GLstencil mask = ctx->Stencil.WriteMask;
1287 const GLstencil invMask = ~mask;
1288 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1289 GLstencil stencil[MAX_WIDTH];
1290 GLint i;
1291 (*swrast->Driver.ReadStencilSpan)(ctx, width, x, y, stencil);
1292 for (i = 0; i < width; i++) {
1293 stencil[i] = (stencil[i] & invMask) | clearVal;
1294 }
1295 (*swrast->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL);
1296 }
1297 }
1298 else {
1299 /* no masking */
1300 GLstencil stencil[MAX_WIDTH];
1301 GLint y, i;
1302 for (i = 0; i < width; i++) {
1303 stencil[i] = ctx->Stencil.Clear;
1304 }
1305 for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) {
1306 (*swrast->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL);
1307 }
1308 }
1309 }
1310 else {
1311 /* clear whole stencil buffer */
1312 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1313 /* must apply mask to the clear */
1314 const GLstencil mask = ctx->Stencil.WriteMask;
1315 const GLstencil invMask = ~mask;
1316 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1317 const GLint width = ctx->DrawBuffer->Width;
1318 const GLint height = ctx->DrawBuffer->Height;
1319 const GLint x = ctx->DrawBuffer->_Xmin;
1320 GLint y;
1321 for (y = 0; y < height; y++) {
1322 GLstencil stencil[MAX_WIDTH];
1323 GLint i;
1324 (*swrast->Driver.ReadStencilSpan)(ctx, width, x, y, stencil);
1325 for (i = 0; i < width; i++) {
1326 stencil[i] = (stencil[i] & invMask) | clearVal;
1327 }
1328 (*swrast->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL);
1329 }
1330 }
1331 else {
1332 /* clear whole buffer without masking */
1333 const GLint width = ctx->DrawBuffer->Width;
1334 const GLint height = ctx->DrawBuffer->Height;
1335 const GLint x = ctx->DrawBuffer->_Xmin;
1336 GLstencil stencil[MAX_WIDTH];
1337 GLint y, i;
1338 for (i = 0; i < width; i++) {
1339 stencil[i] = ctx->Stencil.Clear;
1340 }
1341 for (y = 0; y < height; y++) {
1342 (*swrast->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL);
1343 }
1344 }
1345 }
1346 }
1347
1348
1349
1350 /*
1351 * Clear the stencil buffer.
1352 */
1353 void
1354 _mesa_clear_stencil_buffer( GLcontext *ctx )
1355 {
1356 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1357 if (swrast->Driver.WriteStencilSpan) {
1358 ASSERT(swrast->Driver.ReadStencilSpan);
1359 clear_hardware_stencil_buffer(ctx);
1360 }
1361 else {
1362 clear_software_stencil_buffer(ctx);
1363 }
1364 }