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