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