stencil.c revision 716be936866dcb4cd51e774e5403e28645d5c685
1/* $Id: stencil.c,v 1.16 2000/04/11 21:26:57 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.3
6 *
7 * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28#ifdef PC_HEADER
29#include "all.h"
30#else
31#include "glheader.h"
32#include "context.h"
33#include "depth.h"
34#include "mem.h"
35#include "pb.h"
36#include "stencil.h"
37#include "types.h"
38#include "enable.h"
39#endif
40
41
42
43
44void
45_mesa_ClearStencil( GLint s )
46{
47   GET_CURRENT_CONTEXT(ctx);
48   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearStencil");
49   ctx->Stencil.Clear = (GLstencil) s;
50
51   if (ctx->Driver.ClearStencil) {
52      (*ctx->Driver.ClearStencil)( ctx, s );
53   }
54}
55
56
57
58void
59_mesa_StencilFunc( GLenum func, GLint ref, GLuint mask )
60{
61   GET_CURRENT_CONTEXT(ctx);
62   GLint maxref;
63
64   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilFunc");
65
66   switch (func) {
67      case GL_NEVER:
68      case GL_LESS:
69      case GL_LEQUAL:
70      case GL_GREATER:
71      case GL_GEQUAL:
72      case GL_EQUAL:
73      case GL_NOTEQUAL:
74      case GL_ALWAYS:
75         ctx->Stencil.Function = func;
76         break;
77      default:
78         gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" );
79         return;
80   }
81
82   maxref = (1 << STENCIL_BITS) - 1;
83   ctx->Stencil.Ref = (GLstencil) CLAMP( ref, 0, maxref );
84   ctx->Stencil.ValueMask = (GLstencil) mask;
85
86   if (ctx->Driver.StencilFunc) {
87      (*ctx->Driver.StencilFunc)( ctx, func, ctx->Stencil.Ref, mask );
88   }
89}
90
91
92
93void
94_mesa_StencilMask( GLuint mask )
95{
96   GET_CURRENT_CONTEXT(ctx);
97   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilMask");
98   ctx->Stencil.WriteMask = (GLstencil) mask;
99
100   if (ctx->Driver.StencilMask) {
101      (*ctx->Driver.StencilMask)( ctx, mask );
102   }
103}
104
105
106
107void
108_mesa_StencilOp( GLenum fail, GLenum zfail, GLenum zpass )
109{
110   GET_CURRENT_CONTEXT(ctx);
111   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilOp");
112   switch (fail) {
113      case GL_KEEP:
114      case GL_ZERO:
115      case GL_REPLACE:
116      case GL_INCR:
117      case GL_DECR:
118      case GL_INVERT:
119      case GL_INCR_WRAP_EXT:
120      case GL_DECR_WRAP_EXT:
121         ctx->Stencil.FailFunc = fail;
122         break;
123      default:
124         gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
125         return;
126   }
127   switch (zfail) {
128      case GL_KEEP:
129      case GL_ZERO:
130      case GL_REPLACE:
131      case GL_INCR:
132      case GL_DECR:
133      case GL_INVERT:
134      case GL_INCR_WRAP_EXT:
135      case GL_DECR_WRAP_EXT:
136         ctx->Stencil.ZFailFunc = zfail;
137         break;
138      default:
139         gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
140         return;
141   }
142   switch (zpass) {
143      case GL_KEEP:
144      case GL_ZERO:
145      case GL_REPLACE:
146      case GL_INCR:
147      case GL_DECR:
148      case GL_INVERT:
149      case GL_INCR_WRAP_EXT:
150      case GL_DECR_WRAP_EXT:
151         ctx->Stencil.ZPassFunc = zpass;
152         break;
153      default:
154         gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
155         return;
156   }
157
158   if (ctx->Driver.StencilOp) {
159      (*ctx->Driver.StencilOp)( ctx, fail, zfail, zpass );
160   }
161}
162
163
164
165/* Stencil Logic:
166
167IF stencil test fails THEN
168   Apply fail-op to stencil value
169   Don't write the pixel (RGBA,Z)
170ELSE
171   IF doing depth test && depth test fails THEN
172      Apply zfail-op to stencil value
173      Write RGBA and Z to appropriate buffers
174   ELSE
175      Apply zpass-op to stencil value
176ENDIF
177
178*/
179
180
181
182
183/*
184 * Return the address of a stencil buffer value given the window coords:
185 */
186#define STENCIL_ADDRESS(X,Y)  \
187       (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
188
189
190
191/*
192 * Apply the given stencil operator to the array of stencil values.
193 * Don't touch stencil[i] if mask[i] is zero.
194 * Input:  n - size of stencil array
195 *         oper - the stencil buffer operator
196 *         stencil - array of stencil values
197 *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
198 * Output:  stencil - modified values
199 */
200static void apply_stencil_op( const GLcontext *ctx, GLenum oper,
201                              GLuint n, GLstencil stencil[],
202                              const GLubyte mask[] )
203{
204   const GLstencil ref = ctx->Stencil.Ref;
205   const GLstencil wrtmask = ctx->Stencil.WriteMask;
206   const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
207   GLuint i;
208
209   switch (oper) {
210      case GL_KEEP:
211         /* do nothing */
212         break;
213      case GL_ZERO:
214	 if (invmask==0) {
215	    for (i=0;i<n;i++) {
216	       if (mask[i]) {
217		  stencil[i] = 0;
218	       }
219	    }
220	 }
221	 else {
222	    for (i=0;i<n;i++) {
223	       if (mask[i]) {
224		  stencil[i] = (GLstencil) (stencil[i] & invmask);
225	       }
226	    }
227	 }
228	 break;
229      case GL_REPLACE:
230	 if (invmask==0) {
231	    for (i=0;i<n;i++) {
232	       if (mask[i]) {
233                  stencil[i] = ref;
234	       }
235	    }
236	 }
237	 else {
238	    for (i=0;i<n;i++) {
239	       if (mask[i]) {
240		  GLstencil s = stencil[i];
241		  stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref));
242	       }
243	    }
244	 }
245	 break;
246      case GL_INCR:
247	 if (invmask==0) {
248	    for (i=0;i<n;i++) {
249	       if (mask[i]) {
250		  GLstencil s = stencil[i];
251		  if (s < STENCIL_MAX) {
252		     stencil[i] = (GLstencil) (s+1);
253		  }
254	       }
255	    }
256	 }
257	 else {
258	    for (i=0;i<n;i++) {
259	       if (mask[i]) {
260		  /* VERIFY logic of adding 1 to a write-masked value */
261		  GLstencil s = stencil[i];
262		  if (s < STENCIL_MAX) {
263		     stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
264		  }
265	       }
266	    }
267	 }
268	 break;
269      case GL_DECR:
270	 if (invmask==0) {
271	    for (i=0;i<n;i++) {
272	       if (mask[i]) {
273		  GLstencil s = stencil[i];
274		  if (s>0) {
275		     stencil[i] = (GLstencil) (s-1);
276		  }
277	       }
278	    }
279	 }
280	 else {
281	    for (i=0;i<n;i++) {
282	       if (mask[i]) {
283		  /* VERIFY logic of subtracting 1 to a write-masked value */
284		  GLstencil s = stencil[i];
285		  if (s>0) {
286		     stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
287		  }
288	       }
289	    }
290	 }
291	 break;
292      case GL_INCR_WRAP_EXT:
293	 if (invmask==0) {
294	    for (i=0;i<n;i++) {
295	       if (mask[i]) {
296                  stencil[i]++;
297	       }
298	    }
299	 }
300	 else {
301	    for (i=0;i<n;i++) {
302	       if (mask[i]) {
303                  GLstencil s = stencil[i];
304                  stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
305	       }
306	    }
307	 }
308	 break;
309      case GL_DECR_WRAP_EXT:
310	 if (invmask==0) {
311	    for (i=0;i<n;i++) {
312	       if (mask[i]) {
313		  stencil[i]--;
314	       }
315	    }
316	 }
317	 else {
318	    for (i=0;i<n;i++) {
319	       if (mask[i]) {
320                  GLstencil s = stencil[i];
321                  stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
322	       }
323	    }
324	 }
325	 break;
326      case GL_INVERT:
327	 if (invmask==0) {
328	    for (i=0;i<n;i++) {
329	       if (mask[i]) {
330		  GLstencil s = stencil[i];
331		  stencil[i] = (GLstencil) ~s;
332	       }
333	    }
334	 }
335	 else {
336	    for (i=0;i<n;i++) {
337	       if (mask[i]) {
338		  GLstencil s = stencil[i];
339		  stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s));
340	       }
341	    }
342	 }
343	 break;
344      default:
345         gl_problem(ctx, "Bad stencil op in apply_stencil_op");
346   }
347}
348
349
350
351
352/*
353 * Apply stencil test to an array of stencil values (before depth buffering).
354 * Input:  n - number of pixels in the array
355 *         stencil - array of [n] stencil values
356 *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
357 * Output:  mask - pixels which fail the stencil test will have their
358 *                 mask flag set to 0.
359 *          stencil - updated stencil values (where the test passed)
360 * Return:  GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
361 */
362static GLboolean
363do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[],
364                 GLubyte mask[] )
365{
366   GLubyte fail[PB_SIZE];
367   GLboolean allfail = GL_FALSE;
368   GLuint i;
369   GLstencil r, s;
370
371   ASSERT(n <= PB_SIZE);
372
373   /*
374    * Perform stencil test.  The results of this operation are stored
375    * in the fail[] array:
376    *   IF fail[i] is non-zero THEN
377    *       the stencil fail operator is to be applied
378    *   ELSE
379    *       the stencil fail operator is not to be applied
380    *   ENDIF
381    */
382   switch (ctx->Stencil.Function) {
383      case GL_NEVER:
384         /* always fail */
385         for (i=0;i<n;i++) {
386	    if (mask[i]) {
387	       mask[i] = 0;
388	       fail[i] = 1;
389	    }
390	    else {
391	       fail[i] = 0;
392	    }
393	 }
394	 allfail = GL_TRUE;
395	 break;
396      case GL_LESS:
397	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
398	 for (i=0;i<n;i++) {
399	    if (mask[i]) {
400	       s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
401	       if (r < s) {
402		  /* passed */
403		  fail[i] = 0;
404	       }
405	       else {
406		  fail[i] = 1;
407		  mask[i] = 0;
408	       }
409	    }
410	    else {
411	       fail[i] = 0;
412	    }
413	 }
414	 break;
415      case GL_LEQUAL:
416	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
417	 for (i=0;i<n;i++) {
418	    if (mask[i]) {
419	       s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
420	       if (r <= s) {
421		  /* pass */
422		  fail[i] = 0;
423	       }
424	       else {
425		  fail[i] = 1;
426		  mask[i] = 0;
427	       }
428	    }
429	    else {
430	       fail[i] = 0;
431	    }
432	 }
433	 break;
434      case GL_GREATER:
435	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
436	 for (i=0;i<n;i++) {
437	    if (mask[i]) {
438	       s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
439	       if (r > s) {
440		  /* passed */
441		  fail[i] = 0;
442	       }
443	       else {
444		  fail[i] = 1;
445		  mask[i] = 0;
446	       }
447	    }
448	    else {
449	       fail[i] = 0;
450	    }
451	 }
452	 break;
453      case GL_GEQUAL:
454	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
455	 for (i=0;i<n;i++) {
456	    if (mask[i]) {
457	       s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
458	       if (r >= s) {
459		  /* passed */
460		  fail[i] = 0;
461	       }
462	       else {
463		  fail[i] = 1;
464		  mask[i] = 0;
465	       }
466	    }
467	    else {
468	       fail[i] = 0;
469	    }
470	 }
471	 break;
472      case GL_EQUAL:
473	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
474	 for (i=0;i<n;i++) {
475	    if (mask[i]) {
476	       s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
477	       if (r == s) {
478		  /* passed */
479		  fail[i] = 0;
480	       }
481	       else {
482		  fail[i] = 1;
483		  mask[i] = 0;
484	       }
485	    }
486	    else {
487	       fail[i] = 0;
488	    }
489	 }
490	 break;
491      case GL_NOTEQUAL:
492	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
493	 for (i=0;i<n;i++) {
494	    if (mask[i]) {
495	       s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
496	       if (r != s) {
497		  /* passed */
498		  fail[i] = 0;
499	       }
500	       else {
501		  fail[i] = 1;
502		  mask[i] = 0;
503	       }
504	    }
505	    else {
506	       fail[i] = 0;
507	    }
508	 }
509	 break;
510      case GL_ALWAYS:
511	 /* always pass */
512	 for (i=0;i<n;i++) {
513	    fail[i] = 0;
514	 }
515	 break;
516      default:
517         gl_problem(ctx, "Bad stencil func in gl_stencil_span");
518         return 0;
519   }
520
521   if (ctx->Stencil.FailFunc != GL_KEEP) {
522      apply_stencil_op( ctx, ctx->Stencil.FailFunc, n, stencil, fail );
523   }
524
525   return !allfail;
526}
527
528
529
530
531/*
532 * Apply stencil and depth testing to an array of pixels.
533 * Hardware or software stencil buffer acceptable.
534 * Input:  n - number of pixels in the span
535 *         z - array [n] of z values
536 *         stencil - array [n] of stencil values
537 *         mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
538 * Output:  stencil - modified stencil values
539 *          mask - array [n] of flags (1=stencil and depth test passed)
540 * Return: GL_TRUE - all fragments failed the testing
541 *         GL_FALSE - one or more fragments passed the testing
542 *
543 */
544static GLboolean
545stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
546                        const GLdepth z[], GLstencil stencil[],
547                        GLubyte mask[] )
548{
549   ASSERT(ctx->Stencil.Enabled);
550   ASSERT(n <= PB_SIZE);
551
552   /*
553    * Apply the stencil test to the fragments.
554    * failMask[i] is 1 if the stencil test failed.
555    */
556   if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) {
557      /* all fragments failed the stencil test, we're done. */
558      return GL_FALSE;
559   }
560
561
562   /*
563    * Some fragments passed the stencil test, apply depth test to them
564    * and apply Zpass and Zfail stencil ops.
565    */
566   if (ctx->Depth.Test==GL_FALSE) {
567      /*
568       * No depth buffer, just apply zpass stencil function to active pixels.
569       */
570      apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
571   }
572   else {
573      /*
574       * Perform depth buffering, then apply zpass or zfail stencil function.
575       */
576      GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
577      GLuint i;
578
579      /* save the current mask bits */
580      MEMCPY(oldmask, mask, n * sizeof(GLubyte));
581
582      /* apply the depth test */
583      _mesa_depth_test_span(ctx, n, x, y, z, mask);
584
585      /* Set the stencil pass/fail flags according to result of depth testing.
586       * if oldmask[i] == 0 then
587       *    Don't touch the stencil value
588       * else if oldmask[i] and newmask[i] then
589       *    Depth test passed
590       * else
591       *    assert(oldmask[i] && !newmask[i])
592       *    Depth test failed
593       * endif
594       */
595      for (i=0;i<n;i++) {
596         ASSERT(mask[i] == 0 || mask[i] == 1);
597         passmask[i] = oldmask[i] & mask[i];
598         failmask[i] = oldmask[i] & (mask[i] ^ 1);
599      }
600
601      /* apply the pass and fail operations */
602      if (ctx->Stencil.ZFailFunc != GL_KEEP) {
603         apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
604      }
605      if (ctx->Stencil.ZPassFunc != GL_KEEP) {
606         apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
607      }
608   }
609
610   return GL_TRUE;  /* one or more fragments passed both tests */
611}
612
613
614
615/*
616 * Apply stencil and depth testing to the span of pixels.
617 * Both software and hardware stencil buffers are acceptable.
618 * Input:  n - number of pixels in the span
619 *         x, y - location of leftmost pixel in span
620 *         z - array [n] of z values
621 *         mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
622 * Output:  mask - array [n] of flags (1=stencil and depth test passed)
623 * Return: GL_TRUE - all fragments failed the testing
624 *         GL_FALSE - one or more fragments passed the testing
625 *
626 */
627GLboolean
628_mesa_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
629                              const GLdepth z[], GLubyte mask[] )
630{
631   GLstencil stencilRow[MAX_WIDTH];
632   GLstencil *stencil;
633   GLboolean result;
634
635   ASSERT(ctx->Stencil.Enabled);
636   ASSERT(n <= MAX_WIDTH);
637
638   /* Get initial stencil values */
639   if (ctx->Driver.WriteStencilSpan) {
640      ASSERT(ctx->Driver.ReadStencilSpan);
641      /* Get stencil values from the hardware stencil buffer */
642      (*ctx->Driver.ReadStencilSpan)(ctx, n, x, y, stencilRow);
643      stencil = stencilRow;
644   }
645   else {
646      /* software stencil buffer */
647      stencil = STENCIL_ADDRESS(x, y);
648   }
649
650   /* do all the stencil/depth testing/updating */
651   result = stencil_and_ztest_span( ctx, n, x, y, z, stencil, mask );
652
653   if (ctx->Driver.WriteStencilSpan) {
654      /* Write updated stencil values into hardware stencil buffer */
655      (ctx->Driver.WriteStencilSpan)(ctx, n, x, y, stencil, mask );
656   }
657
658   return result;
659}
660
661
662
663
664/*
665 * Apply the given stencil operator for each pixel in the array whose
666 * mask flag is set.  This is for software stencil buffers only.
667 * Input:  n - number of pixels in the span
668 *         x, y - array of [n] pixels
669 *         operator - the stencil buffer operator
670 *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
671 */
672static void
673apply_stencil_op_to_pixels( const GLcontext *ctx,
674                            GLuint n, const GLint x[], const GLint y[],
675                            GLenum oper, const GLubyte mask[] )
676{
677   const GLstencil ref = ctx->Stencil.Ref;
678   const GLstencil wrtmask = ctx->Stencil.WriteMask;
679   const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
680   GLuint i;
681
682   ASSERT(!ctx->Driver.WriteStencilSpan);  /* software stencil buffer only! */
683
684   switch (oper) {
685      case GL_KEEP:
686         /* do nothing */
687         break;
688      case GL_ZERO:
689	 if (invmask==0) {
690	    for (i=0;i<n;i++) {
691	       if (mask[i]) {
692                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
693                  *sptr = 0;
694	       }
695	    }
696	 }
697	 else {
698	    for (i=0;i<n;i++) {
699	       if (mask[i]) {
700                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
701		  *sptr = (GLstencil) (invmask & *sptr);
702	       }
703	    }
704	 }
705	 break;
706      case GL_REPLACE:
707	 if (invmask==0) {
708	    for (i=0;i<n;i++) {
709	       if (mask[i]) {
710                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
711                  *sptr = ref;
712	       }
713	    }
714	 }
715	 else {
716	    for (i=0;i<n;i++) {
717	       if (mask[i]) {
718                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
719		  *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref));
720	       }
721	    }
722	 }
723	 break;
724      case GL_INCR:
725	 if (invmask==0) {
726	    for (i=0;i<n;i++) {
727	       if (mask[i]) {
728                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
729		  if (*sptr < STENCIL_MAX) {
730		     *sptr = (GLstencil) (*sptr + 1);
731		  }
732	       }
733	    }
734	 }
735	 else {
736	    for (i=0;i<n;i++) {
737	       if (mask[i]) {
738                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
739		  if (*sptr < STENCIL_MAX) {
740		     *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
741		  }
742	       }
743	    }
744	 }
745	 break;
746      case GL_DECR:
747	 if (invmask==0) {
748	    for (i=0;i<n;i++) {
749	       if (mask[i]) {
750                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
751		  if (*sptr>0) {
752		     *sptr = (GLstencil) (*sptr - 1);
753		  }
754	       }
755	    }
756	 }
757	 else {
758	    for (i=0;i<n;i++) {
759	       if (mask[i]) {
760                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
761		  if (*sptr>0) {
762		     *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
763		  }
764	       }
765	    }
766	 }
767	 break;
768      case GL_INCR_WRAP_EXT:
769	 if (invmask==0) {
770	    for (i=0;i<n;i++) {
771	       if (mask[i]) {
772                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
773                  *sptr = (GLstencil) (*sptr + 1);
774	       }
775	    }
776	 }
777	 else {
778	    for (i=0;i<n;i++) {
779	       if (mask[i]) {
780                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
781                  *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
782	       }
783	    }
784	 }
785	 break;
786      case GL_DECR_WRAP_EXT:
787	 if (invmask==0) {
788	    for (i=0;i<n;i++) {
789	       if (mask[i]) {
790                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
791                  *sptr = (GLstencil) (*sptr - 1);
792	       }
793	    }
794	 }
795	 else {
796	    for (i=0;i<n;i++) {
797	       if (mask[i]) {
798                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
799                  *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
800	       }
801	    }
802	 }
803	 break;
804      case GL_INVERT:
805	 if (invmask==0) {
806	    for (i=0;i<n;i++) {
807	       if (mask[i]) {
808                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
809                  *sptr = (GLstencil) (~*sptr);
810	       }
811	    }
812	 }
813	 else {
814	    for (i=0;i<n;i++) {
815	       if (mask[i]) {
816                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
817                  *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr));
818	       }
819	    }
820	 }
821	 break;
822      default:
823         gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
824   }
825}
826
827
828
829/*
830 * Apply stencil test to an array of pixels before depth buffering.
831 * Used for software stencil buffer only.
832 * Input:  n - number of pixels in the span
833 *         x, y - array of [n] pixels to stencil
834 *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
835 * Output:  mask - pixels which fail the stencil test will have their
836 *                 mask flag set to 0.
837 * Return:  0 = all pixels failed, 1 = zero or more pixels passed.
838 */
839static GLboolean
840stencil_test_pixels( GLcontext *ctx, GLuint n,
841                     const GLint x[], const GLint y[], GLubyte mask[] )
842{
843   GLubyte fail[PB_SIZE];
844   GLstencil r, s;
845   GLuint i;
846   GLboolean allfail = GL_FALSE;
847
848   ASSERT(!ctx->Driver.WriteStencilSpan);  /* software stencil buffer only! */
849
850   /*
851    * Perform stencil test.  The results of this operation are stored
852    * in the fail[] array:
853    *   IF fail[i] is non-zero THEN
854    *       the stencil fail operator is to be applied
855    *   ELSE
856    *       the stencil fail operator is not to be applied
857    *   ENDIF
858    */
859
860   switch (ctx->Stencil.Function) {
861      case GL_NEVER:
862         /* always fail */
863         for (i=0;i<n;i++) {
864	    if (mask[i]) {
865	       mask[i] = 0;
866	       fail[i] = 1;
867	    }
868	    else {
869	       fail[i] = 0;
870	    }
871	 }
872	 allfail = GL_TRUE;
873	 break;
874      case GL_LESS:
875	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
876	 for (i=0;i<n;i++) {
877	    if (mask[i]) {
878               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
879	       s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
880	       if (r < s) {
881		  /* passed */
882		  fail[i] = 0;
883	       }
884	       else {
885		  fail[i] = 1;
886		  mask[i] = 0;
887	       }
888	    }
889	    else {
890	       fail[i] = 0;
891	    }
892	 }
893	 break;
894      case GL_LEQUAL:
895	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
896	 for (i=0;i<n;i++) {
897	    if (mask[i]) {
898               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
899	       s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
900	       if (r <= s) {
901		  /* pass */
902		  fail[i] = 0;
903	       }
904	       else {
905		  fail[i] = 1;
906		  mask[i] = 0;
907	       }
908	    }
909	    else {
910	       fail[i] = 0;
911	    }
912	 }
913	 break;
914      case GL_GREATER:
915	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
916	 for (i=0;i<n;i++) {
917	    if (mask[i]) {
918               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
919	       s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
920	       if (r > s) {
921		  /* passed */
922		  fail[i] = 0;
923	       }
924	       else {
925		  fail[i] = 1;
926		  mask[i] = 0;
927	       }
928	    }
929	    else {
930	       fail[i] = 0;
931	    }
932	 }
933	 break;
934      case GL_GEQUAL:
935	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
936	 for (i=0;i<n;i++) {
937	    if (mask[i]) {
938               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
939	       s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
940	       if (r >= s) {
941		  /* passed */
942		  fail[i] = 0;
943	       }
944	       else {
945		  fail[i] = 1;
946		  mask[i] = 0;
947	       }
948	    }
949	    else {
950	       fail[i] = 0;
951	    }
952	 }
953	 break;
954      case GL_EQUAL:
955	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
956	 for (i=0;i<n;i++) {
957	    if (mask[i]) {
958               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
959	       s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
960	       if (r == s) {
961		  /* passed */
962		  fail[i] = 0;
963	       }
964	       else {
965		  fail[i] = 1;
966		  mask[i] = 0;
967	       }
968	    }
969	    else {
970	       fail[i] = 0;
971	    }
972	 }
973	 break;
974      case GL_NOTEQUAL:
975	 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
976	 for (i=0;i<n;i++) {
977	    if (mask[i]) {
978               GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
979	       s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
980	       if (r != s) {
981		  /* passed */
982		  fail[i] = 0;
983	       }
984	       else {
985		  fail[i] = 1;
986		  mask[i] = 0;
987	       }
988	    }
989	    else {
990	       fail[i] = 0;
991	    }
992	 }
993	 break;
994      case GL_ALWAYS:
995	 /* always pass */
996	 for (i=0;i<n;i++) {
997	    fail[i] = 0;
998	 }
999	 break;
1000      default:
1001         gl_problem(ctx, "Bad stencil func in gl_stencil_pixels");
1002         return 0;
1003   }
1004
1005   if (ctx->Stencil.FailFunc != GL_KEEP) {
1006      apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
1007   }
1008
1009   return !allfail;
1010}
1011
1012
1013
1014
1015/*
1016 * Apply stencil and depth testing to an array of pixels.
1017 * This is used both for software and hardware stencil buffers.
1018 *
1019 * The comments in this function are a bit sparse but the code is
1020 * almost identical to stencil_and_ztest_span(), which is well
1021 * commented.
1022 *
1023 * Input:  n - number of pixels in the array
1024 *         x, y - array of [n] pixel positions
1025 *         z - array [n] of z values
1026 *         mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
1027 * Output: mask - array [n] of flags (1=stencil and depth test passed)
1028 * Return: GL_TRUE - all fragments failed the testing
1029 *         GL_FALSE - one or more fragments passed the testing
1030 */
1031GLboolean
1032_mesa_stencil_and_ztest_pixels( GLcontext *ctx,
1033                                GLuint n, const GLint x[], const GLint y[],
1034                                const GLdepth z[], GLubyte mask[] )
1035{
1036   ASSERT(ctx->Stencil.Enabled);
1037   ASSERT(n <= PB_SIZE);
1038
1039   if (ctx->Driver.WriteStencilPixels) {
1040      /*** Hardware stencil buffer ***/
1041      GLstencil stencil[PB_SIZE];
1042      GLubyte mask[PB_SIZE];
1043
1044      ASSERT(ctx->Driver.ReadStencilPixels);
1045      (*ctx->Driver.ReadStencilPixels)(ctx, n, x, y, stencil);
1046
1047
1048      if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) {
1049         /* all fragments failed the stencil test, we're done. */
1050         return GL_FALSE;
1051      }
1052
1053      if (ctx->Depth.Test == GL_FALSE) {
1054         apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
1055      }
1056      else {
1057         GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
1058         GLuint i;
1059
1060         MEMCPY(oldmask, mask, n * sizeof(GLubyte));
1061
1062         _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
1063
1064         for (i=0;i<n;i++) {
1065            ASSERT(mask[i] == 0 || mask[i] == 1);
1066            passmask[i] = oldmask[i] & mask[i];
1067            failmask[i] = oldmask[i] & (mask[i] ^ 1);
1068         }
1069
1070         if (ctx->Stencil.ZFailFunc != GL_KEEP) {
1071            apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
1072         }
1073         if (ctx->Stencil.ZPassFunc != GL_KEEP) {
1074            apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
1075         }
1076      }
1077
1078      /* Write updated stencil values into hardware stencil buffer */
1079      (ctx->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, mask );
1080
1081      return GL_TRUE;
1082
1083   }
1084   else {
1085      /*** Software stencil buffer ***/
1086
1087      if (stencil_test_pixels(ctx, n, x, y, mask) == GL_FALSE) {
1088         /* all fragments failed the stencil test, we're done. */
1089         return GL_FALSE;
1090      }
1091
1092
1093      if (ctx->Depth.Test==GL_FALSE) {
1094         apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
1095      }
1096      else {
1097         GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
1098         GLuint i;
1099
1100         MEMCPY(oldmask, mask, n * sizeof(GLubyte));
1101
1102         _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
1103
1104         for (i=0;i<n;i++) {
1105            ASSERT(mask[i] == 0 || mask[i] == 1);
1106            passmask[i] = oldmask[i] & mask[i];
1107            failmask[i] = oldmask[i] & (mask[i] ^ 1);
1108         }
1109
1110         if (ctx->Stencil.ZFailFunc != GL_KEEP) {
1111            apply_stencil_op_to_pixels( ctx, n, x, y,
1112                                        ctx->Stencil.ZFailFunc, failmask );
1113         }
1114         if (ctx->Stencil.ZPassFunc != GL_KEEP) {
1115            apply_stencil_op_to_pixels( ctx, n, x, y,
1116                                        ctx->Stencil.ZPassFunc, passmask );
1117         }
1118      }
1119
1120      return GL_TRUE;  /* one or more fragments passed both tests */
1121   }
1122}
1123
1124
1125
1126/*
1127 * Return a span of stencil values from the stencil buffer.
1128 * Used for glRead/CopyPixels
1129 * Input:  n - how many pixels
1130 *         x,y - location of first pixel
1131 * Output:  stencil - the array of stencil values
1132 */
1133void
1134_mesa_read_stencil_span( GLcontext *ctx,
1135                         GLint n, GLint x, GLint y, GLstencil stencil[] )
1136{
1137   if (y < 0 || y >= ctx->DrawBuffer->Height ||
1138       x + n <= 0 || x >= ctx->DrawBuffer->Width) {
1139      /* span is completely outside framebuffer */
1140      return; /* undefined values OK */
1141   }
1142
1143   if (x < 0) {
1144      GLint dx = -x;
1145      x = 0;
1146      n -= dx;
1147      stencil += dx;
1148   }
1149   if (x + n > ctx->DrawBuffer->Width) {
1150      GLint dx = x + n - ctx->DrawBuffer->Width;
1151      n -= dx;
1152   }
1153   if (n <= 0) {
1154      return;
1155   }
1156
1157
1158   ASSERT(n >= 0);
1159   if (ctx->Driver.ReadStencilSpan) {
1160      (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil );
1161   }
1162   else if (ctx->DrawBuffer->Stencil) {
1163      const GLstencil *s = STENCIL_ADDRESS( x, y );
1164#if STENCIL_BITS == 8
1165      MEMCPY( stencil, s, n * sizeof(GLstencil) );
1166#else
1167      GLuint i;
1168      for (i=0;i<n;i++)
1169         stencil[i] = s[i];
1170#endif
1171   }
1172}
1173
1174
1175
1176/*
1177 * Write a span of stencil values to the stencil buffer.
1178 * Used for glDraw/CopyPixels
1179 * Input:  n - how many pixels
1180 *         x, y - location of first pixel
1181 *         stencil - the array of stencil values
1182 */
1183void
1184_mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
1185                          const GLstencil stencil[] )
1186{
1187   if (y < 0 || y >= ctx->DrawBuffer->Height ||
1188       x + n <= 0 || x >= ctx->DrawBuffer->Width) {
1189      /* span is completely outside framebuffer */
1190      return; /* undefined values OK */
1191   }
1192
1193   if (x < 0) {
1194      GLint dx = -x;
1195      x = 0;
1196      n -= dx;
1197      stencil += dx;
1198   }
1199   if (x + n > ctx->DrawBuffer->Width) {
1200      GLint dx = x + n - ctx->DrawBuffer->Width;
1201      n -= dx;
1202   }
1203   if (n <= 0) {
1204      return;
1205   }
1206
1207   if (ctx->Driver.WriteStencilSpan) {
1208      (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL );
1209   }
1210   else if (ctx->DrawBuffer->Stencil) {
1211      GLstencil *s = STENCIL_ADDRESS( x, y );
1212#if STENCIL_BITS == 8
1213      MEMCPY( s, stencil, n * sizeof(GLstencil) );
1214#else
1215      GLuint i;
1216      for (i=0;i<n;i++)
1217         s[i] = stencil[i];
1218#endif
1219   }
1220}
1221
1222
1223
1224/*
1225 * Allocate a new stencil buffer.  If there's an old one it will be
1226 * deallocated first.  The new stencil buffer will be uninitialized.
1227 */
1228void
1229_mesa_alloc_stencil_buffer( GLcontext *ctx )
1230{
1231   GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1232
1233   /* deallocate current stencil buffer if present */
1234   if (ctx->DrawBuffer->Stencil) {
1235      FREE(ctx->DrawBuffer->Stencil);
1236      ctx->DrawBuffer->Stencil = NULL;
1237   }
1238
1239   /* allocate new stencil buffer */
1240   ctx->DrawBuffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil));
1241   if (!ctx->DrawBuffer->Stencil) {
1242      /* out of memory */
1243      _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE );
1244      gl_error( ctx, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" );
1245   }
1246}
1247
1248
1249
1250/*
1251 * Clear the software (malloc'd) stencil buffer.
1252 */
1253static void
1254clear_software_stencil_buffer( GLcontext *ctx )
1255{
1256   if (ctx->Visual->StencilBits==0 || !ctx->DrawBuffer->Stencil) {
1257      /* no stencil buffer */
1258      return;
1259   }
1260
1261   if (ctx->Scissor.Enabled) {
1262      /* clear scissor region only */
1263      const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
1264      if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1265         /* must apply mask to the clear */
1266         GLint y;
1267         for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1268            const GLstencil mask = ctx->Stencil.WriteMask;
1269            const GLstencil invMask = ~mask;
1270            const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1271            GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
1272            GLint i;
1273            for (i = 0; i < width; i++) {
1274               stencil[i] = (stencil[i] & invMask) | clearVal;
1275            }
1276         }
1277      }
1278      else {
1279         /* no masking */
1280         GLint y;
1281         for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1282            GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
1283#if STENCIL_BITS==8
1284            MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) );
1285#else
1286            GLint i;
1287            for (i = 0; i < width; i++)
1288               stencil[x] = ctx->Stencil.Clear;
1289#endif
1290         }
1291      }
1292   }
1293   else {
1294      /* clear whole stencil buffer */
1295      if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1296         /* must apply mask to the clear */
1297         const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1298         GLstencil *stencil = ctx->DrawBuffer->Stencil;
1299         const GLstencil mask = ctx->Stencil.WriteMask;
1300         const GLstencil invMask = ~mask;
1301         const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1302         GLuint i;
1303         for (i = 0; i < n; i++) {
1304            stencil[i] = (stencil[i] & invMask) | clearVal;
1305         }
1306      }
1307      else {
1308         /* clear whole buffer without masking */
1309         const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
1310         GLstencil *stencil = ctx->DrawBuffer->Stencil;
1311
1312#if STENCIL_BITS==8
1313         MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) );
1314#else
1315         GLuint i;
1316         for (i = 0; i < n; i++) {
1317            stencil[i] = ctx->Stencil.Clear;
1318         }
1319#endif
1320      }
1321   }
1322}
1323
1324
1325
1326/*
1327 * Clear the hardware (in graphics card) stencil buffer.
1328 * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
1329 * functions.
1330 * Actually, if there is a hardware stencil buffer it really should have
1331 * been cleared in Driver.Clear()!  However, if the hardware does not
1332 * support scissored clears or masked clears (i.e. glStencilMask) then
1333 * we have to use the span-based functions.
1334 */
1335static void
1336clear_hardware_stencil_buffer( GLcontext *ctx )
1337{
1338   ASSERT(ctx->Driver.WriteStencilSpan);
1339   ASSERT(ctx->Driver.ReadStencilSpan);
1340
1341   if (ctx->Scissor.Enabled) {
1342      /* clear scissor region only */
1343      const GLint x = ctx->DrawBuffer->Xmin;
1344      const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
1345      if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1346         /* must apply mask to the clear */
1347         GLint y;
1348         for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1349            const GLstencil mask = ctx->Stencil.WriteMask;
1350            const GLstencil invMask = ~mask;
1351            const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1352            GLstencil stencil[MAX_WIDTH];
1353            GLint i;
1354            (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
1355            for (i = 0; i < width; i++) {
1356               stencil[i] = (stencil[i] & invMask) | clearVal;
1357            }
1358            (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1359         }
1360      }
1361      else {
1362         /* no masking */
1363         GLstencil stencil[MAX_WIDTH];
1364         GLint y, i;
1365         for (i = 0; i < width; i++) {
1366            stencil[i] = ctx->Stencil.Clear;
1367         }
1368         for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
1369            (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1370         }
1371      }
1372   }
1373   else {
1374      /* clear whole stencil buffer */
1375      if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1376         /* must apply mask to the clear */
1377         const GLstencil mask = ctx->Stencil.WriteMask;
1378         const GLstencil invMask = ~mask;
1379         const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1380         const GLint width = ctx->DrawBuffer->Width;
1381         const GLint height = ctx->DrawBuffer->Height;
1382         const GLint x = ctx->DrawBuffer->Xmin;
1383         GLint y;
1384         for (y = 0; y < height; y++) {
1385            GLstencil stencil[MAX_WIDTH];
1386            GLuint i;
1387            (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
1388            for (i = 0; i < width; i++) {
1389               stencil[i] = (stencil[i] & invMask) | clearVal;
1390            }
1391            (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1392         }
1393      }
1394      else {
1395         /* clear whole buffer without masking */
1396         const GLint width = ctx->DrawBuffer->Width;
1397         const GLint height = ctx->DrawBuffer->Width;
1398         const GLint x = ctx->DrawBuffer->Xmin;
1399         GLstencil stencil[MAX_WIDTH];
1400         GLint y, i;
1401         for (i = 0; i < width; i++) {
1402            stencil[i] = ctx->Stencil.Clear;
1403         }
1404         for (y = 0; y < height; y++) {
1405            (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
1406         }
1407      }
1408   }
1409}
1410
1411
1412
1413/*
1414 * Clear the stencil buffer.
1415 */
1416void
1417_mesa_clear_stencil_buffer( GLcontext *ctx )
1418{
1419   if (ctx->Driver.WriteStencilSpan) {
1420      ASSERT(ctx->Driver.ReadStencilSpan);
1421      clear_hardware_stencil_buffer(ctx);
1422   }
1423   else {
1424      clear_software_stencil_buffer(ctx);
1425   }
1426}
1427
1428