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 
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