Support for combined depth/stencil renderbuffers (GL_EXT_packed_depth_stencil).
[mesa.git] / src / mesa / main / depthstencil.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2005 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 "fbobject.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 renderbuffer with depth and stencil
44 * adaptors, each with the right kind of depth/stencil Get/Put functions.
45 */
46
47
48 static void *
49 nop_get_pointer(GLcontext *ctx, struct gl_renderbuffer *rb, GLint x, GLint y)
50 {
51 return NULL;
52 }
53
54
55 /**
56 * Delete a depth or stencil renderbuffer.
57 */
58 static void
59 delete_wrapper(struct gl_renderbuffer *rb)
60 {
61 struct gl_renderbuffer *dsrb = rb->Wrapped;
62 assert(dsrb);
63 assert(rb->InternalFormat == GL_DEPTH_COMPONENT24 ||
64 rb->InternalFormat == GL_STENCIL_INDEX8_EXT);
65 /* decrement refcount on the wrapped buffer and delete it if necessary */
66 dsrb->RefCount--;
67 if (dsrb->RefCount <= 0) {
68 dsrb->Delete(dsrb);
69 }
70 _mesa_free(rb);
71 }
72
73
74 /*======================================================================
75 * Depth wrapper around depth/stencil renderbuffer
76 */
77
78 static void
79 get_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
80 GLint x, GLint y, void *values)
81 {
82 struct gl_renderbuffer *dsrb = z24rb->Wrapped;
83 GLuint temp[MAX_WIDTH], i;
84 GLuint *dst = (GLuint *) values;
85 const GLuint *src = (const GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
86 ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
87 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
88 if (!src) {
89 dsrb->GetRow(ctx, dsrb, count, x, y, temp);
90 src = temp;
91 }
92 for (i = 0; i < count; i++) {
93 dst[i] = src[i] >> 8;
94 }
95 }
96
97 static void
98 get_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
99 const GLint x[], const GLint y[], void *values)
100 {
101 struct gl_renderbuffer *dsrb = z24rb->Wrapped;
102 GLuint temp[MAX_WIDTH], i;
103 GLuint *dst = (GLuint *) values;
104 ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
105 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
106 ASSERT(count <= MAX_WIDTH);
107 /* don't bother trying direct access */
108 dsrb->GetValues(ctx, dsrb, count, x, y, temp);
109 for (i = 0; i < count; i++) {
110 dst[i] = temp[i] >> 8;
111 }
112 }
113
114 static void
115 put_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
116 GLint x, GLint y, const void *values, const GLubyte *mask)
117 {
118 struct gl_renderbuffer *dsrb = z24rb->Wrapped;
119 const GLuint *src = (const GLuint *) values;
120 GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
121 ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
122 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
123 if (dst) {
124 /* direct access */
125 GLuint i;
126 for (i = 0; i < count; i++) {
127 if (!mask || mask[i]) {
128 dst[i] = (src[i] << 8) | (dst[i] & 0xff);
129 }
130 }
131 }
132 else {
133 /* get, modify, put */
134 GLuint temp[MAX_WIDTH], i;
135 dsrb->GetRow(ctx, dsrb, count, x, y, temp);
136 for (i = 0; i < count; i++) {
137 if (!mask || mask[i]) {
138 temp[i] = (src[i] << 8) | (temp[i] & 0xff);
139 }
140 }
141 dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
142 }
143 }
144
145 static void
146 put_mono_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
147 GLint x, GLint y, const void *value, const GLubyte *mask)
148 {
149 struct gl_renderbuffer *dsrb = z24rb->Wrapped;
150 const GLuint shiftedVal = *((GLuint *) value) << 8;
151 GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
152 ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
153 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
154 if (dst) {
155 /* direct access */
156 GLuint i;
157 for (i = 0; i < count; i++) {
158 if (!mask || mask[i]) {
159 dst[i] = shiftedVal | (dst[i] & 0xff);
160 }
161 }
162 }
163 else {
164 /* get, modify, put */
165 GLuint temp[MAX_WIDTH], i;
166 dsrb->GetRow(ctx, dsrb, count, x, y, temp);
167 for (i = 0; i < count; i++) {
168 if (!mask || mask[i]) {
169 temp[i] = shiftedVal | (temp[i] & 0xff);
170 }
171 }
172 dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
173 }
174 }
175
176 static void
177 put_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
178 const GLint x[], const GLint y[],
179 const void *values, const GLubyte *mask)
180 {
181 struct gl_renderbuffer *dsrb = z24rb->Wrapped;
182 const GLubyte *src = (const GLubyte *) values;
183 ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
184 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
185 if (dsrb->GetPointer(ctx, dsrb, 0, 0)) {
186 /* direct access */
187 GLuint i;
188 for (i = 0; i < count; i++) {
189 if (!mask || mask[i]) {
190 GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
191 *dst = (src[i] << 8) | (*dst & 0xff);
192 }
193 }
194 }
195 else {
196 /* get, modify, put */
197 GLuint temp[MAX_WIDTH], i;
198 dsrb->GetValues(ctx, dsrb, count, x, y, temp);
199 for (i = 0; i < count; i++) {
200 if (!mask || mask[i]) {
201 temp[i] = (src[i] << 8) | (temp[i] & 0xff);
202 }
203 }
204 dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
205 }
206 }
207
208 static void
209 put_mono_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb,
210 GLuint count, const GLint x[], const GLint y[],
211 const void *value, const GLubyte *mask)
212 {
213 struct gl_renderbuffer *dsrb = z24rb->Wrapped;
214 GLuint temp[MAX_WIDTH], i;
215 const GLuint shiftedVal = *((GLuint *) value) << 8;
216 /* get, modify, put */
217 dsrb->GetValues(ctx, dsrb, count, x, y, temp);
218 for (i = 0; i < count; i++) {
219 if (!mask || mask[i]) {
220 temp[i] = shiftedVal | (temp[i] & 0xff);
221 }
222 }
223 dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
224 }
225
226
227 /**
228 * Wrap the given GL_DEPTH_STENCIL renderbuffer so that it acts like
229 * a depth renderbuffer.
230 * \return new depth renderbuffer
231 */
232 struct gl_renderbuffer *
233 _mesa_new_z24_renderbuffer_wrapper(GLcontext *ctx,
234 struct gl_renderbuffer *dsrb)
235 {
236 struct gl_renderbuffer *z24rb;
237
238 ASSERT(dsrb->_BaseFormat == GL_DEPTH_STENCIL_EXT);
239 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
240
241 z24rb = _mesa_new_renderbuffer(ctx, 0);
242 if (!z24rb)
243 return NULL;
244
245 z24rb->Wrapped = dsrb;
246 z24rb->Name = dsrb->Name;
247 z24rb->RefCount = 1;
248 z24rb->Width = dsrb->Width;
249 z24rb->Height = dsrb->Height;
250 z24rb->InternalFormat = GL_DEPTH_COMPONENT24_ARB;
251 z24rb->_BaseFormat = GL_DEPTH_COMPONENT;
252 z24rb->DataType = GL_UNSIGNED_INT;
253 z24rb->DepthBits = 24;
254 z24rb->Data = NULL;
255 z24rb->Delete = delete_wrapper;
256 z24rb->GetPointer = nop_get_pointer;
257 z24rb->GetRow = get_row_z24;
258 z24rb->GetValues = get_values_z24;
259 z24rb->PutRow = put_row_z24;
260 z24rb->PutRowRGB = NULL;
261 z24rb->PutMonoRow = put_mono_row_z24;
262 z24rb->PutValues = put_values_z24;
263 z24rb->PutMonoValues = put_mono_values_z24;
264
265 return z24rb;
266 }
267
268
269 /*======================================================================
270 * Stencil wrapper around depth/stencil renderbuffer
271 */
272
273 static void
274 get_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
275 GLint x, GLint y, void *values)
276 {
277 struct gl_renderbuffer *dsrb = s8rb->Wrapped;
278 GLuint temp[MAX_WIDTH], i;
279 GLubyte *dst = (GLubyte *) values;
280 const GLuint *src = (const GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
281 ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
282 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
283 if (!src) {
284 dsrb->GetRow(ctx, dsrb, count, x, y, temp);
285 src = temp;
286 }
287 for (i = 0; i < count; i++) {
288 dst[i] = src[i] & 0xff;
289 }
290 }
291
292 static void
293 get_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
294 const GLint x[], const GLint y[], void *values)
295 {
296 struct gl_renderbuffer *dsrb = s8rb->Wrapped;
297 GLuint temp[MAX_WIDTH], i;
298 GLubyte *dst = (GLubyte *) values;
299 ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
300 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
301 ASSERT(count <= MAX_WIDTH);
302 /* don't bother trying direct access */
303 dsrb->GetValues(ctx, dsrb, count, x, y, temp);
304 for (i = 0; i < count; i++) {
305 dst[i] = temp[i] & 0xff;
306 }
307 }
308
309 static void
310 put_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
311 GLint x, GLint y, const void *values, const GLubyte *mask)
312 {
313 struct gl_renderbuffer *dsrb = s8rb->Wrapped;
314 const GLubyte *src = (const GLubyte *) values;
315 GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
316 ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
317 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
318 if (dst) {
319 /* direct access */
320 GLuint i;
321 for (i = 0; i < count; i++) {
322 if (!mask || mask[i]) {
323 dst[i] = (dst[i] & 0xffffff00) | src[i];
324 }
325 }
326 }
327 else {
328 /* get, modify, put */
329 GLuint temp[MAX_WIDTH], i;
330 dsrb->GetRow(ctx, dsrb, count, x, y, temp);
331 for (i = 0; i < count; i++) {
332 if (!mask || mask[i]) {
333 temp[i] = (temp[i] & 0xffffff00) | src[i];
334 }
335 }
336 dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
337 }
338 }
339
340 static void
341 put_mono_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
342 GLint x, GLint y, const void *value, const GLubyte *mask)
343 {
344 struct gl_renderbuffer *dsrb = s8rb->Wrapped;
345 const GLubyte val = *((GLubyte *) value);
346 GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
347 ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
348 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
349 if (dst) {
350 /* direct access */
351 GLuint i;
352 for (i = 0; i < count; i++) {
353 if (!mask || mask[i]) {
354 dst[i] = (dst[i] & 0xffffff00) | val;
355 }
356 }
357 }
358 else {
359 /* get, modify, put */
360 GLuint temp[MAX_WIDTH], i;
361 dsrb->GetRow(ctx, dsrb, count, x, y, temp);
362 for (i = 0; i < count; i++) {
363 if (!mask || mask[i]) {
364 temp[i] = (temp[i] & 0xffffff00) | val;
365 }
366 }
367 dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
368 }
369 }
370
371 static void
372 put_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
373 const GLint x[], const GLint y[],
374 const void *values, const GLubyte *mask)
375 {
376 struct gl_renderbuffer *dsrb = s8rb->Wrapped;
377 const GLubyte *src = (const GLubyte *) values;
378 ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
379 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
380 if (dsrb->GetPointer(ctx, dsrb, 0, 0)) {
381 /* direct access */
382 GLuint i;
383 for (i = 0; i < count; i++) {
384 if (!mask || mask[i]) {
385 GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
386 *dst = (*dst & 0xffffff00) | src[i];
387 }
388 }
389 }
390 else {
391 /* get, modify, put */
392 GLuint temp[MAX_WIDTH], i;
393 dsrb->GetValues(ctx, dsrb, count, x, y, temp);
394 for (i = 0; i < count; i++) {
395 if (!mask || mask[i]) {
396 temp[i] = (temp[i] & 0xffffff00) | src[i];
397 }
398 }
399 dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
400 }
401 }
402
403 static void
404 put_mono_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
405 const GLint x[], const GLint y[],
406 const void *value, const GLubyte *mask)
407 {
408 struct gl_renderbuffer *dsrb = s8rb->Wrapped;
409 GLuint temp[MAX_WIDTH], i;
410 const GLubyte val = *((GLubyte *) value);
411 /* get, modify, put */
412 dsrb->GetValues(ctx, dsrb, count, x, y, temp);
413 for (i = 0; i < count; i++) {
414 if (!mask || mask[i]) {
415 temp[i] = (temp[i] & 0xffffff) | val;
416 }
417 }
418 dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
419 }
420
421
422 /**
423 * Wrap the given GL_DEPTH_STENCIL renderbuffer so that it acts like
424 * a stencil renderbuffer.
425 * \return new stencil renderbuffer
426 */
427 struct gl_renderbuffer *
428 _mesa_new_s8_renderbuffer_wrapper(GLcontext *ctx, struct gl_renderbuffer *dsrb)
429 {
430 struct gl_renderbuffer *s8rb;
431
432 ASSERT(dsrb->_BaseFormat == GL_DEPTH_STENCIL_EXT);
433 ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
434
435 s8rb = _mesa_new_renderbuffer(ctx, 0);
436 if (!s8rb)
437 return NULL;
438
439 s8rb->Wrapped = dsrb;
440 s8rb->Name = dsrb->Name;
441 s8rb->RefCount = 1;
442 s8rb->Width = dsrb->Width;
443 s8rb->Height = dsrb->Height;
444 s8rb->InternalFormat = GL_STENCIL_INDEX8_EXT;
445 s8rb->_BaseFormat = GL_STENCIL_INDEX;
446 s8rb->DataType = GL_UNSIGNED_BYTE;
447 s8rb->StencilBits = 8;
448 s8rb->Data = NULL;
449 s8rb->Delete = delete_wrapper;
450 s8rb->GetPointer = nop_get_pointer;
451 s8rb->GetRow = get_row_s8;
452 s8rb->GetValues = get_values_s8;
453 s8rb->PutRow = put_row_s8;
454 s8rb->PutRowRGB = NULL;
455 s8rb->PutMonoRow = put_mono_row_s8;
456 s8rb->PutValues = put_values_s8;
457 s8rb->PutMonoValues = put_mono_values_s8;
458
459 return s8rb;
460 }
461
462
463 /**
464 * Merge data from a depth renderbuffer and a stencil renderbuffer into a
465 * combined depth/stencil renderbuffer.
466 */
467 void
468 _mesa_merge_depth_stencil_buffers(GLcontext *ctx,
469 struct gl_renderbuffer *dest,
470 struct gl_renderbuffer *depth,
471 struct gl_renderbuffer *stencil)
472 {
473 GLuint depthVals[MAX_WIDTH];
474 GLubyte stencilVals[MAX_WIDTH];
475 GLuint combined[MAX_WIDTH];
476 GLuint row, width;
477
478 ASSERT(dest);
479 ASSERT(depth);
480 ASSERT(stencil);
481
482 ASSERT(dest->InternalFormat == GL_DEPTH24_STENCIL8_EXT);
483 ASSERT(dest->DataType == GL_UNSIGNED_INT_24_8_EXT);
484 ASSERT(depth->InternalFormat == GL_DEPTH_COMPONENT24);
485 ASSERT(depth->DataType == GL_UNSIGNED_INT);
486 ASSERT(stencil->InternalFormat == GL_STENCIL_INDEX8_EXT);
487 ASSERT(stencil->DataType == GL_UNSIGNED_BYTE);
488
489 ASSERT(dest->Width == depth->Width);
490 ASSERT(dest->Height == depth->Height);
491 ASSERT(dest->Width == stencil->Width);
492 ASSERT(dest->Height == stencil->Height);
493
494 width = dest->Width;
495 for (row = 0; row < dest->Height; row++) {
496 GLuint i;
497 depth->GetRow(ctx, depth, width, 0, row, depthVals);
498 stencil->GetRow(ctx, stencil, width, 0, row, stencilVals);
499 for (i = 0; i < width; i++) {
500 combined[i] = (depthVals[i] << 8) | stencilVals[i];
501 }
502 dest->PutRow(ctx, dest, width, 0, row, combined, NULL);
503 }
504 }
505
506
507 /**
508 * Split combined depth/stencil renderbuffer data into separate depth/stencil
509 * buffers.
510 */
511 void
512 _mesa_split_depth_stencil_buffer(GLcontext *ctx,
513 struct gl_renderbuffer *source,
514 struct gl_renderbuffer *depth,
515 struct gl_renderbuffer *stencil)
516 {
517 GLuint depthVals[MAX_WIDTH];
518 GLubyte stencilVals[MAX_WIDTH];
519 GLuint combined[MAX_WIDTH];
520 GLuint row, width;
521
522 ASSERT(source);
523 ASSERT(depth);
524 ASSERT(stencil);
525
526 ASSERT(source->InternalFormat == GL_DEPTH24_STENCIL8_EXT);
527 ASSERT(source->DataType == GL_UNSIGNED_INT_24_8_EXT);
528 ASSERT(depth->InternalFormat == GL_DEPTH_COMPONENT24);
529 ASSERT(depth->DataType == GL_UNSIGNED_INT);
530 ASSERT(stencil->InternalFormat == GL_STENCIL_INDEX8_EXT);
531 ASSERT(stencil->DataType == GL_UNSIGNED_BYTE);
532
533 ASSERT(source->Width == depth->Width);
534 ASSERT(source->Height == depth->Height);
535 ASSERT(source->Width == stencil->Width);
536 ASSERT(source->Height == stencil->Height);
537
538 width = source->Width;
539 for (row = 0; row < source->Height; row++) {
540 GLuint i;
541 source->GetRow(ctx, source, width, 0, row, combined);
542 for (i = 0; i < width; i++) {
543 depthVals[i] = combined[i] >> 8;
544 stencilVals[i] = combined[i] & 0xff;
545 }
546 depth->PutRow(ctx, depth, width, 0, row, depthVals, NULL);
547 stencil->PutRow(ctx, stencil, width, 0, row, stencilVals, NULL);
548 }
549 }