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