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