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