Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 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
 
30
#include "s_context.h"
31
#include "s_depth.h"
32
#include "s_stencil.h"
33
#include "s_span.h"
34
 
35
 
36
 
37
/* Stencil Logic:
38
 
39
IF stencil test fails THEN
40
   Apply fail-op to stencil value
41
   Don't write the pixel (RGBA,Z)
42
ELSE
43
   IF doing depth test && depth test fails THEN
44
      Apply zfail-op to stencil value
45
      Write RGBA and Z to appropriate buffers
46
   ELSE
47
      Apply zpass-op to stencil value
48
ENDIF
49
 
50
*/
51
 
52
 
53
/**
54
 * Apply the given stencil operator to the array of stencil values.
55
 * Don't touch stencil[i] if mask[i] is zero.
56
 * Input:  n - size of stencil array
57
 *         oper - the stencil buffer operator
58
 *         face - 0 or 1 for front or back face operation
59
 *         stencil - array of stencil values
60
 *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
61
 * Output:  stencil - modified values
62
 */
63
static void
64
apply_stencil_op( const struct gl_context *ctx, GLenum oper, GLuint face,
65
                  GLuint n, GLstencil stencil[], const GLubyte mask[] )
66
{
67
   const GLstencil ref = ctx->Stencil.Ref[face];
68
   const GLstencil wrtmask = ctx->Stencil.WriteMask[face];
69
   const GLstencil invmask = (GLstencil) (~wrtmask);
70
   const GLstencil stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
71
   GLuint i;
72
 
73
   switch (oper) {
74
      case GL_KEEP:
75
         /* do nothing */
76
         break;
77
      case GL_ZERO:
78
	 if (invmask==0) {
79
	    for (i=0;i
80
	       if (mask[i]) {
81
		  stencil[i] = 0;
82
	       }
83
	    }
84
	 }
85
	 else {
86
	    for (i=0;i
87
	       if (mask[i]) {
88
		  stencil[i] = (GLstencil) (stencil[i] & invmask);
89
	       }
90
	    }
91
	 }
92
	 break;
93
      case GL_REPLACE:
94
	 if (invmask==0) {
95
	    for (i=0;i
96
	       if (mask[i]) {
97
                  stencil[i] = ref;
98
	       }
99
	    }
100
	 }
101
	 else {
102
	    for (i=0;i
103
	       if (mask[i]) {
104
		  GLstencil s = stencil[i];
105
		  stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref));
106
	       }
107
	    }
108
	 }
109
	 break;
110
      case GL_INCR:
111
	 if (invmask==0) {
112
	    for (i=0;i
113
	       if (mask[i]) {
114
		  GLstencil s = stencil[i];
115
		  if (s < stencilMax) {
116
		     stencil[i] = (GLstencil) (s+1);
117
		  }
118
	       }
119
	    }
120
	 }
121
	 else {
122
	    for (i=0;i
123
	       if (mask[i]) {
124
		  /* VERIFY logic of adding 1 to a write-masked value */
125
		  GLstencil s = stencil[i];
126
		  if (s < stencilMax) {
127
		     stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
128
		  }
129
	       }
130
	    }
131
	 }
132
	 break;
133
      case GL_DECR:
134
	 if (invmask==0) {
135
	    for (i=0;i
136
	       if (mask[i]) {
137
		  GLstencil s = stencil[i];
138
		  if (s>0) {
139
		     stencil[i] = (GLstencil) (s-1);
140
		  }
141
	       }
142
	    }
143
	 }
144
	 else {
145
	    for (i=0;i
146
	       if (mask[i]) {
147
		  /* VERIFY logic of subtracting 1 to a write-masked value */
148
		  GLstencil s = stencil[i];
149
		  if (s>0) {
150
		     stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
151
		  }
152
	       }
153
	    }
154
	 }
155
	 break;
156
      case GL_INCR_WRAP_EXT:
157
	 if (invmask==0) {
158
	    for (i=0;i
159
	       if (mask[i]) {
160
                  stencil[i]++;
161
	       }
162
	    }
163
	 }
164
	 else {
165
	    for (i=0;i
166
	       if (mask[i]) {
167
                  GLstencil s = stencil[i];
168
                  stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
169
	       }
170
	    }
171
	 }
172
	 break;
173
      case GL_DECR_WRAP_EXT:
174
	 if (invmask==0) {
175
	    for (i=0;i
176
	       if (mask[i]) {
177
		  stencil[i]--;
178
	       }
179
	    }
180
	 }
181
	 else {
182
	    for (i=0;i
183
	       if (mask[i]) {
184
                  GLstencil s = stencil[i];
185
                  stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
186
	       }
187
	    }
188
	 }
189
	 break;
190
      case GL_INVERT:
191
	 if (invmask==0) {
192
	    for (i=0;i
193
	       if (mask[i]) {
194
		  GLstencil s = stencil[i];
195
		  stencil[i] = (GLstencil) ~s;
196
	       }
197
	    }
198
	 }
