mesa: move call to _mesa_update_framebuffer_visual()
[profile/ivi/mesa.git] / src / mesa / main / fbobject.c
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  */
64 static struct gl_framebuffer DummyFramebuffer;
65 static 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
73 static void
74 delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
75 {
76    /* no op */
77 }
78
79 static void
80 delete_dummy_framebuffer(struct gl_framebuffer *fb)
81 {
82    /* no op */
83 }
84
85
86 void
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  */
97 struct 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  */
114 struct 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  */
133 static void
134 invalidate_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  */
146 struct 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  */
190 void
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  */
216 void
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  */
258 void
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  */
276 void
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  */
311 static void
312 test_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  */
429 static void
430 fbo_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  */
448 void
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
640 GLboolean 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
654 void 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  */
716 static void
717 detach_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
731 void 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
775 void 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  */
814 GLenum
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  */
869 static void
870 renderbuffer_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
976 void 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
988 void 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
998 void 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
1063 GLboolean 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
1077 static void
1078 check_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  */
1098 static void
1099 check_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
1113 void 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
1231 void 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
1279 void 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
1310 GLenum 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  */
1362 static void
1363 framebuffer_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
1371    ASSERT_OUTSIDE_BEGIN_END(ctx);
1372
1373    if (target != GL_FRAMEBUFFER_EXT) {
1374       _mesa_error(ctx, GL_INVALID_ENUM,
1375                   "glFramebufferTexture%sEXT(target)", caller);
1376       return;
1377    }
1378
1379    fb = ctx->DrawBuffer;
1380    ASSERT(fb);
1381
1382    /* check framebuffer binding */
1383    if (fb->Name == 0) {
1384       _mesa_error(ctx, GL_INVALID_OPERATION,
1385                   "glFramebufferTexture%sEXT", caller);
1386       return;
1387    }
1388
1389
1390    /* The textarget, level, and zoffset parameters are only validated if
1391     * texture is non-zero.
1392     */
1393    if (texture) {
1394       GLboolean err = GL_TRUE;
1395
1396       texObj = _mesa_lookup_texture(ctx, texture);
1397       if (texObj != NULL) {
1398          if (textarget == 0) {
1399             err = (texObj->Target != GL_TEXTURE_3D) &&
1400                 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1401                 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1402          }
1403          else {
1404             err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1405                 ? !IS_CUBE_FACE(textarget)
1406                 : (texObj->Target != textarget);
1407          }
1408       }
1409
1410       if (err) {
1411          _mesa_error(ctx, GL_INVALID_OPERATION,
1412                      "glFramebufferTexture%sEXT(texture target mismatch)",
1413                      caller);
1414          return;
1415       }
1416
1417       if (texObj->Target == GL_TEXTURE_3D) {
1418          const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1419          if (zoffset < 0 || zoffset >= maxSize) {
1420             _mesa_error(ctx, GL_INVALID_VALUE,
1421                         "glFramebufferTexture%sEXT(zoffset)", caller);
1422             return;
1423          }
1424       }
1425       else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1426                (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1427          if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1428             _mesa_error(ctx, GL_INVALID_VALUE,
1429                         "glFramebufferTexture%sEXT(layer)", caller);
1430             return;
1431          }
1432       }
1433
1434       if ((level < 0) || 
1435           (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1436          _mesa_error(ctx, GL_INVALID_VALUE,
1437                      "glFramebufferTexture%sEXT(level)", caller);
1438          return;
1439       }
1440    }
1441
1442    att = _mesa_get_attachment(ctx, fb, attachment);
1443    if (att == NULL) {
1444       _mesa_error(ctx, GL_INVALID_ENUM,
1445                   "glFramebufferTexture%sEXT(attachment)", caller);
1446       return;
1447    }
1448
1449    if (texObj && attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
1450       /* the texture format must be depth+stencil */
1451       const struct gl_texture_image *texImg;
1452       texImg = texObj->Image[0][texObj->BaseLevel];
1453       if (!texImg || texImg->_BaseFormat != GL_DEPTH_STENCIL) {
1454          _mesa_error(ctx, GL_INVALID_OPERATION,
1455                      "glFramebufferTexture%sEXT(texture is not"
1456                      " DEPTH_STENCIL format)", caller);
1457          return;
1458       }
1459    }
1460
1461    FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1462    /* The above doesn't fully flush the drivers in the way that a
1463     * glFlush does, but that is required here:
1464     */
1465    if (ctx->Driver.Flush)
1466       ctx->Driver.Flush(ctx);
1467
1468    _glthread_LOCK_MUTEX(fb->Mutex);
1469    if (texObj) {
1470       _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1471                                    level, zoffset);
1472    }
1473    else {
1474       _mesa_remove_attachment(ctx, att);
1475    }
1476
1477    invalidate_framebuffer(fb);
1478
1479    _glthread_UNLOCK_MUTEX(fb->Mutex);
1480 }
1481
1482
1483
1484 void GLAPIENTRY
1485 _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1486                               GLenum textarget, GLuint texture, GLint level)
1487 {
1488    GET_CURRENT_CONTEXT(ctx);
1489
1490    if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1491       _mesa_error(ctx, GL_INVALID_ENUM,
1492                   "glFramebufferTexture1DEXT(textarget)");
1493       return;
1494    }
1495
1496    framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1497                        level, 0);
1498 }
1499
1500
1501 void GLAPIENTRY
1502 _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1503                               GLenum textarget, GLuint texture, GLint level)
1504 {
1505    GET_CURRENT_CONTEXT(ctx);
1506
1507    if ((texture != 0) &&
1508        (textarget != GL_TEXTURE_2D) &&
1509        (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1510        (!IS_CUBE_FACE(textarget))) {
1511       _mesa_error(ctx, GL_INVALID_OPERATION,
1512                   "glFramebufferTexture2DEXT(textarget)");
1513       return;
1514    }
1515
1516    framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1517                        level, 0);
1518 }
1519
1520
1521 void GLAPIENTRY
1522 _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1523                               GLenum textarget, GLuint texture,
1524                               GLint level, GLint zoffset)
1525 {
1526    GET_CURRENT_CONTEXT(ctx);
1527
1528    if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1529       _mesa_error(ctx, GL_INVALID_ENUM,
1530                   "glFramebufferTexture3DEXT(textarget)");
1531       return;
1532    }
1533
1534    framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
1535                        level, zoffset);
1536 }
1537
1538
1539 void GLAPIENTRY
1540 _mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1541                                  GLuint texture, GLint level, GLint layer)
1542 {
1543    GET_CURRENT_CONTEXT(ctx);
1544
1545    framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1546                        level, layer);
1547 }
1548
1549
1550 void GLAPIENTRY
1551 _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1552                                  GLenum renderbufferTarget,
1553                                  GLuint renderbuffer)
1554 {
1555    struct gl_renderbuffer_attachment *att;
1556    struct gl_framebuffer *fb;
1557    struct gl_renderbuffer *rb;
1558    GET_CURRENT_CONTEXT(ctx);
1559
1560    ASSERT_OUTSIDE_BEGIN_END(ctx);
1561
1562    switch (target) {
1563 #if FEATURE_EXT_framebuffer_blit
1564    case GL_DRAW_FRAMEBUFFER_EXT:
1565       if (!ctx->Extensions.EXT_framebuffer_blit) {
1566          _mesa_error(ctx, GL_INVALID_ENUM,
1567                      "glFramebufferRenderbufferEXT(target)");
1568          return;
1569       }
1570       fb = ctx->DrawBuffer;
1571       break;
1572    case GL_READ_FRAMEBUFFER_EXT:
1573       if (!ctx->Extensions.EXT_framebuffer_blit) {
1574          _mesa_error(ctx, GL_INVALID_ENUM,
1575                      "glFramebufferRenderbufferEXT(target)");
1576          return;
1577       }
1578       fb = ctx->ReadBuffer;
1579       break;
1580 #endif
1581    case GL_FRAMEBUFFER_EXT:
1582       fb = ctx->DrawBuffer;
1583       break;
1584    default:
1585       _mesa_error(ctx, GL_INVALID_ENUM,
1586                   "glFramebufferRenderbufferEXT(target)");
1587       return;
1588    }
1589
1590    if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
1591       _mesa_error(ctx, GL_INVALID_ENUM,
1592                   "glFramebufferRenderbufferEXT(renderbufferTarget)");
1593       return;
1594    }
1595
1596    if (fb->Name == 0) {
1597       /* Can't attach new renderbuffers to a window system framebuffer */
1598       _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1599       return;
1600    }
1601
1602    att = _mesa_get_attachment(ctx, fb, attachment);
1603    if (att == NULL) {
1604       _mesa_error(ctx, GL_INVALID_ENUM,
1605                  "glFramebufferRenderbufferEXT(attachment)");
1606       return;
1607    }
1608
1609    if (renderbuffer) {
1610       rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
1611       if (!rb) {
1612          _mesa_error(ctx, GL_INVALID_OPERATION,
1613                      "glFramebufferRenderbufferEXT(renderbuffer)");
1614          return;
1615       }
1616    }
1617    else {
1618       /* remove renderbuffer attachment */
1619       rb = NULL;
1620    }
1621
1622    if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
1623       /* make sure the renderbuffer is a depth/stencil format */
1624       if (rb->_BaseFormat != GL_DEPTH_STENCIL) {
1625          _mesa_error(ctx, GL_INVALID_OPERATION,
1626                      "glFramebufferRenderbufferEXT(renderbuffer"
1627                      " is not DEPTH_STENCIL format)");
1628          return;
1629       }
1630    }
1631
1632
1633    FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1634    /* The above doesn't fully flush the drivers in the way that a
1635     * glFlush does, but that is required here:
1636     */
1637    if (ctx->Driver.Flush)
1638       ctx->Driver.Flush(ctx);
1639
1640    assert(ctx->Driver.FramebufferRenderbuffer);
1641    ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
1642
1643    /* Some subsequent GL commands may depend on the framebuffer's visual
1644     * after the binding is updated.  Update visual info now.
1645     */
1646    _mesa_update_framebuffer_visual(fb);
1647 }
1648
1649
1650 void GLAPIENTRY
1651 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1652                                              GLenum pname, GLint *params)
1653 {
1654    const struct gl_renderbuffer_attachment *att;
1655    struct gl_framebuffer *buffer;
1656    GET_CURRENT_CONTEXT(ctx);
1657
1658    ASSERT_OUTSIDE_BEGIN_END(ctx);
1659
1660    switch (target) {
1661 #if FEATURE_EXT_framebuffer_blit
1662    case GL_DRAW_FRAMEBUFFER_EXT:
1663       if (!ctx->Extensions.EXT_framebuffer_blit) {
1664          _mesa_error(ctx, GL_INVALID_ENUM,
1665                      "glGetFramebufferAttachmentParameterivEXT(target)");
1666          return;
1667       }
1668       buffer = ctx->DrawBuffer;
1669       break;
1670    case GL_READ_FRAMEBUFFER_EXT:
1671       if (!ctx->Extensions.EXT_framebuffer_blit) {
1672          _mesa_error(ctx, GL_INVALID_ENUM,
1673                      "glGetFramebufferAttachmentParameterivEXT(target)");
1674          return;
1675       }
1676       buffer = ctx->ReadBuffer;
1677       break;
1678 #endif
1679    case GL_FRAMEBUFFER_EXT:
1680       buffer = ctx->DrawBuffer;
1681       break;
1682    default:
1683       _mesa_error(ctx, GL_INVALID_ENUM,
1684                   "glGetFramebufferAttachmentParameterivEXT(target)");
1685       return;
1686    }
1687
1688    if (buffer->Name == 0) {
1689       _mesa_error(ctx, GL_INVALID_OPERATION,
1690                   "glGetFramebufferAttachmentParameterivEXT");
1691       return;
1692    }
1693
1694    att = _mesa_get_attachment(ctx, buffer, attachment);
1695    if (att == NULL) {
1696       _mesa_error(ctx, GL_INVALID_ENUM,
1697                   "glGetFramebufferAttachmentParameterivEXT(attachment)");
1698       return;
1699    }
1700
1701    if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
1702       /* the depth and stencil attachments must point to the same buffer */
1703       const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
1704       depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
1705       stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
1706       if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
1707          _mesa_error(ctx, GL_INVALID_OPERATION,
1708                      "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
1709                      " attachments differ)");
1710          return;
1711       }
1712    }
1713
1714    FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1715    /* The above doesn't fully flush the drivers in the way that a
1716     * glFlush does, but that is required here:
1717     */
1718    if (ctx->Driver.Flush)
1719       ctx->Driver.Flush(ctx);
1720
1721    switch (pname) {
1722    case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
1723       *params = att->Type;
1724       return;
1725    case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
1726       if (att->Type == GL_RENDERBUFFER_EXT) {
1727          *params = att->Renderbuffer->Name;
1728       }
1729       else if (att->Type == GL_TEXTURE) {
1730          *params = att->Texture->Name;
1731       }
1732       else {
1733          _mesa_error(ctx, GL_INVALID_ENUM,
1734                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1735       }
1736       return;
1737    case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
1738       if (att->Type == GL_TEXTURE) {
1739          *params = att->TextureLevel;
1740       }
1741       else {
1742          _mesa_error(ctx, GL_INVALID_ENUM,
1743                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1744       }
1745       return;
1746    case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
1747       if (att->Type == GL_TEXTURE) {
1748          if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
1749             *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1750          }
1751          else {
1752             *params = 0;
1753          }
1754       }
1755       else {
1756          _mesa_error(ctx, GL_INVALID_ENUM,
1757                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1758       }
1759       return;
1760    case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
1761       if (att->Type == GL_TEXTURE) {
1762          if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
1763             *params = att->Zoffset;
1764          }
1765          else {
1766             *params = 0;
1767          }
1768       }
1769       else {
1770          _mesa_error(ctx, GL_INVALID_ENUM,
1771                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1772       }
1773       return;
1774    case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
1775       if (!ctx->Extensions.ARB_framebuffer_object) {
1776          _mesa_error(ctx, GL_INVALID_ENUM,
1777                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1778       }
1779       else {
1780          *params = att->Renderbuffer->ColorEncoding;
1781       }
1782       return;
1783    case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
1784       if (!ctx->Extensions.ARB_framebuffer_object) {
1785          _mesa_error(ctx, GL_INVALID_ENUM,
1786                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1787          return;
1788       }
1789       else {
1790          *params = att->Renderbuffer->ComponentType;
1791       }
1792       return;
1793    case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
1794       if (!ctx->Extensions.ARB_framebuffer_object) {
1795          _mesa_error(ctx, GL_INVALID_ENUM,
1796                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1797       }
1798       else {
1799          *params = att->Renderbuffer->RedBits;
1800       }
1801       return;
1802    case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
1803       if (!ctx->Extensions.ARB_framebuffer_object) {
1804          _mesa_error(ctx, GL_INVALID_ENUM,
1805                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1806       }
1807       else {
1808          *params = att->Renderbuffer->GreenBits;
1809       }
1810       return;
1811    case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
1812       if (!ctx->Extensions.ARB_framebuffer_object) {
1813          _mesa_error(ctx, GL_INVALID_ENUM,
1814                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1815       }
1816       else {
1817          *params = att->Renderbuffer->BlueBits;
1818       }
1819       return;
1820    case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
1821       if (!ctx->Extensions.ARB_framebuffer_object) {
1822          _mesa_error(ctx, GL_INVALID_ENUM,
1823                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1824       }
1825       else {
1826          *params = att->Renderbuffer->AlphaBits;
1827       }
1828       return;
1829    case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
1830       if (!ctx->Extensions.ARB_framebuffer_object) {
1831          _mesa_error(ctx, GL_INVALID_ENUM,
1832                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1833       }
1834       else {
1835          *params = att->Renderbuffer->DepthBits;
1836       }
1837       return;
1838    case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
1839       if (!ctx->Extensions.ARB_framebuffer_object) {
1840          _mesa_error(ctx, GL_INVALID_ENUM,
1841                      "glGetFramebufferAttachmentParameterivEXT(pname)");
1842       }
1843       else {
1844          *params = att->Renderbuffer->StencilBits;
1845       }
1846       return;
1847    default:
1848       _mesa_error(ctx, GL_INVALID_ENUM,
1849                   "glGetFramebufferAttachmentParameterivEXT(pname)");
1850       return;
1851    }
1852 }
1853
1854
1855 void GLAPIENTRY
1856 _mesa_GenerateMipmapEXT(GLenum target)
1857 {
1858    struct gl_texture_unit *texUnit;
1859    struct gl_texture_object *texObj;
1860    GET_CURRENT_CONTEXT(ctx);
1861
1862    ASSERT_OUTSIDE_BEGIN_END(ctx);
1863    FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1864
1865    switch (target) {
1866    case GL_TEXTURE_1D:
1867    case GL_TEXTURE_2D:
1868    case GL_TEXTURE_3D:
1869    case GL_TEXTURE_CUBE_MAP:
1870       /* OK, legal value */
1871       break;
1872    default:
1873       _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
1874       return;
1875    }
1876
1877    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1878    texObj = _mesa_select_tex_object(ctx, texUnit, target);
1879
1880    _mesa_lock_texture(ctx, texObj);
1881    if (target == GL_TEXTURE_CUBE_MAP) {
1882       int face;
1883
1884       for (face = 0; face < 6; face++)
1885          ctx->Driver.GenerateMipmap(ctx,
1886                                     GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
1887                                     texObj);
1888    } else {
1889       ctx->Driver.GenerateMipmap(ctx, target, texObj);
1890    }
1891    _mesa_unlock_texture(ctx, texObj);
1892 }
1893
1894
1895 #if FEATURE_EXT_framebuffer_blit
1896 /**
1897  * Blit rectangular region, optionally from one framebuffer to another.
1898  *
1899  * Note, if the src buffer is multisampled and the dest is not, this is
1900  * when the samples must be resolved to a single color.
1901  */
1902 void GLAPIENTRY
1903 _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
1904                          GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
1905                          GLbitfield mask, GLenum filter)
1906 {
1907    const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
1908                                      GL_DEPTH_BUFFER_BIT |
1909                                      GL_STENCIL_BUFFER_BIT);
1910    const struct gl_framebuffer *readFb, *drawFb;
1911    const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
1912    GET_CURRENT_CONTEXT(ctx);
1913
1914    ASSERT_OUTSIDE_BEGIN_END(ctx);
1915    FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1916
1917    if (ctx->NewState) {
1918       _mesa_update_state(ctx);
1919    }
1920
1921    readFb = ctx->ReadBuffer;
1922    drawFb = ctx->DrawBuffer;
1923
1924    if (!readFb || !drawFb) {
1925       /* This will normally never happen but someday we may want to
1926        * support MakeCurrent() with no drawables.
1927        */
1928       return;
1929    }
1930
1931    /* check for complete framebuffers */
1932    if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
1933        readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1934       _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
1935                   "glBlitFramebufferEXT(incomplete draw/read buffers)");
1936       return;
1937    }
1938
1939    if (filter != GL_NEAREST && filter != GL_LINEAR) {
1940       _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
1941       return;
1942    }
1943
1944    if (mask & ~legalMaskBits) {
1945       _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
1946       return;
1947    }
1948
1949    /* depth/stencil must be blitted with nearest filtering */
1950    if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
1951         && filter != GL_NEAREST) {
1952       _mesa_error(ctx, GL_INVALID_OPERATION,
1953              "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
1954       return;
1955    }
1956
1957    /* get color read/draw renderbuffers */
1958    if (mask & GL_COLOR_BUFFER_BIT) {
1959       colorReadRb = readFb->_ColorReadBuffer;
1960       colorDrawRb = drawFb->_ColorDrawBuffers[0];
1961    }
1962    else {
1963       colorReadRb = colorDrawRb = NULL;
1964    }
1965
1966    if (mask & GL_STENCIL_BUFFER_BIT) {
1967       struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
1968       struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
1969       if (readRb->StencilBits != drawRb->StencilBits) {
1970          _mesa_error(ctx, GL_INVALID_OPERATION,
1971                      "glBlitFramebufferEXT(stencil buffer size mismatch");
1972          return;
1973       }
1974    }
1975
1976    if (mask & GL_DEPTH_BUFFER_BIT) {
1977       struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
1978       struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
1979       if (readRb->DepthBits != drawRb->DepthBits) {
1980          _mesa_error(ctx, GL_INVALID_OPERATION,
1981                      "glBlitFramebufferEXT(depth buffer size mismatch");
1982          return;
1983       }
1984    }
1985
1986    if (readFb->Visual.samples > 0 &&
1987        drawFb->Visual.samples > 0 &&
1988        readFb->Visual.samples != drawFb->Visual.samples) {
1989       _mesa_error(ctx, GL_INVALID_OPERATION,
1990                   "glBlitFramebufferEXT(mismatched samples");
1991       return;
1992    }
1993
1994    /* extra checks for multisample copies... */
1995    if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
1996       /* src and dest region sizes must be the same */
1997       if (srcX1 - srcX0 != dstX1 - dstX0 ||
1998           srcY1 - srcY0 != dstY1 - dstY0) {
1999          _mesa_error(ctx, GL_INVALID_OPERATION,
2000                 "glBlitFramebufferEXT(bad src/dst multisample region sizes");
2001          return;
2002       }
2003
2004       /* color formats must match */
2005       if (colorReadRb &&
2006           colorDrawRb &&
2007           colorReadRb->_ActualFormat != colorDrawRb->_ActualFormat) {
2008          _mesa_error(ctx, GL_INVALID_OPERATION,
2009                 "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
2010          return;
2011       }
2012    }
2013
2014    if (!ctx->Extensions.EXT_framebuffer_blit) {
2015       _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
2016       return;
2017    }
2018
2019    ASSERT(ctx->Driver.BlitFramebuffer);
2020    ctx->Driver.BlitFramebuffer(ctx,
2021                                srcX0, srcY0, srcX1, srcY1,
2022                                dstX0, dstY0, dstX1, dstY1,
2023                                mask, filter);
2024 }
2025 #endif /* FEATURE_EXT_framebuffer_blit */