• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
42 IF stencil test fails THEN
43    Apply fail-op to stencil value
44    Don't write the pixel (RGBA,Z)
45 ELSE
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
51 ENDIF
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  */
62 static GLint
get_stencil_offset(mesa_format format)63 get_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] */
85 static inline GLubyte
clamp(GLint val)86 clamp(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  */
127 static void
apply_stencil_op(const struct gl_context * ctx,GLenum oper,GLuint face,GLuint n,GLubyte stencil[],const GLubyte mask[],GLint stride)128 apply_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  */
210 static GLboolean
do_stencil_test(struct gl_context * ctx,GLuint face,GLuint n,GLubyte stencil[],GLubyte mask[],GLint stride)211 do_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  */
275 static inline void
compute_pass_fail_masks(GLuint n,const GLubyte origMask[],const GLubyte newMask[],GLubyte passMask[],GLubyte failMask[])276 compute_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  */
292 static void
get_s8_values(struct gl_context * ctx,struct gl_renderbuffer * rb,GLuint count,const GLint x[],const GLint y[],GLubyte stencil[])293 get_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 
328 static void
pack_ubyte_stencil_Z24_S8(const uint8_t * src,void * dst)329 pack_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 
338 static void
pack_ubyte_stencil_S8_Z24(const uint8_t * src,void * dst)339 pack_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 
348 static void
pack_ubyte_stencil_S8(const uint8_t * src,void * dst)349 pack_ubyte_stencil_S8(const uint8_t *src, void *dst)
350 {
351    uint8_t *d = (uint8_t *) dst;
352    *d = *src;
353 }
354 
355 static void
pack_ubyte_stencil_Z32_FLOAT_X24S8(const uint8_t * src,void * dst)356 pack_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 */
363 typedef void (*mesa_pack_ubyte_stencil_func)(const uint8_t *src, void *dst);
364 
365 static mesa_pack_ubyte_stencil_func
get_pack_ubyte_stencil_func(mesa_format format)366 get_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  */
386 static void
put_s8_values(struct gl_context * ctx,struct gl_renderbuffer * rb,GLuint count,const GLint x[],const GLint y[],const GLubyte stencil[])387 put_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  */
409 GLboolean
_swrast_stencil_and_ztest_span(struct gl_context * ctx,SWspan * span)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  */
513 void
_swrast_read_stencil_span(struct gl_context * ctx,struct gl_renderbuffer * rb,GLint n,GLint x,GLint y,GLubyte stencil[])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  */
553 void
_swrast_write_stencil_span(struct gl_context * ctx,GLint n,GLint x,GLint y,const GLubyte stencil[])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  */
609 void
_swrast_clear_stencil_buffer(struct gl_context * ctx)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