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->PopAttribState |= GL_STENCIL_BUFFER_BIT;
116    ctx->Stencil.Clear = (GLuint) s;
117 }
118 
119 
120 /**
121  * Set the function and reference value for stencil testing.
122  *
123  * \param frontfunc front test function.
124  * \param backfunc back test function.
125  * \param ref front and back reference value.
126  * \param mask front and back bitmask.
127  *
128  * \sa glStencilFunc().
129  *
130  * Verifies the parameters and updates the respective values in
131  * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
132  * the driver via the dd_function_table::StencilFunc callback.
133  */
134 void GLAPIENTRY
_mesa_StencilFuncSeparateATI(GLenum frontfunc,GLenum backfunc,GLint ref,GLuint mask)135 _mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask )
136 {
137    GET_CURRENT_CONTEXT(ctx);
138 
139    if (MESA_VERBOSE & VERBOSE_API)
140       _mesa_debug(ctx, "glStencilFuncSeparateATI()\n");
141 
142    if (!validate_stencil_func(ctx, frontfunc)) {
143       _mesa_error(ctx, GL_INVALID_ENUM,
144                   "glStencilFuncSeparateATI(frontfunc)");
145       return;
146    }
147    if (!validate_stencil_func(ctx, backfunc)) {
148       _mesa_error(ctx, GL_INVALID_ENUM,
149                   "glStencilFuncSeparateATI(backfunc)");
150       return;
151    }
152 
153    /* set both front and back state */
154    if (ctx->Stencil.Function[0] == frontfunc &&
155        ctx->Stencil.Function[1] == backfunc &&
156        ctx->Stencil.ValueMask[0] == mask &&
157        ctx->Stencil.ValueMask[1] == mask &&
158        ctx->Stencil.Ref[0] == ref &&
159        ctx->Stencil.Ref[1] == ref)
160       return;
161    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
162                   GL_STENCIL_BUFFER_BIT);
163    ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
164    ctx->Stencil.Function[0]  = frontfunc;
165    ctx->Stencil.Function[1]  = backfunc;
166    ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
167    ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
168    if (ctx->Driver.StencilFuncSeparate) {
169       ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT,
170                                       frontfunc, ref, mask);
171       ctx->Driver.StencilFuncSeparate(ctx, GL_BACK,
172                                       backfunc, ref, mask);
173    }
174 }
175 
176 
177 /**
178  * Set the function and reference value for stencil testing.
179  *
180  * \param func test function.
181  * \param ref reference value.
182  * \param mask bitmask.
183  *
184  * \sa glStencilFunc().
185  *
186  * Verifies the parameters and updates the respective values in
187  * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
188  * the driver via the dd_function_table::StencilFunc callback.
189  */
190 static void
stencil_func(struct gl_context * ctx,GLenum func,GLint ref,GLuint mask)191 stencil_func(struct gl_context *ctx, GLenum func, GLint ref, GLuint mask)
192 {
193    const GLint face = ctx->Stencil.ActiveFace;
194 
195    if (face != 0) {
196       if (ctx->Stencil.Function[face] == func &&
197           ctx->Stencil.ValueMask[face] == mask &&
198           ctx->Stencil.Ref[face] == ref)
199          return;
200       FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
201                      GL_STENCIL_BUFFER_BIT);
202       ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
203       ctx->Stencil.Function[face] = func;
204       ctx->Stencil.Ref[face] = ref;
205       ctx->Stencil.ValueMask[face] = mask;
206 
207       /* Only propagate the change to the driver if EXT_stencil_two_side
208        * is enabled.
209        */
210       if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) {
211          ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask);
212       }
213    }
214    else {
215       /* set both front and back state */
216       if (ctx->Stencil.Function[0] == func &&
217           ctx->Stencil.Function[1] == func &&
218           ctx->Stencil.ValueMask[0] == mask &&
219           ctx->Stencil.ValueMask[1] == mask &&
220           ctx->Stencil.Ref[0] == ref &&
221           ctx->Stencil.Ref[1] == ref)
222          return;
223       FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
224                      GL_STENCIL_BUFFER_BIT);
225       ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
226       ctx->Stencil.Function[0]  = ctx->Stencil.Function[1]  = func;
227       ctx->Stencil.Ref[0]       = ctx->Stencil.Ref[1]       = ref;
228       ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
229       if (ctx->Driver.StencilFuncSeparate) {
230          ctx->Driver.StencilFuncSeparate(ctx,
231 					 ((ctx->Stencil.TestTwoSide)
232 					  ? GL_FRONT : GL_FRONT_AND_BACK),
233                                          func, ref, mask);
234       }
235    }
236 }
237 
238 
239 void GLAPIENTRY
_mesa_StencilFunc_no_error(GLenum func,GLint ref,GLuint mask)240 _mesa_StencilFunc_no_error(GLenum func, GLint ref, GLuint mask)
241 {
242    GET_CURRENT_CONTEXT(ctx);
243    stencil_func(ctx, func, ref, mask);
244 }
245 
246 
247 void GLAPIENTRY
_mesa_StencilFunc(GLenum func,GLint ref,GLuint mask)248 _mesa_StencilFunc(GLenum func, GLint ref, GLuint mask)
249 {
250    GET_CURRENT_CONTEXT(ctx);
251 
252    if (MESA_VERBOSE & VERBOSE_API)
253       _mesa_debug(ctx, "glStencilFunc()\n");
254 
255    if (!validate_stencil_func(ctx, func)) {
256       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)");
257       return;
258    }
259 
260    stencil_func(ctx, func, ref, mask);
261 }
262 
263 
264 /**
265  * Set the stencil writing mask.
266  *
267  * \param mask bit-mask to enable/disable writing of individual bits in the
268  * stencil planes.
269  *
270  * \sa glStencilMask().
271  *
272  * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
273  * notifies the driver via the dd_function_table::StencilMask callback.
274  */
275 void GLAPIENTRY
_mesa_StencilMask(GLuint mask)276 _mesa_StencilMask( GLuint mask )
277 {
278    GET_CURRENT_CONTEXT(ctx);
279    const GLint face = ctx->Stencil.ActiveFace;
280 
281    if (MESA_VERBOSE & VERBOSE_API)
282       _mesa_debug(ctx, "glStencilMask()\n");
283 
284    if (face != 0) {
285       /* Only modify the EXT_stencil_two_side back-face state.
286        */
287       if (ctx->Stencil.WriteMask[face] == mask)
288          return;
289       FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
290                      GL_STENCIL_BUFFER_BIT);
291       ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
292       ctx->Stencil.WriteMask[face] = mask;
293 
294       /* Only propagate the change to the driver if EXT_stencil_two_side
295        * is enabled.
296        */
297       if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) {
298          ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask);
299       }
300    }
301    else {
302       /* set both front and back state */
303       if (ctx->Stencil.WriteMask[0] == mask &&
304           ctx->Stencil.WriteMask[1] == mask)
305          return;
306       FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
307                      GL_STENCIL_BUFFER_BIT);
308       ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
309       ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask;
310       if (ctx->Driver.StencilMaskSeparate) {
311          ctx->Driver.StencilMaskSeparate(ctx,
312 					 ((ctx->Stencil.TestTwoSide)
313 					  ? GL_FRONT : GL_FRONT_AND_BACK),
314 					  mask);
315       }
316    }
317 }
318 
319 
320 /**
321  * Set the stencil test actions.
322  *
323  * \param fail action to take when stencil test fails.
324  * \param zfail action to take when stencil test passes, but depth test fails.
325  * \param zpass action to take when stencil test passes and the depth test
326  * passes (or depth testing is not enabled).
327  *
328  * \sa glStencilOp().
329  *
330  * Verifies the parameters and updates the respective fields in
331  * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies
332  * the driver via the dd_function_table::StencilOp callback.
333  */
334 static void
stencil_op(struct gl_context * ctx,GLenum fail,GLenum zfail,GLenum zpass)335 stencil_op(struct gl_context *ctx, GLenum fail, GLenum zfail, GLenum zpass)
336 {
337    const GLint face = ctx->Stencil.ActiveFace;
338 
339    if (face != 0) {
340       /* only set active face state */
341       if (ctx->Stencil.ZFailFunc[face] == zfail &&
342           ctx->Stencil.ZPassFunc[face] == zpass &&
343           ctx->Stencil.FailFunc[face] == fail)
344          return;
345       FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
346                      GL_STENCIL_BUFFER_BIT);
347       ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
348       ctx->Stencil.ZFailFunc[face] = zfail;
349       ctx->Stencil.ZPassFunc[face] = zpass;
350       ctx->Stencil.FailFunc[face] = fail;
351 
352       /* Only propagate the change to the driver if EXT_stencil_two_side
353        * is enabled.
354        */
355       if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) {
356          ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass);
357       }
358    }
359    else {
360       /* set both front and back state */
361       if (ctx->Stencil.ZFailFunc[0] == zfail &&
362           ctx->Stencil.ZFailFunc[1] == zfail &&
363           ctx->Stencil.ZPassFunc[0] == zpass &&
364           ctx->Stencil.ZPassFunc[1] == zpass &&
365           ctx->Stencil.FailFunc[0] == fail &&
366           ctx->Stencil.FailFunc[1] == fail)
367          return;
368       FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
369                      GL_STENCIL_BUFFER_BIT);
370       ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
371       ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail;
372       ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass;
373       ctx->Stencil.FailFunc[0]  = ctx->Stencil.FailFunc[1]  = fail;
374       if (ctx->Driver.StencilOpSeparate) {
375          ctx->Driver.StencilOpSeparate(ctx,
376 				       ((ctx->Stencil.TestTwoSide)
377 					? GL_FRONT : GL_FRONT_AND_BACK),
378                                        fail, zfail, zpass);
379       }
380    }
381 }
382 
383 
384 void GLAPIENTRY
_mesa_StencilOp_no_error(GLenum fail,GLenum zfail,GLenum zpass)385 _mesa_StencilOp_no_error(GLenum fail, GLenum zfail, GLenum zpass)
386 {
387    GET_CURRENT_CONTEXT(ctx);
388    stencil_op(ctx, fail, zfail, zpass);
389 }
390 
391 
392 void GLAPIENTRY
_mesa_StencilOp(GLenum fail,GLenum zfail,GLenum zpass)393 _mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
394 {
395    GET_CURRENT_CONTEXT(ctx);
396 
397    if (MESA_VERBOSE & VERBOSE_API)
398       _mesa_debug(ctx, "glStencilOp()\n");
399 
400    if (!validate_stencil_op(ctx, fail)) {
401       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)");
402       return;
403    }
404 
405    if (!validate_stencil_op(ctx, zfail)) {
406       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)");
407       return;
408    }
409 
410    if (!validate_stencil_op(ctx, zpass)) {
411       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)");
412       return;
413    }
414 
415    stencil_op(ctx, fail, zfail, zpass);
416 }
417 
418 
419 /* GL_EXT_stencil_two_side */
420 void GLAPIENTRY
_mesa_ActiveStencilFaceEXT(GLenum face)421 _mesa_ActiveStencilFaceEXT(GLenum face)
422 {
423    GET_CURRENT_CONTEXT(ctx);
424 
425    if (MESA_VERBOSE & VERBOSE_API)
426       _mesa_debug(ctx, "glActiveStencilFaceEXT()\n");
427 
428    if (!ctx->Extensions.EXT_stencil_two_side) {
429       _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT");
430       return;
431    }
432 
433    if (face == GL_FRONT || face == GL_BACK) {
434       ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2;
435    }
436    else {
437       _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)");
438    }
439 }
440 
441 
442 static void
stencil_op_separate(struct gl_context * ctx,GLenum face,GLenum sfail,GLenum zfail,GLenum zpass)443 stencil_op_separate(struct gl_context *ctx, GLenum face, GLenum sfail,
444                     GLenum zfail, GLenum zpass)
445 {
446    GLboolean set = GL_FALSE;
447 
448    if (face != GL_BACK) {
449       /* set front */
450       if (ctx->Stencil.ZFailFunc[0] != zfail ||
451           ctx->Stencil.ZPassFunc[0] != zpass ||
452           ctx->Stencil.FailFunc[0] != sfail){
453          FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
454                         GL_STENCIL_BUFFER_BIT);
455          ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
456          ctx->Stencil.ZFailFunc[0] = zfail;
457          ctx->Stencil.ZPassFunc[0] = zpass;
458          ctx->Stencil.FailFunc[0] = sfail;
459          set = GL_TRUE;
460       }
461    }
462 
463    if (face != GL_FRONT) {
464       /* set back */
465       if (ctx->Stencil.ZFailFunc[1] != zfail ||
466           ctx->Stencil.ZPassFunc[1] != zpass ||
467           ctx->Stencil.FailFunc[1] != sfail) {
468          FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
469                         GL_STENCIL_BUFFER_BIT);
470          ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
471          ctx->Stencil.ZFailFunc[1] = zfail;
472          ctx->Stencil.ZPassFunc[1] = zpass;
473          ctx->Stencil.FailFunc[1] = sfail;
474          set = GL_TRUE;
475       }
476    }
477 
478    if (set && ctx->Driver.StencilOpSeparate) {
479       ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass);
480    }
481 }
482 
483 
484 void GLAPIENTRY
_mesa_StencilOpSeparate_no_error(GLenum face,GLenum sfail,GLenum zfail,GLenum zpass)485 _mesa_StencilOpSeparate_no_error(GLenum face, GLenum sfail, GLenum zfail,
486                                  GLenum zpass)
487 {
488    GET_CURRENT_CONTEXT(ctx);
489    stencil_op_separate(ctx, face, sfail, zfail, zpass);
490 }
491 
492 
493 void GLAPIENTRY
_mesa_StencilOpSeparate(GLenum face,GLenum sfail,GLenum zfail,GLenum zpass)494 _mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass)
495 {
496    GET_CURRENT_CONTEXT(ctx);
497 
498    if (MESA_VERBOSE & VERBOSE_API)
499       _mesa_debug(ctx, "glStencilOpSeparate()\n");
500 
501    if (!validate_stencil_op(ctx, sfail)) {
502       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)");
503       return;
504    }
505 
506    if (!validate_stencil_op(ctx, zfail)) {
507       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)");
508       return;
509    }
510 
511    if (!validate_stencil_op(ctx, zpass)) {
512       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)");
513       return;
514    }
515 
516    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
517       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)");
518       return;
519    }
520 
521    stencil_op_separate(ctx, face, sfail, zfail, zpass);
522 }
523 
524 
525 static void
stencil_func_separate(struct gl_context * ctx,GLenum face,GLenum func,GLint ref,GLuint mask)526 stencil_func_separate(struct gl_context *ctx, GLenum face, GLenum func,
527                       GLint ref, GLuint mask)
528 {
529    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
530                   GL_STENCIL_BUFFER_BIT);
531    ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
532 
533    if (face != GL_BACK) {
534       /* set front */
535       ctx->Stencil.Function[0] = func;
536       ctx->Stencil.Ref[0] = ref;
537       ctx->Stencil.ValueMask[0] = mask;
538    }
539 
540    if (face != GL_FRONT) {
541       /* set back */
542       ctx->Stencil.Function[1] = func;
543       ctx->Stencil.Ref[1] = ref;
544       ctx->Stencil.ValueMask[1] = mask;
545    }
546 
547    if (ctx->Driver.StencilFuncSeparate) {
548       ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask);
549    }
550 }
551 
552 
553 /* OpenGL 2.0 */
554 void GLAPIENTRY
_mesa_StencilFuncSeparate_no_error(GLenum face,GLenum func,GLint ref,GLuint mask)555 _mesa_StencilFuncSeparate_no_error(GLenum face, GLenum func, GLint ref,
556                                    GLuint mask)
557 {
558    GET_CURRENT_CONTEXT(ctx);
559    stencil_func_separate(ctx, face, func, ref, mask);
560 }
561 
562 
563 void GLAPIENTRY
_mesa_StencilFuncSeparate(GLenum face,GLenum func,GLint ref,GLuint mask)564 _mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
565 {
566    GET_CURRENT_CONTEXT(ctx);
567 
568    if (MESA_VERBOSE & VERBOSE_API)
569       _mesa_debug(ctx, "glStencilFuncSeparate()\n");
570 
571    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
572       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)");
573       return;
574    }
575 
576    if (!validate_stencil_func(ctx, func)) {
577       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)");
578       return;
579    }
580 
581    stencil_func_separate(ctx, face, func, ref, mask);
582 }
583 
584 
585 static void
stencil_mask_separate(struct gl_context * ctx,GLenum face,GLuint mask)586 stencil_mask_separate(struct gl_context *ctx, GLenum face, GLuint mask)
587 {
588    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL,
589                   GL_STENCIL_BUFFER_BIT);
590    ctx->NewDriverState |= ctx->DriverFlags.NewStencil;
591 
592    if (face != GL_BACK) {
593       ctx->Stencil.WriteMask[0] = mask;
594    }
595 
596    if (face != GL_FRONT) {
597       ctx->Stencil.WriteMask[1] = mask;
598    }
599 
600    if (ctx->Driver.StencilMaskSeparate) {
601       ctx->Driver.StencilMaskSeparate(ctx, face, mask);
602    }
603 }
604 
605 
606 /* OpenGL 2.0 */
607 void GLAPIENTRY
_mesa_StencilMaskSeparate_no_error(GLenum face,GLuint mask)608 _mesa_StencilMaskSeparate_no_error(GLenum face, GLuint mask)
609 {
610    GET_CURRENT_CONTEXT(ctx);
611    stencil_mask_separate(ctx, face, mask);
612 }
613 
614 
615 void GLAPIENTRY
_mesa_StencilMaskSeparate(GLenum face,GLuint mask)616 _mesa_StencilMaskSeparate(GLenum face, GLuint mask)
617 {
618    GET_CURRENT_CONTEXT(ctx);
619 
620    if (MESA_VERBOSE & VERBOSE_API)
621       _mesa_debug(ctx, "glStencilMaskSeparate()\n");
622 
623    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
624       _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)");
625       return;
626    }
627 
628    stencil_mask_separate(ctx, face, mask);
629 }
630 
631 
632 /**
633  * Initialize the context stipple state.
634  *
635  * \param ctx GL context.
636  *
637  * Initializes __struct gl_contextRec::Stencil attribute group.
638  */
639 void
_mesa_init_stencil(struct gl_context * ctx)640 _mesa_init_stencil(struct gl_context *ctx)
641 {
642    ctx->Stencil.Enabled = GL_FALSE;
643    ctx->Stencil.TestTwoSide = GL_FALSE;
644    ctx->Stencil.ActiveFace = 0;  /* 0 = GL_FRONT, 2 = GL_BACK */
645    ctx->Stencil.Function[0] = GL_ALWAYS;
646    ctx->Stencil.Function[1] = GL_ALWAYS;
647    ctx->Stencil.Function[2] = GL_ALWAYS;
648    ctx->Stencil.FailFunc[0] = GL_KEEP;
649    ctx->Stencil.FailFunc[1] = GL_KEEP;
650    ctx->Stencil.FailFunc[2] = GL_KEEP;
651    ctx->Stencil.ZPassFunc[0] = GL_KEEP;
652    ctx->Stencil.ZPassFunc[1] = GL_KEEP;
653    ctx->Stencil.ZPassFunc[2] = GL_KEEP;
654    ctx->Stencil.ZFailFunc[0] = GL_KEEP;
655    ctx->Stencil.ZFailFunc[1] = GL_KEEP;
656    ctx->Stencil.ZFailFunc[2] = GL_KEEP;
657    ctx->Stencil.Ref[0] = 0;
658    ctx->Stencil.Ref[1] = 0;
659    ctx->Stencil.Ref[2] = 0;
660 
661    /* 4.1.4 Stencil Test section of the GL-ES 3.0 specification says:
662     *
663     *     "In the initial state, [...] the front and back stencil mask are both
664     *     set to the value 2^s − 1, where s is greater than or equal to the
665     *     number of bits in the deepest stencil buffer* supported by the GL
666     *     implementation."
667     *
668     * Since the maximum supported precision for stencil buffers is 8 bits,
669     * mask values should be initialized to 2^8 - 1 = 0xFF.
670     */
671    ctx->Stencil.ValueMask[0] = 0xFF;
672    ctx->Stencil.ValueMask[1] = 0xFF;
673    ctx->Stencil.ValueMask[2] = 0xFF;
674    ctx->Stencil.WriteMask[0] = 0xFF;
675    ctx->Stencil.WriteMask[1] = 0xFF;
676    ctx->Stencil.WriteMask[2] = 0xFF;
677 
678    ctx->Stencil.Clear = 0;
679    ctx->Stencil._BackFace = 1;
680 }
681