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