199
	 else {
200
	    for (i=0;i
201
	       if (mask[i]) {
202
		  GLstencil s = stencil[i];
203
		  stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s));
204
	       }
205
	    }
206
	 }
207
	 break;
208
      default:
209
         _mesa_problem(ctx, "Bad stencil op in apply_stencil_op");
210
   }
211
}
212
 
213
 
214
 
215
 
216
/**
217
 * Apply stencil test to an array of stencil values (before depth buffering).
218
 * Input:  face - 0 or 1 for front or back-face polygons
219
 *         n - number of pixels in the array
220
 *         stencil - array of [n] stencil values
221
 *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
222
 * Output:  mask - pixels which fail the stencil test will have their
223
 *                 mask flag set to 0.
224
 *          stencil - updated stencil values (where the test passed)
225
 * Return:  GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
226
 */
227
static GLboolean
228
do_stencil_test( struct gl_context *ctx, GLuint face, GLuint n, GLstencil stencil[],
229
                 GLubyte mask[] )
230
{
231
   GLubyte fail[MAX_WIDTH];
232
   GLboolean allfail = GL_FALSE;
233
   GLuint i;
234
   const GLuint valueMask = ctx->Stencil.ValueMask[face];
235
   const GLstencil r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
236
   GLstencil s;
237
 
238
   ASSERT(n <= MAX_WIDTH);
239
 
240
   /*
241
    * Perform stencil test.  The results of this operation are stored
242
    * in the fail[] array:
243
    *   IF fail[i] is non-zero THEN
244
    *       the stencil fail operator is to be applied
245
    *   ELSE
246
    *       the stencil fail operator is not to be applied
247
    *   ENDIF
248
    */
249
   switch (ctx->Stencil.Function[face]) {
250
      case GL_NEVER:
251
         /* never pass; always fail */
252
         for (i=0;i
253
	    if (mask[i]) {
254
	       mask[i] = 0;
255
	       fail[i] = 1;
256
	    }
257
	    else {
258
	       fail[i] = 0;
259
	    }
260
	 }
261
	 allfail = GL_TRUE;
262
	 break;
263
      case GL_LESS:
264
	 for (i=0;i
265
	    if (mask[i]) {
266
	       s = (GLstencil) (stencil[i] & valueMask);
267
	       if (r < s) {
268
		  /* passed */
269
		  fail[i] = 0;
270
	       }
271
	       else {
272
		  fail[i] = 1;
273
		  mask[i] = 0;
274
	       }
275
	    }
276
	    else {
277
	       fail[i] = 0;
278
	    }
279
	 }
280
	 break;
281
      case GL_LEQUAL:
282
	 for (i=0;i
283
	    if (mask[i]) {
284
	       s = (GLstencil) (stencil[i] & valueMask);
285
	       if (r <= s) {
286
		  /* pass */
287
		  fail[i] = 0;
288
	       }
289
	       else {
290
		  fail[i] = 1;
291
		  mask[i] = 0;
292
	       }
293
	    }
294
	    else {
295
	       fail[i] = 0;
296
	    }
297
	 }
298
	 break;
299
      case GL_GREATER:
300
	 for (i=0;i
301
	    if (mask[i]) {
302
	       s = (GLstencil) (stencil[i] & valueMask);
303
	       if (r > s) {
304
		  /* passed */
305
		  fail[i] = 0;
306
	       }
307
	       else {
308
		  fail[i] = 1;
309
		  mask[i] = 0;
310
	       }
311
	    }
312
	    else {
313
	       fail[i] = 0;
314
	    }
315
	 }
316
	 break;
317
      case GL_GEQUAL:
318
	 for (i=0;i
319
	    if (mask[i]) {
320
	       s = (GLstencil) (stencil[i] & valueMask);
321
	       if (r >= s) {
322
		  /* passed */
323
		  fail[i] = 0;
324
	       }
325
	       else {
326
		  fail[i] = 1;
327
		  mask[i] = 0;
328
	       }
329
	    }
330
	    else {
331
	       fail[i] = 0;
332
	    }
333
	 }
334
	 break;
335
      case GL_EQUAL:
336
	 for (i=0;i
337
	    if (mask[i]) {
338
	       s = (GLstencil) (stencil[i] & valueMask);
339
	       if (r == s) {
340
		  /* passed */
341
		  fail[i] = 0;
342
	       }
343
	       else {
344
		  fail[i] = 1;
345
		  mask[i] = 0;
346
	       }
347
	    }
348
	    else {
349
	       fail[i] = 0;
350
	    }
351
	 }
352
	 break;
353
      case GL_NOTEQUAL:
354
	 for (i=0;i
355
	    if (mask[i]) {
356
	       s = (GLstencil) (stencil[i] & valueMask);
357
	       if (r != s) {
358
		  /* passed */
359
		  fail[i] = 0;
360
	       }
361
	       else {
362
		  fail[i] = 1;
363
		  mask[i] = 0;
364
	       }
365
	    }
366
	    else {
367
	       fail[i] = 0;
368
	    }
369
	 }
370
	 break;
371
      case GL_ALWAYS:
372
	 /* always pass */
373
	 for (i=0;i
374
	    fail[i] = 0;
375
	 }
376
	 break;
377
      default:
378
         _mesa_problem(ctx, "Bad stencil func in gl_stencil_span");
379
         return 0;
380
   }
381
 
382
   if (ctx->Stencil.FailFunc[face] != GL_KEEP) {
383
      apply_stencil_op( ctx, ctx->Stencil.FailFunc[face], face, n, stencil, fail );
384
   }
385
 
386
   return !allfail;
387
}
388
 
