fbobject.c revision 3464ebd5
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"
433464ebd5Sriastradh#include "mfeatures.h"
443464ebd5Sriastradh#include "mtypes.h"
457117f1b4Smrg#include "renderbuffer.h"
467117f1b4Smrg#include "state.h"
477117f1b4Smrg#include "teximage.h"
487117f1b4Smrg#include "texobj.h"
494a49301eSmrg
504a49301eSmrg
514a49301eSmrg/** Set this to 1 to help debug FBO incompleteness problems */
524a49301eSmrg#define DEBUG_FBO 0
534a49301eSmrg
544a49301eSmrg/** Set this to 1 to debug/log glBlitFramebuffer() calls */
554a49301eSmrg#define DEBUG_BLIT 0
567117f1b4Smrg
577117f1b4Smrg
587117f1b4Smrg/**
597117f1b4Smrg * Notes:
607117f1b4Smrg *
617117f1b4Smrg * None of the GL_EXT_framebuffer_object functions are compiled into
627117f1b4Smrg * display lists.
637117f1b4Smrg */
647117f1b4Smrg
657117f1b4Smrg
667117f1b4Smrg
677117f1b4Smrg/*
687117f1b4Smrg * When glGenRender/FramebuffersEXT() is called we insert pointers to
697117f1b4Smrg * these placeholder objects into the hash table.
707117f1b4Smrg * Later, when the object ID is first bound, we replace the placeholder
717117f1b4Smrg * with the real frame/renderbuffer.
727117f1b4Smrg */
737117f1b4Smrgstatic struct gl_framebuffer DummyFramebuffer;
747117f1b4Smrgstatic struct gl_renderbuffer DummyRenderbuffer;
757117f1b4Smrg
763464ebd5Sriastradh/* We bind this framebuffer when applications pass a NULL
773464ebd5Sriastradh * drawable/surface in make current. */
783464ebd5Sriastradhstatic struct gl_framebuffer IncompleteFramebuffer;
797117f1b4Smrg
803464ebd5Sriastradh
813464ebd5Sriastradhstatic INLINE GLboolean
823464ebd5Sriastradhis_cube_face(GLenum target)
833464ebd5Sriastradh{
843464ebd5Sriastradh   return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
853464ebd5Sriastradh           target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
863464ebd5Sriastradh}
873464ebd5Sriastradh
883464ebd5Sriastradh
893464ebd5Sriastradh/**
903464ebd5Sriastradh * Is the given FBO a user-created FBO?
913464ebd5Sriastradh */
923464ebd5Sriastradhstatic INLINE GLboolean
933464ebd5Sriastradhis_user_fbo(const struct gl_framebuffer *fb)
943464ebd5Sriastradh{
953464ebd5Sriastradh   return fb->Name != 0;
963464ebd5Sriastradh}
973464ebd5Sriastradh
983464ebd5Sriastradh
993464ebd5Sriastradh/**
1003464ebd5Sriastradh * Is the given FBO a window system FBO (like an X window)?
1013464ebd5Sriastradh */
1023464ebd5Sriastradhstatic INLINE GLboolean
1033464ebd5Sriastradhis_winsys_fbo(const struct gl_framebuffer *fb)
1043464ebd5Sriastradh{
1053464ebd5Sriastradh   return fb->Name == 0;
1063464ebd5Sriastradh}
1077117f1b4Smrg
1087117f1b4Smrg
109c1f859d4Smrgstatic void
110c1f859d4Smrgdelete_dummy_renderbuffer(struct gl_renderbuffer *rb)
111c1f859d4Smrg{
112c1f859d4Smrg   /* no op */
113c1f859d4Smrg}
114c1f859d4Smrg
115c1f859d4Smrgstatic void
116c1f859d4Smrgdelete_dummy_framebuffer(struct gl_framebuffer *fb)
117c1f859d4Smrg{
118c1f859d4Smrg   /* no op */
119c1f859d4Smrg}
120c1f859d4Smrg
121c1f859d4Smrg
122c1f859d4Smrgvoid
1233464ebd5Sriastradh_mesa_init_fbobjects(struct gl_context *ctx)
124c1f859d4Smrg{
1253464ebd5Sriastradh   _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
1263464ebd5Sriastradh   _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
1273464ebd5Sriastradh   _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex);
128c1f859d4Smrg   DummyFramebuffer.Delete = delete_dummy_framebuffer;
129c1f859d4Smrg   DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
1303464ebd5Sriastradh   IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
131c1f859d4Smrg}
132c1f859d4Smrg
1333464ebd5Sriastradhstruct gl_framebuffer *
1343464ebd5Sriastradh_mesa_get_incomplete_framebuffer(void)
1353464ebd5Sriastradh{
1363464ebd5Sriastradh   return &IncompleteFramebuffer;
1373464ebd5Sriastradh}
138c1f859d4Smrg
1397117f1b4Smrg/**
1407117f1b4Smrg * Helper routine for getting a gl_renderbuffer.
1417117f1b4Smrg */
1427117f1b4Smrgstruct gl_renderbuffer *
1433464ebd5Sriastradh_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
1447117f1b4Smrg{
1457117f1b4Smrg   struct gl_renderbuffer *rb;
1467117f1b4Smrg
1477117f1b4Smrg   if (id == 0)
1487117f1b4Smrg      return NULL;
1497117f1b4Smrg
1507117f1b4Smrg   rb = (struct gl_renderbuffer *)
1517117f1b4Smrg      _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
1527117f1b4Smrg   return rb;
1537117f1b4Smrg}
1547117f1b4Smrg
1557117f1b4Smrg
1567117f1b4Smrg/**
1577117f1b4Smrg * Helper routine for getting a gl_framebuffer.
1587117f1b4Smrg */
1597117f1b4Smrgstruct gl_framebuffer *
1603464ebd5Sriastradh_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
1617117f1b4Smrg{
1627117f1b4Smrg   struct gl_framebuffer *fb;
1637117f1b4Smrg
1647117f1b4Smrg   if (id == 0)
1657117f1b4Smrg      return NULL;
1667117f1b4Smrg
1677117f1b4Smrg   fb = (struct gl_framebuffer *)
1687117f1b4Smrg      _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
1697117f1b4Smrg   return fb;
1707117f1b4Smrg}
1717117f1b4Smrg
1727117f1b4Smrg
1734a49301eSmrg/**
1744a49301eSmrg * Mark the given framebuffer as invalid.  This will force the
1754a49301eSmrg * test for framebuffer completeness to be done before the framebuffer
1764a49301eSmrg * is used.
1774a49301eSmrg */
1784a49301eSmrgstatic void
1794a49301eSmrginvalidate_framebuffer(struct gl_framebuffer *fb)
1804a49301eSmrg{
1814a49301eSmrg   fb->_Status = 0; /* "indeterminate" */
1824a49301eSmrg}
1834a49301eSmrg
1844a49301eSmrg
1853464ebd5Sriastradh/**
1863464ebd5Sriastradh * Return the gl_framebuffer object which corresponds to the given
1873464ebd5Sriastradh * framebuffer target, such as GL_DRAW_FRAMEBUFFER.
1883464ebd5Sriastradh * Check support for GL_EXT_framebuffer_blit to determine if certain
1893464ebd5Sriastradh * targets are legal.
1903464ebd5Sriastradh * \return gl_framebuffer pointer or NULL if target is illegal
1913464ebd5Sriastradh */
1923464ebd5Sriastradhstatic struct gl_framebuffer *
1933464ebd5Sriastradhget_framebuffer_target(struct gl_context *ctx, GLenum target)
1943464ebd5Sriastradh{
1953464ebd5Sriastradh   switch (target) {
1963464ebd5Sriastradh   case GL_DRAW_FRAMEBUFFER:
1973464ebd5Sriastradh      return ctx->Extensions.EXT_framebuffer_blit ? ctx->DrawBuffer : NULL;
1983464ebd5Sriastradh   case GL_READ_FRAMEBUFFER:
1993464ebd5Sriastradh      return ctx->Extensions.EXT_framebuffer_blit ? ctx->ReadBuffer : NULL;
2003464ebd5Sriastradh   case GL_FRAMEBUFFER_EXT:
2013464ebd5Sriastradh      return ctx->DrawBuffer;
2023464ebd5Sriastradh   default:
2033464ebd5Sriastradh      return NULL;
2043464ebd5Sriastradh   }
2053464ebd5Sriastradh}
2063464ebd5Sriastradh
2073464ebd5Sriastradh
2087117f1b4Smrg/**
2097117f1b4Smrg * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
2107117f1b4Smrg * gl_renderbuffer_attachment object.
2113464ebd5Sriastradh * This function is only used for user-created FB objects, not the
2123464ebd5Sriastradh * default / window-system FB object.
2134a49301eSmrg * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
2144a49301eSmrg * the depth buffer attachment point.
2157117f1b4Smrg */
2167117f1b4Smrgstruct gl_renderbuffer_attachment *
2173464ebd5Sriastradh_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
2187117f1b4Smrg                     GLenum attachment)
2197117f1b4Smrg{
2207117f1b4Smrg   GLuint i;
2217117f1b4Smrg
2223464ebd5Sriastradh   assert(is_user_fbo(fb));
2233464ebd5Sriastradh
2247117f1b4Smrg   switch (attachment) {
2257117f1b4Smrg   case GL_COLOR_ATTACHMENT0_EXT:
2267117f1b4Smrg   case GL_COLOR_ATTACHMENT1_EXT:
2277117f1b4Smrg   case GL_COLOR_ATTACHMENT2_EXT:
2287117f1b4Smrg   case GL_COLOR_ATTACHMENT3_EXT:
2297117f1b4Smrg   case GL_COLOR_ATTACHMENT4_EXT:
2307117f1b4Smrg   case GL_COLOR_ATTACHMENT5_EXT:
2317117f1b4Smrg   case GL_COLOR_ATTACHMENT6_EXT:
2327117f1b4Smrg   case GL_COLOR_ATTACHMENT7_EXT:
2337117f1b4Smrg   case GL_COLOR_ATTACHMENT8_EXT:
2347117f1b4Smrg   case GL_COLOR_ATTACHMENT9_EXT:
2357117f1b4Smrg   case GL_COLOR_ATTACHMENT10_EXT:
2367117f1b4Smrg   case GL_COLOR_ATTACHMENT11_EXT:
2377117f1b4Smrg   case GL_COLOR_ATTACHMENT12_EXT:
2387117f1b4Smrg   case GL_COLOR_ATTACHMENT13_EXT:
2397117f1b4Smrg   case GL_COLOR_ATTACHMENT14_EXT:
2407117f1b4Smrg   case GL_COLOR_ATTACHMENT15_EXT:
2417117f1b4Smrg      i = attachment - GL_COLOR_ATTACHMENT0_EXT;
2427117f1b4Smrg      if (i >= ctx->Const.MaxColorAttachments) {
2437117f1b4Smrg	 return NULL;
2447117f1b4Smrg      }
2457117f1b4Smrg      return &fb->Attachment[BUFFER_COLOR0 + i];
2464a49301eSmrg   case GL_DEPTH_STENCIL_ATTACHMENT:
2474a49301eSmrg      /* fall-through */
2483464ebd5Sriastradh   case GL_DEPTH_BUFFER:
2493464ebd5Sriastradh      /* fall-through / new in GL 3.0 */
2507117f1b4Smrg   case GL_DEPTH_ATTACHMENT_EXT:
2517117f1b4Smrg      return &fb->Attachment[BUFFER_DEPTH];
2523464ebd5Sriastradh   case GL_STENCIL_BUFFER:
2533464ebd5Sriastradh      /* fall-through / new in GL 3.0 */
2547117f1b4Smrg   case GL_STENCIL_ATTACHMENT_EXT:
2557117f1b4Smrg      return &fb->Attachment[BUFFER_STENCIL];
2567117f1b4Smrg   default:
2577117f1b4Smrg      return NULL;
2587117f1b4Smrg   }
2597117f1b4Smrg}
2607117f1b4Smrg
2617117f1b4Smrg
2623464ebd5Sriastradh/**
2633464ebd5Sriastradh * As above, but only used for getting attachments of the default /
2643464ebd5Sriastradh * window-system framebuffer (not user-created framebuffer objects).
2653464ebd5Sriastradh */
2663464ebd5Sriastradhstatic struct gl_renderbuffer_attachment *
2673464ebd5Sriastradh_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
2683464ebd5Sriastradh                         GLenum attachment)
2693464ebd5Sriastradh{
2703464ebd5Sriastradh   assert(is_winsys_fbo(fb));
2713464ebd5Sriastradh
2723464ebd5Sriastradh   switch (attachment) {
2733464ebd5Sriastradh   case GL_FRONT_LEFT:
2743464ebd5Sriastradh      return &fb->Attachment[BUFFER_FRONT_LEFT];
2753464ebd5Sriastradh   case GL_FRONT_RIGHT:
2763464ebd5Sriastradh      return &fb->Attachment[BUFFER_FRONT_RIGHT];
2773464ebd5Sriastradh   case GL_BACK_LEFT:
2783464ebd5Sriastradh      return &fb->Attachment[BUFFER_BACK_LEFT];
2793464ebd5Sriastradh   case GL_BACK_RIGHT:
2803464ebd5Sriastradh      return &fb->Attachment[BUFFER_BACK_RIGHT];
2813464ebd5Sriastradh   case GL_AUX0:
2823464ebd5Sriastradh      if (fb->Visual.numAuxBuffers == 1) {
2833464ebd5Sriastradh         return &fb->Attachment[BUFFER_AUX0];
2843464ebd5Sriastradh      }
2853464ebd5Sriastradh      return NULL;
2863464ebd5Sriastradh   case GL_DEPTH_BUFFER:
2873464ebd5Sriastradh      /* fall-through / new in GL 3.0 */
2883464ebd5Sriastradh   case GL_DEPTH_ATTACHMENT_EXT:
2893464ebd5Sriastradh      return &fb->Attachment[BUFFER_DEPTH];
2903464ebd5Sriastradh   case GL_STENCIL_BUFFER:
2913464ebd5Sriastradh      /* fall-through / new in GL 3.0 */
2923464ebd5Sriastradh   case GL_STENCIL_ATTACHMENT_EXT:
2933464ebd5Sriastradh      return &fb->Attachment[BUFFER_STENCIL];
2943464ebd5Sriastradh   default:
2953464ebd5Sriastradh      return NULL;
2963464ebd5Sriastradh   }
2973464ebd5Sriastradh}
2983464ebd5Sriastradh
2993464ebd5Sriastradh
3003464ebd5Sriastradh
3017117f1b4Smrg/**
3027117f1b4Smrg * Remove any texture or renderbuffer attached to the given attachment
3037117f1b4Smrg * point.  Update reference counts, etc.
3047117f1b4Smrg */
3057117f1b4Smrgvoid
3063464ebd5Sriastradh_mesa_remove_attachment(struct gl_context *ctx,
3073464ebd5Sriastradh                        struct gl_renderbuffer_attachment *att)
3087117f1b4Smrg{
3097117f1b4Smrg   if (att->Type == GL_TEXTURE) {
3107117f1b4Smrg      ASSERT(att->Texture);
3117117f1b4Smrg      if (ctx->Driver.FinishRenderTexture) {
3124a49301eSmrg         /* tell driver that we're done rendering to this texture. */
3137117f1b4Smrg         ctx->Driver.FinishRenderTexture(ctx, att);
3147117f1b4Smrg      }
3157117f1b4Smrg      _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
3167117f1b4Smrg      ASSERT(!att->Texture);
3177117f1b4Smrg   }
3187117f1b4Smrg   if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
3197117f1b4Smrg      ASSERT(!att->Texture);
3207117f1b4Smrg      _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
3217117f1b4Smrg      ASSERT(!att->Renderbuffer);
3227117f1b4Smrg   }
3237117f1b4Smrg   att->Type = GL_NONE;
3247117f1b4Smrg   att->Complete = GL_TRUE;
3257117f1b4Smrg}
3267117f1b4Smrg
3277117f1b4Smrg
3287117f1b4Smrg/**
3297117f1b4Smrg * Bind a texture object to an attachment point.
3307117f1b4Smrg * The previous binding, if any, will be removed first.
3317117f1b4Smrg */
3327117f1b4Smrgvoid
3333464ebd5Sriastradh_mesa_set_texture_attachment(struct gl_context *ctx,
3347117f1b4Smrg                             struct gl_framebuffer *fb,
3357117f1b4Smrg                             struct gl_renderbuffer_attachment *att,
3367117f1b4Smrg                             struct gl_texture_object *texObj,
3377117f1b4Smrg                             GLenum texTarget, GLuint level, GLuint zoffset)
3387117f1b4Smrg{
3397117f1b4Smrg   if (att->Texture == texObj) {
3407117f1b4Smrg      /* re-attaching same texture */
3417117f1b4Smrg      ASSERT(att->Type == GL_TEXTURE);
3424a49301eSmrg      if (ctx->Driver.FinishRenderTexture)
3434a49301eSmrg	 ctx->Driver.FinishRenderTexture(ctx, att);
3447117f1b4Smrg   }
3457117f1b4Smrg   else {
3467117f1b4Smrg      /* new attachment */
3474a49301eSmrg      if (ctx->Driver.FinishRenderTexture && att->Texture)
3484a49301eSmrg	 ctx->Driver.FinishRenderTexture(ctx, att);
3497117f1b4Smrg      _mesa_remove_attachment(ctx, att);
3507117f1b4Smrg      att->Type = GL_TEXTURE;
3517117f1b4Smrg      assert(!att->Texture);
3527117f1b4Smrg      _mesa_reference_texobj(&att->Texture, texObj);
3537117f1b4Smrg   }
3547117f1b4Smrg
3557117f1b4Smrg   /* always update these fields */
3567117f1b4Smrg   att->TextureLevel = level;
3574a49301eSmrg   att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
3587117f1b4Smrg   att->Zoffset = zoffset;
3597117f1b4Smrg   att->Complete = GL_FALSE;
3607117f1b4Smrg
3613464ebd5Sriastradh   if (_mesa_get_attachment_teximage(att)) {
3627117f1b4Smrg      ctx->Driver.RenderTexture(ctx, fb, att);
3637117f1b4Smrg   }
3644a49301eSmrg
3654a49301eSmrg   invalidate_framebuffer(fb);
3667117f1b4Smrg}
3677117f1b4Smrg
3687117f1b4Smrg
3697117f1b4Smrg/**
3707117f1b4Smrg * Bind a renderbuffer to an attachment point.
3717117f1b4Smrg * The previous binding, if any, will be removed first.
3727117f1b4Smrg */
3737117f1b4Smrgvoid
3743464ebd5Sriastradh_mesa_set_renderbuffer_attachment(struct gl_context *ctx,
3757117f1b4Smrg                                  struct gl_renderbuffer_attachment *att,
3767117f1b4Smrg                                  struct gl_renderbuffer *rb)
3777117f1b4Smrg{
3787117f1b4Smrg   /* XXX check if re-doing same attachment, exit early */
3797117f1b4Smrg   _mesa_remove_attachment(ctx, att);
3807117f1b4Smrg   att->Type = GL_RENDERBUFFER_EXT;
3817117f1b4Smrg   att->Texture = NULL; /* just to be safe */
3827117f1b4Smrg   att->Complete = GL_FALSE;
3837117f1b4Smrg   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
3847117f1b4Smrg}
3857117f1b4Smrg
3867117f1b4Smrg
3877117f1b4Smrg/**
3887117f1b4Smrg * Fallback for ctx->Driver.FramebufferRenderbuffer()
3897117f1b4Smrg * Attach a renderbuffer object to a framebuffer object.
3907117f1b4Smrg */
3917117f1b4Smrgvoid
3923464ebd5Sriastradh_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
3933464ebd5Sriastradh                               struct gl_framebuffer *fb,
3947117f1b4Smrg                               GLenum attachment, struct gl_renderbuffer *rb)
3957117f1b4Smrg{
3967117f1b4Smrg   struct gl_renderbuffer_attachment *att;
3977117f1b4Smrg
3987117f1b4Smrg   _glthread_LOCK_MUTEX(fb->Mutex);
3997117f1b4Smrg
4007117f1b4Smrg   att = _mesa_get_attachment(ctx, fb, attachment);
4017117f1b4Smrg   ASSERT(att);
4027117f1b4Smrg   if (rb) {
4037117f1b4Smrg      _mesa_set_renderbuffer_attachment(ctx, att, rb);
4044a49301eSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
4054a49301eSmrg         /* do stencil attachment here (depth already done above) */
4064a49301eSmrg         att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
4074a49301eSmrg         assert(att);
4084a49301eSmrg         _mesa_set_renderbuffer_attachment(ctx, att, rb);
4094a49301eSmrg      }
4103464ebd5Sriastradh      rb->AttachedAnytime = GL_TRUE;
4117117f1b4Smrg   }
4127117f1b4Smrg   else {
4137117f1b4Smrg      _mesa_remove_attachment(ctx, att);
4147117f1b4Smrg   }
4157117f1b4Smrg
4164a49301eSmrg   invalidate_framebuffer(fb);
4174a49301eSmrg
4187117f1b4Smrg   _glthread_UNLOCK_MUTEX(fb->Mutex);
4197117f1b4Smrg}
4207117f1b4Smrg
4217117f1b4Smrg
4223464ebd5Sriastradh/**
4233464ebd5Sriastradh * Fallback for ctx->Driver.ValidateFramebuffer()
4243464ebd5Sriastradh * Check if the renderbuffer's formats are supported by the software
4253464ebd5Sriastradh * renderer.
4263464ebd5Sriastradh * Drivers should probably override this.
4273464ebd5Sriastradh */
4283464ebd5Sriastradhvoid
4293464ebd5Sriastradh_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
4303464ebd5Sriastradh{
4313464ebd5Sriastradh   gl_buffer_index buf;
4323464ebd5Sriastradh   for (buf = 0; buf < BUFFER_COUNT; buf++) {
4333464ebd5Sriastradh      const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer;
4343464ebd5Sriastradh      if (rb) {
4353464ebd5Sriastradh         switch (rb->_BaseFormat) {
4363464ebd5Sriastradh         case GL_ALPHA:
4373464ebd5Sriastradh         case GL_LUMINANCE_ALPHA:
4383464ebd5Sriastradh         case GL_LUMINANCE:
4393464ebd5Sriastradh         case GL_INTENSITY:
4403464ebd5Sriastradh         case GL_RED:
4413464ebd5Sriastradh         case GL_RG:
4423464ebd5Sriastradh            fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
4433464ebd5Sriastradh            return;
4443464ebd5Sriastradh
4453464ebd5Sriastradh         default:
4463464ebd5Sriastradh            switch (rb->Format) {
4473464ebd5Sriastradh            /* XXX This list is likely incomplete. */
4483464ebd5Sriastradh            case MESA_FORMAT_RGB9_E5_FLOAT:
4493464ebd5Sriastradh               fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
4503464ebd5Sriastradh               return;
4513464ebd5Sriastradh            default:;
4523464ebd5Sriastradh               /* render buffer format is supported by software rendering */
4533464ebd5Sriastradh            }
4543464ebd5Sriastradh         }
4553464ebd5Sriastradh      }
4563464ebd5Sriastradh   }
4573464ebd5Sriastradh}
4583464ebd5Sriastradh
4593464ebd5Sriastradh
4604a49301eSmrg/**
4614a49301eSmrg * For debug only.
4624a49301eSmrg */
4634a49301eSmrgstatic void
4644a49301eSmrgatt_incomplete(const char *msg)
4654a49301eSmrg{
4664a49301eSmrg#if DEBUG_FBO
4674a49301eSmrg   _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
4684a49301eSmrg#else
4694a49301eSmrg   (void) msg;
4704a49301eSmrg#endif
4714a49301eSmrg}
4724a49301eSmrg
4734a49301eSmrg
4744a49301eSmrg/**
4754a49301eSmrg * For debug only.
4764a49301eSmrg */
4774a49301eSmrgstatic void
4784a49301eSmrgfbo_incomplete(const char *msg, int index)
4794a49301eSmrg{
4804a49301eSmrg#if DEBUG_FBO
4814a49301eSmrg   _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
4824a49301eSmrg#else
4834a49301eSmrg   (void) msg;
4844a49301eSmrg   (void) index;
4854a49301eSmrg#endif
4864a49301eSmrg}
4874a49301eSmrg
4884a49301eSmrg
4893464ebd5Sriastradh/**
4903464ebd5Sriastradh * Is the given base format a legal format for a color renderbuffer?
4913464ebd5Sriastradh */
4923464ebd5SriastradhGLboolean
4933464ebd5Sriastradh_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
4943464ebd5Sriastradh{
4953464ebd5Sriastradh   switch (baseFormat) {
4963464ebd5Sriastradh   case GL_RGB:
4973464ebd5Sriastradh   case GL_RGBA:
4983464ebd5Sriastradh      return GL_TRUE;
4993464ebd5Sriastradh   case GL_LUMINANCE:
5003464ebd5Sriastradh   case GL_LUMINANCE_ALPHA:
5013464ebd5Sriastradh   case GL_INTENSITY:
5023464ebd5Sriastradh   case GL_ALPHA:
5033464ebd5Sriastradh      return ctx->Extensions.ARB_framebuffer_object;
5043464ebd5Sriastradh   case GL_RED:
5053464ebd5Sriastradh   case GL_RG:
5063464ebd5Sriastradh      return ctx->Extensions.ARB_texture_rg;
5073464ebd5Sriastradh   default:
5083464ebd5Sriastradh      return GL_FALSE;
5093464ebd5Sriastradh   }
5103464ebd5Sriastradh}
5113464ebd5Sriastradh
5123464ebd5Sriastradh
5133464ebd5Sriastradh/**
5143464ebd5Sriastradh * Is the given base format a legal format for a depth/stencil renderbuffer?
5153464ebd5Sriastradh */
5163464ebd5Sriastradhstatic GLboolean
5173464ebd5Sriastradhis_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
5183464ebd5Sriastradh{
5193464ebd5Sriastradh   switch (baseFormat) {
5203464ebd5Sriastradh   case GL_DEPTH_COMPONENT:
5213464ebd5Sriastradh   case GL_DEPTH_STENCIL_EXT:
5223464ebd5Sriastradh      return GL_TRUE;
5233464ebd5Sriastradh   default:
5243464ebd5Sriastradh      return GL_FALSE;
5253464ebd5Sriastradh   }
5263464ebd5Sriastradh}
5274a49301eSmrg
5284a49301eSmrg
5297117f1b4Smrg/**
5307117f1b4Smrg * Test if an attachment point is complete and update its Complete field.
5317117f1b4Smrg * \param format if GL_COLOR, this is a color attachment point,
5327117f1b4Smrg *               if GL_DEPTH, this is a depth component attachment point,
5337117f1b4Smrg *               if GL_STENCIL, this is a stencil component attachment point.
5347117f1b4Smrg */
5357117f1b4Smrgstatic void
5363464ebd5Sriastradhtest_attachment_completeness(const struct gl_context *ctx, GLenum format,
5377117f1b4Smrg                             struct gl_renderbuffer_attachment *att)
5387117f1b4Smrg{
5397117f1b4Smrg   assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
5407117f1b4Smrg
5417117f1b4Smrg   /* assume complete */
5427117f1b4Smrg   att->Complete = GL_TRUE;
5437117f1b4Smrg
5447117f1b4Smrg   /* Look for reasons why the attachment might be incomplete */
5457117f1b4Smrg   if (att->Type == GL_TEXTURE) {
5467117f1b4Smrg      const struct gl_texture_object *texObj = att->Texture;
5477117f1b4Smrg      struct gl_texture_image *texImage;
5484a49301eSmrg      GLenum baseFormat;
5497117f1b4Smrg
5507117f1b4Smrg      if (!texObj) {
5514a49301eSmrg         att_incomplete("no texobj");
5527117f1b4Smrg         att->Complete = GL_FALSE;
5537117f1b4Smrg         return;
5547117f1b4Smrg      }
5557117f1b4Smrg
5567117f1b4Smrg      texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
5577117f1b4Smrg      if (!texImage) {
5584a49301eSmrg         att_incomplete("no teximage");
5597117f1b4Smrg         att->Complete = GL_FALSE;
5607117f1b4Smrg         return;
5617117f1b4Smrg      }
5627117f1b4Smrg      if (texImage->Width < 1 || texImage->Height < 1) {
5634a49301eSmrg         att_incomplete("teximage width/height=0");
564cdc920a0Smrg         printf("texobj = %u\n", texObj->Name);
565cdc920a0Smrg         printf("level = %d\n", att->TextureLevel);
5667117f1b4Smrg         att->Complete = GL_FALSE;
5677117f1b4Smrg         return;
5687117f1b4Smrg      }
5697117f1b4Smrg      if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
5704a49301eSmrg         att_incomplete("bad z offset");
5717117f1b4Smrg         att->Complete = GL_FALSE;
5727117f1b4Smrg         return;
5737117f1b4Smrg      }
5747117f1b4Smrg
5754a49301eSmrg      baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
5764a49301eSmrg
5777117f1b4Smrg      if (format == GL_COLOR) {
5783464ebd5Sriastradh         if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
5794a49301eSmrg            att_incomplete("bad format");
5804a49301eSmrg            att->Complete = GL_FALSE;
5814a49301eSmrg            return;
5824a49301eSmrg         }
5834a49301eSmrg         if (_mesa_is_format_compressed(texImage->TexFormat)) {
5844a49301eSmrg            att_incomplete("compressed internalformat");
5857117f1b4Smrg            att->Complete = GL_FALSE;
5867117f1b4Smrg            return;
5877117f1b4Smrg         }
5887117f1b4Smrg      }
5897117f1b4Smrg      else if (format == GL_DEPTH) {
5904a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
5917117f1b4Smrg            /* OK */
5927117f1b4Smrg         }
5937117f1b4Smrg         else if (ctx->Extensions.EXT_packed_depth_stencil &&
594c7037ccdSmrg                  ctx->Extensions.ARB_depth_texture &&
5954a49301eSmrg                  baseFormat == GL_DEPTH_STENCIL_EXT) {
5967117f1b4Smrg            /* OK */
5977117f1b4Smrg         }
5987117f1b4Smrg         else {
5997117f1b4Smrg            att->Complete = GL_FALSE;
6004a49301eSmrg            att_incomplete("bad depth format");
6017117f1b4Smrg            return;
6027117f1b4Smrg         }
6037117f1b4Smrg      }
6047117f1b4Smrg      else {
605c7037ccdSmrg         ASSERT(format == GL_STENCIL);
606c7037ccdSmrg         if (ctx->Extensions.EXT_packed_depth_stencil &&
607c7037ccdSmrg             ctx->Extensions.ARB_depth_texture &&
6084a49301eSmrg             baseFormat == GL_DEPTH_STENCIL_EXT) {
609c7037ccdSmrg            /* OK */
610c7037ccdSmrg         }
611c7037ccdSmrg         else {
612c7037ccdSmrg            /* no such thing as stencil-only textures */
6134a49301eSmrg            att_incomplete("illegal stencil texture");
614c7037ccdSmrg            att->Complete = GL_FALSE;
615c7037ccdSmrg            return;
616c7037ccdSmrg         }
6177117f1b4Smrg      }
6187117f1b4Smrg   }
6197117f1b4Smrg   else if (att->Type == GL_RENDERBUFFER_EXT) {
6204a49301eSmrg      const GLenum baseFormat =
6214a49301eSmrg         _mesa_get_format_base_format(att->Renderbuffer->Format);
6224a49301eSmrg
6237117f1b4Smrg      ASSERT(att->Renderbuffer);
6247117f1b4Smrg      if (!att->Renderbuffer->InternalFormat ||
6257117f1b4Smrg          att->Renderbuffer->Width < 1 ||
6267117f1b4Smrg          att->Renderbuffer->Height < 1) {
6274a49301eSmrg         att_incomplete("0x0 renderbuffer");
6287117f1b4Smrg         att->Complete = GL_FALSE;
6297117f1b4Smrg         return;
6307117f1b4Smrg      }
6317117f1b4Smrg      if (format == GL_COLOR) {
6323464ebd5Sriastradh         if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
6334a49301eSmrg            att_incomplete("bad renderbuffer color format");
6347117f1b4Smrg            att->Complete = GL_FALSE;
6357117f1b4Smrg            return;
6367117f1b4Smrg         }
6377117f1b4Smrg      }
6387117f1b4Smrg      else if (format == GL_DEPTH) {
6394a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
6407117f1b4Smrg            /* OK */
6417117f1b4Smrg         }
6427117f1b4Smrg         else if (ctx->Extensions.EXT_packed_depth_stencil &&
6434a49301eSmrg                  baseFormat == GL_DEPTH_STENCIL_EXT) {
6447117f1b4Smrg            /* OK */
6457117f1b4Smrg         }
6467117f1b4Smrg         else {
6474a49301eSmrg            att_incomplete("bad renderbuffer depth format");
6487117f1b4Smrg            att->Complete = GL_FALSE;
6497117f1b4Smrg            return;
6507117f1b4Smrg         }
6517117f1b4Smrg      }
6527117f1b4Smrg      else {
6537117f1b4Smrg         assert(format == GL_STENCIL);
6544a49301eSmrg         if (baseFormat == GL_STENCIL_INDEX) {
6557117f1b4Smrg            /* OK */
6567117f1b4Smrg         }
6577117f1b4Smrg         else if (ctx->Extensions.EXT_packed_depth_stencil &&
6584a49301eSmrg                  baseFormat == GL_DEPTH_STENCIL_EXT) {
6597117f1b4Smrg            /* OK */
6607117f1b4Smrg         }
6617117f1b4Smrg         else {
6627117f1b4Smrg            att->Complete = GL_FALSE;
6634a49301eSmrg            att_incomplete("bad renderbuffer stencil format");
6647117f1b4Smrg            return;
6657117f1b4Smrg         }
6667117f1b4Smrg      }
6677117f1b4Smrg   }
6687117f1b4Smrg   else {
6697117f1b4Smrg      ASSERT(att->Type == GL_NONE);
6707117f1b4Smrg      /* complete */
6717117f1b4Smrg      return;
6727117f1b4Smrg   }
6737117f1b4Smrg}
6747117f1b4Smrg
6757117f1b4Smrg
6767117f1b4Smrg/**
6777117f1b4Smrg * Test if the given framebuffer object is complete and update its
6787117f1b4Smrg * Status field with the results.
6794a49301eSmrg * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
6804a49301eSmrg * driver to make hardware-specific validation/completeness checks.
6817117f1b4Smrg * Also update the framebuffer's Width and Height fields if the
6827117f1b4Smrg * framebuffer is complete.
6837117f1b4Smrg */
6847117f1b4Smrgvoid
6853464ebd5Sriastradh_mesa_test_framebuffer_completeness(struct gl_context *ctx,
6863464ebd5Sriastradh                                    struct gl_framebuffer *fb)
6877117f1b4Smrg{
6884a49301eSmrg   GLuint numImages;
6894a49301eSmrg   GLenum intFormat = GL_NONE; /* color buffers' internal format */
6904a49301eSmrg   GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
6914a49301eSmrg   GLint numSamples = -1;
6927117f1b4Smrg   GLint i;
6937117f1b4Smrg   GLuint j;
6947117f1b4Smrg
6953464ebd5Sriastradh   assert(is_user_fbo(fb));
6967117f1b4Smrg
6977117f1b4Smrg   numImages = 0;
6987117f1b4Smrg   fb->Width = 0;
6997117f1b4Smrg   fb->Height = 0;
7007117f1b4Smrg
7014a49301eSmrg   /* Start at -2 to more easily loop over all attachment points.
7024a49301eSmrg    *  -2: depth buffer
7034a49301eSmrg    *  -1: stencil buffer
7044a49301eSmrg    * >=0: color buffer
7054a49301eSmrg    */
7067117f1b4Smrg   for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
7077117f1b4Smrg      struct gl_renderbuffer_attachment *att;
7087117f1b4Smrg      GLenum f;
7093464ebd5Sriastradh      gl_format attFormat;
7107117f1b4Smrg
7114a49301eSmrg      /*
7124a49301eSmrg       * XXX for ARB_fbo, only check color buffers that are named by
7134a49301eSmrg       * GL_READ_BUFFER and GL_DRAW_BUFFERi.
7144a49301eSmrg       */
7154a49301eSmrg
7164a49301eSmrg      /* check for attachment completeness
7174a49301eSmrg       */
7187117f1b4Smrg      if (i == -2) {
7197117f1b4Smrg         att = &fb->Attachment[BUFFER_DEPTH];
7207117f1b4Smrg         test_attachment_completeness(ctx, GL_DEPTH, att);
7217117f1b4Smrg         if (!att->Complete) {
7227117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
7237117f1b4Smrg            fbo_incomplete("depth attachment incomplete", -1);
7247117f1b4Smrg            return;
7257117f1b4Smrg         }
7267117f1b4Smrg      }
7277117f1b4Smrg      else if (i == -1) {
7287117f1b4Smrg         att = &fb->Attachment[BUFFER_STENCIL];
7297117f1b4Smrg         test_attachment_completeness(ctx, GL_STENCIL, att);
7307117f1b4Smrg         if (!att->Complete) {
7317117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
7327117f1b4Smrg            fbo_incomplete("stencil attachment incomplete", -1);
7337117f1b4Smrg            return;
7347117f1b4Smrg         }
7357117f1b4Smrg      }
7367117f1b4Smrg      else {
7377117f1b4Smrg         att = &fb->Attachment[BUFFER_COLOR0 + i];
7387117f1b4Smrg         test_attachment_completeness(ctx, GL_COLOR, att);
7397117f1b4Smrg         if (!att->Complete) {
7407117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
7417117f1b4Smrg            fbo_incomplete("color attachment incomplete", i);
7427117f1b4Smrg            return;
7437117f1b4Smrg         }
7447117f1b4Smrg      }
7457117f1b4Smrg
7464a49301eSmrg      /* get width, height, format of the renderbuffer/texture
7474a49301eSmrg       */
7487117f1b4Smrg      if (att->Type == GL_TEXTURE) {
7493464ebd5Sriastradh         const struct gl_texture_image *texImg =
7503464ebd5Sriastradh            _mesa_get_attachment_teximage(att);
7514a49301eSmrg         minWidth = MIN2(minWidth, texImg->Width);
7524a49301eSmrg         maxWidth = MAX2(maxWidth, texImg->Width);
7534a49301eSmrg         minHeight = MIN2(minHeight, texImg->Height);
7544a49301eSmrg         maxHeight = MAX2(maxHeight, texImg->Height);
7557117f1b4Smrg         f = texImg->_BaseFormat;
7563464ebd5Sriastradh         attFormat = texImg->TexFormat;
7577117f1b4Smrg         numImages++;
7583464ebd5Sriastradh         if (!_mesa_is_legal_color_format(ctx, f) &&
7593464ebd5Sriastradh             !is_legal_depth_format(ctx, f)) {
7607117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
7617117f1b4Smrg            fbo_incomplete("texture attachment incomplete", -1);
7627117f1b4Smrg            return;
7637117f1b4Smrg         }
7647117f1b4Smrg      }
7657117f1b4Smrg      else if (att->Type == GL_RENDERBUFFER_EXT) {
7664a49301eSmrg         minWidth = MIN2(minWidth, att->Renderbuffer->Width);
7674a49301eSmrg         maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
7684a49301eSmrg         minHeight = MIN2(minHeight, att->Renderbuffer->Height);
7694a49301eSmrg         maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
7707117f1b4Smrg         f = att->Renderbuffer->InternalFormat;
7713464ebd5Sriastradh         attFormat = att->Renderbuffer->Format;
7727117f1b4Smrg         numImages++;
7737117f1b4Smrg      }
7747117f1b4Smrg      else {
7757117f1b4Smrg         assert(att->Type == GL_NONE);
7767117f1b4Smrg         continue;
7777117f1b4Smrg      }
7787117f1b4Smrg
7793464ebd5Sriastradh      if (att->Renderbuffer && numSamples < 0) {
7804a49301eSmrg         /* first buffer */
7814a49301eSmrg         numSamples = att->Renderbuffer->NumSamples;
7824a49301eSmrg      }
7834a49301eSmrg
7843464ebd5Sriastradh      /* check if integer color */
7853464ebd5Sriastradh      fb->_IntegerColor = _mesa_is_format_integer_color(attFormat);
7863464ebd5Sriastradh
7874a49301eSmrg      /* Error-check width, height, format, samples
7884a49301eSmrg       */
7897117f1b4Smrg      if (numImages == 1) {
7904a49301eSmrg         /* save format, num samples */
7914a49301eSmrg         if (i >= 0) {
7927117f1b4Smrg            intFormat = f;
7934a49301eSmrg         }
7947117f1b4Smrg      }
7957117f1b4Smrg      else {
7964a49301eSmrg         if (!ctx->Extensions.ARB_framebuffer_object) {
7974a49301eSmrg            /* check that width, height, format are same */
7984a49301eSmrg            if (minWidth != maxWidth || minHeight != maxHeight) {
7994a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
8004a49301eSmrg               fbo_incomplete("width or height mismatch", -1);
8014a49301eSmrg               return;
8024a49301eSmrg            }
8034a49301eSmrg            /* check that all color buffer have same format */
8044a49301eSmrg            if (intFormat != GL_NONE && f != intFormat) {
8054a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
8064a49301eSmrg               fbo_incomplete("format mismatch", -1);
8074a49301eSmrg               return;
8084a49301eSmrg            }
8097117f1b4Smrg         }
8104a49301eSmrg         if (att->Renderbuffer &&
8114a49301eSmrg             att->Renderbuffer->NumSamples != numSamples) {
8124a49301eSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
8134a49301eSmrg            fbo_incomplete("inconsistant number of samples", i);
8147117f1b4Smrg            return;
8154a49301eSmrg         }
8164a49301eSmrg
8177117f1b4Smrg      }
8187117f1b4Smrg   }
8197117f1b4Smrg
8203464ebd5Sriastradh#if FEATURE_GL
8213464ebd5Sriastradh   if (ctx->API == API_OPENGL && !ctx->Extensions.ARB_ES2_compatibility) {
8223464ebd5Sriastradh      /* Check that all DrawBuffers are present */
8233464ebd5Sriastradh      for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
8243464ebd5Sriastradh	 if (fb->ColorDrawBuffer[j] != GL_NONE) {
8253464ebd5Sriastradh	    const struct gl_renderbuffer_attachment *att
8263464ebd5Sriastradh	       = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
8273464ebd5Sriastradh	    assert(att);
8283464ebd5Sriastradh	    if (att->Type == GL_NONE) {
8293464ebd5Sriastradh	       fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
8303464ebd5Sriastradh	       fbo_incomplete("missing drawbuffer", j);
8313464ebd5Sriastradh	       return;
8323464ebd5Sriastradh	    }
8333464ebd5Sriastradh	 }
8347117f1b4Smrg      }
8357117f1b4Smrg
8363464ebd5Sriastradh      /* Check that the ReadBuffer is present */
8373464ebd5Sriastradh      if (fb->ColorReadBuffer != GL_NONE) {
8383464ebd5Sriastradh	 const struct gl_renderbuffer_attachment *att
8393464ebd5Sriastradh	    = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
8403464ebd5Sriastradh	 assert(att);
8413464ebd5Sriastradh	 if (att->Type == GL_NONE) {
8423464ebd5Sriastradh	    fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
8437117f1b4Smrg            fbo_incomplete("missing readbuffer", -1);
8443464ebd5Sriastradh	    return;
8453464ebd5Sriastradh	 }
8467117f1b4Smrg      }
8477117f1b4Smrg   }
8484a49301eSmrg#else
8494a49301eSmrg   (void) j;
850c1f859d4Smrg#endif
8517117f1b4Smrg
8527117f1b4Smrg   if (numImages == 0) {
8537117f1b4Smrg      fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
8547117f1b4Smrg      fbo_incomplete("no attachments", -1);
8557117f1b4Smrg      return;
8567117f1b4Smrg   }
8577117f1b4Smrg
8584a49301eSmrg   /* Provisionally set status = COMPLETE ... */
8597117f1b4Smrg   fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
8604a49301eSmrg
8614a49301eSmrg   /* ... but the driver may say the FB is incomplete.
8624a49301eSmrg    * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
8634a49301eSmrg    * if anything.
8644a49301eSmrg    */
8654a49301eSmrg   if (ctx->Driver.ValidateFramebuffer) {
8664a49301eSmrg      ctx->Driver.ValidateFramebuffer(ctx, fb);
8674a49301eSmrg      if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
8684a49301eSmrg         fbo_incomplete("driver marked FBO as incomplete", -1);
8694a49301eSmrg      }
8704a49301eSmrg   }
8714a49301eSmrg
8724a49301eSmrg   if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
8734a49301eSmrg      /*
8744a49301eSmrg       * Note that if ARB_framebuffer_object is supported and the attached
8754a49301eSmrg       * renderbuffers/textures are different sizes, the framebuffer
8764a49301eSmrg       * width/height will be set to the smallest width/height.
8774a49301eSmrg       */
8784a49301eSmrg      fb->Width = minWidth;
8794a49301eSmrg      fb->Height = minHeight;
8804a49301eSmrg
8814a49301eSmrg      /* finally, update the visual info for the framebuffer */
8823464ebd5Sriastradh      _mesa_update_framebuffer_visual(ctx, fb);
8834a49301eSmrg   }
8847117f1b4Smrg}
8857117f1b4Smrg
8867117f1b4Smrg
8877117f1b4SmrgGLboolean GLAPIENTRY
8887117f1b4Smrg_mesa_IsRenderbufferEXT(GLuint renderbuffer)
8897117f1b4Smrg{
8907117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
8917117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
8927117f1b4Smrg   if (renderbuffer) {
8937117f1b4Smrg      struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
8947117f1b4Smrg      if (rb != NULL && rb != &DummyRenderbuffer)
8957117f1b4Smrg         return GL_TRUE;
8967117f1b4Smrg   }
8977117f1b4Smrg   return GL_FALSE;
8987117f1b4Smrg}
8997117f1b4Smrg
9007117f1b4Smrg
9017117f1b4Smrgvoid GLAPIENTRY
9027117f1b4Smrg_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
9037117f1b4Smrg{
9047117f1b4Smrg   struct gl_renderbuffer *newRb;
9057117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9067117f1b4Smrg
9077117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
9087117f1b4Smrg
9097117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
9104a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
9117117f1b4Smrg      return;
9127117f1b4Smrg   }
9137117f1b4Smrg
9144a49301eSmrg   /* No need to flush here since the render buffer binding has no
9154a49301eSmrg    * effect on rendering state.
9167117f1b4Smrg    */
9177117f1b4Smrg
9187117f1b4Smrg   if (renderbuffer) {
9197117f1b4Smrg      newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
9207117f1b4Smrg      if (newRb == &DummyRenderbuffer) {
9217117f1b4Smrg         /* ID was reserved, but no real renderbuffer object made yet */
9227117f1b4Smrg         newRb = NULL;
9237117f1b4Smrg      }
9244a49301eSmrg      else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
9254a49301eSmrg         /* All RB IDs must be Gen'd */
9264a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
9274a49301eSmrg         return;
9284a49301eSmrg      }
9294a49301eSmrg
9307117f1b4Smrg      if (!newRb) {
9317117f1b4Smrg	 /* create new renderbuffer object */
9327117f1b4Smrg	 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
9337117f1b4Smrg	 if (!newRb) {
9347117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
9357117f1b4Smrg	    return;
9367117f1b4Smrg	 }
9377117f1b4Smrg         ASSERT(newRb->AllocStorage);
9387117f1b4Smrg         _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
9397117f1b4Smrg         newRb->RefCount = 1; /* referenced by hash table */
9407117f1b4Smrg      }
9417117f1b4Smrg   }
9427117f1b4Smrg   else {
9437117f1b4Smrg      newRb = NULL;
9447117f1b4Smrg   }
9457117f1b4Smrg
9467117f1b4Smrg   ASSERT(newRb != &DummyRenderbuffer);
9477117f1b4Smrg
9487117f1b4Smrg   _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
9497117f1b4Smrg}
9507117f1b4Smrg
9517117f1b4Smrg
9524a49301eSmrg/**
9534a49301eSmrg * If the given renderbuffer is anywhere attached to the framebuffer, detach
9544a49301eSmrg * the renderbuffer.
9554a49301eSmrg * This is used when a renderbuffer object is deleted.
9564a49301eSmrg * The spec calls for unbinding.
9574a49301eSmrg */
9584a49301eSmrgstatic void
9593464ebd5Sriastradhdetach_renderbuffer(struct gl_context *ctx,
9604a49301eSmrg                    struct gl_framebuffer *fb,
9614a49301eSmrg                    struct gl_renderbuffer *rb)
9624a49301eSmrg{
9634a49301eSmrg   GLuint i;
9644a49301eSmrg   for (i = 0; i < BUFFER_COUNT; i++) {
9654a49301eSmrg      if (fb->Attachment[i].Renderbuffer == rb) {
9664a49301eSmrg         _mesa_remove_attachment(ctx, &fb->Attachment[i]);
9674a49301eSmrg      }
9684a49301eSmrg   }
9694a49301eSmrg   invalidate_framebuffer(fb);
9704a49301eSmrg}
9714a49301eSmrg
9724a49301eSmrg
9737117f1b4Smrgvoid GLAPIENTRY
9747117f1b4Smrg_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
9757117f1b4Smrg{
9767117f1b4Smrg   GLint i;
9777117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9787117f1b4Smrg
9797117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
9807117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
9817117f1b4Smrg
9827117f1b4Smrg   for (i = 0; i < n; i++) {
9837117f1b4Smrg      if (renderbuffers[i] > 0) {
9847117f1b4Smrg	 struct gl_renderbuffer *rb;
9857117f1b4Smrg	 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
9867117f1b4Smrg	 if (rb) {
9877117f1b4Smrg            /* check if deleting currently bound renderbuffer object */
9887117f1b4Smrg            if (rb == ctx->CurrentRenderbuffer) {
9897117f1b4Smrg               /* bind default */
9907117f1b4Smrg               ASSERT(rb->RefCount >= 2);
9917117f1b4Smrg               _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
9927117f1b4Smrg            }
9937117f1b4Smrg
9943464ebd5Sriastradh            if (is_user_fbo(ctx->DrawBuffer)) {
9954a49301eSmrg               detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
9964a49301eSmrg            }
9973464ebd5Sriastradh            if (is_user_fbo(ctx->ReadBuffer)
9983464ebd5Sriastradh                && ctx->ReadBuffer != ctx->DrawBuffer) {
9994a49301eSmrg               detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
10004a49301eSmrg            }
10014a49301eSmrg
10027117f1b4Smrg	    /* Remove from hash table immediately, to free the ID.
10037117f1b4Smrg             * But the object will not be freed until it's no longer
10047117f1b4Smrg             * referenced anywhere else.
10057117f1b4Smrg             */
10067117f1b4Smrg	    _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
10077117f1b4Smrg
10087117f1b4Smrg            if (rb != &DummyRenderbuffer) {
10097117f1b4Smrg               /* no longer referenced by hash table */
10107117f1b4Smrg               _mesa_reference_renderbuffer(&rb, NULL);
10117117f1b4Smrg	    }
10127117f1b4Smrg	 }
10137117f1b4Smrg      }
10147117f1b4Smrg   }
10157117f1b4Smrg}
10167117f1b4Smrg
10177117f1b4Smrg
10187117f1b4Smrgvoid GLAPIENTRY
10197117f1b4Smrg_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
10207117f1b4Smrg{
10217117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
10227117f1b4Smrg   GLuint first;
10237117f1b4Smrg   GLint i;
10247117f1b4Smrg
10257117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
10267117f1b4Smrg
10277117f1b4Smrg   if (n < 0) {
10287117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
10297117f1b4Smrg      return;
10307117f1b4Smrg   }
10317117f1b4Smrg
10327117f1b4Smrg   if (!renderbuffers)
10337117f1b4Smrg      return;
10347117f1b4Smrg
10357117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
10367117f1b4Smrg
10377117f1b4Smrg   for (i = 0; i < n; i++) {
10387117f1b4Smrg      GLuint name = first + i;
10397117f1b4Smrg      renderbuffers[i] = name;
10407117f1b4Smrg      /* insert dummy placeholder into hash table */
10417117f1b4Smrg      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
10427117f1b4Smrg      _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
10437117f1b4Smrg      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
10447117f1b4Smrg   }
10457117f1b4Smrg}
10467117f1b4Smrg
10477117f1b4Smrg
10487117f1b4Smrg/**
10497117f1b4Smrg * Given an internal format token for a render buffer, return the
10503464ebd5Sriastradh * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
10513464ebd5Sriastradh * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE,
10523464ebd5Sriastradh * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc).
10537117f1b4Smrg *
10543464ebd5Sriastradh * This is similar to _mesa_base_tex_format() but the set of valid
10553464ebd5Sriastradh * internal formats is different.
1056cdc920a0Smrg *
10573464ebd5Sriastradh * Note that even if a format is determined to be legal here, validation
10583464ebd5Sriastradh * of the FBO may fail if the format is not supported by the driver/GPU.
10593464ebd5Sriastradh *
10603464ebd5Sriastradh * \param internalFormat  as passed to glRenderbufferStorage()
10613464ebd5Sriastradh * \return the base internal format, or 0 if internalFormat is illegal
10627117f1b4Smrg */
10637117f1b4SmrgGLenum
10643464ebd5Sriastradh_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
10657117f1b4Smrg{
10663464ebd5Sriastradh   /*
10673464ebd5Sriastradh    * Notes: some formats such as alpha, luminance, etc. were added
10683464ebd5Sriastradh    * with GL_ARB_framebuffer_object.
10693464ebd5Sriastradh    */
10707117f1b4Smrg   switch (internalFormat) {
10713464ebd5Sriastradh   case GL_ALPHA:
10723464ebd5Sriastradh   case GL_ALPHA4:
10733464ebd5Sriastradh   case GL_ALPHA8:
10743464ebd5Sriastradh   case GL_ALPHA12:
10753464ebd5Sriastradh   case GL_ALPHA16:
10763464ebd5Sriastradh      return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
10773464ebd5Sriastradh   case GL_LUMINANCE:
10783464ebd5Sriastradh   case GL_LUMINANCE4:
10793464ebd5Sriastradh   case GL_LUMINANCE8:
10803464ebd5Sriastradh   case GL_LUMINANCE12:
10813464ebd5Sriastradh   case GL_LUMINANCE16:
10823464ebd5Sriastradh      return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
10833464ebd5Sriastradh   case GL_LUMINANCE_ALPHA:
10843464ebd5Sriastradh   case GL_LUMINANCE4_ALPHA4:
10853464ebd5Sriastradh   case GL_LUMINANCE6_ALPHA2:
10863464ebd5Sriastradh   case GL_LUMINANCE8_ALPHA8:
10873464ebd5Sriastradh   case GL_LUMINANCE12_ALPHA4:
10883464ebd5Sriastradh   case GL_LUMINANCE12_ALPHA12:
10893464ebd5Sriastradh   case GL_LUMINANCE16_ALPHA16:
10903464ebd5Sriastradh      return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
10913464ebd5Sriastradh   case GL_INTENSITY:
10923464ebd5Sriastradh   case GL_INTENSITY4:
10933464ebd5Sriastradh   case GL_INTENSITY8:
10943464ebd5Sriastradh   case GL_INTENSITY12:
10953464ebd5Sriastradh   case GL_INTENSITY16:
10963464ebd5Sriastradh      return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
10977117f1b4Smrg   case GL_RGB:
10987117f1b4Smrg   case GL_R3_G3_B2:
10997117f1b4Smrg   case GL_RGB4:
11007117f1b4Smrg   case GL_RGB5:
11017117f1b4Smrg   case GL_RGB8:
11027117f1b4Smrg   case GL_RGB10:
11037117f1b4Smrg   case GL_RGB12:
11047117f1b4Smrg   case GL_RGB16:
11053464ebd5Sriastradh   case GL_SRGB8_EXT:
11067117f1b4Smrg      return GL_RGB;
11077117f1b4Smrg   case GL_RGBA:
11087117f1b4Smrg   case GL_RGBA2:
11097117f1b4Smrg   case GL_RGBA4:
11107117f1b4Smrg   case GL_RGB5_A1:
11117117f1b4Smrg   case GL_RGBA8:
11127117f1b4Smrg   case GL_RGB10_A2:
11137117f1b4Smrg   case GL_RGBA12:
11147117f1b4Smrg   case GL_RGBA16:
11153464ebd5Sriastradh   case GL_SRGB8_ALPHA8_EXT:
11167117f1b4Smrg      return GL_RGBA;
11177117f1b4Smrg   case GL_STENCIL_INDEX:
11187117f1b4Smrg   case GL_STENCIL_INDEX1_EXT:
11197117f1b4Smrg   case GL_STENCIL_INDEX4_EXT:
11207117f1b4Smrg   case GL_STENCIL_INDEX8_EXT:
11217117f1b4Smrg   case GL_STENCIL_INDEX16_EXT:
11227117f1b4Smrg      return GL_STENCIL_INDEX;
11237117f1b4Smrg   case GL_DEPTH_COMPONENT:
11247117f1b4Smrg   case GL_DEPTH_COMPONENT16:
11257117f1b4Smrg   case GL_DEPTH_COMPONENT24:
11267117f1b4Smrg   case GL_DEPTH_COMPONENT32:
11277117f1b4Smrg      return GL_DEPTH_COMPONENT;
11287117f1b4Smrg   case GL_DEPTH_STENCIL_EXT:
11297117f1b4Smrg   case GL_DEPTH24_STENCIL8_EXT:
11307117f1b4Smrg      if (ctx->Extensions.EXT_packed_depth_stencil)
11317117f1b4Smrg         return GL_DEPTH_STENCIL_EXT;
11327117f1b4Smrg      else
11337117f1b4Smrg         return 0;
11343464ebd5Sriastradh   case GL_RED:
11353464ebd5Sriastradh   case GL_R8:
11363464ebd5Sriastradh   case GL_R16:
11373464ebd5Sriastradh      return ctx->Extensions.ARB_texture_rg ? GL_RED : 0;
11383464ebd5Sriastradh   case GL_RG:
11393464ebd5Sriastradh   case GL_RG8:
11403464ebd5Sriastradh   case GL_RG16:
11413464ebd5Sriastradh      return ctx->Extensions.ARB_texture_rg ? GL_RG : 0;
11423464ebd5Sriastradh   /* signed normalized texture formats */
11433464ebd5Sriastradh   case GL_RED_SNORM:
11443464ebd5Sriastradh   case GL_R8_SNORM:
11453464ebd5Sriastradh   case GL_R16_SNORM:
11463464ebd5Sriastradh      return ctx->Extensions.EXT_texture_snorm ? GL_RED : 0;
11473464ebd5Sriastradh   case GL_RG_SNORM:
11483464ebd5Sriastradh   case GL_RG8_SNORM:
11493464ebd5Sriastradh   case GL_RG16_SNORM:
11503464ebd5Sriastradh      return ctx->Extensions.EXT_texture_snorm ? GL_RG : 0;
11513464ebd5Sriastradh   case GL_RGB_SNORM:
11523464ebd5Sriastradh   case GL_RGB8_SNORM:
11533464ebd5Sriastradh   case GL_RGB16_SNORM:
11543464ebd5Sriastradh      return ctx->Extensions.EXT_texture_snorm ? GL_RGB : 0;
11553464ebd5Sriastradh   case GL_RGBA_SNORM:
11563464ebd5Sriastradh   case GL_RGBA8_SNORM:
11573464ebd5Sriastradh   case GL_RGBA16_SNORM:
11583464ebd5Sriastradh      return ctx->Extensions.EXT_texture_snorm ? GL_RGBA : 0;
11593464ebd5Sriastradh   case GL_ALPHA_SNORM:
11603464ebd5Sriastradh   case GL_ALPHA8_SNORM:
11613464ebd5Sriastradh   case GL_ALPHA16_SNORM:
11623464ebd5Sriastradh      return ctx->Extensions.EXT_texture_snorm &&
11633464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
11643464ebd5Sriastradh   case GL_LUMINANCE_SNORM:
11653464ebd5Sriastradh   case GL_LUMINANCE8_SNORM:
11663464ebd5Sriastradh   case GL_LUMINANCE16_SNORM:
11673464ebd5Sriastradh      return ctx->Extensions.EXT_texture_snorm &&
11683464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
11693464ebd5Sriastradh   case GL_LUMINANCE_ALPHA_SNORM:
11703464ebd5Sriastradh   case GL_LUMINANCE8_ALPHA8_SNORM:
11713464ebd5Sriastradh   case GL_LUMINANCE16_ALPHA16_SNORM:
11723464ebd5Sriastradh      return ctx->Extensions.EXT_texture_snorm &&
11733464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
11743464ebd5Sriastradh   case GL_INTENSITY_SNORM:
11753464ebd5Sriastradh   case GL_INTENSITY8_SNORM:
11763464ebd5Sriastradh   case GL_INTENSITY16_SNORM:
11773464ebd5Sriastradh      return ctx->Extensions.EXT_texture_snorm &&
11783464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
11793464ebd5Sriastradh   case GL_R16F:
11803464ebd5Sriastradh   case GL_R32F:
11813464ebd5Sriastradh      return ctx->Extensions.ARB_texture_rg &&
11823464ebd5Sriastradh             ctx->Extensions.ARB_texture_float ? GL_RED : 0;
11833464ebd5Sriastradh   case GL_RG16F:
11843464ebd5Sriastradh   case GL_RG32F:
11853464ebd5Sriastradh      return ctx->Extensions.ARB_texture_rg &&
11863464ebd5Sriastradh             ctx->Extensions.ARB_texture_float ? GL_RG : 0;
11873464ebd5Sriastradh   case GL_RGB16F:
11883464ebd5Sriastradh   case GL_RGB32F:
11893464ebd5Sriastradh      return ctx->Extensions.ARB_texture_float ? GL_RGB : 0;
11903464ebd5Sriastradh   case GL_RGBA16F:
11913464ebd5Sriastradh   case GL_RGBA32F:
11923464ebd5Sriastradh      return ctx->Extensions.ARB_texture_float ? GL_RGBA : 0;
11933464ebd5Sriastradh   case GL_ALPHA16F_ARB:
11943464ebd5Sriastradh   case GL_ALPHA32F_ARB:
11953464ebd5Sriastradh      return ctx->Extensions.ARB_texture_float &&
11963464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
11973464ebd5Sriastradh   case GL_LUMINANCE16F_ARB:
11983464ebd5Sriastradh   case GL_LUMINANCE32F_ARB:
11993464ebd5Sriastradh      return ctx->Extensions.ARB_texture_float &&
12003464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
12013464ebd5Sriastradh   case GL_LUMINANCE_ALPHA16F_ARB:
12023464ebd5Sriastradh   case GL_LUMINANCE_ALPHA32F_ARB:
12033464ebd5Sriastradh      return ctx->Extensions.ARB_texture_float &&
12043464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
12053464ebd5Sriastradh   case GL_INTENSITY16F_ARB:
12063464ebd5Sriastradh   case GL_INTENSITY32F_ARB:
12073464ebd5Sriastradh      return ctx->Extensions.ARB_texture_float &&
12083464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
12093464ebd5Sriastradh   case GL_RGB9_E5:
12103464ebd5Sriastradh      return ctx->Extensions.EXT_texture_shared_exponent ? GL_RGB : 0;
12113464ebd5Sriastradh   case GL_R11F_G11F_B10F:
12123464ebd5Sriastradh      return ctx->Extensions.EXT_packed_float ? GL_RGB : 0;
12133464ebd5Sriastradh   /* XXX add integer formats eventually */
12147117f1b4Smrg   default:
12157117f1b4Smrg      return 0;
12167117f1b4Smrg   }
12177117f1b4Smrg}
12187117f1b4Smrg
12197117f1b4Smrg
12203464ebd5Sriastradh/**
12213464ebd5Sriastradh * Invalidate a renderbuffer attachment.  Called from _mesa_HashWalk().
12223464ebd5Sriastradh */
12233464ebd5Sriastradhstatic void
12243464ebd5Sriastradhinvalidate_rb(GLuint key, void *data, void *userData)
12253464ebd5Sriastradh{
12263464ebd5Sriastradh   struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
12273464ebd5Sriastradh   struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData;
12283464ebd5Sriastradh
12293464ebd5Sriastradh   /* If this is a user-created FBO */
12303464ebd5Sriastradh   if (is_user_fbo(fb)) {
12313464ebd5Sriastradh      GLuint i;
12323464ebd5Sriastradh      for (i = 0; i < BUFFER_COUNT; i++) {
12333464ebd5Sriastradh         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
12343464ebd5Sriastradh         if (att->Type == GL_RENDERBUFFER &&
12353464ebd5Sriastradh             att->Renderbuffer == rb) {
12363464ebd5Sriastradh            /* Mark fb status as indeterminate to force re-validation */
12373464ebd5Sriastradh            fb->_Status = 0;
12383464ebd5Sriastradh            return;
12393464ebd5Sriastradh         }
12403464ebd5Sriastradh      }
12413464ebd5Sriastradh   }
12423464ebd5Sriastradh}
12433464ebd5Sriastradh
12443464ebd5Sriastradh
12454a49301eSmrg/** sentinal value, see below */
12464a49301eSmrg#define NO_SAMPLES 1000
12474a49301eSmrg
12484a49301eSmrg
12494a49301eSmrg/**
12504a49301eSmrg * Helper function used by _mesa_RenderbufferStorageEXT() and
12514a49301eSmrg * _mesa_RenderbufferStorageMultisample().
12524a49301eSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
12534a49301eSmrg */
12544a49301eSmrgstatic void
12554a49301eSmrgrenderbuffer_storage(GLenum target, GLenum internalFormat,
12564a49301eSmrg                     GLsizei width, GLsizei height, GLsizei samples)
12577117f1b4Smrg{
12584a49301eSmrg   const char *func = samples == NO_SAMPLES ?
12594a49301eSmrg      "glRenderbufferStorage" : "RenderbufferStorageMultisample";
12607117f1b4Smrg   struct gl_renderbuffer *rb;
12617117f1b4Smrg   GLenum baseFormat;
12627117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
12637117f1b4Smrg
12647117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
12657117f1b4Smrg
12667117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
12674a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
12687117f1b4Smrg      return;
12697117f1b4Smrg   }
12707117f1b4Smrg
12717117f1b4Smrg   baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
12727117f1b4Smrg   if (baseFormat == 0) {
12734a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
12747117f1b4Smrg      return;
12757117f1b4Smrg   }
12767117f1b4Smrg
12777117f1b4Smrg   if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
12784a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
12797117f1b4Smrg      return;
12807117f1b4Smrg   }
12817117f1b4Smrg
12827117f1b4Smrg   if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
12834a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
12847117f1b4Smrg      return;
12857117f1b4Smrg   }
12867117f1b4Smrg
12874a49301eSmrg   if (samples == NO_SAMPLES) {
12884a49301eSmrg      /* NumSamples == 0 indicates non-multisampling */
12894a49301eSmrg      samples = 0;
12904a49301eSmrg   }
1291cdc920a0Smrg   else if (samples > (GLsizei) ctx->Const.MaxSamples) {
12924a49301eSmrg      /* note: driver may choose to use more samples than what's requested */
12934a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
12944a49301eSmrg      return;
12954a49301eSmrg   }
12967117f1b4Smrg
12974a49301eSmrg   rb = ctx->CurrentRenderbuffer;
12987117f1b4Smrg   if (!rb) {
12993464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
13007117f1b4Smrg      return;
13017117f1b4Smrg   }
13027117f1b4Smrg
13037117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
13047117f1b4Smrg
13057117f1b4Smrg   if (rb->InternalFormat == internalFormat &&
13067117f1b4Smrg       rb->Width == (GLuint) width &&
13077117f1b4Smrg       rb->Height == (GLuint) height) {
13087117f1b4Smrg      /* no change in allocation needed */
13097117f1b4Smrg      return;
13107117f1b4Smrg   }
13117117f1b4Smrg
13127117f1b4Smrg   /* These MUST get set by the AllocStorage func */
13134a49301eSmrg   rb->Format = MESA_FORMAT_NONE;
13144a49301eSmrg   rb->NumSamples = samples;
13157117f1b4Smrg
13167117f1b4Smrg   /* Now allocate the storage */
13177117f1b4Smrg   ASSERT(rb->AllocStorage);
13187117f1b4Smrg   if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
13197117f1b4Smrg      /* No error - check/set fields now */
13204a49301eSmrg      assert(rb->Format != MESA_FORMAT_NONE);
13217117f1b4Smrg      assert(rb->Width == (GLuint) width);
13227117f1b4Smrg      assert(rb->Height == (GLuint) height);
13237117f1b4Smrg      rb->InternalFormat = internalFormat;
1324cdc920a0Smrg      rb->_BaseFormat = baseFormat;
13254a49301eSmrg      assert(rb->_BaseFormat != 0);
13267117f1b4Smrg   }
13277117f1b4Smrg   else {
13287117f1b4Smrg      /* Probably ran out of memory - clear the fields */
13297117f1b4Smrg      rb->Width = 0;
13307117f1b4Smrg      rb->Height = 0;
13314a49301eSmrg      rb->Format = MESA_FORMAT_NONE;
13327117f1b4Smrg      rb->InternalFormat = GL_NONE;
13337117f1b4Smrg      rb->_BaseFormat = GL_NONE;
13344a49301eSmrg      rb->NumSamples = 0;
13357117f1b4Smrg   }
13367117f1b4Smrg
13373464ebd5Sriastradh   /* Invalidate the framebuffers the renderbuffer is attached in. */
13383464ebd5Sriastradh   if (rb->AttachedAnytime) {
13393464ebd5Sriastradh      _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb);
13403464ebd5Sriastradh   }
13417117f1b4Smrg}
13427117f1b4Smrg
13433464ebd5Sriastradh
1344cdc920a0Smrg#if FEATURE_OES_EGL_image
1345cdc920a0Smrgvoid GLAPIENTRY
13463464ebd5Sriastradh_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1347cdc920a0Smrg{
1348cdc920a0Smrg   struct gl_renderbuffer *rb;
1349cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
1350cdc920a0Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1351cdc920a0Smrg
13523464ebd5Sriastradh   if (!ctx->Extensions.OES_EGL_image) {
13533464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
13543464ebd5Sriastradh                  "glEGLImageTargetRenderbufferStorageOES(unsupported)");
13553464ebd5Sriastradh      return;
13563464ebd5Sriastradh   }
13573464ebd5Sriastradh
1358cdc920a0Smrg   if (target != GL_RENDERBUFFER) {
13593464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_ENUM,
13603464ebd5Sriastradh                  "EGLImageTargetRenderbufferStorageOES");
1361cdc920a0Smrg      return;
1362cdc920a0Smrg   }
1363cdc920a0Smrg
1364cdc920a0Smrg   rb = ctx->CurrentRenderbuffer;
1365cdc920a0Smrg   if (!rb) {
13663464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
13673464ebd5Sriastradh                  "EGLImageTargetRenderbufferStorageOES");
1368cdc920a0Smrg      return;
1369cdc920a0Smrg   }
1370cdc920a0Smrg
1371cdc920a0Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1372cdc920a0Smrg
1373cdc920a0Smrg   ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1374cdc920a0Smrg}
1375cdc920a0Smrg#endif
13767117f1b4Smrg
13773464ebd5Sriastradh
13784a49301eSmrg/**
13794a49301eSmrg * Helper function for _mesa_GetRenderbufferParameterivEXT() and
13804a49301eSmrg * _mesa_GetFramebufferAttachmentParameterivEXT()
13814a49301eSmrg * We have to be careful to respect the base format.  For example, if a
13824a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the
13834a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
13844a49301eSmrg * we need to return zero.
13854a49301eSmrg */
13864a49301eSmrgstatic GLint
13874a49301eSmrgget_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
13884a49301eSmrg{
13894a49301eSmrg   switch (pname) {
13904a49301eSmrg   case GL_RENDERBUFFER_RED_SIZE_EXT:
13914a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
13923464ebd5Sriastradh      if (baseFormat == GL_RGB || baseFormat == GL_RGBA ||
13933464ebd5Sriastradh	  baseFormat == GL_RG || baseFormat == GL_RED)
13943464ebd5Sriastradh         return _mesa_get_format_bits(format, pname);
13953464ebd5Sriastradh      else
13963464ebd5Sriastradh         return 0;
13974a49301eSmrg   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
13984a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
13993464ebd5Sriastradh      if (baseFormat == GL_RGB || baseFormat == GL_RGBA || baseFormat == GL_RG)
14003464ebd5Sriastradh         return _mesa_get_format_bits(format, pname);
14013464ebd5Sriastradh      else
14023464ebd5Sriastradh         return 0;
14034a49301eSmrg   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
14044a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
14054a49301eSmrg      if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
14064a49301eSmrg         return _mesa_get_format_bits(format, pname);
14074a49301eSmrg      else
14084a49301eSmrg         return 0;
14094a49301eSmrg   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
14104a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
14113464ebd5Sriastradh      if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA ||
14123464ebd5Sriastradh	  baseFormat == GL_LUMINANCE_ALPHA)
14134a49301eSmrg         return _mesa_get_format_bits(format, pname);
14144a49301eSmrg      else
14154a49301eSmrg         return 0;
14164a49301eSmrg   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
14174a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
14184a49301eSmrg      if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
14194a49301eSmrg         return _mesa_get_format_bits(format, pname);
14204a49301eSmrg      else
14214a49301eSmrg         return 0;
14224a49301eSmrg   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
14234a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
14244a49301eSmrg      if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
14254a49301eSmrg         return _mesa_get_format_bits(format, pname);
14264a49301eSmrg      else
14274a49301eSmrg         return 0;
14284a49301eSmrg   default:
14294a49301eSmrg      return 0;
14304a49301eSmrg   }
14314a49301eSmrg}
14324a49301eSmrg
14334a49301eSmrg
14344a49301eSmrg
14354a49301eSmrgvoid GLAPIENTRY
14364a49301eSmrg_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
14374a49301eSmrg                             GLsizei width, GLsizei height)
14384a49301eSmrg{
14394a49301eSmrg   /* GL_ARB_fbo says calling this function is equivalent to calling
14404a49301eSmrg    * glRenderbufferStorageMultisample() with samples=0.  We pass in
14414a49301eSmrg    * a token value here just for error reporting purposes.
14424a49301eSmrg    */
14434a49301eSmrg   renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
14444a49301eSmrg}
14454a49301eSmrg
14464a49301eSmrg
14474a49301eSmrgvoid GLAPIENTRY
14484a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
14494a49301eSmrg                                     GLenum internalFormat,
14504a49301eSmrg                                     GLsizei width, GLsizei height)
14514a49301eSmrg{
14524a49301eSmrg   renderbuffer_storage(target, internalFormat, width, height, samples);
14534a49301eSmrg}
14544a49301eSmrg
14554a49301eSmrg
14563464ebd5Sriastradh/**
14573464ebd5Sriastradh * OpenGL ES version of glRenderBufferStorage.
14583464ebd5Sriastradh */
14593464ebd5Sriastradhvoid GLAPIENTRY
14603464ebd5Sriastradh_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
14613464ebd5Sriastradh			   GLsizei width, GLsizei height)
14623464ebd5Sriastradh{
14633464ebd5Sriastradh   switch (internalFormat) {
14643464ebd5Sriastradh   case GL_RGB565:
14653464ebd5Sriastradh      /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
14663464ebd5Sriastradh      /* choose a closest format */
14673464ebd5Sriastradh      internalFormat = GL_RGB5;
14683464ebd5Sriastradh      break;
14693464ebd5Sriastradh   default:
14703464ebd5Sriastradh      break;
14713464ebd5Sriastradh   }
14723464ebd5Sriastradh
14733464ebd5Sriastradh   renderbuffer_storage(target, internalFormat, width, height, 0);
14743464ebd5Sriastradh}
14753464ebd5Sriastradh
14764a49301eSmrg
14777117f1b4Smrgvoid GLAPIENTRY
14787117f1b4Smrg_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
14797117f1b4Smrg{
14804a49301eSmrg   struct gl_renderbuffer *rb;
14817117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
14827117f1b4Smrg
14837117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
14847117f1b4Smrg
14857117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
14867117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
14877117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
14887117f1b4Smrg      return;
14897117f1b4Smrg   }
14907117f1b4Smrg
14914a49301eSmrg   rb = ctx->CurrentRenderbuffer;
14924a49301eSmrg   if (!rb) {
14937117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
14947117f1b4Smrg                  "glGetRenderbufferParameterivEXT");
14957117f1b4Smrg      return;
14967117f1b4Smrg   }
14977117f1b4Smrg
14984a49301eSmrg   /* No need to flush here since we're just quering state which is
14994a49301eSmrg    * not effected by rendering.
15004a49301eSmrg    */
15017117f1b4Smrg
15027117f1b4Smrg   switch (pname) {
15037117f1b4Smrg   case GL_RENDERBUFFER_WIDTH_EXT:
15044a49301eSmrg      *params = rb->Width;
15057117f1b4Smrg      return;
15067117f1b4Smrg   case GL_RENDERBUFFER_HEIGHT_EXT:
15074a49301eSmrg      *params = rb->Height;
15087117f1b4Smrg      return;
15097117f1b4Smrg   case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
15104a49301eSmrg      *params = rb->InternalFormat;
15117117f1b4Smrg      return;
15127117f1b4Smrg   case GL_RENDERBUFFER_RED_SIZE_EXT:
15137117f1b4Smrg   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
15147117f1b4Smrg   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
15157117f1b4Smrg   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
15167117f1b4Smrg   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
15177117f1b4Smrg   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
15184a49301eSmrg      *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
15197117f1b4Smrg      break;
15204a49301eSmrg   case GL_RENDERBUFFER_SAMPLES:
15214a49301eSmrg      if (ctx->Extensions.ARB_framebuffer_object) {
15224a49301eSmrg         *params = rb->NumSamples;
15234a49301eSmrg         break;
15244a49301eSmrg      }
15254a49301eSmrg      /* fallthrough */
15267117f1b4Smrg   default:
15277117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
15287117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
15297117f1b4Smrg      return;
15307117f1b4Smrg   }
15317117f1b4Smrg}
15327117f1b4Smrg
15337117f1b4Smrg
15347117f1b4SmrgGLboolean GLAPIENTRY
15357117f1b4Smrg_mesa_IsFramebufferEXT(GLuint framebuffer)
15367117f1b4Smrg{
15377117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
15387117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
15397117f1b4Smrg   if (framebuffer) {
15407117f1b4Smrg      struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
15417117f1b4Smrg      if (rb != NULL && rb != &DummyFramebuffer)
15427117f1b4Smrg         return GL_TRUE;
15437117f1b4Smrg   }
15447117f1b4Smrg   return GL_FALSE;
15457117f1b4Smrg}
15467117f1b4Smrg
15477117f1b4Smrg
15484a49301eSmrg/**
15494a49301eSmrg * Check if any of the attachments of the given framebuffer are textures
15504a49301eSmrg * (render to texture).  Call ctx->Driver.RenderTexture() for such
15514a49301eSmrg * attachments.
15524a49301eSmrg */
15537117f1b4Smrgstatic void
15543464ebd5Sriastradhcheck_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
15557117f1b4Smrg{
15567117f1b4Smrg   GLuint i;
15577117f1b4Smrg   ASSERT(ctx->Driver.RenderTexture);
15584a49301eSmrg
15593464ebd5Sriastradh   if (is_winsys_fbo(fb))
15604a49301eSmrg      return; /* can't render to texture with winsys framebuffers */
15614a49301eSmrg
15627117f1b4Smrg   for (i = 0; i < BUFFER_COUNT; i++) {
15637117f1b4Smrg      struct gl_renderbuffer_attachment *att = fb->Attachment + i;
15643464ebd5Sriastradh      if (att->Texture && _mesa_get_attachment_teximage(att)) {
15657117f1b4Smrg         ctx->Driver.RenderTexture(ctx, fb, att);
15667117f1b4Smrg      }
15677117f1b4Smrg   }
15687117f1b4Smrg}
15697117f1b4Smrg
15707117f1b4Smrg
15717117f1b4Smrg/**
15727117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures.
15737117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to
15747117f1b4Smrg * notify the device driver that the texture image may have changed.
15757117f1b4Smrg */
15767117f1b4Smrgstatic void
15773464ebd5Sriastradhcheck_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
15787117f1b4Smrg{
15793464ebd5Sriastradh   if (is_winsys_fbo(fb))
15804a49301eSmrg      return; /* can't render to texture with winsys framebuffers */
15814a49301eSmrg
15827117f1b4Smrg   if (ctx->Driver.FinishRenderTexture) {
15837117f1b4Smrg      GLuint i;
15847117f1b4Smrg      for (i = 0; i < BUFFER_COUNT; i++) {
15857117f1b4Smrg         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1586c1f859d4Smrg         if (att->Texture && att->Renderbuffer) {
15877117f1b4Smrg            ctx->Driver.FinishRenderTexture(ctx, att);
15887117f1b4Smrg         }
15897117f1b4Smrg      }
15907117f1b4Smrg   }
15917117f1b4Smrg}
15927117f1b4Smrg
15937117f1b4Smrg
15947117f1b4Smrgvoid GLAPIENTRY
15957117f1b4Smrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
15967117f1b4Smrg{
15974a49301eSmrg   struct gl_framebuffer *newDrawFb, *newReadFb;
15984a49301eSmrg   struct gl_framebuffer *oldDrawFb, *oldReadFb;
15997117f1b4Smrg   GLboolean bindReadBuf, bindDrawBuf;
16007117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
16017117f1b4Smrg
16024a49301eSmrg#ifdef DEBUG
16034a49301eSmrg   if (ctx->Extensions.ARB_framebuffer_object) {
16044a49301eSmrg      ASSERT(ctx->Extensions.EXT_framebuffer_object);
16054a49301eSmrg      ASSERT(ctx->Extensions.EXT_framebuffer_blit);
16064a49301eSmrg   }
16074a49301eSmrg#endif
16084a49301eSmrg
16097117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
16107117f1b4Smrg
16117117f1b4Smrg   if (!ctx->Extensions.EXT_framebuffer_object) {
16127117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
16137117f1b4Smrg                  "glBindFramebufferEXT(unsupported)");
16147117f1b4Smrg      return;
16157117f1b4Smrg   }
16167117f1b4Smrg
16177117f1b4Smrg   switch (target) {
16187117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
16197117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
16207117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
16217117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
16227117f1b4Smrg         return;
16237117f1b4Smrg      }
16247117f1b4Smrg      bindDrawBuf = GL_TRUE;
16257117f1b4Smrg      bindReadBuf = GL_FALSE;
16267117f1b4Smrg      break;
16277117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
16287117f1b4Smrg      if (!ctx->Extensions.EXT_framebuffer_blit) {
16297117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
16307117f1b4Smrg         return;
16317117f1b4Smrg      }
16327117f1b4Smrg      bindDrawBuf = GL_FALSE;
16337117f1b4Smrg      bindReadBuf = GL_TRUE;
16347117f1b4Smrg      break;
16357117f1b4Smrg#endif
16367117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
16377117f1b4Smrg      bindDrawBuf = GL_TRUE;
16387117f1b4Smrg      bindReadBuf = GL_TRUE;
16397117f1b4Smrg      break;
16407117f1b4Smrg   default:
16417117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
16427117f1b4Smrg      return;
16437117f1b4Smrg   }
16447117f1b4Smrg
16457117f1b4Smrg   if (framebuffer) {
16467117f1b4Smrg      /* Binding a user-created framebuffer object */
16474a49301eSmrg      newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
16484a49301eSmrg      if (newDrawFb == &DummyFramebuffer) {
16497117f1b4Smrg         /* ID was reserved, but no real framebuffer object made yet */
16504a49301eSmrg         newDrawFb = NULL;
16517117f1b4Smrg      }
16524a49301eSmrg      else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
16534a49301eSmrg         /* All FBO IDs must be Gen'd */
16544a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
16554a49301eSmrg         return;
16564a49301eSmrg      }
16574a49301eSmrg
16584a49301eSmrg      if (!newDrawFb) {
16597117f1b4Smrg	 /* create new framebuffer object */
16604a49301eSmrg	 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
16614a49301eSmrg	 if (!newDrawFb) {
16627117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
16637117f1b4Smrg	    return;
16647117f1b4Smrg	 }
16654a49301eSmrg         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
16667117f1b4Smrg      }
16674a49301eSmrg      newReadFb = newDrawFb;
16687117f1b4Smrg   }
16697117f1b4Smrg   else {
16707117f1b4Smrg      /* Binding the window system framebuffer (which was originally set
16717117f1b4Smrg       * with MakeCurrent).
16727117f1b4Smrg       */
16734a49301eSmrg      newDrawFb = ctx->WinSysDrawBuffer;
16744a49301eSmrg      newReadFb = ctx->WinSysReadBuffer;
16757117f1b4Smrg   }
16767117f1b4Smrg
16774a49301eSmrg   ASSERT(newDrawFb);
16784a49301eSmrg   ASSERT(newDrawFb != &DummyFramebuffer);
16794a49301eSmrg
16804a49301eSmrg   /* save pointers to current/old framebuffers */
16814a49301eSmrg   oldDrawFb = ctx->DrawBuffer;
16824a49301eSmrg   oldReadFb = ctx->ReadBuffer;
16834a49301eSmrg
16844a49301eSmrg   /* check if really changing bindings */
16854a49301eSmrg   if (oldDrawFb == newDrawFb)
16864a49301eSmrg      bindDrawBuf = GL_FALSE;
16874a49301eSmrg   if (oldReadFb == newReadFb)
16884a49301eSmrg      bindReadBuf = GL_FALSE;
16897117f1b4Smrg
16907117f1b4Smrg   /*
16914a49301eSmrg    * OK, now bind the new Draw/Read framebuffers, if they're changing.
16924a49301eSmrg    *
16934a49301eSmrg    * We also check if we're beginning and/or ending render-to-texture.
16944a49301eSmrg    * When a framebuffer with texture attachments is unbound, call
16954a49301eSmrg    * ctx->Driver.FinishRenderTexture().
16964a49301eSmrg    * When a framebuffer with texture attachments is bound, call
16974a49301eSmrg    * ctx->Driver.RenderTexture().
16984a49301eSmrg    *
16994a49301eSmrg    * Note that if the ReadBuffer has texture attachments we don't consider
17004a49301eSmrg    * that a render-to-texture case.
17017117f1b4Smrg    */
17027117f1b4Smrg   if (bindReadBuf) {
17034a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
17044a49301eSmrg
17054a49301eSmrg      /* check if old readbuffer was render-to-texture */
17064a49301eSmrg      check_end_texture_render(ctx, oldReadFb);
17074a49301eSmrg
17084a49301eSmrg      _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
17097117f1b4Smrg   }
17107117f1b4Smrg
17117117f1b4Smrg   if (bindDrawBuf) {
17124a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
17137117f1b4Smrg
17144a49301eSmrg      /* check if old read/draw buffers were render-to-texture */
17154a49301eSmrg      if (!bindReadBuf)
17164a49301eSmrg         check_end_texture_render(ctx, oldReadFb);
17177117f1b4Smrg
17184a49301eSmrg      if (oldDrawFb != oldReadFb)
17194a49301eSmrg         check_end_texture_render(ctx, oldDrawFb);
17204a49301eSmrg
17214a49301eSmrg      /* check if newly bound framebuffer has any texture attachments */
17224a49301eSmrg      check_begin_texture_render(ctx, newDrawFb);
17234a49301eSmrg
17244a49301eSmrg      _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
17257117f1b4Smrg   }
17267117f1b4Smrg
17274a49301eSmrg   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
17284a49301eSmrg      ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
17297117f1b4Smrg   }
17307117f1b4Smrg}
17317117f1b4Smrg
17327117f1b4Smrg
17337117f1b4Smrgvoid GLAPIENTRY
17347117f1b4Smrg_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
17357117f1b4Smrg{
17367117f1b4Smrg   GLint i;
17377117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
17387117f1b4Smrg
17397117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
17407117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
17417117f1b4Smrg
17427117f1b4Smrg   for (i = 0; i < n; i++) {
17437117f1b4Smrg      if (framebuffers[i] > 0) {
17447117f1b4Smrg	 struct gl_framebuffer *fb;
17457117f1b4Smrg	 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
17467117f1b4Smrg	 if (fb) {
17477117f1b4Smrg            ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
17487117f1b4Smrg
17497117f1b4Smrg            /* check if deleting currently bound framebuffer object */
17504a49301eSmrg            if (ctx->Extensions.EXT_framebuffer_blit) {
17514a49301eSmrg               /* separate draw/read binding points */
17524a49301eSmrg               if (fb == ctx->DrawBuffer) {
17534a49301eSmrg                  /* bind default */
17544a49301eSmrg                  ASSERT(fb->RefCount >= 2);
17554a49301eSmrg                  _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
17564a49301eSmrg               }
17574a49301eSmrg               if (fb == ctx->ReadBuffer) {
17584a49301eSmrg                  /* bind default */
17594a49301eSmrg                  ASSERT(fb->RefCount >= 2);
17604a49301eSmrg                  _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
17614a49301eSmrg               }
17624a49301eSmrg            }
17634a49301eSmrg            else {
17644a49301eSmrg               /* only one binding point for read/draw buffers */
17654a49301eSmrg               if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
17664a49301eSmrg                  /* bind default */
17674a49301eSmrg                  ASSERT(fb->RefCount >= 2);
17684a49301eSmrg                  _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
17694a49301eSmrg               }
17707117f1b4Smrg            }
17717117f1b4Smrg
17727117f1b4Smrg	    /* remove from hash table immediately, to free the ID */
17737117f1b4Smrg	    _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
17747117f1b4Smrg
17757117f1b4Smrg            if (fb != &DummyFramebuffer) {
17767117f1b4Smrg               /* But the object will not be freed until it's no longer
17777117f1b4Smrg                * bound in any context.
17787117f1b4Smrg                */
17794a49301eSmrg               _mesa_reference_framebuffer(&fb, NULL);
17807117f1b4Smrg	    }
17817117f1b4Smrg	 }
17827117f1b4Smrg      }
17837117f1b4Smrg   }
17847117f1b4Smrg}
17857117f1b4Smrg
17867117f1b4Smrg
17877117f1b4Smrgvoid GLAPIENTRY
17887117f1b4Smrg_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
17897117f1b4Smrg{
17907117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
17917117f1b4Smrg   GLuint first;
17927117f1b4Smrg   GLint i;
17937117f1b4Smrg
17947117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
17957117f1b4Smrg
17967117f1b4Smrg   if (n < 0) {
17977117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
17987117f1b4Smrg      return;
17997117f1b4Smrg   }
18007117f1b4Smrg
18017117f1b4Smrg   if (!framebuffers)
18027117f1b4Smrg      return;
18037117f1b4Smrg
18047117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
18057117f1b4Smrg
18067117f1b4Smrg   for (i = 0; i < n; i++) {
18077117f1b4Smrg      GLuint name = first + i;
18087117f1b4Smrg      framebuffers[i] = name;
18097117f1b4Smrg      /* insert dummy placeholder into hash table */
18107117f1b4Smrg      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
18117117f1b4Smrg      _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
18127117f1b4Smrg      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
18137117f1b4Smrg   }
18147117f1b4Smrg}
18157117f1b4Smrg
18167117f1b4Smrg
18177117f1b4Smrg
18187117f1b4SmrgGLenum GLAPIENTRY
18197117f1b4Smrg_mesa_CheckFramebufferStatusEXT(GLenum target)
18207117f1b4Smrg{
18217117f1b4Smrg   struct gl_framebuffer *buffer;
18227117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
18237117f1b4Smrg
18247117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
18257117f1b4Smrg
18263464ebd5Sriastradh   buffer = get_framebuffer_target(ctx, target);
18273464ebd5Sriastradh   if (!buffer) {
18287117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
18293464ebd5Sriastradh      return 0;
18307117f1b4Smrg   }
18317117f1b4Smrg
18323464ebd5Sriastradh   if (is_winsys_fbo(buffer)) {
18337117f1b4Smrg      /* The window system / default framebuffer is always complete */
18347117f1b4Smrg      return GL_FRAMEBUFFER_COMPLETE_EXT;
18357117f1b4Smrg   }
18367117f1b4Smrg
18374a49301eSmrg   /* No need to flush here */
18384a49301eSmrg
18394a49301eSmrg   if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
18404a49301eSmrg      _mesa_test_framebuffer_completeness(ctx, buffer);
18414a49301eSmrg   }
18427117f1b4Smrg
18437117f1b4Smrg   return buffer->_Status;
18447117f1b4Smrg}
18457117f1b4Smrg
18467117f1b4Smrg
18477117f1b4Smrg
18487117f1b4Smrg/**
18497117f1b4Smrg * Common code called by glFramebufferTexture1D/2D/3DEXT().
18507117f1b4Smrg */
18517117f1b4Smrgstatic void
18523464ebd5Sriastradhframebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
18537117f1b4Smrg                    GLenum attachment, GLenum textarget, GLuint texture,
18547117f1b4Smrg                    GLint level, GLint zoffset)
18557117f1b4Smrg{
18567117f1b4Smrg   struct gl_renderbuffer_attachment *att;
18577117f1b4Smrg   struct gl_texture_object *texObj = NULL;
18587117f1b4Smrg   struct gl_framebuffer *fb;
18597117f1b4Smrg
18607117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
18617117f1b4Smrg
18623464ebd5Sriastradh   fb = get_framebuffer_target(ctx, target);
18633464ebd5Sriastradh   if (!fb) {
18647117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
18654a49301eSmrg                  "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
18667117f1b4Smrg      return;
18677117f1b4Smrg   }
18687117f1b4Smrg
18697117f1b4Smrg   /* check framebuffer binding */
18703464ebd5Sriastradh   if (is_winsys_fbo(fb)) {
18717117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
18727117f1b4Smrg                  "glFramebufferTexture%sEXT", caller);
18737117f1b4Smrg      return;
18747117f1b4Smrg   }
18757117f1b4Smrg
18767117f1b4Smrg
18777117f1b4Smrg   /* The textarget, level, and zoffset parameters are only validated if
18787117f1b4Smrg    * texture is non-zero.
18797117f1b4Smrg    */
18807117f1b4Smrg   if (texture) {
18817117f1b4Smrg      GLboolean err = GL_TRUE;
18827117f1b4Smrg
18837117f1b4Smrg      texObj = _mesa_lookup_texture(ctx, texture);
18847117f1b4Smrg      if (texObj != NULL) {
1885c1f859d4Smrg         if (textarget == 0) {
18863464ebd5Sriastradh            /* XXX what's the purpose of this? */
1887c1f859d4Smrg            err = (texObj->Target != GL_TEXTURE_3D) &&
1888c1f859d4Smrg                (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1889c1f859d4Smrg                (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1890c1f859d4Smrg         }
1891c1f859d4Smrg         else {
1892c1f859d4Smrg            err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
18933464ebd5Sriastradh                ? !is_cube_face(textarget)
1894c1f859d4Smrg                : (texObj->Target != textarget);
1895c1f859d4Smrg         }
18967117f1b4Smrg      }
18973464ebd5Sriastradh      else {
18983464ebd5Sriastradh         /* can't render to a non-existant texture */
18993464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
19003464ebd5Sriastradh                     "glFramebufferTexture%sEXT(non existant texture)",
19013464ebd5Sriastradh                     caller);
19023464ebd5Sriastradh         return;
19033464ebd5Sriastradh      }
19047117f1b4Smrg
19057117f1b4Smrg      if (err) {
19067117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
19077117f1b4Smrg                     "glFramebufferTexture%sEXT(texture target mismatch)",
19087117f1b4Smrg                     caller);
19097117f1b4Smrg         return;
19107117f1b4Smrg      }
19117117f1b4Smrg
19127117f1b4Smrg      if (texObj->Target == GL_TEXTURE_3D) {
19137117f1b4Smrg         const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
19147117f1b4Smrg         if (zoffset < 0 || zoffset >= maxSize) {
19157117f1b4Smrg            _mesa_error(ctx, GL_INVALID_VALUE,
1916c1f859d4Smrg                        "glFramebufferTexture%sEXT(zoffset)", caller);
19177117f1b4Smrg            return;
19187117f1b4Smrg         }
19197117f1b4Smrg      }
1920c1f859d4Smrg      else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1921c1f859d4Smrg               (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1922c1f859d4Smrg         if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1923c1f859d4Smrg            _mesa_error(ctx, GL_INVALID_VALUE,
1924c1f859d4Smrg                        "glFramebufferTexture%sEXT(layer)", caller);
1925c1f859d4Smrg            return;
1926c1f859d4Smrg         }
1927c1f859d4Smrg      }
1928c1f859d4Smrg
19297117f1b4Smrg      if ((level < 0) ||
19307117f1b4Smrg          (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
19317117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
19327117f1b4Smrg                     "glFramebufferTexture%sEXT(level)", caller);
19337117f1b4Smrg         return;
19347117f1b4Smrg      }
19357117f1b4Smrg   }
19367117f1b4Smrg
19377117f1b4Smrg   att = _mesa_get_attachment(ctx, fb, attachment);
19387117f1b4Smrg   if (att == NULL) {
19397117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
19407117f1b4Smrg                  "glFramebufferTexture%sEXT(attachment)", caller);
19417117f1b4Smrg      return;
19427117f1b4Smrg   }
19437117f1b4Smrg
19447117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
19457117f1b4Smrg
19467117f1b4Smrg   _glthread_LOCK_MUTEX(fb->Mutex);
19477117f1b4Smrg   if (texObj) {
19487117f1b4Smrg      _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
19497117f1b4Smrg                                   level, zoffset);
19504a49301eSmrg      /* Set the render-to-texture flag.  We'll check this flag in
19514a49301eSmrg       * glTexImage() and friends to determine if we need to revalidate
19524a49301eSmrg       * any FBOs that might be rendering into this texture.
19534a49301eSmrg       * This flag never gets cleared since it's non-trivial to determine
19544a49301eSmrg       * when all FBOs might be done rendering to this texture.  That's OK
19554a49301eSmrg       * though since it's uncommon to render to a texture then repeatedly
19564a49301eSmrg       * call glTexImage() to change images in the texture.
19574a49301eSmrg       */
19584a49301eSmrg      texObj->_RenderToTexture = GL_TRUE;
19597117f1b4Smrg   }
19607117f1b4Smrg   else {
19617117f1b4Smrg      _mesa_remove_attachment(ctx, att);
19627117f1b4Smrg   }
19634a49301eSmrg
19644a49301eSmrg   invalidate_framebuffer(fb);
19654a49301eSmrg
19667117f1b4Smrg   _glthread_UNLOCK_MUTEX(fb->Mutex);
19677117f1b4Smrg}
19687117f1b4Smrg
19697117f1b4Smrg
19707117f1b4Smrg
19717117f1b4Smrgvoid GLAPIENTRY
19727117f1b4Smrg_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
19737117f1b4Smrg                              GLenum textarget, GLuint texture, GLint level)
19747117f1b4Smrg{
19757117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
19767117f1b4Smrg
19777117f1b4Smrg   if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
19783464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
19797117f1b4Smrg                  "glFramebufferTexture1DEXT(textarget)");
19807117f1b4Smrg      return;
19817117f1b4Smrg   }
19827117f1b4Smrg
19837117f1b4Smrg   framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
19847117f1b4Smrg                       level, 0);
19857117f1b4Smrg}
19867117f1b4Smrg
19877117f1b4Smrg
19887117f1b4Smrgvoid GLAPIENTRY
19897117f1b4Smrg_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
19907117f1b4Smrg                              GLenum textarget, GLuint texture, GLint level)
19917117f1b4Smrg{
19927117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
19937117f1b4Smrg
19947117f1b4Smrg   if ((texture != 0) &&
19957117f1b4Smrg       (textarget != GL_TEXTURE_2D) &&
19967117f1b4Smrg       (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
19973464ebd5Sriastradh       (!is_cube_face(textarget))) {
19987117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
19994a49301eSmrg                  "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
20007117f1b4Smrg      return;
20017117f1b4Smrg   }
20027117f1b4Smrg
20037117f1b4Smrg   framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
20047117f1b4Smrg                       level, 0);
20057117f1b4Smrg}
20067117f1b4Smrg
20077117f1b4Smrg
20087117f1b4Smrgvoid GLAPIENTRY
20097117f1b4Smrg_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
20107117f1b4Smrg                              GLenum textarget, GLuint texture,
20117117f1b4Smrg                              GLint level, GLint zoffset)
20127117f1b4Smrg{
20137117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
20147117f1b4Smrg
20157117f1b4Smrg   if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
20163464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
20177117f1b4Smrg                  "glFramebufferTexture3DEXT(textarget)");
20187117f1b4Smrg      return;
20197117f1b4Smrg   }
20207117f1b4Smrg
20217117f1b4Smrg   framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
20227117f1b4Smrg                       level, zoffset);
20237117f1b4Smrg}
20247117f1b4Smrg
20257117f1b4Smrg
2026c1f859d4Smrgvoid GLAPIENTRY
2027c1f859d4Smrg_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
2028c1f859d4Smrg                                 GLuint texture, GLint level, GLint layer)
2029c1f859d4Smrg{
2030c1f859d4Smrg   GET_CURRENT_CONTEXT(ctx);
2031c1f859d4Smrg
2032c1f859d4Smrg   framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
2033c1f859d4Smrg                       level, layer);
2034c1f859d4Smrg}
2035c1f859d4Smrg
2036c1f859d4Smrg
20377117f1b4Smrgvoid GLAPIENTRY
20387117f1b4Smrg_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
20397117f1b4Smrg                                 GLenum renderbufferTarget,
20407117f1b4Smrg                                 GLuint renderbuffer)
20417117f1b4Smrg{
20427117f1b4Smrg   struct gl_renderbuffer_attachment *att;
20437117f1b4Smrg   struct gl_framebuffer *fb;
20447117f1b4Smrg   struct gl_renderbuffer *rb;
20457117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
20467117f1b4Smrg
20477117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
20487117f1b4Smrg
20493464ebd5Sriastradh   fb = get_framebuffer_target(ctx, target);
20503464ebd5Sriastradh   if (!fb) {
20513464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(target)");
20527117f1b4Smrg      return;
20537117f1b4Smrg   }
20547117f1b4Smrg
20557117f1b4Smrg   if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
20567117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
20577117f1b4Smrg                  "glFramebufferRenderbufferEXT(renderbufferTarget)");
20587117f1b4Smrg      return;
20597117f1b4Smrg   }
20607117f1b4Smrg
20613464ebd5Sriastradh   if (is_winsys_fbo(fb)) {
20627117f1b4Smrg      /* Can't attach new renderbuffers to a window system framebuffer */
20637117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
20647117f1b4Smrg      return;
20657117f1b4Smrg   }
20667117f1b4Smrg
20677117f1b4Smrg   att = _mesa_get_attachment(ctx, fb, attachment);
20687117f1b4Smrg   if (att == NULL) {
20697117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
20704a49301eSmrg                  "glFramebufferRenderbufferEXT(invalid attachment %s)",
20714a49301eSmrg                  _mesa_lookup_enum_by_nr(attachment));
20727117f1b4Smrg      return;
20737117f1b4Smrg   }
20747117f1b4Smrg
20757117f1b4Smrg   if (renderbuffer) {
20767117f1b4Smrg      rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
20777117f1b4Smrg      if (!rb) {
20787117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION,
20794a49301eSmrg		     "glFramebufferRenderbufferEXT(non-existant"
20804a49301eSmrg                     " renderbuffer %u)", renderbuffer);
20817117f1b4Smrg	 return;
20827117f1b4Smrg      }
20833464ebd5Sriastradh      else if (rb == &DummyRenderbuffer) {
20843464ebd5Sriastradh         /* This is what NVIDIA does */
20853464ebd5Sriastradh	 _mesa_error(ctx, GL_INVALID_VALUE,
20863464ebd5Sriastradh		     "glFramebufferRenderbufferEXT(renderbuffer %u)",
20873464ebd5Sriastradh                     renderbuffer);
20883464ebd5Sriastradh	 return;
20893464ebd5Sriastradh      }
20907117f1b4Smrg   }
20917117f1b4Smrg   else {
20927117f1b4Smrg      /* remove renderbuffer attachment */
20937117f1b4Smrg      rb = NULL;
20947117f1b4Smrg   }
20957117f1b4Smrg
2096cdc920a0Smrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
2097cdc920a0Smrg       rb && rb->Format != MESA_FORMAT_NONE) {
20984a49301eSmrg      /* make sure the renderbuffer is a depth/stencil format */
2099cdc920a0Smrg      const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
21004a49301eSmrg      if (baseFormat != GL_DEPTH_STENCIL) {
21014a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
21024a49301eSmrg                     "glFramebufferRenderbufferEXT(renderbuffer"
21034a49301eSmrg                     " is not DEPTH_STENCIL format)");
21044a49301eSmrg         return;
21054a49301eSmrg      }
21064a49301eSmrg   }
21074a49301eSmrg
21084a49301eSmrg
21097117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
21107117f1b4Smrg
21117117f1b4Smrg   assert(ctx->Driver.FramebufferRenderbuffer);
21127117f1b4Smrg   ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
21137117f1b4Smrg
21147117f1b4Smrg   /* Some subsequent GL commands may depend on the framebuffer's visual
21157117f1b4Smrg    * after the binding is updated.  Update visual info now.
21167117f1b4Smrg    */
21173464ebd5Sriastradh   _mesa_update_framebuffer_visual(ctx, fb);
21187117f1b4Smrg}
21197117f1b4Smrg
21207117f1b4Smrg
21217117f1b4Smrgvoid GLAPIENTRY
21227117f1b4Smrg_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
21237117f1b4Smrg                                             GLenum pname, GLint *params)
21247117f1b4Smrg{
21257117f1b4Smrg   const struct gl_renderbuffer_attachment *att;
21267117f1b4Smrg   struct gl_framebuffer *buffer;
21273464ebd5Sriastradh   GLenum err;
21287117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
21297117f1b4Smrg
21307117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
21317117f1b4Smrg
21323464ebd5Sriastradh   /* The error differs in GL andd GLES. */
21333464ebd5Sriastradh   err = ctx->API == API_OPENGL ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
21343464ebd5Sriastradh
21353464ebd5Sriastradh   buffer = get_framebuffer_target(ctx, target);
21363464ebd5Sriastradh   if (!buffer) {
21377117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
21387117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(target)");
21397117f1b4Smrg      return;
21407117f1b4Smrg   }
21417117f1b4Smrg
21423464ebd5Sriastradh   if (is_winsys_fbo(buffer)) {
21433464ebd5Sriastradh      /* the default / window-system FBO */
21443464ebd5Sriastradh      att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
21453464ebd5Sriastradh   }
21463464ebd5Sriastradh   else {
21473464ebd5Sriastradh      /* user-created framebuffer FBO */
21483464ebd5Sriastradh      att = _mesa_get_attachment(ctx, buffer, attachment);
21497117f1b4Smrg   }
21507117f1b4Smrg
21517117f1b4Smrg   if (att == NULL) {
21527117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
21537117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(attachment)");
21547117f1b4Smrg      return;
21557117f1b4Smrg   }
21567117f1b4Smrg
21574a49301eSmrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
21584a49301eSmrg      /* the depth and stencil attachments must point to the same buffer */
21594a49301eSmrg      const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
21604a49301eSmrg      depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
21614a49301eSmrg      stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
21624a49301eSmrg      if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
21634a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
21644a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
21654a49301eSmrg                     " attachments differ)");
21664a49301eSmrg         return;
21674a49301eSmrg      }
21684a49301eSmrg   }
21694a49301eSmrg
21704a49301eSmrg   /* No need to flush here */
21717117f1b4Smrg
21727117f1b4Smrg   switch (pname) {
21737117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
21743464ebd5Sriastradh      *params = is_winsys_fbo(buffer) ? GL_FRAMEBUFFER_DEFAULT : att->Type;
21757117f1b4Smrg      return;
21767117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
21777117f1b4Smrg      if (att->Type == GL_RENDERBUFFER_EXT) {
21787117f1b4Smrg	 *params = att->Renderbuffer->Name;
21797117f1b4Smrg      }
21807117f1b4Smrg      else if (att->Type == GL_TEXTURE) {
21817117f1b4Smrg	 *params = att->Texture->Name;
21827117f1b4Smrg      }
21837117f1b4Smrg      else {
21843464ebd5Sriastradh         assert(att->Type == GL_NONE);
21853464ebd5Sriastradh         if (ctx->API == API_OPENGL) {
21863464ebd5Sriastradh            *params = 0;
21873464ebd5Sriastradh         } else {
21883464ebd5Sriastradh            _mesa_error(ctx, GL_INVALID_ENUM,
21893464ebd5Sriastradh                        "glGetFramebufferAttachmentParameterivEXT(pname)");
21903464ebd5Sriastradh         }
21917117f1b4Smrg      }
21927117f1b4Smrg      return;
21937117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
21947117f1b4Smrg      if (att->Type == GL_TEXTURE) {
21957117f1b4Smrg	 *params = att->TextureLevel;
21967117f1b4Smrg      }
21973464ebd5Sriastradh      else if (att->Type == GL_NONE) {
21983464ebd5Sriastradh         _mesa_error(ctx, err,
21993464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
22003464ebd5Sriastradh      }
22017117f1b4Smrg      else {
22027117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
22037117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
22047117f1b4Smrg      }
22057117f1b4Smrg      return;
22067117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
22077117f1b4Smrg      if (att->Type == GL_TEXTURE) {
2208c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
2209c1f859d4Smrg            *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
2210c1f859d4Smrg         }
2211c1f859d4Smrg         else {
2212c1f859d4Smrg            *params = 0;
2213c1f859d4Smrg         }
22147117f1b4Smrg      }
22153464ebd5Sriastradh      else if (att->Type == GL_NONE) {
22163464ebd5Sriastradh         _mesa_error(ctx, err,
22173464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
22183464ebd5Sriastradh      }
22197117f1b4Smrg      else {
22207117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
22217117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
22227117f1b4Smrg      }
22237117f1b4Smrg      return;
22247117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
22257117f1b4Smrg      if (att->Type == GL_TEXTURE) {
2226c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2227c1f859d4Smrg            *params = att->Zoffset;
2228c1f859d4Smrg         }
2229c1f859d4Smrg         else {
2230c1f859d4Smrg            *params = 0;
2231c1f859d4Smrg         }
22327117f1b4Smrg      }
22333464ebd5Sriastradh      else if (att->Type == GL_NONE) {
22343464ebd5Sriastradh         _mesa_error(ctx, err,
22353464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
22363464ebd5Sriastradh      }
22377117f1b4Smrg      else {
22387117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_ENUM,
22397117f1b4Smrg		     "glGetFramebufferAttachmentParameterivEXT(pname)");
22407117f1b4Smrg      }
22417117f1b4Smrg      return;
22424a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
22434a49301eSmrg      if (!ctx->Extensions.ARB_framebuffer_object) {
22444a49301eSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
22454a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
22464a49301eSmrg      }
22473464ebd5Sriastradh      else if (att->Type == GL_NONE) {
22483464ebd5Sriastradh         _mesa_error(ctx, err,
22493464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
22503464ebd5Sriastradh      }
22514a49301eSmrg      else {
22523464ebd5Sriastradh         if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) {
22533464ebd5Sriastradh            *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
22543464ebd5Sriastradh         }
22553464ebd5Sriastradh         else {
22563464ebd5Sriastradh            /* According to ARB_framebuffer_sRGB, we should return LINEAR
22573464ebd5Sriastradh             * if the sRGB conversion is unsupported. */
22583464ebd5Sriastradh            *params = GL_LINEAR;
22593464ebd5Sriastradh         }
22604a49301eSmrg      }
22614a49301eSmrg      return;
22624a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
22634a49301eSmrg      if (!ctx->Extensions.ARB_framebuffer_object) {
22644a49301eSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
22654a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
22664a49301eSmrg         return;
22674a49301eSmrg      }
22683464ebd5Sriastradh      else if (att->Type == GL_NONE) {
22693464ebd5Sriastradh         _mesa_error(ctx, err,
22703464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
22713464ebd5Sriastradh      }
22724a49301eSmrg      else {
22734a49301eSmrg         gl_format format = att->Renderbuffer->Format;
22744a49301eSmrg         if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
22754a49301eSmrg            /* special cases */
22764a49301eSmrg            *params = GL_INDEX;
22774a49301eSmrg         }
22784a49301eSmrg         else {
22794a49301eSmrg            *params = _mesa_get_format_datatype(format);
22804a49301eSmrg         }
22814a49301eSmrg      }
22824a49301eSmrg      return;
22834a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
22844a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
22854a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
22864a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
22874a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
22884a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
22894a49301eSmrg      if (!ctx->Extensions.ARB_framebuffer_object) {
22904a49301eSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
22914a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
22924a49301eSmrg      }
22933464ebd5Sriastradh      else if (att->Type == GL_NONE) {
22943464ebd5Sriastradh         _mesa_error(ctx, err,
22953464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
22963464ebd5Sriastradh      }
22974a49301eSmrg      else if (att->Texture) {
22984a49301eSmrg         const struct gl_texture_image *texImage =
22994a49301eSmrg            _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
23004a49301eSmrg                                   att->TextureLevel);
23014a49301eSmrg         if (texImage) {
23024a49301eSmrg            *params = get_component_bits(pname, texImage->_BaseFormat,
23034a49301eSmrg                                         texImage->TexFormat);
23044a49301eSmrg         }
23054a49301eSmrg         else {
23064a49301eSmrg            *params = 0;
23074a49301eSmrg         }
23084a49301eSmrg      }
23094a49301eSmrg      else if (att->Renderbuffer) {
23104a49301eSmrg         *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
23114a49301eSmrg                                      att->Renderbuffer->Format);
23124a49301eSmrg      }
23134a49301eSmrg      else {
23143464ebd5Sriastradh         _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:"
23153464ebd5Sriastradh                       " invalid FBO attachment structure");
23164a49301eSmrg      }
23174a49301eSmrg      return;
23187117f1b4Smrg   default:
23197117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
23207117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(pname)");
23217117f1b4Smrg      return;
23227117f1b4Smrg   }
23237117f1b4Smrg}
23247117f1b4Smrg
23257117f1b4Smrg
23267117f1b4Smrgvoid GLAPIENTRY
23277117f1b4Smrg_mesa_GenerateMipmapEXT(GLenum target)
23287117f1b4Smrg{
23297117f1b4Smrg   struct gl_texture_object *texObj;
23307117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
23317117f1b4Smrg
23327117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
23337117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
23347117f1b4Smrg
23357117f1b4Smrg   switch (target) {
23367117f1b4Smrg   case GL_TEXTURE_1D:
23377117f1b4Smrg   case GL_TEXTURE_2D:
23387117f1b4Smrg   case GL_TEXTURE_3D:
23397117f1b4Smrg   case GL_TEXTURE_CUBE_MAP:
23407117f1b4Smrg      /* OK, legal value */
23417117f1b4Smrg      break;
23427117f1b4Smrg   default:
23433464ebd5Sriastradh      /* XXX need to implement GL_TEXTURE_1D_ARRAY and GL_TEXTURE_2D_ARRAY */
23447117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
23457117f1b4Smrg      return;
23467117f1b4Smrg   }
23477117f1b4Smrg
23484a49301eSmrg   texObj = _mesa_get_current_tex_object(ctx, target);
23494a49301eSmrg
23504a49301eSmrg   if (texObj->BaseLevel >= texObj->MaxLevel) {
23514a49301eSmrg      /* nothing to do */
23524a49301eSmrg      return;
23534a49301eSmrg   }
23547117f1b4Smrg
23553464ebd5Sriastradh   if (texObj->Target == GL_TEXTURE_CUBE_MAP &&
23563464ebd5Sriastradh       !_mesa_cube_complete(texObj)) {
23573464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
23583464ebd5Sriastradh                  "glGenerateMipmap(incomplete cube map)");
23593464ebd5Sriastradh      return;
23603464ebd5Sriastradh   }
23613464ebd5Sriastradh
23627117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
2363c1f859d4Smrg   if (target == GL_TEXTURE_CUBE_MAP) {
23644a49301eSmrg      GLuint face;
2365c1f859d4Smrg      for (face = 0; face < 6; face++)
2366c1f859d4Smrg	 ctx->Driver.GenerateMipmap(ctx,
2367c1f859d4Smrg				    GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2368c1f859d4Smrg				    texObj);
23694a49301eSmrg   }
23704a49301eSmrg   else {
2371c1f859d4Smrg      ctx->Driver.GenerateMipmap(ctx, target, texObj);
2372c1f859d4Smrg   }
23737117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
23747117f1b4Smrg}
23757117f1b4Smrg
23767117f1b4Smrg
23777117f1b4Smrg#if FEATURE_EXT_framebuffer_blit
23784a49301eSmrg
23794a49301eSmrgstatic const struct gl_renderbuffer_attachment *
23803464ebd5Sriastradhfind_attachment(const struct gl_framebuffer *fb,
23813464ebd5Sriastradh                const struct gl_renderbuffer *rb)
23824a49301eSmrg{
23834a49301eSmrg   GLuint i;
23844a49301eSmrg   for (i = 0; i < Elements(fb->Attachment); i++) {
23854a49301eSmrg      if (fb->Attachment[i].Renderbuffer == rb)
23864a49301eSmrg         return &fb->Attachment[i];
23874a49301eSmrg   }
23884a49301eSmrg   return NULL;
23894a49301eSmrg}
23904a49301eSmrg
23914a49301eSmrg
23924a49301eSmrg
23934a49301eSmrg/**
23944a49301eSmrg * Blit rectangular region, optionally from one framebuffer to another.
23954a49301eSmrg *
23964a49301eSmrg * Note, if the src buffer is multisampled and the dest is not, this is
23974a49301eSmrg * when the samples must be resolved to a single color.
23984a49301eSmrg */
23997117f1b4Smrgvoid GLAPIENTRY
24007117f1b4Smrg_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
24017117f1b4Smrg                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
24027117f1b4Smrg                         GLbitfield mask, GLenum filter)
24037117f1b4Smrg{
24044a49301eSmrg   const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
24054a49301eSmrg                                     GL_DEPTH_BUFFER_BIT |
24064a49301eSmrg                                     GL_STENCIL_BUFFER_BIT);
24074a49301eSmrg   const struct gl_framebuffer *readFb, *drawFb;
24084a49301eSmrg   const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
24097117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
24107117f1b4Smrg
24117117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
24127117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
24137117f1b4Smrg
24143464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
24153464ebd5Sriastradh      _mesa_debug(ctx,
24163464ebd5Sriastradh                  "glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d, 0x%x, %s)\n",
24173464ebd5Sriastradh                  srcX0, srcY0, srcX1, srcY1,
24183464ebd5Sriastradh                  dstX0, dstY0, dstX1, dstY1,
24193464ebd5Sriastradh                  mask, _mesa_lookup_enum_by_nr(filter));
24203464ebd5Sriastradh
24217117f1b4Smrg   if (ctx->NewState) {
24227117f1b4Smrg      _mesa_update_state(ctx);
24237117f1b4Smrg   }
24247117f1b4Smrg
24254a49301eSmrg   readFb = ctx->ReadBuffer;
24264a49301eSmrg   drawFb = ctx->DrawBuffer;
24274a49301eSmrg
24284a49301eSmrg   if (!readFb || !drawFb) {
24294a49301eSmrg      /* This will normally never happen but someday we may want to
24304a49301eSmrg       * support MakeCurrent() with no drawables.
24314a49301eSmrg       */
24324a49301eSmrg      return;
24337117f1b4Smrg   }
24347117f1b4Smrg
24357117f1b4Smrg   /* check for complete framebuffers */
24364a49301eSmrg   if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
24374a49301eSmrg       readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
24387117f1b4Smrg      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
24397117f1b4Smrg                  "glBlitFramebufferEXT(incomplete draw/read buffers)");
24407117f1b4Smrg      return;
24417117f1b4Smrg   }
24427117f1b4Smrg
24437117f1b4Smrg   if (filter != GL_NEAREST && filter != GL_LINEAR) {
24447117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
24457117f1b4Smrg      return;
24467117f1b4Smrg   }
24477117f1b4Smrg
24484a49301eSmrg   if (mask & ~legalMaskBits) {
24497117f1b4Smrg      _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
24507117f1b4Smrg      return;
24517117f1b4Smrg   }
24527117f1b4Smrg
24537117f1b4Smrg   /* depth/stencil must be blitted with nearest filtering */
24547117f1b4Smrg   if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
24557117f1b4Smrg        && filter != GL_NEAREST) {
24567117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
24573464ebd5Sriastradh             "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)");
24587117f1b4Smrg      return;
24597117f1b4Smrg   }
24607117f1b4Smrg
24614a49301eSmrg   /* get color read/draw renderbuffers */
24624a49301eSmrg   if (mask & GL_COLOR_BUFFER_BIT) {
24634a49301eSmrg      colorReadRb = readFb->_ColorReadBuffer;
24644a49301eSmrg      colorDrawRb = drawFb->_ColorDrawBuffers[0];
24653464ebd5Sriastradh
24663464ebd5Sriastradh      /* From the EXT_framebuffer_object spec:
24673464ebd5Sriastradh       *
24683464ebd5Sriastradh       *     "If a buffer is specified in <mask> and does not exist in both
24693464ebd5Sriastradh       *     the read and draw framebuffers, the corresponding bit is silently
24703464ebd5Sriastradh       *     ignored."
24713464ebd5Sriastradh       */
24723464ebd5Sriastradh      if ((colorReadRb == NULL) || (colorDrawRb == NULL)) {
24733464ebd5Sriastradh	 colorReadRb = colorDrawRb = NULL;
24743464ebd5Sriastradh	 mask &= ~GL_COLOR_BUFFER_BIT;
24753464ebd5Sriastradh      }
24764a49301eSmrg   }
24774a49301eSmrg   else {
24784a49301eSmrg      colorReadRb = colorDrawRb = NULL;
24794a49301eSmrg   }
24804a49301eSmrg
24817117f1b4Smrg   if (mask & GL_STENCIL_BUFFER_BIT) {
24824a49301eSmrg      struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
24834a49301eSmrg      struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
24843464ebd5Sriastradh
24853464ebd5Sriastradh      /* From the EXT_framebuffer_object spec:
24863464ebd5Sriastradh       *
24873464ebd5Sriastradh       *     "If a buffer is specified in <mask> and does not exist in both
24883464ebd5Sriastradh       *     the read and draw framebuffers, the corresponding bit is silently
24893464ebd5Sriastradh       *     ignored."
24903464ebd5Sriastradh       */
24913464ebd5Sriastradh      if ((readRb == NULL) || (drawRb == NULL)) {
24923464ebd5Sriastradh	 readRb = drawRb = NULL;
24933464ebd5Sriastradh	 mask &= ~GL_STENCIL_BUFFER_BIT;
24943464ebd5Sriastradh      }
24953464ebd5Sriastradh      else if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
24963464ebd5Sriastradh	       _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
24977117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
24983464ebd5Sriastradh                     "glBlitFramebufferEXT(stencil buffer size mismatch)");
24997117f1b4Smrg         return;
25007117f1b4Smrg      }
25017117f1b4Smrg   }
25027117f1b4Smrg
25037117f1b4Smrg   if (mask & GL_DEPTH_BUFFER_BIT) {
25044a49301eSmrg      struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
25054a49301eSmrg      struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
25063464ebd5Sriastradh
25073464ebd5Sriastradh      /* From the EXT_framebuffer_object spec:
25083464ebd5Sriastradh       *
25093464ebd5Sriastradh       *     "If a buffer is specified in <mask> and does not exist in both
25103464ebd5Sriastradh       *     the read and draw framebuffers, the corresponding bit is silently
25113464ebd5Sriastradh       *     ignored."
25123464ebd5Sriastradh       */
25133464ebd5Sriastradh      if ((readRb == NULL) || (drawRb == NULL)) {
25143464ebd5Sriastradh	 readRb = drawRb = NULL;
25153464ebd5Sriastradh	 mask &= ~GL_DEPTH_BUFFER_BIT;
25163464ebd5Sriastradh      }
25173464ebd5Sriastradh      else if (_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
25183464ebd5Sriastradh	       _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
25197117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
25203464ebd5Sriastradh                     "glBlitFramebufferEXT(depth buffer size mismatch)");
25217117f1b4Smrg         return;
25227117f1b4Smrg      }
25237117f1b4Smrg   }
25247117f1b4Smrg
25254a49301eSmrg   if (readFb->Visual.samples > 0 &&
25264a49301eSmrg       drawFb->Visual.samples > 0 &&
25274a49301eSmrg       readFb->Visual.samples != drawFb->Visual.samples) {
25284a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
25294a49301eSmrg                  "glBlitFramebufferEXT(mismatched samples");
25304a49301eSmrg      return;
25314a49301eSmrg   }
25324a49301eSmrg
25334a49301eSmrg   /* extra checks for multisample copies... */
25344a49301eSmrg   if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
25354a49301eSmrg      /* src and dest region sizes must be the same */
25364a49301eSmrg      if (srcX1 - srcX0 != dstX1 - dstX0 ||
25374a49301eSmrg          srcY1 - srcY0 != dstY1 - dstY0) {
25384a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
25393464ebd5Sriastradh                "glBlitFramebufferEXT(bad src/dst multisample region sizes)");
25404a49301eSmrg         return;
25414a49301eSmrg      }
25424a49301eSmrg
25434a49301eSmrg      /* color formats must match */
25444a49301eSmrg      if (colorReadRb &&
25454a49301eSmrg          colorDrawRb &&
25464a49301eSmrg          colorReadRb->Format != colorDrawRb->Format) {
25474a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
25483464ebd5Sriastradh                "glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
25494a49301eSmrg         return;
25504a49301eSmrg      }
25514a49301eSmrg   }
25524a49301eSmrg
25537117f1b4Smrg   if (!ctx->Extensions.EXT_framebuffer_blit) {
25547117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
25557117f1b4Smrg      return;
25567117f1b4Smrg   }
25577117f1b4Smrg
25584a49301eSmrg   /* Debug code */
25594a49301eSmrg   if (DEBUG_BLIT) {
2560cdc920a0Smrg      printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
2561cdc920a0Smrg	     " 0x%x, 0x%x)\n",
2562cdc920a0Smrg	     srcX0, srcY0, srcX1, srcY1,
2563cdc920a0Smrg	     dstX0, dstY0, dstX1, dstY1,
2564cdc920a0Smrg	     mask, filter);
25654a49301eSmrg      if (colorReadRb) {
25664a49301eSmrg         const struct gl_renderbuffer_attachment *att;
25674a49301eSmrg
25684a49301eSmrg         att = find_attachment(readFb, colorReadRb);
2569cdc920a0Smrg         printf("  Src FBO %u  RB %u (%dx%d)  ",
2570cdc920a0Smrg		readFb->Name, colorReadRb->Name,
2571cdc920a0Smrg		colorReadRb->Width, colorReadRb->Height);
25724a49301eSmrg         if (att && att->Texture) {
2573cdc920a0Smrg            printf("Tex %u  tgt 0x%x  level %u  face %u",
2574cdc920a0Smrg		   att->Texture->Name,
2575cdc920a0Smrg		   att->Texture->Target,
2576cdc920a0Smrg		   att->TextureLevel,
2577cdc920a0Smrg		   att->CubeMapFace);
25784a49301eSmrg         }
2579cdc920a0Smrg         printf("\n");
25804a49301eSmrg
25814a49301eSmrg         att = find_attachment(drawFb, colorDrawRb);
2582cdc920a0Smrg         printf("  Dst FBO %u  RB %u (%dx%d)  ",
2583cdc920a0Smrg		drawFb->Name, colorDrawRb->Name,
2584cdc920a0Smrg		colorDrawRb->Width, colorDrawRb->Height);
25854a49301eSmrg         if (att && att->Texture) {
2586cdc920a0Smrg            printf("Tex %u  tgt 0x%x  level %u  face %u",
2587cdc920a0Smrg		   att->Texture->Name,
2588cdc920a0Smrg		   att->Texture->Target,
2589cdc920a0Smrg		   att->TextureLevel,
2590cdc920a0Smrg		   att->CubeMapFace);
25914a49301eSmrg         }
2592cdc920a0Smrg         printf("\n");
25934a49301eSmrg      }
25944a49301eSmrg   }
25954a49301eSmrg
25963464ebd5Sriastradh   if (!mask) {
25973464ebd5Sriastradh      return;
25983464ebd5Sriastradh   }
25993464ebd5Sriastradh
26007117f1b4Smrg   ASSERT(ctx->Driver.BlitFramebuffer);
26017117f1b4Smrg   ctx->Driver.BlitFramebuffer(ctx,
26027117f1b4Smrg                               srcX0, srcY0, srcX1, srcY1,
26037117f1b4Smrg                               dstX0, dstY0, dstX1, dstY1,
26047117f1b4Smrg                               mask, filter);
26057117f1b4Smrg}
26067117f1b4Smrg#endif /* FEATURE_EXT_framebuffer_blit */
26073464ebd5Sriastradh
26083464ebd5Sriastradh#if FEATURE_ARB_geometry_shader4
26093464ebd5Sriastradhvoid GLAPIENTRY
26103464ebd5Sriastradh_mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
26113464ebd5Sriastradh                            GLuint texture, GLint level)
26123464ebd5Sriastradh{
26133464ebd5Sriastradh   GET_CURRENT_CONTEXT(ctx);
26143464ebd5Sriastradh   _mesa_error(ctx, GL_INVALID_OPERATION,
26153464ebd5Sriastradh               "glFramebufferTextureARB "
26163464ebd5Sriastradh               "not implemented!");
26173464ebd5Sriastradh}
26183464ebd5Sriastradh
26193464ebd5Sriastradhvoid GLAPIENTRY
26203464ebd5Sriastradh_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
26213464ebd5Sriastradh                                GLuint texture, GLint level, GLenum face)
26223464ebd5Sriastradh{
26233464ebd5Sriastradh   GET_CURRENT_CONTEXT(ctx);
26243464ebd5Sriastradh   _mesa_error(ctx, GL_INVALID_OPERATION,
26253464ebd5Sriastradh               "glFramebufferTextureFaceARB "
26263464ebd5Sriastradh               "not implemented!");
26273464ebd5Sriastradh}
26283464ebd5Sriastradh#endif /* FEATURE_ARB_geometry_shader4 */
2629