fbobject.c revision cdc920a0
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");
377cdc920a0Smrg         printf("texobj = %u\n", texObj->Name);
378cdc920a0Smrg         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.
861cdc920a0Smrg *
862cdc920a0Smrg * XXX in the future when we support red-only and red-green formats
863cdc920a0Smrg * we'll also return GL_RED and GL_RG.
8647117f1b4Smrg */
8657117f1b4SmrgGLenum
8667117f1b4Smrg_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
8677117f1b4Smrg{
8687117f1b4Smrg   switch (internalFormat) {
8697117f1b4Smrg   case GL_RGB:
8707117f1b4Smrg   case GL_R3_G3_B2:
8717117f1b4Smrg   case GL_RGB4:
8727117f1b4Smrg   case GL_RGB5:
8737117f1b4Smrg   case GL_RGB8:
8747117f1b4Smrg   case GL_RGB10:
8757117f1b4Smrg   case GL_RGB12:
8767117f1b4Smrg   case GL_RGB16:
8777117f1b4Smrg      return GL_RGB;
8787117f1b4Smrg   case GL_RGBA:
8797117f1b4Smrg   case GL_RGBA2:
8807117f1b4Smrg   case GL_RGBA4:
8817117f1b4Smrg   case GL_RGB5_A1:
8827117f1b4Smrg   case GL_RGBA8:
8837117f1b4Smrg   case GL_RGB10_A2:
8847117f1b4Smrg   case GL_RGBA12:
8857117f1b4Smrg   case GL_RGBA16:
8867117f1b4Smrg      return GL_RGBA;
8877117f1b4Smrg   case GL_STENCIL_INDEX:
8887117f1b4Smrg   case GL_STENCIL_INDEX1_EXT:
8897117f1b4Smrg   case GL_STENCIL_INDEX4_EXT:
8907117f1b4Smrg   case GL_STENCIL_INDEX8_EXT:
8917117f1b4Smrg   case GL_STENCIL_INDEX16_EXT:
8927117f1b4Smrg      return GL_STENCIL_INDEX;
8937117f1b4Smrg   case GL_DEPTH_COMPONENT:
8947117f1b4Smrg   case GL_DEPTH_COMPONENT16:
8957117f1b4Smrg   case GL_DEPTH_COMPONENT24:
8967117f1b4Smrg   case GL_DEPTH_COMPONENT32:
8977117f1b4Smrg      return GL_DEPTH_COMPONENT;
8987117f1b4Smrg   case GL_DEPTH_STENCIL_EXT:
8997117f1b4Smrg   case GL_DEPTH24_STENCIL8_EXT:
9007117f1b4Smrg      if (ctx->Extensions.EXT_packed_depth_stencil)
9017117f1b4Smrg         return GL_DEPTH_STENCIL_EXT;
9027117f1b4Smrg      else
9037117f1b4Smrg         return 0;
9047117f1b4Smrg   /* XXX add floating point formats eventually */
9057117f1b4Smrg   default:
9067117f1b4Smrg      return 0;
9077117f1b4Smrg   }
9087117f1b4Smrg}
9097117f1b4Smrg
9107117f1b4Smrg
9114a49301eSmrg/** sentinal value, see below */
9124a49301eSmrg#define NO_SAMPLES 1000
9134a49301eSmrg
9144a49301eSmrg
9154a49301eSmrg/**
9164a49301eSmrg * Helper function used by _mesa_RenderbufferStorageEXT() and
9174a49301eSmrg * _mesa_RenderbufferStorageMultisample().
9184a49301eSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
9194a49301eSmrg */
9204a49301eSmrgstatic void
9214a49301eSmrgrenderbuffer_storage(GLenum target, GLenum internalFormat,
9224a49301eSmrg                     GLsizei width, GLsizei height, GLsizei samples)
9237117f1b4Smrg{
9244a49301eSmrg   const char *func = samples == NO_SAMPLES ?
9254a49301eSmrg      "glRenderbufferStorage" : "RenderbufferStorageMultisample";
9267117f1b4Smrg   struct gl_renderbuffer *rb;
9277117f1b4Smrg   GLenum baseFormat;
9287117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9297117f1b4Smrg
9307117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
9317117f1b4Smrg
9327117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
9334a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
9347117f1b4Smrg      return;
9357117f1b4Smrg   }
9367117f1b4Smrg
9377117f1b4Smrg   baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
9387117f1b4Smrg   if (baseFormat == 0) {
9394a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
9407117f1b4Smrg      return;
9417117f1b4Smrg   }
9427117f1b4Smrg
9437117f1b4Smrg   if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
9444a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
9457117f1b4Smrg      return;
9467117f1b4Smrg   }
9477117f1b4Smrg
9487117f1b4Smrg   if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
9494a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
9507117f1b4Smrg      return;
9517117f1b4Smrg   }
9527117f1b4Smrg
9534a49301eSmrg   if (samples == NO_SAMPLES) {
9544a49301eSmrg      /* NumSamples == 0 indicates non-multisampling */
9554a49301eSmrg      samples = 0;
9564a49301eSmrg   }
957cdc920a0Smrg   else if (samples > (GLsizei) ctx->Const.MaxSamples) {
9584a49301eSmrg      /* note: driver may choose to use more samples than what's requested */
9594a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
9604a49301eSmrg      return;
9614a49301eSmrg   }
9627117f1b4Smrg
9634a49301eSmrg   rb = ctx->CurrentRenderbuffer;
9647117f1b4Smrg   if (!rb) {
9654a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, func);
9667117f1b4Smrg      return;
9677117f1b4Smrg   }
9687117f1b4Smrg
9697117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
9707117f1b4Smrg
9717117f1b4Smrg   if (rb->InternalFormat == internalFormat &&
9727117f1b4Smrg       rb->Width == (GLuint) width &&
9737117f1b4Smrg       rb->Height == (GLuint) height) {
9747117f1b4Smrg      /* no change in allocation needed */
9757117f1b4Smrg      return;
9767117f1b4Smrg   }
9777117f1b4Smrg
9787117f1b4Smrg   /* These MUST get set by the AllocStorage func */
9794a49301eSmrg   rb->Format = MESA_FORMAT_NONE;
9804a49301eSmrg   rb->NumSamples = samples;
9817117f1b4Smrg
9827117f1b4Smrg   /* Now allocate the storage */
9837117f1b4Smrg   ASSERT(rb->AllocStorage);
9847117f1b4Smrg   if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
9857117f1b4Smrg      /* No error - check/set fields now */
9864a49301eSmrg      assert(rb->Format != MESA_FORMAT_NONE);
9877117f1b4Smrg      assert(rb->Width == (GLuint) width);
9887117f1b4Smrg      assert(rb->Height == (GLuint) height);
9897117f1b4Smrg      rb->InternalFormat = internalFormat;
990cdc920a0Smrg      rb->_BaseFormat = baseFormat;
9914a49301eSmrg      assert(rb->_BaseFormat != 0);
9927117f1b4Smrg   }
9937117f1b4Smrg   else {
9947117f1b4Smrg      /* Probably ran out of memory - clear the fields */
9957117f1b4Smrg      rb->Width = 0;
9967117f1b4Smrg      rb->Height = 0;
9974a49301eSmrg      rb->Format = MESA_FORMAT_NONE;
9987117f1b4Smrg      rb->InternalFormat = GL_NONE;
9997117f1b4Smrg      rb->_BaseFormat = GL_NONE;
10004a49301eSmrg      rb->NumSamples = 0;
10017117f1b4Smrg   }
10027117f1b4Smrg
10037117f1b4Smrg   /*
10047117f1b4Smrg   test_framebuffer_completeness(ctx, fb);
10057117f1b4Smrg   */
10067117f1b4Smrg   /* XXX if this renderbuffer is attached anywhere, invalidate attachment
10077117f1b4Smrg    * points???
10087117f1b4Smrg    */
10097117f1b4Smrg}
10107117f1b4Smrg
1011cdc920a0Smrg#if FEATURE_OES_EGL_image
1012cdc920a0Smrgvoid GLAPIENTRY
1013cdc920a0Smrg_mesa_EGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image)
1014cdc920a0Smrg{
1015cdc920a0Smrg   struct gl_renderbuffer *rb;
1016cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
1017cdc920a0Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1018cdc920a0Smrg
1019cdc920a0Smrg   if (target != GL_RENDERBUFFER) {
1020cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "EGLImageTargetRenderbufferStorageOES");
1021cdc920a0Smrg      return;
1022cdc920a0Smrg   }
1023cdc920a0Smrg
1024cdc920a0Smrg   rb = ctx->CurrentRenderbuffer;
1025cdc920a0Smrg   if (!rb) {
1026cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "EGLImageTargetRenderbufferStorageOES");
1027cdc920a0Smrg      return;
1028cdc920a0Smrg   }
1029cdc920a0Smrg
1030cdc920a0Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1031cdc920a0Smrg
1032cdc920a0Smrg   ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1033cdc920a0Smrg}
1034cdc920a0Smrg#endif
10357117f1b4Smrg
10364a49301eSmrg/**
10374a49301eSmrg * Helper function for _mesa_GetRenderbufferParameterivEXT() and
10384a49301eSmrg * _mesa_GetFramebufferAttachmentParameterivEXT()
10394a49301eSmrg * We have to be careful to respect the base format.  For example, if a
10404a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the
10414a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
10424a49301eSmrg * we need to return zero.
10434a49301eSmrg */
10444a49301eSmrgstatic GLint
10454a49301eSmrgget_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
10464a49301eSmrg{
10474a49301eSmrg   switch (pname) {
10484a49301eSmrg   case GL_RENDERBUFFER_RED_SIZE_EXT:
10494a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
10504a49301eSmrg   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
10514a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
10524a49301eSmrg   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
10534a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
10544a49301eSmrg      if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
10554a49301eSmrg         return _mesa_get_format_bits(format, pname);
10564a49301eSmrg      else
10574a49301eSmrg         return 0;
10584a49301eSmrg   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
10594a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
10604a49301eSmrg      if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA)
10614a49301eSmrg         return _mesa_get_format_bits(format, pname);
10624a49301eSmrg      else
10634a49301eSmrg         return 0;
10644a49301eSmrg   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
10654a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
10664a49301eSmrg      if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
10674a49301eSmrg         return _mesa_get_format_bits(format, pname);
10684a49301eSmrg      else
10694a49301eSmrg         return 0;
10704a49301eSmrg   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
10714a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
10724a49301eSmrg      if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
10734a49301eSmrg         return _mesa_get_format_bits(format, pname);
10744a49301eSmrg      else
10754a49301eSmrg         return 0;
10764a49301eSmrg   default:
10774a49301eSmrg      return 0;
10784a49301eSmrg   }
10794a49301eSmrg}
10804a49301eSmrg
10814a49301eSmrg
10824a49301eSmrg
10834a49301eSmrgvoid GLAPIENTRY
10844a49301eSmrg_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
10854a49301eSmrg                             GLsizei width, GLsizei height)
10864a49301eSmrg{
10874a49301eSmrg   /* GL_ARB_fbo says calling this function is equivalent to calling
10884a49301eSmrg    * glRenderbufferStorageMultisample() with samples=0.  We pass in
10894a49301eSmrg    * a token value here just for error reporting purposes.
10904a49301eSmrg    */
10914a49301eSmrg   renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
10924a49301eSmrg}
10934a49301eSmrg
10944a49301eSmrg
10954a49301eSmrgvoid GLAPIENTRY
10964a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
10974a49301eSmrg                                     GLenum internalFormat,
10984a49301eSmrg                                     GLsizei width, GLsizei height)
10994a49301eSmrg{
11004a49301eSmrg   renderbuffer_storage(target, internalFormat, width, height, samples);
11014a49301eSmrg}
11024a49301eSmrg
11034a49301eSmrg
11044a49301eSmrg
11057117f1b4Smrgvoid GLAPIENTRY
11067117f1b4Smrg_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
11077117f1b4Smrg{
11084a49301eSmrg   struct gl_renderbuffer *rb;
11097117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
11107117f1b4Smrg
11117117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
11127117f1b4Smrg
11137117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
11147117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
11157117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
11167117f1b4Smrg      return;
11177117f1b4Smrg   }
11187117f1b4Smrg
11194a49301eSmrg   rb = ctx->CurrentRenderbuffer;
11204a49301eSmrg   if (!rb) {
11217117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
11227117f1b4Smrg                  "glGetRenderbufferParameterivEXT");
11237117f1b4Smrg      return;
11247117f1b4Smrg   }
11257117f1b4Smrg
11264a49301eSmrg   /* No need to flush here since we're just quering state which is
11274a49301eSmrg    * not effected by rendering.
11284a49301eSmrg    */
11297117f1b4Smrg
11307117f1b4Smrg   switch (pname) {
11317117f1b4Smrg   case GL_RENDERBUFFER_WIDTH_EXT:
11324a49301eSmrg      *params = rb->Width;
11337117f1b4Smrg      return;
11347117f1b4Smrg   case GL_RENDERBUFFER_HEIGHT_EXT:
11354a49301eSmrg      *params = rb->Height;
11367117f1b4Smrg      return;
11377117f1b4Smrg   case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
11384a49301eSmrg      *params = rb->InternalFormat;
11397117f1b4Smrg      return;
11407117f1b4Smrg   case GL_RENDERBUFFER_RED_SIZE_EXT:
11417117f1b4Smrg   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
11427117f1b4Smrg   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
11437117f1b4Smrg   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
11447117f1b4Smrg   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
11457117f1b4Smrg   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
11464a49301eSmrg      *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
11477117f1b4Smrg      break;
11484a49301eSmrg   case GL_RENDERBUFFER_SAMPLES:
11494a49301eSmrg      if (ctx->Extensions.ARB_framebuffer_object) {
11504a49301eSmrg         *params = rb->NumSamples;
11514a49301eSmrg         break;
11524a49301eSmrg      }
11534a49301eSmrg      /* fallthrough */
11547117f1b4Smrg   default:
11557117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
11567117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
11577117f1b4Smrg      return;
11587117f1b4Smrg   }
11597117f1b4Smrg}
11607117f1b4Smrg
11617117f1b4Smrg
11627117f1b4SmrgGLboolean GLAPIENTRY
11637117f1b4Smrg_mesa_IsFramebufferEXT(GLuint framebuffer)
11647117f1b4Smrg{
11657117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
11667117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
11677117f1b4Smrg   if (framebuffer) {
11687117f1b4Smrg      struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
11697117f1b4Smrg      if (rb != NULL && rb != &DummyFramebuffer)
11707117f1b4Smrg         return GL_TRUE;
11717117f1b4Smrg   }
11727117f1b4Smrg   return GL_FALSE;
11737117f1b4Smrg}
11747117f1b4Smrg
11757117f1b4Smrg
11764a49301eSmrg/**
11774a49301eSmrg * Check if any of the attachments of the given framebuffer are textures
11784a49301eSmrg * (render to texture).  Call ctx->Driver.RenderTexture() for such
11794a49301eSmrg * attachments.
11804a49301eSmrg */
11817117f1b4Smrgstatic void
11827117f1b4Smrgcheck_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
11837117f1b4Smrg{
11847117f1b4Smrg   GLuint i;
11857117f1b4Smrg   ASSERT(ctx->Driver.RenderTexture);
11864a49301eSmrg
11874a49301eSmrg   if (fb->Name == 0)
11884a49301eSmrg      return; /* can't render to texture with winsys framebuffers */
11894a49301eSmrg
11907117f1b4Smrg   for (i = 0; i < BUFFER_COUNT; i++) {
11917117f1b4Smrg      struct gl_renderbuffer_attachment *att = fb->Attachment + i;
11927117f1b4Smrg      struct gl_texture_object *texObj = att->Texture;
11937117f1b4Smrg      if (texObj
11944a49301eSmrg          && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
11957117f1b4Smrg         ctx->Driver.RenderTexture(ctx, fb, att);
11967117f1b4Smrg      }
11977117f1b4Smrg   }
11987117f1b4Smrg}
11997117f1b4Smrg
12007117f1b4Smrg
12017117f1b4Smrg/**
12027117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures.
12037117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to
12047117f1b4Smrg * notify the device driver that the texture image may have changed.
12057117f1b4Smrg */
12067117f1b4Smrgstatic void
12077117f1b4Smrgcheck_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
12087117f1b4Smrg{
12094a49301eSmrg   if (fb->Name == 0)
12104a49301eSmrg      return; /* can't render to texture with winsys framebuffers */
12114a49301eSmrg
12127117f1b4Smrg   if (ctx->Driver.FinishRenderTexture) {
12137117f1b4Smrg      GLuint i;
12147117f1b4Smrg      for (i = 0; i < BUFFER_COUNT; i++) {
12157117f1b4Smrg         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1216c1f859d4Smrg         if (att->Texture && att->Renderbuffer) {
12177117f1b4Smrg            ctx->Driver.FinishRenderTexture(ctx, att);
12187117f1b4Smrg         }
12197117f1b4Smrg      }
12207117f1b4Smrg   }
12217117f1b4Smrg}
12227117f1b4Smrg
12237117f1b4Smrg
12247117f1b4Smrgvoid GLAPIENTRY
12257117f1b4Smrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
12267117f1b4Smrg{
12274a49301eSmrg   struct gl_framebuffer *newDrawFb, *newReadFb;
12284a49301eSmrg   struct gl_framebuffer *oldDrawFb, *oldReadFb;
12297117f1b4Smrg   GLboolean bindReadBuf, bindDrawBuf;
12307117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
12317117f1b4Smrg
12324a49301eSmrg#ifdef DEBUG
12334a49301eSmrg   if (ctx->Extensions.ARB_framebuffer_object) {
12344a49301eSmrg      ASSERT(ctx->Extensions.EXT_framebuffer_object);
12354a49301eSmrg      ASSERT(ctx->Extensions.EXT_framebuffer_blit);
12364a49301eSmrg   }
12374a49301eSmrg#endif
12384a49301eSmrg
12397117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
12407117f1b4Smrg
12417117f1b4Smrg   if (!ctx->Extensions.EXT_framebuffer_object) {
12427117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
12437117f1b4Smrg                  "glBindFramebufferEXT(unsupported)");
12447117f1b4Smrg      return;
12457117f1b4Smrg   }
12467117f1b4Smrg
12477117f1b4Smrg   switch (target) {
12487117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
12497117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
12507117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
12517117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
12527117f1b4Smrg         return;
12537117f1b4Smrg      }
12547117f1b4Smrg      bindDrawBuf = GL_TRUE;
12557117f1b4Smrg      bindReadBuf = GL_FALSE;
12567117f1b4Smrg      break;
12577117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
12587117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
12597117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
12607117f1b4Smrg         return;
12617117f1b4Smrg      }
12627117f1b4Smrg      bindDrawBuf = GL_FALSE;
12637117f1b4Smrg      bindReadBuf = GL_TRUE;
12647117f1b4Smrg      break;
12657117f1b4Smrg#endif
12667117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
12677117f1b4Smrg      bindDrawBuf = GL_TRUE;
12687117f1b4Smrg      bindReadBuf = GL_TRUE;
12697117f1b4Smrg      break;
12707117f1b4Smrg   default:
12717117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
12727117f1b4Smrg      return;
12737117f1b4Smrg   }
12747117f1b4Smrg
12757117f1b4Smrg   if (framebuffer) {
12767117f1b4Smrg      /* Binding a user-created framebuffer object */
12774a49301eSmrg      newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
12784a49301eSmrg      if (newDrawFb == &DummyFramebuffer) {
12797117f1b4Smrg         /* ID was reserved, but no real framebuffer object made yet */
12804a49301eSmrg         newDrawFb = NULL;
12817117f1b4Smrg      }
12824a49301eSmrg      else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
12834a49301eSmrg         /* All FBO IDs must be Gen'd */
12844a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
12854a49301eSmrg         return;
12864a49301eSmrg      }
12874a49301eSmrg
12884a49301eSmrg      if (!newDrawFb) {
12897117f1b4Smrg	 /* create new framebuffer object */
12904a49301eSmrg	 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
12914a49301eSmrg	 if (!newDrawFb) {
12927117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
12937117f1b4Smrg	    return;
12947117f1b4Smrg	 }
12954a49301eSmrg         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
12967117f1b4Smrg      }
12974a49301eSmrg      newReadFb = newDrawFb;
12987117f1b4Smrg   }
12997117f1b4Smrg   else {
13007117f1b4Smrg      /* Binding the window system framebuffer (which was originally set
13017117f1b4Smrg       * with MakeCurrent).
13027117f1b4Smrg       */
13034a49301eSmrg      newDrawFb = ctx->WinSysDrawBuffer;
13044a49301eSmrg      newReadFb = ctx->WinSysReadBuffer;
13057117f1b4Smrg   }
13067117f1b4Smrg
13074a49301eSmrg   ASSERT(newDrawFb);
13084a49301eSmrg   ASSERT(newDrawFb != &DummyFramebuffer);
13094a49301eSmrg
13104a49301eSmrg   /* save pointers to current/old framebuffers */
13114a49301eSmrg   oldDrawFb = ctx->DrawBuffer;
13124a49301eSmrg   oldReadFb = ctx->ReadBuffer;
13134a49301eSmrg
13144a49301eSmrg   /* check if really changing bindings */
13154a49301eSmrg   if (oldDrawFb == newDrawFb)
13164a49301eSmrg      bindDrawBuf = GL_FALSE;
13174a49301eSmrg   if (oldReadFb == newReadFb)
13184a49301eSmrg      bindReadBuf = GL_FALSE;
13197117f1b4Smrg
13207117f1b4Smrg   /*
13214a49301eSmrg    * OK, now bind the new Draw/Read framebuffers, if they're changing.
13224a49301eSmrg    *
13234a49301eSmrg    * We also check if we're beginning and/or ending render-to-texture.
13244a49301eSmrg    * When a framebuffer with texture attachments is unbound, call
13254a49301eSmrg    * ctx->Driver.FinishRenderTexture().
13264a49301eSmrg    * When a framebuffer with texture attachments is bound, call
13274a49301eSmrg    * ctx->Driver.RenderTexture().
13284a49301eSmrg    *
13294a49301eSmrg    * Note that if the ReadBuffer has texture attachments we don't consider
13304a49301eSmrg    * that a render-to-texture case.
13317117f1b4Smrg    */
13327117f1b4Smrg   if (bindReadBuf) {
13334a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
13344a49301eSmrg
13354a49301eSmrg      /* check if old readbuffer was render-to-texture */
13364a49301eSmrg      check_end_texture_render(ctx, oldReadFb);
13374a49301eSmrg
13384a49301eSmrg      _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
13397117f1b4Smrg   }
13407117f1b4Smrg
13417117f1b4Smrg   if (bindDrawBuf) {
13424a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
13437117f1b4Smrg
13444a49301eSmrg      /* check if old read/draw buffers were render-to-texture */
13454a49301eSmrg      if (!bindReadBuf)
13464a49301eSmrg         check_end_texture_render(ctx, oldReadFb);
13477117f1b4Smrg
13484a49301eSmrg      if (oldDrawFb != oldReadFb)
13494a49301eSmrg         check_end_texture_render(ctx, oldDrawFb);
13504a49301eSmrg
13514a49301eSmrg      /* check if newly bound framebuffer has any texture attachments */
13524a49301eSmrg      check_begin_texture_render(ctx, newDrawFb);
13534a49301eSmrg
13544a49301eSmrg      _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
13557117f1b4Smrg   }
13567117f1b4Smrg
13574a49301eSmrg   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
13584a49301eSmrg      ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
13597117f1b4Smrg   }
13607117f1b4Smrg}
13617117f1b4Smrg
13627117f1b4Smrg
13637117f1b4Smrgvoid GLAPIENTRY
13647117f1b4Smrg_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
13657117f1b4Smrg{
13667117f1b4Smrg   GLint i;
13677117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
13687117f1b4Smrg
13697117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
13707117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
13717117f1b4Smrg
13727117f1b4Smrg   for (i = 0; i < n; i++) {
13737117f1b4Smrg      if (framebuffers[i] > 0) {
13747117f1b4Smrg	 struct gl_framebuffer *fb;
13757117f1b4Smrg	 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
13767117f1b4Smrg	 if (fb) {
13777117f1b4Smrg            ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
13787117f1b4Smrg
13797117f1b4Smrg            /* check if deleting currently bound framebuffer object */
13804a49301eSmrg            if (ctx->Extensions.EXT_framebuffer_blit) {
13814a49301eSmrg               /* separate draw/read binding points */
13824a49301eSmrg               if (fb == ctx->DrawBuffer) {
13834a49301eSmrg                  /* bind default */
13844a49301eSmrg                  ASSERT(fb->RefCount >= 2);
13854a49301eSmrg                  _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
13864a49301eSmrg               }
13874a49301eSmrg               if (fb == ctx->ReadBuffer) {
13884a49301eSmrg                  /* bind default */
13894a49301eSmrg                  ASSERT(fb->RefCount >= 2);
13904a49301eSmrg                  _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
13914a49301eSmrg               }
13924a49301eSmrg            }
13934a49301eSmrg            else {
13944a49301eSmrg               /* only one binding point for read/draw buffers */
13954a49301eSmrg               if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
13964a49301eSmrg                  /* bind default */
13974a49301eSmrg                  ASSERT(fb->RefCount >= 2);
13984a49301eSmrg                  _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
13994a49301eSmrg               }
14007117f1b4Smrg            }
14017117f1b4Smrg
14027117f1b4Smrg	    /* remove from hash table immediately, to free the ID */
14037117f1b4Smrg	    _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
14047117f1b4Smrg
14057117f1b4Smrg            if (fb != &DummyFramebuffer) {
14067117f1b4Smrg               /* But the object will not be freed until it's no longer
14077117f1b4Smrg                * bound in any context.
14087117f1b4Smrg                */
14094a49301eSmrg               _mesa_reference_framebuffer(&fb, NULL);
14107117f1b4Smrg	    }
14117117f1b4Smrg	 }
14127117f1b4Smrg      }
14137117f1b4Smrg   }
14147117f1b4Smrg}
14157117f1b4Smrg
14167117f1b4Smrg
14177117f1b4Smrgvoid GLAPIENTRY
14187117f1b4Smrg_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
14197117f1b4Smrg{
14207117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
14217117f1b4Smrg   GLuint first;
14227117f1b4Smrg   GLint i;
14237117f1b4Smrg
14247117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
14257117f1b4Smrg
14267117f1b4Smrg   if (n < 0) {
14277117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
14287117f1b4Smrg      return;
14297117f1b4Smrg   }
14307117f1b4Smrg
14317117f1b4Smrg   if (!framebuffers)
14327117f1b4Smrg      return;
14337117f1b4Smrg
14347117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
14357117f1b4Smrg
14367117f1b4Smrg   for (i = 0; i < n; i++) {
14377117f1b4Smrg      GLuint name = first + i;
14387117f1b4Smrg      framebuffers[i] = name;
14397117f1b4Smrg      /* insert dummy placeholder into hash table */
14407117f1b4Smrg      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
14417117f1b4Smrg      _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
14427117f1b4Smrg      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
14437117f1b4Smrg   }
14447117f1b4Smrg}
14457117f1b4Smrg
14467117f1b4Smrg
14477117f1b4Smrg
14487117f1b4SmrgGLenum GLAPIENTRY
14497117f1b4Smrg_mesa_CheckFramebufferStatusEXT(GLenum target)
14507117f1b4Smrg{
14517117f1b4Smrg   struct gl_framebuffer *buffer;
14527117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
14537117f1b4Smrg
14547117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
14557117f1b4Smrg
14567117f1b4Smrg   switch (target) {
14577117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
14587117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
14597117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
14607117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
14617117f1b4Smrg         return 0;
14627117f1b4Smrg      }
14637117f1b4Smrg      buffer = ctx->DrawBuffer;
14647117f1b4Smrg      break;
14657117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
14667117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
14677117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
14687117f1b4Smrg         return 0;
14697117f1b4Smrg      }
14707117f1b4Smrg      buffer = ctx->ReadBuffer;
14717117f1b4Smrg      break;
14727117f1b4Smrg#endif
14737117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
14747117f1b4Smrg      buffer = ctx->DrawBuffer;
14757117f1b4Smrg      break;
14767117f1b4Smrg   default:
14777117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
14787117f1b4Smrg      return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
14797117f1b4Smrg   }
14807117f1b4Smrg
14817117f1b4Smrg   if (buffer->Name == 0) {
14827117f1b4Smrg      /* The window system / default framebuffer is always complete */
14837117f1b4Smrg      return GL_FRAMEBUFFER_COMPLETE_EXT;
14847117f1b4Smrg   }
14857117f1b4Smrg
14864a49301eSmrg   /* No need to flush here */
14874a49301eSmrg
14884a49301eSmrg   if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
14894a49301eSmrg      _mesa_test_framebuffer_completeness(ctx, buffer);
14904a49301eSmrg   }
14917117f1b4Smrg
14927117f1b4Smrg   return buffer->_Status;
14937117f1b4Smrg}
14947117f1b4Smrg
14957117f1b4Smrg
14967117f1b4Smrg
14977117f1b4Smrg/**
14987117f1b4Smrg * Common code called by glFramebufferTexture1D/2D/3DEXT().
14997117f1b4Smrg */
15007117f1b4Smrgstatic void
15017117f1b4Smrgframebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
15027117f1b4Smrg                    GLenum attachment, GLenum textarget, GLuint texture,
15037117f1b4Smrg                    GLint level, GLint zoffset)
15047117f1b4Smrg{
15057117f1b4Smrg   struct gl_renderbuffer_attachment *att;
15067117f1b4Smrg   struct gl_texture_object *texObj = NULL;
15077117f1b4Smrg   struct gl_framebuffer *fb;
15084a49301eSmrg   GLboolean error = GL_FALSE;
15097117f1b4Smrg
15107117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
15117117f1b4Smrg
15124a49301eSmrg   switch (target) {
15134a49301eSmrg   case GL_READ_FRAMEBUFFER_EXT:
15144a49301eSmrg      error = !ctx->Extensions.EXT_framebuffer_blit;
15154a49301eSmrg      fb = ctx->ReadBuffer;
15164a49301eSmrg      break;
15174a49301eSmrg   case GL_DRAW_FRAMEBUFFER_EXT:
15184a49301eSmrg      error = !ctx->Extensions.EXT_framebuffer_blit;
15194a49301eSmrg      /* fall-through */
15204a49301eSmrg   case GL_FRAMEBUFFER_EXT:
15214a49301eSmrg      fb = ctx->DrawBuffer;
15224a49301eSmrg      break;
15234a49301eSmrg   default:
15244a49301eSmrg      error = GL_TRUE;
15254a49301eSmrg   }
15264a49301eSmrg
15274a49301eSmrg   if (error) {
15287117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
15294a49301eSmrg                  "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
15307117f1b4Smrg      return;
15317117f1b4Smrg   }
15327117f1b4Smrg
15337117f1b4Smrg   ASSERT(fb);
15347117f1b4Smrg
15357117f1b4Smrg   /* check framebuffer binding */
15367117f1b4Smrg   if (fb->Name == 0) {
15377117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
15387117f1b4Smrg                  "glFramebufferTexture%sEXT", caller);
15397117f1b4Smrg      return;
15407117f1b4Smrg   }
15417117f1b4Smrg
15427117f1b4Smrg
15437117f1b4Smrg   /* The textarget, level, and zoffset parameters are only validated if
15447117f1b4Smrg    * texture is non-zero.
15457117f1b4Smrg    */
15467117f1b4Smrg   if (texture) {
15477117f1b4Smrg      GLboolean err = GL_TRUE;
15487117f1b4Smrg
15497117f1b4Smrg      texObj = _mesa_lookup_texture(ctx, texture);
15507117f1b4Smrg      if (texObj != NULL) {
1551c1f859d4Smrg         if (textarget == 0) {
1552c1f859d4Smrg            err = (texObj->Target != GL_TEXTURE_3D) &&
1553c1f859d4Smrg                (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1554c1f859d4Smrg                (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1555c1f859d4Smrg         }
1556c1f859d4Smrg         else {
1557c1f859d4Smrg            err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1558c1f859d4Smrg                ? !IS_CUBE_FACE(textarget)
1559c1f859d4Smrg                : (texObj->Target != textarget);
1560c1f859d4Smrg         }
15617117f1b4Smrg      }
15627117f1b4Smrg
15637117f1b4Smrg      if (err) {
15647117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
15657117f1b4Smrg                     "glFramebufferTexture%sEXT(texture target mismatch)",
15667117f1b4Smrg                     caller);
15677117f1b4Smrg         return;
15687117f1b4Smrg      }
15697117f1b4Smrg
15707117f1b4Smrg      if (texObj->Target == GL_TEXTURE_3D) {
15717117f1b4Smrg         const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
15727117f1b4Smrg         if (zoffset < 0 || zoffset >= maxSize) {
15737117f1b4Smrg            _mesa_error(ctx, GL_INVALID_VALUE,
1574c1f859d4Smrg                        "glFramebufferTexture%sEXT(zoffset)", caller);
15757117f1b4Smrg            return;
15767117f1b4Smrg         }
15777117f1b4Smrg      }
1578c1f859d4Smrg      else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1579c1f859d4Smrg               (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1580c1f859d4Smrg         if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1581c1f859d4Smrg            _mesa_error(ctx, GL_INVALID_VALUE,
1582c1f859d4Smrg                        "glFramebufferTexture%sEXT(layer)", caller);
1583c1f859d4Smrg            return;
1584c1f859d4Smrg         }
1585c1f859d4Smrg      }
1586c1f859d4Smrg
15877117f1b4Smrg      if ((level < 0) ||
15887117f1b4Smrg          (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
15897117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
15907117f1b4Smrg                     "glFramebufferTexture%sEXT(level)", caller);
15917117f1b4Smrg         return;
15927117f1b4Smrg      }
15937117f1b4Smrg   }
15947117f1b4Smrg
15957117f1b4Smrg   att = _mesa_get_attachment(ctx, fb, attachment);
15967117f1b4Smrg   if (att == NULL) {
15977117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
15987117f1b4Smrg                  "glFramebufferTexture%sEXT(attachment)", caller);
15997117f1b4Smrg      return;
16007117f1b4Smrg   }
16017117f1b4Smrg
16027117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
16037117f1b4Smrg
16047117f1b4Smrg   _glthread_LOCK_MUTEX(fb->Mutex);
16057117f1b4Smrg   if (texObj) {
16067117f1b4Smrg      _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
16077117f1b4Smrg                                   level, zoffset);
16084a49301eSmrg      /* Set the render-to-texture flag.  We'll check this flag in
16094a49301eSmrg       * glTexImage() and friends to determine if we need to revalidate
16104a49301eSmrg       * any FBOs that might be rendering into this texture.
16114a49301eSmrg       * This flag never gets cleared since it's non-trivial to determine
16124a49301eSmrg       * when all FBOs might be done rendering to this texture.  That's OK
16134a49301eSmrg       * though since it's uncommon to render to a texture then repeatedly
16144a49301eSmrg       * call glTexImage() to change images in the texture.
16154a49301eSmrg       */
16164a49301eSmrg      texObj->_RenderToTexture = GL_TRUE;
16177117f1b4Smrg   }
16187117f1b4Smrg   else {
16197117f1b4Smrg      _mesa_remove_attachment(ctx, att);
16207117f1b4Smrg   }
16214a49301eSmrg
16224a49301eSmrg   invalidate_framebuffer(fb);
16234a49301eSmrg
16247117f1b4Smrg   _glthread_UNLOCK_MUTEX(fb->Mutex);
16257117f1b4Smrg}
16267117f1b4Smrg
16277117f1b4Smrg
16287117f1b4Smrg
16297117f1b4Smrgvoid GLAPIENTRY
16307117f1b4Smrg_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
16317117f1b4Smrg                              GLenum textarget, GLuint texture, GLint level)
16327117f1b4Smrg{
16337117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
16347117f1b4Smrg
16357117f1b4Smrg   if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
16367117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
16377117f1b4Smrg                  "glFramebufferTexture1DEXT(textarget)");
16387117f1b4Smrg      return;
16397117f1b4Smrg   }
16407117f1b4Smrg
16417117f1b4Smrg   framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
16427117f1b4Smrg                       level, 0);
16437117f1b4Smrg}
16447117f1b4Smrg
16457117f1b4Smrg
16467117f1b4Smrgvoid GLAPIENTRY
16477117f1b4Smrg_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
16487117f1b4Smrg                              GLenum textarget, GLuint texture, GLint level)
16497117f1b4Smrg{
16507117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
16517117f1b4Smrg
16527117f1b4Smrg   if ((texture != 0) &&
16537117f1b4Smrg       (textarget != GL_TEXTURE_2D) &&
16547117f1b4Smrg       (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
16557117f1b4Smrg       (!IS_CUBE_FACE(textarget))) {
16567117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
16574a49301eSmrg                  "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
16587117f1b4Smrg      return;
16597117f1b4Smrg   }
16607117f1b4Smrg
16617117f1b4Smrg   framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
16627117f1b4Smrg                       level, 0);
16637117f1b4Smrg}
16647117f1b4Smrg
16657117f1b4Smrg
16667117f1b4Smrgvoid GLAPIENTRY
16677117f1b4Smrg_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
16687117f1b4Smrg                              GLenum textarget, GLuint texture,
16697117f1b4Smrg                              GLint level, GLint zoffset)
16707117f1b4Smrg{
16717117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
16727117f1b4Smrg
16737117f1b4Smrg   if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
16747117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
16757117f1b4Smrg                  "glFramebufferTexture3DEXT(textarget)");
16767117f1b4Smrg      return;
16777117f1b4Smrg   }
16787117f1b4Smrg
16797117f1b4Smrg   framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
16807117f1b4Smrg                       level, zoffset);
16817117f1b4Smrg}
16827117f1b4Smrg
16837117f1b4Smrg
1684c1f859d4Smrgvoid GLAPIENTRY
1685c1f859d4Smrg_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1686c1f859d4Smrg                                 GLuint texture, GLint level, GLint layer)
1687c1f859d4Smrg{
1688c1f859d4Smrg   GET_CURRENT_CONTEXT(ctx);
1689c1f859d4Smrg
1690c1f859d4Smrg   framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1691c1f859d4Smrg                       level, layer);
1692c1f859d4Smrg}
1693c1f859d4Smrg
1694c1f859d4Smrg
16957117f1b4Smrgvoid GLAPIENTRY
16967117f1b4Smrg_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
16977117f1b4Smrg                                 GLenum renderbufferTarget,
16987117f1b4Smrg                                 GLuint renderbuffer)
16997117f1b4Smrg{
17007117f1b4Smrg   struct gl_renderbuffer_attachment *att;
17017117f1b4Smrg   struct gl_framebuffer *fb;
17027117f1b4Smrg   struct gl_renderbuffer *rb;
17037117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
17047117f1b4Smrg
17057117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
17067117f1b4Smrg
17077117f1b4Smrg   switch (target) {
17087117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
17097117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
17107117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
17117117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
17127117f1b4Smrg                     "glFramebufferRenderbufferEXT(target)");
17137117f1b4Smrg         return;
17147117f1b4Smrg      }
17157117f1b4Smrg      fb = ctx->DrawBuffer;
17167117f1b4Smrg      break;
17177117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
17187117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
17197117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
17207117f1b4Smrg                     "glFramebufferRenderbufferEXT(target)");
17217117f1b4Smrg         return;
17227117f1b4Smrg      }
17237117f1b4Smrg      fb = ctx->ReadBuffer;
17247117f1b4Smrg      break;
17257117f1b4Smrg#endif
17267117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
17277117f1b4Smrg      fb = ctx->DrawBuffer;
17287117f1b4Smrg      break;
17297117f1b4Smrg   default:
17307117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
17317117f1b4Smrg                  "glFramebufferRenderbufferEXT(target)");
17327117f1b4Smrg      return;
17337117f1b4Smrg   }
17347117f1b4Smrg
17357117f1b4Smrg   if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
17367117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
17377117f1b4Smrg                  "glFramebufferRenderbufferEXT(renderbufferTarget)");
17387117f1b4Smrg      return;
17397117f1b4Smrg   }
17407117f1b4Smrg
17417117f1b4Smrg   if (fb->Name == 0) {
17427117f1b4Smrg      /* Can't attach new renderbuffers to a window system framebuffer */
17437117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
17447117f1b4Smrg      return;
17457117f1b4Smrg   }
17467117f1b4Smrg
17477117f1b4Smrg   att = _mesa_get_attachment(ctx, fb, attachment);
17487117f1b4Smrg   if (att == NULL) {
17497117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
17504a49301eSmrg                  "glFramebufferRenderbufferEXT(invalid attachment %s)",
17514a49301eSmrg                  _mesa_lookup_enum_by_nr(attachment));
17527117f1b4Smrg      return;
17537117f1b4Smrg   }
17547117f1b4Smrg
17557117f1b4Smrg   if (renderbuffer) {
17567117f1b4Smrg      rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
17577117f1b4Smrg      if (!rb) {
17587117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION,
17594a49301eSmrg		     "glFramebufferRenderbufferEXT(non-existant"
17604a49301eSmrg                     " renderbuffer %u)", renderbuffer);
17617117f1b4Smrg	 return;
17627117f1b4Smrg      }
17637117f1b4Smrg   }
17647117f1b4Smrg   else {
17657117f1b4Smrg      /* remove renderbuffer attachment */
17667117f1b4Smrg      rb = NULL;
17677117f1b4Smrg   }
17687117f1b4Smrg
1769cdc920a0Smrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
1770cdc920a0Smrg       rb && rb->Format != MESA_FORMAT_NONE) {
17714a49301eSmrg      /* make sure the renderbuffer is a depth/stencil format */
1772cdc920a0Smrg      const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
17734a49301eSmrg      if (baseFormat != GL_DEPTH_STENCIL) {
17744a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
17754a49301eSmrg                     "glFramebufferRenderbufferEXT(renderbuffer"
17764a49301eSmrg                     " is not DEPTH_STENCIL format)");
17774a49301eSmrg         return;
17784a49301eSmrg      }
17794a49301eSmrg   }
17804a49301eSmrg
17814a49301eSmrg
17827117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
17837117f1b4Smrg
17847117f1b4Smrg   assert(ctx->Driver.FramebufferRenderbuffer);
17857117f1b4Smrg   ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
17867117f1b4Smrg
17877117f1b4Smrg   /* Some subsequent GL commands may depend on the framebuffer's visual
17887117f1b4Smrg    * after the binding is updated.  Update visual info now.
17897117f1b4Smrg    */
17907117f1b4Smrg   _mesa_update_framebuffer_visual(fb);
17917117f1b4Smrg}
17927117f1b4Smrg
17937117f1b4Smrg
17947117f1b4Smrgvoid GLAPIENTRY
17957117f1b4Smrg_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
17967117f1b4Smrg                                             GLenum pname, GLint *params)
17977117f1b4Smrg{
17987117f1b4Smrg   const struct gl_renderbuffer_attachment *att;
17997117f1b4Smrg   struct gl_framebuffer *buffer;
18007117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
18017117f1b4Smrg
18027117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
18037117f1b4Smrg
18047117f1b4Smrg   switch (target) {
18057117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
18067117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
18077117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
18087117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
18097117f1b4Smrg                     "glGetFramebufferAttachmentParameterivEXT(target)");
18107117f1b4Smrg         return;
18117117f1b4Smrg      }
18127117f1b4Smrg      buffer = ctx->DrawBuffer;
18137117f1b4Smrg      break;
18147117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
18157117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
18167117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
18177117f1b4Smrg                     "glGetFramebufferAttachmentParameterivEXT(target)");
18187117f1b4Smrg         return;
18197117f1b4Smrg      }
18207117f1b4Smrg      buffer = ctx->ReadBuffer;
18217117f1b4Smrg      break;
18227117f1b4Smrg#endif
18237117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
18247117f1b4Smrg      buffer = ctx->DrawBuffer;
18257117f1b4Smrg      break;
18267117f1b4Smrg   default:
18277117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
18287117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(target)");
18297117f1b4Smrg      return;
18307117f1b4Smrg   }
18317117f1b4Smrg
18327117f1b4Smrg   if (buffer->Name == 0) {
18337117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
18347117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT");
18357117f1b4Smrg      return;
18367117f1b4Smrg   }
18377117f1b4Smrg
18387117f1b4Smrg   att = _mesa_get_attachment(ctx, buffer, attachment);
18397117f1b4Smrg   if (att == NULL) {
18407117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
18417117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(attachment)");
18427117f1b4Smrg      return;
18437117f1b4Smrg   }
18447117f1b4Smrg
18454a49301eSmrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
18464a49301eSmrg      /* the depth and stencil attachments must point to the same buffer */
18474a49301eSmrg      const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
18484a49301eSmrg      depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
18494a49301eSmrg      stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
18504a49301eSmrg      if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
18514a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
18524a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
18534a49301eSmrg                     " attachments differ)");
18544a49301eSmrg         return;
18554a49301eSmrg      }
18564a49301eSmrg   }
18574a49301eSmrg
18584a49301eSmrg   /* No need to flush here */
18597117f1b4Smrg
18607117f1b4Smrg   switch (pname) {
18617117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
18627117f1b4Smrg      *params = att->Type;
18637117f1b4Smrg      return;
18647117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
18657117f1b4Smrg      if (att->Type == GL_RENDERBUFFER_EXT) {
18667117f1b4Smrg	 *params = att->Renderbuffer->Name;
18677117f1b4Smrg      }
18687117f1b4Smrg      else if (att->Type == GL_TEXTURE) {
18697117f1b4Smrg	 *params = att->Texture->Name;
18707117f1b4Smrg      }
18717117f1b4Smrg      else {
18727117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
18737117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
18747117f1b4Smrg      }
18757117f1b4Smrg      return;
18767117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
18777117f1b4Smrg      if (att->Type == GL_TEXTURE) {
18787117f1b4Smrg	 *params = att->TextureLevel;
18797117f1b4Smrg      }
18807117f1b4Smrg      else {
18817117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
18827117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
18837117f1b4Smrg      }
18847117f1b4Smrg      return;
18857117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
18867117f1b4Smrg      if (att->Type == GL_TEXTURE) {
1887c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
1888c1f859d4Smrg            *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1889c1f859d4Smrg         }
1890c1f859d4Smrg         else {
1891c1f859d4Smrg            *params = 0;
1892c1f859d4Smrg         }
18937117f1b4Smrg      }
18947117f1b4Smrg      else {
18957117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
18967117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
18977117f1b4Smrg      }
18987117f1b4Smrg      return;
18997117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
19007117f1b4Smrg      if (att->Type == GL_TEXTURE) {
1901c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
1902c1f859d4Smrg            *params = att->Zoffset;
1903c1f859d4Smrg         }
1904c1f859d4Smrg         else {
1905c1f859d4Smrg            *params = 0;
1906c1f859d4Smrg         }
19077117f1b4Smrg      }
19087117f1b4Smrg      else {
19097117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
19107117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
19117117f1b4Smrg      }
19127117f1b4Smrg      return;
19134a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
19144a49301eSmrg      if (!ctx->Extensions.ARB_framebuffer_object) {
19154a49301eSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
19164a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
19174a49301eSmrg      }
19184a49301eSmrg      else {
19194a49301eSmrg         *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
19204a49301eSmrg      }
19214a49301eSmrg      return;
19224a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
19234a49301eSmrg      if (!ctx->Extensions.ARB_framebuffer_object) {
19244a49301eSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
19254a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
19264a49301eSmrg         return;
19274a49301eSmrg      }
19284a49301eSmrg      else {
19294a49301eSmrg         gl_format format = att->Renderbuffer->Format;
19304a49301eSmrg         if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
19314a49301eSmrg            /* special cases */
19324a49301eSmrg            *params = GL_INDEX;
19334a49301eSmrg         }
19344a49301eSmrg         else {
19354a49301eSmrg            *params = _mesa_get_format_datatype(format);
19364a49301eSmrg         }
19374a49301eSmrg      }
19384a49301eSmrg      return;
19394a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
19404a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
19414a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
19424a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
19434a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
19444a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
19454a49301eSmrg      if (!ctx->Extensions.ARB_framebuffer_object) {
19464a49301eSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
19474a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
19484a49301eSmrg      }
19494a49301eSmrg      else if (att->Texture) {
19504a49301eSmrg         const struct gl_texture_image *texImage =
19514a49301eSmrg            _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
19524a49301eSmrg                                   att->TextureLevel);
19534a49301eSmrg         if (texImage) {
19544a49301eSmrg            *params = get_component_bits(pname, texImage->_BaseFormat,
19554a49301eSmrg                                         texImage->TexFormat);
19564a49301eSmrg         }
19574a49301eSmrg         else {
19584a49301eSmrg            *params = 0;
19594a49301eSmrg         }
19604a49301eSmrg      }
19614a49301eSmrg      else if (att->Renderbuffer) {
19624a49301eSmrg         *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
19634a49301eSmrg                                      att->Renderbuffer->Format);
19644a49301eSmrg      }
19654a49301eSmrg      else {
19664a49301eSmrg         *params = 0;
19674a49301eSmrg      }
19684a49301eSmrg      return;
19697117f1b4Smrg   default:
19707117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
19717117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(pname)");
19727117f1b4Smrg      return;
19737117f1b4Smrg   }
19747117f1b4Smrg}
19757117f1b4Smrg
19767117f1b4Smrg
19777117f1b4Smrgvoid GLAPIENTRY
19787117f1b4Smrg_mesa_GenerateMipmapEXT(GLenum target)
19797117f1b4Smrg{
19807117f1b4Smrg   struct gl_texture_object *texObj;
19817117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
19827117f1b4Smrg
19837117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
19847117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
19857117f1b4Smrg
19867117f1b4Smrg   switch (target) {
19877117f1b4Smrg   case GL_TEXTURE_1D:
19887117f1b4Smrg   case GL_TEXTURE_2D:
19897117f1b4Smrg   case GL_TEXTURE_3D:
19907117f1b4Smrg   case GL_TEXTURE_CUBE_MAP:
19917117f1b4Smrg      /* OK, legal value */
19927117f1b4Smrg      break;
19937117f1b4Smrg   default:
19947117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
19957117f1b4Smrg      return;
19967117f1b4Smrg   }
19977117f1b4Smrg
19984a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
19994a49301eSmrg
20004a49301eSmrg   if (texObj->BaseLevel >= texObj->MaxLevel) {
20014a49301eSmrg      /* nothing to do */
20024a49301eSmrg      return;
20034a49301eSmrg   }
20047117f1b4Smrg
20057117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
2006c1f859d4Smrg   if (target == GL_TEXTURE_CUBE_MAP) {
20074a49301eSmrg      GLuint face;
2008c1f859d4Smrg      for (face = 0; face < 6; face++)
2009c1f859d4Smrg	 ctx->Driver.GenerateMipmap(ctx,
2010c1f859d4Smrg				    GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2011c1f859d4Smrg				    texObj);
20124a49301eSmrg   }
20134a49301eSmrg   else {
2014c1f859d4Smrg      ctx->Driver.GenerateMipmap(ctx, target, texObj);
2015c1f859d4Smrg   }
20167117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
20177117f1b4Smrg}
20187117f1b4Smrg
20197117f1b4Smrg
20207117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
20214a49301eSmrg
20224a49301eSmrgstatic const struct gl_renderbuffer_attachment *
20234a49301eSmrgfind_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb)
20244a49301eSmrg{
20254a49301eSmrg   GLuint i;
20264a49301eSmrg   for (i = 0; i < Elements(fb->Attachment); i++) {
20274a49301eSmrg      if (fb->Attachment[i].Renderbuffer == rb)
20284a49301eSmrg         return &fb->Attachment[i];
20294a49301eSmrg   }
20304a49301eSmrg   return NULL;
20314a49301eSmrg}
20324a49301eSmrg
20334a49301eSmrg
20344a49301eSmrg
20354a49301eSmrg/**
20364a49301eSmrg * Blit rectangular region, optionally from one framebuffer to another.
20374a49301eSmrg *
20384a49301eSmrg * Note, if the src buffer is multisampled and the dest is not, this is
20394a49301eSmrg * when the samples must be resolved to a single color.
20404a49301eSmrg */
20417117f1b4Smrgvoid GLAPIENTRY
20427117f1b4Smrg_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
20437117f1b4Smrg                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
20447117f1b4Smrg                         GLbitfield mask, GLenum filter)
20457117f1b4Smrg{
20464a49301eSmrg   const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
20474a49301eSmrg                                     GL_DEPTH_BUFFER_BIT |
20484a49301eSmrg                                     GL_STENCIL_BUFFER_BIT);
20494a49301eSmrg   const struct gl_framebuffer *readFb, *drawFb;
20504a49301eSmrg   const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
20517117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
20527117f1b4Smrg
20537117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
20547117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
20557117f1b4Smrg
20567117f1b4Smrg   if (ctx->NewState) {
20577117f1b4Smrg      _mesa_update_state(ctx);
20587117f1b4Smrg   }
20597117f1b4Smrg
20604a49301eSmrg   readFb = ctx->ReadBuffer;
20614a49301eSmrg   drawFb = ctx->DrawBuffer;
20624a49301eSmrg
20634a49301eSmrg   if (!readFb || !drawFb) {
20644a49301eSmrg      /* This will normally never happen but someday we may want to
20654a49301eSmrg       * support MakeCurrent() with no drawables.
20664a49301eSmrg       */
20674a49301eSmrg      return;
20687117f1b4Smrg   }
20697117f1b4Smrg
20707117f1b4Smrg   /* check for complete framebuffers */
20714a49301eSmrg   if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
20724a49301eSmrg       readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
20737117f1b4Smrg      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
20747117f1b4Smrg                  "glBlitFramebufferEXT(incomplete draw/read buffers)");
20757117f1b4Smrg      return;
20767117f1b4Smrg   }
20777117f1b4Smrg
20787117f1b4Smrg   if (filter != GL_NEAREST && filter != GL_LINEAR) {
20797117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
20807117f1b4Smrg      return;
20817117f1b4Smrg   }
20827117f1b4Smrg
20834a49301eSmrg   if (mask & ~legalMaskBits) {
20847117f1b4Smrg      _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
20857117f1b4Smrg      return;
20867117f1b4Smrg   }
20877117f1b4Smrg
20887117f1b4Smrg   /* depth/stencil must be blitted with nearest filtering */
20897117f1b4Smrg   if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
20907117f1b4Smrg        && filter != GL_NEAREST) {
20917117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
20927117f1b4Smrg             "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
20937117f1b4Smrg      return;
20947117f1b4Smrg   }
20957117f1b4Smrg
20964a49301eSmrg   /* get color read/draw renderbuffers */
20974a49301eSmrg   if (mask & GL_COLOR_BUFFER_BIT) {
20984a49301eSmrg      colorReadRb = readFb->_ColorReadBuffer;
20994a49301eSmrg      colorDrawRb = drawFb->_ColorDrawBuffers[0];
21004a49301eSmrg   }
21014a49301eSmrg   else {
21024a49301eSmrg      colorReadRb = colorDrawRb = NULL;
21034a49301eSmrg   }
21044a49301eSmrg
21057117f1b4Smrg   if (mask & GL_STENCIL_BUFFER_BIT) {
21064a49301eSmrg      struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
21074a49301eSmrg      struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
21084a49301eSmrg      if (!readRb ||
21094a49301eSmrg          !drawRb ||
21104a49301eSmrg          _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
21114a49301eSmrg          _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
21127117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
21137117f1b4Smrg                     "glBlitFramebufferEXT(stencil buffer size mismatch");
21147117f1b4Smrg         return;
21157117f1b4Smrg      }
21167117f1b4Smrg   }
21177117f1b4Smrg
21187117f1b4Smrg   if (mask & GL_DEPTH_BUFFER_BIT) {
21194a49301eSmrg      struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
21204a49301eSmrg      struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
21214a49301eSmrg      if (!readRb ||
21224a49301eSmrg          !drawRb ||
21234a49301eSmrg          _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
21244a49301eSmrg          _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
21257117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
21267117f1b4Smrg                     "glBlitFramebufferEXT(depth buffer size mismatch");
21277117f1b4Smrg         return;
21287117f1b4Smrg      }
21297117f1b4Smrg   }
21307117f1b4Smrg
21314a49301eSmrg   if (readFb->Visual.samples > 0 &&
21324a49301eSmrg       drawFb->Visual.samples > 0 &&
21334a49301eSmrg       readFb->Visual.samples != drawFb->Visual.samples) {
21344a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
21354a49301eSmrg                  "glBlitFramebufferEXT(mismatched samples");
21364a49301eSmrg      return;
21374a49301eSmrg   }
21384a49301eSmrg
21394a49301eSmrg   /* extra checks for multisample copies... */
21404a49301eSmrg   if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
21414a49301eSmrg      /* src and dest region sizes must be the same */
21424a49301eSmrg      if (srcX1 - srcX0 != dstX1 - dstX0 ||
21434a49301eSmrg          srcY1 - srcY0 != dstY1 - dstY0) {
21444a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
21454a49301eSmrg                "glBlitFramebufferEXT(bad src/dst multisample region sizes");
21464a49301eSmrg         return;
21474a49301eSmrg      }
21484a49301eSmrg
21494a49301eSmrg      /* color formats must match */
21504a49301eSmrg      if (colorReadRb &&
21514a49301eSmrg          colorDrawRb &&
21524a49301eSmrg          colorReadRb->Format != colorDrawRb->Format) {
21534a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
21544a49301eSmrg                "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
21554a49301eSmrg         return;
21564a49301eSmrg      }
21574a49301eSmrg   }
21584a49301eSmrg
21597117f1b4Smrg   if (!ctx->Extensions.EXT_framebuffer_blit) {
21607117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
21617117f1b4Smrg      return;
21627117f1b4Smrg   }
21637117f1b4Smrg
21644a49301eSmrg   /* Debug code */
21654a49301eSmrg   if (DEBUG_BLIT) {
2166cdc920a0Smrg      printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
2167cdc920a0Smrg	     " 0x%x, 0x%x)\n",
2168cdc920a0Smrg	     srcX0, srcY0, srcX1, srcY1,
2169cdc920a0Smrg	     dstX0, dstY0, dstX1, dstY1,
2170cdc920a0Smrg	     mask, filter);
21714a49301eSmrg      if (colorReadRb) {
21724a49301eSmrg         const struct gl_renderbuffer_attachment *att;
21734a49301eSmrg
21744a49301eSmrg         att = find_attachment(readFb, colorReadRb);
2175cdc920a0Smrg         printf("  Src FBO %u  RB %u (%dx%d)  ",
2176cdc920a0Smrg		readFb->Name, colorReadRb->Name,
2177cdc920a0Smrg		colorReadRb->Width, colorReadRb->Height);
21784a49301eSmrg         if (att && att->Texture) {
2179cdc920a0Smrg            printf("Tex %u  tgt 0x%x  level %u  face %u",
2180cdc920a0Smrg		   att->Texture->Name,
2181cdc920a0Smrg		   att->Texture->Target,
2182cdc920a0Smrg		   att->TextureLevel,
2183cdc920a0Smrg		   att->CubeMapFace);
21844a49301eSmrg         }
2185cdc920a0Smrg         printf("\n");
21864a49301eSmrg
21874a49301eSmrg         att = find_attachment(drawFb, colorDrawRb);
2188cdc920a0Smrg         printf("  Dst FBO %u  RB %u (%dx%d)  ",
2189cdc920a0Smrg		drawFb->Name, colorDrawRb->Name,
2190cdc920a0Smrg		colorDrawRb->Width, colorDrawRb->Height);
21914a49301eSmrg         if (att && att->Texture) {
2192cdc920a0Smrg            printf("Tex %u  tgt 0x%x  level %u  face %u",
2193cdc920a0Smrg		   att->Texture->Name,
2194cdc920a0Smrg		   att->Texture->Target,
2195cdc920a0Smrg		   att->TextureLevel,
2196cdc920a0Smrg		   att->CubeMapFace);
21974a49301eSmrg         }
2198cdc920a0Smrg         printf("\n");
21994a49301eSmrg      }
22004a49301eSmrg   }
22014a49301eSmrg
22027117f1b4Smrg   ASSERT(ctx->Driver.BlitFramebuffer);
22037117f1b4Smrg   ctx->Driver.BlitFramebuffer(ctx,
22047117f1b4Smrg                               srcX0, srcY0, srcX1, srcY1,
22057117f1b4Smrg                               dstX0, dstY0, dstX1, dstY1,
22067117f1b4Smrg                               mask, filter);
22077117f1b4Smrg}
22087117f1b4Smrg#endif /* FEATURE_EXT_framebuffer_blit */
2209