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