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