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