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