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