2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #include "s_context.h"
33 #include "s_stencil.h"
39 IF stencil test fails THEN
40 Apply fail-op to stencil value
41 Don't write the pixel (RGBA,Z)
43 IF doing depth test && depth test fails THEN
44 Apply zfail-op to stencil value
45 Write RGBA and Z to appropriate buffers
47 Apply zpass-op to stencil value
54 * Return the address of a stencil buffer value given the window coords:
56 #define STENCIL_ADDRESS(X,Y) \
57 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
62 * Apply the given stencil operator to the array of stencil values.
63 * Don't touch stencil[i] if mask[i] is zero.
64 * Input: n - size of stencil array
65 * oper - the stencil buffer operator
66 * face - 0 or 1 for front or back face operation
67 * stencil - array of stencil values
68 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
69 * Output: stencil - modified values
72 apply_stencil_op( const GLcontext
*ctx
, GLenum oper
, GLuint face
,
73 GLuint n
, GLstencil stencil
[], const GLubyte mask
[] )
75 const GLstencil ref
= ctx
->Stencil
.Ref
[face
];
76 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
[face
];
77 const GLstencil invmask
= (GLstencil
) (~wrtmask
);
95 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
111 GLstencil s
= stencil
[i
];
112 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
121 GLstencil s
= stencil
[i
];
122 if (s
< STENCIL_MAX
) {
123 stencil
[i
] = (GLstencil
) (s
+1);
131 /* VERIFY logic of adding 1 to a write-masked value */
132 GLstencil s
= stencil
[i
];
133 if (s
< STENCIL_MAX
) {
134 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
144 GLstencil s
= stencil
[i
];
146 stencil
[i
] = (GLstencil
) (s
-1);
154 /* VERIFY logic of subtracting 1 to a write-masked value */
155 GLstencil s
= stencil
[i
];
157 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
163 case GL_INCR_WRAP_EXT
:
174 GLstencil s
= stencil
[i
];
175 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
180 case GL_DECR_WRAP_EXT
:
191 GLstencil s
= stencil
[i
];
192 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
201 GLstencil s
= stencil
[i
];
202 stencil
[i
] = (GLstencil
) ~s
;
209 GLstencil s
= stencil
[i
];
210 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
216 _mesa_problem(ctx
, "Bad stencil op in apply_stencil_op");
224 * Apply stencil test to an array of stencil values (before depth buffering).
225 * Input: face - 0 or 1 for front or back-face polygons
226 * 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 face
, GLuint n
, GLstencil stencil
[],
238 GLubyte fail
[MAX_WIDTH
];
239 GLboolean allfail
= GL_FALSE
;
242 const GLuint valueMask
= ctx
->Stencil
.ValueMask
[face
];
244 ASSERT(n
<= MAX_WIDTH
);
247 * Perform stencil test. The results of this operation are stored
248 * in the fail[] array:
249 * IF fail[i] is non-zero THEN
250 * the stencil fail operator is to be applied
252 * the stencil fail operator is not to be applied
255 switch (ctx
->Stencil
.Function
[face
]) {
257 /* never pass; always fail */
270 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
273 s
= (GLstencil
) (stencil
[i
] & valueMask
);
289 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
292 s
= (GLstencil
) (stencil
[i
] & valueMask
);
308 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
311 s
= (GLstencil
) (stencil
[i
] & valueMask
);
327 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
330 s
= (GLstencil
) (stencil
[i
] & valueMask
);
346 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
349 s
= (GLstencil
) (stencil
[i
] & valueMask
);
365 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
368 s
= (GLstencil
) (stencil
[i
] & valueMask
);
390 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_span");
394 if (ctx
->Stencil
.FailFunc
[face
] != GL_KEEP
) {
395 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
[face
], face
, n
, stencil
, fail
);
404 * Apply stencil and depth testing to the span of pixels.
405 * Both software and hardware stencil buffers are acceptable.
406 * Input: n - number of pixels in the span
407 * x, y - location of leftmost pixel in span
408 * z - array [n] of z values
409 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
410 * Output: mask - array [n] of flags (1=stencil and depth test passed)
411 * Return: GL_FALSE - all fragments failed the testing
412 * GL_TRUE - one or more fragments passed the testing
416 stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
, GLuint face
)
418 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
419 GLstencil stencilRow
[MAX_WIDTH
];
421 const GLuint n
= span
->end
;
422 const GLint x
= span
->x
;
423 const GLint y
= span
->y
;
424 GLubyte
*mask
= span
->array
->mask
;
426 ASSERT((span
->arrayMask
& SPAN_XY
) == 0);
427 ASSERT(ctx
->Stencil
.Enabled
);
428 ASSERT(n
<= MAX_WIDTH
);
430 if (ctx
->Depth
.Test
) {
431 ASSERT(span
->arrayMask
& SPAN_Z
);
435 /* Get initial stencil values */
436 if (swrast
->Driver
.WriteStencilSpan
) {
437 /* Get stencil values from the hardware stencil buffer */
438 ASSERT(swrast
->Driver
.ReadStencilSpan
);
439 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
440 stencil
= stencilRow
;
443 /* Get pointer into software stencil buffer */
444 stencil
= STENCIL_ADDRESS(x
, y
);
448 * Apply the stencil test to the fragments.
449 * failMask[i] is 1 if the stencil test failed.
451 if (do_stencil_test( ctx
, face
, n
, stencil
, mask
) == GL_FALSE
) {
452 /* all fragments failed the stencil test, we're done. */
453 span
->writeAll
= GL_FALSE
;
458 * Some fragments passed the stencil test, apply depth test to them
459 * and apply Zpass and Zfail stencil ops.
461 if (ctx
->Depth
.Test
== GL_FALSE
) {
463 * No depth buffer, just apply zpass stencil function to active pixels.
465 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
, n
, stencil
, mask
);
469 * Perform depth buffering, then apply zpass or zfail stencil function.
471 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
474 /* save the current mask bits */
475 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
477 /* apply the depth test */
478 _swrast_depth_test_span(ctx
, span
);
480 /* Set the stencil pass/fail flags according to result of depth testing.
481 * if oldmask[i] == 0 then
482 * Don't touch the stencil value
483 * else if oldmask[i] and newmask[i] then
486 * assert(oldmask[i] && !newmask[i])
491 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
492 passmask
[i
] = oldmask
[i
] & mask
[i
];
493 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
496 /* apply the pass and fail operations */
497 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
498 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
[face
], face
,
499 n
, stencil
, failmask
);
501 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
502 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
503 n
, stencil
, passmask
);
508 * Write updated stencil values back into hardware stencil buffer.
510 if (swrast
->Driver
.WriteStencilSpan
) {
511 ASSERT(stencil
== stencilRow
);
512 (swrast
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
515 span
->writeAll
= GL_FALSE
;
517 return GL_TRUE
; /* one or more fragments passed both tests */
524 * Apply the given stencil operator for each pixel in the array whose
526 * \note This is for software stencil buffers only.
527 * Input: n - number of pixels in the span
528 * x, y - array of [n] pixels
529 * operator - the stencil buffer operator
530 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
533 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
534 GLuint n
, const GLint x
[], const GLint y
[],
535 GLenum oper
, GLuint face
, const GLubyte mask
[] )
537 const GLstencil ref
= ctx
->Stencil
.Ref
[face
];
538 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
[face
];
539 const GLstencil invmask
= (GLstencil
) (~wrtmask
);
542 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
552 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
560 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
561 *sptr
= (GLstencil
) (invmask
& *sptr
);
570 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
578 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
579 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
588 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
589 if (*sptr
< STENCIL_MAX
) {
590 *sptr
= (GLstencil
) (*sptr
+ 1);
598 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
599 if (*sptr
< STENCIL_MAX
) {
600 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
610 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
612 *sptr
= (GLstencil
) (*sptr
- 1);
620 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
622 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
628 case GL_INCR_WRAP_EXT
:
632 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
633 *sptr
= (GLstencil
) (*sptr
+ 1);
640 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
641 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
646 case GL_DECR_WRAP_EXT
:
650 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
651 *sptr
= (GLstencil
) (*sptr
- 1);
658 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
659 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
668 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
669 *sptr
= (GLstencil
) (~*sptr
);
676 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
677 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
683 _mesa_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
690 * Apply stencil test to an array of pixels before depth buffering.
692 * \note Used for software stencil buffer only.
693 * Input: n - number of pixels in the span
694 * x, y - array of [n] pixels to stencil
695 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
696 * Output: mask - pixels which fail the stencil test will have their
697 * mask flag set to 0.
698 * \return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
701 stencil_test_pixels( GLcontext
*ctx
, GLuint face
, GLuint n
,
702 const GLint x
[], const GLint y
[], GLubyte mask
[] )
704 GLubyte fail
[MAX_WIDTH
];
707 GLboolean allfail
= GL_FALSE
;
708 const GLuint valueMask
= ctx
->Stencil
.ValueMask
[face
];
710 /* software stencil buffer only! */
711 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
712 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.ReadStencilSpan
);
713 ASSERT(!SWRAST_CONTEXT(ctx
)->Driver
.WriteStencilSpan
);
716 * Perform stencil test. The results of this operation are stored
717 * in the fail[] array:
718 * IF fail[i] is non-zero THEN
719 * the stencil fail operator is to be applied
721 * the stencil fail operator is not to be applied
725 switch (ctx
->Stencil
.Function
[face
]) {
740 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
743 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
744 s
= (GLstencil
) (*sptr
& valueMask
);
760 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
763 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
764 s
= (GLstencil
) (*sptr
& valueMask
);
780 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
783 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
784 s
= (GLstencil
) (*sptr
& valueMask
);
800 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
803 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
804 s
= (GLstencil
) (*sptr
& valueMask
);
820 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
823 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
824 s
= (GLstencil
) (*sptr
& valueMask
);
840 r
= (GLstencil
) (ctx
->Stencil
.Ref
[face
] & valueMask
);
843 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
844 s
= (GLstencil
) (*sptr
& valueMask
);
866 _mesa_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
870 if (ctx
->Stencil
.FailFunc
[face
] != GL_KEEP
) {
871 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
[face
],
882 * Apply stencil and depth testing to an array of pixels.
883 * This is used both for software and hardware stencil buffers.
885 * The comments in this function are a bit sparse but the code is
886 * almost identical to stencil_and_ztest_span(), which is well
889 * Input: n - number of pixels in the array
890 * x, y - array of [n] pixel positions
891 * z - array [n] of z values
892 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
893 * Output: mask - array [n] of flags (1=stencil and depth test passed)
894 * Return: GL_FALSE - all fragments failed the testing
895 * GL_TRUE - one or more fragments passed the testing
898 stencil_and_ztest_pixels( GLcontext
*ctx
, struct sw_span
*span
, GLuint face
)
900 const GLuint n
= span
->end
;
901 const GLint
*x
= span
->array
->x
;
902 const GLint
*y
= span
->array
->y
;
903 GLubyte
*mask
= span
->array
->mask
;
904 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
906 ASSERT(span
->arrayMask
& SPAN_XY
);
907 ASSERT(ctx
->Stencil
.Enabled
);
908 ASSERT(n
<= MAX_WIDTH
);
910 if (swrast
->Driver
.WriteStencilPixels
) {
911 /*** Hardware stencil buffer ***/
912 GLstencil stencil
[MAX_WIDTH
];
913 GLubyte origMask
[MAX_WIDTH
];
915 ASSERT(!ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
916 ASSERT(swrast
->Driver
.ReadStencilPixels
);
917 (*swrast
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
919 MEMCPY(origMask
, mask
, n
* sizeof(GLubyte
));
921 (void) do_stencil_test(ctx
, face
, n
, stencil
, mask
);
923 if (ctx
->Depth
.Test
== GL_FALSE
) {
924 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
928 _swrast_depth_test_span(ctx
, span
);
930 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
931 GLubyte failmask
[MAX_WIDTH
];
933 for (i
= 0; i
< n
; i
++) {
934 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
935 failmask
[i
] = origMask
[i
] & (mask
[i
] ^ 1);
937 apply_stencil_op(ctx
, ctx
->Stencil
.ZFailFunc
[face
], face
,
938 n
, stencil
, failmask
);
940 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
941 GLubyte passmask
[MAX_WIDTH
];
943 for (i
= 0; i
< n
; i
++) {
944 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
945 passmask
[i
] = origMask
[i
] & mask
[i
];
947 apply_stencil_op(ctx
, ctx
->Stencil
.ZPassFunc
[face
], face
,
948 n
, stencil
, passmask
);
952 /* Write updated stencil values into hardware stencil buffer */
953 (swrast
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, origMask
);
958 /*** Software stencil buffer ***/
960 ASSERT(ctx
->DrawBuffer
->UseSoftwareStencilBuffer
);
962 if (stencil_test_pixels(ctx
, face
, n
, x
, y
, mask
) == GL_FALSE
) {
963 /* all fragments failed the stencil test, we're done. */
967 if (ctx
->Depth
.Test
==GL_FALSE
) {
968 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
969 ctx
->Stencil
.ZPassFunc
[face
], face
, mask
);
972 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
975 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
977 _swrast_depth_test_span(ctx
, span
);
980 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
981 passmask
[i
] = oldmask
[i
] & mask
[i
];
982 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
985 if (ctx
->Stencil
.ZFailFunc
[face
] != GL_KEEP
) {
986 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
987 ctx
->Stencil
.ZFailFunc
[face
],
990 if (ctx
->Stencil
.ZPassFunc
[face
] != GL_KEEP
) {
991 apply_stencil_op_to_pixels(ctx
, n
, x
, y
,
992 ctx
->Stencil
.ZPassFunc
[face
],
997 return GL_TRUE
; /* one or more fragments passed both tests */
1003 * /return GL_TRUE = one or more fragments passed,
1004 * GL_FALSE = all fragments failed.
1007 _swrast_stencil_and_ztest_span(GLcontext
*ctx
, struct sw_span
*span
)
1009 /* span->facing can only be non-zero if using two-sided stencil */
1010 ASSERT(ctx
->Stencil
.TestTwoSide
|| span
->facing
== 0);
1011 if (span
->arrayMask
& SPAN_XY
)
1012 return stencil_and_ztest_pixels(ctx
, span
, span
->facing
);
1014 return stencil_and_ztest_span(ctx
, span
, span
->facing
);
1019 * Return a span of stencil values from the stencil buffer.
1020 * Used for glRead/CopyPixels
1021 * Input: n - how many pixels
1022 * x,y - location of first pixel
1023 * Output: stencil - the array of stencil values
1026 _swrast_read_stencil_span( GLcontext
*ctx
,
1027 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1029 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1030 const GLint bufWidth
= (GLint
) ctx
->DrawBuffer
->Width
;
1031 const GLint bufHeight
= (GLint
) ctx
->DrawBuffer
->Height
;
1033 if (y
< 0 || y
>= bufHeight
|| x
+ n
<= 0 || x
>= bufWidth
) {
1034 /* span is completely outside framebuffer */
1035 return; /* undefined values OK */
1044 if (x
+ n
> bufWidth
) {
1045 GLint dx
= x
+ n
- bufWidth
;
1054 if (swrast
->Driver
.ReadStencilSpan
) {
1055 (*swrast
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1057 else if (ctx
->DrawBuffer
->Stencil
) {
1058 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1059 #if STENCIL_BITS == 8
1060 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1072 * Write a span of stencil values to the stencil buffer.
1073 * Used for glDraw/CopyPixels
1074 * Input: n - how many pixels
1075 * x, y - location of first pixel
1076 * stencil - the array of stencil values
1079 _swrast_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1080 const GLstencil stencil
[] )
1082 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1083 const GLstencil
*ssrc
= stencil
;
1084 const GLint bufWidth
= (GLint
) ctx
->DrawBuffer
->Width
;
1085 const GLint bufHeight
= (GLint
) ctx
->DrawBuffer
->Height
;
1087 if (y
< 0 || y
>= bufHeight
|| x
+ n
<= 0 || x
>= bufWidth
) {
1088 /* span is completely outside framebuffer */
1089 return; /* undefined values OK */
1098 if (x
+ n
> bufWidth
) {
1099 GLint dx
= x
+ n
- bufWidth
;
1106 if (swrast
->Driver
.WriteStencilSpan
) {
1107 (*swrast
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, ssrc
, NULL
);
1109 else if (ctx
->DrawBuffer
->Stencil
) {
1110 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1111 #if STENCIL_BITS == 8
1112 MEMCPY( s
, ssrc
, n
* sizeof(GLstencil
) );
1124 * Allocate a new stencil buffer. If there's an old one it will be
1125 * deallocated first. The new stencil buffer will be uninitialized.
1128 _swrast_alloc_stencil_buffer( GLframebuffer
*buffer
)
1130 /* deallocate current stencil buffer if present */
1131 if (buffer
->Stencil
) {
1132 MESA_PBUFFER_FREE(buffer
->Stencil
);
1133 buffer
->Stencil
= NULL
;
1136 /* allocate new stencil buffer */
1137 buffer
->Stencil
= (GLstencil
*)
1138 MESA_PBUFFER_ALLOC(buffer
->Width
* buffer
->Height
* sizeof(GLstencil
));
1139 if (!buffer
->Stencil
) {
1141 _mesa_error( NULL
, GL_OUT_OF_MEMORY
, "_swrast_alloc_stencil_buffer" );
1148 * Clear the software (malloc'd) stencil buffer.
1151 clear_software_stencil_buffer( GLcontext
*ctx
)
1153 if (ctx
->Visual
.stencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1154 /* no stencil buffer */
1158 if (ctx
->Scissor
.Enabled
) {
1159 /* clear scissor region only */
1160 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1161 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1162 /* must apply mask to the clear */
1164 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1165 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1166 const GLstencil invMask
= ~mask
;
1167 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1168 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1170 for (i
= 0; i
< width
; i
++) {
1171 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1178 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1179 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->_Xmin
, y
);
1181 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1184 for (i
= 0; i
< width
; i
++)
1185 stencil
[i
] = ctx
->Stencil
.Clear
;
1191 /* clear whole stencil buffer */
1192 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1193 /* must apply mask to the clear */
1194 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1195 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1196 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1197 const GLstencil invMask
= ~mask
;
1198 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1200 for (i
= 0; i
< n
; i
++) {
1201 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1205 /* clear whole buffer without masking */
1206 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1207 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1210 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1213 for (i
= 0; i
< n
; i
++) {
1214 stencil
[i
] = ctx
->Stencil
.Clear
;
1224 * Clear the hardware (in graphics card) stencil buffer.
1225 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1227 * Actually, if there is a hardware stencil buffer it really should have
1228 * been cleared in Driver.Clear()! However, if the hardware does not
1229 * support scissored clears or masked clears (i.e. glStencilMask) then
1230 * we have to use the span-based functions.
1233 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1235 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1236 ASSERT(swrast
->Driver
.WriteStencilSpan
);
1237 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1239 if (ctx
->Scissor
.Enabled
) {
1240 /* clear scissor region only */
1241 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1242 const GLint width
= ctx
->DrawBuffer
->_Xmax
- ctx
->DrawBuffer
->_Xmin
;
1243 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1244 /* must apply mask to the clear */
1246 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1247 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1248 const GLstencil invMask
= ~mask
;
1249 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1250 GLstencil stencil
[MAX_WIDTH
];
1252 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1253 for (i
= 0; i
< width
; i
++) {
1254 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1256 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1261 GLstencil stencil
[MAX_WIDTH
];
1263 for (i
= 0; i
< width
; i
++) {
1264 stencil
[i
] = ctx
->Stencil
.Clear
;
1266 for (y
= ctx
->DrawBuffer
->_Ymin
; y
< ctx
->DrawBuffer
->_Ymax
; y
++) {
1267 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1272 /* clear whole stencil buffer */
1273 if (ctx
->Stencil
.WriteMask
[0] != STENCIL_MAX
) {
1274 /* must apply mask to the clear */
1275 const GLstencil mask
= ctx
->Stencil
.WriteMask
[0];
1276 const GLstencil invMask
= ~mask
;
1277 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1278 const GLint width
= ctx
->DrawBuffer
->Width
;
1279 const GLint height
= ctx
->DrawBuffer
->Height
;
1280 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1282 for (y
= 0; y
< height
; y
++) {
1283 GLstencil stencil
[MAX_WIDTH
];
1285 (*swrast
->Driver
.ReadStencilSpan
)(ctx
, width
, x
, y
, stencil
);
1286 for (i
= 0; i
< width
; i
++) {
1287 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1289 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1293 /* clear whole buffer without masking */
1294 const GLint width
= ctx
->DrawBuffer
->Width
;
1295 const GLint height
= ctx
->DrawBuffer
->Height
;
1296 const GLint x
= ctx
->DrawBuffer
->_Xmin
;
1297 GLstencil stencil
[MAX_WIDTH
];
1299 for (i
= 0; i
< width
; i
++) {
1300 stencil
[i
] = ctx
->Stencil
.Clear
;
1302 for (y
= 0; y
< height
; y
++) {
1303 (*swrast
->Driver
.WriteStencilSpan
)(ctx
, width
, x
, y
, stencil
, NULL
);
1312 * Clear the stencil buffer (hardware or software).
1315 _swrast_clear_stencil_buffer( GLcontext
*ctx
)
1317 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
1318 if (swrast
->Driver
.WriteStencilSpan
) {
1319 ASSERT(swrast
->Driver
.ReadStencilSpan
);
1320 clear_hardware_stencil_buffer(ctx
);
1323 clear_software_stencil_buffer(ctx
);