Use MESA_PBUFFER_ALLOC/FREE macros to allocate all framebuffer and texture
[mesa.git] / src / mesa / swrast / s_stencil.c
1 /* $Id: s_stencil.c,v 1.22 2002/03/19 16:47:05 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( GLframebuffer *buffer )
1116 {
1117 /* deallocate current stencil buffer if present */
1118 if (buffer->Stencil) {
1119 MESA_PBUFFER_FREE(buffer->Stencil);
1120 buffer->Stencil = NULL;
1121 }
1122
1123 /* allocate new stencil buffer */
1124 buffer->Stencil = (GLstencil *)
1125 MESA_PBUFFER_ALLOC(buffer->Width * buffer->Height * sizeof(GLstencil));
1126 if (!buffer->Stencil) {
1127 /* out of memory */
1128 _mesa_error( NULL, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" );
1129 }
1130 }
1131
1132
1133
1134 /**
1135 * Clear the software (malloc'd) stencil buffer.
1136 */
1137 static void
1138 clear_software_stencil_buffer( GLcontext *ctx )
1139 {
1140 if (ctx->Visual.stencilBits==0 || !ctx->DrawBuffer->Stencil) {
1141 /* no stencil buffer */
1142 return;
1143 }
1144
1145 if (ctx->Scissor.Enabled) {
1146 /* clear scissor region only */
1147 const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
1148 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1149 /* must apply mask to the clear */
1150 GLint y;
1151 for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) {
1152 const GLstencil mask = ctx->Stencil.WriteMask;
1153 const GLstencil invMask = ~mask;
1154 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1155 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->_Xmin, y );
1156 GLint i;
1157 for (i = 0; i < width; i++) {
1158 stencil[i] = (stencil[i] & invMask) | clearVal;
1159 }
1160 }
1161 }
1162 else {
1163 /* no masking */
1164 GLint y;
1165 for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) {
1166 GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->_Xmin, y );
1167 #if STENCIL_BITS==8
1168 MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) );
1169 #else
1170 GLint i;
1171 for (i = 0; i < width; i++)
1172 stencil[x] = ctx->Stencil.Clear;
1173 #endif
1174 }
1175 }
1176 }
1177 else {
1178 /* clear whole stencil buffer */
1179 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1180 /* must apply mask to the clear */
1181 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1182 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1183 const GLstencil mask = ctx->Stencil.WriteMask;
1184 const GLstencil invMask = ~mask;
1185 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1186 GLuint i;
1187 for (i = 0; i < n; i++) {
1188 stencil[i] = (stencil[i] & invMask) | clearVal;
1189 }
1190 }
1191 else {
1192 /* clear whole buffer without masking */
1193 const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1194 GLstencil *stencil = ctx->DrawBuffer->Stencil;
1195
1196 #if STENCIL_BITS==8
1197 MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) );
1198 #else
1199 GLuint i;
1200 for (i = 0; i < n; i++) {
1201 stencil[i] = ctx->Stencil.Clear;
1202 }
1203 #endif
1204 }
1205 }
1206 }
1207
1208
1209
1210 /**
1211 * Clear the hardware (in graphics card) stencil buffer.
1212 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1213 * functions.
1214 * Actually, if there is a hardware stencil buffer it really should have
1215 * been cleared in Driver.Clear()! However, if the hardware does not
1216 * support scissored clears or masked clears (i.e. glStencilMask) then
1217 * we have to use the span-based functions.
1218 */
1219 static void
1220 clear_hardware_stencil_buffer( GLcontext *ctx )
1221 {
1222 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1223 ASSERT(swrast->Driver.WriteStencilSpan);
1224 ASSERT(swrast->Driver.ReadStencilSpan);
1225
1226 if (ctx->Scissor.Enabled) {
1227 /* clear scissor region only */
1228 const GLint x = ctx->DrawBuffer->_Xmin;
1229 const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
1230 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1231 /* must apply mask to the clear */
1232 GLint y;
1233 for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) {
1234 const GLstencil mask = ctx->Stencil.WriteMask;
1235 const GLstencil invMask = ~mask;
1236 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1237 GLstencil stencil[MAX_WIDTH];
1238 GLint i;
1239 (*swrast->Driver.ReadStencilSpan)(ctx, width, x, y, stencil);
1240 for (i = 0; i < width; i++) {
1241 stencil[i] = (stencil[i] & invMask) | clearVal;
1242 }
1243 (*swrast->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL);
1244 }
1245 }
1246 else {
1247 /* no masking */
1248 GLstencil stencil[MAX_WIDTH];
1249 GLint y, i;
1250 for (i = 0; i < width; i++) {
1251 stencil[i] = ctx->Stencil.Clear;
1252 }
1253 for (y = ctx->DrawBuffer->_Ymin; y < ctx->DrawBuffer->_Ymax; y++) {
1254 (*swrast->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL);
1255 }
1256 }
1257 }
1258 else {
1259 /* clear whole stencil buffer */
1260 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1261 /* must apply mask to the clear */
1262 const GLstencil mask = ctx->Stencil.WriteMask;
1263 const GLstencil invMask = ~mask;
1264 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1265 const GLint width = ctx->DrawBuffer->Width;
1266 const GLint height = ctx->DrawBuffer->Height;
1267 const GLint x = ctx->DrawBuffer->_Xmin;
1268 GLint y;
1269 for (y = 0; y < height; y++) {
1270 GLstencil stencil[MAX_WIDTH];
1271 GLint i;
1272 (*swrast->Driver.ReadStencilSpan)(ctx, width, x, y, stencil);
1273 for (i = 0; i < width; i++) {
1274 stencil[i] = (stencil[i] & invMask) | clearVal;
1275 }
1276 (*swrast->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL);
1277 }
1278 }
1279 else {
1280 /* clear whole buffer without masking */
1281 const GLint width = ctx->DrawBuffer->Width;
1282 const GLint height = ctx->DrawBuffer->Height;
1283 const GLint x = ctx->DrawBuffer->_Xmin;
1284 GLstencil stencil[MAX_WIDTH];
1285 GLint y, i;
1286 for (i = 0; i < width; i++) {
1287 stencil[i] = ctx->Stencil.Clear;
1288 }
1289 for (y = 0; y < height; y++) {
1290 (*swrast->Driver.WriteStencilSpan)(ctx, width, x, y, stencil, NULL);
1291 }
1292 }
1293 }
1294 }
1295
1296
1297
1298 /**
1299 * Clear the stencil buffer (hardware or software).
1300 */
1301 void
1302 _mesa_clear_stencil_buffer( GLcontext *ctx )
1303 {
1304 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1305 if (swrast->Driver.WriteStencilSpan) {
1306 ASSERT(swrast->Driver.ReadStencilSpan);
1307 clear_hardware_stencil_buffer(ctx);
1308 }
1309 else {
1310 clear_software_stencil_buffer(ctx);
1311 }
1312 }