1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * \file stencil.c
28 * Stencil operations.
29 *
30 * Note: There's some conflict between GL_EXT_stencil_two_side and
31 * OpenGL 2.0's two-sided stencil feature.
32 *
33 * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the
34 * front OR back face state (as set by glActiveStencilFaceEXT) is set.
35 *
36 * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the
37 * front AND back state.
38 *
39 * Also, note that GL_ATI_separate_stencil is different as well:
40 * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs.
41 * glStencilFuncSeparate(GLenum face, GLenum func, ...).
42 *
43 * This problem is solved by keeping three sets of stencil state:
44 * state[0] = GL_FRONT state.
45 * state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state.
46 * state[2] = GL_EXT_stencil_two_side GL_BACK state.
47 */
48
49
50 #include "glheader.h"
51 #include "imports.h"
52 #include "context.h"
53 #include "macros.h"
54 #include "stencil.h"
55 #include "mtypes.h"
56
57
58 static GLboolean
validate_stencil_op(struct gl_context * ctx,GLenum op)59 validate_stencil_op(struct gl_context *ctx, GLenum op)
60 {
61 switch (op) {
62 case GL_KEEP:
63 case GL_ZERO:
64 case GL_REPLACE:
65 case GL_INCR:
66 case GL_DECR:
67 case GL_INVERT:
68 case GL_INCR_WRAP:
69 case GL_DECR_WRAP:
70 return GL_TRUE;
71 default:
72 return GL_FALSE;
73 }
74 }
75
76
77 static GLboolean
validate_stencil_func(struct gl_context * ctx,GLenum func)78 validate_stencil_func(struct gl_context *ctx, GLenum func)
79 {
80 switch (func) {
81 case GL_NEVER:
82 case GL_LESS:
83 case GL_LEQUAL:
84 case GL_GREATER:
85 case GL_GEQUAL:
86 case GL_EQUAL:
87 case GL_NOTEQUAL:
88 case GL_ALWAYS:
89 return GL_TRUE;
90 default:
91 return GL_FALSE;
92 }
93 }
94
95
96 /**
97 * Set the clear value for the stencil buffer.
98 *
99 * \param s clear value.
100 *
101 * \sa glClearStencil().
102 *
103 * Updates gl_stencil_attrib::Clear. On change
104 * flushes the vertices and notifies the driver via
105 * the dd_function_table::ClearStencil callback.
106 */
107 void GLAPIENTRY
_mesa_ClearStencil(GLint s)108 _mesa_ClearStencil( GLint s )
109 {
110 GET_CURRENT_CONTEXT(ctx);
111
112 if (MESA_VERBOSE & VERBOSE_API)
113 _mesa_debug(ctx, "glClearStencil(%d)\n", s);
114
115 ctx->Stencil.Clear = (GLuint) s;
116 }
117
118
119 /**
120 * Set the function and reference value for stencil testing.
121 *
122 * \param frontfunc front test function.
123 * \param backfunc back test function.
124 * \param ref front and back reference value.
125 * \param mask front and back bitmask.
126 *
127 * \sa glStencilFunc().
128 *
129 * Verifies the parameters and updates the respective values in
130 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
131 * the driver via the dd_function_table::StencilFunc callback.
132 */
133 void GLAPIENTRY
_mesa_StencilFuncSeparateATI(GLenum frontfunc,GLenum backfunc,GLint ref,GLuint mask)134 _mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask )
135 {
136 GET_CURRENT_CONTEXT(ctx);
137
138 if (MESA_VERBOSE & VERBOSE_API)
139 _mesa_debug(ctx, "glStencilFuncSeparateATI()\n");
140
141 if (!validate_stencil_func(ctx, frontfunc)) {
142 _mesa_error(ctx, GL_INVALID_ENUM,
143 "glStencilFuncSeparateATI(frontfunc)");
144 return;
145 }
146 if (!validate_stencil_func(ctx, backfunc)) {
147 _mesa_error(ctx, GL_INVALID_ENUM,
148 "glStencilFuncSeparateATI(backfunc)");
149 return;
150 }
151
152 /* set both front and back state */
153 if (ctx->Stencil.Function[0] == frontfunc &&
154 ctx->Stencil.Function[1] == backfunc &&
155 ctx->Stencil.ValueMask[0] == mask &&
156 ctx->Stencil.ValueMask[1] == mask &&
157 ctx->Stencil.Ref[0] == ref &&
158 ctx->Stencil.Ref[1] == ref)
159 return;
160 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
161 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
162 ctx->Stencil.Function[0] = frontfunc;
163 ctx->Stencil.Function[1] = backfunc;
164 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref;
165 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
166 if (ctx->Driver.StencilFuncSeparate) {
167 ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT,
168 frontfunc, ref, mask);
169 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK,
170 backfunc, ref, mask);
171 }
172 }
173
174
175 /**
176 * Set the function and reference value for stencil testing.
177 *
178 * \param func test function.
179 * \param ref reference value.
180 * \param mask bitmask.
181 *
182 * \sa glStencilFunc().
183 *
184 * Verifies the parameters and updates the respective values in
185 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
186 * the driver via the dd_function_table::StencilFunc callback.
187 */
188 static void
stencil_func(struct gl_context * ctx,GLenum func,GLint ref,GLuint mask)189 stencil_func(struct gl_context *ctx, GLenum func, GLint ref, GLuint mask)
190 {
191 const GLint face = ctx->Stencil.ActiveFace;
192
193 if (face != 0) {
194 if (ctx->Stencil.Function[face] == func &&
195 ctx->Stencil.ValueMask[face] == mask &&
196 ctx->Stencil.Ref[face] == ref)
197 return;
198 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
199 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
200 ctx->Stencil.Function[face] = func;
201 ctx->Stencil.Ref[face] = ref;
202 ctx->Stencil.ValueMask[face] = mask;
203
204 /* Only propagate the change to the driver if EXT_stencil_two_side
205 * is enabled.
206 */
207 if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) {
208 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask);
209 }
210 }
211 else {
212 /* set both front and back state */
213 if (ctx->Stencil.Function[0] == func &&
214 ctx->Stencil.Function[1] == func &&
215 ctx->Stencil.ValueMask[0] == mask &&
216 ctx->Stencil.ValueMask[1] == mask &&
217 ctx->Stencil.Ref[0] == ref &&
218 ctx->Stencil.Ref[1] == ref)
219 return;
220 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
221 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
222 ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func;
223 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref;
224 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
225 if (ctx->Driver.StencilFuncSeparate) {
226 ctx->Driver.StencilFuncSeparate(ctx,
227 ((ctx->Stencil.TestTwoSide)
228 ? GL_FRONT : GL_FRONT_AND_BACK),
229 func, ref, mask);
230 }
231 }
232 }
233
234
235 void GLAPIENTRY
_mesa_StencilFunc_no_error(GLenum func,GLint ref,GLuint mask)236 _mesa_StencilFunc_no_error(GLenum func, GLint ref, GLuint mask)
237 {
238 GET_CURRENT_CONTEXT(ctx);
239 stencil_func(ctx, func, ref, mask);
240 }
241
242
243 void GLAPIENTRY
_mesa_StencilFunc(GLenum func,GLint ref,GLuint mask)244 _mesa_StencilFunc(GLenum func, GLint ref, GLuint mask)
245 {
246 GET_CURRENT_CONTEXT(ctx);
247
248 if (MESA_VERBOSE & VERBOSE_API)
249 _mesa_debug(ctx, "glStencilFunc()\n");
250
251 if (!validate_stencil_func(ctx, func)) {
252 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)");
253 return;
254 }
255
256 stencil_func(ctx, func, ref, mask);
257 }
258
259
260 /**
261 * Set the stencil writing mask.
262 *
263 * \param mask bit-mask to enable/disable writing of individual bits in the
264 * stencil planes.
265 *
266 * \sa glStencilMask().
267 *
268 * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
269 * notifies the driver via the dd_function_table::StencilMask callback.
270 */
271 void GLAPIENTRY
_mesa_StencilMask(GLuint mask)272 _mesa_StencilMask( GLuint mask )
273 {
274 GET_CURRENT_CONTEXT(ctx);
275 const GLint face = ctx->Stencil.ActiveFace;
276
277 if (MESA_VERBOSE & VERBOSE_API)
278 _mesa_debug(ctx, "glStencilMask()\n");
279
280 if (face != 0) {
281 /* Only modify the EXT_stencil_two_side back-face state.
282 */
283 if (ctx->Stencil.WriteMask[face] == mask)
284 return;
285 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
286 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
287 ctx->Stencil.WriteMask[face] = mask;
288
289 /* Only propagate the change to the driver if EXT_stencil_two_side
290 * is enabled.
291 */
292 if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) {
293 ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask);
294 }
295 }
296 else {
297 /* set both front and back state */
298 if (ctx->Stencil.WriteMask[0] == mask &&
299 ctx->Stencil.WriteMask[1] == mask)
300 return;
301 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
302 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
303 ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask;
304 if (ctx->Driver.StencilMaskSeparate) {
305 ctx->Driver.StencilMaskSeparate(ctx,
306 ((ctx->Stencil.TestTwoSide)
307 ? GL_FRONT : GL_FRONT_AND_BACK),
308 mask);
309 }
310 }
311 }
312
313
314 /**
315 * Set the stencil test actions.
316 *
317 * \param fail action to take when stencil test fails.
318 * \param zfail action to take when stencil test passes, but depth test fails.
319 * \param zpass action to take when stencil test passes and the depth test
320 * passes (or depth testing is not enabled).
321 *
322 * \sa glStencilOp().
323 *
324 * Verifies the parameters and updates the respective fields in
325 * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
326 * the driver via the dd_function_table::StencilOp callback.
327 */
328 static void
stencil_op(struct gl_context * ctx,GLenum fail,GLenum zfail,GLenum zpass)329 stencil_op(struct gl_context *ctx, GLenum fail, GLenum zfail, GLenum zpass)
330 {
331 const GLint face = ctx->Stencil.ActiveFace;
332
333 if (face != 0) {
334 /* only set active face state */
335 if (ctx->Stencil.ZFailFunc[face] == zfail &&
336 ctx->Stencil.ZPassFunc[face] == zpass &&
337 ctx->Stencil.FailFunc[face] == fail)
338 return;
339 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
340 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
341 ctx->Stencil.ZFailFunc[face] = zfail;
342 ctx->Stencil.ZPassFunc[face] = zpass;
343 ctx->Stencil.FailFunc[face] = fail;
344
345 /* Only propagate the change to the driver if EXT_stencil_two_side
346 * is enabled.
347 */
348 if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) {
349 ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass);
350 }
351 }
352 else {
353 /* set both front and back state */
354 if (ctx->Stencil.ZFailFunc[0] == zfail &&
355 ctx->Stencil.ZFailFunc[1] == zfail &&
356 ctx->Stencil.ZPassFunc[0] == zpass &&
357 ctx->Stencil.ZPassFunc[1] == zpass &&
358 ctx->Stencil.FailFunc[0] == fail &&
359 ctx->Stencil.FailFunc[1] == fail)
360 return;
361 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
362 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
363 ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail;
364 ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass;
365 ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail;
366 if (ctx->Driver.StencilOpSeparate) {
367 ctx->Driver.StencilOpSeparate(ctx,
368 ((ctx->Stencil.TestTwoSide)
369 ? GL_FRONT : GL_FRONT_AND_BACK),
370 fail, zfail, zpass);
371 }
372 }
373 }
374
375
376 void GLAPIENTRY
_mesa_StencilOp_no_error(GLenum fail,GLenum zfail,GLenum zpass)377 _mesa_StencilOp_no_error(GLenum fail, GLenum zfail, GLenum zpass)
378 {
379 GET_CURRENT_CONTEXT(ctx);
380 stencil_op(ctx, fail, zfail, zpass);
381 }
382
383
384 void GLAPIENTRY
_mesa_StencilOp(GLenum fail,GLenum zfail,GLenum zpass)385 _mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
386 {
387 GET_CURRENT_CONTEXT(ctx);
388
389 if (MESA_VERBOSE & VERBOSE_API)
390 _mesa_debug(ctx, "glStencilOp()\n");
391
392 if (!validate_stencil_op(ctx, fail)) {
393 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)");
394 return;
395 }
396
397 if (!validate_stencil_op(ctx, zfail)) {
398 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)");
399 return;
400 }
401
402 if (!validate_stencil_op(ctx, zpass)) {
403 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)");
404 return;
405 }
406
407 stencil_op(ctx, fail, zfail, zpass);
408 }
409
410
411 /* GL_EXT_stencil_two_side */
412 void GLAPIENTRY
_mesa_ActiveStencilFaceEXT(GLenum face)413 _mesa_ActiveStencilFaceEXT(GLenum face)
414 {
415 GET_CURRENT_CONTEXT(ctx);
416
417 if (MESA_VERBOSE & VERBOSE_API)
418 _mesa_debug(ctx, "glActiveStencilFaceEXT()\n");
419
420 if (!ctx->Extensions.EXT_stencil_two_side) {
421 _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT");
422 return;
423 }
424
425 if (face == GL_FRONT || face == GL_BACK) {
426 ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2;
427 }
428 else {
429 _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)");
430 }
431 }
432
433
434 static void
stencil_op_separate(struct gl_context * ctx,GLenum face,GLenum sfail,GLenum zfail,GLenum zpass)435 stencil_op_separate(struct gl_context *ctx, GLenum face, GLenum sfail,
436 GLenum zfail, GLenum zpass)
437 {
438 GLboolean set = GL_FALSE;
439
440 if (face != GL_BACK) {
441 /* set front */
442 if (ctx->Stencil.ZFailFunc[0] != zfail ||
443 ctx->Stencil.ZPassFunc[0] != zpass ||
444 ctx->Stencil.FailFunc[0] != sfail){
445 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
446 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
447 ctx->Stencil.ZFailFunc[0] = zfail;
448 ctx->Stencil.ZPassFunc[0] = zpass;
449 ctx->Stencil.FailFunc[0] = sfail;
450 set = GL_TRUE;
451 }
452 }
453
454 if (face != GL_FRONT) {
455 /* set back */
456 if (ctx->Stencil.ZFailFunc[1] != zfail ||
457 ctx->Stencil.ZPassFunc[1] != zpass ||
458 ctx->Stencil.FailFunc[1] != sfail) {
459 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
460 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
461 ctx->Stencil.ZFailFunc[1] = zfail;
462 ctx->Stencil.ZPassFunc[1] = zpass;
463 ctx->Stencil.FailFunc[1] = sfail;
464 set = GL_TRUE;
465 }
466 }
467
468 if (set && ctx->Driver.StencilOpSeparate) {
469 ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass);
470 }
471 }
472
473
474 void GLAPIENTRY
_mesa_StencilOpSeparate_no_error(GLenum face,GLenum sfail,GLenum zfail,GLenum zpass)475 _mesa_StencilOpSeparate_no_error(GLenum face, GLenum sfail, GLenum zfail,
476 GLenum zpass)
477 {
478 GET_CURRENT_CONTEXT(ctx);
479 stencil_op_separate(ctx, face, sfail, zfail, zpass);
480 }
481
482
483 void GLAPIENTRY
_mesa_StencilOpSeparate(GLenum face,GLenum sfail,GLenum zfail,GLenum zpass)484 _mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass)
485 {
486 GET_CURRENT_CONTEXT(ctx);
487
488 if (MESA_VERBOSE & VERBOSE_API)
489 _mesa_debug(ctx, "glStencilOpSeparate()\n");
490
491 if (!validate_stencil_op(ctx, sfail)) {
492 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)");
493 return;
494 }
495
496 if (!validate_stencil_op(ctx, zfail)) {
497 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)");
498 return;
499 }
500
501 if (!validate_stencil_op(ctx, zpass)) {
502 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)");
503 return;
504 }
505
506 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
507 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)");
508 return;
509 }
510
511 stencil_op_separate(ctx, face, sfail, zfail, zpass);
512 }
513
514
515 static void
stencil_func_separate(struct gl_context * ctx,GLenum face,GLenum func,GLint ref,GLuint mask)516 stencil_func_separate(struct gl_context *ctx, GLenum face, GLenum func,
517 GLint ref, GLuint mask)
518 {
519 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
520 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
521
522 if (face != GL_BACK) {
523 /* set front */
524 ctx->Stencil.Function[0] = func;
525 ctx->Stencil.Ref[0] = ref;
526 ctx->Stencil.ValueMask[0] = mask;
527 }
528
529 if (face != GL_FRONT) {
530 /* set back */
531 ctx->Stencil.Function[1] = func;
532 ctx->Stencil.Ref[1] = ref;
533 ctx->Stencil.ValueMask[1] = mask;
534 }
535
536 if (ctx->Driver.StencilFuncSeparate) {
537 ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask);
538 }
539 }
540
541
542 /* OpenGL 2.0 */
543 void GLAPIENTRY
_mesa_StencilFuncSeparate_no_error(GLenum face,GLenum func,GLint ref,GLuint mask)544 _mesa_StencilFuncSeparate_no_error(GLenum face, GLenum func, GLint ref,
545 GLuint mask)
546 {
547 GET_CURRENT_CONTEXT(ctx);
548 stencil_func_separate(ctx, face, func, ref, mask);
549 }
550
551
552 void GLAPIENTRY
_mesa_StencilFuncSeparate(GLenum face,GLenum func,GLint ref,GLuint mask)553 _mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
554 {
555 GET_CURRENT_CONTEXT(ctx);
556
557 if (MESA_VERBOSE & VERBOSE_API)
558 _mesa_debug(ctx, "glStencilFuncSeparate()\n");
559
560 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
561 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)");
562 return;
563 }
564
565 if (!validate_stencil_func(ctx, func)) {
566 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)");
567 return;
568 }
569
570 stencil_func_separate(ctx, face, func, ref, mask);
571 }
572
573
574 static void
stencil_mask_separate(struct gl_context * ctx,GLenum face,GLuint mask)575 stencil_mask_separate(struct gl_context *ctx, GLenum face, GLuint mask)
576 {
577 FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL);
578 ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
579
580 if (face != GL_BACK) {
581 ctx->Stencil.WriteMask[0] = mask;
582 }
583
584 if (face != GL_FRONT) {
585 ctx->Stencil.WriteMask[1] = mask;
586 }
587
588 if (ctx->Driver.StencilMaskSeparate) {
589 ctx->Driver.StencilMaskSeparate(ctx, face, mask);
590 }
591 }
592
593
594 /* OpenGL 2.0 */
595 void GLAPIENTRY
_mesa_StencilMaskSeparate_no_error(GLenum face,GLuint mask)596 _mesa_StencilMaskSeparate_no_error(GLenum face, GLuint mask)
597 {
598 GET_CURRENT_CONTEXT(ctx);
599 stencil_mask_separate(ctx, face, mask);
600 }
601
602
603 void GLAPIENTRY
_mesa_StencilMaskSeparate(GLenum face,GLuint mask)604 _mesa_StencilMaskSeparate(GLenum face, GLuint mask)
605 {
606 GET_CURRENT_CONTEXT(ctx);
607
608 if (MESA_VERBOSE & VERBOSE_API)
609 _mesa_debug(ctx, "glStencilMaskSeparate()\n");
610
611 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
612 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)");
613 return;
614 }
615
616 stencil_mask_separate(ctx, face, mask);
617 }
618
619
620 /**
621 * Initialize the context stipple state.
622 *
623 * \param ctx GL context.
624 *
625 * Initializes __struct gl_contextRec::Stencil attribute group.
626 */
627 void
_mesa_init_stencil(struct gl_context * ctx)628 _mesa_init_stencil(struct gl_context *ctx)
629 {
630 ctx->Stencil.Enabled = GL_FALSE;
631 ctx->Stencil.TestTwoSide = GL_FALSE;
632 ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */
633 ctx->Stencil.Function[0] = GL_ALWAYS;
634 ctx->Stencil.Function[1] = GL_ALWAYS;
635 ctx->Stencil.Function[2] = GL_ALWAYS;
636 ctx->Stencil.FailFunc[0] = GL_KEEP;
637 ctx->Stencil.FailFunc[1] = GL_KEEP;
638 ctx->Stencil.FailFunc[2] = GL_KEEP;
639 ctx->Stencil.ZPassFunc[0] = GL_KEEP;
640 ctx->Stencil.ZPassFunc[1] = GL_KEEP;
641 ctx->Stencil.ZPassFunc[2] = GL_KEEP;
642 ctx->Stencil.ZFailFunc[0] = GL_KEEP;
643 ctx->Stencil.ZFailFunc[1] = GL_KEEP;
644 ctx->Stencil.ZFailFunc[2] = GL_KEEP;
645 ctx->Stencil.Ref[0] = 0;
646 ctx->Stencil.Ref[1] = 0;
647 ctx->Stencil.Ref[2] = 0;
648
649 /* 4.1.4 Stencil Test section of the GL-ES 3.0 specification says:
650 *
651 * "In the initial state, [...] the front and back stencil mask are both
652 * set to the value 2^s − 1, where s is greater than or equal to the
653 * number of bits in the deepest stencil buffer* supported by the GL
654 * implementation."
655 *
656 * Since the maximum supported precision for stencil buffers is 8 bits,
657 * mask values should be initialized to 2^8 - 1 = 0xFF.
658 */
659 ctx->Stencil.ValueMask[0] = 0xFF;
660 ctx->Stencil.ValueMask[1] = 0xFF;
661 ctx->Stencil.ValueMask[2] = 0xFF;
662 ctx->Stencil.WriteMask[0] = 0xFF;
663 ctx->Stencil.WriteMask[1] = 0xFF;
664 ctx->Stencil.WriteMask[2] = 0xFF;
665
666 ctx->Stencil.Clear = 0;
667 ctx->Stencil._BackFace = 1;
668 }
669