Merge branch 'master' into gallium-texture-transfer
[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 that we're done rendering to this texture. */
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_reference_framebuffer(&fb, NULL);
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    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
1508 void 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
1525 void 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
1545 void 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
1563 void 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
1574 void 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
1674 void 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
1879 void 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  */
1926 void 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 */