389
 
390
/**
391
 * Compute the zpass/zfail masks by comparing the pre- and post-depth test
392
 * masks.
393
 */
394
static INLINE void
395
compute_pass_fail_masks(GLuint n, const GLubyte origMask[],
396
                        const GLubyte newMask[],
397
                        GLubyte passMask[], GLubyte failMask[])
398
{
399
   GLuint i;
400
   for (i = 0; i < n; i++) {
401
      ASSERT(newMask[i] == 0 || newMask[i] == 1);
402
      passMask[i] = origMask[i] & newMask[i];
403
      failMask[i] = origMask[i] & (newMask[i] ^ 1);
404
   }
405
}
406
 
407
 
408
/**
409
 * Apply stencil and depth testing to the span of pixels.
410
 * Both software and hardware stencil buffers are acceptable.
411
 * Input:  n - number of pixels in the span
412
 *         x, y - location of leftmost pixel in span
413
 *         z - array [n] of z values
414
 *         mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
415
 * Output:  mask - array [n] of flags (1=stencil and depth test passed)
416
 * Return: GL_FALSE - all fragments failed the testing
417
 *         GL_TRUE - one or more fragments passed the testing
418
 *
419
 */
420
static GLboolean
421
stencil_and_ztest_span(struct gl_context *ctx, SWspan *span, GLuint face)
422
{
423
   struct gl_framebuffer *fb = ctx->DrawBuffer;
424
   struct gl_renderbuffer *rb = fb->_StencilBuffer;
425
   GLstencil stencilRow[MAX_WIDTH];
426
   GLstencil *stencil;
427
   const GLuint n = span->end;
428
   const GLint x = span->x;
429
   const GLint y = span->y;
430
   GLubyte *mask = span->array->mask;
431
 
432
   ASSERT((span->arrayMask & SPAN_XY) == 0);
433
   ASSERT(ctx->Stencil.Enabled);
434
   ASSERT(n <= MAX_WIDTH);
435
#ifdef DEBUG
436
   if (ctx->Depth.Test) {
437
      ASSERT(span->arrayMask & SPAN_Z);
438
   }
439
#endif
440
 
441
   stencil = (GLstencil *) rb->GetPointer(ctx, rb, x, y);
442
   if (!stencil) {
443
      rb->GetRow(ctx, rb, n, x, y, stencilRow);
444
      stencil = stencilRow;
445
   }
446
 
447
   /*
448
    * Apply the stencil test to the fragments.
449
    * failMask[i] is 1 if the stencil test failed.
450
    */
451
   if (do_stencil_test( ctx, face, n, stencil, mask ) == GL_FALSE) {
452
      /* all fragments failed the stencil test, we're done. */
453
      span->writeAll = GL_FALSE;
454
      if (!rb->GetPointer(ctx, rb, 0, 0)) {
455
         /* put updated stencil values into buffer */
456
         rb->PutRow(ctx, rb, n, x, y, stencil, NULL);
457
      }
458
      return GL_FALSE;
459
   }
460
 
461
   /*
462
    * Some fragments passed the stencil test, apply depth test to them
463
    * and apply Zpass and Zfail stencil ops.
464
    */
465
   if (ctx->Depth.Test == GL_FALSE) {
466
      /*
467
       * No depth buffer, just apply zpass stencil function to active pixels.
468
       */
469
      apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face, n, stencil, mask );
470
   }
471
   else {
472
      /*
473
       * Perform depth buffering, then apply zpass or zfail stencil function.
474
       */
475
      GLubyte passMask[MAX_WIDTH], failMask[MAX_WIDTH], origMask[MAX_WIDTH];
476
 
477
      /* save the current mask bits */
478
      memcpy(origMask, mask, n * sizeof(GLubyte));
479
 
480
      /* apply the depth test */
481
      _swrast_depth_test_span(ctx, span);
482
 
483
      compute_pass_fail_masks(n, origMask, mask, passMask, failMask);
484
 
485
      /* apply the pass and fail operations */
486
      if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) {
487
         apply_stencil_op( ctx, ctx->Stencil.ZFailFunc[face], face,
488
                           n, stencil, failMask );
489
      }
490
      if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) {
491
         apply_stencil_op( ctx, ctx->Stencil.ZPassFunc[face], face,
492
                           n, stencil, passMask );
493
      }
494
   }
495
 
496
   /*
497
    * Write updated stencil values back into hardware stencil buffer.
498
    */
