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