In _mesa_make_current(), don't unbind FBOs from the old context.
[mesa.git] / src / mesa / main / framebuffer.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.1
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
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 "buffers.h"
36 #include "context.h"
37 #include "depthstencil.h"
38 #include "mtypes.h"
39 #include "fbobject.h"
40 #include "framebuffer.h"
41 #include "renderbuffer.h"
42 #include "texobj.h"
43
44
45
46 /**
47 * Compute/set the _DepthMax field for the given framebuffer.
48 * This value depends on the Z buffer resolution.
49 */
50 static void
51 compute_depth_max(struct gl_framebuffer *fb)
52 {
53 if (fb->Visual.depthBits == 0) {
54 /* Special case. Even if we don't have a depth buffer we need
55 * good values for DepthMax for Z vertex transformation purposes
56 * and for per-fragment fog computation.
57 */
58 fb->_DepthMax = (1 << 16) - 1;
59 }
60 else if (fb->Visual.depthBits < 32) {
61 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1;
62 }
63 else {
64 /* Special case since shift values greater than or equal to the
65 * number of bits in the left hand expression's type are undefined.
66 */
67 fb->_DepthMax = 0xffffffff;
68 }
69 fb->_DepthMaxF = (GLfloat) fb->_DepthMax;
70
71 /* Minimum resolvable depth value, for polygon offset */
72 fb->_MRD = 1.0 / fb->_DepthMaxF;
73 }
74
75
76 /**
77 * Create and initialize a gl_framebuffer object.
78 * This is intended for creating _window_system_ framebuffers, not generic
79 * framebuffer objects ala GL_EXT_framebuffer_object.
80 *
81 * \sa _mesa_new_framebuffer
82 */
83 struct gl_framebuffer *
84 _mesa_create_framebuffer(const GLvisual *visual)
85 {
86 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
87 assert(visual);
88 if (fb) {
89 _mesa_initialize_framebuffer(fb, visual);
90 }
91 return fb;
92 }
93
94
95 /**
96 * Allocate a new gl_framebuffer object.
97 * This is the default function for ctx->Driver.NewFramebuffer().
98 * This is for allocating user-created framebuffers, not window-system
99 * framebuffers!
100 * \sa _mesa_create_framebuffer
101 */
102 struct gl_framebuffer *
103 _mesa_new_framebuffer(GLcontext *ctx, GLuint name)
104 {
105 struct gl_framebuffer *fb;
106 (void) ctx;
107 assert(name != 0);
108 fb = CALLOC_STRUCT(gl_framebuffer);
109 if (fb) {
110 fb->Name = name;
111 fb->RefCount = 1;
112 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
113 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
114 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
115 fb->_ColorReadBufferIndex = BUFFER_COLOR0;
116 fb->Delete = _mesa_destroy_framebuffer;
117 }
118 return fb;
119 }
120
121
122 /**
123 * Initialize a gl_framebuffer object. Typically used to initialize
124 * window system-created framebuffers, not user-created framebuffers.
125 * \sa _mesa_create_framebuffer
126 */
127 void
128 _mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
129 {
130 assert(fb);
131 assert(visual);
132
133 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
134
135 _glthread_INIT_MUTEX(fb->Mutex);
136
137 fb->RefCount = 1;
138
139 /* save the visual */
140 fb->Visual = *visual;
141
142 /* Init read/draw renderbuffer state */
143 if (visual->doubleBufferMode) {
144 fb->ColorDrawBuffer[0] = GL_BACK;
145 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
146 fb->ColorReadBuffer = GL_BACK;
147 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT;
148 }
149 else {
150 fb->ColorDrawBuffer[0] = GL_FRONT;
151 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
152 fb->ColorReadBuffer = GL_FRONT;
153 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT;
154 }
155
156 fb->Delete = _mesa_destroy_framebuffer;
157 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
158
159 compute_depth_max(fb);
160 }
161
162
163 /**
164 * Deallocate buffer and everything attached to it.
165 * Typically called via the gl_framebuffer->Delete() method.
166 */
167 void
168 _mesa_destroy_framebuffer(struct gl_framebuffer *fb)
169 {
170 if (fb) {
171 _mesa_free_framebuffer_data(fb);
172 _mesa_free(fb);
173 }
174 }
175
176
177 /**
178 * Free all the data hanging off the given gl_framebuffer, but don't free
179 * the gl_framebuffer object itself.
180 */
181 void
182 _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
183 {
184 GLuint i;
185
186 assert(fb);
187 assert(fb->RefCount == 0);
188
189 _glthread_DESTROY_MUTEX(fb->Mutex);
190
191 for (i = 0; i < BUFFER_COUNT; i++) {
192 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
193 if (att->Renderbuffer) {
194 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
195 }
196 if (att->Texture) {
197 _mesa_reference_texobj(&att->Texture, NULL);
198 }
199 ASSERT(!att->Renderbuffer);
200 ASSERT(!att->Texture);
201 att->Type = GL_NONE;
202 }
203
204 /* unbind _Depth/_StencilBuffer to decr ref counts */
205 _mesa_reference_renderbuffer(&fb->_DepthBuffer, NULL);
206 _mesa_reference_renderbuffer(&fb->_StencilBuffer, NULL);
207 }
208
209
210 /**
211 * Set *ptr to point to fb, with refcounting and locking.
212 */
213 void
214 _mesa_reference_framebuffer(struct gl_framebuffer **ptr,
215 struct gl_framebuffer *fb)
216 {
217 assert(ptr);
218 if (*ptr == fb) {
219 /* no change */
220 return;
221 }
222 if (*ptr) {
223 _mesa_unreference_framebuffer(ptr);
224 }
225 assert(!*ptr);
226 assert(fb);
227 _glthread_LOCK_MUTEX(fb->Mutex);
228 fb->RefCount++;
229 _glthread_UNLOCK_MUTEX(fb->Mutex);
230 *ptr = fb;
231 }
232
233
234 /**
235 * Undo/remove a reference to a framebuffer object.
236 * Decrement the framebuffer object's reference count and delete it when
237 * the refcount hits zero.
238 * Note: we pass the address of a pointer and set it to NULL.
239 */
240 void
241 _mesa_unreference_framebuffer(struct gl_framebuffer **fb)
242 {
243 assert(fb);
244 if (*fb) {
245 GLboolean deleteFlag = GL_FALSE;
246
247 _glthread_LOCK_MUTEX((*fb)->Mutex);
248 ASSERT((*fb)->RefCount > 0);
249 (*fb)->RefCount--;
250 deleteFlag = ((*fb)->RefCount == 0);
251 _glthread_UNLOCK_MUTEX((*fb)->Mutex);
252
253 if (deleteFlag)
254 (*fb)->Delete(*fb);
255
256 *fb = NULL;
257 }
258 }
259
260
261
262
263 /**
264 * Resize the given framebuffer's renderbuffers to the new width and height.
265 * This should only be used for window-system framebuffers, not
266 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
267 * This will typically be called via ctx->Driver.ResizeBuffers() or directly
268 * from a device driver.
269 *
270 * \note it's possible for ctx to be null since a window can be resized
271 * without a currently bound rendering context.
272 */
273 void
274 _mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
275 GLuint width, GLuint height)
276 {
277 GLuint i;
278
279 /* XXX I think we could check if the size is not changing
280 * and return early.
281 */
282
283 /* For window system framebuffers, Name is zero */
284 assert(fb->Name == 0);
285
286 for (i = 0; i < BUFFER_COUNT; i++) {
287 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
288 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
289 struct gl_renderbuffer *rb = att->Renderbuffer;
290 /* only resize if size is changing */
291 if (rb->Width != width || rb->Height != height) {
292 /* could just as well pass rb->_ActualFormat here */
293 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
294 ASSERT(rb->Width == width);
295 ASSERT(rb->Height == height);
296 }
297 else {
298 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
299 /* no return */
300 }
301 }
302 }
303 }
304
305 if (fb->_DepthBuffer) {
306 struct gl_renderbuffer *rb = fb->_DepthBuffer;
307 if (rb->Width != width || rb->Height != height) {
308 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
309 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
310 }
311 }
312 }
313
314 if (fb->_StencilBuffer) {
315 struct gl_renderbuffer *rb = fb->_StencilBuffer;
316 if (rb->Width != width || rb->Height != height) {
317 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
318 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
319 }
320 }
321 }
322
323 fb->Width = width;
324 fb->Height = height;
325
326 if (ctx) {
327 /* update scissor / window bounds */
328 _mesa_update_draw_buffer_bounds(ctx);
329 /* Signal new buffer state so that swrast will update its clipping
330 * info (the CLIP_BIT flag).
331 */
332 ctx->NewState |= _NEW_BUFFERS;
333 }
334 }
335
336
337 /**
338 * Examine all the framebuffer's renderbuffers to update the Width/Height
339 * fields of the framebuffer. If we have renderbuffers with different
340 * sizes, set the framebuffer's width and height to zero.
341 * Note: this is only intended for user-created framebuffers, not
342 * window-system framebuffes.
343 */
344 static void
345 update_framebuffer_size(struct gl_framebuffer *fb)
346 {
347 GLboolean haveSize = GL_FALSE;
348 GLuint i;
349
350 /* user-created framebuffers only */
351 assert(fb->Name);
352
353 for (i = 0; i < BUFFER_COUNT; i++) {
354 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
355 const struct gl_renderbuffer *rb = att->Renderbuffer;
356 if (rb) {
357 if (haveSize) {
358 if (rb->Width != fb->Width && rb->Height != fb->Height) {
359 /* size mismatch! */
360 fb->Width = 0;
361 fb->Height = 0;
362 return;
363 }
364 }
365 else {
366 fb->Width = rb->Width;
367 fb->Height = rb->Height;
368 haveSize = GL_TRUE;
369 }
370 }
371 }
372 }
373
374
375 /**
376 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
377 * These values are computed from the buffer's width and height and
378 * the scissor box, if it's enabled.
379 * \param ctx the GL context.
380 */
381 void
382 _mesa_update_draw_buffer_bounds(GLcontext *ctx)
383 {
384 struct gl_framebuffer *buffer = ctx->DrawBuffer;
385
386 if (!buffer)
387 return;
388
389 if (buffer->Name) {
390 /* user-created framebuffer size depends on the renderbuffers */
391 update_framebuffer_size(buffer);
392 }
393
394 buffer->_Xmin = 0;
395 buffer->_Ymin = 0;
396 buffer->_Xmax = buffer->Width;
397 buffer->_Ymax = buffer->Height;
398
399 if (ctx->Scissor.Enabled) {
400 if (ctx->Scissor.X > buffer->_Xmin) {
401 buffer->_Xmin = ctx->Scissor.X;
402 }
403 if (ctx->Scissor.Y > buffer->_Ymin) {
404 buffer->_Ymin = ctx->Scissor.Y;
405 }
406 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
407 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
408 }
409 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
410 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
411 }
412 /* finally, check for empty region */
413 if (buffer->_Xmin > buffer->_Xmax) {
414 buffer->_Xmin = buffer->_Xmax;
415 }
416 if (buffer->_Ymin > buffer->_Ymax) {
417 buffer->_Ymin = buffer->_Ymax;
418 }
419 }
420
421 ASSERT(buffer->_Xmin <= buffer->_Xmax);
422 ASSERT(buffer->_Ymin <= buffer->_Ymax);
423 }
424
425
426 /**
427 * The glGet queries of the framebuffer red/green/blue size, stencil size,
428 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
429 * change depending on the renderbuffer bindings. This function updates
430 * the given framebuffer's Visual from the current renderbuffer bindings.
431 *
432 * This may apply to user-created framebuffers or window system framebuffers.
433 *
434 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal
435 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits.
436 * The former one is used to convert floating point depth values into
437 * integer Z values.
438 */
439 void
440 _mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
441 {
442 GLuint i;
443
444 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
445 fb->Visual.rgbMode = GL_TRUE; /* assume this */
446
447 #if 0 /* this _might_ be needed */
448 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
449 /* leave visual fields zero'd */
450 return;
451 }
452 #endif
453
454 /* find first RGB or CI renderbuffer */
455 for (i = 0; i < BUFFER_COUNT; i++) {
456 if (fb->Attachment[i].Renderbuffer) {
457 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
458 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) {
459 fb->Visual.redBits = rb->RedBits;
460 fb->Visual.greenBits = rb->GreenBits;
461 fb->Visual.blueBits = rb->BlueBits;
462 fb->Visual.alphaBits = rb->AlphaBits;
463 fb->Visual.rgbBits = fb->Visual.redBits
464 + fb->Visual.greenBits + fb->Visual.blueBits;
465 fb->Visual.floatMode = GL_FALSE;
466 break;
467 }
468 else if (rb->_BaseFormat == GL_COLOR_INDEX) {
469 fb->Visual.indexBits = rb->IndexBits;
470 fb->Visual.rgbMode = GL_FALSE;
471 break;
472 }
473 }
474 }
475
476 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
477 fb->Visual.haveDepthBuffer = GL_TRUE;
478 fb->Visual.depthBits
479 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits;
480 }
481
482 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
483 fb->Visual.haveStencilBuffer = GL_TRUE;
484 fb->Visual.stencilBits
485 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits;
486 }
487
488 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) {
489 fb->Visual.haveAccumBuffer = GL_TRUE;
490 fb->Visual.accumRedBits
491 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits;
492 fb->Visual.accumGreenBits
493 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits;
494 fb->Visual.accumBlueBits
495 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits;
496 fb->Visual.accumAlphaBits
497 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits;
498 }
499
500 compute_depth_max(fb);
501 }
502
503
504 /**
505 * Update the framebuffer's _DepthBuffer field using the renderbuffer
506 * found at the given attachment index.
507 *
508 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
509 * create and install a depth wrapper/adaptor.
510 *
511 * \param fb the framebuffer whose _DepthBuffer field to update
512 * \param attIndex indicates the renderbuffer to possibly wrap
513 */
514 void
515 _mesa_update_depth_buffer(GLcontext *ctx,
516 struct gl_framebuffer *fb,
517 GLuint attIndex)
518 {
519 struct gl_renderbuffer *depthRb;
520
521 /* only one possiblity for now */
522 ASSERT(attIndex == BUFFER_DEPTH);
523
524 depthRb = fb->Attachment[attIndex].Renderbuffer;
525
526 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
527 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */
528 if (!fb->_DepthBuffer
529 || fb->_DepthBuffer->Wrapped != depthRb
530 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) {
531 /* need to update wrapper */
532 struct gl_renderbuffer *wrapper
533 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb);
534 _mesa_reference_renderbuffer(&fb->_DepthBuffer, wrapper);
535 ASSERT(fb->_DepthBuffer->Wrapped == depthRb);
536 }
537 }
538 else {
539 /* depthRb may be null */
540 _mesa_reference_renderbuffer(&fb->_DepthBuffer, depthRb);
541 }
542 }
543
544
545 /**
546 * Update the framebuffer's _StencilBuffer field using the renderbuffer
547 * found at the given attachment index.
548 *
549 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer,
550 * create and install a stencil wrapper/adaptor.
551 *
552 * \param fb the framebuffer whose _StencilBuffer field to update
553 * \param attIndex indicates the renderbuffer to possibly wrap
554 */
555 void
556 _mesa_update_stencil_buffer(GLcontext *ctx,
557 struct gl_framebuffer *fb,
558 GLuint attIndex)
559 {
560 struct gl_renderbuffer *stencilRb;
561
562 ASSERT(attIndex == BUFFER_DEPTH ||
563 attIndex == BUFFER_STENCIL);
564
565 stencilRb = fb->Attachment[attIndex].Renderbuffer;
566
567 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
568 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */
569 if (!fb->_StencilBuffer
570 || fb->_StencilBuffer->Wrapped != stencilRb
571 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) {
572 /* need to update wrapper */
573 struct gl_renderbuffer *wrapper
574 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb);
575 _mesa_reference_renderbuffer(&fb->_StencilBuffer, wrapper);
576 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb);
577 }
578 }
579 else {
580 /* stencilRb may be null */
581 _mesa_reference_renderbuffer(&fb->_StencilBuffer, stencilRb);
582 }
583 }
584
585
586 /**
587 * Update the (derived) list of color drawing renderbuffer pointers.
588 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
589 * writing colors.
590 */
591 static void
592 update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
593 {
594 GLuint output;
595
596 /*
597 * Fragment programs can write to multiple colorbuffers with
598 * the GL_ARB_draw_buffers extension.
599 */
600 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
601 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
602 GLuint count = 0;
603 GLuint i;
604 if (!fb->DeletePending) {
605 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK)
606 * can specify writing to two or four color buffers (for example).
607 */
608 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) {
609 const GLuint bufferBit = 1 << i;
610 if (bufferBit & bufferMask) {
611 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
612 if (rb && rb->Width > 0 && rb->Height > 0) {
613 fb->_ColorDrawBuffers[output][count] = rb;
614 count++;
615 }
616 else {
617 /*
618 _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n");
619 */
620 }
621 bufferMask &= ~bufferBit;
622 }
623 }
624 }
625 fb->_NumColorDrawBuffers[output] = count;
626 }
627 }
628
629
630 /**
631 * Update the (derived) color read renderbuffer pointer.
632 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
633 */
634 static void
635 update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb)
636 {
637 (void) ctx;
638 if (fb->_ColorReadBufferIndex == -1 ||
639 fb->DeletePending ||
640 fb->Width == 0 ||
641 fb->Height == 0) {
642 fb->_ColorReadBuffer = NULL; /* legal! */
643 }
644 else {
645 ASSERT(fb->_ColorReadBufferIndex >= 0);
646 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT);
647 fb->_ColorReadBuffer
648 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
649 }
650 }
651
652
653 /**
654 * Update a gl_framebuffer's derived state.
655 *
656 * Specifically, update these framebuffer fields:
657 * _ColorDrawBuffers
658 * _NumColorDrawBuffers
659 * _ColorReadBuffer
660 * _DepthBuffer
661 * _StencilBuffer
662 *
663 * If the framebuffer is user-created, make sure it's complete.
664 *
665 * The following functions (at least) can effect framebuffer state:
666 * glReadBuffer, glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT,
667 * glRenderbufferStorageEXT.
668 */
669 static void
670 update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
671 {
672 if (fb->Name == 0) {
673 /* This is a window-system framebuffer */
674 /* Need to update the FB's GL_DRAW_BUFFER state to match the
675 * context state (GL_READ_BUFFER too).
676 */
677 if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) {
678 _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers,
679 ctx->Color.DrawBuffer, NULL);
680 }
681 if (fb->ColorReadBuffer != ctx->Pixel.ReadBuffer) {
682
683 }
684 }
685 else {
686 /* This is a user-created framebuffer.
687 * Completeness only matters for user-created framebuffers.
688 */
689 _mesa_test_framebuffer_completeness(ctx, fb);
690 _mesa_update_framebuffer_visual(fb);
691 }
692
693 /* Strictly speaking, we don't need to update the draw-state
694 * if this FB is bound as ctx->ReadBuffer (and conversely, the
695 * read-state if this FB is bound as ctx->DrawBuffer), but no
696 * harm.
697 */
698 update_color_draw_buffers(ctx, fb);
699 update_color_read_buffer(ctx, fb);
700 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
701 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
702
703 compute_depth_max(fb);
704 }
705
706
707 /**
708 * Update state related to the current draw/read framebuffers.
709 */
710 void
711 _mesa_update_framebuffer(GLcontext *ctx)
712 {
713 struct gl_framebuffer *drawFb = ctx->DrawBuffer;
714 struct gl_framebuffer *readFb = ctx->ReadBuffer;
715
716 update_framebuffer(ctx, drawFb);
717 if (readFb != drawFb)
718 update_framebuffer(ctx, readFb);
719 }
720
721
722 /**
723 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels,
724 * glCopyTex[Sub]Image, etc. exists.
725 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA,
726 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL.
727 * \return GL_TRUE if buffer exists, GL_FALSE otherwise
728 */
729 GLboolean
730 _mesa_source_buffer_exists(GLcontext *ctx, GLenum format)
731 {
732 const struct gl_renderbuffer_attachment *att
733 = ctx->ReadBuffer->Attachment;
734
735 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
736 return GL_FALSE;
737 }
738
739 switch (format) {
740 case GL_COLOR:
741 case GL_RED:
742 case GL_GREEN:
743 case GL_BLUE:
744 case GL_ALPHA:
745 case GL_LUMINANCE:
746 case GL_LUMINANCE_ALPHA:
747 case GL_INTENSITY:
748 case GL_RGB:
749 case GL_BGR:
750 case GL_RGBA:
751 case GL_BGRA:
752 case GL_ABGR_EXT:
753 case GL_COLOR_INDEX:
754 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) {
755 return GL_FALSE;
756 }
757 /* XXX enable this post 6.5 release:
758 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 ||
759 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0);
760 */
761 break;
762 case GL_DEPTH:
763 case GL_DEPTH_COMPONENT:
764 if (!att[BUFFER_DEPTH].Renderbuffer) {
765 return GL_FALSE;
766 }
767 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
768 break;
769 case GL_STENCIL:
770 case GL_STENCIL_INDEX:
771 if (!att[BUFFER_STENCIL].Renderbuffer) {
772 return GL_FALSE;
773 }
774 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
775 break;
776 case GL_DEPTH_STENCIL_EXT:
777 if (!att[BUFFER_DEPTH].Renderbuffer ||
778 !att[BUFFER_STENCIL].Renderbuffer) {
779 return GL_FALSE;
780 }
781 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
782 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
783 break;
784 default:
785 _mesa_problem(ctx,
786 "Unexpected format 0x%x in _mesa_source_buffer_exists",
787 format);
788 return GL_FALSE;
789 }
790
791 /* OK */
792 return GL_TRUE;
793 }
794
795
796 /**
797 * As above, but for drawing operations.
798 * XXX code do some code merging w/ above function.
799 */
800 GLboolean
801 _mesa_dest_buffer_exists(GLcontext *ctx, GLenum format)
802 {
803 const struct gl_renderbuffer_attachment *att
804 = ctx->ReadBuffer->Attachment;
805
806 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
807 return GL_FALSE;
808 }
809
810 switch (format) {
811 case GL_COLOR:
812 case GL_RED:
813 case GL_GREEN:
814 case GL_BLUE:
815 case GL_ALPHA:
816 case GL_LUMINANCE:
817 case GL_LUMINANCE_ALPHA:
818 case GL_INTENSITY:
819 case GL_RGB:
820 case GL_BGR:
821 case GL_RGBA:
822 case GL_BGRA:
823 case GL_ABGR_EXT:
824 case GL_COLOR_INDEX:
825 /* nothing special */
826 /* Could assert that colorbuffer has RedBits > 0 */
827 break;
828 case GL_DEPTH:
829 case GL_DEPTH_COMPONENT:
830 if (!att[BUFFER_DEPTH].Renderbuffer) {
831 return GL_FALSE;
832 }
833 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
834 break;
835 case GL_STENCIL:
836 case GL_STENCIL_INDEX:
837 if (!att[BUFFER_STENCIL].Renderbuffer) {
838 return GL_FALSE;
839 }
840 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
841 break;
842 case GL_DEPTH_STENCIL_EXT:
843 if (!att[BUFFER_DEPTH].Renderbuffer ||
844 !att[BUFFER_STENCIL].Renderbuffer) {
845 return GL_FALSE;
846 }
847 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);
848 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);
849 break;
850 default:
851 _mesa_problem(ctx,
852 "Unexpected format 0x%x in _mesa_source_buffer_exists",
853 format);
854 return GL_FALSE;
855 }
856
857 /* OK */
858 return GL_TRUE;
859 }