Merge branch 'master' into gallium-texture-transfer
[mesa.git] / src / mesa / main / stencil.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * \file stencil.c
28 * Stencil operations.
29 *
30 */
31
32
33 #include "glheader.h"
34 #include "imports.h"
35 #include "context.h"
36 #include "macros.h"
37 #include "stencil.h"
38 #include "mtypes.h"
39
40
41 static GLboolean
42 validate_stencil_op(GLcontext *ctx, GLenum op)
43 {
44 switch (op) {
45 case GL_KEEP:
46 case GL_ZERO:
47 case GL_REPLACE:
48 case GL_INCR:
49 case GL_DECR:
50 case GL_INVERT:
51 return GL_TRUE;
52 case GL_INCR_WRAP_EXT:
53 case GL_DECR_WRAP_EXT:
54 if (ctx->Extensions.EXT_stencil_wrap) {
55 return GL_TRUE;
56 }
57 /* FALL-THROUGH */
58 default:
59 return GL_FALSE;
60 }
61 }
62
63
64 static GLboolean
65 validate_stencil_func(GLcontext *ctx, GLenum func)
66 {
67 switch (func) {
68 case GL_NEVER:
69 case GL_LESS:
70 case GL_LEQUAL:
71 case GL_GREATER:
72 case GL_GEQUAL:
73 case GL_EQUAL:
74 case GL_NOTEQUAL:
75 case GL_ALWAYS:
76 return GL_TRUE;
77 default:
78 return GL_FALSE;
79 }
80 }
81
82
83 /**
84 * Set the clear value for the stencil buffer.
85 *
86 * \param s clear value.
87 *
88 * \sa glClearStencil().
89 *
90 * Updates gl_stencil_attrib::Clear. On change
91 * flushes the vertices and notifies the driver via
92 * the dd_function_table::ClearStencil callback.
93 */
94 void GLAPIENTRY
95 _mesa_ClearStencil( GLint s )
96 {
97 GET_CURRENT_CONTEXT(ctx);
98 ASSERT_OUTSIDE_BEGIN_END(ctx);
99
100 if (ctx->Stencil.Clear == (GLuint) s)
101 return;
102
103 FLUSH_VERTICES(ctx, _NEW_STENCIL);
104 ctx->Stencil.Clear = (GLuint) s;
105
106 if (ctx->Driver.ClearStencil) {
107 ctx->Driver.ClearStencil( ctx, s );
108 }
109 }
110
111
112 /**
113 * Set the function and reference value for stencil testing.
114 *
115 * \param frontfunc front test function.
116 * \param backfunc back test function.
117 * \param ref front and back reference value.
118 * \param mask front and back bitmask.
119 *
120 * \sa glStencilFunc().
121 *
122 * Verifies the parameters and updates the respective values in
123 * __GLcontextRec::Stencil. On change flushes the vertices and notifies the
124 * driver via the dd_function_table::StencilFunc callback.
125 */
126 void GLAPIENTRY
127 _mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask )
128 {
129 GET_CURRENT_CONTEXT(ctx);
130 const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
131 ASSERT_OUTSIDE_BEGIN_END(ctx);
132
133 if (!validate_stencil_func(ctx, frontfunc)) {
134 _mesa_error(ctx, GL_INVALID_ENUM,
135 "glStencilFuncSeparateATI(frontfunc)");
136 return;
137 }
138 if (!validate_stencil_func(ctx, backfunc)) {
139 _mesa_error(ctx, GL_INVALID_ENUM,
140 "glStencilFuncSeparateATI(backfunc)");
141 return;
142 }
143
144 ref = CLAMP( ref, 0, stencilMax );
145
146 /* set both front and back state */
147 if (ctx->Stencil.Function[0] == frontfunc &&
148 ctx->Stencil.Function[1] == backfunc &&
149 ctx->Stencil.ValueMask[0] == mask &&
150 ctx->Stencil.ValueMask[1] == mask &&
151 ctx->Stencil.Ref[0] == ref &&
152 ctx->Stencil.Ref[1] == ref)
153 return;
154 FLUSH_VERTICES(ctx, _NEW_STENCIL);
155 ctx->Stencil.Function[0] = frontfunc;
156 ctx->Stencil.Function[1] = backfunc;
157 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref;
158 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
159 if (ctx->Driver.StencilFuncSeparate) {
160 ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT,
161 frontfunc, ref, mask);
162 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK,
163 backfunc, ref, mask);
164 }
165 }
166
167
168 /**
169 * Set the function and reference value for stencil testing.
170 *
171 * \param func test function.
172 * \param ref reference value.
173 * \param mask bitmask.
174 *
175 * \sa glStencilFunc().
176 *
177 * Verifies the parameters and updates the respective values in
178 * __GLcontextRec::Stencil. On change flushes the vertices and notifies the
179 * driver via the dd_function_table::StencilFunc callback.
180 */
181 void GLAPIENTRY
182 _mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
183 {
184 GET_CURRENT_CONTEXT(ctx);
185 const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
186 const GLint face = ctx->Stencil.ActiveFace;
187 ASSERT_OUTSIDE_BEGIN_END(ctx);
188
189 if (!validate_stencil_func(ctx, func)) {
190 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)");
191 return;
192 }
193
194 ref = CLAMP( ref, 0, stencilMax );
195
196 if (face != 0) {
197 if (ctx->Stencil.Function[face] == func &&
198 ctx->Stencil.ValueMask[face] == mask &&
199 ctx->Stencil.Ref[face] == ref)
200 return;
201 FLUSH_VERTICES(ctx, _NEW_STENCIL);
202 ctx->Stencil.Function[face] = func;
203 ctx->Stencil.Ref[face] = ref;
204 ctx->Stencil.ValueMask[face] = mask;
205
206 /* Only propagate the change to the driver if EXT_stencil_two_side
207 * is enabled.
208 */
209 if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) {
210 ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask);
211 }
212 }
213 else {
214 /* set both front and back state */
215 if (ctx->Stencil.Function[0] == func &&
216 ctx->Stencil.Function[1] == func &&
217 ctx->Stencil.ValueMask[0] == mask &&
218 ctx->Stencil.ValueMask[1] == mask &&
219 ctx->Stencil.Ref[0] == ref &&
220 ctx->Stencil.Ref[1] == ref)
221 return;
222 FLUSH_VERTICES(ctx, _NEW_STENCIL);
223 ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func;
224 ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref;
225 ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask;
226 if (ctx->Driver.StencilFuncSeparate) {
227 ctx->Driver.StencilFuncSeparate(ctx,
228 ((ctx->Stencil.TestTwoSide)
229 ? GL_FRONT : GL_FRONT_AND_BACK),
230 func, ref, mask);
231 }
232 }
233 }
234
235
236 /**
237 * Set the stencil writing mask.
238 *
239 * \param mask bit-mask to enable/disable writing of individual bits in the
240 * stencil planes.
241 *
242 * \sa glStencilMask().
243 *
244 * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and
245 * notifies the driver via the dd_function_table::StencilMask callback.
246 */
247 void GLAPIENTRY
248 _mesa_StencilMask( GLuint mask )
249 {
250 GET_CURRENT_CONTEXT(ctx);
251 const GLint face = ctx->Stencil.ActiveFace;
252
253 ASSERT_OUTSIDE_BEGIN_END(ctx);
254
255 if (face != 0) {
256 /* Only modify the EXT_stencil_two_side back-face state.
257 */
258 if (ctx->Stencil.WriteMask[face] == mask)
259 return;
260 FLUSH_VERTICES(ctx, _NEW_STENCIL);
261 ctx->Stencil.WriteMask[face] = mask;
262
263 /* Only propagate the change to the driver if EXT_stencil_two_side
264 * is enabled.
265 */
266 if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) {
267 ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask);
268 }
269 }
270 else {
271 /* set both front and back state */
272 if (ctx->Stencil.WriteMask[0] == mask &&
273 ctx->Stencil.WriteMask[1] == mask)
274 return;
275 FLUSH_VERTICES(ctx, _NEW_STENCIL);
276 ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask;
277 if (ctx->Driver.StencilMaskSeparate) {
278 ctx->Driver.StencilMaskSeparate(ctx,
279 ((ctx->Stencil.TestTwoSide)
280 ? GL_FRONT : GL_FRONT_AND_BACK),
281 mask);
282 }
283 }
284 }
285
286
287 /**
288 * Set the stencil test actions.
289 *
290 * \param fail action to take when stencil test fails.
291 * \param zfail action to take when stencil test passes, but depth test fails.
292 * \param zpass action to take when stencil test passes and the depth test
293 * passes (or depth testing is not enabled).
294 *
295 * \sa glStencilOp().
296 *
297 * Verifies the parameters and updates the respective fields in
298 * __GLcontextRec::Stencil. On change flushes the vertices and notifies the
299 * driver via the dd_function_table::StencilOp callback.
300 */
301 void GLAPIENTRY
302 _mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
303 {
304 GET_CURRENT_CONTEXT(ctx);
305 const GLint face = ctx->Stencil.ActiveFace;
306
307 ASSERT_OUTSIDE_BEGIN_END(ctx);
308
309 if (!validate_stencil_op(ctx, fail)) {
310 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)");
311 return;
312 }
313 if (!validate_stencil_op(ctx, zfail)) {
314 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)");
315 return;
316 }
317 if (!validate_stencil_op(ctx, zpass)) {
318 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)");
319 return;
320 }
321
322 if (face != 0) {
323 /* only set active face state */
324 if (ctx->Stencil.ZFailFunc[face] == zfail &&
325 ctx->Stencil.ZPassFunc[face] == zpass &&
326 ctx->Stencil.FailFunc[face] == fail)
327 return;
328 FLUSH_VERTICES(ctx, _NEW_STENCIL);
329 ctx->Stencil.ZFailFunc[face] = zfail;
330 ctx->Stencil.ZPassFunc[face] = zpass;
331 ctx->Stencil.FailFunc[face] = fail;
332
333 /* Only propagate the change to the driver if EXT_stencil_two_side
334 * is enabled.
335 */
336 if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) {
337 ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass);
338 }
339 }
340 else {
341 /* set both front and back state */
342 if (ctx->Stencil.ZFailFunc[0] == zfail &&
343 ctx->Stencil.ZFailFunc[1] == zfail &&
344 ctx->Stencil.ZPassFunc[0] == zpass &&
345 ctx->Stencil.ZPassFunc[1] == zpass &&
346 ctx->Stencil.FailFunc[0] == fail &&
347 ctx->Stencil.FailFunc[1] == fail)
348 return;
349 FLUSH_VERTICES(ctx, _NEW_STENCIL);
350 ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail;
351 ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass;
352 ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail;
353 if (ctx->Driver.StencilOpSeparate) {
354 ctx->Driver.StencilOpSeparate(ctx,
355 ((ctx->Stencil.TestTwoSide)
356 ? GL_FRONT : GL_FRONT_AND_BACK),
357 fail, zfail, zpass);
358 }
359 }
360 }
361
362
363
364 #if _HAVE_FULL_GL
365 /* GL_EXT_stencil_two_side */
366 void GLAPIENTRY
367 _mesa_ActiveStencilFaceEXT(GLenum face)
368 {
369 GET_CURRENT_CONTEXT(ctx);
370 ASSERT_OUTSIDE_BEGIN_END(ctx);
371
372 if (!ctx->Extensions.EXT_stencil_two_side) {
373 _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT");
374 return;
375 }
376
377 if (face == GL_FRONT || face == GL_BACK) {
378 FLUSH_VERTICES(ctx, _NEW_STENCIL);
379 ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2;
380 }
381 else {
382 _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)");
383 }
384 }
385 #endif
386
387
388
389 /**
390 * OpenGL 2.0 function.
391 * \todo Make StencilOp() call this function. And eventually remove the
392 * ctx->Driver.StencilOp function and use ctx->Driver.StencilOpSeparate
393 * instead.
394 */
395 void GLAPIENTRY
396 _mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass)
397 {
398 GLboolean set = GL_FALSE;
399 GET_CURRENT_CONTEXT(ctx);
400 ASSERT_OUTSIDE_BEGIN_END(ctx);
401
402 if (!validate_stencil_op(ctx, sfail)) {
403 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)");
404 return;
405 }
406 if (!validate_stencil_op(ctx, zfail)) {
407 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)");
408 return;
409 }
410 if (!validate_stencil_op(ctx, zpass)) {
411 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)");
412 return;
413 }
414 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
415 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)");
416 return;
417 }
418
419 if (face != GL_BACK) {
420 /* set front */
421 if (ctx->Stencil.ZFailFunc[0] != zfail ||
422 ctx->Stencil.ZPassFunc[0] != zpass ||
423 ctx->Stencil.FailFunc[0] != sfail){
424 FLUSH_VERTICES(ctx, _NEW_STENCIL);
425 ctx->Stencil.ZFailFunc[0] = zfail;
426 ctx->Stencil.ZPassFunc[0] = zpass;
427 ctx->Stencil.FailFunc[0] = sfail;
428 set = GL_TRUE;
429 }
430 }
431 if (face != GL_FRONT) {
432 /* set back */
433 if (ctx->Stencil.ZFailFunc[1] != zfail ||
434 ctx->Stencil.ZPassFunc[1] != zpass ||
435 ctx->Stencil.FailFunc[1] != sfail) {
436 FLUSH_VERTICES(ctx, _NEW_STENCIL);
437 ctx->Stencil.ZFailFunc[1] = zfail;
438 ctx->Stencil.ZPassFunc[1] = zpass;
439 ctx->Stencil.FailFunc[1] = sfail;
440 set = GL_TRUE;
441 }
442 }
443 if (set && ctx->Driver.StencilOpSeparate) {
444 ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass);
445 }
446 }
447
448
449 /* OpenGL 2.0 */
450 void GLAPIENTRY
451 _mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
452 {
453 GET_CURRENT_CONTEXT(ctx);
454 const GLint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
455 ASSERT_OUTSIDE_BEGIN_END(ctx);
456
457 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
458 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)");
459 return;
460 }
461 if (!validate_stencil_func(ctx, func)) {
462 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)");
463 return;
464 }
465
466 ref = CLAMP(ref, 0, stencilMax);
467
468 FLUSH_VERTICES(ctx, _NEW_STENCIL);
469
470 if (face != GL_BACK) {
471 /* set front */
472 ctx->Stencil.Function[0] = func;
473 ctx->Stencil.Ref[0] = ref;
474 ctx->Stencil.ValueMask[0] = mask;
475 }
476 if (face != GL_FRONT) {
477 /* set back */
478 ctx->Stencil.Function[1] = func;
479 ctx->Stencil.Ref[1] = ref;
480 ctx->Stencil.ValueMask[1] = mask;
481 }
482 if (ctx->Driver.StencilFuncSeparate) {
483 ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask);
484 }
485 }
486
487
488 /* OpenGL 2.0 */
489 void GLAPIENTRY
490 _mesa_StencilMaskSeparate(GLenum face, GLuint mask)
491 {
492 GET_CURRENT_CONTEXT(ctx);
493 ASSERT_OUTSIDE_BEGIN_END(ctx);
494
495 if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
496 _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)");
497 return;
498 }
499
500 FLUSH_VERTICES(ctx, _NEW_STENCIL);
501
502 if (face != GL_BACK) {
503 ctx->Stencil.WriteMask[0] = mask;
504 }
505 if (face != GL_FRONT) {
506 ctx->Stencil.WriteMask[1] = mask;
507 }
508 if (ctx->Driver.StencilMaskSeparate) {
509 ctx->Driver.StencilMaskSeparate(ctx, face, mask);
510 }
511 }
512
513
514 /**
515 * Update derived stencil state.
516 */
517 void
518 _mesa_update_stencil(GLcontext *ctx)
519 {
520 const GLint face = ctx->Stencil._BackFace;
521
522 ctx->Stencil._TestTwoSide =
523 (ctx->Stencil.Function[0] != ctx->Stencil.Function[face] ||
524 ctx->Stencil.FailFunc[0] != ctx->Stencil.FailFunc[face] ||
525 ctx->Stencil.ZPassFunc[0] != ctx->Stencil.ZPassFunc[face] ||
526 ctx->Stencil.ZFailFunc[0] != ctx->Stencil.ZFailFunc[face] ||
527 ctx->Stencil.Ref[0] != ctx->Stencil.Ref[face] ||
528 ctx->Stencil.ValueMask[0] != ctx->Stencil.ValueMask[face] ||
529 ctx->Stencil.WriteMask[0] != ctx->Stencil.WriteMask[face]);
530 }
531
532
533 /**
534 * Initialize the context stipple state.
535 *
536 * \param ctx GL context.
537 *
538 * Initializes __GLcontextRec::Stencil attribute group.
539 */
540 void
541 _mesa_init_stencil(GLcontext *ctx)
542 {
543 ctx->Stencil.Enabled = GL_FALSE;
544 ctx->Stencil.TestTwoSide = GL_FALSE;
545 ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 1 = GL_BACK */
546 ctx->Stencil.Function[0] = GL_ALWAYS;
547 ctx->Stencil.Function[1] = GL_ALWAYS;
548 ctx->Stencil.Function[2] = GL_ALWAYS;
549 ctx->Stencil.FailFunc[0] = GL_KEEP;
550 ctx->Stencil.FailFunc[1] = GL_KEEP;
551 ctx->Stencil.FailFunc[2] = GL_KEEP;
552 ctx->Stencil.ZPassFunc[0] = GL_KEEP;
553 ctx->Stencil.ZPassFunc[1] = GL_KEEP;
554 ctx->Stencil.ZPassFunc[2] = GL_KEEP;
555 ctx->Stencil.ZFailFunc[0] = GL_KEEP;
556 ctx->Stencil.ZFailFunc[1] = GL_KEEP;
557 ctx->Stencil.ZFailFunc[2] = GL_KEEP;
558 ctx->Stencil.Ref[0] = 0;
559 ctx->Stencil.Ref[1] = 0;
560 ctx->Stencil.Ref[2] = 0;
561 ctx->Stencil.ValueMask[0] = ~0U;
562 ctx->Stencil.ValueMask[1] = ~0U;
563 ctx->Stencil.ValueMask[2] = ~0U;
564 ctx->Stencil.WriteMask[0] = ~0U;
565 ctx->Stencil.WriteMask[1] = ~0U;
566 ctx->Stencil.WriteMask[2] = ~0U;
567 ctx->Stencil.Clear = 0;
568 }