c957a683a16bc2695b71070fb364bf988fc26ed8
1 /* $Id: s_stencil.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 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.
35 #include "s_stencil.h"
43 IF stencil test fails THEN
44 Apply fail-op to stencil value
45 Don't write the pixel (RGBA,Z)
47 IF doing depth test && depth test fails THEN
48 Apply zfail-op to stencil value
49 Write RGBA and Z to appropriate buffers
51 Apply zpass-op to stencil value
60 * Return the address of a stencil buffer value given the window coords:
62 #define STENCIL_ADDRESS(X,Y) \
63 (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
68 * Apply the given stencil operator to the array of stencil values.
69 * Don't touch stencil[i] if mask[i] is zero.
70 * Input: n - size of stencil array
71 * oper - the stencil buffer operator
72 * stencil - array of stencil values
73 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
74 * Output: stencil - modified values
76 static void apply_stencil_op( const GLcontext
*ctx
, GLenum oper
,
77 GLuint n
, GLstencil stencil
[],
78 const GLubyte mask
[] )
80 const GLstencil ref
= ctx
->Stencil
.Ref
;
81 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
82 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
100 stencil
[i
] = (GLstencil
) (stencil
[i
] & invmask
);
116 GLstencil s
= stencil
[i
];
117 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ref
));
126 GLstencil s
= stencil
[i
];
127 if (s
< STENCIL_MAX
) {
128 stencil
[i
] = (GLstencil
) (s
+1);
136 /* VERIFY logic of adding 1 to a write-masked value */
137 GLstencil s
= stencil
[i
];
138 if (s
< STENCIL_MAX
) {
139 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
149 GLstencil s
= stencil
[i
];
151 stencil
[i
] = (GLstencil
) (s
-1);
159 /* VERIFY logic of subtracting 1 to a write-masked value */
160 GLstencil s
= stencil
[i
];
162 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
168 case GL_INCR_WRAP_EXT
:
179 GLstencil s
= stencil
[i
];
180 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
+1)));
185 case GL_DECR_WRAP_EXT
:
196 GLstencil s
= stencil
[i
];
197 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& (s
-1)));
206 GLstencil s
= stencil
[i
];
207 stencil
[i
] = (GLstencil
) ~s
;
214 GLstencil s
= stencil
[i
];
215 stencil
[i
] = (GLstencil
) ((invmask
& s
) | (wrtmask
& ~s
));
221 gl_problem(ctx
, "Bad stencil op in apply_stencil_op");
229 * Apply stencil test to an array of stencil values (before depth buffering).
230 * Input: n - number of pixels in the array
231 * stencil - array of [n] stencil values
232 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
233 * Output: mask - pixels which fail the stencil test will have their
234 * mask flag set to 0.
235 * stencil - updated stencil values (where the test passed)
236 * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
239 do_stencil_test( GLcontext
*ctx
, GLuint n
, GLstencil stencil
[],
242 GLubyte fail
[PB_SIZE
];
243 GLboolean allfail
= GL_FALSE
;
247 ASSERT(n
<= PB_SIZE
);
250 * Perform stencil test. The results of this operation are stored
251 * in the fail[] array:
252 * IF fail[i] is non-zero THEN
253 * the stencil fail operator is to be applied
255 * the stencil fail operator is not to be applied
258 switch (ctx
->Stencil
.Function
) {
273 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
276 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
292 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
295 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
311 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
314 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
330 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
333 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
349 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
352 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
368 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
371 s
= (GLstencil
) (stencil
[i
] & ctx
->Stencil
.ValueMask
);
393 gl_problem(ctx
, "Bad stencil func in gl_stencil_span");
397 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
398 apply_stencil_op( ctx
, ctx
->Stencil
.FailFunc
, n
, stencil
, fail
);
408 * Apply stencil and depth testing to an array of pixels.
409 * Hardware or software stencil buffer acceptable.
410 * Input: n - number of pixels in the span
411 * z - array [n] of z values
412 * stencil - array [n] of stencil values
413 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
414 * Output: stencil - modified stencil values
415 * mask - array [n] of flags (1=stencil and depth test passed)
416 * Return: GL_TRUE - all fragments failed the testing
417 * GL_FALSE - one or more fragments passed the testing
421 stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
422 const GLdepth z
[], GLstencil stencil
[],
425 ASSERT(ctx
->Stencil
.Enabled
);
426 ASSERT(n
<= PB_SIZE
);
429 * Apply the stencil test to the fragments.
430 * failMask[i] is 1 if the stencil test failed.
432 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
433 /* all fragments failed the stencil test, we're done. */
439 * Some fragments passed the stencil test, apply depth test to them
440 * and apply Zpass and Zfail stencil ops.
442 if (ctx
->Depth
.Test
==GL_FALSE
) {
444 * No depth buffer, just apply zpass stencil function to active pixels.
446 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
450 * Perform depth buffering, then apply zpass or zfail stencil function.
452 GLubyte passmask
[MAX_WIDTH
], failmask
[MAX_WIDTH
], oldmask
[MAX_WIDTH
];
455 /* save the current mask bits */
456 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
458 /* apply the depth test */
459 _mesa_depth_test_span(ctx
, n
, x
, y
, z
, mask
);
461 /* Set the stencil pass/fail flags according to result of depth testing.
462 * if oldmask[i] == 0 then
463 * Don't touch the stencil value
464 * else if oldmask[i] and newmask[i] then
467 * assert(oldmask[i] && !newmask[i])
472 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
473 passmask
[i
] = oldmask
[i
] & mask
[i
];
474 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
477 /* apply the pass and fail operations */
478 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
479 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
481 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
482 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
486 return GL_TRUE
; /* one or more fragments passed both tests */
492 * Apply stencil and depth testing to the span of pixels.
493 * Both software and hardware stencil buffers are acceptable.
494 * Input: n - number of pixels in the span
495 * x, y - location of leftmost pixel in span
496 * z - array [n] of z values
497 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
498 * Output: mask - array [n] of flags (1=stencil and depth test passed)
499 * Return: GL_TRUE - all fragments failed the testing
500 * GL_FALSE - one or more fragments passed the testing
504 _mesa_stencil_and_ztest_span( GLcontext
*ctx
, GLuint n
, GLint x
, GLint y
,
505 const GLdepth z
[], GLubyte mask
[] )
507 GLstencil stencilRow
[MAX_WIDTH
];
511 ASSERT(ctx
->Stencil
.Enabled
);
512 ASSERT(n
<= MAX_WIDTH
);
514 /* Get initial stencil values */
515 if (ctx
->Driver
.WriteStencilSpan
) {
516 ASSERT(ctx
->Driver
.ReadStencilSpan
);
517 /* Get stencil values from the hardware stencil buffer */
518 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, n
, x
, y
, stencilRow
);
519 stencil
= stencilRow
;
522 /* software stencil buffer */
523 stencil
= STENCIL_ADDRESS(x
, y
);
526 /* do all the stencil/depth testing/updating */
527 result
= stencil_and_ztest_span( ctx
, n
, x
, y
, z
, stencil
, mask
);
529 if (ctx
->Driver
.WriteStencilSpan
) {
530 /* Write updated stencil values into hardware stencil buffer */
531 (ctx
->Driver
.WriteStencilSpan
)(ctx
, n
, x
, y
, stencil
, mask
);
541 * Apply the given stencil operator for each pixel in the array whose
542 * mask flag is set. This is for software stencil buffers only.
543 * Input: n - number of pixels in the span
544 * x, y - array of [n] pixels
545 * operator - the stencil buffer operator
546 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
549 apply_stencil_op_to_pixels( const GLcontext
*ctx
,
550 GLuint n
, const GLint x
[], const GLint y
[],
551 GLenum oper
, const GLubyte mask
[] )
553 const GLstencil ref
= ctx
->Stencil
.Ref
;
554 const GLstencil wrtmask
= ctx
->Stencil
.WriteMask
;
555 const GLstencil invmask
= (GLstencil
) (~ctx
->Stencil
.WriteMask
);
558 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
568 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
576 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
577 *sptr
= (GLstencil
) (invmask
& *sptr
);
586 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
594 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
595 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ref
));
604 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
605 if (*sptr
< STENCIL_MAX
) {
606 *sptr
= (GLstencil
) (*sptr
+ 1);
614 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
615 if (*sptr
< STENCIL_MAX
) {
616 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
626 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
628 *sptr
= (GLstencil
) (*sptr
- 1);
636 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
638 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
644 case GL_INCR_WRAP_EXT
:
648 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
649 *sptr
= (GLstencil
) (*sptr
+ 1);
656 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
657 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
+1)));
662 case GL_DECR_WRAP_EXT
:
666 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
667 *sptr
= (GLstencil
) (*sptr
- 1);
674 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
675 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& (*sptr
-1)));
684 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
685 *sptr
= (GLstencil
) (~*sptr
);
692 GLstencil
*sptr
= STENCIL_ADDRESS( x
[i
], y
[i
] );
693 *sptr
= (GLstencil
) ((invmask
& *sptr
) | (wrtmask
& ~*sptr
));
699 gl_problem(ctx
, "Bad stencilop in apply_stencil_op_to_pixels");
706 * Apply stencil test to an array of pixels before depth buffering.
707 * Used for software stencil buffer only.
708 * Input: n - number of pixels in the span
709 * x, y - array of [n] pixels to stencil
710 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
711 * Output: mask - pixels which fail the stencil test will have their
712 * mask flag set to 0.
713 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
716 stencil_test_pixels( GLcontext
*ctx
, GLuint n
,
717 const GLint x
[], const GLint y
[], GLubyte mask
[] )
719 GLubyte fail
[PB_SIZE
];
722 GLboolean allfail
= GL_FALSE
;
724 ASSERT(!ctx
->Driver
.WriteStencilSpan
); /* software stencil buffer only! */
727 * Perform stencil test. The results of this operation are stored
728 * in the fail[] array:
729 * IF fail[i] is non-zero THEN
730 * the stencil fail operator is to be applied
732 * the stencil fail operator is not to be applied
736 switch (ctx
->Stencil
.Function
) {
751 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
754 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
755 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
771 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
774 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
775 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
791 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
794 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
795 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
811 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
814 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
815 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
831 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
834 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
835 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
851 r
= (GLstencil
) (ctx
->Stencil
.Ref
& ctx
->Stencil
.ValueMask
);
854 GLstencil
*sptr
= STENCIL_ADDRESS(x
[i
],y
[i
]);
855 s
= (GLstencil
) (*sptr
& ctx
->Stencil
.ValueMask
);
877 gl_problem(ctx
, "Bad stencil func in gl_stencil_pixels");
881 if (ctx
->Stencil
.FailFunc
!= GL_KEEP
) {
882 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.FailFunc
, fail
);
892 * Apply stencil and depth testing to an array of pixels.
893 * This is used both for software and hardware stencil buffers.
895 * The comments in this function are a bit sparse but the code is
896 * almost identical to stencil_and_ztest_span(), which is well
899 * Input: n - number of pixels in the array
900 * x, y - array of [n] pixel positions
901 * z - array [n] of z values
902 * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
903 * Output: mask - array [n] of flags (1=stencil and depth test passed)
904 * Return: GL_TRUE - all fragments failed the testing
905 * GL_FALSE - one or more fragments passed the testing
908 _mesa_stencil_and_ztest_pixels( GLcontext
*ctx
,
909 GLuint n
, const GLint x
[], const GLint y
[],
910 const GLdepth z
[], GLubyte mask
[] )
912 ASSERT(ctx
->Stencil
.Enabled
);
913 ASSERT(n
<= PB_SIZE
);
915 if (ctx
->Driver
.WriteStencilPixels
) {
916 /*** Hardware stencil buffer ***/
917 GLstencil stencil
[PB_SIZE
];
918 GLubyte mask
[PB_SIZE
];
920 ASSERT(ctx
->Driver
.ReadStencilPixels
);
921 (*ctx
->Driver
.ReadStencilPixels
)(ctx
, n
, x
, y
, stencil
);
924 if (do_stencil_test( ctx
, n
, stencil
, mask
) == GL_FALSE
) {
925 /* all fragments failed the stencil test, we're done. */
929 if (ctx
->Depth
.Test
== GL_FALSE
) {
930 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, mask
);
933 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
936 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
938 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
941 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
942 passmask
[i
] = oldmask
[i
] & mask
[i
];
943 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
946 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
947 apply_stencil_op( ctx
, ctx
->Stencil
.ZFailFunc
, n
, stencil
, failmask
);
949 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
950 apply_stencil_op( ctx
, ctx
->Stencil
.ZPassFunc
, n
, stencil
, passmask
);
954 /* Write updated stencil values into hardware stencil buffer */
955 (ctx
->Driver
.WriteStencilPixels
)(ctx
, n
, x
, y
, stencil
, mask
);
961 /*** Software stencil buffer ***/
963 if (stencil_test_pixels(ctx
, n
, x
, y
, mask
) == GL_FALSE
) {
964 /* all fragments failed the stencil test, we're done. */
969 if (ctx
->Depth
.Test
==GL_FALSE
) {
970 apply_stencil_op_to_pixels( ctx
, n
, x
, y
, ctx
->Stencil
.ZPassFunc
, mask
);
973 GLubyte passmask
[PB_SIZE
], failmask
[PB_SIZE
], oldmask
[PB_SIZE
];
976 MEMCPY(oldmask
, mask
, n
* sizeof(GLubyte
));
978 _mesa_depth_test_pixels(ctx
, n
, x
, y
, z
, mask
);
981 ASSERT(mask
[i
] == 0 || mask
[i
] == 1);
982 passmask
[i
] = oldmask
[i
] & mask
[i
];
983 failmask
[i
] = oldmask
[i
] & (mask
[i
] ^ 1);
986 if (ctx
->Stencil
.ZFailFunc
!= GL_KEEP
) {
987 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
988 ctx
->Stencil
.ZFailFunc
, failmask
);
990 if (ctx
->Stencil
.ZPassFunc
!= GL_KEEP
) {
991 apply_stencil_op_to_pixels( ctx
, n
, x
, y
,
992 ctx
->Stencil
.ZPassFunc
, passmask
);
996 return GL_TRUE
; /* one or more fragments passed both tests */
1003 * Return a span of stencil values from the stencil buffer.
1004 * Used for glRead/CopyPixels
1005 * Input: n - how many pixels
1006 * x,y - location of first pixel
1007 * Output: stencil - the array of stencil values
1010 _mesa_read_stencil_span( GLcontext
*ctx
,
1011 GLint n
, GLint x
, GLint y
, GLstencil stencil
[] )
1013 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1014 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1015 /* span is completely outside framebuffer */
1016 return; /* undefined values OK */
1025 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1026 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1035 if (ctx
->Driver
.ReadStencilSpan
) {
1036 (*ctx
->Driver
.ReadStencilSpan
)( ctx
, (GLuint
) n
, x
, y
, stencil
);
1038 else if (ctx
->DrawBuffer
->Stencil
) {
1039 const GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1040 #if STENCIL_BITS == 8
1041 MEMCPY( stencil
, s
, n
* sizeof(GLstencil
) );
1053 * Write a span of stencil values to the stencil buffer.
1054 * Used for glDraw/CopyPixels
1055 * Input: n - how many pixels
1056 * x, y - location of first pixel
1057 * stencil - the array of stencil values
1060 _mesa_write_stencil_span( GLcontext
*ctx
, GLint n
, GLint x
, GLint y
,
1061 const GLstencil stencil
[] )
1063 if (y
< 0 || y
>= ctx
->DrawBuffer
->Height
||
1064 x
+ n
<= 0 || x
>= ctx
->DrawBuffer
->Width
) {
1065 /* span is completely outside framebuffer */
1066 return; /* undefined values OK */
1075 if (x
+ n
> ctx
->DrawBuffer
->Width
) {
1076 GLint dx
= x
+ n
- ctx
->DrawBuffer
->Width
;
1083 if (ctx
->Driver
.WriteStencilSpan
) {
1084 (*ctx
->Driver
.WriteStencilSpan
)( ctx
, n
, x
, y
, stencil
, NULL
);
1086 else if (ctx
->DrawBuffer
->Stencil
) {
1087 GLstencil
*s
= STENCIL_ADDRESS( x
, y
);
1088 #if STENCIL_BITS == 8
1089 MEMCPY( s
, stencil
, n
* sizeof(GLstencil
) );
1101 * Allocate a new stencil buffer. If there's an old one it will be
1102 * deallocated first. The new stencil buffer will be uninitialized.
1105 _mesa_alloc_stencil_buffer( GLcontext
*ctx
)
1107 GLuint buffersize
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1109 /* deallocate current stencil buffer if present */
1110 if (ctx
->DrawBuffer
->Stencil
) {
1111 FREE(ctx
->DrawBuffer
->Stencil
);
1112 ctx
->DrawBuffer
->Stencil
= NULL
;
1115 /* allocate new stencil buffer */
1116 ctx
->DrawBuffer
->Stencil
= (GLstencil
*) MALLOC(buffersize
* sizeof(GLstencil
));
1117 if (!ctx
->DrawBuffer
->Stencil
) {
1119 /* _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); */
1120 gl_error( ctx
, GL_OUT_OF_MEMORY
, "_mesa_alloc_stencil_buffer" );
1127 * Clear the software (malloc'd) stencil buffer.
1130 clear_software_stencil_buffer( GLcontext
*ctx
)
1132 if (ctx
->Visual
.StencilBits
==0 || !ctx
->DrawBuffer
->Stencil
) {
1133 /* no stencil buffer */
1137 if (ctx
->Scissor
.Enabled
) {
1138 /* clear scissor region only */
1139 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
1140 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1141 /* must apply mask to the clear */
1143 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1144 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1145 const GLstencil invMask
= ~mask
;
1146 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1147 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1149 for (i
= 0; i
< width
; i
++) {
1150 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1157 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1158 GLstencil
*stencil
= STENCIL_ADDRESS( ctx
->DrawBuffer
->Xmin
, y
);
1160 MEMSET( stencil
, ctx
->Stencil
.Clear
, width
* sizeof(GLstencil
) );
1163 for (i
= 0; i
< width
; i
++)
1164 stencil
[x
] = ctx
->Stencil
.Clear
;
1170 /* clear whole stencil buffer */
1171 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1172 /* must apply mask to the clear */
1173 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1174 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1175 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1176 const GLstencil invMask
= ~mask
;
1177 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1179 for (i
= 0; i
< n
; i
++) {
1180 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1184 /* clear whole buffer without masking */
1185 const GLuint n
= ctx
->DrawBuffer
->Width
* ctx
->DrawBuffer
->Height
;
1186 GLstencil
*stencil
= ctx
->DrawBuffer
->Stencil
;
1189 MEMSET(stencil
, ctx
->Stencil
.Clear
, n
* sizeof(GLstencil
) );
1192 for (i
= 0; i
< n
; i
++) {
1193 stencil
[i
] = ctx
->Stencil
.Clear
;
1203 * Clear the hardware (in graphics card) stencil buffer.
1204 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1206 * Actually, if there is a hardware stencil buffer it really should have
1207 * been cleared in Driver.Clear()! However, if the hardware does not
1208 * support scissored clears or masked clears (i.e. glStencilMask) then
1209 * we have to use the span-based functions.
1212 clear_hardware_stencil_buffer( GLcontext
*ctx
)
1214 ASSERT(ctx
->Driver
.WriteStencilSpan
);
1215 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1217 if (ctx
->Scissor
.Enabled
) {
1218 /* clear scissor region only */
1219 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1220 const GLint width
= ctx
->DrawBuffer
->Xmax
- ctx
->DrawBuffer
->Xmin
;
1221 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1222 /* must apply mask to the clear */
1224 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1225 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1226 const GLstencil invMask
= ~mask
;
1227 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1228 GLstencil stencil
[MAX_WIDTH
];
1230 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1231 for (i
= 0; i
< width
; i
++) {
1232 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1234 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1239 GLstencil stencil
[MAX_WIDTH
];
1241 for (i
= 0; i
< width
; i
++) {
1242 stencil
[i
] = ctx
->Stencil
.Clear
;
1244 for (y
= ctx
->DrawBuffer
->Ymin
; y
< ctx
->DrawBuffer
->Ymax
; y
++) {
1245 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1250 /* clear whole stencil buffer */
1251 if (ctx
->Stencil
.WriteMask
!= STENCIL_MAX
) {
1252 /* must apply mask to the clear */
1253 const GLstencil mask
= ctx
->Stencil
.WriteMask
;
1254 const GLstencil invMask
= ~mask
;
1255 const GLstencil clearVal
= (ctx
->Stencil
.Clear
& mask
);
1256 const GLint width
= ctx
->DrawBuffer
->Width
;
1257 const GLint height
= ctx
->DrawBuffer
->Height
;
1258 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1260 for (y
= 0; y
< height
; y
++) {
1261 GLstencil stencil
[MAX_WIDTH
];
1263 (*ctx
->Driver
.ReadStencilSpan
)(ctx
, x
, y
, width
, stencil
);
1264 for (i
= 0; i
< width
; i
++) {
1265 stencil
[i
] = (stencil
[i
] & invMask
) | clearVal
;
1267 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1271 /* clear whole buffer without masking */
1272 const GLint width
= ctx
->DrawBuffer
->Width
;
1273 const GLint height
= ctx
->DrawBuffer
->Width
;
1274 const GLint x
= ctx
->DrawBuffer
->Xmin
;
1275 GLstencil stencil
[MAX_WIDTH
];
1277 for (i
= 0; i
< width
; i
++) {
1278 stencil
[i
] = ctx
->Stencil
.Clear
;
1280 for (y
= 0; y
< height
; y
++) {
1281 (*ctx
->Driver
.WriteStencilSpan
)(ctx
, x
, y
, width
, stencil
, NULL
);
1290 * Clear the stencil buffer.
1293 _mesa_clear_stencil_buffer( GLcontext
*ctx
)
1295 if (ctx
->Driver
.WriteStencilSpan
) {
1296 ASSERT(ctx
->Driver
.ReadStencilSpan
);
1297 clear_hardware_stencil_buffer(ctx
);
1300 clear_software_stencil_buffer(ctx
);