499
   if (!rb->GetPointer(ctx, rb, 0, 0)) {
500
      rb->PutRow(ctx, rb, n, x, y, stencil, NULL);
501
   }
502
 
503
   span->writeAll = GL_FALSE;
504
 
505
   return GL_TRUE;  /* one or more fragments passed both tests */
506
}
507
 
508
 
509
 
510
/*
511
 * Return the address of a stencil buffer value given the window coords:
512
 */
513
#define STENCIL_ADDRESS(X, Y)  (stencilStart + (Y) * stride + (X))
514
 
515
 
516
 
517
/**
518
 * Apply the given stencil operator for each pixel in the array whose
519
 * mask flag is set.
520
 * \note  This is for software stencil buffers only.
521
 * Input:  n - number of pixels in the span
522
 *         x, y - array of [n] pixels
523
 *         operator - the stencil buffer operator
524
 *         mask - array [n] of flag:  1=apply operator, 0=don't apply operator
525
 */
526
static void
527
apply_stencil_op_to_pixels( struct gl_context *ctx,
528
                            GLuint n, const GLint x[], const GLint y[],
529
                            GLenum oper, GLuint face, const GLubyte mask[] )
530
{
531
   struct gl_framebuffer *fb = ctx->DrawBuffer;
532
   struct gl_renderbuffer *rb = fb->_StencilBuffer;
533
   const GLstencil stencilMax = (1 << fb->Visual.stencilBits) - 1;
534
   const GLstencil ref = ctx->Stencil.Ref[face];
535
   const GLstencil wrtmask = ctx->Stencil.WriteMask[face];
536
   const GLstencil invmask = (GLstencil) (~wrtmask);
537
   GLuint i;
538
   GLstencil *stencilStart = (GLubyte *) rb->Data;
539
   const GLuint stride = rb->Width;
540
 
541
   ASSERT(rb->GetPointer(ctx, rb, 0, 0));
542
   ASSERT(sizeof(GLstencil) == 1);
543
 
544
   switch (oper) {
545
      case GL_KEEP:
546
         /* do nothing */
547
         break;
548
      case GL_ZERO:
549
	 if (invmask==0) {
550
	    for (i=0;i
551
	       if (mask[i]) {
552
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
553
                  *sptr = 0;
554
	       }
555
	    }
556
	 }
557
	 else {
558
	    for (i=0;i
559
	       if (mask[i]) {
560
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
561
		  *sptr = (GLstencil) (invmask & *sptr);
562
	       }
563
	    }
564
	 }
565
	 break;
566
      case GL_REPLACE:
567
	 if (invmask==0) {
568
	    for (i=0;i
569
	       if (mask[i]) {
570
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
571
                  *sptr = ref;
572
	       }
573
	    }
574
	 }
575
	 else {
576
	    for (i=0;i
577
	       if (mask[i]) {
578
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
579
		  *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref));
580
	       }
581
	    }
582
	 }
583
	 break;
584
      case GL_INCR:
585
	 if (invmask==0) {
586
	    for (i=0;i
587
	       if (mask[i]) {
588
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
589
		  if (*sptr < stencilMax) {
590
		     *sptr = (GLstencil) (*sptr + 1);
591
		  }
592
	       }
593
	    }
594
	 }
595
	 else {
596
	    for (i=0;i
597
	       if (mask[i]) {
598
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
599
		  if (*sptr < stencilMax) {
600
		     *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
601
		  }
602
	       }
603
	    }
604
	 }
605
	 break;
606
      case GL_DECR:
607
	 if (invmask==0) {
608
	    for (i=0;i
609
	       if (mask[i]) {
610
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
611
		  if (*sptr>0) {
612
		     *sptr = (GLstencil) (*sptr - 1);
613
		  }
614
	       }
615
	    }
616
	 }
617
	 else {
618
	    for (i=0;i
619
	       if (mask[i]) {
620
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
621
		  if (*sptr>0) {
622
		     *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
623
		  }
624
	       }
625
	    }
626
	 }
627
	 break;
628
      case GL_INCR_WRAP_EXT:
629
	 if (invmask==0) {
630
	    for (i=0;i
631
	       if (mask[i]) {
632
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
633
                  *sptr = (GLstencil) (*sptr + 1);
634
	       }
635
	    }
636
	 }
637
	 else {
638
	    for (i=0;i
639
	       if (mask[i]) {
640
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
641
                  *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
642
	       }
643
	    }
644
	 }
645
	 break;
646
      case GL_DECR_WRAP_EXT:
647
	 if (invmask==0) {
648
	    for (i=0;i
649
	       if (mask[i]) {
650
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
651
                  *sptr = (GLstencil) (*sptr - 1);
652
	       }
653
	    }
654
	 }
655
	 else {
656
	    for (i=0;i
657
	       if (mask[i]) {
658
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
659
                  *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
660
	       }
661
	    }
662
	 }
663
	 break;
664
      case GL_INVERT:
665
	 if (invmask==0) {
666
	    for (i=0;i
667
	       if (mask[i]) {
668
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
669
                  *sptr = (GLstencil) (~*sptr);
670
	       }
671
	    }
672
	 }
