fbobject.c revision 4a49301e
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
3c1f859d4Smrg * Version:  7.1
47117f1b4Smrg *
5c1f859d4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
64a49301eSmrg * Copyright (C) 1999-2009  VMware, Inc.  All Rights Reserved.
77117f1b4Smrg *
87117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
97117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
107117f1b4Smrg * to deal in the Software without restriction, including without limitation
117117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
127117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
137117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
147117f1b4Smrg *
157117f1b4Smrg * The above copyright notice and this permission notice shall be included
167117f1b4Smrg * in all copies or substantial portions of the Software.
177117f1b4Smrg *
187117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
197117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
207117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
217117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
227117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
237117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
267117f1b4Smrg
277117f1b4Smrg/*
284a49301eSmrg * GL_EXT/ARB_framebuffer_object extensions
294a49301eSmrg *
307117f1b4Smrg * Authors:
317117f1b4Smrg *   Brian Paul
327117f1b4Smrg */
337117f1b4Smrg
347117f1b4Smrg
35c1f859d4Smrg#include "buffers.h"
367117f1b4Smrg#include "context.h"
374a49301eSmrg#include "enums.h"
387117f1b4Smrg#include "fbobject.h"
394a49301eSmrg#include "formats.h"
407117f1b4Smrg#include "framebuffer.h"
417117f1b4Smrg#include "hash.h"
424a49301eSmrg#include "macros.h"
437117f1b4Smrg#include "renderbuffer.h"
447117f1b4Smrg#include "state.h"
457117f1b4Smrg#include "teximage.h"
467117f1b4Smrg#include "texobj.h"
474a49301eSmrg
484a49301eSmrg
494a49301eSmrg/** Set this to 1 to help debug FBO incompleteness problems */
504a49301eSmrg#define DEBUG_FBO 0
514a49301eSmrg
524a49301eSmrg/** Set this to 1 to debug/log glBlitFramebuffer() calls */
534a49301eSmrg#define DEBUG_BLIT 0
547117f1b4Smrg
557117f1b4Smrg
567117f1b4Smrg/**
577117f1b4Smrg * Notes:
587117f1b4Smrg *
597117f1b4Smrg * None of the GL_EXT_framebuffer_object functions are compiled into
607117f1b4Smrg * display lists.
617117f1b4Smrg */
627117f1b4Smrg
637117f1b4Smrg
647117f1b4Smrg
657117f1b4Smrg/*
667117f1b4Smrg * When glGenRender/FramebuffersEXT() is called we insert pointers to
677117f1b4Smrg * these placeholder objects into the hash table.
687117f1b4Smrg * Later, when the object ID is first bound, we replace the placeholder
697117f1b4Smrg * with the real frame/renderbuffer.
707117f1b4Smrg */
717117f1b4Smrgstatic struct gl_framebuffer DummyFramebuffer;
727117f1b4Smrgstatic struct gl_renderbuffer DummyRenderbuffer;
737117f1b4Smrg
747117f1b4Smrg
757117f1b4Smrg#define IS_CUBE_FACE(TARGET) \
767117f1b4Smrg   ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
777117f1b4Smrg    (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
787117f1b4Smrg
797117f1b4Smrg
80c1f859d4Smrgstatic void
81c1f859d4Smrgdelete_dummy_renderbuffer(struct gl_renderbuffer *rb)
82c1f859d4Smrg{
83c1f859d4Smrg   /* no op */
84c1f859d4Smrg}
85c1f859d4Smrg
86c1f859d4Smrgstatic void
87c1f859d4Smrgdelete_dummy_framebuffer(struct gl_framebuffer *fb)
88c1f859d4Smrg{
89c1f859d4Smrg   /* no op */
90c1f859d4Smrg}
91c1f859d4Smrg
92c1f859d4Smrg
93c1f859d4Smrgvoid
94c1f859d4Smrg_mesa_init_fbobjects(GLcontext *ctx)
95c1f859d4Smrg{
96c1f859d4Smrg   DummyFramebuffer.Delete = delete_dummy_framebuffer;
97c1f859d4Smrg   DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
98c1f859d4Smrg}
99c1f859d4Smrg
100c1f859d4Smrg
1017117f1b4Smrg/**
1027117f1b4Smrg * Helper routine for getting a gl_renderbuffer.
1037117f1b4Smrg */
1047117f1b4Smrgstruct gl_renderbuffer *
1057117f1b4Smrg_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id)
1067117f1b4Smrg{
1077117f1b4Smrg   struct gl_renderbuffer *rb;
1087117f1b4Smrg
1097117f1b4Smrg   if (id == 0)
1107117f1b4Smrg      return NULL;
1117117f1b4Smrg
1127117f1b4Smrg   rb = (struct gl_renderbuffer *)
1137117f1b4Smrg      _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
1147117f1b4Smrg   return rb;
1157117f1b4Smrg}
1167117f1b4Smrg
1177117f1b4Smrg
1187117f1b4Smrg/**
1197117f1b4Smrg * Helper routine for getting a gl_framebuffer.
1207117f1b4Smrg */
1217117f1b4Smrgstruct gl_framebuffer *
1227117f1b4Smrg_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id)
1237117f1b4Smrg{
1247117f1b4Smrg   struct gl_framebuffer *fb;
1257117f1b4Smrg
1267117f1b4Smrg   if (id == 0)
1277117f1b4Smrg      return NULL;
1287117f1b4Smrg
1297117f1b4Smrg   fb = (struct gl_framebuffer *)
1307117f1b4Smrg      _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
1317117f1b4Smrg   return fb;
1327117f1b4Smrg}
1337117f1b4Smrg
1347117f1b4Smrg
1354a49301eSmrg/**
1364a49301eSmrg * Mark the given framebuffer as invalid.  This will force the
1374a49301eSmrg * test for framebuffer completeness to be done before the framebuffer
1384a49301eSmrg * is used.
1394a49301eSmrg */
1404a49301eSmrgstatic void
1414a49301eSmrginvalidate_framebuffer(struct gl_framebuffer *fb)
1424a49301eSmrg{
1434a49301eSmrg   fb->_Status = 0; /* "indeterminate" */
1444a49301eSmrg}
1454a49301eSmrg
1464a49301eSmrg
1477117f1b4Smrg/**
1487117f1b4Smrg * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
1497117f1b4Smrg * gl_renderbuffer_attachment object.
1504a49301eSmrg * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
1514a49301eSmrg * the depth buffer attachment point.
1527117f1b4Smrg */
1537117f1b4Smrgstruct gl_renderbuffer_attachment *
1547117f1b4Smrg_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
1557117f1b4Smrg                     GLenum attachment)
1567117f1b4Smrg{
1577117f1b4Smrg   GLuint i;
1587117f1b4Smrg
1597117f1b4Smrg   switch (attachment) {
1607117f1b4Smrg   case GL_COLOR_ATTACHMENT0_EXT:
1617117f1b4Smrg   case GL_COLOR_ATTACHMENT1_EXT:
1627117f1b4Smrg   case GL_COLOR_ATTACHMENT2_EXT:
1637117f1b4Smrg   case GL_COLOR_ATTACHMENT3_EXT:
1647117f1b4Smrg   case GL_COLOR_ATTACHMENT4_EXT:
1657117f1b4Smrg   case GL_COLOR_ATTACHMENT5_EXT:
1667117f1b4Smrg   case GL_COLOR_ATTACHMENT6_EXT:
1677117f1b4Smrg   case GL_COLOR_ATTACHMENT7_EXT:
1687117f1b4Smrg   case GL_COLOR_ATTACHMENT8_EXT:
1697117f1b4Smrg   case GL_COLOR_ATTACHMENT9_EXT:
1707117f1b4Smrg   case GL_COLOR_ATTACHMENT10_EXT:
1717117f1b4Smrg   case GL_COLOR_ATTACHMENT11_EXT:
1727117f1b4Smrg   case GL_COLOR_ATTACHMENT12_EXT:
1737117f1b4Smrg   case GL_COLOR_ATTACHMENT13_EXT:
1747117f1b4Smrg   case GL_COLOR_ATTACHMENT14_EXT:
1757117f1b4Smrg   case GL_COLOR_ATTACHMENT15_EXT:
1767117f1b4Smrg      i = attachment - GL_COLOR_ATTACHMENT0_EXT;
1777117f1b4Smrg      if (i >= ctx->Const.MaxColorAttachments) {
1787117f1b4Smrg	 return NULL;
1797117f1b4Smrg      }
1807117f1b4Smrg      return &fb->Attachment[BUFFER_COLOR0 + i];
1814a49301eSmrg   case GL_DEPTH_STENCIL_ATTACHMENT:
1824a49301eSmrg      /* fall-through */
1837117f1b4Smrg   case GL_DEPTH_ATTACHMENT_EXT:
1847117f1b4Smrg      return &fb->Attachment[BUFFER_DEPTH];
1857117f1b4Smrg   case GL_STENCIL_ATTACHMENT_EXT:
1867117f1b4Smrg      return &fb->Attachment[BUFFER_STENCIL];
1877117f1b4Smrg   default:
1887117f1b4Smrg      return NULL;
1897117f1b4Smrg   }
1907117f1b4Smrg}
1917117f1b4Smrg
1927117f1b4Smrg
1937117f1b4Smrg/**
1947117f1b4Smrg * Remove any texture or renderbuffer attached to the given attachment
1957117f1b4Smrg * point.  Update reference counts, etc.
1967117f1b4Smrg */
1977117f1b4Smrgvoid
1987117f1b4Smrg_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
1997117f1b4Smrg{
2007117f1b4Smrg   if (att->Type == GL_TEXTURE) {
2017117f1b4Smrg      ASSERT(att->Texture);
2027117f1b4Smrg      if (ctx->Driver.FinishRenderTexture) {
2034a49301eSmrg         /* tell driver that we're done rendering to this texture. */
2047117f1b4Smrg         ctx->Driver.FinishRenderTexture(ctx, att);
2057117f1b4Smrg      }
2067117f1b4Smrg      _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
2077117f1b4Smrg      ASSERT(!att->Texture);
2087117f1b4Smrg   }
2097117f1b4Smrg   if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
2107117f1b4Smrg      ASSERT(!att->Texture);
2117117f1b4Smrg      _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
2127117f1b4Smrg      ASSERT(!att->Renderbuffer);
2137117f1b4Smrg   }
2147117f1b4Smrg   att->Type = GL_NONE;
2157117f1b4Smrg   att->Complete = GL_TRUE;
2167117f1b4Smrg}
2177117f1b4Smrg
2187117f1b4Smrg
2197117f1b4Smrg/**
2207117f1b4Smrg * Bind a texture object to an attachment point.
2217117f1b4Smrg * The previous binding, if any, will be removed first.
2227117f1b4Smrg */
2237117f1b4Smrgvoid
2247117f1b4Smrg_mesa_set_texture_attachment(GLcontext *ctx,
2257117f1b4Smrg                             struct gl_framebuffer *fb,
2267117f1b4Smrg                             struct gl_renderbuffer_attachment *att,
2277117f1b4Smrg                             struct gl_texture_object *texObj,
2287117f1b4Smrg                             GLenum texTarget, GLuint level, GLuint zoffset)
2297117f1b4Smrg{
2307117f1b4Smrg   if (att->Texture == texObj) {
2317117f1b4Smrg      /* re-attaching same texture */
2327117f1b4Smrg      ASSERT(att->Type == GL_TEXTURE);
2334a49301eSmrg      if (ctx->Driver.FinishRenderTexture)
2344a49301eSmrg	 ctx->Driver.FinishRenderTexture(ctx, att);
2357117f1b4Smrg   }
2367117f1b4Smrg   else {
2377117f1b4Smrg      /* new attachment */
2384a49301eSmrg      if (ctx->Driver.FinishRenderTexture && att->Texture)
2394a49301eSmrg	 ctx->Driver.FinishRenderTexture(ctx, att);
2407117f1b4Smrg      _mesa_remove_attachment(ctx, att);
2417117f1b4Smrg      att->Type = GL_TEXTURE;
2427117f1b4Smrg      assert(!att->Texture);
2437117f1b4Smrg      _mesa_reference_texobj(&att->Texture, texObj);
2447117f1b4Smrg   }
2457117f1b4Smrg
2467117f1b4Smrg   /* always update these fields */
2477117f1b4Smrg   att->TextureLevel = level;
2484a49301eSmrg   att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
2497117f1b4Smrg   att->Zoffset = zoffset;
2507117f1b4Smrg   att->Complete = GL_FALSE;
2517117f1b4Smrg
2527117f1b4Smrg   if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
2537117f1b4Smrg      ctx->Driver.RenderTexture(ctx, fb, att);
2547117f1b4Smrg   }
2554a49301eSmrg
2564a49301eSmrg   invalidate_framebuffer(fb);
2577117f1b4Smrg}
2587117f1b4Smrg
2597117f1b4Smrg
2607117f1b4Smrg/**
2617117f1b4Smrg * Bind a renderbuffer to an attachment point.
2627117f1b4Smrg * The previous binding, if any, will be removed first.
2637117f1b4Smrg */
2647117f1b4Smrgvoid
2657117f1b4Smrg_mesa_set_renderbuffer_attachment(GLcontext *ctx,
2667117f1b4Smrg                                  struct gl_renderbuffer_attachment *att,
2677117f1b4Smrg                                  struct gl_renderbuffer *rb)
2687117f1b4Smrg{
2697117f1b4Smrg   /* XXX check if re-doing same attachment, exit early */
2707117f1b4Smrg   _mesa_remove_attachment(ctx, att);
2717117f1b4Smrg   att->Type = GL_RENDERBUFFER_EXT;
2727117f1b4Smrg   att->Texture = NULL; /* just to be safe */
2737117f1b4Smrg   att->Complete = GL_FALSE;
2747117f1b4Smrg   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
2757117f1b4Smrg}
2767117f1b4Smrg
2777117f1b4Smrg
2787117f1b4Smrg/**
2797117f1b4Smrg * Fallback for ctx->Driver.FramebufferRenderbuffer()
2807117f1b4Smrg * Attach a renderbuffer object to a framebuffer object.
2817117f1b4Smrg */
2827117f1b4Smrgvoid
2837117f1b4Smrg_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
2847117f1b4Smrg                               GLenum attachment, struct gl_renderbuffer *rb)
2857117f1b4Smrg{
2867117f1b4Smrg   struct gl_renderbuffer_attachment *att;
2877117f1b4Smrg
2887117f1b4Smrg   _glthread_LOCK_MUTEX(fb->Mutex);
2897117f1b4Smrg
2907117f1b4Smrg   att = _mesa_get_attachment(ctx, fb, attachment);
2917117f1b4Smrg   ASSERT(att);
2927117f1b4Smrg   if (rb) {
2937117f1b4Smrg      _mesa_set_renderbuffer_attachment(ctx, att, rb);
2944a49301eSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2954a49301eSmrg         /* do stencil attachment here (depth already done above) */
2964a49301eSmrg         att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
2974a49301eSmrg         assert(att);
2984a49301eSmrg         _mesa_set_renderbuffer_attachment(ctx, att, rb);
2994a49301eSmrg      }
3007117f1b4Smrg   }
3017117f1b4Smrg   else {
3027117f1b4Smrg      _mesa_remove_attachment(ctx, att);
3037117f1b4Smrg   }
3047117f1b4Smrg
3054a49301eSmrg   invalidate_framebuffer(fb);
3064a49301eSmrg
3077117f1b4Smrg   _glthread_UNLOCK_MUTEX(fb->Mutex);
3087117f1b4Smrg}
3097117f1b4Smrg
3107117f1b4Smrg
3114a49301eSmrg/**
3124a49301eSmrg * For debug only.
3134a49301eSmrg */
3144a49301eSmrgstatic void
3154a49301eSmrgatt_incomplete(const char *msg)
3164a49301eSmrg{
3174a49301eSmrg#if DEBUG_FBO
3184a49301eSmrg   _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
3194a49301eSmrg#else
3204a49301eSmrg   (void) msg;
3214a49301eSmrg#endif
3224a49301eSmrg}
3234a49301eSmrg
3244a49301eSmrg
3254a49301eSmrg/**
3264a49301eSmrg * For debug only.
3274a49301eSmrg */
3284a49301eSmrgstatic void
3294a49301eSmrgfbo_incomplete(const char *msg, int index)
3304a49301eSmrg{
3314a49301eSmrg#if DEBUG_FBO
3324a49301eSmrg   _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
3334a49301eSmrg#else
3344a49301eSmrg   (void) msg;
3354a49301eSmrg   (void) index;
3364a49301eSmrg#endif
3374a49301eSmrg}
3384a49301eSmrg
3394a49301eSmrg
3404a49301eSmrg
3414a49301eSmrg
3427117f1b4Smrg/**
3437117f1b4Smrg * Test if an attachment point is complete and update its Complete field.
3447117f1b4Smrg * \param format if GL_COLOR, this is a color attachment point,
3457117f1b4Smrg *               if GL_DEPTH, this is a depth component attachment point,
3467117f1b4Smrg *               if GL_STENCIL, this is a stencil component attachment point.
3477117f1b4Smrg */
3487117f1b4Smrgstatic void
3497117f1b4Smrgtest_attachment_completeness(const GLcontext *ctx, GLenum format,
3507117f1b4Smrg                             struct gl_renderbuffer_attachment *att)
3517117f1b4Smrg{
3527117f1b4Smrg   assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
3537117f1b4Smrg
3547117f1b4Smrg   /* assume complete */
3557117f1b4Smrg   att->Complete = GL_TRUE;
3567117f1b4Smrg
3577117f1b4Smrg   /* Look for reasons why the attachment might be incomplete */
3587117f1b4Smrg   if (att->Type == GL_TEXTURE) {
3597117f1b4Smrg      const struct gl_texture_object *texObj = att->Texture;
3607117f1b4Smrg      struct gl_texture_image *texImage;
3614a49301eSmrg      GLenum baseFormat;
3627117f1b4Smrg
3637117f1b4Smrg      if (!texObj) {
3644a49301eSmrg         att_incomplete("no texobj");
3657117f1b4Smrg         att->Complete = GL_FALSE;
3667117f1b4Smrg         return;
3677117f1b4Smrg      }
3687117f1b4Smrg
3697117f1b4Smrg      texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
3707117f1b4Smrg      if (!texImage) {
3714a49301eSmrg         att_incomplete("no teximage");
3727117f1b4Smrg         att->Complete = GL_FALSE;
3737117f1b4Smrg         return;
3747117f1b4Smrg      }
3757117f1b4Smrg      if (texImage->Width < 1 || texImage->Height < 1) {
3764a49301eSmrg         att_incomplete("teximage width/height=0");
3774a49301eSmrg         _mesa_printf("texobj = %u\n", texObj->Name);
3784a49301eSmrg         _mesa_printf("level = %d\n", att->TextureLevel);
3797117f1b4Smrg         att->Complete = GL_FALSE;
3807117f1b4Smrg         return;
3817117f1b4Smrg      }
3827117f1b4Smrg      if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
3834a49301eSmrg         att_incomplete("bad z offset");
3847117f1b4Smrg         att->Complete = GL_FALSE;
3857117f1b4Smrg         return;
3867117f1b4Smrg      }
3877117f1b4Smrg
3884a49301eSmrg      baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
3894a49301eSmrg
3907117f1b4Smrg      if (format == GL_COLOR) {
3914a49301eSmrg         if (baseFormat != GL_RGB &&
3924a49301eSmrg             baseFormat != GL_RGBA) {
3934a49301eSmrg            att_incomplete("bad format");
3944a49301eSmrg            att->Complete = GL_FALSE;
3954a49301eSmrg            return;
3964a49301eSmrg         }
3974a49301eSmrg         if (_mesa_is_format_compressed(texImage->TexFormat)) {
3984a49301eSmrg            att_incomplete("compressed internalformat");
3997117f1b4Smrg            att->Complete = GL_FALSE;
4007117f1b4Smrg            return;
4017117f1b4Smrg         }
4027117f1b4Smrg      }
4037117f1b4Smrg      else if (format == GL_DEPTH) {
4044a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
4057117f1b4Smrg            /* OK */
4067117f1b4Smrg         }
4077117f1b4Smrg         else if (ctx->Extensions.EXT_packed_depth_stencil &&
408c7037ccdSmrg                  ctx->Extensions.ARB_depth_texture &&
4094a49301eSmrg                  baseFormat == GL_DEPTH_STENCIL_EXT) {
4107117f1b4Smrg            /* OK */
4117117f1b4Smrg         }
4127117f1b4Smrg         else {
4137117f1b4Smrg            att->Complete = GL_FALSE;
4144a49301eSmrg            att_incomplete("bad depth format");
4157117f1b4Smrg            return;
4167117f1b4Smrg         }
4177117f1b4Smrg      }
4187117f1b4Smrg      else {
419c7037ccdSmrg         ASSERT(format == GL_STENCIL);
420c7037ccdSmrg         if (ctx->Extensions.EXT_packed_depth_stencil &&
421c7037ccdSmrg             ctx->Extensions.ARB_depth_texture &&
4224a49301eSmrg             baseFormat == GL_DEPTH_STENCIL_EXT) {
423c7037ccdSmrg            /* OK */
424c7037ccdSmrg         }
425c7037ccdSmrg         else {
426c7037ccdSmrg            /* no such thing as stencil-only textures */
4274a49301eSmrg            att_incomplete("illegal stencil texture");
428c7037ccdSmrg            att->Complete = GL_FALSE;
429c7037ccdSmrg            return;
430c7037ccdSmrg         }
4317117f1b4Smrg      }
4327117f1b4Smrg   }
4337117f1b4Smrg   else if (att->Type == GL_RENDERBUFFER_EXT) {
4344a49301eSmrg      const GLenum baseFormat =
4354a49301eSmrg         _mesa_get_format_base_format(att->Renderbuffer->Format);
4364a49301eSmrg
4377117f1b4Smrg      ASSERT(att->Renderbuffer);
4387117f1b4Smrg      if (!att->Renderbuffer->InternalFormat ||
4397117f1b4Smrg          att->Renderbuffer->Width < 1 ||
4407117f1b4Smrg          att->Renderbuffer->Height < 1) {
4414a49301eSmrg         att_incomplete("0x0 renderbuffer");
4427117f1b4Smrg         att->Complete = GL_FALSE;
4437117f1b4Smrg         return;
4447117f1b4Smrg      }
4457117f1b4Smrg      if (format == GL_COLOR) {
4464a49301eSmrg         if (baseFormat != GL_RGB &&
4474a49301eSmrg             baseFormat != GL_RGBA) {
4484a49301eSmrg            att_incomplete("bad renderbuffer color format");
4497117f1b4Smrg            att->Complete = GL_FALSE;
4507117f1b4Smrg            return;
4517117f1b4Smrg         }
4527117f1b4Smrg      }
4537117f1b4Smrg      else if (format == GL_DEPTH) {
4544a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
4557117f1b4Smrg            /* OK */
4567117f1b4Smrg         }
4577117f1b4Smrg         else if (ctx->Extensions.EXT_packed_depth_stencil &&
4584a49301eSmrg                  baseFormat == GL_DEPTH_STENCIL_EXT) {
4597117f1b4Smrg            /* OK */
4607117f1b4Smrg         }
4617117f1b4Smrg         else {
4624a49301eSmrg            att_incomplete("bad renderbuffer depth format");
4637117f1b4Smrg            att->Complete = GL_FALSE;
4647117f1b4Smrg            return;
4657117f1b4Smrg         }
4667117f1b4Smrg      }
4677117f1b4Smrg      else {
4687117f1b4Smrg         assert(format == GL_STENCIL);
4694a49301eSmrg         if (baseFormat == GL_STENCIL_INDEX) {
4707117f1b4Smrg            /* OK */
4717117f1b4Smrg         }
4727117f1b4Smrg         else if (ctx->Extensions.EXT_packed_depth_stencil &&
4734a49301eSmrg                  baseFormat == GL_DEPTH_STENCIL_EXT) {
4747117f1b4Smrg            /* OK */
4757117f1b4Smrg         }
4767117f1b4Smrg         else {
4777117f1b4Smrg            att->Complete = GL_FALSE;
4784a49301eSmrg            att_incomplete("bad renderbuffer stencil format");
4797117f1b4Smrg            return;
4807117f1b4Smrg         }
4817117f1b4Smrg      }
4827117f1b4Smrg   }
4837117f1b4Smrg   else {
4847117f1b4Smrg      ASSERT(att->Type == GL_NONE);
4857117f1b4Smrg      /* complete */
4867117f1b4Smrg      return;
4877117f1b4Smrg   }
4887117f1b4Smrg}
4897117f1b4Smrg
4907117f1b4Smrg
4917117f1b4Smrg/**
4927117f1b4Smrg * Test if the given framebuffer object is complete and update its
4937117f1b4Smrg * Status field with the results.
4944a49301eSmrg * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
4954a49301eSmrg * driver to make hardware-specific validation/completeness checks.
4967117f1b4Smrg * Also update the framebuffer's Width and Height fields if the
4977117f1b4Smrg * framebuffer is complete.
4987117f1b4Smrg */
4997117f1b4Smrgvoid
5007117f1b4Smrg_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
5017117f1b4Smrg{
5024a49301eSmrg   GLuint numImages;
5034a49301eSmrg   GLenum intFormat = GL_NONE; /* color buffers' internal format */
5044a49301eSmrg   GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
5054a49301eSmrg   GLint numSamples = -1;
5067117f1b4Smrg   GLint i;
5077117f1b4Smrg   GLuint j;
5087117f1b4Smrg
5097117f1b4Smrg   assert(fb->Name != 0);
5107117f1b4Smrg
5117117f1b4Smrg   numImages = 0;
5127117f1b4Smrg   fb->Width = 0;
5137117f1b4Smrg   fb->Height = 0;
5147117f1b4Smrg
5154a49301eSmrg   /* Start at -2 to more easily loop over all attachment points.
5164a49301eSmrg    *  -2: depth buffer
5174a49301eSmrg    *  -1: stencil buffer
5184a49301eSmrg    * >=0: color buffer
5194a49301eSmrg    */
5207117f1b4Smrg   for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
5217117f1b4Smrg      struct gl_renderbuffer_attachment *att;
5227117f1b4Smrg      GLenum f;
5237117f1b4Smrg
5244a49301eSmrg      /*
5254a49301eSmrg       * XXX for ARB_fbo, only check color buffers that are named by
5264a49301eSmrg       * GL_READ_BUFFER and GL_DRAW_BUFFERi.
5274a49301eSmrg       */
5284a49301eSmrg
5294a49301eSmrg      /* check for attachment completeness
5304a49301eSmrg       */
5317117f1b4Smrg      if (i == -2) {
5327117f1b4Smrg         att = &fb->Attachment[BUFFER_DEPTH];
5337117f1b4Smrg         test_attachment_completeness(ctx, GL_DEPTH, att);
5347117f1b4Smrg         if (!att->Complete) {
5357117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
5367117f1b4Smrg            fbo_incomplete("depth attachment incomplete", -1);
5377117f1b4Smrg            return;
5387117f1b4Smrg         }
5397117f1b4Smrg      }
5407117f1b4Smrg      else if (i == -1) {
5417117f1b4Smrg         att = &fb->Attachment[BUFFER_STENCIL];
5427117f1b4Smrg         test_attachment_completeness(ctx, GL_STENCIL, att);
5437117f1b4Smrg         if (!att->Complete) {
5447117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
5457117f1b4Smrg            fbo_incomplete("stencil attachment incomplete", -1);
5467117f1b4Smrg            return;
5477117f1b4Smrg         }
5487117f1b4Smrg      }
5497117f1b4Smrg      else {
5507117f1b4Smrg         att = &fb->Attachment[BUFFER_COLOR0 + i];
5517117f1b4Smrg         test_attachment_completeness(ctx, GL_COLOR, att);
5527117f1b4Smrg         if (!att->Complete) {
5537117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
5547117f1b4Smrg            fbo_incomplete("color attachment incomplete", i);
5557117f1b4Smrg            return;
5567117f1b4Smrg         }
5577117f1b4Smrg      }
5587117f1b4Smrg
5594a49301eSmrg      /* get width, height, format of the renderbuffer/texture
5604a49301eSmrg       */
5617117f1b4Smrg      if (att->Type == GL_TEXTURE) {
5627117f1b4Smrg         const struct gl_texture_image *texImg
5637117f1b4Smrg            = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
5644a49301eSmrg         minWidth = MIN2(minWidth, texImg->Width);
5654a49301eSmrg         maxWidth = MAX2(maxWidth, texImg->Width);
5664a49301eSmrg         minHeight = MIN2(minHeight, texImg->Height);
5674a49301eSmrg         maxHeight = MAX2(maxHeight, texImg->Height);
5687117f1b4Smrg         f = texImg->_BaseFormat;
5697117f1b4Smrg         numImages++;
5707117f1b4Smrg         if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT
5717117f1b4Smrg             && f != GL_DEPTH_STENCIL_EXT) {
5727117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
5737117f1b4Smrg            fbo_incomplete("texture attachment incomplete", -1);
5747117f1b4Smrg            return;
5757117f1b4Smrg         }
5767117f1b4Smrg      }
5777117f1b4Smrg      else if (att->Type == GL_RENDERBUFFER_EXT) {
5784a49301eSmrg         minWidth = MIN2(minWidth, att->Renderbuffer->Width);
5794a49301eSmrg         maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
5804a49301eSmrg         minHeight = MIN2(minHeight, att->Renderbuffer->Height);
5814a49301eSmrg         maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
5827117f1b4Smrg         f = att->Renderbuffer->InternalFormat;
5837117f1b4Smrg         numImages++;
5847117f1b4Smrg      }
5857117f1b4Smrg      else {
5867117f1b4Smrg         assert(att->Type == GL_NONE);
5877117f1b4Smrg         continue;
5887117f1b4Smrg      }
5897117f1b4Smrg
5904a49301eSmrg      if (numSamples < 0) {
5914a49301eSmrg         /* first buffer */
5924a49301eSmrg         numSamples = att->Renderbuffer->NumSamples;
5934a49301eSmrg      }
5944a49301eSmrg
5954a49301eSmrg      /* Error-check width, height, format, samples
5964a49301eSmrg       */
5977117f1b4Smrg      if (numImages == 1) {
5984a49301eSmrg         /* save format, num samples */
5994a49301eSmrg         if (i >= 0) {
6007117f1b4Smrg            intFormat = f;
6014a49301eSmrg         }
6027117f1b4Smrg      }
6037117f1b4Smrg      else {
6044a49301eSmrg         if (!ctx->Extensions.ARB_framebuffer_object) {
6054a49301eSmrg            /* check that width, height, format are same */
6064a49301eSmrg            if (minWidth != maxWidth || minHeight != maxHeight) {
6074a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
6084a49301eSmrg               fbo_incomplete("width or height mismatch", -1);
6094a49301eSmrg               return;
6104a49301eSmrg            }
6114a49301eSmrg            /* check that all color buffer have same format */
6124a49301eSmrg            if (intFormat != GL_NONE && f != intFormat) {
6134a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
6144a49301eSmrg               fbo_incomplete("format mismatch", -1);
6154a49301eSmrg               return;
6164a49301eSmrg            }
6177117f1b4Smrg         }
6184a49301eSmrg         if (att->Renderbuffer &&
6194a49301eSmrg             att->Renderbuffer->NumSamples != numSamples) {
6204a49301eSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
6214a49301eSmrg            fbo_incomplete("inconsistant number of samples", i);
6227117f1b4Smrg            return;
6234a49301eSmrg         }
6244a49301eSmrg
6257117f1b4Smrg      }
6267117f1b4Smrg   }
6277117f1b4Smrg
628c1f859d4Smrg#ifndef FEATURE_OES_framebuffer_object
6297117f1b4Smrg   /* Check that all DrawBuffers are present */
6307117f1b4Smrg   for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
6317117f1b4Smrg      if (fb->ColorDrawBuffer[j] != GL_NONE) {
6327117f1b4Smrg         const struct gl_renderbuffer_attachment *att
6337117f1b4Smrg            = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
6347117f1b4Smrg         assert(att);
6357117f1b4Smrg         if (att->Type == GL_NONE) {
6367117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
6377117f1b4Smrg            fbo_incomplete("missing drawbuffer", j);
6387117f1b4Smrg            return;
6397117f1b4Smrg         }
6407117f1b4Smrg      }
6417117f1b4Smrg   }
6427117f1b4Smrg
6437117f1b4Smrg   /* Check that the ReadBuffer is present */
6447117f1b4Smrg   if (fb->ColorReadBuffer != GL_NONE) {
6457117f1b4Smrg      const struct gl_renderbuffer_attachment *att
6467117f1b4Smrg         = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
6477117f1b4Smrg      assert(att);
6487117f1b4Smrg      if (att->Type == GL_NONE) {
6497117f1b4Smrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
6507117f1b4Smrg            fbo_incomplete("missing readbuffer", -1);
6517117f1b4Smrg         return;
6527117f1b4Smrg      }
6537117f1b4Smrg   }
6544a49301eSmrg#else
6554a49301eSmrg   (void) j;
656c1f859d4Smrg#endif
6577117f1b4Smrg
6587117f1b4Smrg   if (numImages == 0) {
6597117f1b4Smrg      fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
6607117f1b4Smrg      fbo_incomplete("no attachments", -1);
6617117f1b4Smrg      return;
6627117f1b4Smrg   }
6637117f1b4Smrg
6644a49301eSmrg   /* Provisionally set status = COMPLETE ... */
6657117f1b4Smrg   fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
6664a49301eSmrg
6674a49301eSmrg   /* ... but the driver may say the FB is incomplete.
6684a49301eSmrg    * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
6694a49301eSmrg    * if anything.
6704a49301eSmrg    */
6714a49301eSmrg   if (ctx->Driver.ValidateFramebuffer) {
6724a49301eSmrg      ctx->Driver.ValidateFramebuffer(ctx, fb);
6734a49301eSmrg      if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
6744a49301eSmrg         fbo_incomplete("driver marked FBO as incomplete", -1);
6754a49301eSmrg      }
6764a49301eSmrg   }
6774a49301eSmrg
6784a49301eSmrg   if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6794a49301eSmrg      /*
6804a49301eSmrg       * Note that if ARB_framebuffer_object is supported and the attached
6814a49301eSmrg       * renderbuffers/textures are different sizes, the framebuffer
6824a49301eSmrg       * width/height will be set to the smallest width/height.
6834a49301eSmrg       */
6844a49301eSmrg      fb->Width = minWidth;
6854a49301eSmrg      fb->Height = minHeight;
6864a49301eSmrg
6874a49301eSmrg      /* finally, update the visual info for the framebuffer */
6884a49301eSmrg      _mesa_update_framebuffer_visual(fb);
6894a49301eSmrg   }
6907117f1b4Smrg}
6917117f1b4Smrg
6927117f1b4Smrg
6937117f1b4SmrgGLboolean GLAPIENTRY
6947117f1b4Smrg_mesa_IsRenderbufferEXT(GLuint renderbuffer)
6957117f1b4Smrg{
6967117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
6977117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
6987117f1b4Smrg   if (renderbuffer) {
6997117f1b4Smrg      struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
7007117f1b4Smrg      if (rb != NULL && rb != &DummyRenderbuffer)
7017117f1b4Smrg         return GL_TRUE;
7027117f1b4Smrg   }
7037117f1b4Smrg   return GL_FALSE;
7047117f1b4Smrg}
7057117f1b4Smrg
7067117f1b4Smrg
7077117f1b4Smrgvoid GLAPIENTRY
7087117f1b4Smrg_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
7097117f1b4Smrg{
7107117f1b4Smrg   struct gl_renderbuffer *newRb;
7117117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
7127117f1b4Smrg
7137117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
7147117f1b4Smrg
7157117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
7164a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
7177117f1b4Smrg      return;
7187117f1b4Smrg   }
7197117f1b4Smrg
7204a49301eSmrg   /* No need to flush here since the render buffer binding has no
7214a49301eSmrg    * effect on rendering state.
7227117f1b4Smrg    */
7237117f1b4Smrg
7247117f1b4Smrg   if (renderbuffer) {
7257117f1b4Smrg      newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
7267117f1b4Smrg      if (newRb == &DummyRenderbuffer) {
7277117f1b4Smrg         /* ID was reserved, but no real renderbuffer object made yet */
7287117f1b4Smrg         newRb = NULL;
7297117f1b4Smrg      }
7304a49301eSmrg      else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
7314a49301eSmrg         /* All RB IDs must be Gen'd */
7324a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
7334a49301eSmrg         return;
7344a49301eSmrg      }
7354a49301eSmrg
7367117f1b4Smrg      if (!newRb) {
7377117f1b4Smrg	 /* create new renderbuffer object */
7387117f1b4Smrg	 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
7397117f1b4Smrg	 if (!newRb) {
7407117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
7417117f1b4Smrg	    return;
7427117f1b4Smrg	 }
7437117f1b4Smrg         ASSERT(newRb->AllocStorage);
7447117f1b4Smrg         _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
7457117f1b4Smrg         newRb->RefCount = 1; /* referenced by hash table */
7467117f1b4Smrg      }
7477117f1b4Smrg   }
7487117f1b4Smrg   else {
7497117f1b4Smrg      newRb = NULL;
7507117f1b4Smrg   }
7517117f1b4Smrg
7527117f1b4Smrg   ASSERT(newRb != &DummyRenderbuffer);
7537117f1b4Smrg
7547117f1b4Smrg   _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
7557117f1b4Smrg}
7567117f1b4Smrg
7577117f1b4Smrg
7584a49301eSmrg/**
7594a49301eSmrg * If the given renderbuffer is anywhere attached to the framebuffer, detach
7604a49301eSmrg * the renderbuffer.
7614a49301eSmrg * This is used when a renderbuffer object is deleted.
7624a49301eSmrg * The spec calls for unbinding.
7634a49301eSmrg */
7644a49301eSmrgstatic void
7654a49301eSmrgdetach_renderbuffer(GLcontext *ctx,
7664a49301eSmrg                    struct gl_framebuffer *fb,
7674a49301eSmrg                    struct gl_renderbuffer *rb)
7684a49301eSmrg{
7694a49301eSmrg   GLuint i;
7704a49301eSmrg   for (i = 0; i < BUFFER_COUNT; i++) {
7714a49301eSmrg      if (fb->Attachment[i].Renderbuffer == rb) {
7724a49301eSmrg         _mesa_remove_attachment(ctx, &fb->Attachment[i]);
7734a49301eSmrg      }
7744a49301eSmrg   }
7754a49301eSmrg   invalidate_framebuffer(fb);
7764a49301eSmrg}
7774a49301eSmrg
7784a49301eSmrg
7797117f1b4Smrgvoid GLAPIENTRY
7807117f1b4Smrg_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
7817117f1b4Smrg{
7827117f1b4Smrg   GLint i;
7837117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
7847117f1b4Smrg
7857117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
7867117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
7877117f1b4Smrg
7887117f1b4Smrg   for (i = 0; i < n; i++) {
7897117f1b4Smrg      if (renderbuffers[i] > 0) {
7907117f1b4Smrg	 struct gl_renderbuffer *rb;
7917117f1b4Smrg	 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
7927117f1b4Smrg	 if (rb) {
7937117f1b4Smrg            /* check if deleting currently bound renderbuffer object */
7947117f1b4Smrg            if (rb == ctx->CurrentRenderbuffer) {
7957117f1b4Smrg               /* bind default */
7967117f1b4Smrg               ASSERT(rb->RefCount >= 2);
7977117f1b4Smrg               _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
7987117f1b4Smrg            }
7997117f1b4Smrg
8004a49301eSmrg            if (ctx->DrawBuffer->Name) {
8014a49301eSmrg               detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
8024a49301eSmrg            }
8034a49301eSmrg            if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) {
8044a49301eSmrg               detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
8054a49301eSmrg            }
8064a49301eSmrg
8077117f1b4Smrg	    /* Remove from hash table immediately, to free the ID.
8087117f1b4Smrg             * But the object will not be freed until it's no longer
8097117f1b4Smrg             * referenced anywhere else.
8107117f1b4Smrg             */
8117117f1b4Smrg	    _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
8127117f1b4Smrg
8137117f1b4Smrg            if (rb != &DummyRenderbuffer) {
8147117f1b4Smrg               /* no longer referenced by hash table */
8157117f1b4Smrg               _mesa_reference_renderbuffer(&rb, NULL);
8167117f1b4Smrg	    }
8177117f1b4Smrg	 }
8187117f1b4Smrg      }
8197117f1b4Smrg   }
8207117f1b4Smrg}
8217117f1b4Smrg
8227117f1b4Smrg
8237117f1b4Smrgvoid GLAPIENTRY
8247117f1b4Smrg_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
8257117f1b4Smrg{
8267117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
8277117f1b4Smrg   GLuint first;
8287117f1b4Smrg   GLint i;
8297117f1b4Smrg
8307117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
8317117f1b4Smrg
8327117f1b4Smrg   if (n < 0) {
8337117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
8347117f1b4Smrg      return;
8357117f1b4Smrg   }
8367117f1b4Smrg
8377117f1b4Smrg   if (!renderbuffers)
8387117f1b4Smrg      return;
8397117f1b4Smrg
8407117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
8417117f1b4Smrg
8427117f1b4Smrg   for (i = 0; i < n; i++) {
8437117f1b4Smrg      GLuint name = first + i;
8447117f1b4Smrg      renderbuffers[i] = name;
8457117f1b4Smrg      /* insert dummy placeholder into hash table */
8467117f1b4Smrg      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
8477117f1b4Smrg      _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
8487117f1b4Smrg      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
8497117f1b4Smrg   }
8507117f1b4Smrg}
8517117f1b4Smrg
8527117f1b4Smrg
8537117f1b4Smrg/**
8547117f1b4Smrg * Given an internal format token for a render buffer, return the
8557117f1b4Smrg * corresponding base format.
8567117f1b4Smrg * This is very similar to _mesa_base_tex_format() but the set of valid
8577117f1b4Smrg * internal formats is somewhat different.
8587117f1b4Smrg *
8597117f1b4Smrg * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
8607117f1b4Smrg *  GL_DEPTH_STENCIL_EXT or zero if error.
8617117f1b4Smrg */
8627117f1b4SmrgGLenum
8637117f1b4Smrg_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
8647117f1b4Smrg{
8657117f1b4Smrg   switch (internalFormat) {
8667117f1b4Smrg   case GL_RGB:
8677117f1b4Smrg   case GL_R3_G3_B2:
8687117f1b4Smrg   case GL_RGB4:
8697117f1b4Smrg   case GL_RGB5:
8707117f1b4Smrg   case GL_RGB8:
8717117f1b4Smrg   case GL_RGB10:
8727117f1b4Smrg   case GL_RGB12:
8737117f1b4Smrg   case GL_RGB16:
8747117f1b4Smrg      return GL_RGB;
8757117f1b4Smrg   case GL_RGBA:
8767117f1b4Smrg   case GL_RGBA2:
8777117f1b4Smrg   case GL_RGBA4:
8787117f1b4Smrg   case GL_RGB5_A1:
8797117f1b4Smrg   case GL_RGBA8:
8807117f1b4Smrg   case GL_RGB10_A2:
8817117f1b4Smrg   case GL_RGBA12:
8827117f1b4Smrg   case GL_RGBA16:
8837117f1b4Smrg      return GL_RGBA;
8847117f1b4Smrg   case GL_STENCIL_INDEX:
8857117f1b4Smrg   case GL_STENCIL_INDEX1_EXT:
8867117f1b4Smrg   case GL_STENCIL_INDEX4_EXT:
8877117f1b4Smrg   case GL_STENCIL_INDEX8_EXT:
8887117f1b4Smrg   case GL_STENCIL_INDEX16_EXT:
8897117f1b4Smrg      return GL_STENCIL_INDEX;
8907117f1b4Smrg   case GL_DEPTH_COMPONENT:
8917117f1b4Smrg   case GL_DEPTH_COMPONENT16:
8927117f1b4Smrg   case GL_DEPTH_COMPONENT24:
8937117f1b4Smrg   case GL_DEPTH_COMPONENT32:
8947117f1b4Smrg      return GL_DEPTH_COMPONENT;
8957117f1b4Smrg   case GL_DEPTH_STENCIL_EXT:
8967117f1b4Smrg   case GL_DEPTH24_STENCIL8_EXT:
8977117f1b4Smrg      if (ctx->Extensions.EXT_packed_depth_stencil)
8987117f1b4Smrg         return GL_DEPTH_STENCIL_EXT;
8997117f1b4Smrg      else
9007117f1b4Smrg         return 0;
9017117f1b4Smrg   /* XXX add floating point formats eventually */
9027117f1b4Smrg   default:
9037117f1b4Smrg      return 0;
9047117f1b4Smrg   }
9057117f1b4Smrg}
9067117f1b4Smrg
9077117f1b4Smrg
9084a49301eSmrg/** sentinal value, see below */
9094a49301eSmrg#define NO_SAMPLES 1000
9104a49301eSmrg
9114a49301eSmrg
9124a49301eSmrg/**
9134a49301eSmrg * Helper function used by _mesa_RenderbufferStorageEXT() and
9144a49301eSmrg * _mesa_RenderbufferStorageMultisample().
9154a49301eSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
9164a49301eSmrg */
9174a49301eSmrgstatic void
9184a49301eSmrgrenderbuffer_storage(GLenum target, GLenum internalFormat,
9194a49301eSmrg                     GLsizei width, GLsizei height, GLsizei samples)
9207117f1b4Smrg{
9214a49301eSmrg   const char *func = samples == NO_SAMPLES ?
9224a49301eSmrg      "glRenderbufferStorage" : "RenderbufferStorageMultisample";
9237117f1b4Smrg   struct gl_renderbuffer *rb;
9247117f1b4Smrg   GLenum baseFormat;
9257117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9267117f1b4Smrg
9277117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
9287117f1b4Smrg
9297117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
9304a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
9317117f1b4Smrg      return;
9327117f1b4Smrg   }
9337117f1b4Smrg
9347117f1b4Smrg   baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
9357117f1b4Smrg   if (baseFormat == 0) {
9364a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
9377117f1b4Smrg      return;
9387117f1b4Smrg   }
9397117f1b4Smrg
9407117f1b4Smrg   if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
9414a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
9427117f1b4Smrg      return;
9437117f1b4Smrg   }
9447117f1b4Smrg
9457117f1b4Smrg   if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
9464a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
9477117f1b4Smrg      return;
9487117f1b4Smrg   }
9497117f1b4Smrg
9504a49301eSmrg   if (samples == NO_SAMPLES) {
9514a49301eSmrg      /* NumSamples == 0 indicates non-multisampling */
9524a49301eSmrg      samples = 0;
9534a49301eSmrg   }
9544a49301eSmrg   else if (samples > ctx->Const.MaxSamples) {
9554a49301eSmrg      /* note: driver may choose to use more samples than what's requested */
9564a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
9574a49301eSmrg      return;
9584a49301eSmrg   }
9597117f1b4Smrg
9604a49301eSmrg   rb = ctx->CurrentRenderbuffer;
9617117f1b4Smrg   if (!rb) {
9624a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, func);
9637117f1b4Smrg      return;
9647117f1b4Smrg   }
9657117f1b4Smrg
9667117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
9677117f1b4Smrg
9687117f1b4Smrg   if (rb->InternalFormat == internalFormat &&
9697117f1b4Smrg       rb->Width == (GLuint) width &&
9707117f1b4Smrg       rb->Height == (GLuint) height) {
9717117f1b4Smrg      /* no change in allocation needed */
9727117f1b4Smrg      return;
9737117f1b4Smrg   }
9747117f1b4Smrg
9757117f1b4Smrg   /* These MUST get set by the AllocStorage func */
9764a49301eSmrg   rb->Format = MESA_FORMAT_NONE;
9774a49301eSmrg   rb->NumSamples = samples;
9787117f1b4Smrg
9797117f1b4Smrg   /* Now allocate the storage */
9807117f1b4Smrg   ASSERT(rb->AllocStorage);
9817117f1b4Smrg   if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
9827117f1b4Smrg      /* No error - check/set fields now */
9834a49301eSmrg      assert(rb->Format != MESA_FORMAT_NONE);
9847117f1b4Smrg      assert(rb->Width == (GLuint) width);
9857117f1b4Smrg      assert(rb->Height == (GLuint) height);
9867117f1b4Smrg      rb->InternalFormat = internalFormat;
9874a49301eSmrg      rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
9884a49301eSmrg      assert(rb->_BaseFormat != 0);
9897117f1b4Smrg   }
9907117f1b4Smrg   else {
9917117f1b4Smrg      /* Probably ran out of memory - clear the fields */
9927117f1b4Smrg      rb->Width = 0;
9937117f1b4Smrg      rb->Height = 0;
9944a49301eSmrg      rb->Format = MESA_FORMAT_NONE;
9957117f1b4Smrg      rb->InternalFormat = GL_NONE;
9967117f1b4Smrg      rb->_BaseFormat = GL_NONE;
9974a49301eSmrg      rb->NumSamples = 0;
9987117f1b4Smrg   }
9997117f1b4Smrg
10007117f1b4Smrg   /*
10017117f1b4Smrg   test_framebuffer_completeness(ctx, fb);
10027117f1b4Smrg   */
10037117f1b4Smrg   /* XXX if this renderbuffer is attached anywhere, invalidate attachment
10047117f1b4Smrg    * points???
10057117f1b4Smrg    */
10067117f1b4Smrg}
10077117f1b4Smrg
10087117f1b4Smrg
10094a49301eSmrg/**
10104a49301eSmrg * Helper function for _mesa_GetRenderbufferParameterivEXT() and
10114a49301eSmrg * _mesa_GetFramebufferAttachmentParameterivEXT()
10124a49301eSmrg * We have to be careful to respect the base format.  For example, if a
10134a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the
10144a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
10154a49301eSmrg * we need to return zero.
10164a49301eSmrg */
10174a49301eSmrgstatic GLint
10184a49301eSmrgget_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
10194a49301eSmrg{
10204a49301eSmrg   switch (pname) {
10214a49301eSmrg   case GL_RENDERBUFFER_RED_SIZE_EXT:
10224a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
10234a49301eSmrg   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
10244a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
10254a49301eSmrg   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
10264a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
10274a49301eSmrg      if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
10284a49301eSmrg         return _mesa_get_format_bits(format, pname);
10294a49301eSmrg      else
10304a49301eSmrg         return 0;
10314a49301eSmrg   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
10324a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
10334a49301eSmrg      if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA)
10344a49301eSmrg         return _mesa_get_format_bits(format, pname);
10354a49301eSmrg      else
10364a49301eSmrg         return 0;
10374a49301eSmrg   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
10384a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
10394a49301eSmrg      if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
10404a49301eSmrg         return _mesa_get_format_bits(format, pname);
10414a49301eSmrg      else
10424a49301eSmrg         return 0;
10434a49301eSmrg   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
10444a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
10454a49301eSmrg      if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
10464a49301eSmrg         return _mesa_get_format_bits(format, pname);
10474a49301eSmrg      else
10484a49301eSmrg         return 0;
10494a49301eSmrg   default:
10504a49301eSmrg      return 0;
10514a49301eSmrg   }
10524a49301eSmrg}
10534a49301eSmrg
10544a49301eSmrg
10554a49301eSmrg
10564a49301eSmrgvoid GLAPIENTRY
10574a49301eSmrg_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
10584a49301eSmrg                             GLsizei width, GLsizei height)
10594a49301eSmrg{
10604a49301eSmrg   /* GL_ARB_fbo says calling this function is equivalent to calling
10614a49301eSmrg    * glRenderbufferStorageMultisample() with samples=0.  We pass in
10624a49301eSmrg    * a token value here just for error reporting purposes.
10634a49301eSmrg    */
10644a49301eSmrg   renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
10654a49301eSmrg}
10664a49301eSmrg
10674a49301eSmrg
10684a49301eSmrgvoid GLAPIENTRY
10694a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
10704a49301eSmrg                                     GLenum internalFormat,
10714a49301eSmrg                                     GLsizei width, GLsizei height)
10724a49301eSmrg{
10734a49301eSmrg   renderbuffer_storage(target, internalFormat, width, height, samples);
10744a49301eSmrg}
10754a49301eSmrg
10764a49301eSmrg
10774a49301eSmrg
10787117f1b4Smrgvoid GLAPIENTRY
10797117f1b4Smrg_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
10807117f1b4Smrg{
10814a49301eSmrg   struct gl_renderbuffer *rb;
10827117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
10837117f1b4Smrg
10847117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
10857117f1b4Smrg
10867117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
10877117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
10887117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
10897117f1b4Smrg      return;
10907117f1b4Smrg   }
10917117f1b4Smrg
10924a49301eSmrg   rb = ctx->CurrentRenderbuffer;
10934a49301eSmrg   if (!rb) {
10947117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
10957117f1b4Smrg                  "glGetRenderbufferParameterivEXT");
10967117f1b4Smrg      return;
10977117f1b4Smrg   }
10987117f1b4Smrg
10994a49301eSmrg   /* No need to flush here since we're just quering state which is
11004a49301eSmrg    * not effected by rendering.
11014a49301eSmrg    */
11027117f1b4Smrg
11037117f1b4Smrg   switch (pname) {
11047117f1b4Smrg   case GL_RENDERBUFFER_WIDTH_EXT:
11054a49301eSmrg      *params = rb->Width;
11067117f1b4Smrg      return;
11077117f1b4Smrg   case GL_RENDERBUFFER_HEIGHT_EXT:
11084a49301eSmrg      *params = rb->Height;
11097117f1b4Smrg      return;
11107117f1b4Smrg   case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
11114a49301eSmrg      *params = rb->InternalFormat;
11127117f1b4Smrg      return;
11137117f1b4Smrg   case GL_RENDERBUFFER_RED_SIZE_EXT:
11147117f1b4Smrg   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
11157117f1b4Smrg   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
11167117f1b4Smrg   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
11177117f1b4Smrg   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
11187117f1b4Smrg   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
11194a49301eSmrg      *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
11207117f1b4Smrg      break;
11214a49301eSmrg   case GL_RENDERBUFFER_SAMPLES:
11224a49301eSmrg      if (ctx->Extensions.ARB_framebuffer_object) {
11234a49301eSmrg         *params = rb->NumSamples;
11244a49301eSmrg         break;
11254a49301eSmrg      }
11264a49301eSmrg      /* fallthrough */
11277117f1b4Smrg   default:
11287117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
11297117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
11307117f1b4Smrg      return;
11317117f1b4Smrg   }
11327117f1b4Smrg}
11337117f1b4Smrg
11347117f1b4Smrg
11357117f1b4SmrgGLboolean GLAPIENTRY
11367117f1b4Smrg_mesa_IsFramebufferEXT(GLuint framebuffer)
11377117f1b4Smrg{
11387117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
11397117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
11407117f1b4Smrg   if (framebuffer) {
11417117f1b4Smrg      struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
11427117f1b4Smrg      if (rb != NULL && rb != &DummyFramebuffer)
11437117f1b4Smrg         return GL_TRUE;
11447117f1b4Smrg   }
11457117f1b4Smrg   return GL_FALSE;
11467117f1b4Smrg}
11477117f1b4Smrg
11487117f1b4Smrg
11494a49301eSmrg/**
11504a49301eSmrg * Check if any of the attachments of the given framebuffer are textures
11514a49301eSmrg * (render to texture).  Call ctx->Driver.RenderTexture() for such
11524a49301eSmrg * attachments.
11534a49301eSmrg */
11547117f1b4Smrgstatic void
11557117f1b4Smrgcheck_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
11567117f1b4Smrg{
11577117f1b4Smrg   GLuint i;
11587117f1b4Smrg   ASSERT(ctx->Driver.RenderTexture);
11594a49301eSmrg
11604a49301eSmrg   if (fb->Name == 0)
11614a49301eSmrg      return; /* can't render to texture with winsys framebuffers */
11624a49301eSmrg
11637117f1b4Smrg   for (i = 0; i < BUFFER_COUNT; i++) {
11647117f1b4Smrg      struct gl_renderbuffer_attachment *att = fb->Attachment + i;
11657117f1b4Smrg      struct gl_texture_object *texObj = att->Texture;
11667117f1b4Smrg      if (texObj
11674a49301eSmrg          && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
11687117f1b4Smrg         ctx->Driver.RenderTexture(ctx, fb, att);
11697117f1b4Smrg      }
11707117f1b4Smrg   }
11717117f1b4Smrg}
11727117f1b4Smrg
11737117f1b4Smrg
11747117f1b4Smrg/**
11757117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures.
11767117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to
11777117f1b4Smrg * notify the device driver that the texture image may have changed.
11787117f1b4Smrg */
11797117f1b4Smrgstatic void
11807117f1b4Smrgcheck_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
11817117f1b4Smrg{
11824a49301eSmrg   if (fb->Name == 0)
11834a49301eSmrg      return; /* can't render to texture with winsys framebuffers */
11844a49301eSmrg
11857117f1b4Smrg   if (ctx->Driver.FinishRenderTexture) {
11867117f1b4Smrg      GLuint i;
11877117f1b4Smrg      for (i = 0; i < BUFFER_COUNT; i++) {
11887117f1b4Smrg         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1189c1f859d4Smrg         if (att->Texture && att->Renderbuffer) {
11907117f1b4Smrg            ctx->Driver.FinishRenderTexture(ctx, att);
11917117f1b4Smrg         }
11927117f1b4Smrg      }
11937117f1b4Smrg   }
11947117f1b4Smrg}
11957117f1b4Smrg
11967117f1b4Smrg
11977117f1b4Smrgvoid GLAPIENTRY
11987117f1b4Smrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
11997117f1b4Smrg{
12004a49301eSmrg   struct gl_framebuffer *newDrawFb, *newReadFb;
12014a49301eSmrg   struct gl_framebuffer *oldDrawFb, *oldReadFb;
12027117f1b4Smrg   GLboolean bindReadBuf, bindDrawBuf;
12037117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
12047117f1b4Smrg
12054a49301eSmrg#ifdef DEBUG
12064a49301eSmrg   if (ctx->Extensions.ARB_framebuffer_object) {
12074a49301eSmrg      ASSERT(ctx->Extensions.EXT_framebuffer_object);
12084a49301eSmrg      ASSERT(ctx->Extensions.EXT_framebuffer_blit);
12094a49301eSmrg   }
12104a49301eSmrg#endif
12114a49301eSmrg
12127117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
12137117f1b4Smrg
12147117f1b4Smrg   if (!ctx->Extensions.EXT_framebuffer_object) {
12157117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
12167117f1b4Smrg                  "glBindFramebufferEXT(unsupported)");
12177117f1b4Smrg      return;
12187117f1b4Smrg   }
12197117f1b4Smrg
12207117f1b4Smrg   switch (target) {
12217117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
12227117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
12237117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
12247117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
12257117f1b4Smrg         return;
12267117f1b4Smrg      }
12277117f1b4Smrg      bindDrawBuf = GL_TRUE;
12287117f1b4Smrg      bindReadBuf = GL_FALSE;
12297117f1b4Smrg      break;
12307117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
12317117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
12327117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
12337117f1b4Smrg         return;
12347117f1b4Smrg      }
12357117f1b4Smrg      bindDrawBuf = GL_FALSE;
12367117f1b4Smrg      bindReadBuf = GL_TRUE;
12377117f1b4Smrg      break;
12387117f1b4Smrg#endif
12397117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
12407117f1b4Smrg      bindDrawBuf = GL_TRUE;
12417117f1b4Smrg      bindReadBuf = GL_TRUE;
12427117f1b4Smrg      break;
12437117f1b4Smrg   default:
12447117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
12457117f1b4Smrg      return;
12467117f1b4Smrg   }
12477117f1b4Smrg
12487117f1b4Smrg   if (framebuffer) {
12497117f1b4Smrg      /* Binding a user-created framebuffer object */
12504a49301eSmrg      newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
12514a49301eSmrg      if (newDrawFb == &DummyFramebuffer) {
12527117f1b4Smrg         /* ID was reserved, but no real framebuffer object made yet */
12534a49301eSmrg         newDrawFb = NULL;
12547117f1b4Smrg      }
12554a49301eSmrg      else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
12564a49301eSmrg         /* All FBO IDs must be Gen'd */
12574a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
12584a49301eSmrg         return;
12594a49301eSmrg      }
12604a49301eSmrg
12614a49301eSmrg      if (!newDrawFb) {
12627117f1b4Smrg	 /* create new framebuffer object */
12634a49301eSmrg	 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
12644a49301eSmrg	 if (!newDrawFb) {
12657117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
12667117f1b4Smrg	    return;
12677117f1b4Smrg	 }
12684a49301eSmrg         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
12697117f1b4Smrg      }
12704a49301eSmrg      newReadFb = newDrawFb;
12717117f1b4Smrg   }
12727117f1b4Smrg   else {
12737117f1b4Smrg      /* Binding the window system framebuffer (which was originally set
12747117f1b4Smrg       * with MakeCurrent).
12757117f1b4Smrg       */
12764a49301eSmrg      newDrawFb = ctx->WinSysDrawBuffer;
12774a49301eSmrg      newReadFb = ctx->WinSysReadBuffer;
12787117f1b4Smrg   }
12797117f1b4Smrg
12804a49301eSmrg   ASSERT(newDrawFb);
12814a49301eSmrg   ASSERT(newDrawFb != &DummyFramebuffer);
12824a49301eSmrg
12834a49301eSmrg   /* save pointers to current/old framebuffers */
12844a49301eSmrg   oldDrawFb = ctx->DrawBuffer;
12854a49301eSmrg   oldReadFb = ctx->ReadBuffer;
12864a49301eSmrg
12874a49301eSmrg   /* check if really changing bindings */
12884a49301eSmrg   if (oldDrawFb == newDrawFb)
12894a49301eSmrg      bindDrawBuf = GL_FALSE;
12904a49301eSmrg   if (oldReadFb == newReadFb)
12914a49301eSmrg      bindReadBuf = GL_FALSE;
12927117f1b4Smrg
12937117f1b4Smrg   /*
12944a49301eSmrg    * OK, now bind the new Draw/Read framebuffers, if they're changing.
12954a49301eSmrg    *
12964a49301eSmrg    * We also check if we're beginning and/or ending render-to-texture.
12974a49301eSmrg    * When a framebuffer with texture attachments is unbound, call
12984a49301eSmrg    * ctx->Driver.FinishRenderTexture().
12994a49301eSmrg    * When a framebuffer with texture attachments is bound, call
13004a49301eSmrg    * ctx->Driver.RenderTexture().
13014a49301eSmrg    *
13024a49301eSmrg    * Note that if the ReadBuffer has texture attachments we don't consider
13034a49301eSmrg    * that a render-to-texture case.
13047117f1b4Smrg    */
13057117f1b4Smrg   if (bindReadBuf) {
13064a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
13074a49301eSmrg
13084a49301eSmrg      /* check if old readbuffer was render-to-texture */
13094a49301eSmrg      check_end_texture_render(ctx, oldReadFb);
13104a49301eSmrg
13114a49301eSmrg      _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
13127117f1b4Smrg   }
13137117f1b4Smrg
13147117f1b4Smrg   if (bindDrawBuf) {
13154a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
13167117f1b4Smrg
13174a49301eSmrg      /* check if old read/draw buffers were render-to-texture */
13184a49301eSmrg      if (!bindReadBuf)
13194a49301eSmrg         check_end_texture_render(ctx, oldReadFb);
13207117f1b4Smrg
13214a49301eSmrg      if (oldDrawFb != oldReadFb)
13224a49301eSmrg         check_end_texture_render(ctx, oldDrawFb);
13234a49301eSmrg
13244a49301eSmrg      /* check if newly bound framebuffer has any texture attachments */
13254a49301eSmrg      check_begin_texture_render(ctx, newDrawFb);
13264a49301eSmrg
13274a49301eSmrg      _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
13287117f1b4Smrg   }
13297117f1b4Smrg
13304a49301eSmrg   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
13314a49301eSmrg      ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
13327117f1b4Smrg   }
13337117f1b4Smrg}
13347117f1b4Smrg
13357117f1b4Smrg
13367117f1b4Smrgvoid GLAPIENTRY
13377117f1b4Smrg_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
13387117f1b4Smrg{
13397117f1b4Smrg   GLint i;
13407117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
13417117f1b4Smrg
13427117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
13437117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
13447117f1b4Smrg
13457117f1b4Smrg   for (i = 0; i < n; i++) {
13467117f1b4Smrg      if (framebuffers[i] > 0) {
13477117f1b4Smrg	 struct gl_framebuffer *fb;
13487117f1b4Smrg	 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
13497117f1b4Smrg	 if (fb) {
13507117f1b4Smrg            ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
13517117f1b4Smrg
13527117f1b4Smrg            /* check if deleting currently bound framebuffer object */
13534a49301eSmrg            if (ctx->Extensions.EXT_framebuffer_blit) {
13544a49301eSmrg               /* separate draw/read binding points */
13554a49301eSmrg               if (fb == ctx->DrawBuffer) {
13564a49301eSmrg                  /* bind default */
13574a49301eSmrg                  ASSERT(fb->RefCount >= 2);
13584a49301eSmrg                  _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
13594a49301eSmrg               }
13604a49301eSmrg               if (fb == ctx->ReadBuffer) {
13614a49301eSmrg                  /* bind default */
13624a49301eSmrg                  ASSERT(fb->RefCount >= 2);
13634a49301eSmrg                  _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
13644a49301eSmrg               }
13654a49301eSmrg            }
13664a49301eSmrg            else {
13674a49301eSmrg               /* only one binding point for read/draw buffers */
13684a49301eSmrg               if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
13694a49301eSmrg                  /* bind default */
13704a49301eSmrg                  ASSERT(fb->RefCount >= 2);
13714a49301eSmrg                  _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
13724a49301eSmrg               }
13737117f1b4Smrg            }
13747117f1b4Smrg
13757117f1b4Smrg	    /* remove from hash table immediately, to free the ID */
13767117f1b4Smrg	    _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
13777117f1b4Smrg
13787117f1b4Smrg            if (fb != &DummyFramebuffer) {
13797117f1b4Smrg               /* But the object will not be freed until it's no longer
13807117f1b4Smrg                * bound in any context.
13817117f1b4Smrg                */
13824a49301eSmrg               _mesa_reference_framebuffer(&fb, NULL);
13837117f1b4Smrg	    }
13847117f1b4Smrg	 }
13857117f1b4Smrg      }
13867117f1b4Smrg   }
13877117f1b4Smrg}
13887117f1b4Smrg
13897117f1b4Smrg
13907117f1b4Smrgvoid GLAPIENTRY
13917117f1b4Smrg_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
13927117f1b4Smrg{
13937117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
13947117f1b4Smrg   GLuint first;
13957117f1b4Smrg   GLint i;
13967117f1b4Smrg
13977117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
13987117f1b4Smrg
13997117f1b4Smrg   if (n < 0) {
14007117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
14017117f1b4Smrg      return;
14027117f1b4Smrg   }
14037117f1b4Smrg
14047117f1b4Smrg   if (!framebuffers)
14057117f1b4Smrg      return;
14067117f1b4Smrg
14077117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
14087117f1b4Smrg
14097117f1b4Smrg   for (i = 0; i < n; i++) {
14107117f1b4Smrg      GLuint name = first + i;
14117117f1b4Smrg      framebuffers[i] = name;
14127117f1b4Smrg      /* insert dummy placeholder into hash table */
14137117f1b4Smrg      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
14147117f1b4Smrg      _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
14157117f1b4Smrg      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
14167117f1b4Smrg   }
14177117f1b4Smrg}
14187117f1b4Smrg
14197117f1b4Smrg
14207117f1b4Smrg
14217117f1b4SmrgGLenum GLAPIENTRY
14227117f1b4Smrg_mesa_CheckFramebufferStatusEXT(GLenum target)
14237117f1b4Smrg{
14247117f1b4Smrg   struct gl_framebuffer *buffer;
14257117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
14267117f1b4Smrg
14277117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
14287117f1b4Smrg
14297117f1b4Smrg   switch (target) {
14307117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
14317117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
14327117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
14337117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
14347117f1b4Smrg         return 0;
14357117f1b4Smrg      }
14367117f1b4Smrg      buffer = ctx->DrawBuffer;
14377117f1b4Smrg      break;
14387117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
14397117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
14407117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
14417117f1b4Smrg         return 0;
14427117f1b4Smrg      }
14437117f1b4Smrg      buffer = ctx->ReadBuffer;
14447117f1b4Smrg      break;
14457117f1b4Smrg#endif
14467117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
14477117f1b4Smrg      buffer = ctx->DrawBuffer;
14487117f1b4Smrg      break;
14497117f1b4Smrg   default:
14507117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
14517117f1b4Smrg      return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
14527117f1b4Smrg   }
14537117f1b4Smrg
14547117f1b4Smrg   if (buffer->Name == 0) {
14557117f1b4Smrg      /* The window system / default framebuffer is always complete */
14567117f1b4Smrg      return GL_FRAMEBUFFER_COMPLETE_EXT;
14577117f1b4Smrg   }
14587117f1b4Smrg
14594a49301eSmrg   /* No need to flush here */
14604a49301eSmrg
14614a49301eSmrg   if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
14624a49301eSmrg      _mesa_test_framebuffer_completeness(ctx, buffer);
14634a49301eSmrg   }
14647117f1b4Smrg
14657117f1b4Smrg   return buffer->_Status;
14667117f1b4Smrg}
14677117f1b4Smrg
14687117f1b4Smrg
14697117f1b4Smrg
14707117f1b4Smrg/**
14717117f1b4Smrg * Common code called by glFramebufferTexture1D/2D/3DEXT().
14727117f1b4Smrg */
14737117f1b4Smrgstatic void
14747117f1b4Smrgframebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
14757117f1b4Smrg                    GLenum attachment, GLenum textarget, GLuint texture,
14767117f1b4Smrg                    GLint level, GLint zoffset)
14777117f1b4Smrg{
14787117f1b4Smrg   struct gl_renderbuffer_attachment *att;
14797117f1b4Smrg   struct gl_texture_object *texObj = NULL;
14807117f1b4Smrg   struct gl_framebuffer *fb;
14814a49301eSmrg   GLboolean error = GL_FALSE;
14827117f1b4Smrg
14837117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
14847117f1b4Smrg
14854a49301eSmrg   switch (target) {
14864a49301eSmrg   case GL_READ_FRAMEBUFFER_EXT:
14874a49301eSmrg      error = !ctx->Extensions.EXT_framebuffer_blit;
14884a49301eSmrg      fb = ctx->ReadBuffer;
14894a49301eSmrg      break;
14904a49301eSmrg   case GL_DRAW_FRAMEBUFFER_EXT:
14914a49301eSmrg      error = !ctx->Extensions.EXT_framebuffer_blit;
14924a49301eSmrg      /* fall-through */
14934a49301eSmrg   case GL_FRAMEBUFFER_EXT:
14944a49301eSmrg      fb = ctx->DrawBuffer;
14954a49301eSmrg      break;
14964a49301eSmrg   default:
14974a49301eSmrg      error = GL_TRUE;
14984a49301eSmrg   }
14994a49301eSmrg
15004a49301eSmrg   if (error) {
15017117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
15024a49301eSmrg                  "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
15037117f1b4Smrg      return;
15047117f1b4Smrg   }
15057117f1b4Smrg
15067117f1b4Smrg   ASSERT(fb);
15077117f1b4Smrg
15087117f1b4Smrg   /* check framebuffer binding */
15097117f1b4Smrg   if (fb->Name == 0) {
15107117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
15117117f1b4Smrg                  "glFramebufferTexture%sEXT", caller);
15127117f1b4Smrg      return;
15137117f1b4Smrg   }
15147117f1b4Smrg
15157117f1b4Smrg
15167117f1b4Smrg   /* The textarget, level, and zoffset parameters are only validated if
15177117f1b4Smrg    * texture is non-zero.
15187117f1b4Smrg    */
15197117f1b4Smrg   if (texture) {
15207117f1b4Smrg      GLboolean err = GL_TRUE;
15217117f1b4Smrg
15227117f1b4Smrg      texObj = _mesa_lookup_texture(ctx, texture);
15237117f1b4Smrg      if (texObj != NULL) {
1524c1f859d4Smrg         if (textarget == 0) {
1525c1f859d4Smrg            err = (texObj->Target != GL_TEXTURE_3D) &&
1526c1f859d4Smrg                (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1527c1f859d4Smrg                (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1528c1f859d4Smrg         }
1529c1f859d4Smrg         else {
1530c1f859d4Smrg            err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1531c1f859d4Smrg                ? !IS_CUBE_FACE(textarget)
1532c1f859d4Smrg                : (texObj->Target != textarget);
1533c1f859d4Smrg         }
15347117f1b4Smrg      }
15357117f1b4Smrg
15367117f1b4Smrg      if (err) {
15377117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
15387117f1b4Smrg                     "glFramebufferTexture%sEXT(texture target mismatch)",
15397117f1b4Smrg                     caller);
15407117f1b4Smrg         return;
15417117f1b4Smrg      }
15427117f1b4Smrg
15437117f1b4Smrg      if (texObj->Target == GL_TEXTURE_3D) {
15447117f1b4Smrg         const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
15457117f1b4Smrg         if (zoffset < 0 || zoffset >= maxSize) {
15467117f1b4Smrg            _mesa_error(ctx, GL_INVALID_VALUE,
1547c1f859d4Smrg                        "glFramebufferTexture%sEXT(zoffset)", caller);
15487117f1b4Smrg            return;
15497117f1b4Smrg         }
15507117f1b4Smrg      }
1551c1f859d4Smrg      else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1552c1f859d4Smrg               (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1553c1f859d4Smrg         if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1554c1f859d4Smrg            _mesa_error(ctx, GL_INVALID_VALUE,
1555c1f859d4Smrg                        "glFramebufferTexture%sEXT(layer)", caller);
1556c1f859d4Smrg            return;
1557c1f859d4Smrg         }
1558c1f859d4Smrg      }
1559c1f859d4Smrg
15607117f1b4Smrg      if ((level < 0) ||
15617117f1b4Smrg          (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
15627117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
15637117f1b4Smrg                     "glFramebufferTexture%sEXT(level)", caller);
15647117f1b4Smrg         return;
15657117f1b4Smrg      }
15667117f1b4Smrg   }
15677117f1b4Smrg
15687117f1b4Smrg   att = _mesa_get_attachment(ctx, fb, attachment);
15697117f1b4Smrg   if (att == NULL) {
15707117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
15717117f1b4Smrg                  "glFramebufferTexture%sEXT(attachment)", caller);
15727117f1b4Smrg      return;
15737117f1b4Smrg   }
15747117f1b4Smrg
15757117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
15767117f1b4Smrg
15777117f1b4Smrg   _glthread_LOCK_MUTEX(fb->Mutex);
15787117f1b4Smrg   if (texObj) {
15797117f1b4Smrg      _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
15807117f1b4Smrg                                   level, zoffset);
15814a49301eSmrg      /* Set the render-to-texture flag.  We'll check this flag in
15824a49301eSmrg       * glTexImage() and friends to determine if we need to revalidate
15834a49301eSmrg       * any FBOs that might be rendering into this texture.
15844a49301eSmrg       * This flag never gets cleared since it's non-trivial to determine
15854a49301eSmrg       * when all FBOs might be done rendering to this texture.  That's OK
15864a49301eSmrg       * though since it's uncommon to render to a texture then repeatedly
15874a49301eSmrg       * call glTexImage() to change images in the texture.
15884a49301eSmrg       */
15894a49301eSmrg      texObj->_RenderToTexture = GL_TRUE;
15907117f1b4Smrg   }
15917117f1b4Smrg   else {
15927117f1b4Smrg      _mesa_remove_attachment(ctx, att);
15937117f1b4Smrg   }
15944a49301eSmrg
15954a49301eSmrg   invalidate_framebuffer(fb);
15964a49301eSmrg
15977117f1b4Smrg   _glthread_UNLOCK_MUTEX(fb->Mutex);
15987117f1b4Smrg}
15997117f1b4Smrg
16007117f1b4Smrg
16017117f1b4Smrg
16027117f1b4Smrgvoid GLAPIENTRY
16037117f1b4Smrg_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
16047117f1b4Smrg                              GLenum textarget, GLuint texture, GLint level)
16057117f1b4Smrg{
16067117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
16077117f1b4Smrg
16087117f1b4Smrg   if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
16097117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
16107117f1b4Smrg                  "glFramebufferTexture1DEXT(textarget)");
16117117f1b4Smrg      return;
16127117f1b4Smrg   }
16137117f1b4Smrg
16147117f1b4Smrg   framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
16157117f1b4Smrg                       level, 0);
16167117f1b4Smrg}
16177117f1b4Smrg
16187117f1b4Smrg
16197117f1b4Smrgvoid GLAPIENTRY
16207117f1b4Smrg_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
16217117f1b4Smrg                              GLenum textarget, GLuint texture, GLint level)
16227117f1b4Smrg{
16237117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
16247117f1b4Smrg
16257117f1b4Smrg   if ((texture != 0) &&
16267117f1b4Smrg       (textarget != GL_TEXTURE_2D) &&
16277117f1b4Smrg       (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
16287117f1b4Smrg       (!IS_CUBE_FACE(textarget))) {
16297117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
16304a49301eSmrg                  "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
16317117f1b4Smrg      return;
16327117f1b4Smrg   }
16337117f1b4Smrg
16347117f1b4Smrg   framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
16357117f1b4Smrg                       level, 0);
16367117f1b4Smrg}
16377117f1b4Smrg
16387117f1b4Smrg
16397117f1b4Smrgvoid GLAPIENTRY
16407117f1b4Smrg_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
16417117f1b4Smrg                              GLenum textarget, GLuint texture,
16427117f1b4Smrg                              GLint level, GLint zoffset)
16437117f1b4Smrg{
16447117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
16457117f1b4Smrg
16467117f1b4Smrg   if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
16477117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
16487117f1b4Smrg                  "glFramebufferTexture3DEXT(textarget)");
16497117f1b4Smrg      return;
16507117f1b4Smrg   }
16517117f1b4Smrg
16527117f1b4Smrg   framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
16537117f1b4Smrg                       level, zoffset);
16547117f1b4Smrg}
16557117f1b4Smrg
16567117f1b4Smrg
1657c1f859d4Smrgvoid GLAPIENTRY
1658c1f859d4Smrg_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1659c1f859d4Smrg                                 GLuint texture, GLint level, GLint layer)
1660c1f859d4Smrg{
1661c1f859d4Smrg   GET_CURRENT_CONTEXT(ctx);
1662c1f859d4Smrg
1663c1f859d4Smrg   framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1664c1f859d4Smrg                       level, layer);
1665c1f859d4Smrg}
1666c1f859d4Smrg
1667c1f859d4Smrg
16687117f1b4Smrgvoid GLAPIENTRY
16697117f1b4Smrg_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
16707117f1b4Smrg                                 GLenum renderbufferTarget,
16717117f1b4Smrg                                 GLuint renderbuffer)
16727117f1b4Smrg{
16737117f1b4Smrg   struct gl_renderbuffer_attachment *att;
16747117f1b4Smrg   struct gl_framebuffer *fb;
16757117f1b4Smrg   struct gl_renderbuffer *rb;
16767117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
16777117f1b4Smrg
16787117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
16797117f1b4Smrg
16807117f1b4Smrg   switch (target) {
16817117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
16827117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
16837117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
16847117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
16857117f1b4Smrg                     "glFramebufferRenderbufferEXT(target)");
16867117f1b4Smrg         return;
16877117f1b4Smrg      }
16887117f1b4Smrg      fb = ctx->DrawBuffer;
16897117f1b4Smrg      break;
16907117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
16917117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
16927117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
16937117f1b4Smrg                     "glFramebufferRenderbufferEXT(target)");
16947117f1b4Smrg         return;
16957117f1b4Smrg      }
16967117f1b4Smrg      fb = ctx->ReadBuffer;
16977117f1b4Smrg      break;
16987117f1b4Smrg#endif
16997117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
17007117f1b4Smrg      fb = ctx->DrawBuffer;
17017117f1b4Smrg      break;
17027117f1b4Smrg   default:
17037117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
17047117f1b4Smrg                  "glFramebufferRenderbufferEXT(target)");
17057117f1b4Smrg      return;
17067117f1b4Smrg   }
17077117f1b4Smrg
17087117f1b4Smrg   if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
17097117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
17107117f1b4Smrg                  "glFramebufferRenderbufferEXT(renderbufferTarget)");
17117117f1b4Smrg      return;
17127117f1b4Smrg   }
17137117f1b4Smrg
17147117f1b4Smrg   if (fb->Name == 0) {
17157117f1b4Smrg      /* Can't attach new renderbuffers to a window system framebuffer */
17167117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
17177117f1b4Smrg      return;
17187117f1b4Smrg   }
17197117f1b4Smrg
17207117f1b4Smrg   att = _mesa_get_attachment(ctx, fb, attachment);
17217117f1b4Smrg   if (att == NULL) {
17227117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
17234a49301eSmrg                  "glFramebufferRenderbufferEXT(invalid attachment %s)",
17244a49301eSmrg                  _mesa_lookup_enum_by_nr(attachment));
17257117f1b4Smrg      return;
17267117f1b4Smrg   }
17277117f1b4Smrg
17287117f1b4Smrg   if (renderbuffer) {
17297117f1b4Smrg      rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
17307117f1b4Smrg      if (!rb) {
17317117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION,
17324a49301eSmrg		     "glFramebufferRenderbufferEXT(non-existant"
17334a49301eSmrg                     " renderbuffer %u)", renderbuffer);
17347117f1b4Smrg	 return;
17357117f1b4Smrg      }
17367117f1b4Smrg   }
17377117f1b4Smrg   else {
17387117f1b4Smrg      /* remove renderbuffer attachment */
17397117f1b4Smrg      rb = NULL;
17407117f1b4Smrg   }
17417117f1b4Smrg
17424a49301eSmrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
17434a49301eSmrg      /* make sure the renderbuffer is a depth/stencil format */
17444a49301eSmrg      const GLenum baseFormat =
17454a49301eSmrg         _mesa_get_format_base_format(att->Renderbuffer->Format);
17464a49301eSmrg      if (baseFormat != GL_DEPTH_STENCIL) {
17474a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
17484a49301eSmrg                     "glFramebufferRenderbufferEXT(renderbuffer"
17494a49301eSmrg                     " is not DEPTH_STENCIL format)");
17504a49301eSmrg         return;
17514a49301eSmrg      }
17524a49301eSmrg   }
17534a49301eSmrg
17544a49301eSmrg
17557117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
17567117f1b4Smrg
17577117f1b4Smrg   assert(ctx->Driver.FramebufferRenderbuffer);
17587117f1b4Smrg   ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
17597117f1b4Smrg
17607117f1b4Smrg   /* Some subsequent GL commands may depend on the framebuffer's visual
17617117f1b4Smrg    * after the binding is updated.  Update visual info now.
17627117f1b4Smrg    */
17637117f1b4Smrg   _mesa_update_framebuffer_visual(fb);
17647117f1b4Smrg}
17657117f1b4Smrg
17667117f1b4Smrg
17677117f1b4Smrgvoid GLAPIENTRY
17687117f1b4Smrg_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
17697117f1b4Smrg                                             GLenum pname, GLint *params)
17707117f1b4Smrg{
17717117f1b4Smrg   const struct gl_renderbuffer_attachment *att;
17727117f1b4Smrg   struct gl_framebuffer *buffer;
17737117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
17747117f1b4Smrg
17757117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
17767117f1b4Smrg
17777117f1b4Smrg   switch (target) {
17787117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
17797117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
17807117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
17817117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
17827117f1b4Smrg                     "glGetFramebufferAttachmentParameterivEXT(target)");
17837117f1b4Smrg         return;
17847117f1b4Smrg      }
17857117f1b4Smrg      buffer = ctx->DrawBuffer;
17867117f1b4Smrg      break;
17877117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
17887117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
17897117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
17907117f1b4Smrg                     "glGetFramebufferAttachmentParameterivEXT(target)");
17917117f1b4Smrg         return;
17927117f1b4Smrg      }
17937117f1b4Smrg      buffer = ctx->ReadBuffer;
17947117f1b4Smrg      break;
17957117f1b4Smrg#endif
17967117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
17977117f1b4Smrg      buffer = ctx->DrawBuffer;
17987117f1b4Smrg      break;
17997117f1b4Smrg   default:
18007117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
18017117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(target)");
18027117f1b4Smrg      return;
18037117f1b4Smrg   }
18047117f1b4Smrg
18057117f1b4Smrg   if (buffer->Name == 0) {
18067117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
18077117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT");
18087117f1b4Smrg      return;
18097117f1b4Smrg   }
18107117f1b4Smrg
18117117f1b4Smrg   att = _mesa_get_attachment(ctx, buffer, attachment);
18127117f1b4Smrg   if (att == NULL) {
18137117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
18147117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(attachment)");
18157117f1b4Smrg      return;
18167117f1b4Smrg   }
18177117f1b4Smrg
18184a49301eSmrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
18194a49301eSmrg      /* the depth and stencil attachments must point to the same buffer */
18204a49301eSmrg      const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
18214a49301eSmrg      depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
18224a49301eSmrg      stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
18234a49301eSmrg      if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
18244a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
18254a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
18264a49301eSmrg                     " attachments differ)");
18274a49301eSmrg         return;
18284a49301eSmrg      }
18294a49301eSmrg   }
18304a49301eSmrg
18314a49301eSmrg   /* No need to flush here */
18327117f1b4Smrg
18337117f1b4Smrg   switch (pname) {
18347117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
18357117f1b4Smrg      *params = att->Type;
18367117f1b4Smrg      return;
18377117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
18387117f1b4Smrg      if (att->Type == GL_RENDERBUFFER_EXT) {
18397117f1b4Smrg	 *params = att->Renderbuffer->Name;
18407117f1b4Smrg      }
18417117f1b4Smrg      else if (att->Type == GL_TEXTURE) {
18427117f1b4Smrg	 *params = att->Texture->Name;
18437117f1b4Smrg      }
18447117f1b4Smrg      else {
18457117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
18467117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
18477117f1b4Smrg      }
18487117f1b4Smrg      return;
18497117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
18507117f1b4Smrg      if (att->Type == GL_TEXTURE) {
18517117f1b4Smrg	 *params = att->TextureLevel;
18527117f1b4Smrg      }
18537117f1b4Smrg      else {
18547117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
18557117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
18567117f1b4Smrg      }
18577117f1b4Smrg      return;
18587117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
18597117f1b4Smrg      if (att->Type == GL_TEXTURE) {
1860c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
1861c1f859d4Smrg            *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1862c1f859d4Smrg         }
1863c1f859d4Smrg         else {
1864c1f859d4Smrg            *params = 0;
1865c1f859d4Smrg         }
18667117f1b4Smrg      }
18677117f1b4Smrg      else {
18687117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
18697117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
18707117f1b4Smrg      }
18717117f1b4Smrg      return;
18727117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
18737117f1b4Smrg      if (att->Type == GL_TEXTURE) {
1874c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
1875c1f859d4Smrg            *params = att->Zoffset;
1876c1f859d4Smrg         }
1877c1f859d4Smrg         else {
1878c1f859d4Smrg            *params = 0;
1879c1f859d4Smrg         }
18807117f1b4Smrg      }
18817117f1b4Smrg      else {
18827117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
18837117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
18847117f1b4Smrg      }
18857117f1b4Smrg      return;
18864a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
18874a49301eSmrg      if (!ctx->Extensions.ARB_framebuffer_object) {
18884a49301eSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
18894a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
18904a49301eSmrg      }
18914a49301eSmrg      else {
18924a49301eSmrg         *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
18934a49301eSmrg      }
18944a49301eSmrg      return;
18954a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
18964a49301eSmrg      if (!ctx->Extensions.ARB_framebuffer_object) {
18974a49301eSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
18984a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
18994a49301eSmrg         return;
19004a49301eSmrg      }
19014a49301eSmrg      else {
19024a49301eSmrg         gl_format format = att->Renderbuffer->Format;
19034a49301eSmrg         if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
19044a49301eSmrg            /* special cases */
19054a49301eSmrg            *params = GL_INDEX;
19064a49301eSmrg         }
19074a49301eSmrg         else {
19084a49301eSmrg            *params = _mesa_get_format_datatype(format);
19094a49301eSmrg         }
19104a49301eSmrg      }
19114a49301eSmrg      return;
19124a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
19134a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
19144a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
19154a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
19164a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
19174a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
19184a49301eSmrg      if (!ctx->Extensions.ARB_framebuffer_object) {
19194a49301eSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
19204a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
19214a49301eSmrg      }
19224a49301eSmrg      else if (att->Texture) {
19234a49301eSmrg         const struct gl_texture_image *texImage =
19244a49301eSmrg            _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
19254a49301eSmrg                                   att->TextureLevel);
19264a49301eSmrg         if (texImage) {
19274a49301eSmrg            *params = get_component_bits(pname, texImage->_BaseFormat,
19284a49301eSmrg                                         texImage->TexFormat);
19294a49301eSmrg         }
19304a49301eSmrg         else {
19314a49301eSmrg            *params = 0;
19324a49301eSmrg         }
19334a49301eSmrg      }
19344a49301eSmrg      else if (att->Renderbuffer) {
19354a49301eSmrg         *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
19364a49301eSmrg                                      att->Renderbuffer->Format);
19374a49301eSmrg      }
19384a49301eSmrg      else {
19394a49301eSmrg         *params = 0;
19404a49301eSmrg      }
19414a49301eSmrg      return;
19427117f1b4Smrg   default:
19437117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
19447117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(pname)");
19457117f1b4Smrg      return;
19467117f1b4Smrg   }
19477117f1b4Smrg}
19487117f1b4Smrg
19497117f1b4Smrg
19507117f1b4Smrgvoid GLAPIENTRY
19517117f1b4Smrg_mesa_GenerateMipmapEXT(GLenum target)
19527117f1b4Smrg{
19537117f1b4Smrg   struct gl_texture_object *texObj;
19547117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
19557117f1b4Smrg
19567117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
19577117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
19587117f1b4Smrg
19597117f1b4Smrg   switch (target) {
19607117f1b4Smrg   case GL_TEXTURE_1D:
19617117f1b4Smrg   case GL_TEXTURE_2D:
19627117f1b4Smrg   case GL_TEXTURE_3D:
19637117f1b4Smrg   case GL_TEXTURE_CUBE_MAP:
19647117f1b4Smrg      /* OK, legal value */
19657117f1b4Smrg      break;
19667117f1b4Smrg   default:
19677117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
19687117f1b4Smrg      return;
19697117f1b4Smrg   }
19707117f1b4Smrg
19714a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
19724a49301eSmrg
19734a49301eSmrg   if (texObj->BaseLevel >= texObj->MaxLevel) {
19744a49301eSmrg      /* nothing to do */
19754a49301eSmrg      return;
19764a49301eSmrg   }
19777117f1b4Smrg
19787117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
1979c1f859d4Smrg   if (target == GL_TEXTURE_CUBE_MAP) {
19804a49301eSmrg      GLuint face;
1981c1f859d4Smrg      for (face = 0; face < 6; face++)
1982c1f859d4Smrg	 ctx->Driver.GenerateMipmap(ctx,
1983c1f859d4Smrg				    GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
1984c1f859d4Smrg				    texObj);
19854a49301eSmrg   }
19864a49301eSmrg   else {
1987c1f859d4Smrg      ctx->Driver.GenerateMipmap(ctx, target, texObj);
1988c1f859d4Smrg   }
19897117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
19907117f1b4Smrg}
19917117f1b4Smrg
19927117f1b4Smrg
19937117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
19944a49301eSmrg
19954a49301eSmrgstatic const struct gl_renderbuffer_attachment *
19964a49301eSmrgfind_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb)
19974a49301eSmrg{
19984a49301eSmrg   GLuint i;
19994a49301eSmrg   for (i = 0; i < Elements(fb->Attachment); i++) {
20004a49301eSmrg      if (fb->Attachment[i].Renderbuffer == rb)
20014a49301eSmrg         return &fb->Attachment[i];
20024a49301eSmrg   }
20034a49301eSmrg   return NULL;
20044a49301eSmrg}
20054a49301eSmrg
20064a49301eSmrg
20074a49301eSmrg
20084a49301eSmrg/**
20094a49301eSmrg * Blit rectangular region, optionally from one framebuffer to another.
20104a49301eSmrg *
20114a49301eSmrg * Note, if the src buffer is multisampled and the dest is not, this is
20124a49301eSmrg * when the samples must be resolved to a single color.
20134a49301eSmrg */
20147117f1b4Smrgvoid GLAPIENTRY
20157117f1b4Smrg_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
20167117f1b4Smrg                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
20177117f1b4Smrg                         GLbitfield mask, GLenum filter)
20187117f1b4Smrg{
20194a49301eSmrg   const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
20204a49301eSmrg                                     GL_DEPTH_BUFFER_BIT |
20214a49301eSmrg                                     GL_STENCIL_BUFFER_BIT);
20224a49301eSmrg   const struct gl_framebuffer *readFb, *drawFb;
20234a49301eSmrg   const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
20247117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
20257117f1b4Smrg
20267117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
20277117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
20287117f1b4Smrg
20297117f1b4Smrg   if (ctx->NewState) {
20307117f1b4Smrg      _mesa_update_state(ctx);
20317117f1b4Smrg   }
20327117f1b4Smrg
20334a49301eSmrg   readFb = ctx->ReadBuffer;
20344a49301eSmrg   drawFb = ctx->DrawBuffer;
20354a49301eSmrg
20364a49301eSmrg   if (!readFb || !drawFb) {
20374a49301eSmrg      /* This will normally never happen but someday we may want to
20384a49301eSmrg       * support MakeCurrent() with no drawables.
20394a49301eSmrg       */
20404a49301eSmrg      return;
20417117f1b4Smrg   }
20427117f1b4Smrg
20437117f1b4Smrg   /* check for complete framebuffers */
20444a49301eSmrg   if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
20454a49301eSmrg       readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
20467117f1b4Smrg      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
20477117f1b4Smrg                  "glBlitFramebufferEXT(incomplete draw/read buffers)");
20487117f1b4Smrg      return;
20497117f1b4Smrg   }
20507117f1b4Smrg
20517117f1b4Smrg   if (filter != GL_NEAREST && filter != GL_LINEAR) {
20527117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
20537117f1b4Smrg      return;
20547117f1b4Smrg   }
20557117f1b4Smrg
20564a49301eSmrg   if (mask & ~legalMaskBits) {
20577117f1b4Smrg      _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
20587117f1b4Smrg      return;
20597117f1b4Smrg   }
20607117f1b4Smrg
20617117f1b4Smrg   /* depth/stencil must be blitted with nearest filtering */
20627117f1b4Smrg   if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
20637117f1b4Smrg        && filter != GL_NEAREST) {
20647117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
20657117f1b4Smrg             "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
20667117f1b4Smrg      return;
20677117f1b4Smrg   }
20687117f1b4Smrg
20694a49301eSmrg   /* get color read/draw renderbuffers */
20704a49301eSmrg   if (mask & GL_COLOR_BUFFER_BIT) {
20714a49301eSmrg      colorReadRb = readFb->_ColorReadBuffer;
20724a49301eSmrg      colorDrawRb = drawFb->_ColorDrawBuffers[0];
20734a49301eSmrg   }
20744a49301eSmrg   else {
20754a49301eSmrg      colorReadRb = colorDrawRb = NULL;
20764a49301eSmrg   }
20774a49301eSmrg
20787117f1b4Smrg   if (mask & GL_STENCIL_BUFFER_BIT) {
20794a49301eSmrg      struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
20804a49301eSmrg      struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
20814a49301eSmrg      if (!readRb ||
20824a49301eSmrg          !drawRb ||
20834a49301eSmrg          _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
20844a49301eSmrg          _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
20857117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
20867117f1b4Smrg                     "glBlitFramebufferEXT(stencil buffer size mismatch");
20877117f1b4Smrg         return;
20887117f1b4Smrg      }
20897117f1b4Smrg   }
20907117f1b4Smrg
20917117f1b4Smrg   if (mask & GL_DEPTH_BUFFER_BIT) {
20924a49301eSmrg      struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
20934a49301eSmrg      struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
20944a49301eSmrg      if (!readRb ||
20954a49301eSmrg          !drawRb ||
20964a49301eSmrg          _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
20974a49301eSmrg          _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
20987117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
20997117f1b4Smrg                     "glBlitFramebufferEXT(depth buffer size mismatch");
21007117f1b4Smrg         return;
21017117f1b4Smrg      }
21027117f1b4Smrg   }
21037117f1b4Smrg
21044a49301eSmrg   if (readFb->Visual.samples > 0 &&
21054a49301eSmrg       drawFb->Visual.samples > 0 &&
21064a49301eSmrg       readFb->Visual.samples != drawFb->Visual.samples) {
21074a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
21084a49301eSmrg                  "glBlitFramebufferEXT(mismatched samples");
21094a49301eSmrg      return;
21104a49301eSmrg   }
21114a49301eSmrg
21124a49301eSmrg   /* extra checks for multisample copies... */
21134a49301eSmrg   if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
21144a49301eSmrg      /* src and dest region sizes must be the same */
21154a49301eSmrg      if (srcX1 - srcX0 != dstX1 - dstX0 ||
21164a49301eSmrg          srcY1 - srcY0 != dstY1 - dstY0) {
21174a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
21184a49301eSmrg                "glBlitFramebufferEXT(bad src/dst multisample region sizes");
21194a49301eSmrg         return;
21204a49301eSmrg      }
21214a49301eSmrg
21224a49301eSmrg      /* color formats must match */
21234a49301eSmrg      if (colorReadRb &&
21244a49301eSmrg          colorDrawRb &&
21254a49301eSmrg          colorReadRb->Format != colorDrawRb->Format) {
21264a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
21274a49301eSmrg                "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
21284a49301eSmrg         return;
21294a49301eSmrg      }
21304a49301eSmrg   }
21314a49301eSmrg
21327117f1b4Smrg   if (!ctx->Extensions.EXT_framebuffer_blit) {
21337117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
21347117f1b4Smrg      return;
21357117f1b4Smrg   }
21367117f1b4Smrg
21374a49301eSmrg   /* Debug code */
21384a49301eSmrg   if (DEBUG_BLIT) {
21394a49301eSmrg      _mesa_printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
21404a49301eSmrg                   " 0x%x, 0x%x)\n",
21414a49301eSmrg                   srcX0, srcY0, srcX1, srcY1,
21424a49301eSmrg                   dstX0, dstY0, dstX1, dstY1,
21434a49301eSmrg                   mask, filter);
21444a49301eSmrg      if (colorReadRb) {
21454a49301eSmrg         const struct gl_renderbuffer_attachment *att;
21464a49301eSmrg
21474a49301eSmrg         att = find_attachment(readFb, colorReadRb);
21484a49301eSmrg         _mesa_printf("  Src FBO %u  RB %u (%dx%d)  ",
21494a49301eSmrg                      readFb->Name, colorReadRb->Name,
21504a49301eSmrg                      colorReadRb->Width, colorReadRb->Height);
21514a49301eSmrg         if (att && att->Texture) {
21524a49301eSmrg            _mesa_printf("Tex %u  tgt 0x%x  level %u  face %u",
21534a49301eSmrg                         att->Texture->Name,
21544a49301eSmrg                         att->Texture->Target,
21554a49301eSmrg                         att->TextureLevel,
21564a49301eSmrg                         att->CubeMapFace);
21574a49301eSmrg         }
21584a49301eSmrg         _mesa_printf("\n");
21594a49301eSmrg
21604a49301eSmrg         att = find_attachment(drawFb, colorDrawRb);
21614a49301eSmrg         _mesa_printf("  Dst FBO %u  RB %u (%dx%d)  ",
21624a49301eSmrg                      drawFb->Name, colorDrawRb->Name,
21634a49301eSmrg                      colorDrawRb->Width, colorDrawRb->Height);
21644a49301eSmrg         if (att && att->Texture) {
21654a49301eSmrg            _mesa_printf("Tex %u  tgt 0x%x  level %u  face %u",
21664a49301eSmrg                         att->Texture->Name,
21674a49301eSmrg                         att->Texture->Target,
21684a49301eSmrg                         att->TextureLevel,
21694a49301eSmrg                         att->CubeMapFace);
21704a49301eSmrg         }
21714a49301eSmrg         _mesa_printf("\n");
21724a49301eSmrg      }
21734a49301eSmrg   }
21744a49301eSmrg
21757117f1b4Smrg   ASSERT(ctx->Driver.BlitFramebuffer);
21767117f1b4Smrg   ctx->Driver.BlitFramebuffer(ctx,
21777117f1b4Smrg                               srcX0, srcY0, srcX1, srcY1,
21787117f1b4Smrg                               dstX0, dstY0, dstX1, dstY1,
21797117f1b4Smrg                               mask, filter);
21807117f1b4Smrg}
21817117f1b4Smrg#endif /* FEATURE_EXT_framebuffer_blit */
2182