stencil.c revision 7ec681f3
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
58static GLboolean
59validate_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
77static GLboolean
78validate_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 */
107void GLAPIENTRY
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 */
134void GLAPIENTRY
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 */
190static void
191stencil_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
239void GLAPIENTRY
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
247void GLAPIENTRY
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 */
275void GLAPIENTRY
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 */
334static void
335stencil_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
384void GLAPIENTRY
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
392void GLAPIENTRY
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 */
420void GLAPIENTRY
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
442static void
443stencil_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
484void GLAPIENTRY
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
493void GLAPIENTRY
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
525static void
526stencil_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 */
554void GLAPIENTRY
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
563void GLAPIENTRY
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
585static void
586stencil_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 */
607void GLAPIENTRY
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
615void GLAPIENTRY
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 */
639void
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