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