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