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