673
	 else {
674
	    for (i=0;i
675
	       if (mask[i]) {
676
                  GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
677
                  *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr));
678
	       }
679
	    }
680
	 }
681
	 break;
682
      default:
683
         _mesa_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
684
   }
685
}
686
 
687
 
688
 
689
/**
690
 * Apply stencil test to an array of pixels before depth buffering.
691
 *
692
 * \note Used for software stencil buffer only.
693
 * Input:  n - number of pixels in the span
694
 *         x, y - array of [n] pixels to stencil
695
 *         mask - array [n] of flag:  0=skip the pixel, 1=stencil the pixel
696
 * Output:  mask - pixels which fail the stencil test will have their
697
 *                 mask flag set to 0.
698
 * \return  GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
699
 */
700
static GLboolean
701
stencil_test_pixels( struct gl_context *ctx, GLuint face, GLuint n,
702
                     const GLint x[], const GLint y[], GLubyte mask[] )
703
{
704
   const struct gl_framebuffer *fb = ctx->DrawBuffer;
705
   struct gl_renderbuffer *rb = fb->_StencilBuffer;
706
   GLubyte fail[MAX_WIDTH];
707
   GLstencil r, s;
708
   GLuint i;
709
   GLboolean allfail = GL_FALSE;
710
   const GLuint valueMask = ctx->Stencil.ValueMask[face];
711
   const GLstencil *stencilStart = (GLstencil *) rb->Data;
712
   const GLuint stride = rb->Width;
713
 
714
   ASSERT(rb->GetPointer(ctx, rb, 0, 0));
715
   ASSERT(sizeof(GLstencil) == 1);
716
 
717
   /*
718
    * Perform stencil test.  The results of this operation are stored
719
    * in the fail[] array:
720
    *   IF fail[i] is non-zero THEN
721
    *       the stencil fail operator is to be applied
722
    *   ELSE
723
    *       the stencil fail operator is not to be applied
724
    *   ENDIF
725
    */
726
 
727
   switch (ctx->Stencil.Function[face]) {
728
      case GL_NEVER:
729
         /* always fail */
730
         for (i=0;i
731
	    if (mask[i]) {
732
	       mask[i] = 0;
733
	       fail[i] = 1;
734
	    }
735
	    else {
736
	       fail[i] = 0;
737
	    }
738
	 }
739
	 allfail = GL_TRUE;
740
	 break;
741
      case GL_LESS:
742
	 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
743
	 for (i=0;i
744
	    if (mask[i]) {
745
               const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
746
	       s = (GLstencil) (*sptr & valueMask);
747
	       if (r < s) {
748
		  /* passed */
749
		  fail[i] = 0;
750
	       }
751
	       else {
752
		  fail[i] = 1;
753
		  mask[i] = 0;
754
	       }
755
	    }
756
	    else {
757
	       fail[i] = 0;
758
	    }
759
	 }
760
	 break;
761
      case GL_LEQUAL:
762
	 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
763
	 for (i=0;i
764
	    if (mask[i]) {
765
               const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
766
	       s = (GLstencil) (*sptr & valueMask);
767
	       if (r <= s) {
768
		  /* pass */
769
		  fail[i] = 0;
770
	       }
771
	       else {
772
		  fail[i] = 1;
773
		  mask[i] = 0;
774
	       }
775
	    }
776
	    else {
777
	       fail[i] = 0;
778
	    }
779
	 }
780
	 break;
781
      case GL_GREATER:
782
	 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
783
	 for (i=0;i
784
	    if (mask[i]) {
785
               const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
786
	       s = (GLstencil) (*sptr & valueMask);
787
	       if (r > s) {
788
		  /* passed */
789
		  fail[i] = 0;
790
	       }
791
	       else {
792
		  fail[i] = 1;
793
		  mask[i] = 0;
794
	       }
795
	    }
796
	    else {
797
	       fail[i] = 0;
798
	    }
799
	 }
800
	 break;
801
      case GL_GEQUAL:
802
	 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
803
	 for (i=0;i
804
	    if (mask[i]) {
805
               const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
806
	       s = (GLstencil) (*sptr & valueMask);
807
	       if (r >= s) {
808
		  /* passed */
809
		  fail[i] = 0;
810
	       }
811
	       else {
812
		  fail[i] = 1;
813
		  mask[i] = 0;
814
	       }
815
	    }
816
	    else {
817
	       fail[i] = 0;
818
	    }
819
	 }
820
	 break;
821
      case GL_EQUAL:
822
	 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
823
	 for (i=0;i
824
	    if (mask[i]) {
825
               const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
826
	       s = (GLstencil) (*sptr & valueMask);
827
	       if (r == s) {
828
		  /* passed */
829
		  fail[i] = 0;
830
	       }
831
	       else {
832
		  fail[i] = 1;
833
		  mask[i] = 0;
834
	       }
835
	    }
836
	    else {
837
	       fail[i] = 0;
838
	    }
839
	 }
840
	 break;
841
      case GL_NOTEQUAL:
842
	 r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask);
843
	 for (i=0;i
844
	    if (mask[i]) {
845
               const GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
846
	       s = (GLstencil) (*sptr & valueMask);
847
	       if (r != s) {
848
		  /* passed */
849
		  fail[i] = 0;
850
	       }
851
	       else {
852
		  fail[i] = 1;
853
		  mask[i] = 0;
854
	       }
855
	    }
856
	    else {
857
	       fail[i] = 0;
858
	    }
859
	 }
860
	 break;
861
      case GL_ALWAYS:
862
	 /* always pass */
863
	 for (i=0;i
864
	    fail[i] = 0;
865
	 }
866
	 break;
867
      default:
868
         _mesa_problem(ctx, "Bad stencil func in gl_stencil_pixels");
869
         return 0;
870
   }
