stencil.c revision 01e04c3f
17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 47117f1b4Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 57117f1b4Smrg * 67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 87117f1b4Smrg * to deal in the Software without restriction, including without limitation 97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 117117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 127117f1b4Smrg * 137117f1b4Smrg * The above copyright notice and this permission notice shall be included 147117f1b4Smrg * in all copies or substantial portions of the Software. 157117f1b4Smrg * 167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 237117f1b4Smrg */ 247117f1b4Smrg 257117f1b4Smrg 267117f1b4Smrg/** 277117f1b4Smrg * \file stencil.c 287117f1b4Smrg * Stencil operations. 297117f1b4Smrg * 30c1f859d4Smrg * Note: There's some conflict between GL_EXT_stencil_two_side and 317117f1b4Smrg * OpenGL 2.0's two-sided stencil feature. 327117f1b4Smrg * 337117f1b4Smrg * With GL_EXT_stencil_two_side, calling glStencilOp/Func/Mask() only the 347117f1b4Smrg * front OR back face state (as set by glActiveStencilFaceEXT) is set. 357117f1b4Smrg * 367117f1b4Smrg * But with OpenGL 2.0, calling glStencilOp/Func/Mask() sets BOTH the 377117f1b4Smrg * front AND back state. 387117f1b4Smrg * 397117f1b4Smrg * Also, note that GL_ATI_separate_stencil is different as well: 407117f1b4Smrg * glStencilFuncSeparateATI(GLenum frontfunc, GLenum backfunc, ...) vs. 417117f1b4Smrg * glStencilFuncSeparate(GLenum face, GLenum func, ...). 42c1f859d4Smrg * 43c1f859d4Smrg * This problem is solved by keeping three sets of stencil state: 44c1f859d4Smrg * state[0] = GL_FRONT state. 45c1f859d4Smrg * state[1] = OpenGL 2.0 / GL_ATI_separate_stencil GL_BACK state. 46c1f859d4Smrg * state[2] = GL_EXT_stencil_two_side GL_BACK state. 477117f1b4Smrg */ 487117f1b4Smrg 497117f1b4Smrg 507117f1b4Smrg#include "glheader.h" 517117f1b4Smrg#include "imports.h" 527117f1b4Smrg#include "context.h" 537117f1b4Smrg#include "macros.h" 547117f1b4Smrg#include "stencil.h" 557117f1b4Smrg#include "mtypes.h" 567117f1b4Smrg 577117f1b4Smrg 587117f1b4Smrgstatic GLboolean 593464ebd5Sriastradhvalidate_stencil_op(struct gl_context *ctx, GLenum op) 607117f1b4Smrg{ 617117f1b4Smrg switch (op) { 627117f1b4Smrg case GL_KEEP: 637117f1b4Smrg case GL_ZERO: 647117f1b4Smrg case GL_REPLACE: 657117f1b4Smrg case GL_INCR: 667117f1b4Smrg case GL_DECR: 677117f1b4Smrg case GL_INVERT: 68af69d88dSmrg case GL_INCR_WRAP: 69af69d88dSmrg case GL_DECR_WRAP: 707117f1b4Smrg return GL_TRUE; 717117f1b4Smrg default: 727117f1b4Smrg return GL_FALSE; 737117f1b4Smrg } 747117f1b4Smrg} 757117f1b4Smrg 767117f1b4Smrg 777117f1b4Smrgstatic GLboolean 783464ebd5Sriastradhvalidate_stencil_func(struct gl_context *ctx, GLenum func) 797117f1b4Smrg{ 807117f1b4Smrg switch (func) { 817117f1b4Smrg case GL_NEVER: 827117f1b4Smrg case GL_LESS: 837117f1b4Smrg case GL_LEQUAL: 847117f1b4Smrg case GL_GREATER: 857117f1b4Smrg case GL_GEQUAL: 867117f1b4Smrg case GL_EQUAL: 877117f1b4Smrg case GL_NOTEQUAL: 887117f1b4Smrg case GL_ALWAYS: 897117f1b4Smrg return GL_TRUE; 907117f1b4Smrg default: 917117f1b4Smrg return GL_FALSE; 927117f1b4Smrg } 937117f1b4Smrg} 947117f1b4Smrg 957117f1b4Smrg 967117f1b4Smrg/** 977117f1b4Smrg * Set the clear value for the stencil buffer. 987117f1b4Smrg * 997117f1b4Smrg * \param s clear value. 1007117f1b4Smrg * 1017117f1b4Smrg * \sa glClearStencil(). 1027117f1b4Smrg * 1037117f1b4Smrg * Updates gl_stencil_attrib::Clear. On change 1047117f1b4Smrg * flushes the vertices and notifies the driver via 1057117f1b4Smrg * the dd_function_table::ClearStencil callback. 1067117f1b4Smrg */ 1077117f1b4Smrgvoid GLAPIENTRY 1087117f1b4Smrg_mesa_ClearStencil( GLint s ) 1097117f1b4Smrg{ 1107117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 1117117f1b4Smrg 11201e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 11301e04c3fSmrg _mesa_debug(ctx, "glClearStencil(%d)\n", s); 11401e04c3fSmrg 1157117f1b4Smrg ctx->Stencil.Clear = (GLuint) s; 1167117f1b4Smrg} 1177117f1b4Smrg 1187117f1b4Smrg 1197117f1b4Smrg/** 1207117f1b4Smrg * Set the function and reference value for stencil testing. 1217117f1b4Smrg * 1227117f1b4Smrg * \param frontfunc front test function. 1237117f1b4Smrg * \param backfunc back test function. 1247117f1b4Smrg * \param ref front and back reference value. 1257117f1b4Smrg * \param mask front and back bitmask. 1267117f1b4Smrg * 1277117f1b4Smrg * \sa glStencilFunc(). 1287117f1b4Smrg * 1297117f1b4Smrg * Verifies the parameters and updates the respective values in 13001e04c3fSmrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies 13101e04c3fSmrg * the driver via the dd_function_table::StencilFunc callback. 1327117f1b4Smrg */ 1337117f1b4Smrgvoid GLAPIENTRY 1347117f1b4Smrg_mesa_StencilFuncSeparateATI( GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask ) 1357117f1b4Smrg{ 1367117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 1377117f1b4Smrg 1383464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 1393464ebd5Sriastradh _mesa_debug(ctx, "glStencilFuncSeparateATI()\n"); 1403464ebd5Sriastradh 1417117f1b4Smrg if (!validate_stencil_func(ctx, frontfunc)) { 1427117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 1437117f1b4Smrg "glStencilFuncSeparateATI(frontfunc)"); 1447117f1b4Smrg return; 1457117f1b4Smrg } 1467117f1b4Smrg if (!validate_stencil_func(ctx, backfunc)) { 1477117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 1487117f1b4Smrg "glStencilFuncSeparateATI(backfunc)"); 1497117f1b4Smrg return; 1507117f1b4Smrg } 1517117f1b4Smrg 1527117f1b4Smrg /* set both front and back state */ 1537117f1b4Smrg if (ctx->Stencil.Function[0] == frontfunc && 1547117f1b4Smrg ctx->Stencil.Function[1] == backfunc && 1557117f1b4Smrg ctx->Stencil.ValueMask[0] == mask && 1567117f1b4Smrg ctx->Stencil.ValueMask[1] == mask && 1577117f1b4Smrg ctx->Stencil.Ref[0] == ref && 1587117f1b4Smrg ctx->Stencil.Ref[1] == ref) 1597117f1b4Smrg return; 16001e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 16101e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 1627117f1b4Smrg ctx->Stencil.Function[0] = frontfunc; 1637117f1b4Smrg ctx->Stencil.Function[1] = backfunc; 1647117f1b4Smrg ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 1657117f1b4Smrg ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 1667117f1b4Smrg if (ctx->Driver.StencilFuncSeparate) { 1677117f1b4Smrg ctx->Driver.StencilFuncSeparate(ctx, GL_FRONT, 1687117f1b4Smrg frontfunc, ref, mask); 1697117f1b4Smrg ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, 1707117f1b4Smrg backfunc, ref, mask); 1717117f1b4Smrg } 1727117f1b4Smrg} 1737117f1b4Smrg 1747117f1b4Smrg 1757117f1b4Smrg/** 1767117f1b4Smrg * Set the function and reference value for stencil testing. 1777117f1b4Smrg * 1787117f1b4Smrg * \param func test function. 1797117f1b4Smrg * \param ref reference value. 1807117f1b4Smrg * \param mask bitmask. 1817117f1b4Smrg * 1827117f1b4Smrg * \sa glStencilFunc(). 1837117f1b4Smrg * 1847117f1b4Smrg * Verifies the parameters and updates the respective values in 18501e04c3fSmrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies 18601e04c3fSmrg * the driver via the dd_function_table::StencilFunc callback. 1877117f1b4Smrg */ 18801e04c3fSmrgstatic void 18901e04c3fSmrgstencil_func(struct gl_context *ctx, GLenum func, GLint ref, GLuint mask) 1907117f1b4Smrg{ 191c1f859d4Smrg const GLint face = ctx->Stencil.ActiveFace; 1927117f1b4Smrg 193c1f859d4Smrg if (face != 0) { 194c1f859d4Smrg if (ctx->Stencil.Function[face] == func && 195c1f859d4Smrg ctx->Stencil.ValueMask[face] == mask && 196c1f859d4Smrg ctx->Stencil.Ref[face] == ref) 197c1f859d4Smrg return; 19801e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 19901e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 200c1f859d4Smrg ctx->Stencil.Function[face] = func; 201c1f859d4Smrg ctx->Stencil.Ref[face] = ref; 202c1f859d4Smrg ctx->Stencil.ValueMask[face] = mask; 203c1f859d4Smrg 204c1f859d4Smrg /* Only propagate the change to the driver if EXT_stencil_two_side 205c1f859d4Smrg * is enabled. 206c1f859d4Smrg */ 207c1f859d4Smrg if (ctx->Driver.StencilFuncSeparate && ctx->Stencil.TestTwoSide) { 208c1f859d4Smrg ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, func, ref, mask); 209c1f859d4Smrg } 210c1f859d4Smrg } 211c1f859d4Smrg else { 2127117f1b4Smrg /* set both front and back state */ 2137117f1b4Smrg if (ctx->Stencil.Function[0] == func && 2147117f1b4Smrg ctx->Stencil.Function[1] == func && 2157117f1b4Smrg ctx->Stencil.ValueMask[0] == mask && 2167117f1b4Smrg ctx->Stencil.ValueMask[1] == mask && 2177117f1b4Smrg ctx->Stencil.Ref[0] == ref && 2187117f1b4Smrg ctx->Stencil.Ref[1] == ref) 2197117f1b4Smrg return; 22001e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 22101e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 2227117f1b4Smrg ctx->Stencil.Function[0] = ctx->Stencil.Function[1] = func; 2237117f1b4Smrg ctx->Stencil.Ref[0] = ctx->Stencil.Ref[1] = ref; 2247117f1b4Smrg ctx->Stencil.ValueMask[0] = ctx->Stencil.ValueMask[1] = mask; 2257117f1b4Smrg if (ctx->Driver.StencilFuncSeparate) { 226c1f859d4Smrg ctx->Driver.StencilFuncSeparate(ctx, 227c1f859d4Smrg ((ctx->Stencil.TestTwoSide) 228c1f859d4Smrg ? GL_FRONT : GL_FRONT_AND_BACK), 2297117f1b4Smrg func, ref, mask); 2307117f1b4Smrg } 2317117f1b4Smrg } 2327117f1b4Smrg} 2337117f1b4Smrg 2347117f1b4Smrg 23501e04c3fSmrgvoid GLAPIENTRY 23601e04c3fSmrg_mesa_StencilFunc_no_error(GLenum func, GLint ref, GLuint mask) 23701e04c3fSmrg{ 23801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 23901e04c3fSmrg stencil_func(ctx, func, ref, mask); 24001e04c3fSmrg} 24101e04c3fSmrg 24201e04c3fSmrg 24301e04c3fSmrgvoid GLAPIENTRY 24401e04c3fSmrg_mesa_StencilFunc(GLenum func, GLint ref, GLuint mask) 24501e04c3fSmrg{ 24601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 24701e04c3fSmrg 24801e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 24901e04c3fSmrg _mesa_debug(ctx, "glStencilFunc()\n"); 25001e04c3fSmrg 25101e04c3fSmrg if (!validate_stencil_func(ctx, func)) { 25201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFunc(func)"); 25301e04c3fSmrg return; 25401e04c3fSmrg } 25501e04c3fSmrg 25601e04c3fSmrg stencil_func(ctx, func, ref, mask); 25701e04c3fSmrg} 25801e04c3fSmrg 25901e04c3fSmrg 2607117f1b4Smrg/** 2617117f1b4Smrg * Set the stencil writing mask. 2627117f1b4Smrg * 2637117f1b4Smrg * \param mask bit-mask to enable/disable writing of individual bits in the 2647117f1b4Smrg * stencil planes. 2657117f1b4Smrg * 2667117f1b4Smrg * \sa glStencilMask(). 2677117f1b4Smrg * 2687117f1b4Smrg * Updates gl_stencil_attrib::WriteMask. On change flushes the vertices and 2697117f1b4Smrg * notifies the driver via the dd_function_table::StencilMask callback. 2707117f1b4Smrg */ 2717117f1b4Smrgvoid GLAPIENTRY 2727117f1b4Smrg_mesa_StencilMask( GLuint mask ) 2737117f1b4Smrg{ 2747117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 275c1f859d4Smrg const GLint face = ctx->Stencil.ActiveFace; 276c1f859d4Smrg 2773464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 2783464ebd5Sriastradh _mesa_debug(ctx, "glStencilMask()\n"); 2793464ebd5Sriastradh 280c1f859d4Smrg if (face != 0) { 281c1f859d4Smrg /* Only modify the EXT_stencil_two_side back-face state. 282c1f859d4Smrg */ 283c1f859d4Smrg if (ctx->Stencil.WriteMask[face] == mask) 2847117f1b4Smrg return; 28501e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 28601e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 287c1f859d4Smrg ctx->Stencil.WriteMask[face] = mask; 288c1f859d4Smrg 289c1f859d4Smrg /* Only propagate the change to the driver if EXT_stencil_two_side 290c1f859d4Smrg * is enabled. 291c1f859d4Smrg */ 292c1f859d4Smrg if (ctx->Driver.StencilMaskSeparate && ctx->Stencil.TestTwoSide) { 293c1f859d4Smrg ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, mask); 2947117f1b4Smrg } 2957117f1b4Smrg } 2967117f1b4Smrg else { 297c1f859d4Smrg /* set both front and back state */ 298c1f859d4Smrg if (ctx->Stencil.WriteMask[0] == mask && 299c1f859d4Smrg ctx->Stencil.WriteMask[1] == mask) 3007117f1b4Smrg return; 30101e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 30201e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 303c1f859d4Smrg ctx->Stencil.WriteMask[0] = ctx->Stencil.WriteMask[1] = mask; 3047117f1b4Smrg if (ctx->Driver.StencilMaskSeparate) { 305c1f859d4Smrg ctx->Driver.StencilMaskSeparate(ctx, 306c1f859d4Smrg ((ctx->Stencil.TestTwoSide) 307c1f859d4Smrg ? GL_FRONT : GL_FRONT_AND_BACK), 308c1f859d4Smrg mask); 3097117f1b4Smrg } 3107117f1b4Smrg } 3117117f1b4Smrg} 3127117f1b4Smrg 3137117f1b4Smrg 3147117f1b4Smrg/** 3157117f1b4Smrg * Set the stencil test actions. 3167117f1b4Smrg * 3177117f1b4Smrg * \param fail action to take when stencil test fails. 3187117f1b4Smrg * \param zfail action to take when stencil test passes, but depth test fails. 3197117f1b4Smrg * \param zpass action to take when stencil test passes and the depth test 3207117f1b4Smrg * passes (or depth testing is not enabled). 3217117f1b4Smrg * 3227117f1b4Smrg * \sa glStencilOp(). 3237117f1b4Smrg * 3247117f1b4Smrg * Verifies the parameters and updates the respective fields in 32501e04c3fSmrg * __struct gl_contextRec::Stencil. On change flushes the vertices and notifies 32601e04c3fSmrg * the driver via the dd_function_table::StencilOp callback. 3277117f1b4Smrg */ 32801e04c3fSmrgstatic void 32901e04c3fSmrgstencil_op(struct gl_context *ctx, GLenum fail, GLenum zfail, GLenum zpass) 3307117f1b4Smrg{ 331c1f859d4Smrg const GLint face = ctx->Stencil.ActiveFace; 332c1f859d4Smrg 333c1f859d4Smrg if (face != 0) { 334c1f859d4Smrg /* only set active face state */ 335c1f859d4Smrg if (ctx->Stencil.ZFailFunc[face] == zfail && 336c1f859d4Smrg ctx->Stencil.ZPassFunc[face] == zpass && 337c1f859d4Smrg ctx->Stencil.FailFunc[face] == fail) 338c1f859d4Smrg return; 33901e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 34001e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 341c1f859d4Smrg ctx->Stencil.ZFailFunc[face] = zfail; 342c1f859d4Smrg ctx->Stencil.ZPassFunc[face] = zpass; 343c1f859d4Smrg ctx->Stencil.FailFunc[face] = fail; 344c1f859d4Smrg 345c1f859d4Smrg /* Only propagate the change to the driver if EXT_stencil_two_side 346c1f859d4Smrg * is enabled. 347c1f859d4Smrg */ 348c1f859d4Smrg if (ctx->Driver.StencilOpSeparate && ctx->Stencil.TestTwoSide) { 349c1f859d4Smrg ctx->Driver.StencilOpSeparate(ctx, GL_BACK, fail, zfail, zpass); 350c1f859d4Smrg } 351c1f859d4Smrg } 352c1f859d4Smrg else { 3537117f1b4Smrg /* set both front and back state */ 3547117f1b4Smrg if (ctx->Stencil.ZFailFunc[0] == zfail && 3557117f1b4Smrg ctx->Stencil.ZFailFunc[1] == zfail && 3567117f1b4Smrg ctx->Stencil.ZPassFunc[0] == zpass && 3577117f1b4Smrg ctx->Stencil.ZPassFunc[1] == zpass && 3587117f1b4Smrg ctx->Stencil.FailFunc[0] == fail && 3597117f1b4Smrg ctx->Stencil.FailFunc[1] == fail) 3607117f1b4Smrg return; 36101e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 36201e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 3637117f1b4Smrg ctx->Stencil.ZFailFunc[0] = ctx->Stencil.ZFailFunc[1] = zfail; 3647117f1b4Smrg ctx->Stencil.ZPassFunc[0] = ctx->Stencil.ZPassFunc[1] = zpass; 3657117f1b4Smrg ctx->Stencil.FailFunc[0] = ctx->Stencil.FailFunc[1] = fail; 3667117f1b4Smrg if (ctx->Driver.StencilOpSeparate) { 367c1f859d4Smrg ctx->Driver.StencilOpSeparate(ctx, 368c1f859d4Smrg ((ctx->Stencil.TestTwoSide) 369c1f859d4Smrg ? GL_FRONT : GL_FRONT_AND_BACK), 3707117f1b4Smrg fail, zfail, zpass); 3717117f1b4Smrg } 3727117f1b4Smrg } 3737117f1b4Smrg} 3747117f1b4Smrg 3757117f1b4Smrg 37601e04c3fSmrgvoid GLAPIENTRY 37701e04c3fSmrg_mesa_StencilOp_no_error(GLenum fail, GLenum zfail, GLenum zpass) 37801e04c3fSmrg{ 37901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 38001e04c3fSmrg stencil_op(ctx, fail, zfail, zpass); 38101e04c3fSmrg} 38201e04c3fSmrg 38301e04c3fSmrg 38401e04c3fSmrgvoid GLAPIENTRY 38501e04c3fSmrg_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass) 38601e04c3fSmrg{ 38701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 38801e04c3fSmrg 38901e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 39001e04c3fSmrg _mesa_debug(ctx, "glStencilOp()\n"); 39101e04c3fSmrg 39201e04c3fSmrg if (!validate_stencil_op(ctx, fail)) { 39301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(sfail)"); 39401e04c3fSmrg return; 39501e04c3fSmrg } 39601e04c3fSmrg 39701e04c3fSmrg if (!validate_stencil_op(ctx, zfail)) { 39801e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zfail)"); 39901e04c3fSmrg return; 40001e04c3fSmrg } 40101e04c3fSmrg 40201e04c3fSmrg if (!validate_stencil_op(ctx, zpass)) { 40301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOp(zpass)"); 40401e04c3fSmrg return; 40501e04c3fSmrg } 40601e04c3fSmrg 40701e04c3fSmrg stencil_op(ctx, fail, zfail, zpass); 40801e04c3fSmrg} 40901e04c3fSmrg 4107117f1b4Smrg 4117117f1b4Smrg/* GL_EXT_stencil_two_side */ 4127117f1b4Smrgvoid GLAPIENTRY 4137117f1b4Smrg_mesa_ActiveStencilFaceEXT(GLenum face) 4147117f1b4Smrg{ 4157117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4167117f1b4Smrg 4173464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 4183464ebd5Sriastradh _mesa_debug(ctx, "glActiveStencilFaceEXT()\n"); 4193464ebd5Sriastradh 4207117f1b4Smrg if (!ctx->Extensions.EXT_stencil_two_side) { 4217117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glActiveStencilFaceEXT"); 4227117f1b4Smrg return; 4237117f1b4Smrg } 4247117f1b4Smrg 4257117f1b4Smrg if (face == GL_FRONT || face == GL_BACK) { 426c1f859d4Smrg ctx->Stencil.ActiveFace = (face == GL_FRONT) ? 0 : 2; 4277117f1b4Smrg } 4287117f1b4Smrg else { 4297117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glActiveStencilFaceEXT(face)"); 4307117f1b4Smrg } 4317117f1b4Smrg} 4327117f1b4Smrg 4337117f1b4Smrg 43401e04c3fSmrgstatic void 43501e04c3fSmrgstencil_op_separate(struct gl_context *ctx, GLenum face, GLenum sfail, 43601e04c3fSmrg GLenum zfail, GLenum zpass) 4377117f1b4Smrg{ 4387117f1b4Smrg GLboolean set = GL_FALSE; 4397117f1b4Smrg 4407117f1b4Smrg if (face != GL_BACK) { 4417117f1b4Smrg /* set front */ 4427117f1b4Smrg if (ctx->Stencil.ZFailFunc[0] != zfail || 4437117f1b4Smrg ctx->Stencil.ZPassFunc[0] != zpass || 4447117f1b4Smrg ctx->Stencil.FailFunc[0] != sfail){ 44501e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 44601e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 4477117f1b4Smrg ctx->Stencil.ZFailFunc[0] = zfail; 4487117f1b4Smrg ctx->Stencil.ZPassFunc[0] = zpass; 4497117f1b4Smrg ctx->Stencil.FailFunc[0] = sfail; 4507117f1b4Smrg set = GL_TRUE; 4517117f1b4Smrg } 4527117f1b4Smrg } 45301e04c3fSmrg 4547117f1b4Smrg if (face != GL_FRONT) { 4557117f1b4Smrg /* set back */ 4567117f1b4Smrg if (ctx->Stencil.ZFailFunc[1] != zfail || 4577117f1b4Smrg ctx->Stencil.ZPassFunc[1] != zpass || 4587117f1b4Smrg ctx->Stencil.FailFunc[1] != sfail) { 45901e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 46001e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 4617117f1b4Smrg ctx->Stencil.ZFailFunc[1] = zfail; 4627117f1b4Smrg ctx->Stencil.ZPassFunc[1] = zpass; 4637117f1b4Smrg ctx->Stencil.FailFunc[1] = sfail; 4647117f1b4Smrg set = GL_TRUE; 4657117f1b4Smrg } 4667117f1b4Smrg } 46701e04c3fSmrg 4687117f1b4Smrg if (set && ctx->Driver.StencilOpSeparate) { 4697117f1b4Smrg ctx->Driver.StencilOpSeparate(ctx, face, sfail, zfail, zpass); 4707117f1b4Smrg } 4717117f1b4Smrg} 4727117f1b4Smrg 4737117f1b4Smrg 4747117f1b4Smrgvoid GLAPIENTRY 47501e04c3fSmrg_mesa_StencilOpSeparate_no_error(GLenum face, GLenum sfail, GLenum zfail, 47601e04c3fSmrg GLenum zpass) 47701e04c3fSmrg{ 47801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 47901e04c3fSmrg stencil_op_separate(ctx, face, sfail, zfail, zpass); 48001e04c3fSmrg} 48101e04c3fSmrg 48201e04c3fSmrg 48301e04c3fSmrgvoid GLAPIENTRY 48401e04c3fSmrg_mesa_StencilOpSeparate(GLenum face, GLenum sfail, GLenum zfail, GLenum zpass) 4857117f1b4Smrg{ 4867117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4877117f1b4Smrg 4883464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 48901e04c3fSmrg _mesa_debug(ctx, "glStencilOpSeparate()\n"); 4903464ebd5Sriastradh 49101e04c3fSmrg if (!validate_stencil_op(ctx, sfail)) { 49201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(sfail)"); 4937117f1b4Smrg return; 4947117f1b4Smrg } 49501e04c3fSmrg 49601e04c3fSmrg if (!validate_stencil_op(ctx, zfail)) { 49701e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zfail)"); 49801e04c3fSmrg return; 49901e04c3fSmrg } 50001e04c3fSmrg 50101e04c3fSmrg if (!validate_stencil_op(ctx, zpass)) { 50201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(zpass)"); 50301e04c3fSmrg return; 50401e04c3fSmrg } 50501e04c3fSmrg 50601e04c3fSmrg if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 50701e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilOpSeparate(face)"); 5087117f1b4Smrg return; 5097117f1b4Smrg } 5107117f1b4Smrg 51101e04c3fSmrg stencil_op_separate(ctx, face, sfail, zfail, zpass); 51201e04c3fSmrg} 51301e04c3fSmrg 51401e04c3fSmrg 51501e04c3fSmrgstatic void 51601e04c3fSmrgstencil_func_separate(struct gl_context *ctx, GLenum face, GLenum func, 51701e04c3fSmrg GLint ref, GLuint mask) 51801e04c3fSmrg{ 51901e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 52001e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 5217117f1b4Smrg 522c1f859d4Smrg if (face != GL_BACK) { 523c1f859d4Smrg /* set front */ 5247117f1b4Smrg ctx->Stencil.Function[0] = func; 5257117f1b4Smrg ctx->Stencil.Ref[0] = ref; 5267117f1b4Smrg ctx->Stencil.ValueMask[0] = mask; 5277117f1b4Smrg } 52801e04c3fSmrg 529c1f859d4Smrg if (face != GL_FRONT) { 530c1f859d4Smrg /* set back */ 5317117f1b4Smrg ctx->Stencil.Function[1] = func; 5327117f1b4Smrg ctx->Stencil.Ref[1] = ref; 5337117f1b4Smrg ctx->Stencil.ValueMask[1] = mask; 5347117f1b4Smrg } 53501e04c3fSmrg 5367117f1b4Smrg if (ctx->Driver.StencilFuncSeparate) { 5377117f1b4Smrg ctx->Driver.StencilFuncSeparate(ctx, face, func, ref, mask); 5387117f1b4Smrg } 5397117f1b4Smrg} 5407117f1b4Smrg 5417117f1b4Smrg 5427117f1b4Smrg/* OpenGL 2.0 */ 5437117f1b4Smrgvoid GLAPIENTRY 54401e04c3fSmrg_mesa_StencilFuncSeparate_no_error(GLenum face, GLenum func, GLint ref, 54501e04c3fSmrg GLuint mask) 54601e04c3fSmrg{ 54701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 54801e04c3fSmrg stencil_func_separate(ctx, face, func, ref, mask); 54901e04c3fSmrg} 55001e04c3fSmrg 55101e04c3fSmrg 55201e04c3fSmrgvoid GLAPIENTRY 55301e04c3fSmrg_mesa_StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) 5547117f1b4Smrg{ 5557117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5567117f1b4Smrg 5573464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 55801e04c3fSmrg _mesa_debug(ctx, "glStencilFuncSeparate()\n"); 5593464ebd5Sriastradh 5607117f1b4Smrg if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 56101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(face)"); 56201e04c3fSmrg return; 56301e04c3fSmrg } 56401e04c3fSmrg 56501e04c3fSmrg if (!validate_stencil_func(ctx, func)) { 56601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilFuncSeparate(func)"); 5677117f1b4Smrg return; 5687117f1b4Smrg } 5697117f1b4Smrg 57001e04c3fSmrg stencil_func_separate(ctx, face, func, ref, mask); 57101e04c3fSmrg} 57201e04c3fSmrg 57301e04c3fSmrg 57401e04c3fSmrgstatic void 57501e04c3fSmrgstencil_mask_separate(struct gl_context *ctx, GLenum face, GLuint mask) 57601e04c3fSmrg{ 57701e04c3fSmrg FLUSH_VERTICES(ctx, ctx->DriverFlags.NewStencil ? 0 : _NEW_STENCIL); 57801e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewStencil; 5797117f1b4Smrg 5807117f1b4Smrg if (face != GL_BACK) { 5817117f1b4Smrg ctx->Stencil.WriteMask[0] = mask; 5827117f1b4Smrg } 58301e04c3fSmrg 5847117f1b4Smrg if (face != GL_FRONT) { 5857117f1b4Smrg ctx->Stencil.WriteMask[1] = mask; 5867117f1b4Smrg } 58701e04c3fSmrg 5887117f1b4Smrg if (ctx->Driver.StencilMaskSeparate) { 5897117f1b4Smrg ctx->Driver.StencilMaskSeparate(ctx, face, mask); 5907117f1b4Smrg } 5917117f1b4Smrg} 5927117f1b4Smrg 5937117f1b4Smrg 59401e04c3fSmrg/* OpenGL 2.0 */ 59501e04c3fSmrgvoid GLAPIENTRY 59601e04c3fSmrg_mesa_StencilMaskSeparate_no_error(GLenum face, GLuint mask) 59701e04c3fSmrg{ 59801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 59901e04c3fSmrg stencil_mask_separate(ctx, face, mask); 60001e04c3fSmrg} 60101e04c3fSmrg 60201e04c3fSmrg 60301e04c3fSmrgvoid GLAPIENTRY 60401e04c3fSmrg_mesa_StencilMaskSeparate(GLenum face, GLuint mask) 6057117f1b4Smrg{ 60601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 60701e04c3fSmrg 60801e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 60901e04c3fSmrg _mesa_debug(ctx, "glStencilMaskSeparate()\n"); 61001e04c3fSmrg 61101e04c3fSmrg if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) { 61201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glStencilaMaskSeparate(face)"); 61301e04c3fSmrg return; 61401e04c3fSmrg } 61501e04c3fSmrg 61601e04c3fSmrg stencil_mask_separate(ctx, face, mask); 6177117f1b4Smrg} 6187117f1b4Smrg 6197117f1b4Smrg 6207117f1b4Smrg/** 6217117f1b4Smrg * Initialize the context stipple state. 6227117f1b4Smrg * 6237117f1b4Smrg * \param ctx GL context. 6247117f1b4Smrg * 6253464ebd5Sriastradh * Initializes __struct gl_contextRec::Stencil attribute group. 6267117f1b4Smrg */ 6277117f1b4Smrgvoid 6283464ebd5Sriastradh_mesa_init_stencil(struct gl_context *ctx) 6297117f1b4Smrg{ 6307117f1b4Smrg ctx->Stencil.Enabled = GL_FALSE; 6317117f1b4Smrg ctx->Stencil.TestTwoSide = GL_FALSE; 632c1f859d4Smrg ctx->Stencil.ActiveFace = 0; /* 0 = GL_FRONT, 2 = GL_BACK */ 6337117f1b4Smrg ctx->Stencil.Function[0] = GL_ALWAYS; 6347117f1b4Smrg ctx->Stencil.Function[1] = GL_ALWAYS; 635c1f859d4Smrg ctx->Stencil.Function[2] = GL_ALWAYS; 6367117f1b4Smrg ctx->Stencil.FailFunc[0] = GL_KEEP; 6377117f1b4Smrg ctx->Stencil.FailFunc[1] = GL_KEEP; 638c1f859d4Smrg ctx->Stencil.FailFunc[2] = GL_KEEP; 6397117f1b4Smrg ctx->Stencil.ZPassFunc[0] = GL_KEEP; 6407117f1b4Smrg ctx->Stencil.ZPassFunc[1] = GL_KEEP; 641c1f859d4Smrg ctx->Stencil.ZPassFunc[2] = GL_KEEP; 6427117f1b4Smrg ctx->Stencil.ZFailFunc[0] = GL_KEEP; 6437117f1b4Smrg ctx->Stencil.ZFailFunc[1] = GL_KEEP; 644c1f859d4Smrg ctx->Stencil.ZFailFunc[2] = GL_KEEP; 6457117f1b4Smrg ctx->Stencil.Ref[0] = 0; 6467117f1b4Smrg ctx->Stencil.Ref[1] = 0; 647c1f859d4Smrg ctx->Stencil.Ref[2] = 0; 64801e04c3fSmrg 64901e04c3fSmrg /* 4.1.4 Stencil Test section of the GL-ES 3.0 specification says: 65001e04c3fSmrg * 65101e04c3fSmrg * "In the initial state, [...] the front and back stencil mask are both 65201e04c3fSmrg * set to the value 2^s − 1, where s is greater than or equal to the 65301e04c3fSmrg * number of bits in the deepest stencil buffer* supported by the GL 65401e04c3fSmrg * implementation." 65501e04c3fSmrg * 65601e04c3fSmrg * Since the maximum supported precision for stencil buffers is 8 bits, 65701e04c3fSmrg * mask values should be initialized to 2^8 - 1 = 0xFF. 65801e04c3fSmrg */ 65901e04c3fSmrg ctx->Stencil.ValueMask[0] = 0xFF; 66001e04c3fSmrg ctx->Stencil.ValueMask[1] = 0xFF; 66101e04c3fSmrg ctx->Stencil.ValueMask[2] = 0xFF; 66201e04c3fSmrg ctx->Stencil.WriteMask[0] = 0xFF; 66301e04c3fSmrg ctx->Stencil.WriteMask[1] = 0xFF; 66401e04c3fSmrg ctx->Stencil.WriteMask[2] = 0xFF; 66501e04c3fSmrg 6667117f1b4Smrg ctx->Stencil.Clear = 0; 667c1f859d4Smrg ctx->Stencil._BackFace = 1; 6687117f1b4Smrg} 669