blob: 26e72da3f7c70c7f6074718a3f2d23b1896e8cd1 [file] [log] [blame]
Brian Paule4b23562005-05-04 20:11:35 +00001/*
2 * Mesa 3-D graphics library
Brian Paulf084f602005-09-13 23:37:50 +00003 * Version: 6.5
Brian Paule4b23562005-05-04 20:11:35 +00004 *
Brian Paul7275d4d2006-03-20 15:25:18 +00005 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
Brian Paule4b23562005-05-04 20:11:35 +00006 *
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/**
27 * Functions for allocating/managing framebuffers and renderbuffers.
28 * Also, routines for reading/writing renderbuffer data as ubytes,
29 * ushorts, uints, etc.
30 */
31
32
33#include "glheader.h"
34#include "imports.h"
35#include "context.h"
Brian Paul84716042005-11-16 04:05:54 +000036#include "depthstencil.h"
Brian Paule4b23562005-05-04 20:11:35 +000037#include "mtypes.h"
38#include "fbobject.h"
39#include "framebuffer.h"
40#include "renderbuffer.h"
41
42
43
44/**
45 * Compute/set the _DepthMax field for the given framebuffer.
46 * This value depends on the Z buffer resolution.
47 */
48static void
49compute_depth_max(struct gl_framebuffer *fb)
50{
51 if (fb->Visual.depthBits == 0) {
52 /* Special case. Even if we don't have a depth buffer we need
53 * good values for DepthMax for Z vertex transformation purposes
54 * and for per-fragment fog computation.
55 */
56 fb->_DepthMax = (1 << 16) - 1;
57 }
58 else if (fb->Visual.depthBits < 32) {
59 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1;
60 }
61 else {
62 /* Special case since shift values greater than or equal to the
63 * number of bits in the left hand expression's type are undefined.
64 */
65 fb->_DepthMax = 0xffffffff;
66 }
67 fb->_DepthMaxF = (GLfloat) fb->_DepthMax;
68 fb->_MRD = 1.0; /* Minimum resolvable depth value, for polygon offset */
69}
70
71
72/**
73 * Create and initialize a gl_framebuffer object.
74 * This is intended for creating _window_system_ framebuffers, not generic
75 * framebuffer objects ala GL_EXT_framebuffer_object.
76 *
77 * \sa _mesa_new_framebuffer
78 */
79struct gl_framebuffer *
80_mesa_create_framebuffer(const GLvisual *visual)
81{
82 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
83 assert(visual);
84 if (fb) {
85 _mesa_initialize_framebuffer(fb, visual);
86 }
87 return fb;
88}
89
90
91/**
92 * Allocate a new gl_framebuffer object.
93 * This is the default function for ctx->Driver.NewFramebuffer().
94 * This is for allocating user-created framebuffers, not window-system
95 * framebuffers!
96 * \sa _mesa_create_framebuffer
97 */
98struct gl_framebuffer *
99_mesa_new_framebuffer(GLcontext *ctx, GLuint name)
100{
101 struct gl_framebuffer *fb;
102 assert(name != 0);
103 fb = CALLOC_STRUCT(gl_framebuffer);
104 if (fb) {
105 fb->Name = name;
106 fb->RefCount = 1;
Brian Paule4b23562005-05-04 20:11:35 +0000107 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
108 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
109 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
Brian Paul048b13d2005-09-23 03:22:20 +0000110 fb->_ColorReadBufferIndex = BUFFER_COLOR0;
Brian Paule4b23562005-05-04 20:11:35 +0000111 fb->Delete = _mesa_destroy_framebuffer;
112 }
113 return fb;
114}
115
116
117/**
Brian Paulf084f602005-09-13 23:37:50 +0000118 * Initialize a gl_framebuffer object. Typically used to initialize
119 * window system-created framebuffers, not user-created framebuffers.
Brian Paule4b23562005-05-04 20:11:35 +0000120 * \sa _mesa_create_framebuffer
121 */
122void
123_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
124{
125 assert(fb);
126 assert(visual);
127
128 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
129
130 /* save the visual */
131 fb->Visual = *visual;
132
133 /* Init glRead/DrawBuffer state */
134 if (visual->doubleBufferMode) {
135 fb->ColorDrawBuffer[0] = GL_BACK;
136 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
137 fb->ColorReadBuffer = GL_BACK;
Brian Paul048b13d2005-09-23 03:22:20 +0000138 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000139 }
140 else {
141 fb->ColorDrawBuffer[0] = GL_FRONT;
142 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
143 fb->ColorReadBuffer = GL_FRONT;
Brian Paul048b13d2005-09-23 03:22:20 +0000144 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
Brian Paule4b23562005-05-04 20:11:35 +0000145 }
146
147 fb->Delete = _mesa_destroy_framebuffer;
Brian Pauld95000d2005-09-28 15:46:46 +0000148 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
Brian Paule4b23562005-05-04 20:11:35 +0000149
150 compute_depth_max(fb);
151}
152
153
154/**
Brian Paule4b23562005-05-04 20:11:35 +0000155 * Deallocate buffer and everything attached to it.
Brian Paulf084f602005-09-13 23:37:50 +0000156 * Typically called via the gl_framebuffer->Delete() method.
Brian Paule4b23562005-05-04 20:11:35 +0000157 */
158void
Brian Paulf084f602005-09-13 23:37:50 +0000159_mesa_destroy_framebuffer(struct gl_framebuffer *fb)
Brian Paule4b23562005-05-04 20:11:35 +0000160{
Brian Paulf084f602005-09-13 23:37:50 +0000161 if (fb) {
162 _mesa_free_framebuffer_data(fb);
Brian Paul84716042005-11-16 04:05:54 +0000163 _mesa_free(fb);
Brian Paule4b23562005-05-04 20:11:35 +0000164 }
165}
166
167
168/**
169 * Free all the data hanging off the given gl_framebuffer, but don't free
170 * the gl_framebuffer object itself.
171 */
172void
173_mesa_free_framebuffer_data(struct gl_framebuffer *fb)
174{
175 GLuint i;
176
177 assert(fb);
178
179 for (i = 0; i < BUFFER_COUNT; i++) {
180 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
181 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
182 struct gl_renderbuffer *rb = att->Renderbuffer;
183 rb->RefCount--;
184 if (rb->RefCount == 0) {
185 rb->Delete(rb);
186 }
187 }
188 att->Type = GL_NONE;
189 att->Renderbuffer = NULL;
190 }
Brian Paul84716042005-11-16 04:05:54 +0000191
192 if (fb->_DepthBuffer) {
193 struct gl_renderbuffer *rb = fb->_DepthBuffer;
194 rb->RefCount--;
195 if (rb->RefCount <= 0) {
196 rb->Delete(rb);
197 }
198 fb->_DepthBuffer = NULL;
199 }
200 if (fb->_StencilBuffer) {
201 struct gl_renderbuffer *rb = fb->_StencilBuffer;
202 rb->RefCount--;
203 if (rb->RefCount <= 0) {
204 rb->Delete(rb);
205 }
206 fb->_StencilBuffer = NULL;
207 }
Brian Paule4b23562005-05-04 20:11:35 +0000208}
209
210
211/**
212 * Resize the given framebuffer's renderbuffers to the new width and height.
213 * This should only be used for window-system framebuffers, not
214 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
Brian Paul84716042005-11-16 04:05:54 +0000215 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
216 * from a device driver.
217 *
218 * \note it's possible for ctx to be null since a window can be resized
219 * without a currently bound rendering context.
Brian Paule4b23562005-05-04 20:11:35 +0000220 */
221void
222_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
223 GLuint width, GLuint height)
224{
225 GLuint i;
226
227 /* For window system framebuffers, Name is zero */
228 assert(fb->Name == 0);
229
230 for (i = 0; i < BUFFER_COUNT; i++) {
231 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
232 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
233 struct gl_renderbuffer *rb = att->Renderbuffer;
234 /* only resize if size is changing */
235 if (rb->Width != width || rb->Height != height) {
236 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
237 rb->Width = width;
238 rb->Height = height;
239 }
240 else {
241 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
242 }
243 }
244 }
245 }
246
247 fb->Width = width;
248 fb->Height = height;
Brian Paul52f686c2005-10-21 21:39:10 +0000249
250 /* to update scissor / window bounds */
Brian Paul7edf68e2005-11-15 14:50:55 +0000251 if (ctx)
252 ctx->NewState |= _NEW_BUFFERS;
Brian Paule4b23562005-05-04 20:11:35 +0000253}
254
255
256/**
257 * Examine all the framebuffer's renderbuffers to update the Width/Height
258 * fields of the framebuffer. If we have renderbuffers with different
259 * sizes, set the framebuffer's width and height to zero.
260 * Note: this is only intended for user-created framebuffers, not
261 * window-system framebuffes.
262 */
263static void
264update_framebuffer_size(struct gl_framebuffer *fb)
265{
266 GLboolean haveSize = GL_FALSE;
267 GLuint i;
268
269 /* user-created framebuffers only */
270 assert(fb->Name);
271
272 for (i = 0; i < BUFFER_COUNT; i++) {
273 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
274 const struct gl_renderbuffer *rb = att->Renderbuffer;
275 if (rb) {
276 if (haveSize) {
277 if (rb->Width != fb->Width && rb->Height != fb->Height) {
278 /* size mismatch! */
279 fb->Width = 0;
280 fb->Height = 0;
281 return;
282 }
283 }
284 else {
285 fb->Width = rb->Width;
286 fb->Height = rb->Height;
287 haveSize = GL_TRUE;
288 }
289 }
290 }
291}
292
293
294/**
295 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
296 * These values are computed from the buffer's width and height and
297 * the scissor box, if it's enabled.
298 * \param ctx the GL context.
299 */
300void
301_mesa_update_draw_buffer_bounds(GLcontext *ctx)
302{
303 struct gl_framebuffer *buffer = ctx->DrawBuffer;
304
305 if (buffer->Name) {
306 /* user-created framebuffer size depends on the renderbuffers */
307 update_framebuffer_size(buffer);
308 }
309
310 buffer->_Xmin = 0;
311 buffer->_Ymin = 0;
312 buffer->_Xmax = buffer->Width;
313 buffer->_Ymax = buffer->Height;
314
315 if (ctx->Scissor.Enabled) {
316 if (ctx->Scissor.X > buffer->_Xmin) {
317 buffer->_Xmin = ctx->Scissor.X;
318 }
319 if (ctx->Scissor.Y > buffer->_Ymin) {
320 buffer->_Ymin = ctx->Scissor.Y;
321 }
322 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
323 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
324 }
325 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
326 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
327 }
328 /* finally, check for empty region */
329 if (buffer->_Xmin > buffer->_Xmax) {
330 buffer->_Xmin = buffer->_Xmax;
331 }
332 if (buffer->_Ymin > buffer->_Ymax) {
333 buffer->_Ymin = buffer->_Ymax;
334 }
335 }
336
337 ASSERT(buffer->_Xmin <= buffer->_Xmax);
338 ASSERT(buffer->_Ymin <= buffer->_Ymax);
339}
340
341
342/**
343 * The glGet queries of the framebuffer red/green/blue size, stencil size,
344 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
Brian Paulf084f602005-09-13 23:37:50 +0000345 * change depending on the renderbuffer bindings. This function updates
Brian Paule4b23562005-05-04 20:11:35 +0000346 * the given framebuffer's Visual from the current renderbuffer bindings.
347 * This is only intended for user-created framebuffers.
Brian Pauleb063cf2005-10-04 14:48:24 +0000348 *
349 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
350 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
351 * The former one is used to convert floating point depth values into
352 * integer Z values.
Brian Paule4b23562005-05-04 20:11:35 +0000353 */
354void
355_mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
356{
Brian Paul474f28e2005-10-08 14:41:17 +0000357 GLuint i;
358
Brian Paule4b23562005-05-04 20:11:35 +0000359 assert(fb->Name != 0);
360
361 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
Brian Paul474f28e2005-10-08 14:41:17 +0000362 fb->Visual.rgbMode = GL_TRUE; /* assume this */
Brian Paule4b23562005-05-04 20:11:35 +0000363
Brian Paul474f28e2005-10-08 14:41:17 +0000364 /* find first RGB or CI renderbuffer */
365 for (i = 0; i < BUFFER_COUNT; i++) {
366 if (fb->Attachment[i].Renderbuffer) {
367 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
368 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
369 fb->Visual.redBits = rb->RedBits;
370 fb->Visual.greenBits = rb->GreenBits;
371 fb->Visual.blueBits = rb->BlueBits;
372 fb->Visual.alphaBits = rb->AlphaBits;
373 fb->Visual.rgbBits = fb->Visual.redBits
374 + fb->Visual.greenBits + fb->Visual.blueBits;
375 fb->Visual.floatMode = GL_FALSE;
376 break;
377 }
378 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
379 fb->Visual.indexBits = rb->IndexBits;
380 fb->Visual.rgbMode = GL_FALSE;
381 break;
382 }
383 }
Brian Paule4b23562005-05-04 20:11:35 +0000384 }
385
386 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
387 fb->Visual.haveDepthBuffer = GL_TRUE;
388 fb->Visual.depthBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000389 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
Brian Paule4b23562005-05-04 20:11:35 +0000390 }
391
392 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
393 fb->Visual.haveStencilBuffer = GL_TRUE;
394 fb->Visual.stencilBits
Brian Paul676d0ac2005-09-22 05:19:57 +0000395 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
Brian Paule4b23562005-05-04 20:11:35 +0000396 }
397
398 compute_depth_max(fb);
399}
400
401
402/**
Brian Paul84716042005-11-16 04:05:54 +0000403 * Helper function for _mesa_update_framebuffer().
404 * Set the actual depth renderbuffer for the given framebuffer.
405 * Take care of reference counts, etc.
406 */
407static void
408set_depth_renderbuffer(struct gl_framebuffer *fb,
409 struct gl_renderbuffer *rb)
410{
411 if (fb->_DepthBuffer) {
412 fb->_DepthBuffer->RefCount--;
413 if (fb->_DepthBuffer->RefCount <= 0) {
414 fb->_DepthBuffer->Delete(fb->_DepthBuffer);
415 }
416 }
417 fb->_DepthBuffer = rb;
418 if (rb)
419 rb->RefCount++;
420}
421
422/**
423 * \sa set_depth_renderbuffer.
424 */
425static void
426set_stencil_renderbuffer(struct gl_framebuffer *fb,
427 struct gl_renderbuffer *rb)
428{
429 if (fb->_StencilBuffer) {
430 fb->_StencilBuffer->RefCount--;
431 if (fb->_StencilBuffer->RefCount <= 0) {
432 fb->_StencilBuffer->Delete(fb->_StencilBuffer);
433 }
434 }
435 fb->_StencilBuffer = rb;
436 if (rb)
437 rb->RefCount++;
438}
439
440
441/**
Brian Paule4b23562005-05-04 20:11:35 +0000442 * Update state related to the current draw/read framebuffers.
Brian Paul52783592005-08-31 21:38:53 +0000443 * Specifically, update these framebuffer fields:
444 * _ColorDrawBuffers
Brian Paul52783592005-08-31 21:38:53 +0000445 * _NumColorDrawBuffers
446 * _ColorReadBuffer
Brian Paul0f29ef62005-11-16 04:17:20 +0000447 * _DepthBuffer
448 * _StencilBuffer
Brian Paule4b23562005-05-04 20:11:35 +0000449 * If the current framebuffer is user-created, make sure it's complete.
Brian Paul52783592005-08-31 21:38:53 +0000450 * The following functions can effect this state: glReadBuffer,
Brian Paul0f29ef62005-11-16 04:17:20 +0000451 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
452 * glRenderbufferStorageEXT.
Brian Paule4b23562005-05-04 20:11:35 +0000453 */
454void
455_mesa_update_framebuffer(GLcontext *ctx)
456{
457 struct gl_framebuffer *fb = ctx->DrawBuffer;
458 GLuint output;
459
460 /* Completeness only matters for user-created framebuffers */
Brian Paul474f28e2005-10-08 14:41:17 +0000461 if (fb->Name != 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000462 _mesa_test_framebuffer_completeness(ctx, fb);
Brian Paul474f28e2005-10-08 14:41:17 +0000463 _mesa_update_framebuffer_visual(fb);
464 }
Brian Paule4b23562005-05-04 20:11:35 +0000465
466 /*
Brian Paul048b13d2005-09-23 03:22:20 +0000467 * Update the list of color drawing renderbuffer pointers.
Brian Paule4b23562005-05-04 20:11:35 +0000468 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
Brian Paulf084f602005-09-13 23:37:50 +0000469 * writing colors. We need the inner loop here because
470 * glDrawBuffer(GL_FRONT_AND_BACK) can specify writing to two or four
471 * color buffers (for example).
Brian Paule4b23562005-05-04 20:11:35 +0000472 */
473 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
Brian Paule00ac112005-09-15 05:00:45 +0000474 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
Brian Paule4b23562005-05-04 20:11:35 +0000475 GLuint count = 0;
Brian Paul048b13d2005-09-23 03:22:20 +0000476 GLuint i;
477 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
478 const GLuint bufferBit = 1 << i;
Brian Paule4b23562005-05-04 20:11:35 +0000479 if (bufferBit & bufferMask) {
Brian Paul048b13d2005-09-23 03:22:20 +0000480 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
Brian Paule4b23562005-05-04 20:11:35 +0000481 if (rb) {
482 fb->_ColorDrawBuffers[output][count] = rb;
Brian Paule4b23562005-05-04 20:11:35 +0000483 count++;
484 }
485 else {
Brian Paula6296dd2005-10-03 16:11:47 +0000486 /*_mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");*/
Brian Paule4b23562005-05-04 20:11:35 +0000487 }
488 bufferMask &= ~bufferBit;
489 }
490 }
491 fb->_NumColorDrawBuffers[output] = count;
492 }
493
494 /*
Brian Paul048b13d2005-09-23 03:22:20 +0000495 * Update the color read renderbuffer pointer.
Brian Paule4b23562005-05-04 20:11:35 +0000496 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
497 */
Brian Paul048b13d2005-09-23 03:22:20 +0000498 if (fb->_ColorReadBufferIndex == -1) {
Brian Paule4b23562005-05-04 20:11:35 +0000499 fb->_ColorReadBuffer = NULL; /* legal! */
Brian Paul048b13d2005-09-23 03:22:20 +0000500 }
501 else {
502 ASSERT(fb->_ColorReadBufferIndex >= 0);
503 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
504 fb->_ColorReadBuffer
505 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
Brian Paul048b13d2005-09-23 03:22:20 +0000506 }
Brian Paul84716042005-11-16 04:05:54 +0000507
508 /*
509 * Deal with GL_DEPTH_STENCIL renderbuffer(s) attached to the depth
Brian Paul0f29ef62005-11-16 04:17:20 +0000510 * and/or stencil attachment points. If either of the DEPTH or STENCIL
511 * renderbuffer attachments are GL_DEPTH_STENCIL buffers, we need to set
512 * up depth/stencil renderbuffer wrappers.
Brian Paul84716042005-11-16 04:05:54 +0000513 */
514 {
515 struct gl_renderbuffer *depthRb
516 = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
517 struct gl_renderbuffer *stencilRb
518 = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
519
520 if (depthRb && depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul0f29ef62005-11-16 04:17:20 +0000521 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul84716042005-11-16 04:05:54 +0000522 if (!fb->_DepthBuffer || fb->_DepthBuffer->Wrapped != depthRb) {
523 /* need to update wrapper */
524 struct gl_renderbuffer *wrapper
525 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
526 set_depth_renderbuffer(fb, wrapper);
527 assert(fb->_DepthBuffer->Wrapped == depthRb);
528 }
529 }
530 else {
531 /* depthRb may be null */
532 set_depth_renderbuffer(fb, depthRb);
533 }
534
535 if (stencilRb && stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul0f29ef62005-11-16 04:17:20 +0000536 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
Brian Paul84716042005-11-16 04:05:54 +0000537 if (!fb->_StencilBuffer || fb->_StencilBuffer->Wrapped != stencilRb) {
538 /* need to update wrapper */
539 struct gl_renderbuffer *wrapper
540 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
541 set_stencil_renderbuffer(fb, wrapper);
542 assert(fb->_StencilBuffer->Wrapped == stencilRb);
543 }
544 }
545 else {
546 /* stencilRb may be null */
547 set_stencil_renderbuffer(fb, stencilRb);
548 }
549 }
550
Brian Paule4b23562005-05-04 20:11:35 +0000551 compute_depth_max(fb);
552}
Brian Paul7275d4d2006-03-20 15:25:18 +0000553
554
555/**
556 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
557 * glCopyTex[Sub]Image, etc. exists.
558 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
559 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
560 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
561 */
562GLboolean
563_mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
564{
565 const struct gl_renderbuffer_attachment *att
566 = ctx->ReadBuffer->Attachment;
567
568 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
569 return GL_FALSE;
570 }
571
572 switch (format) {
573 case GL_COLOR:
574 case GL_ALPHA:
575 case GL_LUMINANCE:
576 case GL_LUMINANCE_ALPHA:
577 case GL_INTENSITY:
578 case GL_RGB:
579 case GL_RGBA:
580 case GL_COLOR_INDEX:
581 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
582 return GL_FALSE;
583 }
584 break;
585 case GL_DEPTH:
586 case GL_DEPTH_COMPONENT:
587 if (!att[BUFFER_DEPTH].Renderbuffer) {
588 return GL_FALSE;
589 }
590 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
591 break;
592 case GL_STENCIL:
593 case GL_STENCIL_INDEX:
594 if (!att[BUFFER_STENCIL].Renderbuffer) {
595 return GL_FALSE;
596 }
597 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
598 break;
599 case GL_DEPTH_STENCIL_EXT:
600 if (!att[BUFFER_DEPTH].Renderbuffer ||
601 !att[BUFFER_STENCIL].Renderbuffer) {
602 return GL_FALSE;
603 }
604 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
605 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
606 break;
607 default:
608 _mesa_problem(ctx,
609 "Unexpected format 0x%x in _mesa_source_buffer_exists");
610 return GL_FALSE;
611 }
612
613 /* OK */
614 return GL_TRUE;
615}
616
617
618/**
619 * As above, but for drawing operations.
620 * XXX code do some code merging w/ above function.
621 */
622GLboolean
623_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
624{
625 const struct gl_renderbuffer_attachment *att
626 = ctx->ReadBuffer->Attachment;
627
628 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
629 return GL_FALSE;
630 }
631
632 switch (format) {
633 case GL_COLOR:
634 case GL_ALPHA:
635 case GL_LUMINANCE:
636 case GL_LUMINANCE_ALPHA:
637 case GL_INTENSITY:
638 case GL_RGB:
639 case GL_RGBA:
640 case GL_COLOR_INDEX:
641 /* nothing special */
642 break;
643 case GL_DEPTH:
644 case GL_DEPTH_COMPONENT:
645 if (!att[BUFFER_DEPTH].Renderbuffer) {
646 return GL_FALSE;
647 }
648 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
649 break;
650 case GL_STENCIL:
651 case GL_STENCIL_INDEX:
652 if (!att[BUFFER_STENCIL].Renderbuffer) {
653 return GL_FALSE;
654 }
655 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
656 break;
657 case GL_DEPTH_STENCIL_EXT:
658 if (!att[BUFFER_DEPTH].Renderbuffer ||
659 !att[BUFFER_STENCIL].Renderbuffer) {
660 return GL_FALSE;
661 }
662 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
663 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
664 break;
665 default:
666 _mesa_problem(ctx,
667 "Unexpected format 0x%x in _mesa_source_buffer_exists");
668 return GL_FALSE;
669 }
670
671 /* OK */
672 return GL_TRUE;
673}