s_stencil.c revision 7ec681f3
1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26#include "main/glheader.h"
27#include "main/context.h"
28
29#include "main/format_pack.h"
30#include "main/format_unpack.h"
31#include "main/stencil.h"
32
33#include "s_context.h"
34#include "s_depth.h"
35#include "s_stencil.h"
36#include "s_span.h"
37
38
39
40/* Stencil Logic:
41
42IF stencil test fails THEN
43   Apply fail-op to stencil value
44   Don't write the pixel (RGBA,Z)
45ELSE
46   IF doing depth test && depth test fails THEN
47      Apply zfail-op to stencil value
48      Write RGBA and Z to appropriate buffers
49   ELSE
50      Apply zpass-op to stencil value
51ENDIF
52
53*/
54
55
56
57/**
58 * Compute/return the offset of the stencil value in a pixel.
59 * For example, if the format is Z24+S8, the position of the stencil bits
60 * within the 4-byte pixel will be either 0 or 3.
61 */
62static GLint
63get_stencil_offset(mesa_format format)
64{
65   const GLubyte one = 1;
66   GLubyte pixel[MAX_PIXEL_BYTES];
67   GLint bpp = _mesa_get_format_bytes(format);
68   GLint i;
69
70   assert(_mesa_get_format_bits(format, GL_STENCIL_BITS) == 8);
71   memset(pixel, 0, sizeof(pixel));
72   _mesa_pack_ubyte_stencil_row(format, 1, &one, pixel);
73
74   for (i = 0; i < bpp; i++) {
75      if (pixel[i])
76         return i;
77   }
78
79   _mesa_problem(NULL, "get_stencil_offset() failed\n");
80   return 0;
81}
82
83
84/** Clamp the stencil value to [0, 255] */
85static inline GLubyte
86clamp(GLint val)
87{
88   if (val < 0)
89      return 0;
90   else if (val > 255)
91      return 255;
92   else
93      return val;
94}
95
96
97#define STENCIL_OP(NEW_VAL)                                                 \
98   if (invmask == 0) {                                                      \
99      for (i = j = 0; i < n; i++, j += stride) {                            \
100         if (mask[i]) {                                                     \
101            GLubyte s = stencil[j];                                         \
102            (void) s;                                                       \
103            stencil[j] = (GLubyte) (NEW_VAL);                               \
104         }                                                                  \
105      }                                                                     \
106   }                                                                        \
107   else {                                                                   \
108      for (i = j = 0; i < n; i++, j += stride) {                            \
109         if (mask[i]) {                                                     \
110            GLubyte s = stencil[j];                                         \
111            stencil[j] = (GLubyte) ((invmask & s) | (wrtmask & (NEW_VAL))); \
112         }                                                                  \
113      }                                                                     \
114   }
115
116
117/**
118 * Apply the given stencil operator to the array of stencil values.
119 * Don't touch stencil[i] if mask[i] is zero.
120 * @param n   number of stencil values
121 * @param oper  the stencil buffer operator
122 * @param face  0 or 1 for front or back face operation
123 * @param stencil  array of stencil values (in/out)
124 * @param mask  array [n] of flag:  1=apply operator, 0=don't apply operator
125 * @param stride  stride between stencil values
126 */
127static void
128apply_stencil_op(const struct gl_context *ctx, GLenum oper, GLuint face,
129                 GLuint n, GLubyte stencil[], const GLubyte mask[],
130                 GLint stride)
131{
132   const GLubyte ref = _mesa_get_stencil_ref(ctx, face);
133   const GLubyte wrtmask = ctx->Stencil.WriteMask[face];
134   const GLubyte invmask = (GLubyte) (~wrtmask);
135   GLuint i, j;
136
137   switch (oper) {
138   case GL_KEEP:
139      /* do nothing */
140      break;
141   case GL_ZERO:
142      /* replace stencil buf values with zero */
143      STENCIL_OP(0);
144      break;
145   case GL_REPLACE:
146      /* replace stencil buf values with ref value */
147      STENCIL_OP(ref);
148      break;
149   case GL_INCR:
150      /* increment stencil buf values, with clamping */
151      STENCIL_OP(clamp(s + 1));
152      break;
153   case GL_DECR:
154      /* increment stencil buf values, with clamping */
155      STENCIL_OP(clamp(s - 1));
156      break;
157   case GL_INCR_WRAP_EXT:
158      /* increment stencil buf values, without clamping */
159      STENCIL_OP(s + 1);
160      break;
161   case GL_DECR_WRAP_EXT:
162      /* increment stencil buf values, without clamping */
163      STENCIL_OP(s - 1);
164      break;
165   case GL_INVERT:
166      /* replace stencil buf values with inverted value */
167      STENCIL_OP(~s);
168      break;
169   default:
170      _mesa_problem(ctx, "Bad stencil op in apply_stencil_op");
171   }
172}
173
174
175
176#define STENCIL_TEST(FUNC)                        \
177   for (i = j = 0; i < n; i++, j += stride) {     \
178      if (mask[i]) {                              \
179         s = (GLubyte) (stencil[j] & valueMask);  \
180         if (FUNC) {                              \
181            /* stencil pass */                    \
182            fail[i] = 0;                          \
183         }                                        \
184         else {                                   \
185            /* stencil fail */                    \
186            fail[i] = 1;                          \
187            mask[i] = 0;                          \
188         }                                        \
189      }                                           \
190      else {                                      \
191         fail[i] = 0;                             \
192      }                                           \
193   }
194
195
196
197/**
198 * Apply stencil test to an array of stencil values (before depth buffering).
199 * For the values that fail, we'll apply the GL_STENCIL_FAIL operator to
200 * the stencil values.
201 *
202 * @param face  0 or 1 for front or back-face polygons
203 * @param n  number of pixels in the array
204 * @param stencil  array of [n] stencil values (in/out)
205 * @param mask  array [n] of flag:  0=skip the pixel, 1=stencil the pixel,
206 *              values are set to zero where the stencil test fails.
207 * @param stride  stride between stencil values
208 * @return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
209 */
210static GLboolean
211do_stencil_test(struct gl_context *ctx, GLuint face, GLuint n,
212                GLubyte stencil[], GLubyte mask[], GLint stride)
213{
214   SWcontext *swrast = SWRAST_CONTEXT(ctx);
215   GLubyte *fail = swrast->stencil_temp.buf2;
216   GLboolean allfail = GL_FALSE;
217   GLuint i, j;
218   const GLuint valueMask = ctx->Stencil.ValueMask[face];
219   const GLubyte ref = (GLubyte) (_mesa_get_stencil_ref(ctx, face) & valueMask);
220   GLubyte s;
221
222   /*
223    * Perform stencil test.  The results of this operation are stored
224    * in the fail[] array:
225    *   IF fail[i] is non-zero THEN
226    *       the stencil fail operator is to be applied
227    *   ELSE
228    *       the stencil fail operator is not to be applied
229    *   ENDIF
230    */
231   switch (ctx->Stencil.Function[face]) {
232   case GL_NEVER:
233      STENCIL_TEST(0);
234      allfail = GL_TRUE;
235      break;
236   case GL_LESS:
237      STENCIL_TEST(ref < s);
238      break;
239   case GL_LEQUAL:
240      STENCIL_TEST(ref <= s);
241      break;
242   case GL_GREATER:
243      STENCIL_TEST(ref > s);
244      break;
245   case GL_GEQUAL:
246      STENCIL_TEST(ref >= s);
247      break;
248   case GL_EQUAL:
249      STENCIL_TEST(ref == s);
250      break;
251   case GL_NOTEQUAL:
252      STENCIL_TEST(ref != s);
253      break;
254   case GL_ALWAYS:
255      STENCIL_TEST(1);
256      break;
257   default:
258      _mesa_problem(ctx, "Bad stencil func in gl_stencil_span");
259      return 0;
260   }
261
262   if (ctx->Stencil.FailFunc[face] != GL_KEEP) {
263      apply_stencil_op(ctx, ctx->Stencil.FailFunc[face], face, n, stencil,
264                       fail, stride);
265   }
266
267   return !allfail;
268}
269
270
271/**
272 * Compute the zpass/zfail masks by comparing the pre- and post-depth test
273 * masks.
274 */
275static inline void
276compute_pass_fail_masks(GLuint n, const GLubyte origMask[],
277                        const GLubyte newMask[],
278                        GLubyte passMask[], GLubyte failMask[])
279{
280   GLuint i;
281   for (i = 0; i < n; i++) {
282      assert(newMask[i] == 0 || newMask[i] == 1);
283      passMask[i] = origMask[i] & newMask[i];
284      failMask[i] = origMask[i] & (newMask[i] ^ 1);
285   }
286}
287
288
289/**
290 * Get 8-bit stencil values from random locations in the stencil buffer.
291 */
292static void
293get_s8_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
294              GLuint count, const GLint x[], const GLint y[],
295              GLubyte stencil[])
296{
297   struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
298   const GLint w = rb->Width, h = rb->Height;
299   const GLubyte *map = _swrast_pixel_address(rb, 0, 0);
300   GLuint i;
301
302   if (rb->Format == MESA_FORMAT_S_UINT8) {
303      const GLint rowStride = srb->RowStride;
304      for (i = 0; i < count; i++) {
305         if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
306            stencil[i] = *(map + y[i] * rowStride + x[i]);
307         }
308      }
309   }
310   else {
311      const GLint bpp = _mesa_get_format_bytes(rb->Format);
312      const GLint rowStride = srb->RowStride;
313      for (i = 0; i < count; i++) {
314         if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
315            const GLubyte *src = map + y[i] * rowStride + x[i] * bpp;
316            _mesa_unpack_ubyte_stencil_row(rb->Format, 1, src, &stencil[i]);
317         }
318      }
319   }
320}
321
322
323
324/**
325 ** Pack ubyte stencil pixels
326 **/
327
328static void
329pack_ubyte_stencil_Z24_S8(const uint8_t *src, void *dst)
330{
331   /* don't disturb the Z values */
332   uint32_t *d = ((uint32_t *) dst);
333   uint32_t s = *src;
334   uint32_t z = *d & 0xffffff00;
335   *d = z | s;
336}
337
338static void
339pack_ubyte_stencil_S8_Z24(const uint8_t *src, void *dst)
340{
341   /* don't disturb the Z values */
342   uint32_t *d = ((uint32_t *) dst);
343   uint32_t s = *src << 24;
344   uint32_t z = *d & 0xffffff;
345   *d = s | z;
346}
347
348static void
349pack_ubyte_stencil_S8(const uint8_t *src, void *dst)
350{
351   uint8_t *d = (uint8_t *) dst;
352   *d = *src;
353}
354
355static void
356pack_ubyte_stencil_Z32_FLOAT_X24S8(const uint8_t *src, void *dst)
357{
358   float *d = ((float *) dst);
359   d[1] = *src;
360}
361
362/** Pack a uint8_t stencil value to dest address */
363typedef void (*mesa_pack_ubyte_stencil_func)(const uint8_t *src, void *dst);
364
365static mesa_pack_ubyte_stencil_func
366get_pack_ubyte_stencil_func(mesa_format format)
367{
368   switch (format) {
369   case MESA_FORMAT_S8_UINT_Z24_UNORM:
370      return pack_ubyte_stencil_Z24_S8;
371   case MESA_FORMAT_Z24_UNORM_S8_UINT:
372      return pack_ubyte_stencil_S8_Z24;
373   case MESA_FORMAT_S_UINT8:
374      return pack_ubyte_stencil_S8;
375   case MESA_FORMAT_Z32_FLOAT_S8X24_UINT:
376      return pack_ubyte_stencil_Z32_FLOAT_X24S8;
377   default:
378      unreachable("unexpected format in get_pack_ubyte_stencil_func()");
379   }
380}
381
382
383/**
384 * Put 8-bit stencil values at random locations into the stencil buffer.
385 */
386static void
387put_s8_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
388              GLuint count, const GLint x[], const GLint y[],
389              const GLubyte stencil[])
390{
391   const GLint w = rb->Width, h = rb->Height;
392   mesa_pack_ubyte_stencil_func pack_stencil =
393      get_pack_ubyte_stencil_func(rb->Format);
394   GLuint i;
395
396   for (i = 0; i < count; i++) {
397      if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
398         GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]);
399         pack_stencil(&stencil[i], dst);
400      }
401   }
402}
403
404
405/**
406 * /return GL_TRUE = one or more fragments passed,
407 * GL_FALSE = all fragments failed.
408 */
409GLboolean
410_swrast_stencil_and_ztest_span(struct gl_context *ctx, SWspan *span)
411{
412   SWcontext *swrast = SWRAST_CONTEXT(ctx);
413   struct gl_framebuffer *fb = ctx->DrawBuffer;
414   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
415   const GLint stencilOffset = get_stencil_offset(rb->Format);
416   const GLint stencilStride = _mesa_get_format_bytes(rb->Format);
417   const GLuint face = (span->facing == 0) ? 0 : ctx->Stencil._BackFace;
418   const GLuint count = span->end;
419   GLubyte *mask = span->array->mask;
420   GLubyte *stencilTemp = swrast->stencil_temp.buf1;
421   GLubyte *stencilBuf;
422
423   if (span->arrayMask & SPAN_XY) {
424      /* read stencil values from random locations */
425      get_s8_values(ctx, rb, count, span->array->x, span->array->y,
426                    stencilTemp);
427      stencilBuf = stencilTemp;
428   }
429   else {
430      /* Processing a horizontal run of pixels.  Since stencil is always
431       * 8 bits for all MESA_FORMATs, we just need to use the right offset
432       * and stride to access them.
433       */
434      stencilBuf = _swrast_pixel_address(rb, span->x, span->y) + stencilOffset;
435   }
436
437   /*
438    * Apply the stencil test to the fragments.
439    * failMask[i] is 1 if the stencil test failed.
440    */
441   if (!do_stencil_test(ctx, face, count, stencilBuf, mask, stencilStride)) {
442      /* all fragments failed the stencil test, we're done. */
443      span->writeAll = GL_FALSE;
444      if (span->arrayMask & SPAN_XY) {
445         /* need to write the updated stencil values back to the buffer */
446         put_s8_values(ctx, rb, count, span->array->x, span->array->y,
447                       stencilTemp);
448      }
449      return GL_FALSE;
450   }
451
452   /*
453    * Some fragments passed the stencil test, apply depth test to them
454    * and apply Zpass and Zfail stencil ops.
455    */
456   if (ctx->Depth.Test == GL_FALSE ||
457       ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer == NULL) {
458      /*
459       * No depth buffer, just apply zpass stencil function to active pixels.
460       */
461      apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, count,
462                       stencilBuf, mask, stencilStride);
463   }
464   else {
465      /*
466       * Perform depth buffering, then apply zpass or zfail stencil function.
467       */
468      SWcontext *swrast = SWRAST_CONTEXT(ctx);
469      GLubyte *passMask = swrast->stencil_temp.buf2;
470      GLubyte *failMask = swrast->stencil_temp.buf3;
471      GLubyte *origMask = swrast->stencil_temp.buf4;
472
473      /* save the current mask bits */
474      memcpy(origMask, mask, count * sizeof(GLubyte));
475
476      /* apply the depth test */
477      _swrast_depth_test_span(ctx, span);
478
479      compute_pass_fail_masks(count, origMask, mask, passMask, failMask);
480
481      /* apply the pass and fail operations */
482      if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) {
483         apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face,
484                          count, stencilBuf, failMask, stencilStride);
485      }
486      if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) {
487         apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face,
488                          count, stencilBuf, passMask, stencilStride);
489      }
490   }
491
492   /* Write updated stencil values back into hardware stencil buffer */
493   if (span->arrayMask & SPAN_XY) {
494      put_s8_values(ctx, rb, count, span->array->x, span->array->y,
495                    stencilBuf);
496   }
497
498   span->writeAll = GL_FALSE;
499
500   return GL_TRUE;  /* one or more fragments passed both tests */
501}
502
503
504
505
506/**
507 * Return a span of stencil values from the stencil buffer.
508 * Used for glRead/CopyPixels
509 * Input:  n - how many pixels
510 *         x,y - location of first pixel
511 * Output:  stencil - the array of stencil values
512 */
513void
514_swrast_read_stencil_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
515                          GLint n, GLint x, GLint y, GLubyte stencil[])
516{
517   GLubyte *src;
518
519   if (y < 0 || y >= (GLint) rb->Height ||
520       x + n <= 0 || x >= (GLint) rb->Width) {
521      /* span is completely outside framebuffer */
522      return; /* undefined values OK */
523   }
524
525   if (x < 0) {
526      GLint dx = -x;
527      x = 0;
528      n -= dx;
529      stencil += dx;
530   }
531   if (x + n > (GLint) rb->Width) {
532      GLint dx = x + n - rb->Width;
533      n -= dx;
534   }
535   if (n <= 0) {
536      return;
537   }
538
539   src = _swrast_pixel_address(rb, x, y);
540   _mesa_unpack_ubyte_stencil_row(rb->Format, n, src, stencil);
541}
542
543
544
545/**
546 * Write a span of stencil values to the stencil buffer.  This function
547 * applies the stencil write mask when needed.
548 * Used for glDraw/CopyPixels
549 * Input:  n - how many pixels
550 *         x, y - location of first pixel
551 *         stencil - the array of stencil values
552 */
553void
554_swrast_write_stencil_span(struct gl_context *ctx, GLint n, GLint x, GLint y,
555                           const GLubyte stencil[] )
556{
557   SWcontext *swrast = SWRAST_CONTEXT(ctx);
558   struct gl_framebuffer *fb = ctx->DrawBuffer;
559   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
560   const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1;
561   const GLuint stencilMask = ctx->Stencil.WriteMask[0];
562   GLubyte *stencilBuf;
563
564   if (y < 0 || y >= (GLint) rb->Height ||
565       x + n <= 0 || x >= (GLint) rb->Width) {
566      /* span is completely outside framebuffer */
567      return; /* undefined values OK */
568   }
569   if (x < 0) {
570      GLint dx = -x;
571      x = 0;
572      n -= dx;
573      stencil += dx;
574   }
575   if (x + n > (GLint) rb->Width) {
576      GLint dx = x + n - rb->Width;
577      n -= dx;
578   }
579   if (n <= 0) {
580      return;
581   }
582
583   stencilBuf = _swrast_pixel_address(rb, x, y);
584
585   if ((stencilMask & stencilMax) != stencilMax) {
586      /* need to apply writemask */
587      GLubyte *destVals = swrast->stencil_temp.buf1;
588      GLubyte *newVals = swrast->stencil_temp.buf2;
589      GLint i;
590
591      _mesa_unpack_ubyte_stencil_row(rb->Format, n, stencilBuf, destVals);
592      for (i = 0; i < n; i++) {
593         newVals[i]
594            = (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask);
595      }
596      _mesa_pack_ubyte_stencil_row(rb->Format, n, newVals, stencilBuf);
597   }
598   else {
599      _mesa_pack_ubyte_stencil_row(rb->Format, n, stencil, stencilBuf);
600   }
601}
602
603
604
605/**
606 * Clear the stencil buffer.  If the buffer is a combined
607 * depth+stencil buffer, only the stencil bits will be touched.
608 */
609void
610_swrast_clear_stencil_buffer(struct gl_context *ctx)
611{
612   struct gl_renderbuffer *rb =
613      ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
614   const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits;
615   const GLuint writeMask = ctx->Stencil.WriteMask[0];
616   const GLuint stencilMax = (1 << stencilBits) - 1;
617   GLint x, y, width, height;
618   GLubyte *map;
619   GLint rowStride, i, j;
620   GLbitfield mapMode;
621
622   if (!rb || writeMask == 0)
623      return;
624
625   /* compute region to clear */
626   x = ctx->DrawBuffer->_Xmin;
627   y = ctx->DrawBuffer->_Ymin;
628   width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
629   height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
630
631   mapMode = GL_MAP_WRITE_BIT;
632   if ((writeMask & stencilMax) != stencilMax) {
633      /* need to mask stencil values */
634      mapMode |= GL_MAP_READ_BIT;
635   }
636   else if (_mesa_get_format_bits(rb->Format, GL_DEPTH_BITS) > 0) {
637      /* combined depth+stencil, need to mask Z values */
638      mapMode |= GL_MAP_READ_BIT;
639   }
640
641   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
642                               mapMode, &map, &rowStride,
643                               ctx->DrawBuffer->FlipY);
644   if (!map) {
645      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(stencil)");
646      return;
647   }
648
649   switch (rb->Format) {
650   case MESA_FORMAT_S_UINT8:
651      {
652         GLubyte clear = ctx->Stencil.Clear & writeMask & 0xff;
653         GLubyte mask = (~writeMask) & 0xff;
654         if (mask != 0) {
655            /* masked clear */
656            for (i = 0; i < height; i++) {
657               GLubyte *row = map;
658               for (j = 0; j < width; j++) {
659                  row[j] = (row[j] & mask) | clear;
660               }
661               map += rowStride;
662            }
663         }
664         else if (rowStride == width) {
665            /* clear whole buffer */
666            memset(map, clear, width * height);
667         }
668         else {
669            /* clear scissored */
670            for (i = 0; i < height; i++) {
671               memset(map, clear, width);
672               map += rowStride;
673            }
674         }
675      }
676      break;
677   case MESA_FORMAT_Z24_UNORM_S8_UINT:
678      {
679         GLuint clear = (ctx->Stencil.Clear & writeMask & 0xff) << 24;
680         GLuint mask = (((~writeMask) & 0xff) << 24) | 0xffffff;
681         for (i = 0; i < height; i++) {
682            GLuint *row = (GLuint *) map;
683            for (j = 0; j < width; j++) {
684               row[j] = (row[j] & mask) | clear;
685            }
686            map += rowStride;
687         }
688      }
689      break;
690   case MESA_FORMAT_S8_UINT_Z24_UNORM:
691      {
692         GLuint clear = ctx->Stencil.Clear & writeMask & 0xff;
693         GLuint mask = 0xffffff00 | ((~writeMask) & 0xff);
694         for (i = 0; i < height; i++) {
695            GLuint *row = (GLuint *) map;
696            for (j = 0; j < width; j++) {
697               row[j] = (row[j] & mask) | clear;
698            }
699            map += rowStride;
700         }
701      }
702      break;
703   default:
704      _mesa_problem(ctx, "Unexpected stencil buffer format %s"
705                    " in _swrast_clear_stencil_buffer()",
706                    _mesa_get_format_name(rb->Format));
707   }
708
709   ctx->Driver.UnmapRenderbuffer(ctx, rb);
710}
711