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