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