fbobject.c revision 6e618535901ac71a74ffb80d3da7c841a82eec02
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6 * Copyright (C) 1999-2009  VMware, Inc.  All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27/*
28 * GL_EXT/ARB_framebuffer_object extensions
29 *
30 * Authors:
31 *   Brian Paul
32 */
33
34
35#include "buffers.h"
36#include "context.h"
37#include "enums.h"
38#include "fbobject.h"
39#include "formats.h"
40#include "framebuffer.h"
41#include "hash.h"
42#include "macros.h"
43#include "renderbuffer.h"
44#include "state.h"
45#include "teximage.h"
46#include "texobj.h"
47
48
49/** Set this to 1 to help debug FBO incompleteness problems */
50#define DEBUG_FBO 0
51
52/** Set this to 1 to debug/log glBlitFramebuffer() calls */
53#define DEBUG_BLIT 0
54
55
56/**
57 * Notes:
58 *
59 * None of the GL_EXT_framebuffer_object functions are compiled into
60 * display lists.
61 */
62
63
64
65/*
66 * When glGenRender/FramebuffersEXT() is called we insert pointers to
67 * these placeholder objects into the hash table.
68 * Later, when the object ID is first bound, we replace the placeholder
69 * with the real frame/renderbuffer.
70 */
71static struct gl_framebuffer DummyFramebuffer;
72static struct gl_renderbuffer DummyRenderbuffer;
73
74/* We bind this framebuffer when applications pass a NULL
75 * drawable/surface in make current. */
76static struct gl_framebuffer IncompleteFramebuffer;
77
78
79#define IS_CUBE_FACE(TARGET) \
80   ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
81    (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
82
83
84static void
85delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
86{
87   /* no op */
88}
89
90static void
91delete_dummy_framebuffer(struct gl_framebuffer *fb)
92{
93   /* no op */
94}
95
96
97void
98_mesa_init_fbobjects(struct gl_context *ctx)
99{
100   _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
101   _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
102   _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex);
103   DummyFramebuffer.Delete = delete_dummy_framebuffer;
104   DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
105   IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
106}
107
108struct gl_framebuffer *
109_mesa_get_incomplete_framebuffer(void)
110{
111   return &IncompleteFramebuffer;
112}
113
114/**
115 * Helper routine for getting a gl_renderbuffer.
116 */
117struct gl_renderbuffer *
118_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
119{
120   struct gl_renderbuffer *rb;
121
122   if (id == 0)
123      return NULL;
124
125   rb = (struct gl_renderbuffer *)
126      _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
127   return rb;
128}
129
130
131/**
132 * Helper routine for getting a gl_framebuffer.
133 */
134struct gl_framebuffer *
135_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
136{
137   struct gl_framebuffer *fb;
138
139   if (id == 0)
140      return NULL;
141
142   fb = (struct gl_framebuffer *)
143      _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
144   return fb;
145}
146
147
148/**
149 * Mark the given framebuffer as invalid.  This will force the
150 * test for framebuffer completeness to be done before the framebuffer
151 * is used.
152 */
153static void
154invalidate_framebuffer(struct gl_framebuffer *fb)
155{
156   fb->_Status = 0; /* "indeterminate" */
157}
158
159
160/**
161 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
162 * gl_renderbuffer_attachment object.
163 * This function is only used for user-created FB objects, not the
164 * default / window-system FB object.
165 * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
166 * the depth buffer attachment point.
167 */
168struct gl_renderbuffer_attachment *
169_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
170                     GLenum attachment)
171{
172   GLuint i;
173
174   assert(fb->Name > 0);
175
176   switch (attachment) {
177   case GL_COLOR_ATTACHMENT0_EXT:
178   case GL_COLOR_ATTACHMENT1_EXT:
179   case GL_COLOR_ATTACHMENT2_EXT:
180   case GL_COLOR_ATTACHMENT3_EXT:
181   case GL_COLOR_ATTACHMENT4_EXT:
182   case GL_COLOR_ATTACHMENT5_EXT:
183   case GL_COLOR_ATTACHMENT6_EXT:
184   case GL_COLOR_ATTACHMENT7_EXT:
185   case GL_COLOR_ATTACHMENT8_EXT:
186   case GL_COLOR_ATTACHMENT9_EXT:
187   case GL_COLOR_ATTACHMENT10_EXT:
188   case GL_COLOR_ATTACHMENT11_EXT:
189   case GL_COLOR_ATTACHMENT12_EXT:
190   case GL_COLOR_ATTACHMENT13_EXT:
191   case GL_COLOR_ATTACHMENT14_EXT:
192   case GL_COLOR_ATTACHMENT15_EXT:
193      i = attachment - GL_COLOR_ATTACHMENT0_EXT;
194      if (i >= ctx->Const.MaxColorAttachments) {
195	 return NULL;
196      }
197      return &fb->Attachment[BUFFER_COLOR0 + i];
198   case GL_DEPTH_STENCIL_ATTACHMENT:
199      /* fall-through */
200   case GL_DEPTH_BUFFER:
201      /* fall-through / new in GL 3.0 */
202   case GL_DEPTH_ATTACHMENT_EXT:
203      return &fb->Attachment[BUFFER_DEPTH];
204   case GL_STENCIL_BUFFER:
205      /* fall-through / new in GL 3.0 */
206   case GL_STENCIL_ATTACHMENT_EXT:
207      return &fb->Attachment[BUFFER_STENCIL];
208   default:
209      return NULL;
210   }
211}
212
213
214/**
215 * As above, but only used for getting attachments of the default /
216 * window-system framebuffer (not user-created framebuffer objects).
217 */
218static struct gl_renderbuffer_attachment *
219_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
220                         GLenum attachment)
221{
222   assert(fb->Name == 0);
223
224   switch (attachment) {
225   case GL_FRONT_LEFT:
226      return &fb->Attachment[BUFFER_FRONT_LEFT];
227   case GL_FRONT_RIGHT:
228      return &fb->Attachment[BUFFER_FRONT_RIGHT];
229   case GL_BACK_LEFT:
230      return &fb->Attachment[BUFFER_BACK_LEFT];
231   case GL_BACK_RIGHT:
232      return &fb->Attachment[BUFFER_BACK_RIGHT];
233   case GL_AUX0:
234      if (fb->Visual.numAuxBuffers == 1) {
235         return &fb->Attachment[BUFFER_AUX0];
236      }
237      return NULL;
238   case GL_DEPTH_BUFFER:
239      /* fall-through / new in GL 3.0 */
240   case GL_DEPTH_ATTACHMENT_EXT:
241      return &fb->Attachment[BUFFER_DEPTH];
242   case GL_STENCIL_BUFFER:
243      /* fall-through / new in GL 3.0 */
244   case GL_STENCIL_ATTACHMENT_EXT:
245      return &fb->Attachment[BUFFER_STENCIL];
246   default:
247      return NULL;
248   }
249}
250
251
252
253/**
254 * Remove any texture or renderbuffer attached to the given attachment
255 * point.  Update reference counts, etc.
256 */
257void
258_mesa_remove_attachment(struct gl_context *ctx,
259                        struct gl_renderbuffer_attachment *att)
260{
261   if (att->Type == GL_TEXTURE) {
262      ASSERT(att->Texture);
263      if (ctx->Driver.FinishRenderTexture) {
264         /* tell driver that we're done rendering to this texture. */
265         ctx->Driver.FinishRenderTexture(ctx, att);
266      }
267      _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
268      ASSERT(!att->Texture);
269   }
270   if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
271      ASSERT(!att->Texture);
272      _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
273      ASSERT(!att->Renderbuffer);
274   }
275   att->Type = GL_NONE;
276   att->Complete = GL_TRUE;
277}
278
279
280/**
281 * Bind a texture object to an attachment point.
282 * The previous binding, if any, will be removed first.
283 */
284void
285_mesa_set_texture_attachment(struct gl_context *ctx,
286                             struct gl_framebuffer *fb,
287                             struct gl_renderbuffer_attachment *att,
288                             struct gl_texture_object *texObj,
289                             GLenum texTarget, GLuint level, GLuint zoffset)
290{
291   if (att->Texture == texObj) {
292      /* re-attaching same texture */
293      ASSERT(att->Type == GL_TEXTURE);
294      if (ctx->Driver.FinishRenderTexture)
295	 ctx->Driver.FinishRenderTexture(ctx, att);
296   }
297   else {
298      /* new attachment */
299      if (ctx->Driver.FinishRenderTexture && att->Texture)
300	 ctx->Driver.FinishRenderTexture(ctx, att);
301      _mesa_remove_attachment(ctx, att);
302      att->Type = GL_TEXTURE;
303      assert(!att->Texture);
304      _mesa_reference_texobj(&att->Texture, texObj);
305   }
306
307   /* always update these fields */
308   att->TextureLevel = level;
309   att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
310   att->Zoffset = zoffset;
311   att->Complete = GL_FALSE;
312
313   if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
314      ctx->Driver.RenderTexture(ctx, fb, att);
315   }
316
317   invalidate_framebuffer(fb);
318}
319
320
321/**
322 * Bind a renderbuffer to an attachment point.
323 * The previous binding, if any, will be removed first.
324 */
325void
326_mesa_set_renderbuffer_attachment(struct gl_context *ctx,
327                                  struct gl_renderbuffer_attachment *att,
328                                  struct gl_renderbuffer *rb)
329{
330   /* XXX check if re-doing same attachment, exit early */
331   _mesa_remove_attachment(ctx, att);
332   att->Type = GL_RENDERBUFFER_EXT;
333   att->Texture = NULL; /* just to be safe */
334   att->Complete = GL_FALSE;
335   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
336}
337
338
339/**
340 * Fallback for ctx->Driver.FramebufferRenderbuffer()
341 * Attach a renderbuffer object to a framebuffer object.
342 */
343void
344_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
345                               struct gl_framebuffer *fb,
346                               GLenum attachment, struct gl_renderbuffer *rb)
347{
348   struct gl_renderbuffer_attachment *att;
349
350   _glthread_LOCK_MUTEX(fb->Mutex);
351
352   att = _mesa_get_attachment(ctx, fb, attachment);
353   ASSERT(att);
354   if (rb) {
355      _mesa_set_renderbuffer_attachment(ctx, att, rb);
356      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
357         /* do stencil attachment here (depth already done above) */
358         att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
359         assert(att);
360         _mesa_set_renderbuffer_attachment(ctx, att, rb);
361      }
362   }
363   else {
364      _mesa_remove_attachment(ctx, att);
365   }
366
367   invalidate_framebuffer(fb);
368
369   _glthread_UNLOCK_MUTEX(fb->Mutex);
370}
371
372
373/**
374 * For debug only.
375 */
376static void
377att_incomplete(const char *msg)
378{
379#if DEBUG_FBO
380   _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
381#else
382   (void) msg;
383#endif
384}
385
386
387/**
388 * For debug only.
389 */
390static void
391fbo_incomplete(const char *msg, int index)
392{
393#if DEBUG_FBO
394   _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
395#else
396   (void) msg;
397   (void) index;
398#endif
399}
400
401
402/**
403 * Is the given base format a legal format for a color renderbuffer?
404 */
405static GLboolean
406is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
407{
408   switch (baseFormat) {
409   case GL_RGB:
410   case GL_RGBA:
411      return GL_TRUE;
412   case GL_LUMINANCE:
413   case GL_LUMINANCE_ALPHA:
414   case GL_INTENSITY:
415   case GL_ALPHA:
416      return ctx->Extensions.ARB_framebuffer_object;
417   case GL_RED:
418   case GL_RG:
419      return ctx->Extensions.ARB_texture_rg;
420   default:
421      return GL_FALSE;
422   }
423}
424
425
426/**
427 * Is the given base format a legal format for a depth/stencil renderbuffer?
428 */
429static GLboolean
430is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
431{
432   switch (baseFormat) {
433   case GL_DEPTH_COMPONENT:
434   case GL_DEPTH_STENCIL_EXT:
435      return GL_TRUE;
436   default:
437      return GL_FALSE;
438   }
439}
440
441
442/**
443 * Test if an attachment point is complete and update its Complete field.
444 * \param format if GL_COLOR, this is a color attachment point,
445 *               if GL_DEPTH, this is a depth component attachment point,
446 *               if GL_STENCIL, this is a stencil component attachment point.
447 */
448static void
449test_attachment_completeness(const struct gl_context *ctx, GLenum format,
450                             struct gl_renderbuffer_attachment *att)
451{
452   assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
453
454   /* assume complete */
455   att->Complete = GL_TRUE;
456
457   /* Look for reasons why the attachment might be incomplete */
458   if (att->Type == GL_TEXTURE) {
459      const struct gl_texture_object *texObj = att->Texture;
460      struct gl_texture_image *texImage;
461      GLenum baseFormat;
462
463      if (!texObj) {
464         att_incomplete("no texobj");
465         att->Complete = GL_FALSE;
466         return;
467      }
468
469      texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
470      if (!texImage) {
471         att_incomplete("no teximage");
472         att->Complete = GL_FALSE;
473         return;
474      }
475      if (texImage->Width < 1 || texImage->Height < 1) {
476         att_incomplete("teximage width/height=0");
477         printf("texobj = %u\n", texObj->Name);
478         printf("level = %d\n", att->TextureLevel);
479         att->Complete = GL_FALSE;
480         return;
481      }
482      if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
483         att_incomplete("bad z offset");
484         att->Complete = GL_FALSE;
485         return;
486      }
487
488      baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
489
490      if (format == GL_COLOR) {
491         if (!is_legal_color_format(ctx, baseFormat)) {
492            att_incomplete("bad format");
493            att->Complete = GL_FALSE;
494            return;
495         }
496         if (_mesa_is_format_compressed(texImage->TexFormat)) {
497            att_incomplete("compressed internalformat");
498            att->Complete = GL_FALSE;
499            return;
500         }
501      }
502      else if (format == GL_DEPTH) {
503         if (baseFormat == GL_DEPTH_COMPONENT) {
504            /* OK */
505         }
506         else if (ctx->Extensions.EXT_packed_depth_stencil &&
507                  ctx->Extensions.ARB_depth_texture &&
508                  baseFormat == GL_DEPTH_STENCIL_EXT) {
509            /* OK */
510         }
511         else {
512            att->Complete = GL_FALSE;
513            att_incomplete("bad depth format");
514            return;
515         }
516      }
517      else {
518         ASSERT(format == GL_STENCIL);
519         if (ctx->Extensions.EXT_packed_depth_stencil &&
520             ctx->Extensions.ARB_depth_texture &&
521             baseFormat == GL_DEPTH_STENCIL_EXT) {
522            /* OK */
523         }
524         else {
525            /* no such thing as stencil-only textures */
526            att_incomplete("illegal stencil texture");
527            att->Complete = GL_FALSE;
528            return;
529         }
530      }
531   }
532   else if (att->Type == GL_RENDERBUFFER_EXT) {
533      const GLenum baseFormat =
534         _mesa_get_format_base_format(att->Renderbuffer->Format);
535
536      ASSERT(att->Renderbuffer);
537      if (!att->Renderbuffer->InternalFormat ||
538          att->Renderbuffer->Width < 1 ||
539          att->Renderbuffer->Height < 1) {
540         att_incomplete("0x0 renderbuffer");
541         att->Complete = GL_FALSE;
542         return;
543      }
544      if (format == GL_COLOR) {
545         if (baseFormat != GL_RGB &&
546             baseFormat != GL_RGBA) {
547            att_incomplete("bad renderbuffer color format");
548            att->Complete = GL_FALSE;
549            return;
550         }
551      }
552      else if (format == GL_DEPTH) {
553         if (baseFormat == GL_DEPTH_COMPONENT) {
554            /* OK */
555         }
556         else if (ctx->Extensions.EXT_packed_depth_stencil &&
557                  baseFormat == GL_DEPTH_STENCIL_EXT) {
558            /* OK */
559         }
560         else {
561            att_incomplete("bad renderbuffer depth format");
562            att->Complete = GL_FALSE;
563            return;
564         }
565      }
566      else {
567         assert(format == GL_STENCIL);
568         if (baseFormat == GL_STENCIL_INDEX) {
569            /* OK */
570         }
571         else if (ctx->Extensions.EXT_packed_depth_stencil &&
572                  baseFormat == GL_DEPTH_STENCIL_EXT) {
573            /* OK */
574         }
575         else {
576            att->Complete = GL_FALSE;
577            att_incomplete("bad renderbuffer stencil format");
578            return;
579         }
580      }
581   }
582   else {
583      ASSERT(att->Type == GL_NONE);
584      /* complete */
585      return;
586   }
587}
588
589
590/**
591 * Test if the given framebuffer object is complete and update its
592 * Status field with the results.
593 * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
594 * driver to make hardware-specific validation/completeness checks.
595 * Also update the framebuffer's Width and Height fields if the
596 * framebuffer is complete.
597 */
598void
599_mesa_test_framebuffer_completeness(struct gl_context *ctx,
600                                    struct gl_framebuffer *fb)
601{
602   GLuint numImages;
603   GLenum intFormat = GL_NONE; /* color buffers' internal format */
604   GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
605   GLint numSamples = -1;
606   GLint i;
607   GLuint j;
608
609   assert(fb->Name != 0);
610
611   numImages = 0;
612   fb->Width = 0;
613   fb->Height = 0;
614
615   /* Start at -2 to more easily loop over all attachment points.
616    *  -2: depth buffer
617    *  -1: stencil buffer
618    * >=0: color buffer
619    */
620   for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
621      struct gl_renderbuffer_attachment *att;
622      GLenum f;
623      gl_format mesaFormat;
624
625      /*
626       * XXX for ARB_fbo, only check color buffers that are named by
627       * GL_READ_BUFFER and GL_DRAW_BUFFERi.
628       */
629
630      /* check for attachment completeness
631       */
632      if (i == -2) {
633         att = &fb->Attachment[BUFFER_DEPTH];
634         test_attachment_completeness(ctx, GL_DEPTH, att);
635         if (!att->Complete) {
636            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
637            fbo_incomplete("depth attachment incomplete", -1);
638            return;
639         }
640      }
641      else if (i == -1) {
642         att = &fb->Attachment[BUFFER_STENCIL];
643         test_attachment_completeness(ctx, GL_STENCIL, att);
644         if (!att->Complete) {
645            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
646            fbo_incomplete("stencil attachment incomplete", -1);
647            return;
648         }
649      }
650      else {
651         att = &fb->Attachment[BUFFER_COLOR0 + i];
652         test_attachment_completeness(ctx, GL_COLOR, att);
653         if (!att->Complete) {
654            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
655            fbo_incomplete("color attachment incomplete", i);
656            return;
657         }
658      }
659
660      /* get width, height, format of the renderbuffer/texture
661       */
662      if (att->Type == GL_TEXTURE) {
663         const struct gl_texture_image *texImg
664            = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
665         minWidth = MIN2(minWidth, texImg->Width);
666         maxWidth = MAX2(maxWidth, texImg->Width);
667         minHeight = MIN2(minHeight, texImg->Height);
668         maxHeight = MAX2(maxHeight, texImg->Height);
669         f = texImg->_BaseFormat;
670         mesaFormat = texImg->TexFormat;
671         numImages++;
672         if (!is_legal_color_format(ctx, f) &&
673             !is_legal_depth_format(ctx, f)) {
674            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
675            fbo_incomplete("texture attachment incomplete", -1);
676            return;
677         }
678      }
679      else if (att->Type == GL_RENDERBUFFER_EXT) {
680         minWidth = MIN2(minWidth, att->Renderbuffer->Width);
681         maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
682         minHeight = MIN2(minHeight, att->Renderbuffer->Height);
683         maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
684         f = att->Renderbuffer->InternalFormat;
685         mesaFormat = att->Renderbuffer->Format;
686         numImages++;
687      }
688      else {
689         assert(att->Type == GL_NONE);
690         continue;
691      }
692
693      if (numSamples < 0) {
694         /* first buffer */
695         numSamples = att->Renderbuffer->NumSamples;
696      }
697
698      /* check if integer color */
699      fb->_IntegerColor = _mesa_is_format_integer(mesaFormat);
700
701      /* Error-check width, height, format, samples
702       */
703      if (numImages == 1) {
704         /* save format, num samples */
705         if (i >= 0) {
706            intFormat = f;
707         }
708      }
709      else {
710         if (!ctx->Extensions.ARB_framebuffer_object) {
711            /* check that width, height, format are same */
712            if (minWidth != maxWidth || minHeight != maxHeight) {
713               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
714               fbo_incomplete("width or height mismatch", -1);
715               return;
716            }
717            /* check that all color buffer have same format */
718            if (intFormat != GL_NONE && f != intFormat) {
719               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
720               fbo_incomplete("format mismatch", -1);
721               return;
722            }
723         }
724         if (att->Renderbuffer &&
725             att->Renderbuffer->NumSamples != numSamples) {
726            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
727            fbo_incomplete("inconsistant number of samples", i);
728            return;
729         }
730
731      }
732   }
733
734#if FEATURE_GL
735   if (ctx->API == API_OPENGL) {
736      /* Check that all DrawBuffers are present */
737      for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
738	 if (fb->ColorDrawBuffer[j] != GL_NONE) {
739	    const struct gl_renderbuffer_attachment *att
740	       = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
741	    assert(att);
742	    if (att->Type == GL_NONE) {
743	       fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
744	       fbo_incomplete("missing drawbuffer", j);
745	       return;
746	    }
747	 }
748      }
749
750      /* Check that the ReadBuffer is present */
751      if (fb->ColorReadBuffer != GL_NONE) {
752	 const struct gl_renderbuffer_attachment *att
753	    = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
754	 assert(att);
755	 if (att->Type == GL_NONE) {
756	    fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
757            fbo_incomplete("missing readbuffer", -1);
758	    return;
759	 }
760      }
761   }
762#else
763   (void) j;
764#endif
765
766   if (numImages == 0) {
767      fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
768      fbo_incomplete("no attachments", -1);
769      return;
770   }
771
772   /* Provisionally set status = COMPLETE ... */
773   fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
774
775   /* ... but the driver may say the FB is incomplete.
776    * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
777    * if anything.
778    */
779   if (ctx->Driver.ValidateFramebuffer) {
780      ctx->Driver.ValidateFramebuffer(ctx, fb);
781      if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
782         fbo_incomplete("driver marked FBO as incomplete", -1);
783      }
784   }
785
786   if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
787      /*
788       * Note that if ARB_framebuffer_object is supported and the attached
789       * renderbuffers/textures are different sizes, the framebuffer
790       * width/height will be set to the smallest width/height.
791       */
792      fb->Width = minWidth;
793      fb->Height = minHeight;
794
795      /* finally, update the visual info for the framebuffer */
796      _mesa_update_framebuffer_visual(fb);
797   }
798}
799
800
801GLboolean GLAPIENTRY
802_mesa_IsRenderbufferEXT(GLuint renderbuffer)
803{
804   GET_CURRENT_CONTEXT(ctx);
805   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
806   if (renderbuffer) {
807      struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
808      if (rb != NULL && rb != &DummyRenderbuffer)
809         return GL_TRUE;
810   }
811   return GL_FALSE;
812}
813
814
815void GLAPIENTRY
816_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
817{
818   struct gl_renderbuffer *newRb;
819   GET_CURRENT_CONTEXT(ctx);
820
821   ASSERT_OUTSIDE_BEGIN_END(ctx);
822
823   if (target != GL_RENDERBUFFER_EXT) {
824      _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
825      return;
826   }
827
828   /* No need to flush here since the render buffer binding has no
829    * effect on rendering state.
830    */
831
832   if (renderbuffer) {
833      newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
834      if (newRb == &DummyRenderbuffer) {
835         /* ID was reserved, but no real renderbuffer object made yet */
836         newRb = NULL;
837      }
838      else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
839         /* All RB IDs must be Gen'd */
840         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
841         return;
842      }
843
844      if (!newRb) {
845	 /* create new renderbuffer object */
846	 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
847	 if (!newRb) {
848	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
849	    return;
850	 }
851         ASSERT(newRb->AllocStorage);
852         _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
853         newRb->RefCount = 1; /* referenced by hash table */
854      }
855   }
856   else {
857      newRb = NULL;
858   }
859
860   ASSERT(newRb != &DummyRenderbuffer);
861
862   _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
863}
864
865
866/**
867 * If the given renderbuffer is anywhere attached to the framebuffer, detach
868 * the renderbuffer.
869 * This is used when a renderbuffer object is deleted.
870 * The spec calls for unbinding.
871 */
872static void
873detach_renderbuffer(struct gl_context *ctx,
874                    struct gl_framebuffer *fb,
875                    struct gl_renderbuffer *rb)
876{
877   GLuint i;
878   for (i = 0; i < BUFFER_COUNT; i++) {
879      if (fb->Attachment[i].Renderbuffer == rb) {
880         _mesa_remove_attachment(ctx, &fb->Attachment[i]);
881      }
882   }
883   invalidate_framebuffer(fb);
884}
885
886
887void GLAPIENTRY
888_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
889{
890   GLint i;
891   GET_CURRENT_CONTEXT(ctx);
892
893   ASSERT_OUTSIDE_BEGIN_END(ctx);
894   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
895
896   for (i = 0; i < n; i++) {
897      if (renderbuffers[i] > 0) {
898	 struct gl_renderbuffer *rb;
899	 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
900	 if (rb) {
901            /* check if deleting currently bound renderbuffer object */
902            if (rb == ctx->CurrentRenderbuffer) {
903               /* bind default */
904               ASSERT(rb->RefCount >= 2);
905               _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
906            }
907
908            if (ctx->DrawBuffer->Name) {
909               detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
910            }
911            if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) {
912               detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
913            }
914
915	    /* Remove from hash table immediately, to free the ID.
916             * But the object will not be freed until it's no longer
917             * referenced anywhere else.
918             */
919	    _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
920
921            if (rb != &DummyRenderbuffer) {
922               /* no longer referenced by hash table */
923               _mesa_reference_renderbuffer(&rb, NULL);
924	    }
925	 }
926      }
927   }
928}
929
930
931void GLAPIENTRY
932_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
933{
934   GET_CURRENT_CONTEXT(ctx);
935   GLuint first;
936   GLint i;
937
938   ASSERT_OUTSIDE_BEGIN_END(ctx);
939
940   if (n < 0) {
941      _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
942      return;
943   }
944
945   if (!renderbuffers)
946      return;
947
948   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
949
950   for (i = 0; i < n; i++) {
951      GLuint name = first + i;
952      renderbuffers[i] = name;
953      /* insert dummy placeholder into hash table */
954      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
955      _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
956      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
957   }
958}
959
960
961/**
962 * Given an internal format token for a render buffer, return the
963 * corresponding base format.
964 * This is very similar to _mesa_base_tex_format() but the set of valid
965 * internal formats is somewhat different.
966 *
967 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
968 *  GL_DEPTH_STENCIL_EXT or zero if error.
969 *
970 * XXX in the future when we support red-only and red-green formats
971 * we'll also return GL_RED and GL_RG.
972 */
973GLenum
974_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
975{
976   switch (internalFormat) {
977   case GL_ALPHA:
978   case GL_ALPHA4:
979   case GL_ALPHA8:
980   case GL_ALPHA12:
981   case GL_ALPHA16:
982      return GL_ALPHA;
983   case GL_RGB:
984   case GL_R3_G3_B2:
985   case GL_RGB4:
986   case GL_RGB5:
987   case GL_RGB8:
988   case GL_RGB10:
989   case GL_RGB12:
990   case GL_RGB16:
991      return GL_RGB;
992   case GL_RGBA:
993   case GL_RGBA2:
994   case GL_RGBA4:
995   case GL_RGB5_A1:
996   case GL_RGBA8:
997   case GL_RGB10_A2:
998   case GL_RGBA12:
999   case GL_RGBA16:
1000   case GL_RGBA16_SNORM:
1001      return GL_RGBA;
1002   case GL_STENCIL_INDEX:
1003   case GL_STENCIL_INDEX1_EXT:
1004   case GL_STENCIL_INDEX4_EXT:
1005   case GL_STENCIL_INDEX8_EXT:
1006   case GL_STENCIL_INDEX16_EXT:
1007      return GL_STENCIL_INDEX;
1008   case GL_DEPTH_COMPONENT:
1009   case GL_DEPTH_COMPONENT16:
1010   case GL_DEPTH_COMPONENT24:
1011   case GL_DEPTH_COMPONENT32:
1012      return GL_DEPTH_COMPONENT;
1013   case GL_DEPTH_STENCIL_EXT:
1014   case GL_DEPTH24_STENCIL8_EXT:
1015      if (ctx->Extensions.EXT_packed_depth_stencil)
1016         return GL_DEPTH_STENCIL_EXT;
1017      else
1018         return 0;
1019   /* XXX add floating point formats eventually */
1020   default:
1021      return 0;
1022   }
1023}
1024
1025
1026/** sentinal value, see below */
1027#define NO_SAMPLES 1000
1028
1029
1030/**
1031 * Helper function used by _mesa_RenderbufferStorageEXT() and
1032 * _mesa_RenderbufferStorageMultisample().
1033 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
1034 */
1035static void
1036renderbuffer_storage(GLenum target, GLenum internalFormat,
1037                     GLsizei width, GLsizei height, GLsizei samples)
1038{
1039   const char *func = samples == NO_SAMPLES ?
1040      "glRenderbufferStorage" : "RenderbufferStorageMultisample";
1041   struct gl_renderbuffer *rb;
1042   GLenum baseFormat;
1043   GET_CURRENT_CONTEXT(ctx);
1044
1045   ASSERT_OUTSIDE_BEGIN_END(ctx);
1046
1047   if (target != GL_RENDERBUFFER_EXT) {
1048      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
1049      return;
1050   }
1051
1052   baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
1053   if (baseFormat == 0) {
1054      _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
1055      return;
1056   }
1057
1058   if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
1059      _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
1060      return;
1061   }
1062
1063   if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
1064      _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
1065      return;
1066   }
1067
1068   if (samples == NO_SAMPLES) {
1069      /* NumSamples == 0 indicates non-multisampling */
1070      samples = 0;
1071   }
1072   else if (samples > (GLsizei) ctx->Const.MaxSamples) {
1073      /* note: driver may choose to use more samples than what's requested */
1074      _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
1075      return;
1076   }
1077
1078   rb = ctx->CurrentRenderbuffer;
1079   if (!rb) {
1080      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
1081      return;
1082   }
1083
1084   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1085
1086   if (rb->InternalFormat == internalFormat &&
1087       rb->Width == (GLuint) width &&
1088       rb->Height == (GLuint) height) {
1089      /* no change in allocation needed */
1090      return;
1091   }
1092
1093   /* These MUST get set by the AllocStorage func */
1094   rb->Format = MESA_FORMAT_NONE;
1095   rb->NumSamples = samples;
1096
1097   /* Now allocate the storage */
1098   ASSERT(rb->AllocStorage);
1099   if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
1100      /* No error - check/set fields now */
1101      assert(rb->Format != MESA_FORMAT_NONE);
1102      assert(rb->Width == (GLuint) width);
1103      assert(rb->Height == (GLuint) height);
1104      rb->InternalFormat = internalFormat;
1105      rb->_BaseFormat = baseFormat;
1106      assert(rb->_BaseFormat != 0);
1107   }
1108   else {
1109      /* Probably ran out of memory - clear the fields */
1110      rb->Width = 0;
1111      rb->Height = 0;
1112      rb->Format = MESA_FORMAT_NONE;
1113      rb->InternalFormat = GL_NONE;
1114      rb->_BaseFormat = GL_NONE;
1115      rb->NumSamples = 0;
1116   }
1117
1118   /*
1119   test_framebuffer_completeness(ctx, fb);
1120   */
1121   /* XXX if this renderbuffer is attached anywhere, invalidate attachment
1122    * points???
1123    */
1124}
1125
1126
1127#if FEATURE_OES_EGL_image
1128void GLAPIENTRY
1129_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1130{
1131   struct gl_renderbuffer *rb;
1132   GET_CURRENT_CONTEXT(ctx);
1133   ASSERT_OUTSIDE_BEGIN_END(ctx);
1134
1135   if (!ctx->Extensions.OES_EGL_image) {
1136      _mesa_error(ctx, GL_INVALID_OPERATION,
1137                  "glEGLImageTargetRenderbufferStorageOES(unsupported)");
1138      return;
1139   }
1140
1141   if (target != GL_RENDERBUFFER) {
1142      _mesa_error(ctx, GL_INVALID_ENUM,
1143                  "EGLImageTargetRenderbufferStorageOES");
1144      return;
1145   }
1146
1147   rb = ctx->CurrentRenderbuffer;
1148   if (!rb) {
1149      _mesa_error(ctx, GL_INVALID_OPERATION,
1150                  "EGLImageTargetRenderbufferStorageOES");
1151      return;
1152   }
1153
1154   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1155
1156   ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1157}
1158#endif
1159
1160
1161/**
1162 * Helper function for _mesa_GetRenderbufferParameterivEXT() and
1163 * _mesa_GetFramebufferAttachmentParameterivEXT()
1164 * We have to be careful to respect the base format.  For example, if a
1165 * renderbuffer/texture was created with internalFormat=GL_RGB but the
1166 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
1167 * we need to return zero.
1168 */
1169static GLint
1170get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
1171{
1172   switch (pname) {
1173   case GL_RENDERBUFFER_RED_SIZE_EXT:
1174   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
1175   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1176   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
1177   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1178   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
1179      if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
1180         return _mesa_get_format_bits(format, pname);
1181      else
1182         return 0;
1183   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1184   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
1185      if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA)
1186         return _mesa_get_format_bits(format, pname);
1187      else
1188         return 0;
1189   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1190   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
1191      if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
1192         return _mesa_get_format_bits(format, pname);
1193      else
1194         return 0;
1195   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1196   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
1197      if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
1198         return _mesa_get_format_bits(format, pname);
1199      else
1200         return 0;
1201   default:
1202      return 0;
1203   }
1204}
1205
1206
1207
1208void GLAPIENTRY
1209_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1210                             GLsizei width, GLsizei height)
1211{
1212   /* GL_ARB_fbo says calling this function is equivalent to calling
1213    * glRenderbufferStorageMultisample() with samples=0.  We pass in
1214    * a token value here just for error reporting purposes.
1215    */
1216   renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
1217}
1218
1219
1220void GLAPIENTRY
1221_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
1222                                     GLenum internalFormat,
1223                                     GLsizei width, GLsizei height)
1224{
1225   renderbuffer_storage(target, internalFormat, width, height, samples);
1226}
1227
1228
1229/**
1230 * OpenGL ES version of glRenderBufferStorage.
1231 */
1232void GLAPIENTRY
1233_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1234			   GLsizei width, GLsizei height)
1235{
1236   switch (internalFormat) {
1237   case GL_RGB565:
1238      /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
1239      /* choose a closest format */
1240      internalFormat = GL_RGB5;
1241      break;
1242   default:
1243      break;
1244   }
1245
1246   renderbuffer_storage(target, internalFormat, width, height, 0);
1247}
1248
1249
1250void GLAPIENTRY
1251_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
1252{
1253   struct gl_renderbuffer *rb;
1254   GET_CURRENT_CONTEXT(ctx);
1255
1256   ASSERT_OUTSIDE_BEGIN_END(ctx);
1257
1258   if (target != GL_RENDERBUFFER_EXT) {
1259      _mesa_error(ctx, GL_INVALID_ENUM,
1260                  "glGetRenderbufferParameterivEXT(target)");
1261      return;
1262   }
1263
1264   rb = ctx->CurrentRenderbuffer;
1265   if (!rb) {
1266      _mesa_error(ctx, GL_INVALID_OPERATION,
1267                  "glGetRenderbufferParameterivEXT");
1268      return;
1269   }
1270
1271   /* No need to flush here since we're just quering state which is
1272    * not effected by rendering.
1273    */
1274
1275   switch (pname) {
1276   case GL_RENDERBUFFER_WIDTH_EXT:
1277      *params = rb->Width;
1278      return;
1279   case GL_RENDERBUFFER_HEIGHT_EXT:
1280      *params = rb->Height;
1281      return;
1282   case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
1283      *params = rb->InternalFormat;
1284      return;
1285   case GL_RENDERBUFFER_RED_SIZE_EXT:
1286   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1287   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1288   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1289   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1290   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1291      *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
1292      break;
1293   case GL_RENDERBUFFER_SAMPLES:
1294      if (ctx->Extensions.ARB_framebuffer_object) {
1295         *params = rb->NumSamples;
1296         break;
1297      }
1298      /* fallthrough */
1299   default:
1300      _mesa_error(ctx, GL_INVALID_ENUM,
1301                  "glGetRenderbufferParameterivEXT(target)");
1302      return;
1303   }
1304}
1305
1306
1307GLboolean GLAPIENTRY
1308_mesa_IsFramebufferEXT(GLuint framebuffer)
1309{
1310   GET_CURRENT_CONTEXT(ctx);
1311   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1312   if (framebuffer) {
1313      struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
1314      if (rb != NULL && rb != &DummyFramebuffer)
1315         return GL_TRUE;
1316   }
1317   return GL_FALSE;
1318}
1319
1320
1321/**
1322 * Check if any of the attachments of the given framebuffer are textures
1323 * (render to texture).  Call ctx->Driver.RenderTexture() for such
1324 * attachments.
1325 */
1326static void
1327check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
1328{
1329   GLuint i;
1330   ASSERT(ctx->Driver.RenderTexture);
1331
1332   if (fb->Name == 0)
1333      return; /* can't render to texture with winsys framebuffers */
1334
1335   for (i = 0; i < BUFFER_COUNT; i++) {
1336      struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1337      struct gl_texture_object *texObj = att->Texture;
1338      if (texObj
1339          && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
1340         ctx->Driver.RenderTexture(ctx, fb, att);
1341      }
1342   }
1343}
1344
1345
1346/**
1347 * Examine all the framebuffer's attachments to see if any are textures.
1348 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
1349 * notify the device driver that the texture image may have changed.
1350 */
1351static void
1352check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
1353{
1354   if (fb->Name == 0)
1355      return; /* can't render to texture with winsys framebuffers */
1356
1357   if (ctx->Driver.FinishRenderTexture) {
1358      GLuint i;
1359      for (i = 0; i < BUFFER_COUNT; i++) {
1360         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1361         if (att->Texture && att->Renderbuffer) {
1362            ctx->Driver.FinishRenderTexture(ctx, att);
1363         }
1364      }
1365   }
1366}
1367
1368
1369void GLAPIENTRY
1370_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
1371{
1372   struct gl_framebuffer *newDrawFb, *newReadFb;
1373   struct gl_framebuffer *oldDrawFb, *oldReadFb;
1374   GLboolean bindReadBuf, bindDrawBuf;
1375   GET_CURRENT_CONTEXT(ctx);
1376
1377#ifdef DEBUG
1378   if (ctx->Extensions.ARB_framebuffer_object) {
1379      ASSERT(ctx->Extensions.EXT_framebuffer_object);
1380      ASSERT(ctx->Extensions.EXT_framebuffer_blit);
1381   }
1382#endif
1383
1384   ASSERT_OUTSIDE_BEGIN_END(ctx);
1385
1386   if (!ctx->Extensions.EXT_framebuffer_object) {
1387      _mesa_error(ctx, GL_INVALID_OPERATION,
1388                  "glBindFramebufferEXT(unsupported)");
1389      return;
1390   }
1391
1392   switch (target) {
1393#if FEATURE_EXT_framebuffer_blit
1394   case GL_DRAW_FRAMEBUFFER_EXT:
1395      if (!ctx->Extensions.EXT_framebuffer_blit) {
1396         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1397         return;
1398      }
1399      bindDrawBuf = GL_TRUE;
1400      bindReadBuf = GL_FALSE;
1401      break;
1402   case GL_READ_FRAMEBUFFER_EXT:
1403      if (!ctx->Extensions.EXT_framebuffer_blit) {
1404         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1405         return;
1406      }
1407      bindDrawBuf = GL_FALSE;
1408      bindReadBuf = GL_TRUE;
1409      break;
1410#endif
1411   case GL_FRAMEBUFFER_EXT:
1412      bindDrawBuf = GL_TRUE;
1413      bindReadBuf = GL_TRUE;
1414      break;
1415   default:
1416      _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1417      return;
1418   }
1419
1420   if (framebuffer) {
1421      /* Binding a user-created framebuffer object */
1422      newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
1423      if (newDrawFb == &DummyFramebuffer) {
1424         /* ID was reserved, but no real framebuffer object made yet */
1425         newDrawFb = NULL;
1426      }
1427      else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
1428         /* All FBO IDs must be Gen'd */
1429         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
1430         return;
1431      }
1432
1433      if (!newDrawFb) {
1434	 /* create new framebuffer object */
1435	 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
1436	 if (!newDrawFb) {
1437	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1438	    return;
1439	 }
1440         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
1441      }
1442      newReadFb = newDrawFb;
1443   }
1444   else {
1445      /* Binding the window system framebuffer (which was originally set
1446       * with MakeCurrent).
1447       */
1448      newDrawFb = ctx->WinSysDrawBuffer;
1449      newReadFb = ctx->WinSysReadBuffer;
1450   }
1451
1452   ASSERT(newDrawFb);
1453   ASSERT(newDrawFb != &DummyFramebuffer);
1454
1455   /* save pointers to current/old framebuffers */
1456   oldDrawFb = ctx->DrawBuffer;
1457   oldReadFb = ctx->ReadBuffer;
1458
1459   /* check if really changing bindings */
1460   if (oldDrawFb == newDrawFb)
1461      bindDrawBuf = GL_FALSE;
1462   if (oldReadFb == newReadFb)
1463      bindReadBuf = GL_FALSE;
1464
1465   /*
1466    * OK, now bind the new Draw/Read framebuffers, if they're changing.
1467    *
1468    * We also check if we're beginning and/or ending render-to-texture.
1469    * When a framebuffer with texture attachments is unbound, call
1470    * ctx->Driver.FinishRenderTexture().
1471    * When a framebuffer with texture attachments is bound, call
1472    * ctx->Driver.RenderTexture().
1473    *
1474    * Note that if the ReadBuffer has texture attachments we don't consider
1475    * that a render-to-texture case.
1476    */
1477   if (bindReadBuf) {
1478      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1479
1480      /* check if old readbuffer was render-to-texture */
1481      check_end_texture_render(ctx, oldReadFb);
1482
1483      _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
1484   }
1485
1486   if (bindDrawBuf) {
1487      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1488
1489      /* check if old read/draw buffers were render-to-texture */
1490      if (!bindReadBuf)
1491         check_end_texture_render(ctx, oldReadFb);
1492
1493      if (oldDrawFb != oldReadFb)
1494         check_end_texture_render(ctx, oldDrawFb);
1495
1496      /* check if newly bound framebuffer has any texture attachments */
1497      check_begin_texture_render(ctx, newDrawFb);
1498
1499      _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
1500   }
1501
1502   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
1503      ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
1504   }
1505}
1506
1507
1508void GLAPIENTRY
1509_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1510{
1511   GLint i;
1512   GET_CURRENT_CONTEXT(ctx);
1513
1514   ASSERT_OUTSIDE_BEGIN_END(ctx);
1515   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1516
1517   for (i = 0; i < n; i++) {
1518      if (framebuffers[i] > 0) {
1519	 struct gl_framebuffer *fb;
1520	 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
1521	 if (fb) {
1522            ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
1523
1524            /* check if deleting currently bound framebuffer object */
1525            if (ctx->Extensions.EXT_framebuffer_blit) {
1526               /* separate draw/read binding points */
1527               if (fb == ctx->DrawBuffer) {
1528                  /* bind default */
1529                  ASSERT(fb->RefCount >= 2);
1530                  _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1531               }
1532               if (fb == ctx->ReadBuffer) {
1533                  /* bind default */
1534                  ASSERT(fb->RefCount >= 2);
1535                  _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1536               }
1537            }
1538            else {
1539               /* only one binding point for read/draw buffers */
1540               if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
1541                  /* bind default */
1542                  ASSERT(fb->RefCount >= 2);
1543                  _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1544               }
1545            }
1546
1547	    /* remove from hash table immediately, to free the ID */
1548	    _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
1549
1550            if (fb != &DummyFramebuffer) {
1551               /* But the object will not be freed until it's no longer
1552                * bound in any context.
1553                */
1554               _mesa_reference_framebuffer(&fb, NULL);
1555	    }
1556	 }
1557      }
1558   }
1559}
1560
1561
1562void GLAPIENTRY
1563_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1564{
1565   GET_CURRENT_CONTEXT(ctx);
1566   GLuint first;
1567   GLint i;
1568
1569   ASSERT_OUTSIDE_BEGIN_END(ctx);
1570
1571   if (n < 0) {
1572      _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1573      return;
1574   }
1575
1576   if (!framebuffers)
1577      return;
1578
1579   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1580
1581   for (i = 0; i < n; i++) {
1582      GLuint name = first + i;
1583      framebuffers[i] = name;
1584      /* insert dummy placeholder into hash table */
1585      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
1586      _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
1587      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1588   }
1589}
1590
1591
1592
1593GLenum GLAPIENTRY
1594_mesa_CheckFramebufferStatusEXT(GLenum target)
1595{
1596   struct gl_framebuffer *buffer;
1597   GET_CURRENT_CONTEXT(ctx);
1598
1599   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1600
1601   switch (target) {
1602#if FEATURE_EXT_framebuffer_blit
1603   case GL_DRAW_FRAMEBUFFER_EXT:
1604      if (!ctx->Extensions.EXT_framebuffer_blit) {
1605         _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1606         return 0;
1607      }
1608      buffer = ctx->DrawBuffer;
1609      break;
1610   case GL_READ_FRAMEBUFFER_EXT:
1611      if (!ctx->Extensions.EXT_framebuffer_blit) {
1612         _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1613         return 0;
1614      }
1615      buffer = ctx->ReadBuffer;
1616      break;
1617#endif
1618   case GL_FRAMEBUFFER_EXT:
1619      buffer = ctx->DrawBuffer;
1620      break;
1621   default:
1622      _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1623      return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
1624   }
1625
1626   if (buffer->Name == 0) {
1627      /* The window system / default framebuffer is always complete */
1628      return GL_FRAMEBUFFER_COMPLETE_EXT;
1629   }
1630
1631   /* No need to flush here */
1632
1633   if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
1634      _mesa_test_framebuffer_completeness(ctx, buffer);
1635   }
1636
1637   return buffer->_Status;
1638}
1639
1640
1641
1642/**
1643 * Common code called by glFramebufferTexture1D/2D/3DEXT().
1644 */
1645static void
1646framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
1647                    GLenum attachment, GLenum textarget, GLuint texture,
1648                    GLint level, GLint zoffset)
1649{
1650   struct gl_renderbuffer_attachment *att;
1651   struct gl_texture_object *texObj = NULL;
1652   struct gl_framebuffer *fb;
1653   GLboolean error = GL_FALSE;
1654
1655   ASSERT_OUTSIDE_BEGIN_END(ctx);
1656
1657   switch (target) {
1658   case GL_READ_FRAMEBUFFER_EXT:
1659      error = !ctx->Extensions.EXT_framebuffer_blit;
1660      fb = ctx->ReadBuffer;
1661      break;
1662   case GL_DRAW_FRAMEBUFFER_EXT:
1663      error = !ctx->Extensions.EXT_framebuffer_blit;
1664      /* fall-through */
1665   case GL_FRAMEBUFFER_EXT:
1666      fb = ctx->DrawBuffer;
1667      break;
1668   default:
1669      error = GL_TRUE;
1670   }
1671
1672   if (error) {
1673      _mesa_error(ctx, GL_INVALID_ENUM,
1674                  "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
1675      return;
1676   }
1677
1678   ASSERT(fb);
1679
1680   /* check framebuffer binding */
1681   if (fb->Name == 0) {
1682      _mesa_error(ctx, GL_INVALID_OPERATION,
1683                  "glFramebufferTexture%sEXT", caller);
1684      return;
1685   }
1686
1687
1688   /* The textarget, level, and zoffset parameters are only validated if
1689    * texture is non-zero.
1690    */
1691   if (texture) {
1692      GLboolean err = GL_TRUE;
1693
1694      texObj = _mesa_lookup_texture(ctx, texture);
1695      if (texObj != NULL) {
1696         if (textarget == 0) {
1697            /* XXX what's the purpose of this? */
1698            err = (texObj->Target != GL_TEXTURE_3D) &&
1699                (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1700                (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1701         }
1702         else {
1703            err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1704                ? !IS_CUBE_FACE(textarget)
1705                : (texObj->Target != textarget);
1706         }
1707      }
1708      else {
1709         /* can't render to a non-existant texture */
1710         _mesa_error(ctx, GL_INVALID_OPERATION,
1711                     "glFramebufferTexture%sEXT(non existant texture)",
1712                     caller);
1713         return;
1714      }
1715
1716      if (err) {
1717         _mesa_error(ctx, GL_INVALID_OPERATION,
1718                     "glFramebufferTexture%sEXT(texture target mismatch)",
1719                     caller);
1720         return;
1721      }
1722
1723      if (texObj->Target == GL_TEXTURE_3D) {
1724         const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1725         if (zoffset < 0 || zoffset >= maxSize) {
1726            _mesa_error(ctx, GL_INVALID_VALUE,
1727                        "glFramebufferTexture%sEXT(zoffset)", caller);
1728            return;
1729         }
1730      }
1731      else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1732               (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1733         if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1734            _mesa_error(ctx, GL_INVALID_VALUE,
1735                        "glFramebufferTexture%sEXT(layer)", caller);
1736            return;
1737         }
1738      }
1739
1740      if ((level < 0) ||
1741          (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1742         _mesa_error(ctx, GL_INVALID_VALUE,
1743                     "glFramebufferTexture%sEXT(level)", caller);
1744         return;
1745      }
1746   }
1747
1748   att = _mesa_get_attachment(ctx, fb, attachment);
1749   if (att == NULL) {
1750      _mesa_error(ctx, GL_INVALID_ENUM,
1751                  "glFramebufferTexture%sEXT(attachment)", caller);
1752      return;
1753   }
1754
1755   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1756
1757   _glthread_LOCK_MUTEX(fb->Mutex);
1758   if (texObj) {
1759      _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1760                                   level, zoffset);
1761      /* Set the render-to-texture flag.  We'll check this flag in
1762       * glTexImage() and friends to determine if we need to revalidate
1763       * any FBOs that might be rendering into this texture.
1764       * This flag never gets cleared since it's non-trivial to determine
1765       * when all FBOs might be done rendering to this texture.  That's OK
1766       * though since it's uncommon to render to a texture then repeatedly
1767       * call glTexImage() to change images in the texture.
1768       */
1769      texObj->_RenderToTexture = GL_TRUE;
1770   }
1771   else {
1772      _mesa_remove_attachment(ctx, att);
1773   }
1774
1775   invalidate_framebuffer(fb);
1776
1777   _glthread_UNLOCK_MUTEX(fb->Mutex);
1778}
1779
1780
1781
1782void GLAPIENTRY
1783_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1784                              GLenum textarget, GLuint texture, GLint level)
1785{
1786   GET_CURRENT_CONTEXT(ctx);
1787
1788   if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1789      _mesa_error(ctx, GL_INVALID_ENUM,
1790                  "glFramebufferTexture1DEXT(textarget)");
1791      return;
1792   }
1793
1794   framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1795                       level, 0);
1796}
1797
1798
1799void GLAPIENTRY
1800_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1801                              GLenum textarget, GLuint texture, GLint level)
1802{
1803   GET_CURRENT_CONTEXT(ctx);
1804
1805   if ((texture != 0) &&
1806       (textarget != GL_TEXTURE_2D) &&
1807       (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1808       (!IS_CUBE_FACE(textarget))) {
1809      _mesa_error(ctx, GL_INVALID_OPERATION,
1810                  "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
1811      return;
1812   }
1813
1814   framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1815                       level, 0);
1816}
1817
1818
1819void GLAPIENTRY
1820_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1821                              GLenum textarget, GLuint texture,
1822                              GLint level, GLint zoffset)
1823{
1824   GET_CURRENT_CONTEXT(ctx);
1825
1826   if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1827      _mesa_error(ctx, GL_INVALID_ENUM,
1828                  "glFramebufferTexture3DEXT(textarget)");
1829      return;
1830   }
1831
1832   framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
1833                       level, zoffset);
1834}
1835
1836
1837void GLAPIENTRY
1838_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1839                                 GLuint texture, GLint level, GLint layer)
1840{
1841   GET_CURRENT_CONTEXT(ctx);
1842
1843   framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1844                       level, layer);
1845}
1846
1847
1848void GLAPIENTRY
1849_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1850                                 GLenum renderbufferTarget,
1851                                 GLuint renderbuffer)
1852{
1853   struct gl_renderbuffer_attachment *att;
1854   struct gl_framebuffer *fb;
1855   struct gl_renderbuffer *rb;
1856   GET_CURRENT_CONTEXT(ctx);
1857
1858   ASSERT_OUTSIDE_BEGIN_END(ctx);
1859
1860   switch (target) {
1861#if FEATURE_EXT_framebuffer_blit
1862   case GL_DRAW_FRAMEBUFFER_EXT:
1863      if (!ctx->Extensions.EXT_framebuffer_blit) {
1864         _mesa_error(ctx, GL_INVALID_ENUM,
1865                     "glFramebufferRenderbufferEXT(target)");
1866         return;
1867      }
1868      fb = ctx->DrawBuffer;
1869      break;
1870   case GL_READ_FRAMEBUFFER_EXT:
1871      if (!ctx->Extensions.EXT_framebuffer_blit) {
1872         _mesa_error(ctx, GL_INVALID_ENUM,
1873                     "glFramebufferRenderbufferEXT(target)");
1874         return;
1875      }
1876      fb = ctx->ReadBuffer;
1877      break;
1878#endif
1879   case GL_FRAMEBUFFER_EXT:
1880      fb = ctx->DrawBuffer;
1881      break;
1882   default:
1883      _mesa_error(ctx, GL_INVALID_ENUM,
1884                  "glFramebufferRenderbufferEXT(target)");
1885      return;
1886   }
1887
1888   if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
1889      _mesa_error(ctx, GL_INVALID_ENUM,
1890                  "glFramebufferRenderbufferEXT(renderbufferTarget)");
1891      return;
1892   }
1893
1894   if (fb->Name == 0) {
1895      /* Can't attach new renderbuffers to a window system framebuffer */
1896      _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1897      return;
1898   }
1899
1900   att = _mesa_get_attachment(ctx, fb, attachment);
1901   if (att == NULL) {
1902      _mesa_error(ctx, GL_INVALID_ENUM,
1903                  "glFramebufferRenderbufferEXT(invalid attachment %s)",
1904                  _mesa_lookup_enum_by_nr(attachment));
1905      return;
1906   }
1907
1908   if (renderbuffer) {
1909      rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
1910      if (!rb) {
1911	 _mesa_error(ctx, GL_INVALID_OPERATION,
1912		     "glFramebufferRenderbufferEXT(non-existant"
1913                     " renderbuffer %u)", renderbuffer);
1914	 return;
1915      }
1916   }
1917   else {
1918      /* remove renderbuffer attachment */
1919      rb = NULL;
1920   }
1921
1922   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
1923       rb && rb->Format != MESA_FORMAT_NONE) {
1924      /* make sure the renderbuffer is a depth/stencil format */
1925      const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
1926      if (baseFormat != GL_DEPTH_STENCIL) {
1927         _mesa_error(ctx, GL_INVALID_OPERATION,
1928                     "glFramebufferRenderbufferEXT(renderbuffer"
1929                     " is not DEPTH_STENCIL format)");
1930         return;
1931      }
1932   }
1933
1934
1935   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1936
1937   assert(ctx->Driver.FramebufferRenderbuffer);
1938   ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
1939
1940   /* Some subsequent GL commands may depend on the framebuffer's visual
1941    * after the binding is updated.  Update visual info now.
1942    */
1943   _mesa_update_framebuffer_visual(fb);
1944}
1945
1946
1947void GLAPIENTRY
1948_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1949                                             GLenum pname, GLint *params)
1950{
1951   const struct gl_renderbuffer_attachment *att;
1952   struct gl_framebuffer *buffer;
1953   GET_CURRENT_CONTEXT(ctx);
1954
1955   ASSERT_OUTSIDE_BEGIN_END(ctx);
1956
1957   switch (target) {
1958#if FEATURE_EXT_framebuffer_blit
1959   case GL_DRAW_FRAMEBUFFER_EXT:
1960      if (!ctx->Extensions.EXT_framebuffer_blit) {
1961         _mesa_error(ctx, GL_INVALID_ENUM,
1962                     "glGetFramebufferAttachmentParameterivEXT(target)");
1963         return;
1964      }
1965      buffer = ctx->DrawBuffer;
1966      break;
1967   case GL_READ_FRAMEBUFFER_EXT:
1968      if (!ctx->Extensions.EXT_framebuffer_blit) {
1969         _mesa_error(ctx, GL_INVALID_ENUM,
1970                     "glGetFramebufferAttachmentParameterivEXT(target)");
1971         return;
1972      }
1973      buffer = ctx->ReadBuffer;
1974      break;
1975#endif
1976   case GL_FRAMEBUFFER_EXT:
1977      buffer = ctx->DrawBuffer;
1978      break;
1979   default:
1980      _mesa_error(ctx, GL_INVALID_ENUM,
1981                  "glGetFramebufferAttachmentParameterivEXT(target)");
1982      return;
1983   }
1984
1985   if (buffer->Name == 0) {
1986      /* the default / window-system FBO */
1987      att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
1988   }
1989   else {
1990      /* user-created framebuffer FBO */
1991      att = _mesa_get_attachment(ctx, buffer, attachment);
1992   }
1993
1994   if (att == NULL) {
1995      _mesa_error(ctx, GL_INVALID_ENUM,
1996                  "glGetFramebufferAttachmentParameterivEXT(attachment)");
1997      return;
1998   }
1999
2000   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2001      /* the depth and stencil attachments must point to the same buffer */
2002      const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
2003      depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
2004      stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
2005      if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
2006         _mesa_error(ctx, GL_INVALID_OPERATION,
2007                     "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
2008                     " attachments differ)");
2009         return;
2010      }
2011   }
2012
2013   /* No need to flush here */
2014
2015   switch (pname) {
2016   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
2017      *params = att->Type;
2018      return;
2019   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
2020      if (att->Type == GL_RENDERBUFFER_EXT) {
2021	 *params = att->Renderbuffer->Name;
2022      }
2023      else if (att->Type == GL_TEXTURE) {
2024	 *params = att->Texture->Name;
2025      }
2026      else {
2027	 _mesa_error(ctx, GL_INVALID_ENUM,
2028		     "glGetFramebufferAttachmentParameterivEXT(pname)");
2029      }
2030      return;
2031   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
2032      if (att->Type == GL_TEXTURE) {
2033	 *params = att->TextureLevel;
2034      }
2035      else {
2036	 _mesa_error(ctx, GL_INVALID_ENUM,
2037		     "glGetFramebufferAttachmentParameterivEXT(pname)");
2038      }
2039      return;
2040   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
2041      if (att->Type == GL_TEXTURE) {
2042         if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
2043            *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
2044         }
2045         else {
2046            *params = 0;
2047         }
2048      }
2049      else {
2050	 _mesa_error(ctx, GL_INVALID_ENUM,
2051		     "glGetFramebufferAttachmentParameterivEXT(pname)");
2052      }
2053      return;
2054   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
2055      if (att->Type == GL_TEXTURE) {
2056         if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2057            *params = att->Zoffset;
2058         }
2059         else {
2060            *params = 0;
2061         }
2062      }
2063      else {
2064	 _mesa_error(ctx, GL_INVALID_ENUM,
2065		     "glGetFramebufferAttachmentParameterivEXT(pname)");
2066      }
2067      return;
2068   case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2069      if (!ctx->Extensions.ARB_framebuffer_object) {
2070         _mesa_error(ctx, GL_INVALID_ENUM,
2071                     "glGetFramebufferAttachmentParameterivEXT(pname)");
2072      }
2073      else {
2074         *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
2075      }
2076      return;
2077   case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2078      if (!ctx->Extensions.ARB_framebuffer_object) {
2079         _mesa_error(ctx, GL_INVALID_ENUM,
2080                     "glGetFramebufferAttachmentParameterivEXT(pname)");
2081         return;
2082      }
2083      else {
2084         gl_format format = att->Renderbuffer->Format;
2085         if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
2086            /* special cases */
2087            *params = GL_INDEX;
2088         }
2089         else {
2090            *params = _mesa_get_format_datatype(format);
2091         }
2092      }
2093      return;
2094   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
2095   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
2096   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
2097   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
2098   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
2099   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2100      if (!ctx->Extensions.ARB_framebuffer_object) {
2101         _mesa_error(ctx, GL_INVALID_ENUM,
2102                     "glGetFramebufferAttachmentParameterivEXT(pname)");
2103      }
2104      else if (att->Texture) {
2105         const struct gl_texture_image *texImage =
2106            _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
2107                                   att->TextureLevel);
2108         if (texImage) {
2109            *params = get_component_bits(pname, texImage->_BaseFormat,
2110                                         texImage->TexFormat);
2111         }
2112         else {
2113            *params = 0;
2114         }
2115      }
2116      else if (att->Renderbuffer) {
2117         *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
2118                                      att->Renderbuffer->Format);
2119      }
2120      else {
2121         *params = 0;
2122      }
2123      return;
2124   default:
2125      _mesa_error(ctx, GL_INVALID_ENUM,
2126                  "glGetFramebufferAttachmentParameterivEXT(pname)");
2127      return;
2128   }
2129}
2130
2131
2132void GLAPIENTRY
2133_mesa_GenerateMipmapEXT(GLenum target)
2134{
2135   struct gl_texture_object *texObj;
2136   GET_CURRENT_CONTEXT(ctx);
2137
2138   ASSERT_OUTSIDE_BEGIN_END(ctx);
2139   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2140
2141   switch (target) {
2142   case GL_TEXTURE_1D:
2143   case GL_TEXTURE_2D:
2144   case GL_TEXTURE_3D:
2145   case GL_TEXTURE_CUBE_MAP:
2146      /* OK, legal value */
2147      break;
2148   default:
2149      _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
2150      return;
2151   }
2152
2153   texObj = _mesa_get_current_tex_object(ctx, target);
2154
2155   if (texObj->BaseLevel >= texObj->MaxLevel) {
2156      /* nothing to do */
2157      return;
2158   }
2159
2160   _mesa_lock_texture(ctx, texObj);
2161   if (target == GL_TEXTURE_CUBE_MAP) {
2162      GLuint face;
2163      for (face = 0; face < 6; face++)
2164	 ctx->Driver.GenerateMipmap(ctx,
2165				    GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2166				    texObj);
2167   }
2168   else {
2169      ctx->Driver.GenerateMipmap(ctx, target, texObj);
2170   }
2171   _mesa_unlock_texture(ctx, texObj);
2172}
2173
2174
2175#if FEATURE_EXT_framebuffer_blit
2176
2177static const struct gl_renderbuffer_attachment *
2178find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb)
2179{
2180   GLuint i;
2181   for (i = 0; i < Elements(fb->Attachment); i++) {
2182      if (fb->Attachment[i].Renderbuffer == rb)
2183         return &fb->Attachment[i];
2184   }
2185   return NULL;
2186}
2187
2188
2189
2190/**
2191 * Blit rectangular region, optionally from one framebuffer to another.
2192 *
2193 * Note, if the src buffer is multisampled and the dest is not, this is
2194 * when the samples must be resolved to a single color.
2195 */
2196void GLAPIENTRY
2197_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
2198                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
2199                         GLbitfield mask, GLenum filter)
2200{
2201   const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
2202                                     GL_DEPTH_BUFFER_BIT |
2203                                     GL_STENCIL_BUFFER_BIT);
2204   const struct gl_framebuffer *readFb, *drawFb;
2205   const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
2206   GET_CURRENT_CONTEXT(ctx);
2207
2208   ASSERT_OUTSIDE_BEGIN_END(ctx);
2209   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2210
2211   if (ctx->NewState) {
2212      _mesa_update_state(ctx);
2213   }
2214
2215   readFb = ctx->ReadBuffer;
2216   drawFb = ctx->DrawBuffer;
2217
2218   if (!readFb || !drawFb) {
2219      /* This will normally never happen but someday we may want to
2220       * support MakeCurrent() with no drawables.
2221       */
2222      return;
2223   }
2224
2225   /* check for complete framebuffers */
2226   if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
2227       readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
2228      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
2229                  "glBlitFramebufferEXT(incomplete draw/read buffers)");
2230      return;
2231   }
2232
2233   if (filter != GL_NEAREST && filter != GL_LINEAR) {
2234      _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
2235      return;
2236   }
2237
2238   if (mask & ~legalMaskBits) {
2239      _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
2240      return;
2241   }
2242
2243   /* depth/stencil must be blitted with nearest filtering */
2244   if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
2245        && filter != GL_NEAREST) {
2246      _mesa_error(ctx, GL_INVALID_OPERATION,
2247             "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
2248      return;
2249   }
2250
2251   /* get color read/draw renderbuffers */
2252   if (mask & GL_COLOR_BUFFER_BIT) {
2253      colorReadRb = readFb->_ColorReadBuffer;
2254      colorDrawRb = drawFb->_ColorDrawBuffers[0];
2255   }
2256   else {
2257      colorReadRb = colorDrawRb = NULL;
2258   }
2259
2260   if (mask & GL_STENCIL_BUFFER_BIT) {
2261      struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
2262      struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
2263      if (!readRb ||
2264          !drawRb ||
2265          _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
2266          _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
2267         _mesa_error(ctx, GL_INVALID_OPERATION,
2268                     "glBlitFramebufferEXT(stencil buffer size mismatch");
2269         return;
2270      }
2271   }
2272
2273   if (mask & GL_DEPTH_BUFFER_BIT) {
2274      struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
2275      struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
2276      if (!readRb ||
2277          !drawRb ||
2278          _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
2279          _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
2280         _mesa_error(ctx, GL_INVALID_OPERATION,
2281                     "glBlitFramebufferEXT(depth buffer size mismatch");
2282         return;
2283      }
2284   }
2285
2286   if (readFb->Visual.samples > 0 &&
2287       drawFb->Visual.samples > 0 &&
2288       readFb->Visual.samples != drawFb->Visual.samples) {
2289      _mesa_error(ctx, GL_INVALID_OPERATION,
2290                  "glBlitFramebufferEXT(mismatched samples");
2291      return;
2292   }
2293
2294   /* extra checks for multisample copies... */
2295   if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
2296      /* src and dest region sizes must be the same */
2297      if (srcX1 - srcX0 != dstX1 - dstX0 ||
2298          srcY1 - srcY0 != dstY1 - dstY0) {
2299         _mesa_error(ctx, GL_INVALID_OPERATION,
2300                "glBlitFramebufferEXT(bad src/dst multisample region sizes");
2301         return;
2302      }
2303
2304      /* color formats must match */
2305      if (colorReadRb &&
2306          colorDrawRb &&
2307          colorReadRb->Format != colorDrawRb->Format) {
2308         _mesa_error(ctx, GL_INVALID_OPERATION,
2309                "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
2310         return;
2311      }
2312   }
2313
2314   if (!ctx->Extensions.EXT_framebuffer_blit) {
2315      _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
2316      return;
2317   }
2318
2319   /* Debug code */
2320   if (DEBUG_BLIT) {
2321      printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
2322	     " 0x%x, 0x%x)\n",
2323	     srcX0, srcY0, srcX1, srcY1,
2324	     dstX0, dstY0, dstX1, dstY1,
2325	     mask, filter);
2326      if (colorReadRb) {
2327         const struct gl_renderbuffer_attachment *att;
2328
2329         att = find_attachment(readFb, colorReadRb);
2330         printf("  Src FBO %u  RB %u (%dx%d)  ",
2331		readFb->Name, colorReadRb->Name,
2332		colorReadRb->Width, colorReadRb->Height);
2333         if (att && att->Texture) {
2334            printf("Tex %u  tgt 0x%x  level %u  face %u",
2335		   att->Texture->Name,
2336		   att->Texture->Target,
2337		   att->TextureLevel,
2338		   att->CubeMapFace);
2339         }
2340         printf("\n");
2341
2342         att = find_attachment(drawFb, colorDrawRb);
2343         printf("  Dst FBO %u  RB %u (%dx%d)  ",
2344		drawFb->Name, colorDrawRb->Name,
2345		colorDrawRb->Width, colorDrawRb->Height);
2346         if (att && att->Texture) {
2347            printf("Tex %u  tgt 0x%x  level %u  face %u",
2348		   att->Texture->Name,
2349		   att->Texture->Target,
2350		   att->TextureLevel,
2351		   att->CubeMapFace);
2352         }
2353         printf("\n");
2354      }
2355   }
2356
2357   ASSERT(ctx->Driver.BlitFramebuffer);
2358   ctx->Driver.BlitFramebuffer(ctx,
2359                               srcX0, srcY0, srcX1, srcY1,
2360                               dstX0, dstY0, dstX1, dstY1,
2361                               mask, filter);
2362}
2363#endif /* FEATURE_EXT_framebuffer_blit */
2364
2365#if FEATURE_ARB_geometry_shader4
2366void GLAPIENTRY
2367_mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
2368                            GLuint texture, GLint level)
2369{
2370   GET_CURRENT_CONTEXT(ctx);
2371   _mesa_error(ctx, GL_INVALID_OPERATION,
2372               "glFramebufferTextureARB "
2373               "not implemented!");
2374}
2375
2376void GLAPIENTRY
2377_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
2378                                GLuint texture, GLint level, GLenum face)
2379{
2380   GET_CURRENT_CONTEXT(ctx);
2381   _mesa_error(ctx, GL_INVALID_OPERATION,
2382               "glFramebufferTextureFaceARB "
2383               "not implemented!");
2384}
2385#endif /* FEATURE_ARB_geometry_shader4 */
2386