871
 
872
   if (ctx->Stencil.FailFunc[face] != GL_KEEP) {
873
      apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc[face],
874
                                  face, fail );
875
   }
876
 
877
   return !allfail;
878
}
879
 
880
 
881
 
882
 
883
/**
884
 * Apply stencil and depth testing to an array of pixels.
885
 * This is used both for software and hardware stencil buffers.
886
 *
887
 * The comments in this function are a bit sparse but the code is
888
 * almost identical to stencil_and_ztest_span(), which is well
889
 * commented.
890
 *
891
 * Input:  n - number of pixels in the array
892
 *         x, y - array of [n] pixel positions
893
 *         z - array [n] of z values
894
 *         mask - array [n] of flags  (1=test this pixel, 0=skip the pixel)
895
 * Output: mask - array [n] of flags (1=stencil and depth test passed)
896
 * Return: GL_FALSE - all fragments failed the testing
897
 *         GL_TRUE - one or more fragments passed the testing
898
 */
899
static GLboolean
900
stencil_and_ztest_pixels( struct gl_context *ctx, SWspan *span, GLuint face )
901
{
902
   GLubyte passMask[MAX_WIDTH], failMask[MAX_WIDTH], origMask[MAX_WIDTH];
903
   struct gl_framebuffer *fb = ctx->DrawBuffer;
904
   struct gl_renderbuffer *rb = fb->_StencilBuffer;
905
   const GLuint n = span->end;
906
   const GLint *x = span->array->x;
907
   const GLint *y = span->array->y;
908
   GLubyte *mask = span->array->mask;
909
 
910
   ASSERT(span->arrayMask & SPAN_XY);
911
   ASSERT(ctx->Stencil.Enabled);
912
   ASSERT(n <= MAX_WIDTH);
913
 
914
   if (!rb->GetPointer(ctx, rb, 0, 0)) {
915
      /* No direct access */
916
      GLstencil stencil[MAX_WIDTH];
917
 
918
      ASSERT(rb->DataType == GL_UNSIGNED_BYTE);
919
      _swrast_get_values(ctx, rb, n, x, y, stencil, sizeof(GLubyte));
920
 
921
      memcpy(origMask, mask, n * sizeof(GLubyte));
922
 
923
      (void) do_stencil_test(ctx, face, n, stencil, mask);
924
 
925
      if (ctx->Depth.Test == GL_FALSE) {
926
         apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face,
927
                          n, stencil, mask);
928
      }
929
      else {
930
         GLubyte tmpMask[MAX_WIDTH];
931
         memcpy(tmpMask, mask, n * sizeof(GLubyte));
932
 
933
         _swrast_depth_test_span(ctx, span);
934
 
935
         compute_pass_fail_masks(n, tmpMask, mask, passMask, failMask);
936
 
937
         if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) {
938
            apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face,
939
                             n, stencil, failMask);
940
         }
941
         if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) {
942
            apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face,
943
                             n, stencil, passMask);
944
         }
945
      }
946
 
947
      /* Write updated stencil values into hardware stencil buffer */
948
      rb->PutValues(ctx, rb, n, x, y, stencil, origMask);
949
 
950
      return GL_TRUE;
951
   }
952
   else {
953
      /* Direct access to stencil buffer */
954
 
955
      if (stencil_test_pixels(ctx, face, n, x, y, mask) == GL_FALSE) {
956
         /* all fragments failed the stencil test, we're done. */
957
         return GL_FALSE;
958
      }
959
 
960
      if (ctx->Depth.Test==GL_FALSE) {
961
         apply_stencil_op_to_pixels(ctx, n, x, y,
962
                                    ctx->Stencil.ZPassFunc[face], face, mask);
963
      }
964
      else {
965
         memcpy(origMask, mask, n * sizeof(GLubyte));
966
 
967
         _swrast_depth_test_span(ctx, span);
968
 
969
         compute_pass_fail_masks(n, origMask, mask, passMask, failMask);
970
 
971
         if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) {
972
            apply_stencil_op_to_pixels(ctx, n, x, y,
973
                                       ctx->Stencil.ZFailFunc[face],
974
                                       face, failMask);
975
         }
976
         if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) {
977
            apply_stencil_op_to_pixels(ctx, n, x, y,
978
                                       ctx->Stencil.ZPassFunc[face],
979
                                       face, passMask);
980
         }
