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