775868cb677696475072e2b04ffa63dbc900ad1a
1 /* $Id: s_stencil.c,v 1.25 2002/08/07 00:45:07 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
33 #include "s_context.h"
35 #include "s_stencil.h"
41 IF stencil test fails THEN
42 Apply fail-op to stencil value
43 Don't write the pixel (RGBA,Z)
45 IF doing depth test && depth test fails THEN
46 Apply zfail-op to stencil value
47 Write RGBA and Z to appropriate buffers
49 Apply zpass-op to stencil value
56 * Return the address of a stencil buffer value given the window coords:
58 #define STENCIL_ADDRESS(X,Y) \
59 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
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
73 apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
74 GLuint n
, GLstencil stencil
[], const GLubyte mask
[] )
76 const GLstencil ref
= ctx
->Stencil
.Ref
;
77 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
78 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
96 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
112 GLstencil s
= stencil
[i
];
113 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
122 GLstencil s
= stencil
[i
];
123 if (s
< STENCIL_MAX
) {
124 stencil
[i
] = (GLstencil
) (s
+1);
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)));
145 GLstencil s
= stencil
[i
];
147 stencil
[i
] = (GLstencil
) (s
-1);
155 /* VERIFY logic of subtracting 1 to a write-masked value */
156 GLstencil s
= stencil
[i
];
158 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
164 case GL_INCR_WRAP_EXT
:
175 GLstencil s
= stencil
[i
];
176 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
181 case GL_DECR_WRAP_EXT
:
192 GLstencil s
= stencil
[i
];
193 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
202 GLstencil s
= stencil
[i
];
203 stencil
[i
] = (GLstencil
) ~s
;
210 GLstencil s
= stencil
[i
];
211 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
217 _mesa_problem(ctx
, "Bad stencil op in apply_stencil_op");
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.
235 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
238 GLubyte fail
[MAX_WIDTH
];
239 GLboolean allfail
= GL_FALSE
;
243 ASSERT(n
<= MAX_WIDTH
);
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
251 * the stencil fail operator is not to be applied
254 switch (ctx
->Stencil
.Function
) {
256 /* never pass; always fail */
269 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
272 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
288 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
291 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
307 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
310 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
326 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
329 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
345 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
348 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
364 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
367 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
389 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_span");
393 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
394 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
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
415 stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
)
417 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
418 GLstencil stencilRow
[MAX_WIDTH
];
420 const GLuint n
= span
->end
;
421 const GLint x
= span
->x
;
422 const GLint y
= span
->y
;
423 GLubyte
*mask
= span
->array
->mask
;
425 ASSERT((span
->arrayMask
& SPAN_XY
) == 0);
426 ASSERT(ctx
->Stencil
.Enabled
);
427 ASSERT(n
<= MAX_WIDTH
);
429 if (ctx
->Depth
.Test
) {
430 ASSERT(span
->arrayMask
& SPAN_Z
);
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
;
442 /* Get pointer into software stencil buffer */
443 stencil
= STENCIL_ADDRESS(x
, y
);
447 * Apply the stencil test to the fragments.
448 * failMask[i] is 1 if the stencil test failed.
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
;
457 * Some fragments passed the stencil test, apply depth test to them
458 * and apply Zpass and Zfail stencil ops.
460 if (ctx
->Depth
.Test
== GL_FALSE
) {
462 * No depth buffer, just apply zpass stencil function to active pixels.
464 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
468 * Perform depth buffering, then apply zpass or zfail stencil function.
470 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
473 /* save the current mask bits */
474 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
476 /* apply the depth test */
477 _mesa_depth_test_span(ctx
, span
);
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
485 * assert(oldmask[i] && !newmask[i])
490 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
491 passmask
[i
] = oldmask
[i
] & mask
[i
];
492 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
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
);
499 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
500 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
505 * Write updated stencil values back into hardware stencil buffer.
507 if (swrast
->Driver
.WriteStencilSpan
) {
508 ASSERT(stencil
== stencilRow
);
509 (swrast
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
512 span
->writeAll
= GL_FALSE
;
514 return GL_TRUE
; /* one or more fragments passed both tests */
521 * Apply the given stencil operator for each pixel in the array whose
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
530 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
531 GLuint n
, const GLint x
[], const GLint y
[],
532 GLenum oper
, const GLubyte mask
[] )
534 const GLstencil ref
= ctx
->Stencil
.Ref
;
535 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
536 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
539 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
549 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
557 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
558 *sptr
= (GLstencil
) (invmask
& *sptr
);
567 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
575 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
576 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
585 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
586 if (*sptr
< STENCIL_MAX
) {
587 *sptr
= (GLstencil
) (*sptr
+ 1);
595 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
596 if (*sptr
< STENCIL_MAX
) {
597 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
607 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
609 *sptr
= (GLstencil
) (*sptr
- 1);
617 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
619 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
625 case GL_INCR_WRAP_EXT
:
629 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
630 *sptr
= (GLstencil
) (*sptr
+ 1);
637 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
638 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
643 case GL_DECR_WRAP_EXT
:
647 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
648 *sptr
= (GLstencil
) (*sptr
- 1);
655 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
656 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
665 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
666 *sptr
= (GLstencil
) (~*sptr
);
673 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
674 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
680 _mesa_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
687 * Apply stencil test to an array of pixels before depth buffering.
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.
698 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
699 const GLint x
[], const GLint y
[], GLubyte mask
[] )
701 GLubyte fail
[MAX_WIDTH
];
704 GLboolean allfail
= GL_FALSE
;
706 /* software stencil buffer only! */
707 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
708 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.ReadStencilSpan
);
709 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
);
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
717 * the stencil fail operator is not to be applied
721 switch (ctx
->Stencil
.Function
) {
736 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
739 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
740 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
756 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
759 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
760 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
776 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
779 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
780 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
796 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
799 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
800 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
816 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
819 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
820 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
836 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
839 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
840 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
862 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
866 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
867 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
877 * Apply stencil and depth testing to an array of pixels.
878 * This is used both for software and hardware stencil buffers.
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
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
893 stencil_and_ztest_pixels( GLcontext
*ctx
, struct sw_span
*span
)
895 const GLuint n
= span
->end
;
896 const GLint
*x
= span
->array
->x
;
897 const GLint
*y
= span
->array
->y
;
898 GLubyte
*mask
= span
->array
->mask
;
899 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
901 ASSERT(span
->arrayMask
& SPAN_XY
);
902 ASSERT(ctx
->Stencil
.Enabled
);
903 ASSERT(n
<= MAX_WIDTH
);
905 if (swrast
->Driver
.WriteStencilPixels
) {
906 /*** Hardware stencil buffer ***/
907 GLstencil stencil
[MAX_WIDTH
];
908 GLubyte origMask
[MAX_WIDTH
];
910 ASSERT(!ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
911 ASSERT(swrast
->Driver
.ReadStencilPixels
);
912 (*swrast
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
914 MEMCPY(origMask
, mask
, n
* sizeof(GLubyte
));
916 (void) do_stencil_test(ctx
, n
, stencil
, mask
);
918 if (ctx
->Depth
.Test
== GL_FALSE
) {
919 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
922 _mesa_depth_test_span(ctx
, span
);
924 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
925 GLubyte failmask
[MAX_WIDTH
];
927 for (i
= 0; i
< n
; i
++) {
928 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
929 failmask
[i
] = origMask
[i
] & (mask
[i
] ^ 1);
931 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
,
932 n
, stencil
, failmask
);
934 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
935 GLubyte passmask
[MAX_WIDTH
];
937 for (i
= 0; i
< n
; i
++) {
938 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
939 passmask
[i
] = origMask
[i
] & mask
[i
];
941 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
,
942 n
, stencil
, passmask
);
946 /* Write updated stencil values into hardware stencil buffer */
947 (swrast
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, origMask
);
952 /*** Software stencil buffer ***/
954 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
956 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
957 /* all fragments failed the stencil test, we're done. */
961 if (ctx
->Depth
.Test
==GL_FALSE
) {
962 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
963 ctx
->Stencil
.ZPassFunc
, mask
);
966 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
969 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
971 _mesa_depth_test_span(ctx
, span
);
974 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
975 passmask
[i
] = oldmask
[i
] & mask
[i
];
976 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
979 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
980 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
981 ctx
->Stencil
.ZFailFunc
, failmask
);
983 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
984 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
985 ctx
->Stencil
.ZPassFunc
, passmask
);
989 return GL_TRUE
; /* one or more fragments passed both tests */
995 * /return GL_TRUE = one or more fragments passed,
996 * GL_FALSE = all fragments failed.
999 _mesa_stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
)
1001 if (span
->arrayMask
& SPAN_XY
)
1002 return stencil_and_ztest_pixels(ctx
, span
);
1004 return stencil_and_ztest_span(ctx
, span
);
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
1016 _mesa_read_stencil_span( GLcontext
*ctx
,
1017 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1019 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1020 const GLint bufWidth
= (GLint
) ctx
->DrawBuffer
->Width
;
1021 const GLint bufHeight
= (GLint
) ctx
->DrawBuffer
->Height
;
1023 if (y
< 0 || y
>= bufHeight
|| x
+ n
<= 0 || x
>= bufWidth
) {
1024 /* span is completely outside framebuffer */
1025 return; /* undefined values OK */
1034 if (x
+ n
> bufWidth
) {
1035 GLint dx
= x
+ n
- bufWidth
;
1044 if (swrast
->Driver
.ReadStencilSpan
) {
1045 (*swrast
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1047 else if (ctx
->DrawBuffer
->Stencil
) {
1048 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1049 #if STENCIL_BITS == 8
1050 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1062 * Write a span of stencil values to the stencil buffer.
1063 * Used for glDraw/CopyPixels
1064 * Input: n - how many pixels
1065 * x, y - location of first pixel
1066 * stencil - the array of stencil values
1069 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1070 const GLstencil stencil
[] )
1072 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1073 const GLstencil
*ssrc
= stencil
;
1074 const GLint bufWidth
= (GLint
) ctx
->DrawBuffer
->Width
;
1075 const GLint bufHeight
= (GLint
) ctx
->DrawBuffer
->Height
;
1077 if (y
< 0 || y
>= bufHeight
|| x
+ n
<= 0 || x
>= bufWidth
) {
1078 /* span is completely outside framebuffer */
1079 return; /* undefined values OK */
1088 if (x
+ n
> bufWidth
) {
1089 GLint dx
= x
+ n
- bufWidth
;
1096 if (swrast
->Driver
.WriteStencilSpan
) {
1097 (*swrast
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, ssrc
, NULL
);
1099 else if (ctx
->DrawBuffer
->Stencil
) {
1100 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1101 #if STENCIL_BITS == 8
1102 MEMCPY( s
, ssrc
, n
* sizeof(GLstencil
) );
1114 * Allocate a new stencil buffer. If there's an old one it will be
1115 * deallocated first. The new stencil buffer will be uninitialized.
1118 _mesa_alloc_stencil_buffer( GLframebuffer
*buffer
)
1120 /* deallocate current stencil buffer if present */
1121 if (buffer
->Stencil
) {
1122 MESA_PBUFFER_FREE(buffer
->Stencil
);
1123 buffer
->Stencil
= NULL
;
1126 /* allocate new stencil buffer */
1127 buffer
->Stencil
= (GLstencil
*)
1128 MESA_PBUFFER_ALLOC(buffer
->Width
* buffer
->Height
* sizeof(GLstencil
));
1129 if (!buffer
->Stencil
) {
1131 _mesa_error( NULL
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1138 * Clear the software (malloc'd) stencil buffer.
1141 clear_software_stencil_buffer( GLcontext
*ctx
)
1143 if (ctx
->Visual
.stencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1144 /* no stencil buffer */
1148 if (ctx
->Scissor
.Enabled
) {
1149 /* clear scissor region only */
1150 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1151 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1152 /* must apply mask to the clear */
1154 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1155 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1156 const GLstencil invMask
= ~mask
;
1157 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1158 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1160 for (i
= 0; i
< width
; i
++) {
1161 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1168 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1169 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1171 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1174 for (i
= 0; i
< width
; i
++)
1175 stencil
[x
] = ctx
->Stencil
.Clear
;
1181 /* clear whole stencil buffer */
1182 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1183 /* must apply mask to the clear */
1184 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1185 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1186 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1187 const GLstencil invMask
= ~mask
;
1188 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1190 for (i
= 0; i
< n
; i
++) {
1191 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1195 /* clear whole buffer without masking */
1196 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1197 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1200 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1203 for (i
= 0; i
< n
; i
++) {
1204 stencil
[i
] = ctx
->Stencil
.Clear
;
1214 * Clear the hardware (in graphics card) stencil buffer.
1215 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1217 * Actually, if there is a hardware stencil buffer it really should have
1218 * been cleared in Driver.Clear()! However, if the hardware does not
1219 * support scissored clears or masked clears (i.e. glStencilMask) then
1220 * we have to use the span-based functions.
1223 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1225 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1226 ASSERT(swrast
->Driver
.WriteStencilSpan
);
1227 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1229 if (ctx
->Scissor
.Enabled
) {
1230 /* clear scissor region only */
1231 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1232 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1233 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1234 /* must apply mask to the clear */
1236 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1237 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1238 const GLstencil invMask
= ~mask
;
1239 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1240 GLstencil stencil
[MAX_WIDTH
];
1242 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1243 for (i
= 0; i
< width
; i
++) {
1244 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1246 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1251 GLstencil stencil
[MAX_WIDTH
];
1253 for (i
= 0; i
< width
; i
++) {
1254 stencil
[i
] = ctx
->Stencil
.Clear
;
1256 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1257 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1262 /* clear whole stencil buffer */
1263 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1264 /* must apply mask to the clear */
1265 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1266 const GLstencil invMask
= ~mask
;
1267 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1268 const GLint width
= ctx
->DrawBuffer
->Width
;
1269 const GLint height
= ctx
->DrawBuffer
->Height
;
1270 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1272 for (y
= 0; y
< height
; y
++) {
1273 GLstencil stencil
[MAX_WIDTH
];
1275 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1276 for (i
= 0; i
< width
; i
++) {
1277 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1279 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1283 /* clear whole buffer without masking */
1284 const GLint width
= ctx
->DrawBuffer
->Width
;
1285 const GLint height
= ctx
->DrawBuffer
->Height
;
1286 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1287 GLstencil stencil
[MAX_WIDTH
];
1289 for (i
= 0; i
< width
; i
++) {
1290 stencil
[i
] = ctx
->Stencil
.Clear
;
1292 for (y
= 0; y
< height
; y
++) {
1293 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1302 * Clear the stencil buffer (hardware or software).
1305 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1307 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1308 if (swrast
->Driver
.WriteStencilSpan
) {
1309 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1310 clear_hardware_stencil_buffer(ctx
);
1313 clear_software_stencil_buffer(ctx
);