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