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