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