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