Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / main / depthstencil.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  6.5
4  *
5  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 #include "glheader.h"
26 #include "imports.h"
27 #include "context.h"
28 #include "formats.h"
29 #include "mtypes.h"
30 #include "depthstencil.h"
31 #include "renderbuffer.h"
32
33
34 /**
35  * Adaptor/wrappers for GL_DEPTH_STENCIL renderbuffers.
36  *
37  * The problem with a GL_DEPTH_STENCIL renderbuffer is that sometimes we
38  * want to treat it as a stencil buffer, other times we want to treat it
39  * as a depth/z buffer and still other times when we want to treat it as
40  * a combined Z+stencil buffer!  That implies we need three different sets
41  * of Get/Put functions.
42  *
43  * We solve this by wrapping the Z24_S8 or S8_Z24 renderbuffer with depth and
44  * stencil adaptors, each with the right kind of depth/stencil Get/Put functions.
45  */
46
47
48 static void *
49 nop_get_pointer(struct gl_context *ctx, struct gl_renderbuffer *rb, GLint x, GLint y)
50 {
51    (void) ctx;
52    (void) rb;
53    (void) x;
54    (void) y;
55    return NULL;
56 }
57
58
59 /**
60  * Delete a depth or stencil wrapper renderbuffer.
61  */
62 static void
63 delete_wrapper(struct gl_renderbuffer *rb)
64 {
65    ASSERT(rb->Format == MESA_FORMAT_S8 ||
66           rb->Format == MESA_FORMAT_X8_Z24);
67    _mesa_reference_renderbuffer(&rb->Wrapped, NULL);
68    free(rb);
69 }
70
71
72 /**
73  * Realloc storage for wrapper.
74  */
75 static GLboolean
76 alloc_wrapper_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
77                       GLenum internalFormat, GLuint width, GLuint height)
78 {
79    /* just pass this on to the wrapped renderbuffer */
80    struct gl_renderbuffer *dsrb = rb->Wrapped;
81    GLboolean retVal;
82
83    (void) internalFormat;
84
85    ASSERT(dsrb->Format == MESA_FORMAT_Z24_S8 ||
86           dsrb->Format == MESA_FORMAT_Z24_X8 ||
87           dsrb->Format == MESA_FORMAT_S8_Z24 ||
88           dsrb->Format == MESA_FORMAT_X8_Z24);
89
90    retVal = dsrb->AllocStorage(ctx, dsrb, dsrb->InternalFormat, width, height);
91    if (retVal) {
92       rb->Width = width;
93       rb->Height = height;
94       rb->RowStride = dsrb->RowStride;
95    }
96    return retVal;
97 }
98
99
100
101
102 /*======================================================================
103  * Depth wrapper around depth/stencil renderbuffer
104  */
105
106 static void
107 get_row_z24(struct gl_context *ctx, struct gl_renderbuffer *z24rb, GLuint count,
108             GLint x, GLint y, void *values)
109 {
110    struct gl_renderbuffer *dsrb = z24rb->Wrapped;
111    GLuint temp[MAX_WIDTH], i;
112    GLuint *dst = (GLuint *) values;
113    const GLuint *src = (const GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
114    ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
115    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
116    if (!src) {
117       dsrb->GetRow(ctx, dsrb, count, x, y, temp);
118       src = temp;
119    }
120    if (dsrb->Format == MESA_FORMAT_Z24_S8) {
121       for (i = 0; i < count; i++) {
122          dst[i] = src[i] >> 8;
123       }
124    }
125    else {
126       assert(dsrb->Format == MESA_FORMAT_S8_Z24);
127       for (i = 0; i < count; i++) {
128          dst[i] = src[i] & 0xffffff;
129       }
130    }
131 }
132
133 static void
134 get_values_z24(struct gl_context *ctx, struct gl_renderbuffer *z24rb, GLuint count,
135                const GLint x[], const GLint y[], void *values)
136 {
137    struct gl_renderbuffer *dsrb = z24rb->Wrapped;
138    GLuint temp[MAX_WIDTH], i;
139    GLuint *dst = (GLuint *) values;
140    ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
141    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
142    ASSERT(count <= MAX_WIDTH);
143    /* don't bother trying direct access */
144    dsrb->GetValues(ctx, dsrb, count, x, y, temp);
145    if (dsrb->Format == MESA_FORMAT_Z24_S8) {
146       for (i = 0; i < count; i++) {
147          dst[i] = temp[i] >> 8;
148       }
149    }
150    else {
151       assert(dsrb->Format == MESA_FORMAT_S8_Z24);
152       for (i = 0; i < count; i++) {
153          dst[i] = temp[i] & 0xffffff;
154       }
155    }
156 }
157
158 static void
159 put_row_z24(struct gl_context *ctx, struct gl_renderbuffer *z24rb, GLuint count,
160             GLint x, GLint y, const void *values, const GLubyte *mask)
161 {
162    struct gl_renderbuffer *dsrb = z24rb->Wrapped;
163    const GLuint *src = (const GLuint *) values;
164    GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
165    ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
166    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
167    if (dst) {
168       /* direct access */
169       GLuint i;
170       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
171          for (i = 0; i < count; i++) {
172             if (!mask || mask[i]) {
173                dst[i] = (src[i] << 8) | (dst[i] & 0xff);
174             }
175          }
176       }
177       else {
178          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
179          for (i = 0; i < count; i++) {
180             if (!mask || mask[i]) {
181                dst[i] = (src[i] & 0xffffff) | (dst[i] & 0xff000000);
182             }
183          }
184       }
185    }
186    else {
187       /* get, modify, put */
188       GLuint temp[MAX_WIDTH], i;
189       dsrb->GetRow(ctx, dsrb, count, x, y, temp);
190       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
191          for (i = 0; i < count; i++) {
192             if (!mask || mask[i]) {
193                temp[i] = (src[i] << 8) | (temp[i] & 0xff);
194             }
195          }
196       }
197       else {
198          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
199          for (i = 0; i < count; i++) {
200             if (!mask || mask[i]) {
201                temp[i] = (src[i] & 0xffffff) | (temp[i] & 0xff000000);
202             }
203          }
204       }
205       dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
206    }
207 }
208
209 static void
210 put_mono_row_z24(struct gl_context *ctx, struct gl_renderbuffer *z24rb, GLuint count,
211                  GLint x, GLint y, const void *value, const GLubyte *mask)
212 {
213    struct gl_renderbuffer *dsrb = z24rb->Wrapped;
214    GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
215    ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
216    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
217    if (dst) {
218       /* direct access */
219       GLuint i;
220       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
221          const GLuint shiftedVal = *((GLuint *) value) << 8;
222          for (i = 0; i < count; i++) {
223             if (!mask || mask[i]) {
224                dst[i] = shiftedVal | (dst[i] & 0xff);
225             }
226          }
227       }
228       else {
229          const GLuint shiftedVal = *((GLuint *) value);
230          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
231          for (i = 0; i < count; i++) {
232             if (!mask || mask[i]) {
233                dst[i] = shiftedVal | (dst[i] & 0xff000000);
234             }
235          }
236       }
237    }
238    else {
239       /* get, modify, put */
240       GLuint temp[MAX_WIDTH], i;
241       dsrb->GetRow(ctx, dsrb, count, x, y, temp);
242       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
243          const GLuint shiftedVal = *((GLuint *) value) << 8;
244          for (i = 0; i < count; i++) {
245             if (!mask || mask[i]) {
246                temp[i] = shiftedVal | (temp[i] & 0xff);
247             }
248          }
249       }
250       else {
251          const GLuint shiftedVal = *((GLuint *) value);
252          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
253          for (i = 0; i < count; i++) {
254             if (!mask || mask[i]) {
255                temp[i] = shiftedVal | (temp[i] & 0xff000000);
256             }
257          }
258       }
259       dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
260    }
261 }
262
263 static void
264 put_values_z24(struct gl_context *ctx, struct gl_renderbuffer *z24rb, GLuint count,
265                const GLint x[], const GLint y[],
266                const void *values, const GLubyte *mask)
267 {
268    struct gl_renderbuffer *dsrb = z24rb->Wrapped;
269    const GLuint *src = (const GLuint *) values;
270    ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
271    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
272    if (dsrb->GetPointer(ctx, dsrb, 0, 0)) {
273       /* direct access */
274       GLuint i;
275       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
276          for (i = 0; i < count; i++) {
277             if (!mask || mask[i]) {
278                GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
279                *dst = (src[i] << 8) | (*dst & 0xff);
280             }
281          }
282       }
283       else {
284          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
285          for (i = 0; i < count; i++) {
286             if (!mask || mask[i]) {
287                GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
288                *dst = (src[i] & 0xffffff) | (*dst & 0xff000000);
289             }
290          }
291       }
292    }
293    else {
294       /* get, modify, put */
295       GLuint temp[MAX_WIDTH], i;
296       dsrb->GetValues(ctx, dsrb, count, x, y, temp);
297       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
298          for (i = 0; i < count; i++) {
299             if (!mask || mask[i]) {
300                temp[i] = (src[i] << 8) | (temp[i] & 0xff);
301             }
302          }
303       }
304       else {
305          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
306          for (i = 0; i < count; i++) {
307             if (!mask || mask[i]) {
308                temp[i] = (src[i] & 0xffffff) | (temp[i] & 0xff000000);
309             }
310          }
311       }
312       dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
313    }
314 }
315
316 static void
317 put_mono_values_z24(struct gl_context *ctx, struct gl_renderbuffer *z24rb,
318                     GLuint count, const GLint x[], const GLint y[],
319                     const void *value, const GLubyte *mask)
320 {
321    struct gl_renderbuffer *dsrb = z24rb->Wrapped;
322    GLuint temp[MAX_WIDTH], i;
323    /* get, modify, put */
324    dsrb->GetValues(ctx, dsrb, count, x, y, temp);
325    if (dsrb->Format == MESA_FORMAT_Z24_S8) {
326       const GLuint shiftedVal = *((GLuint *) value) << 8;
327       for (i = 0; i < count; i++) {
328          if (!mask || mask[i]) {
329             temp[i] = shiftedVal | (temp[i] & 0xff);
330          }
331       }
332    }
333    else {
334       const GLuint shiftedVal = *((GLuint *) value);
335       assert(dsrb->Format == MESA_FORMAT_S8_Z24);
336       for (i = 0; i < count; i++) {
337          if (!mask || mask[i]) {
338             temp[i] = shiftedVal | (temp[i] & 0xff000000);
339          }
340       }
341    }
342    dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
343 }
344
345
346 /**
347  * Wrap the given GL_DEPTH_STENCIL renderbuffer so that it acts like
348  * a depth renderbuffer.
349  * \return new depth renderbuffer
350  */
351 struct gl_renderbuffer *
352 _mesa_new_z24_renderbuffer_wrapper(struct gl_context *ctx,
353                                    struct gl_renderbuffer *dsrb)
354 {
355    struct gl_renderbuffer *z24rb;
356
357    ASSERT(dsrb->Format == MESA_FORMAT_Z24_S8 ||
358           dsrb->Format == MESA_FORMAT_Z24_X8 ||
359           dsrb->Format == MESA_FORMAT_S8_Z24 ||
360           dsrb->Format == MESA_FORMAT_X8_Z24);
361    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
362
363    z24rb = ctx->Driver.NewRenderbuffer(ctx, 0);
364    if (!z24rb)
365       return NULL;
366
367    /* NOTE: need to do manual refcounting here */
368    z24rb->Wrapped = dsrb;
369    dsrb->RefCount++;
370
371    z24rb->Name = dsrb->Name;
372    z24rb->RefCount = 0;
373    z24rb->Width = dsrb->Width;
374    z24rb->Height = dsrb->Height;
375    z24rb->RowStride = dsrb->RowStride;
376    z24rb->InternalFormat = GL_DEPTH_COMPONENT24;
377    z24rb->Format = MESA_FORMAT_X8_Z24;
378    z24rb->_BaseFormat = GL_DEPTH_COMPONENT;
379    z24rb->DataType = GL_UNSIGNED_INT;
380    z24rb->Data = NULL;
381    z24rb->Delete = delete_wrapper;
382    z24rb->AllocStorage = alloc_wrapper_storage;
383    z24rb->GetPointer = nop_get_pointer;
384    z24rb->GetRow = get_row_z24;
385    z24rb->GetValues = get_values_z24;
386    z24rb->PutRow = put_row_z24;
387    z24rb->PutRowRGB = NULL;
388    z24rb->PutMonoRow = put_mono_row_z24;
389    z24rb->PutValues = put_values_z24;
390    z24rb->PutMonoValues = put_mono_values_z24;
391
392    return z24rb;
393 }
394
395
396 /*======================================================================
397  * Stencil wrapper around depth/stencil renderbuffer
398  */
399
400 static void
401 get_row_s8(struct gl_context *ctx, struct gl_renderbuffer *s8rb, GLuint count,
402            GLint x, GLint y, void *values)
403 {
404    struct gl_renderbuffer *dsrb = s8rb->Wrapped;
405    GLuint temp[MAX_WIDTH], i;
406    GLubyte *dst = (GLubyte *) values;
407    const GLuint *src = (const GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
408    ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
409    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
410    if (!src) {
411       dsrb->GetRow(ctx, dsrb, count, x, y, temp);
412       src = temp;
413    }
414    if (dsrb->Format == MESA_FORMAT_Z24_S8) {
415       for (i = 0; i < count; i++) {
416          dst[i] = src[i] & 0xff;
417       }
418    }
419    else {
420       assert(dsrb->Format == MESA_FORMAT_S8_Z24);
421       for (i = 0; i < count; i++) {
422          dst[i] = src[i] >> 24;
423       }
424    }
425 }
426
427 static void
428 get_values_s8(struct gl_context *ctx, struct gl_renderbuffer *s8rb, GLuint count,
429               const GLint x[], const GLint y[], void *values)
430 {
431    struct gl_renderbuffer *dsrb = s8rb->Wrapped;
432    GLuint temp[MAX_WIDTH], i;
433    GLubyte *dst = (GLubyte *) values;
434    ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
435    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
436    ASSERT(count <= MAX_WIDTH);
437    /* don't bother trying direct access */
438    dsrb->GetValues(ctx, dsrb, count, x, y, temp);
439    if (dsrb->Format == MESA_FORMAT_Z24_S8) {
440       for (i = 0; i < count; i++) {
441          dst[i] = temp[i] & 0xff;
442       }
443    }
444    else {
445       assert(dsrb->Format == MESA_FORMAT_S8_Z24);
446       for (i = 0; i < count; i++) {
447          dst[i] = temp[i] >> 24;
448       }
449    }
450 }
451
452 static void
453 put_row_s8(struct gl_context *ctx, struct gl_renderbuffer *s8rb, GLuint count,
454            GLint x, GLint y, const void *values, const GLubyte *mask)
455 {
456    struct gl_renderbuffer *dsrb = s8rb->Wrapped;
457    const GLubyte *src = (const GLubyte *) values;
458    GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
459    ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
460    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
461    if (dst) {
462       /* direct access */
463       GLuint i;
464       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
465          for (i = 0; i < count; i++) {
466             if (!mask || mask[i]) {
467                dst[i] = (dst[i] & 0xffffff00) | src[i];
468             }
469          }
470       }
471       else {
472          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
473          for (i = 0; i < count; i++) {
474             if (!mask || mask[i]) {
475                dst[i] = (dst[i] & 0xffffff) | (src[i] << 24);
476             }
477          }
478       }
479    }
480    else {
481       /* get, modify, put */
482       GLuint temp[MAX_WIDTH], i;
483       dsrb->GetRow(ctx, dsrb, count, x, y, temp);
484       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
485          for (i = 0; i < count; i++) {
486             if (!mask || mask[i]) {
487                temp[i] = (temp[i] & 0xffffff00) | src[i];
488             }
489          }
490       }
491       else {
492          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
493          for (i = 0; i < count; i++) {
494             if (!mask || mask[i]) {
495                temp[i] = (temp[i] & 0xffffff) | (src[i] << 24);
496             }
497          }
498       }
499       dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
500    }
501 }
502
503 static void
504 put_mono_row_s8(struct gl_context *ctx, struct gl_renderbuffer *s8rb, GLuint count,
505                 GLint x, GLint y, const void *value, const GLubyte *mask)
506 {
507    struct gl_renderbuffer *dsrb = s8rb->Wrapped;
508    const GLubyte val = *((GLubyte *) value);
509    GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
510    ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
511    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
512    if (dst) {
513       /* direct access */
514       GLuint i;
515       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
516          for (i = 0; i < count; i++) {
517             if (!mask || mask[i]) {
518                dst[i] = (dst[i] & 0xffffff00) | val;
519             }
520          }
521       }
522       else {
523          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
524          for (i = 0; i < count; i++) {
525             if (!mask || mask[i]) {
526                dst[i] = (dst[i] & 0xffffff) | (val << 24);
527             }
528          }
529       }
530    }
531    else {
532       /* get, modify, put */
533       GLuint temp[MAX_WIDTH], i;
534       dsrb->GetRow(ctx, dsrb, count, x, y, temp);
535       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
536          for (i = 0; i < count; i++) {
537             if (!mask || mask[i]) {
538                temp[i] = (temp[i] & 0xffffff00) | val;
539             }
540          }
541       }
542       else {
543          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
544          for (i = 0; i < count; i++) {
545             if (!mask || mask[i]) {
546                temp[i] = (temp[i] & 0xffffff) | (val << 24);
547             }
548          }
549       }
550       dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
551    }
552 }
553
554 static void
555 put_values_s8(struct gl_context *ctx, struct gl_renderbuffer *s8rb, GLuint count,
556               const GLint x[], const GLint y[],
557               const void *values, const GLubyte *mask)
558 {
559    struct gl_renderbuffer *dsrb = s8rb->Wrapped;
560    const GLubyte *src = (const GLubyte *) values;
561    ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
562    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
563    if (dsrb->GetPointer(ctx, dsrb, 0, 0)) {
564       /* direct access */
565       GLuint i;
566       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
567          for (i = 0; i < count; i++) {
568             if (!mask || mask[i]) {
569                GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
570                *dst = (*dst & 0xffffff00) | src[i];
571             }
572          }
573       }
574       else {
575          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
576          for (i = 0; i < count; i++) {
577             if (!mask || mask[i]) {
578                GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
579                *dst = (*dst & 0xffffff) | (src[i] << 24);
580             }
581          }
582       }
583    }
584    else {
585       /* get, modify, put */
586       GLuint temp[MAX_WIDTH], i;
587       dsrb->GetValues(ctx, dsrb, count, x, y, temp);
588       if (dsrb->Format == MESA_FORMAT_Z24_S8) {
589          for (i = 0; i < count; i++) {
590             if (!mask || mask[i]) {
591                temp[i] = (temp[i] & 0xffffff00) | src[i];
592             }
593          }
594       }
595       else {
596          assert(dsrb->Format == MESA_FORMAT_S8_Z24);
597          for (i = 0; i < count; i++) {
598             if (!mask || mask[i]) {
599                temp[i] = (temp[i] & 0xffffff) | (src[i] << 24);
600             }
601          }
602       }
603       dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
604    }
605 }
606
607 static void
608 put_mono_values_s8(struct gl_context *ctx, struct gl_renderbuffer *s8rb, GLuint count,
609                    const GLint x[], const GLint y[],
610                    const void *value, const GLubyte *mask)
611 {
612    struct gl_renderbuffer *dsrb = s8rb->Wrapped;
613    GLuint temp[MAX_WIDTH], i;
614    const GLubyte val = *((GLubyte *) value);
615    /* get, modify, put */
616    dsrb->GetValues(ctx, dsrb, count, x, y, temp);
617    if (dsrb->Format == MESA_FORMAT_Z24_S8) {
618       for (i = 0; i < count; i++) {
619          if (!mask || mask[i]) {
620             temp[i] = (temp[i] & 0xffffff00) | val;
621          }
622       }
623    }
624    else {
625       assert(dsrb->Format == MESA_FORMAT_S8_Z24);
626       for (i = 0; i < count; i++) {
627          if (!mask || mask[i]) {
628             temp[i] = (temp[i] & 0xffffff) | (val << 24);
629          }
630       }
631    }
632    dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
633 }
634
635
636 /**
637  * Wrap the given GL_DEPTH_STENCIL renderbuffer so that it acts like
638  * a stencil renderbuffer.
639  * \return new stencil renderbuffer
640  */
641 struct gl_renderbuffer *
642 _mesa_new_s8_renderbuffer_wrapper(struct gl_context *ctx, struct gl_renderbuffer *dsrb)
643 {
644    struct gl_renderbuffer *s8rb;
645
646    ASSERT(dsrb->Format == MESA_FORMAT_Z24_S8 ||
647           dsrb->Format == MESA_FORMAT_S8_Z24);
648    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
649
650    s8rb = ctx->Driver.NewRenderbuffer(ctx, 0);
651    if (!s8rb)
652       return NULL;
653
654    /* NOTE: need to do manual refcounting here */
655    s8rb->Wrapped = dsrb;
656    dsrb->RefCount++;
657
658    s8rb->Name = dsrb->Name;
659    s8rb->RefCount = 0;
660    s8rb->Width = dsrb->Width;
661    s8rb->Height = dsrb->Height;
662    s8rb->RowStride = dsrb->RowStride;
663    s8rb->InternalFormat = GL_STENCIL_INDEX8_EXT;
664    s8rb->Format = MESA_FORMAT_S8;
665    s8rb->_BaseFormat = GL_STENCIL_INDEX;
666    s8rb->DataType = GL_UNSIGNED_BYTE;
667    s8rb->Data = NULL;
668    s8rb->Delete = delete_wrapper;
669    s8rb->AllocStorage = alloc_wrapper_storage;
670    s8rb->GetPointer = nop_get_pointer;
671    s8rb->GetRow = get_row_s8;
672    s8rb->GetValues = get_values_s8;
673    s8rb->PutRow = put_row_s8;
674    s8rb->PutRowRGB = NULL;
675    s8rb->PutMonoRow = put_mono_row_s8;
676    s8rb->PutValues = put_values_s8;
677    s8rb->PutMonoValues = put_mono_values_s8;
678
679    return s8rb;
680 }
681
682
683
684 /**
685  ** The following functions are useful for hardware drivers that only
686  ** implement combined depth/stencil buffers.
687  ** The GL_EXT_framebuffer_object extension allows indepedent depth and
688  ** stencil buffers to be used in any combination.
689  ** Therefore, we sometimes have to merge separate depth and stencil
690  ** renderbuffers into a single depth+stencil renderbuffer.  And sometimes
691  ** we have to split combined depth+stencil renderbuffers into separate
692  ** renderbuffers.
693  **/
694
695
696 /**
697  * Extract stencil values from the combined depth/stencil renderbuffer, storing
698  * the values into a separate stencil renderbuffer.
699  * \param dsRb  the source depth/stencil renderbuffer
700  * \param stencilRb  the destination stencil renderbuffer
701  *                   (either 8-bit or 32-bit)
702  */
703 void
704 _mesa_extract_stencil(struct gl_context *ctx,
705                       struct gl_renderbuffer *dsRb,
706                       struct gl_renderbuffer *stencilRb)
707 {
708    GLuint row, width, height;
709
710    ASSERT(dsRb);
711    ASSERT(stencilRb);
712
713    ASSERT(dsRb->Format == MESA_FORMAT_Z24_S8);
714    ASSERT(dsRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
715    ASSERT(stencilRb->Format == MESA_FORMAT_Z24_S8 ||
716           stencilRb->Format == MESA_FORMAT_S8);
717    ASSERT(dsRb->Width == stencilRb->Width);
718    ASSERT(dsRb->Height == stencilRb->Height);
719
720    width = dsRb->Width;
721    height = dsRb->Height;
722
723    for (row = 0; row < height; row++) {
724       GLuint depthStencil[MAX_WIDTH];
725       dsRb->GetRow(ctx, dsRb, width, 0, row, depthStencil);
726       if (stencilRb->Format == MESA_FORMAT_S8) {
727          /* 8bpp stencil */
728          GLubyte stencil[MAX_WIDTH];
729          GLuint i;
730          for (i = 0; i < width; i++) {
731             stencil[i] = depthStencil[i] & 0xff;
732          }
733          stencilRb->PutRow(ctx, stencilRb, width, 0, row, stencil, NULL);
734       }
735       else {
736          /* 32bpp stencil */
737          /* the 24 depth bits will be ignored */
738          ASSERT(stencilRb->Format == MESA_FORMAT_Z24_S8);
739          ASSERT(stencilRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
740          stencilRb->PutRow(ctx, stencilRb, width, 0, row, depthStencil, NULL);
741       }
742    }
743 }
744
745
746 /**
747  * Copy stencil values from a stencil renderbuffer into a combined
748  * depth/stencil renderbuffer.
749  * \param dsRb  the destination depth/stencil renderbuffer
750  * \param stencilRb  the source stencil buffer (either 8-bit or 32-bit)
751  */
752 void
753 _mesa_insert_stencil(struct gl_context *ctx,
754                      struct gl_renderbuffer *dsRb,
755                      struct gl_renderbuffer *stencilRb)
756 {
757    GLuint row, width, height;
758
759    ASSERT(dsRb);
760    ASSERT(stencilRb);
761
762    ASSERT(dsRb->Format == MESA_FORMAT_Z24_S8);
763    ASSERT(dsRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
764    ASSERT(stencilRb->Format == MESA_FORMAT_Z24_S8 ||
765           stencilRb->Format == MESA_FORMAT_S8);
766
767    ASSERT(dsRb->Width == stencilRb->Width);
768    ASSERT(dsRb->Height == stencilRb->Height);
769
770    width = dsRb->Width;
771    height = dsRb->Height;
772
773    for (row = 0; row < height; row++) {
774       GLuint depthStencil[MAX_WIDTH];
775
776       dsRb->GetRow(ctx, dsRb, width, 0, row, depthStencil);
777
778       if (stencilRb->Format == MESA_FORMAT_S8) {
779          /* 8bpp stencil */
780          GLubyte stencil[MAX_WIDTH];
781          GLuint i;
782          stencilRb->GetRow(ctx, stencilRb, width, 0, row, stencil);
783          for (i = 0; i < width; i++) {
784             depthStencil[i] = (depthStencil[i] & 0xffffff00) | stencil[i];
785          }
786       }
787       else {
788          /* 32bpp stencil buffer */
789          GLuint stencil[MAX_WIDTH], i;
790          ASSERT(stencilRb->Format == MESA_FORMAT_Z24_S8);
791          ASSERT(stencilRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
792          stencilRb->GetRow(ctx, stencilRb, width, 0, row, stencil);
793          for (i = 0; i < width; i++) {
794             depthStencil[i]
795                = (depthStencil[i] & 0xffffff00) | (stencil[i] & 0xff);
796          }
797       }
798
799       dsRb->PutRow(ctx, dsRb, width, 0, row, depthStencil, NULL);
800    }
801 }
802
803
804 /**
805  * Convert the stencil buffer from 8bpp to 32bpp depth/stencil.
806  * \param stencilRb  the stencil renderbuffer to promote
807  */
808 void
809 _mesa_promote_stencil(struct gl_context *ctx, struct gl_renderbuffer *stencilRb)
810 {
811    const GLsizei width = stencilRb->Width;
812    const GLsizei height = stencilRb->Height;
813    GLubyte *data;
814    GLint i, j, k;
815
816    ASSERT(stencilRb->Format == MESA_FORMAT_S8);
817    ASSERT(stencilRb->Data);
818
819    data = (GLubyte *) stencilRb->Data;
820    stencilRb->Data = NULL;
821    stencilRb->AllocStorage(ctx, stencilRb, GL_DEPTH24_STENCIL8_EXT,
822                            width, height);
823
824    ASSERT(stencilRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
825
826    k = 0;
827    for (i = 0; i < height; i++) {
828       GLuint depthStencil[MAX_WIDTH];
829       for (j = 0; j < width; j++) {
830          depthStencil[j] = data[k++];
831       }
832       stencilRb->PutRow(ctx, stencilRb, width, 0, i, depthStencil, NULL);
833    }
834    free(data);
835 }