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