981
      }
982
 
983
      return GL_TRUE;  /* one or more fragments passed both tests */
984
   }
985
}
986
 
987
 
988
/**
989
 * /return GL_TRUE = one or more fragments passed,
990
 * GL_FALSE = all fragments failed.
991
 */
992
GLboolean
993
_swrast_stencil_and_ztest_span(struct gl_context *ctx, SWspan *span)
994
{
995
   const GLuint face = (span->facing == 0) ? 0 : ctx->Stencil._BackFace;
996
 
997
   if (span->arrayMask & SPAN_XY)
998
      return stencil_and_ztest_pixels(ctx, span, face);
999
   else
1000
      return stencil_and_ztest_span(ctx, span, face);
1001
}
1002
 
1003
 
1004
#if 0
1005
GLuint
1006
clip_span(GLuint bufferWidth, GLuint bufferHeight,
1007
          GLint x, GLint y, GLuint *count)
1008
{
1009
   GLuint n = *count;
1010
   GLuint skipPixels = 0;
1011
 
1012
   if (y < 0 || y >= bufferHeight || x + n <= 0 || x >= bufferWidth) {
1013
      /* totally out of bounds */
1014
      n = 0;
1015
   }
1016
   else {
1017
      /* left clip */
1018
      if (x < 0) {
1019
         skipPixels = -x;
1020
         x = 0;
1021
         n -= skipPixels;
1022
      }
1023
      /* right clip */
1024
      if (x + n > bufferWidth) {
1025
         GLint dx = x + n - bufferWidth;
1026
         n -= dx;
1027
      }
1028
   }
1029
 
1030
   *count = n;
1031
 
1032
   return skipPixels;
1033
}
1034
#endif
1035
 
1036
 
1037
/**
1038
 * Return a span of stencil values from the stencil buffer.
1039
 * Used for glRead/CopyPixels
1040
 * Input:  n - how many pixels
1041
 *         x,y - location of first pixel
1042
 * Output:  stencil - the array of stencil values
1043
 */
1044
void
1045
_swrast_read_stencil_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
1046
                          GLint n, GLint x, GLint y, GLstencil stencil[])
1047
{
1048
   if (y < 0 || y >= (GLint) rb->Height ||
1049
       x + n <= 0 || x >= (GLint) rb->Width) {
1050
      /* span is completely outside framebuffer */
1051
      return; /* undefined values OK */
1052
   }
1053
 
1054
   if (x < 0) {
1055
      GLint dx = -x;
1056
      x = 0;
1057
      n -= dx;
1058
      stencil += dx;
1059
   }
1060
   if (x + n > (GLint) rb->Width) {
1061
      GLint dx = x + n - rb->Width;
1062
      n -= dx;
1063
   }
1064
   if (n <= 0) {
1065
      return;
1066
   }
1067
 
1068
   rb->GetRow(ctx, rb, n, x, y, stencil);
1069
}
1070
 
1071
 
1072
 
1073
/**
1074
 * Write a span of stencil values to the stencil buffer.  This function
1075
 * applies the stencil write mask when needed.
1076
 * Used for glDraw/CopyPixels
1077
 * Input:  n - how many pixels
1078
 *         x, y - location of first pixel
1079
 *         stencil - the array of stencil values
1080
 */
1081
void
1082
_swrast_write_stencil_span(struct gl_context *ctx, GLint n, GLint x, GLint y,
1083
                           const GLstencil stencil[] )
1084
{
1085
   struct gl_framebuffer *fb = ctx->DrawBuffer;
1086
   struct gl_renderbuffer *rb = fb->_StencilBuffer;
1087
   const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1;
1088
   const GLuint stencilMask = ctx->Stencil.WriteMask[0];
1089
 
1090
   if (y < 0 || y >= (GLint) rb->Height ||
1091
       x + n <= 0 || x >= (GLint) rb->Width) {
1092
      /* span is completely outside framebuffer */
1093
      return; /* undefined values OK */
1094
   }
1095
   if (x < 0) {
1096
      GLint dx = -x;
1097
      x = 0;
1098
      n -= dx;
1099
      stencil += dx;
1100
   }
1101
   if (x + n > (GLint) rb->Width) {
1102
      GLint dx = x + n - rb->Width;
1103
      n -= dx;
1104
   }
1105
   if (n <= 0) {
1106
      return;
1107
   }
1108
 
1109
   if ((stencilMask & stencilMax) != stencilMax) {
1110
      /* need to apply writemask */
1111
      GLstencil destVals[MAX_WIDTH], newVals[MAX_WIDTH];
1112
      GLint i;
1113
      rb->GetRow(ctx, rb, n, x, y, destVals);
1114
      for (i = 0; i < n; i++) {
1115
         newVals[i]
1116
            = (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask);
1117
      }
1118
      rb->PutRow(ctx, rb, n, x, y, newVals, NULL);
1119
   }
1120
   else {
1121
      rb->PutRow(ctx, rb, n, x, y, stencil, NULL);
1122
   }
1123
}
1124
 
