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