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