1125
 
1126
 
1127
/**
1128
 * Clear the stencil buffer.
1129
 */
1130
void
1131
_swrast_clear_stencil_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb )
1132
{
1133
   const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits;
1134
   const GLuint mask = ctx->Stencil.WriteMask[0];
1135
   const GLuint invMask = ~mask;
1136
   const GLuint clearVal = (ctx->Stencil.Clear & mask);
1137
   const GLuint stencilMax = (1 << stencilBits) - 1;
1138
   GLint x, y, width, height;
1139
 
1140
   if (!rb || mask == 0)
1141
      return;
1142
 
1143
   ASSERT(rb->DataType == GL_UNSIGNED_BYTE ||
1144
          rb->DataType == GL_UNSIGNED_SHORT);
1145
 
1146
   ASSERT(rb->_BaseFormat == GL_STENCIL_INDEX);
1147
 
1148
   /* compute region to clear */
1149
   x = ctx->DrawBuffer->_Xmin;
1150
   y = ctx->DrawBuffer->_Ymin;
1151
   width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
1152
   height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
1153
 
1154
   if (rb->GetPointer(ctx, rb, 0, 0)) {
1155
      /* Direct buffer access */
1156
      if ((mask & stencilMax) != stencilMax) {
1157
         /* need to mask the clear */
1158
         if (rb->DataType == GL_UNSIGNED_BYTE) {
1159
            GLint i, j;
1160
            for (i = 0; i < height; i++) {
1161
               GLubyte *stencil = (GLubyte*) rb->GetPointer(ctx, rb, x, y + i);
1162
               for (j = 0; j < width; j++) {
1163
                  stencil[j] = (stencil[j] & invMask) | clearVal;
1164
               }
1165
            }
1166
         }
1167
         else {
1168
            GLint i, j;
1169
            for (i = 0; i < height; i++) {
1170
               GLushort *stencil = (GLushort*) rb->GetPointer(ctx, rb, x, y + i);
1171
               for (j = 0; j < width; j++) {
1172
                  stencil[j] = (stencil[j] & invMask) | clearVal;
1173
               }
1174
            }
1175
         }
1176
      }
1177
      else {
1178
         /* no bit masking */
1179
         if (width == (GLint) rb->Width && rb->DataType == GL_UNSIGNED_BYTE) {
1180
            /* optimized case */
1181
            /* Note: bottom-to-top raster assumed! */
1182
            GLubyte *stencil = (GLubyte *) rb->GetPointer(ctx, rb, x, y);
1183
            GLuint len = width * height * sizeof(GLubyte);
1184
            memset(stencil, clearVal, len);
1185
         }
1186
         else {
1187
            /* general case */
1188
            GLint i;
1189
            for (i = 0; i < height; i++) {
1190
               GLvoid *stencil = rb->GetPointer(ctx, rb, x, y + i);
1191
               if (rb->DataType == GL_UNSIGNED_BYTE) {
1192
                  memset(stencil, clearVal, width);
1193
               }
1194
               else {
1195
                  _mesa_memset16((short unsigned int*) stencil, clearVal, width);
1196
               }
1197
            }
1198
         }
1199
      }
1200
   }
1201
   else {
1202
      /* no direct access */
1203
      if ((mask & stencilMax) != stencilMax) {
1204
         /* need to mask the clear */
1205
         if (rb->DataType == GL_UNSIGNED_BYTE) {
1206
            GLint i, j;
1207
            for (i = 0; i < height; i++) {
1208
               GLubyte stencil[MAX_WIDTH];
1209
               rb->GetRow(ctx, rb, width, x, y + i, stencil);
1210
               for (j = 0; j < width; j++) {
1211
                  stencil[j] = (stencil[j] & invMask) | clearVal;
1212
               }
1213
               rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL);
1214
            }
1215
         }
1216
         else {
1217
            GLint i, j;
1218
            for (i = 0; i < height; i++) {
1219
               GLushort stencil[MAX_WIDTH];
1220
               rb->GetRow(ctx, rb, width, x, y + i, stencil);
1221
               for (j = 0; j < width; j++) {
1222
                  stencil[j] = (stencil[j] & invMask) | clearVal;
1223
               }
1224
               rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL);
1225
            }
1226
         }
1227
      }
1228
      else {
1229
         /* no bit masking */
1230
         const GLubyte clear8 = (GLubyte) clearVal;
1231
         const GLushort clear16 = (GLushort) clearVal;
1232
         const void *clear;
1233
         GLint i;
1234
         if (rb->DataType == GL_UNSIGNED_BYTE) {
1235
            clear = &clear8;
1236
         }
1237
         else {
1238
            clear = &clear16;
1239
         }
1240
         for (i = 0; i < height; i++) {
1241
            rb->PutMonoRow(ctx, rb, width, x, y + i, clear, NULL);
1242
         }
1243
      }
1244
   }
1245
}