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