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