17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 4c1f859d4Smrg * 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 26c1f859d4Smrg#include "main/glheader.h" 27c1f859d4Smrg#include "main/context.h" 287ec681f3Smrg 29af69d88dSmrg#include "main/format_pack.h" 30af69d88dSmrg#include "main/format_unpack.h" 31af69d88dSmrg#include "main/stencil.h" 327117f1b4Smrg 337117f1b4Smrg#include "s_context.h" 347117f1b4Smrg#include "s_depth.h" 357117f1b4Smrg#include "s_stencil.h" 367117f1b4Smrg#include "s_span.h" 377117f1b4Smrg 387117f1b4Smrg 397117f1b4Smrg 407117f1b4Smrg/* Stencil Logic: 417117f1b4Smrg 427117f1b4SmrgIF stencil test fails THEN 437117f1b4Smrg Apply fail-op to stencil value 447117f1b4Smrg Don't write the pixel (RGBA,Z) 457117f1b4SmrgELSE 467117f1b4Smrg IF doing depth test && depth test fails THEN 477117f1b4Smrg Apply zfail-op to stencil value 487117f1b4Smrg Write RGBA and Z to appropriate buffers 497117f1b4Smrg ELSE 507117f1b4Smrg Apply zpass-op to stencil value 517117f1b4SmrgENDIF 527117f1b4Smrg 537117f1b4Smrg*/ 547117f1b4Smrg 557117f1b4Smrg 56af69d88dSmrg 57af69d88dSmrg/** 58af69d88dSmrg * Compute/return the offset of the stencil value in a pixel. 59af69d88dSmrg * For example, if the format is Z24+S8, the position of the stencil bits 60af69d88dSmrg * within the 4-byte pixel will be either 0 or 3. 61af69d88dSmrg */ 62af69d88dSmrgstatic GLint 63af69d88dSmrgget_stencil_offset(mesa_format format) 64af69d88dSmrg{ 65af69d88dSmrg const GLubyte one = 1; 66af69d88dSmrg GLubyte pixel[MAX_PIXEL_BYTES]; 67af69d88dSmrg GLint bpp = _mesa_get_format_bytes(format); 68af69d88dSmrg GLint i; 69af69d88dSmrg 70af69d88dSmrg assert(_mesa_get_format_bits(format, GL_STENCIL_BITS) == 8); 71af69d88dSmrg memset(pixel, 0, sizeof(pixel)); 72af69d88dSmrg _mesa_pack_ubyte_stencil_row(format, 1, &one, pixel); 73af69d88dSmrg 74af69d88dSmrg for (i = 0; i < bpp; i++) { 75af69d88dSmrg if (pixel[i]) 76af69d88dSmrg return i; 77af69d88dSmrg } 78af69d88dSmrg 79af69d88dSmrg _mesa_problem(NULL, "get_stencil_offset() failed\n"); 80af69d88dSmrg return 0; 81af69d88dSmrg} 82af69d88dSmrg 83af69d88dSmrg 84af69d88dSmrg/** Clamp the stencil value to [0, 255] */ 85af69d88dSmrgstatic inline GLubyte 86af69d88dSmrgclamp(GLint val) 87af69d88dSmrg{ 88af69d88dSmrg if (val < 0) 89af69d88dSmrg return 0; 90af69d88dSmrg else if (val > 255) 91af69d88dSmrg return 255; 92af69d88dSmrg else 93af69d88dSmrg return val; 94af69d88dSmrg} 95af69d88dSmrg 96af69d88dSmrg 97af69d88dSmrg#define STENCIL_OP(NEW_VAL) \ 98af69d88dSmrg if (invmask == 0) { \ 99af69d88dSmrg for (i = j = 0; i < n; i++, j += stride) { \ 100af69d88dSmrg if (mask[i]) { \ 101af69d88dSmrg GLubyte s = stencil[j]; \ 102af69d88dSmrg (void) s; \ 103af69d88dSmrg stencil[j] = (GLubyte) (NEW_VAL); \ 104af69d88dSmrg } \ 105af69d88dSmrg } \ 106af69d88dSmrg } \ 107af69d88dSmrg else { \ 108af69d88dSmrg for (i = j = 0; i < n; i++, j += stride) { \ 109af69d88dSmrg if (mask[i]) { \ 110af69d88dSmrg GLubyte s = stencil[j]; \ 111af69d88dSmrg stencil[j] = (GLubyte) ((invmask & s) | (wrtmask & (NEW_VAL))); \ 112af69d88dSmrg } \ 113af69d88dSmrg } \ 114af69d88dSmrg } 115af69d88dSmrg 116af69d88dSmrg 1177117f1b4Smrg/** 1187117f1b4Smrg * Apply the given stencil operator to the array of stencil values. 1197117f1b4Smrg * Don't touch stencil[i] if mask[i] is zero. 120af69d88dSmrg * @param n number of stencil values 121af69d88dSmrg * @param oper the stencil buffer operator 122af69d88dSmrg * @param face 0 or 1 for front or back face operation 123af69d88dSmrg * @param stencil array of stencil values (in/out) 124af69d88dSmrg * @param mask array [n] of flag: 1=apply operator, 0=don't apply operator 125af69d88dSmrg * @param stride stride between stencil values 1267117f1b4Smrg */ 1277117f1b4Smrgstatic void 128af69d88dSmrgapply_stencil_op(const struct gl_context *ctx, GLenum oper, GLuint face, 129af69d88dSmrg GLuint n, GLubyte stencil[], const GLubyte mask[], 130af69d88dSmrg GLint stride) 1317117f1b4Smrg{ 132af69d88dSmrg const GLubyte ref = _mesa_get_stencil_ref(ctx, face); 133af69d88dSmrg const GLubyte wrtmask = ctx->Stencil.WriteMask[face]; 134af69d88dSmrg const GLubyte invmask = (GLubyte) (~wrtmask); 135af69d88dSmrg GLuint i, j; 1367117f1b4Smrg 1377117f1b4Smrg switch (oper) { 138af69d88dSmrg case GL_KEEP: 139af69d88dSmrg /* do nothing */ 140af69d88dSmrg break; 141af69d88dSmrg case GL_ZERO: 142af69d88dSmrg /* replace stencil buf values with zero */ 143af69d88dSmrg STENCIL_OP(0); 144af69d88dSmrg break; 145af69d88dSmrg case GL_REPLACE: 146af69d88dSmrg /* replace stencil buf values with ref value */ 147af69d88dSmrg STENCIL_OP(ref); 148af69d88dSmrg break; 149af69d88dSmrg case GL_INCR: 150af69d88dSmrg /* increment stencil buf values, with clamping */ 151af69d88dSmrg STENCIL_OP(clamp(s + 1)); 152af69d88dSmrg break; 153af69d88dSmrg case GL_DECR: 154af69d88dSmrg /* increment stencil buf values, with clamping */ 155af69d88dSmrg STENCIL_OP(clamp(s - 1)); 156af69d88dSmrg break; 157af69d88dSmrg case GL_INCR_WRAP_EXT: 158af69d88dSmrg /* increment stencil buf values, without clamping */ 159af69d88dSmrg STENCIL_OP(s + 1); 160af69d88dSmrg break; 161af69d88dSmrg case GL_DECR_WRAP_EXT: 162af69d88dSmrg /* increment stencil buf values, without clamping */ 163af69d88dSmrg STENCIL_OP(s - 1); 164af69d88dSmrg break; 165af69d88dSmrg case GL_INVERT: 166af69d88dSmrg /* replace stencil buf values with inverted value */ 167af69d88dSmrg STENCIL_OP(~s); 168af69d88dSmrg break; 169af69d88dSmrg default: 170af69d88dSmrg _mesa_problem(ctx, "Bad stencil op in apply_stencil_op"); 1717117f1b4Smrg } 1727117f1b4Smrg} 1737117f1b4Smrg 1747117f1b4Smrg 1757117f1b4Smrg 176af69d88dSmrg#define STENCIL_TEST(FUNC) \ 177af69d88dSmrg for (i = j = 0; i < n; i++, j += stride) { \ 178af69d88dSmrg if (mask[i]) { \ 179af69d88dSmrg s = (GLubyte) (stencil[j] & valueMask); \ 180af69d88dSmrg if (FUNC) { \ 181af69d88dSmrg /* stencil pass */ \ 182af69d88dSmrg fail[i] = 0; \ 183af69d88dSmrg } \ 184af69d88dSmrg else { \ 185af69d88dSmrg /* stencil fail */ \ 186af69d88dSmrg fail[i] = 1; \ 187af69d88dSmrg mask[i] = 0; \ 188af69d88dSmrg } \ 189af69d88dSmrg } \ 190af69d88dSmrg else { \ 191af69d88dSmrg fail[i] = 0; \ 192af69d88dSmrg } \ 193af69d88dSmrg } 194af69d88dSmrg 195af69d88dSmrg 1967117f1b4Smrg 1977117f1b4Smrg/** 1987117f1b4Smrg * Apply stencil test to an array of stencil values (before depth buffering). 199af69d88dSmrg * For the values that fail, we'll apply the GL_STENCIL_FAIL operator to 200af69d88dSmrg * the stencil values. 201af69d88dSmrg * 202af69d88dSmrg * @param face 0 or 1 for front or back-face polygons 203af69d88dSmrg * @param n number of pixels in the array 204af69d88dSmrg * @param stencil array of [n] stencil values (in/out) 205af69d88dSmrg * @param mask array [n] of flag: 0=skip the pixel, 1=stencil the pixel, 206af69d88dSmrg * values are set to zero where the stencil test fails. 207af69d88dSmrg * @param stride stride between stencil values 208af69d88dSmrg * @return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed. 2097117f1b4Smrg */ 2107117f1b4Smrgstatic GLboolean 211af69d88dSmrgdo_stencil_test(struct gl_context *ctx, GLuint face, GLuint n, 212af69d88dSmrg GLubyte stencil[], GLubyte mask[], GLint stride) 2137117f1b4Smrg{ 214af69d88dSmrg SWcontext *swrast = SWRAST_CONTEXT(ctx); 215af69d88dSmrg GLubyte *fail = swrast->stencil_temp.buf2; 2167117f1b4Smrg GLboolean allfail = GL_FALSE; 217af69d88dSmrg GLuint i, j; 2187117f1b4Smrg const GLuint valueMask = ctx->Stencil.ValueMask[face]; 219af69d88dSmrg const GLubyte ref = (GLubyte) (_mesa_get_stencil_ref(ctx, face) & valueMask); 220af69d88dSmrg GLubyte s; 2217117f1b4Smrg 2227117f1b4Smrg /* 2237117f1b4Smrg * Perform stencil test. The results of this operation are stored 2247117f1b4Smrg * in the fail[] array: 2257117f1b4Smrg * IF fail[i] is non-zero THEN 2267117f1b4Smrg * the stencil fail operator is to be applied 2277117f1b4Smrg * ELSE 2287117f1b4Smrg * the stencil fail operator is not to be applied 2297117f1b4Smrg * ENDIF 2307117f1b4Smrg */ 2317117f1b4Smrg switch (ctx->Stencil.Function[face]) { 232af69d88dSmrg case GL_NEVER: 233af69d88dSmrg STENCIL_TEST(0); 234af69d88dSmrg allfail = GL_TRUE; 235af69d88dSmrg break; 236af69d88dSmrg case GL_LESS: 237af69d88dSmrg STENCIL_TEST(ref < s); 238af69d88dSmrg break; 239af69d88dSmrg case GL_LEQUAL: 240af69d88dSmrg STENCIL_TEST(ref <= s); 241af69d88dSmrg break; 242af69d88dSmrg case GL_GREATER: 243af69d88dSmrg STENCIL_TEST(ref > s); 244af69d88dSmrg break; 245af69d88dSmrg case GL_GEQUAL: 246af69d88dSmrg STENCIL_TEST(ref >= s); 247af69d88dSmrg break; 248af69d88dSmrg case GL_EQUAL: 249af69d88dSmrg STENCIL_TEST(ref == s); 250af69d88dSmrg break; 251af69d88dSmrg case GL_NOTEQUAL: 252af69d88dSmrg STENCIL_TEST(ref != s); 253af69d88dSmrg break; 254af69d88dSmrg case GL_ALWAYS: 255af69d88dSmrg STENCIL_TEST(1); 256af69d88dSmrg break; 257af69d88dSmrg default: 258af69d88dSmrg _mesa_problem(ctx, "Bad stencil func in gl_stencil_span"); 259af69d88dSmrg return 0; 2607117f1b4Smrg } 2617117f1b4Smrg 2627117f1b4Smrg if (ctx->Stencil.FailFunc[face] != GL_KEEP) { 263af69d88dSmrg apply_stencil_op(ctx, ctx->Stencil.FailFunc[face], face, n, stencil, 264af69d88dSmrg fail, stride); 2657117f1b4Smrg } 2667117f1b4Smrg 2677117f1b4Smrg return !allfail; 2687117f1b4Smrg} 2697117f1b4Smrg 2707117f1b4Smrg 271c1f859d4Smrg/** 272c1f859d4Smrg * Compute the zpass/zfail masks by comparing the pre- and post-depth test 273c1f859d4Smrg * masks. 274c1f859d4Smrg */ 275af69d88dSmrgstatic inline void 276c1f859d4Smrgcompute_pass_fail_masks(GLuint n, const GLubyte origMask[], 277c1f859d4Smrg const GLubyte newMask[], 278c1f859d4Smrg GLubyte passMask[], GLubyte failMask[]) 279c1f859d4Smrg{ 280c1f859d4Smrg GLuint i; 281c1f859d4Smrg for (i = 0; i < n; i++) { 28201e04c3fSmrg assert(newMask[i] == 0 || newMask[i] == 1); 283c1f859d4Smrg passMask[i] = origMask[i] & newMask[i]; 284c1f859d4Smrg failMask[i] = origMask[i] & (newMask[i] ^ 1); 285c1f859d4Smrg } 286c1f859d4Smrg} 287c1f859d4Smrg 2887117f1b4Smrg 2897117f1b4Smrg/** 290af69d88dSmrg * Get 8-bit stencil values from random locations in the stencil buffer. 2917117f1b4Smrg */ 292af69d88dSmrgstatic void 293af69d88dSmrgget_s8_values(struct gl_context *ctx, struct gl_renderbuffer *rb, 294af69d88dSmrg GLuint count, const GLint x[], const GLint y[], 295af69d88dSmrg GLubyte stencil[]) 2967117f1b4Smrg{ 297af69d88dSmrg struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 298af69d88dSmrg const GLint w = rb->Width, h = rb->Height; 299af69d88dSmrg const GLubyte *map = _swrast_pixel_address(rb, 0, 0); 300af69d88dSmrg GLuint i; 3017117f1b4Smrg 302af69d88dSmrg if (rb->Format == MESA_FORMAT_S_UINT8) { 303af69d88dSmrg const GLint rowStride = srb->RowStride; 304af69d88dSmrg for (i = 0; i < count; i++) { 305af69d88dSmrg if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { 306af69d88dSmrg stencil[i] = *(map + y[i] * rowStride + x[i]); 307af69d88dSmrg } 308af69d88dSmrg } 309af69d88dSmrg } 310af69d88dSmrg else { 311af69d88dSmrg const GLint bpp = _mesa_get_format_bytes(rb->Format); 312af69d88dSmrg const GLint rowStride = srb->RowStride; 313af69d88dSmrg for (i = 0; i < count; i++) { 314af69d88dSmrg if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { 315af69d88dSmrg const GLubyte *src = map + y[i] * rowStride + x[i] * bpp; 316af69d88dSmrg _mesa_unpack_ubyte_stencil_row(rb->Format, 1, src, &stencil[i]); 317af69d88dSmrg } 318af69d88dSmrg } 3197117f1b4Smrg } 320af69d88dSmrg} 3217117f1b4Smrg 322af69d88dSmrg 3237ec681f3Smrg 3247ec681f3Smrg/** 3257ec681f3Smrg ** Pack ubyte stencil pixels 3267ec681f3Smrg **/ 3277ec681f3Smrg 3287ec681f3Smrgstatic void 3297ec681f3Smrgpack_ubyte_stencil_Z24_S8(const uint8_t *src, void *dst) 3307ec681f3Smrg{ 3317ec681f3Smrg /* don't disturb the Z values */ 3327ec681f3Smrg uint32_t *d = ((uint32_t *) dst); 3337ec681f3Smrg uint32_t s = *src; 3347ec681f3Smrg uint32_t z = *d & 0xffffff00; 3357ec681f3Smrg *d = z | s; 3367ec681f3Smrg} 3377ec681f3Smrg 3387ec681f3Smrgstatic void 3397ec681f3Smrgpack_ubyte_stencil_S8_Z24(const uint8_t *src, void *dst) 3407ec681f3Smrg{ 3417ec681f3Smrg /* don't disturb the Z values */ 3427ec681f3Smrg uint32_t *d = ((uint32_t *) dst); 3437ec681f3Smrg uint32_t s = *src << 24; 3447ec681f3Smrg uint32_t z = *d & 0xffffff; 3457ec681f3Smrg *d = s | z; 3467ec681f3Smrg} 3477ec681f3Smrg 3487ec681f3Smrgstatic void 3497ec681f3Smrgpack_ubyte_stencil_S8(const uint8_t *src, void *dst) 3507ec681f3Smrg{ 3517ec681f3Smrg uint8_t *d = (uint8_t *) dst; 3527ec681f3Smrg *d = *src; 3537ec681f3Smrg} 3547ec681f3Smrg 3557ec681f3Smrgstatic void 3567ec681f3Smrgpack_ubyte_stencil_Z32_FLOAT_X24S8(const uint8_t *src, void *dst) 3577ec681f3Smrg{ 3587ec681f3Smrg float *d = ((float *) dst); 3597ec681f3Smrg d[1] = *src; 3607ec681f3Smrg} 3617ec681f3Smrg 3627ec681f3Smrg/** Pack a uint8_t stencil value to dest address */ 3637ec681f3Smrgtypedef void (*mesa_pack_ubyte_stencil_func)(const uint8_t *src, void *dst); 3647ec681f3Smrg 3657ec681f3Smrgstatic mesa_pack_ubyte_stencil_func 3667ec681f3Smrgget_pack_ubyte_stencil_func(mesa_format format) 3677ec681f3Smrg{ 3687ec681f3Smrg switch (format) { 3697ec681f3Smrg case MESA_FORMAT_S8_UINT_Z24_UNORM: 3707ec681f3Smrg return pack_ubyte_stencil_Z24_S8; 3717ec681f3Smrg case MESA_FORMAT_Z24_UNORM_S8_UINT: 3727ec681f3Smrg return pack_ubyte_stencil_S8_Z24; 3737ec681f3Smrg case MESA_FORMAT_S_UINT8: 3747ec681f3Smrg return pack_ubyte_stencil_S8; 3757ec681f3Smrg case MESA_FORMAT_Z32_FLOAT_S8X24_UINT: 3767ec681f3Smrg return pack_ubyte_stencil_Z32_FLOAT_X24S8; 3777ec681f3Smrg default: 3787ec681f3Smrg unreachable("unexpected format in get_pack_ubyte_stencil_func()"); 3797ec681f3Smrg } 3807ec681f3Smrg} 3817ec681f3Smrg 3827ec681f3Smrg 383af69d88dSmrg/** 384af69d88dSmrg * Put 8-bit stencil values at random locations into the stencil buffer. 385af69d88dSmrg */ 386af69d88dSmrgstatic void 387af69d88dSmrgput_s8_values(struct gl_context *ctx, struct gl_renderbuffer *rb, 388af69d88dSmrg GLuint count, const GLint x[], const GLint y[], 389af69d88dSmrg const GLubyte stencil[]) 390af69d88dSmrg{ 391af69d88dSmrg const GLint w = rb->Width, h = rb->Height; 3927ec681f3Smrg mesa_pack_ubyte_stencil_func pack_stencil = 3937ec681f3Smrg get_pack_ubyte_stencil_func(rb->Format); 394af69d88dSmrg GLuint i; 395af69d88dSmrg 396af69d88dSmrg for (i = 0; i < count; i++) { 397af69d88dSmrg if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { 398af69d88dSmrg GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]); 399af69d88dSmrg pack_stencil(&stencil[i], dst); 400af69d88dSmrg } 401af69d88dSmrg } 402af69d88dSmrg} 403af69d88dSmrg 404af69d88dSmrg 405af69d88dSmrg/** 406af69d88dSmrg * /return GL_TRUE = one or more fragments passed, 407af69d88dSmrg * GL_FALSE = all fragments failed. 408af69d88dSmrg */ 409af69d88dSmrgGLboolean 410af69d88dSmrg_swrast_stencil_and_ztest_span(struct gl_context *ctx, SWspan *span) 411af69d88dSmrg{ 412af69d88dSmrg SWcontext *swrast = SWRAST_CONTEXT(ctx); 413af69d88dSmrg struct gl_framebuffer *fb = ctx->DrawBuffer; 414af69d88dSmrg struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 415af69d88dSmrg const GLint stencilOffset = get_stencil_offset(rb->Format); 416af69d88dSmrg const GLint stencilStride = _mesa_get_format_bytes(rb->Format); 417af69d88dSmrg const GLuint face = (span->facing == 0) ? 0 : ctx->Stencil._BackFace; 418af69d88dSmrg const GLuint count = span->end; 419af69d88dSmrg GLubyte *mask = span->array->mask; 420af69d88dSmrg GLubyte *stencilTemp = swrast->stencil_temp.buf1; 421af69d88dSmrg GLubyte *stencilBuf; 422af69d88dSmrg 423af69d88dSmrg if (span->arrayMask & SPAN_XY) { 424af69d88dSmrg /* read stencil values from random locations */ 425af69d88dSmrg get_s8_values(ctx, rb, count, span->array->x, span->array->y, 426af69d88dSmrg stencilTemp); 427af69d88dSmrg stencilBuf = stencilTemp; 428af69d88dSmrg } 429af69d88dSmrg else { 430af69d88dSmrg /* Processing a horizontal run of pixels. Since stencil is always 431af69d88dSmrg * 8 bits for all MESA_FORMATs, we just need to use the right offset 432af69d88dSmrg * and stride to access them. 433af69d88dSmrg */ 434af69d88dSmrg stencilBuf = _swrast_pixel_address(rb, span->x, span->y) + stencilOffset; 4357117f1b4Smrg } 4367117f1b4Smrg 4377117f1b4Smrg /* 4387117f1b4Smrg * Apply the stencil test to the fragments. 4397117f1b4Smrg * failMask[i] is 1 if the stencil test failed. 4407117f1b4Smrg */ 441af69d88dSmrg if (!do_stencil_test(ctx, face, count, stencilBuf, mask, stencilStride)) { 4427117f1b4Smrg /* all fragments failed the stencil test, we're done. */ 4437117f1b4Smrg span->writeAll = GL_FALSE; 444af69d88dSmrg if (span->arrayMask & SPAN_XY) { 445af69d88dSmrg /* need to write the updated stencil values back to the buffer */ 446af69d88dSmrg put_s8_values(ctx, rb, count, span->array->x, span->array->y, 447af69d88dSmrg stencilTemp); 4487117f1b4Smrg } 4497117f1b4Smrg return GL_FALSE; 4507117f1b4Smrg } 4517117f1b4Smrg 4527117f1b4Smrg /* 4537117f1b4Smrg * Some fragments passed the stencil test, apply depth test to them 4547117f1b4Smrg * and apply Zpass and Zfail stencil ops. 4557117f1b4Smrg */ 4563464ebd5Sriastradh if (ctx->Depth.Test == GL_FALSE || 457af69d88dSmrg ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer == NULL) { 4587117f1b4Smrg /* 4597117f1b4Smrg * No depth buffer, just apply zpass stencil function to active pixels. 4607117f1b4Smrg */ 461af69d88dSmrg apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, count, 462af69d88dSmrg stencilBuf, mask, stencilStride); 4637117f1b4Smrg } 4647117f1b4Smrg else { 4657117f1b4Smrg /* 4667117f1b4Smrg * Perform depth buffering, then apply zpass or zfail stencil function. 4677117f1b4Smrg */ 468af69d88dSmrg SWcontext *swrast = SWRAST_CONTEXT(ctx); 469af69d88dSmrg GLubyte *passMask = swrast->stencil_temp.buf2; 470af69d88dSmrg GLubyte *failMask = swrast->stencil_temp.buf3; 471af69d88dSmrg GLubyte *origMask = swrast->stencil_temp.buf4; 4727117f1b4Smrg 4737117f1b4Smrg /* save the current mask bits */ 474af69d88dSmrg memcpy(origMask, mask, count * sizeof(GLubyte)); 4757117f1b4Smrg 4767117f1b4Smrg /* apply the depth test */ 4777117f1b4Smrg _swrast_depth_test_span(ctx, span); 4787117f1b4Smrg 479af69d88dSmrg compute_pass_fail_masks(count, origMask, mask, passMask, failMask); 4807117f1b4Smrg 4817117f1b4Smrg /* apply the pass and fail operations */ 4827117f1b4Smrg if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) { 483af69d88dSmrg apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face, 484af69d88dSmrg count, stencilBuf, failMask, stencilStride); 4857117f1b4Smrg } 4867117f1b4Smrg if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) { 487af69d88dSmrg apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, 488af69d88dSmrg count, stencilBuf, passMask, stencilStride); 4897117f1b4Smrg } 4907117f1b4Smrg } 4917117f1b4Smrg 492af69d88dSmrg /* Write updated stencil values back into hardware stencil buffer */ 493af69d88dSmrg if (span->arrayMask & SPAN_XY) { 494af69d88dSmrg put_s8_values(ctx, rb, count, span->array->x, span->array->y, 495af69d88dSmrg stencilBuf); 4967117f1b4Smrg } 4977ec681f3Smrg 4987117f1b4Smrg span->writeAll = GL_FALSE; 4997ec681f3Smrg 5007117f1b4Smrg return GL_TRUE; /* one or more fragments passed both tests */ 5017117f1b4Smrg} 5027117f1b4Smrg 5037117f1b4Smrg 5047117f1b4Smrg 5057117f1b4Smrg 5067117f1b4Smrg/** 5077117f1b4Smrg * Return a span of stencil values from the stencil buffer. 5087117f1b4Smrg * Used for glRead/CopyPixels 5097117f1b4Smrg * Input: n - how many pixels 5107117f1b4Smrg * x,y - location of first pixel 5117117f1b4Smrg * Output: stencil - the array of stencil values 5127117f1b4Smrg */ 5137117f1b4Smrgvoid 5143464ebd5Sriastradh_swrast_read_stencil_span(struct gl_context *ctx, struct gl_renderbuffer *rb, 515af69d88dSmrg GLint n, GLint x, GLint y, GLubyte stencil[]) 5167117f1b4Smrg{ 517af69d88dSmrg GLubyte *src; 518af69d88dSmrg 5197117f1b4Smrg if (y < 0 || y >= (GLint) rb->Height || 5207117f1b4Smrg x + n <= 0 || x >= (GLint) rb->Width) { 5217117f1b4Smrg /* span is completely outside framebuffer */ 5227117f1b4Smrg return; /* undefined values OK */ 5237117f1b4Smrg } 5247117f1b4Smrg 5257117f1b4Smrg if (x < 0) { 5267117f1b4Smrg GLint dx = -x; 5277117f1b4Smrg x = 0; 5287117f1b4Smrg n -= dx; 5297117f1b4Smrg stencil += dx; 5307117f1b4Smrg } 5317117f1b4Smrg if (x + n > (GLint) rb->Width) { 5327117f1b4Smrg GLint dx = x + n - rb->Width; 5337117f1b4Smrg n -= dx; 5347117f1b4Smrg } 5357117f1b4Smrg if (n <= 0) { 5367117f1b4Smrg return; 5377117f1b4Smrg } 5387117f1b4Smrg 539af69d88dSmrg src = _swrast_pixel_address(rb, x, y); 540af69d88dSmrg _mesa_unpack_ubyte_stencil_row(rb->Format, n, src, stencil); 5417117f1b4Smrg} 5427117f1b4Smrg 5437117f1b4Smrg 5447117f1b4Smrg 5457117f1b4Smrg/** 5467117f1b4Smrg * Write a span of stencil values to the stencil buffer. This function 5477117f1b4Smrg * applies the stencil write mask when needed. 5487117f1b4Smrg * Used for glDraw/CopyPixels 5497117f1b4Smrg * Input: n - how many pixels 5507117f1b4Smrg * x, y - location of first pixel 5517117f1b4Smrg * stencil - the array of stencil values 5527117f1b4Smrg */ 5537117f1b4Smrgvoid 5543464ebd5Sriastradh_swrast_write_stencil_span(struct gl_context *ctx, GLint n, GLint x, GLint y, 555af69d88dSmrg const GLubyte stencil[] ) 5567117f1b4Smrg{ 557af69d88dSmrg SWcontext *swrast = SWRAST_CONTEXT(ctx); 5587117f1b4Smrg struct gl_framebuffer *fb = ctx->DrawBuffer; 559af69d88dSmrg struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 5607117f1b4Smrg const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1; 5617117f1b4Smrg const GLuint stencilMask = ctx->Stencil.WriteMask[0]; 562af69d88dSmrg GLubyte *stencilBuf; 5637117f1b4Smrg 5647117f1b4Smrg if (y < 0 || y >= (GLint) rb->Height || 5657117f1b4Smrg x + n <= 0 || x >= (GLint) rb->Width) { 5667117f1b4Smrg /* span is completely outside framebuffer */ 5677117f1b4Smrg return; /* undefined values OK */ 5687117f1b4Smrg } 5697117f1b4Smrg if (x < 0) { 5707117f1b4Smrg GLint dx = -x; 5717117f1b4Smrg x = 0; 5727117f1b4Smrg n -= dx; 5737117f1b4Smrg stencil += dx; 5747117f1b4Smrg } 5757117f1b4Smrg if (x + n > (GLint) rb->Width) { 5767117f1b4Smrg GLint dx = x + n - rb->Width; 5777117f1b4Smrg n -= dx; 5787117f1b4Smrg } 5797117f1b4Smrg if (n <= 0) { 5807117f1b4Smrg return; 5817117f1b4Smrg } 5827117f1b4Smrg 583af69d88dSmrg stencilBuf = _swrast_pixel_address(rb, x, y); 584af69d88dSmrg 5857117f1b4Smrg if ((stencilMask & stencilMax) != stencilMax) { 5867117f1b4Smrg /* need to apply writemask */ 587af69d88dSmrg GLubyte *destVals = swrast->stencil_temp.buf1; 588af69d88dSmrg GLubyte *newVals = swrast->stencil_temp.buf2; 5897117f1b4Smrg GLint i; 590af69d88dSmrg 591af69d88dSmrg _mesa_unpack_ubyte_stencil_row(rb->Format, n, stencilBuf, destVals); 5927117f1b4Smrg for (i = 0; i < n; i++) { 5937117f1b4Smrg newVals[i] 5947117f1b4Smrg = (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask); 5957117f1b4Smrg } 596af69d88dSmrg _mesa_pack_ubyte_stencil_row(rb->Format, n, newVals, stencilBuf); 5977117f1b4Smrg } 5987117f1b4Smrg else { 599af69d88dSmrg _mesa_pack_ubyte_stencil_row(rb->Format, n, stencil, stencilBuf); 6007117f1b4Smrg } 6017117f1b4Smrg} 6027117f1b4Smrg 6037117f1b4Smrg 6047117f1b4Smrg 6057117f1b4Smrg/** 606af69d88dSmrg * Clear the stencil buffer. If the buffer is a combined 607af69d88dSmrg * depth+stencil buffer, only the stencil bits will be touched. 6087117f1b4Smrg */ 6097117f1b4Smrgvoid 610af69d88dSmrg_swrast_clear_stencil_buffer(struct gl_context *ctx) 6117117f1b4Smrg{ 612af69d88dSmrg struct gl_renderbuffer *rb = 613af69d88dSmrg ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; 6147117f1b4Smrg const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits; 615af69d88dSmrg const GLuint writeMask = ctx->Stencil.WriteMask[0]; 6167117f1b4Smrg const GLuint stencilMax = (1 << stencilBits) - 1; 6177117f1b4Smrg GLint x, y, width, height; 618af69d88dSmrg GLubyte *map; 619af69d88dSmrg GLint rowStride, i, j; 620af69d88dSmrg GLbitfield mapMode; 6217117f1b4Smrg 622af69d88dSmrg if (!rb || writeMask == 0) 6237117f1b4Smrg return; 6247117f1b4Smrg 6257117f1b4Smrg /* compute region to clear */ 6267117f1b4Smrg x = ctx->DrawBuffer->_Xmin; 6277117f1b4Smrg y = ctx->DrawBuffer->_Ymin; 6287117f1b4Smrg width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; 6297117f1b4Smrg height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; 6307117f1b4Smrg 631af69d88dSmrg mapMode = GL_MAP_WRITE_BIT; 632af69d88dSmrg if ((writeMask & stencilMax) != stencilMax) { 633af69d88dSmrg /* need to mask stencil values */ 634af69d88dSmrg mapMode |= GL_MAP_READ_BIT; 635af69d88dSmrg } 636af69d88dSmrg else if (_mesa_get_format_bits(rb->Format, GL_DEPTH_BITS) > 0) { 637af69d88dSmrg /* combined depth+stencil, need to mask Z values */ 638af69d88dSmrg mapMode |= GL_MAP_READ_BIT; 639af69d88dSmrg } 640af69d88dSmrg 641af69d88dSmrg ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, 64201e04c3fSmrg mapMode, &map, &rowStride, 64301e04c3fSmrg ctx->DrawBuffer->FlipY); 644af69d88dSmrg if (!map) { 645af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(stencil)"); 646af69d88dSmrg return; 647af69d88dSmrg } 648af69d88dSmrg 649af69d88dSmrg switch (rb->Format) { 650af69d88dSmrg case MESA_FORMAT_S_UINT8: 651af69d88dSmrg { 652af69d88dSmrg GLubyte clear = ctx->Stencil.Clear & writeMask & 0xff; 653af69d88dSmrg GLubyte mask = (~writeMask) & 0xff; 654af69d88dSmrg if (mask != 0) { 655af69d88dSmrg /* masked clear */ 6567117f1b4Smrg for (i = 0; i < height; i++) { 657af69d88dSmrg GLubyte *row = map; 6587117f1b4Smrg for (j = 0; j < width; j++) { 659af69d88dSmrg row[j] = (row[j] & mask) | clear; 6607117f1b4Smrg } 661af69d88dSmrg map += rowStride; 6627117f1b4Smrg } 6637117f1b4Smrg } 664af69d88dSmrg else if (rowStride == width) { 665af69d88dSmrg /* clear whole buffer */ 666af69d88dSmrg memset(map, clear, width * height); 6677117f1b4Smrg } 6687117f1b4Smrg else { 669af69d88dSmrg /* clear scissored */ 6707117f1b4Smrg for (i = 0; i < height; i++) { 671af69d88dSmrg memset(map, clear, width); 672af69d88dSmrg map += rowStride; 6737117f1b4Smrg } 6747117f1b4Smrg } 6757117f1b4Smrg } 676af69d88dSmrg break; 677af69d88dSmrg case MESA_FORMAT_Z24_UNORM_S8_UINT: 678af69d88dSmrg { 679af69d88dSmrg GLuint clear = (ctx->Stencil.Clear & writeMask & 0xff) << 24; 680af69d88dSmrg GLuint mask = (((~writeMask) & 0xff) << 24) | 0xffffff; 681af69d88dSmrg for (i = 0; i < height; i++) { 682af69d88dSmrg GLuint *row = (GLuint *) map; 683af69d88dSmrg for (j = 0; j < width; j++) { 684af69d88dSmrg row[j] = (row[j] & mask) | clear; 6857117f1b4Smrg } 686af69d88dSmrg map += rowStride; 6877117f1b4Smrg } 6887117f1b4Smrg } 689af69d88dSmrg break; 690af69d88dSmrg case MESA_FORMAT_S8_UINT_Z24_UNORM: 691af69d88dSmrg { 692af69d88dSmrg GLuint clear = ctx->Stencil.Clear & writeMask & 0xff; 693af69d88dSmrg GLuint mask = 0xffffff00 | ((~writeMask) & 0xff); 6947117f1b4Smrg for (i = 0; i < height; i++) { 695af69d88dSmrg GLuint *row = (GLuint *) map; 696af69d88dSmrg for (j = 0; j < width; j++) { 697af69d88dSmrg row[j] = (row[j] & mask) | clear; 698af69d88dSmrg } 699af69d88dSmrg map += rowStride; 7007117f1b4Smrg } 7017117f1b4Smrg } 702af69d88dSmrg break; 703af69d88dSmrg default: 704af69d88dSmrg _mesa_problem(ctx, "Unexpected stencil buffer format %s" 705af69d88dSmrg " in _swrast_clear_stencil_buffer()", 706af69d88dSmrg _mesa_get_format_name(rb->Format)); 7077117f1b4Smrg } 708af69d88dSmrg 709af69d88dSmrg ctx->Driver.UnmapRenderbuffer(ctx, rb); 7107117f1b4Smrg} 711