fbobject.c revision cdc920a0
17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 3c1f859d4Smrg * Version: 7.1 47117f1b4Smrg * 5c1f859d4Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 64a49301eSmrg * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. 77117f1b4Smrg * 87117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 97117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 107117f1b4Smrg * to deal in the Software without restriction, including without limitation 117117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 127117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 137117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 147117f1b4Smrg * 157117f1b4Smrg * The above copyright notice and this permission notice shall be included 167117f1b4Smrg * in all copies or substantial portions of the Software. 177117f1b4Smrg * 187117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 197117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 207117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 217117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 227117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 237117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 247117f1b4Smrg */ 257117f1b4Smrg 267117f1b4Smrg 277117f1b4Smrg/* 284a49301eSmrg * GL_EXT/ARB_framebuffer_object extensions 294a49301eSmrg * 307117f1b4Smrg * Authors: 317117f1b4Smrg * Brian Paul 327117f1b4Smrg */ 337117f1b4Smrg 347117f1b4Smrg 35c1f859d4Smrg#include "buffers.h" 367117f1b4Smrg#include "context.h" 374a49301eSmrg#include "enums.h" 387117f1b4Smrg#include "fbobject.h" 394a49301eSmrg#include "formats.h" 407117f1b4Smrg#include "framebuffer.h" 417117f1b4Smrg#include "hash.h" 424a49301eSmrg#include "macros.h" 437117f1b4Smrg#include "renderbuffer.h" 447117f1b4Smrg#include "state.h" 457117f1b4Smrg#include "teximage.h" 467117f1b4Smrg#include "texobj.h" 474a49301eSmrg 484a49301eSmrg 494a49301eSmrg/** Set this to 1 to help debug FBO incompleteness problems */ 504a49301eSmrg#define DEBUG_FBO 0 514a49301eSmrg 524a49301eSmrg/** Set this to 1 to debug/log glBlitFramebuffer() calls */ 534a49301eSmrg#define DEBUG_BLIT 0 547117f1b4Smrg 557117f1b4Smrg 567117f1b4Smrg/** 577117f1b4Smrg * Notes: 587117f1b4Smrg * 597117f1b4Smrg * None of the GL_EXT_framebuffer_object functions are compiled into 607117f1b4Smrg * display lists. 617117f1b4Smrg */ 627117f1b4Smrg 637117f1b4Smrg 647117f1b4Smrg 657117f1b4Smrg/* 667117f1b4Smrg * When glGenRender/FramebuffersEXT() is called we insert pointers to 677117f1b4Smrg * these placeholder objects into the hash table. 687117f1b4Smrg * Later, when the object ID is first bound, we replace the placeholder 697117f1b4Smrg * with the real frame/renderbuffer. 707117f1b4Smrg */ 717117f1b4Smrgstatic struct gl_framebuffer DummyFramebuffer; 727117f1b4Smrgstatic struct gl_renderbuffer DummyRenderbuffer; 737117f1b4Smrg 747117f1b4Smrg 757117f1b4Smrg#define IS_CUBE_FACE(TARGET) \ 767117f1b4Smrg ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ 777117f1b4Smrg (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) 787117f1b4Smrg 797117f1b4Smrg 80c1f859d4Smrgstatic void 81c1f859d4Smrgdelete_dummy_renderbuffer(struct gl_renderbuffer *rb) 82c1f859d4Smrg{ 83c1f859d4Smrg /* no op */ 84c1f859d4Smrg} 85c1f859d4Smrg 86c1f859d4Smrgstatic void 87c1f859d4Smrgdelete_dummy_framebuffer(struct gl_framebuffer *fb) 88c1f859d4Smrg{ 89c1f859d4Smrg /* no op */ 90c1f859d4Smrg} 91c1f859d4Smrg 92c1f859d4Smrg 93c1f859d4Smrgvoid 94c1f859d4Smrg_mesa_init_fbobjects(GLcontext *ctx) 95c1f859d4Smrg{ 96c1f859d4Smrg DummyFramebuffer.Delete = delete_dummy_framebuffer; 97c1f859d4Smrg DummyRenderbuffer.Delete = delete_dummy_renderbuffer; 98c1f859d4Smrg} 99c1f859d4Smrg 100c1f859d4Smrg 1017117f1b4Smrg/** 1027117f1b4Smrg * Helper routine for getting a gl_renderbuffer. 1037117f1b4Smrg */ 1047117f1b4Smrgstruct gl_renderbuffer * 1057117f1b4Smrg_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id) 1067117f1b4Smrg{ 1077117f1b4Smrg struct gl_renderbuffer *rb; 1087117f1b4Smrg 1097117f1b4Smrg if (id == 0) 1107117f1b4Smrg return NULL; 1117117f1b4Smrg 1127117f1b4Smrg rb = (struct gl_renderbuffer *) 1137117f1b4Smrg _mesa_HashLookup(ctx->Shared->RenderBuffers, id); 1147117f1b4Smrg return rb; 1157117f1b4Smrg} 1167117f1b4Smrg 1177117f1b4Smrg 1187117f1b4Smrg/** 1197117f1b4Smrg * Helper routine for getting a gl_framebuffer. 1207117f1b4Smrg */ 1217117f1b4Smrgstruct gl_framebuffer * 1227117f1b4Smrg_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id) 1237117f1b4Smrg{ 1247117f1b4Smrg struct gl_framebuffer *fb; 1257117f1b4Smrg 1267117f1b4Smrg if (id == 0) 1277117f1b4Smrg return NULL; 1287117f1b4Smrg 1297117f1b4Smrg fb = (struct gl_framebuffer *) 1307117f1b4Smrg _mesa_HashLookup(ctx->Shared->FrameBuffers, id); 1317117f1b4Smrg return fb; 1327117f1b4Smrg} 1337117f1b4Smrg 1347117f1b4Smrg 1354a49301eSmrg/** 1364a49301eSmrg * Mark the given framebuffer as invalid. This will force the 1374a49301eSmrg * test for framebuffer completeness to be done before the framebuffer 1384a49301eSmrg * is used. 1394a49301eSmrg */ 1404a49301eSmrgstatic void 1414a49301eSmrginvalidate_framebuffer(struct gl_framebuffer *fb) 1424a49301eSmrg{ 1434a49301eSmrg fb->_Status = 0; /* "indeterminate" */ 1444a49301eSmrg} 1454a49301eSmrg 1464a49301eSmrg 1477117f1b4Smrg/** 1487117f1b4Smrg * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding 1497117f1b4Smrg * gl_renderbuffer_attachment object. 1504a49301eSmrg * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to 1514a49301eSmrg * the depth buffer attachment point. 1527117f1b4Smrg */ 1537117f1b4Smrgstruct gl_renderbuffer_attachment * 1547117f1b4Smrg_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb, 1557117f1b4Smrg GLenum attachment) 1567117f1b4Smrg{ 1577117f1b4Smrg GLuint i; 1587117f1b4Smrg 1597117f1b4Smrg switch (attachment) { 1607117f1b4Smrg case GL_COLOR_ATTACHMENT0_EXT: 1617117f1b4Smrg case GL_COLOR_ATTACHMENT1_EXT: 1627117f1b4Smrg case GL_COLOR_ATTACHMENT2_EXT: 1637117f1b4Smrg case GL_COLOR_ATTACHMENT3_EXT: 1647117f1b4Smrg case GL_COLOR_ATTACHMENT4_EXT: 1657117f1b4Smrg case GL_COLOR_ATTACHMENT5_EXT: 1667117f1b4Smrg case GL_COLOR_ATTACHMENT6_EXT: 1677117f1b4Smrg case GL_COLOR_ATTACHMENT7_EXT: 1687117f1b4Smrg case GL_COLOR_ATTACHMENT8_EXT: 1697117f1b4Smrg case GL_COLOR_ATTACHMENT9_EXT: 1707117f1b4Smrg case GL_COLOR_ATTACHMENT10_EXT: 1717117f1b4Smrg case GL_COLOR_ATTACHMENT11_EXT: 1727117f1b4Smrg case GL_COLOR_ATTACHMENT12_EXT: 1737117f1b4Smrg case GL_COLOR_ATTACHMENT13_EXT: 1747117f1b4Smrg case GL_COLOR_ATTACHMENT14_EXT: 1757117f1b4Smrg case GL_COLOR_ATTACHMENT15_EXT: 1767117f1b4Smrg i = attachment - GL_COLOR_ATTACHMENT0_EXT; 1777117f1b4Smrg if (i >= ctx->Const.MaxColorAttachments) { 1787117f1b4Smrg return NULL; 1797117f1b4Smrg } 1807117f1b4Smrg return &fb->Attachment[BUFFER_COLOR0 + i]; 1814a49301eSmrg case GL_DEPTH_STENCIL_ATTACHMENT: 1824a49301eSmrg /* fall-through */ 1837117f1b4Smrg case GL_DEPTH_ATTACHMENT_EXT: 1847117f1b4Smrg return &fb->Attachment[BUFFER_DEPTH]; 1857117f1b4Smrg case GL_STENCIL_ATTACHMENT_EXT: 1867117f1b4Smrg return &fb->Attachment[BUFFER_STENCIL]; 1877117f1b4Smrg default: 1887117f1b4Smrg return NULL; 1897117f1b4Smrg } 1907117f1b4Smrg} 1917117f1b4Smrg 1927117f1b4Smrg 1937117f1b4Smrg/** 1947117f1b4Smrg * Remove any texture or renderbuffer attached to the given attachment 1957117f1b4Smrg * point. Update reference counts, etc. 1967117f1b4Smrg */ 1977117f1b4Smrgvoid 1987117f1b4Smrg_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att) 1997117f1b4Smrg{ 2007117f1b4Smrg if (att->Type == GL_TEXTURE) { 2017117f1b4Smrg ASSERT(att->Texture); 2027117f1b4Smrg if (ctx->Driver.FinishRenderTexture) { 2034a49301eSmrg /* tell driver that we're done rendering to this texture. */ 2047117f1b4Smrg ctx->Driver.FinishRenderTexture(ctx, att); 2057117f1b4Smrg } 2067117f1b4Smrg _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ 2077117f1b4Smrg ASSERT(!att->Texture); 2087117f1b4Smrg } 2097117f1b4Smrg if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { 2107117f1b4Smrg ASSERT(!att->Texture); 2117117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ 2127117f1b4Smrg ASSERT(!att->Renderbuffer); 2137117f1b4Smrg } 2147117f1b4Smrg att->Type = GL_NONE; 2157117f1b4Smrg att->Complete = GL_TRUE; 2167117f1b4Smrg} 2177117f1b4Smrg 2187117f1b4Smrg 2197117f1b4Smrg/** 2207117f1b4Smrg * Bind a texture object to an attachment point. 2217117f1b4Smrg * The previous binding, if any, will be removed first. 2227117f1b4Smrg */ 2237117f1b4Smrgvoid 2247117f1b4Smrg_mesa_set_texture_attachment(GLcontext *ctx, 2257117f1b4Smrg struct gl_framebuffer *fb, 2267117f1b4Smrg struct gl_renderbuffer_attachment *att, 2277117f1b4Smrg struct gl_texture_object *texObj, 2287117f1b4Smrg GLenum texTarget, GLuint level, GLuint zoffset) 2297117f1b4Smrg{ 2307117f1b4Smrg if (att->Texture == texObj) { 2317117f1b4Smrg /* re-attaching same texture */ 2327117f1b4Smrg ASSERT(att->Type == GL_TEXTURE); 2334a49301eSmrg if (ctx->Driver.FinishRenderTexture) 2344a49301eSmrg ctx->Driver.FinishRenderTexture(ctx, att); 2357117f1b4Smrg } 2367117f1b4Smrg else { 2377117f1b4Smrg /* new attachment */ 2384a49301eSmrg if (ctx->Driver.FinishRenderTexture && att->Texture) 2394a49301eSmrg ctx->Driver.FinishRenderTexture(ctx, att); 2407117f1b4Smrg _mesa_remove_attachment(ctx, att); 2417117f1b4Smrg att->Type = GL_TEXTURE; 2427117f1b4Smrg assert(!att->Texture); 2437117f1b4Smrg _mesa_reference_texobj(&att->Texture, texObj); 2447117f1b4Smrg } 2457117f1b4Smrg 2467117f1b4Smrg /* always update these fields */ 2477117f1b4Smrg att->TextureLevel = level; 2484a49301eSmrg att->CubeMapFace = _mesa_tex_target_to_face(texTarget); 2497117f1b4Smrg att->Zoffset = zoffset; 2507117f1b4Smrg att->Complete = GL_FALSE; 2517117f1b4Smrg 2527117f1b4Smrg if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { 2537117f1b4Smrg ctx->Driver.RenderTexture(ctx, fb, att); 2547117f1b4Smrg } 2554a49301eSmrg 2564a49301eSmrg invalidate_framebuffer(fb); 2577117f1b4Smrg} 2587117f1b4Smrg 2597117f1b4Smrg 2607117f1b4Smrg/** 2617117f1b4Smrg * Bind a renderbuffer to an attachment point. 2627117f1b4Smrg * The previous binding, if any, will be removed first. 2637117f1b4Smrg */ 2647117f1b4Smrgvoid 2657117f1b4Smrg_mesa_set_renderbuffer_attachment(GLcontext *ctx, 2667117f1b4Smrg struct gl_renderbuffer_attachment *att, 2677117f1b4Smrg struct gl_renderbuffer *rb) 2687117f1b4Smrg{ 2697117f1b4Smrg /* XXX check if re-doing same attachment, exit early */ 2707117f1b4Smrg _mesa_remove_attachment(ctx, att); 2717117f1b4Smrg att->Type = GL_RENDERBUFFER_EXT; 2727117f1b4Smrg att->Texture = NULL; /* just to be safe */ 2737117f1b4Smrg att->Complete = GL_FALSE; 2747117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 2757117f1b4Smrg} 2767117f1b4Smrg 2777117f1b4Smrg 2787117f1b4Smrg/** 2797117f1b4Smrg * Fallback for ctx->Driver.FramebufferRenderbuffer() 2807117f1b4Smrg * Attach a renderbuffer object to a framebuffer object. 2817117f1b4Smrg */ 2827117f1b4Smrgvoid 2837117f1b4Smrg_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, 2847117f1b4Smrg GLenum attachment, struct gl_renderbuffer *rb) 2857117f1b4Smrg{ 2867117f1b4Smrg struct gl_renderbuffer_attachment *att; 2877117f1b4Smrg 2887117f1b4Smrg _glthread_LOCK_MUTEX(fb->Mutex); 2897117f1b4Smrg 2907117f1b4Smrg att = _mesa_get_attachment(ctx, fb, attachment); 2917117f1b4Smrg ASSERT(att); 2927117f1b4Smrg if (rb) { 2937117f1b4Smrg _mesa_set_renderbuffer_attachment(ctx, att, rb); 2944a49301eSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 2954a49301eSmrg /* do stencil attachment here (depth already done above) */ 2964a49301eSmrg att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); 2974a49301eSmrg assert(att); 2984a49301eSmrg _mesa_set_renderbuffer_attachment(ctx, att, rb); 2994a49301eSmrg } 3007117f1b4Smrg } 3017117f1b4Smrg else { 3027117f1b4Smrg _mesa_remove_attachment(ctx, att); 3037117f1b4Smrg } 3047117f1b4Smrg 3054a49301eSmrg invalidate_framebuffer(fb); 3064a49301eSmrg 3077117f1b4Smrg _glthread_UNLOCK_MUTEX(fb->Mutex); 3087117f1b4Smrg} 3097117f1b4Smrg 3107117f1b4Smrg 3114a49301eSmrg/** 3124a49301eSmrg * For debug only. 3134a49301eSmrg */ 3144a49301eSmrgstatic void 3154a49301eSmrgatt_incomplete(const char *msg) 3164a49301eSmrg{ 3174a49301eSmrg#if DEBUG_FBO 3184a49301eSmrg _mesa_debug(NULL, "attachment incomplete: %s\n", msg); 3194a49301eSmrg#else 3204a49301eSmrg (void) msg; 3214a49301eSmrg#endif 3224a49301eSmrg} 3234a49301eSmrg 3244a49301eSmrg 3254a49301eSmrg/** 3264a49301eSmrg * For debug only. 3274a49301eSmrg */ 3284a49301eSmrgstatic void 3294a49301eSmrgfbo_incomplete(const char *msg, int index) 3304a49301eSmrg{ 3314a49301eSmrg#if DEBUG_FBO 3324a49301eSmrg _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); 3334a49301eSmrg#else 3344a49301eSmrg (void) msg; 3354a49301eSmrg (void) index; 3364a49301eSmrg#endif 3374a49301eSmrg} 3384a49301eSmrg 3394a49301eSmrg 3404a49301eSmrg 3414a49301eSmrg 3427117f1b4Smrg/** 3437117f1b4Smrg * Test if an attachment point is complete and update its Complete field. 3447117f1b4Smrg * \param format if GL_COLOR, this is a color attachment point, 3457117f1b4Smrg * if GL_DEPTH, this is a depth component attachment point, 3467117f1b4Smrg * if GL_STENCIL, this is a stencil component attachment point. 3477117f1b4Smrg */ 3487117f1b4Smrgstatic void 3497117f1b4Smrgtest_attachment_completeness(const GLcontext *ctx, GLenum format, 3507117f1b4Smrg struct gl_renderbuffer_attachment *att) 3517117f1b4Smrg{ 3527117f1b4Smrg assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); 3537117f1b4Smrg 3547117f1b4Smrg /* assume complete */ 3557117f1b4Smrg att->Complete = GL_TRUE; 3567117f1b4Smrg 3577117f1b4Smrg /* Look for reasons why the attachment might be incomplete */ 3587117f1b4Smrg if (att->Type == GL_TEXTURE) { 3597117f1b4Smrg const struct gl_texture_object *texObj = att->Texture; 3607117f1b4Smrg struct gl_texture_image *texImage; 3614a49301eSmrg GLenum baseFormat; 3627117f1b4Smrg 3637117f1b4Smrg if (!texObj) { 3644a49301eSmrg att_incomplete("no texobj"); 3657117f1b4Smrg att->Complete = GL_FALSE; 3667117f1b4Smrg return; 3677117f1b4Smrg } 3687117f1b4Smrg 3697117f1b4Smrg texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; 3707117f1b4Smrg if (!texImage) { 3714a49301eSmrg att_incomplete("no teximage"); 3727117f1b4Smrg att->Complete = GL_FALSE; 3737117f1b4Smrg return; 3747117f1b4Smrg } 3757117f1b4Smrg if (texImage->Width < 1 || texImage->Height < 1) { 3764a49301eSmrg att_incomplete("teximage width/height=0"); 377cdc920a0Smrg printf("texobj = %u\n", texObj->Name); 378cdc920a0Smrg printf("level = %d\n", att->TextureLevel); 3797117f1b4Smrg att->Complete = GL_FALSE; 3807117f1b4Smrg return; 3817117f1b4Smrg } 3827117f1b4Smrg if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { 3834a49301eSmrg att_incomplete("bad z offset"); 3847117f1b4Smrg att->Complete = GL_FALSE; 3857117f1b4Smrg return; 3867117f1b4Smrg } 3877117f1b4Smrg 3884a49301eSmrg baseFormat = _mesa_get_format_base_format(texImage->TexFormat); 3894a49301eSmrg 3907117f1b4Smrg if (format == GL_COLOR) { 3914a49301eSmrg if (baseFormat != GL_RGB && 3924a49301eSmrg baseFormat != GL_RGBA) { 3934a49301eSmrg att_incomplete("bad format"); 3944a49301eSmrg att->Complete = GL_FALSE; 3954a49301eSmrg return; 3964a49301eSmrg } 3974a49301eSmrg if (_mesa_is_format_compressed(texImage->TexFormat)) { 3984a49301eSmrg att_incomplete("compressed internalformat"); 3997117f1b4Smrg att->Complete = GL_FALSE; 4007117f1b4Smrg return; 4017117f1b4Smrg } 4027117f1b4Smrg } 4037117f1b4Smrg else if (format == GL_DEPTH) { 4044a49301eSmrg if (baseFormat == GL_DEPTH_COMPONENT) { 4057117f1b4Smrg /* OK */ 4067117f1b4Smrg } 4077117f1b4Smrg else if (ctx->Extensions.EXT_packed_depth_stencil && 408c7037ccdSmrg ctx->Extensions.ARB_depth_texture && 4094a49301eSmrg baseFormat == GL_DEPTH_STENCIL_EXT) { 4107117f1b4Smrg /* OK */ 4117117f1b4Smrg } 4127117f1b4Smrg else { 4137117f1b4Smrg att->Complete = GL_FALSE; 4144a49301eSmrg att_incomplete("bad depth format"); 4157117f1b4Smrg return; 4167117f1b4Smrg } 4177117f1b4Smrg } 4187117f1b4Smrg else { 419c7037ccdSmrg ASSERT(format == GL_STENCIL); 420c7037ccdSmrg if (ctx->Extensions.EXT_packed_depth_stencil && 421c7037ccdSmrg ctx->Extensions.ARB_depth_texture && 4224a49301eSmrg baseFormat == GL_DEPTH_STENCIL_EXT) { 423c7037ccdSmrg /* OK */ 424c7037ccdSmrg } 425c7037ccdSmrg else { 426c7037ccdSmrg /* no such thing as stencil-only textures */ 4274a49301eSmrg att_incomplete("illegal stencil texture"); 428c7037ccdSmrg att->Complete = GL_FALSE; 429c7037ccdSmrg return; 430c7037ccdSmrg } 4317117f1b4Smrg } 4327117f1b4Smrg } 4337117f1b4Smrg else if (att->Type == GL_RENDERBUFFER_EXT) { 4344a49301eSmrg const GLenum baseFormat = 4354a49301eSmrg _mesa_get_format_base_format(att->Renderbuffer->Format); 4364a49301eSmrg 4377117f1b4Smrg ASSERT(att->Renderbuffer); 4387117f1b4Smrg if (!att->Renderbuffer->InternalFormat || 4397117f1b4Smrg att->Renderbuffer->Width < 1 || 4407117f1b4Smrg att->Renderbuffer->Height < 1) { 4414a49301eSmrg att_incomplete("0x0 renderbuffer"); 4427117f1b4Smrg att->Complete = GL_FALSE; 4437117f1b4Smrg return; 4447117f1b4Smrg } 4457117f1b4Smrg if (format == GL_COLOR) { 4464a49301eSmrg if (baseFormat != GL_RGB && 4474a49301eSmrg baseFormat != GL_RGBA) { 4484a49301eSmrg att_incomplete("bad renderbuffer color format"); 4497117f1b4Smrg att->Complete = GL_FALSE; 4507117f1b4Smrg return; 4517117f1b4Smrg } 4527117f1b4Smrg } 4537117f1b4Smrg else if (format == GL_DEPTH) { 4544a49301eSmrg if (baseFormat == GL_DEPTH_COMPONENT) { 4557117f1b4Smrg /* OK */ 4567117f1b4Smrg } 4577117f1b4Smrg else if (ctx->Extensions.EXT_packed_depth_stencil && 4584a49301eSmrg baseFormat == GL_DEPTH_STENCIL_EXT) { 4597117f1b4Smrg /* OK */ 4607117f1b4Smrg } 4617117f1b4Smrg else { 4624a49301eSmrg att_incomplete("bad renderbuffer depth format"); 4637117f1b4Smrg att->Complete = GL_FALSE; 4647117f1b4Smrg return; 4657117f1b4Smrg } 4667117f1b4Smrg } 4677117f1b4Smrg else { 4687117f1b4Smrg assert(format == GL_STENCIL); 4694a49301eSmrg if (baseFormat == GL_STENCIL_INDEX) { 4707117f1b4Smrg /* OK */ 4717117f1b4Smrg } 4727117f1b4Smrg else if (ctx->Extensions.EXT_packed_depth_stencil && 4734a49301eSmrg baseFormat == GL_DEPTH_STENCIL_EXT) { 4747117f1b4Smrg /* OK */ 4757117f1b4Smrg } 4767117f1b4Smrg else { 4777117f1b4Smrg att->Complete = GL_FALSE; 4784a49301eSmrg att_incomplete("bad renderbuffer stencil format"); 4797117f1b4Smrg return; 4807117f1b4Smrg } 4817117f1b4Smrg } 4827117f1b4Smrg } 4837117f1b4Smrg else { 4847117f1b4Smrg ASSERT(att->Type == GL_NONE); 4857117f1b4Smrg /* complete */ 4867117f1b4Smrg return; 4877117f1b4Smrg } 4887117f1b4Smrg} 4897117f1b4Smrg 4907117f1b4Smrg 4917117f1b4Smrg/** 4927117f1b4Smrg * Test if the given framebuffer object is complete and update its 4937117f1b4Smrg * Status field with the results. 4944a49301eSmrg * Calls the ctx->Driver.ValidateFramebuffer() function to allow the 4954a49301eSmrg * driver to make hardware-specific validation/completeness checks. 4967117f1b4Smrg * Also update the framebuffer's Width and Height fields if the 4977117f1b4Smrg * framebuffer is complete. 4987117f1b4Smrg */ 4997117f1b4Smrgvoid 5007117f1b4Smrg_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) 5017117f1b4Smrg{ 5024a49301eSmrg GLuint numImages; 5034a49301eSmrg GLenum intFormat = GL_NONE; /* color buffers' internal format */ 5044a49301eSmrg GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; 5054a49301eSmrg GLint numSamples = -1; 5067117f1b4Smrg GLint i; 5077117f1b4Smrg GLuint j; 5087117f1b4Smrg 5097117f1b4Smrg assert(fb->Name != 0); 5107117f1b4Smrg 5117117f1b4Smrg numImages = 0; 5127117f1b4Smrg fb->Width = 0; 5137117f1b4Smrg fb->Height = 0; 5147117f1b4Smrg 5154a49301eSmrg /* Start at -2 to more easily loop over all attachment points. 5164a49301eSmrg * -2: depth buffer 5174a49301eSmrg * -1: stencil buffer 5184a49301eSmrg * >=0: color buffer 5194a49301eSmrg */ 5207117f1b4Smrg for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { 5217117f1b4Smrg struct gl_renderbuffer_attachment *att; 5227117f1b4Smrg GLenum f; 5237117f1b4Smrg 5244a49301eSmrg /* 5254a49301eSmrg * XXX for ARB_fbo, only check color buffers that are named by 5264a49301eSmrg * GL_READ_BUFFER and GL_DRAW_BUFFERi. 5274a49301eSmrg */ 5284a49301eSmrg 5294a49301eSmrg /* check for attachment completeness 5304a49301eSmrg */ 5317117f1b4Smrg if (i == -2) { 5327117f1b4Smrg att = &fb->Attachment[BUFFER_DEPTH]; 5337117f1b4Smrg test_attachment_completeness(ctx, GL_DEPTH, att); 5347117f1b4Smrg if (!att->Complete) { 5357117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 5367117f1b4Smrg fbo_incomplete("depth attachment incomplete", -1); 5377117f1b4Smrg return; 5387117f1b4Smrg } 5397117f1b4Smrg } 5407117f1b4Smrg else if (i == -1) { 5417117f1b4Smrg att = &fb->Attachment[BUFFER_STENCIL]; 5427117f1b4Smrg test_attachment_completeness(ctx, GL_STENCIL, att); 5437117f1b4Smrg if (!att->Complete) { 5447117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 5457117f1b4Smrg fbo_incomplete("stencil attachment incomplete", -1); 5467117f1b4Smrg return; 5477117f1b4Smrg } 5487117f1b4Smrg } 5497117f1b4Smrg else { 5507117f1b4Smrg att = &fb->Attachment[BUFFER_COLOR0 + i]; 5517117f1b4Smrg test_attachment_completeness(ctx, GL_COLOR, att); 5527117f1b4Smrg if (!att->Complete) { 5537117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 5547117f1b4Smrg fbo_incomplete("color attachment incomplete", i); 5557117f1b4Smrg return; 5567117f1b4Smrg } 5577117f1b4Smrg } 5587117f1b4Smrg 5594a49301eSmrg /* get width, height, format of the renderbuffer/texture 5604a49301eSmrg */ 5617117f1b4Smrg if (att->Type == GL_TEXTURE) { 5627117f1b4Smrg const struct gl_texture_image *texImg 5637117f1b4Smrg = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 5644a49301eSmrg minWidth = MIN2(minWidth, texImg->Width); 5654a49301eSmrg maxWidth = MAX2(maxWidth, texImg->Width); 5664a49301eSmrg minHeight = MIN2(minHeight, texImg->Height); 5674a49301eSmrg maxHeight = MAX2(maxHeight, texImg->Height); 5687117f1b4Smrg f = texImg->_BaseFormat; 5697117f1b4Smrg numImages++; 5707117f1b4Smrg if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT 5717117f1b4Smrg && f != GL_DEPTH_STENCIL_EXT) { 5727117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 5737117f1b4Smrg fbo_incomplete("texture attachment incomplete", -1); 5747117f1b4Smrg return; 5757117f1b4Smrg } 5767117f1b4Smrg } 5777117f1b4Smrg else if (att->Type == GL_RENDERBUFFER_EXT) { 5784a49301eSmrg minWidth = MIN2(minWidth, att->Renderbuffer->Width); 5794a49301eSmrg maxWidth = MAX2(minWidth, att->Renderbuffer->Width); 5804a49301eSmrg minHeight = MIN2(minHeight, att->Renderbuffer->Height); 5814a49301eSmrg maxHeight = MAX2(minHeight, att->Renderbuffer->Height); 5827117f1b4Smrg f = att->Renderbuffer->InternalFormat; 5837117f1b4Smrg numImages++; 5847117f1b4Smrg } 5857117f1b4Smrg else { 5867117f1b4Smrg assert(att->Type == GL_NONE); 5877117f1b4Smrg continue; 5887117f1b4Smrg } 5897117f1b4Smrg 5904a49301eSmrg if (numSamples < 0) { 5914a49301eSmrg /* first buffer */ 5924a49301eSmrg numSamples = att->Renderbuffer->NumSamples; 5934a49301eSmrg } 5944a49301eSmrg 5954a49301eSmrg /* Error-check width, height, format, samples 5964a49301eSmrg */ 5977117f1b4Smrg if (numImages == 1) { 5984a49301eSmrg /* save format, num samples */ 5994a49301eSmrg if (i >= 0) { 6007117f1b4Smrg intFormat = f; 6014a49301eSmrg } 6027117f1b4Smrg } 6037117f1b4Smrg else { 6044a49301eSmrg if (!ctx->Extensions.ARB_framebuffer_object) { 6054a49301eSmrg /* check that width, height, format are same */ 6064a49301eSmrg if (minWidth != maxWidth || minHeight != maxHeight) { 6074a49301eSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 6084a49301eSmrg fbo_incomplete("width or height mismatch", -1); 6094a49301eSmrg return; 6104a49301eSmrg } 6114a49301eSmrg /* check that all color buffer have same format */ 6124a49301eSmrg if (intFormat != GL_NONE && f != intFormat) { 6134a49301eSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 6144a49301eSmrg fbo_incomplete("format mismatch", -1); 6154a49301eSmrg return; 6164a49301eSmrg } 6177117f1b4Smrg } 6184a49301eSmrg if (att->Renderbuffer && 6194a49301eSmrg att->Renderbuffer->NumSamples != numSamples) { 6204a49301eSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 6214a49301eSmrg fbo_incomplete("inconsistant number of samples", i); 6227117f1b4Smrg return; 6234a49301eSmrg } 6244a49301eSmrg 6257117f1b4Smrg } 6267117f1b4Smrg } 6277117f1b4Smrg 628c1f859d4Smrg#ifndef FEATURE_OES_framebuffer_object 6297117f1b4Smrg /* Check that all DrawBuffers are present */ 6307117f1b4Smrg for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { 6317117f1b4Smrg if (fb->ColorDrawBuffer[j] != GL_NONE) { 6327117f1b4Smrg const struct gl_renderbuffer_attachment *att 6337117f1b4Smrg = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); 6347117f1b4Smrg assert(att); 6357117f1b4Smrg if (att->Type == GL_NONE) { 6367117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; 6377117f1b4Smrg fbo_incomplete("missing drawbuffer", j); 6387117f1b4Smrg return; 6397117f1b4Smrg } 6407117f1b4Smrg } 6417117f1b4Smrg } 6427117f1b4Smrg 6437117f1b4Smrg /* Check that the ReadBuffer is present */ 6447117f1b4Smrg if (fb->ColorReadBuffer != GL_NONE) { 6457117f1b4Smrg const struct gl_renderbuffer_attachment *att 6467117f1b4Smrg = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); 6477117f1b4Smrg assert(att); 6487117f1b4Smrg if (att->Type == GL_NONE) { 6497117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; 6507117f1b4Smrg fbo_incomplete("missing readbuffer", -1); 6517117f1b4Smrg return; 6527117f1b4Smrg } 6537117f1b4Smrg } 6544a49301eSmrg#else 6554a49301eSmrg (void) j; 656c1f859d4Smrg#endif 6577117f1b4Smrg 6587117f1b4Smrg if (numImages == 0) { 6597117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 6607117f1b4Smrg fbo_incomplete("no attachments", -1); 6617117f1b4Smrg return; 6627117f1b4Smrg } 6637117f1b4Smrg 6644a49301eSmrg /* Provisionally set status = COMPLETE ... */ 6657117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 6664a49301eSmrg 6674a49301eSmrg /* ... but the driver may say the FB is incomplete. 6684a49301eSmrg * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED 6694a49301eSmrg * if anything. 6704a49301eSmrg */ 6714a49301eSmrg if (ctx->Driver.ValidateFramebuffer) { 6724a49301eSmrg ctx->Driver.ValidateFramebuffer(ctx, fb); 6734a49301eSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 6744a49301eSmrg fbo_incomplete("driver marked FBO as incomplete", -1); 6754a49301eSmrg } 6764a49301eSmrg } 6774a49301eSmrg 6784a49301eSmrg if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) { 6794a49301eSmrg /* 6804a49301eSmrg * Note that if ARB_framebuffer_object is supported and the attached 6814a49301eSmrg * renderbuffers/textures are different sizes, the framebuffer 6824a49301eSmrg * width/height will be set to the smallest width/height. 6834a49301eSmrg */ 6844a49301eSmrg fb->Width = minWidth; 6854a49301eSmrg fb->Height = minHeight; 6864a49301eSmrg 6874a49301eSmrg /* finally, update the visual info for the framebuffer */ 6884a49301eSmrg _mesa_update_framebuffer_visual(fb); 6894a49301eSmrg } 6907117f1b4Smrg} 6917117f1b4Smrg 6927117f1b4Smrg 6937117f1b4SmrgGLboolean GLAPIENTRY 6947117f1b4Smrg_mesa_IsRenderbufferEXT(GLuint renderbuffer) 6957117f1b4Smrg{ 6967117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 6977117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 6987117f1b4Smrg if (renderbuffer) { 6997117f1b4Smrg struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 7007117f1b4Smrg if (rb != NULL && rb != &DummyRenderbuffer) 7017117f1b4Smrg return GL_TRUE; 7027117f1b4Smrg } 7037117f1b4Smrg return GL_FALSE; 7047117f1b4Smrg} 7057117f1b4Smrg 7067117f1b4Smrg 7077117f1b4Smrgvoid GLAPIENTRY 7087117f1b4Smrg_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 7097117f1b4Smrg{ 7107117f1b4Smrg struct gl_renderbuffer *newRb; 7117117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 7127117f1b4Smrg 7137117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 7147117f1b4Smrg 7157117f1b4Smrg if (target != GL_RENDERBUFFER_EXT) { 7164a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); 7177117f1b4Smrg return; 7187117f1b4Smrg } 7197117f1b4Smrg 7204a49301eSmrg /* No need to flush here since the render buffer binding has no 7214a49301eSmrg * effect on rendering state. 7227117f1b4Smrg */ 7237117f1b4Smrg 7247117f1b4Smrg if (renderbuffer) { 7257117f1b4Smrg newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 7267117f1b4Smrg if (newRb == &DummyRenderbuffer) { 7277117f1b4Smrg /* ID was reserved, but no real renderbuffer object made yet */ 7287117f1b4Smrg newRb = NULL; 7297117f1b4Smrg } 7304a49301eSmrg else if (!newRb && ctx->Extensions.ARB_framebuffer_object) { 7314a49301eSmrg /* All RB IDs must be Gen'd */ 7324a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); 7334a49301eSmrg return; 7344a49301eSmrg } 7354a49301eSmrg 7367117f1b4Smrg if (!newRb) { 7377117f1b4Smrg /* create new renderbuffer object */ 7387117f1b4Smrg newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); 7397117f1b4Smrg if (!newRb) { 7407117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); 7417117f1b4Smrg return; 7427117f1b4Smrg } 7437117f1b4Smrg ASSERT(newRb->AllocStorage); 7447117f1b4Smrg _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); 7457117f1b4Smrg newRb->RefCount = 1; /* referenced by hash table */ 7467117f1b4Smrg } 7477117f1b4Smrg } 7487117f1b4Smrg else { 7497117f1b4Smrg newRb = NULL; 7507117f1b4Smrg } 7517117f1b4Smrg 7527117f1b4Smrg ASSERT(newRb != &DummyRenderbuffer); 7537117f1b4Smrg 7547117f1b4Smrg _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); 7557117f1b4Smrg} 7567117f1b4Smrg 7577117f1b4Smrg 7584a49301eSmrg/** 7594a49301eSmrg * If the given renderbuffer is anywhere attached to the framebuffer, detach 7604a49301eSmrg * the renderbuffer. 7614a49301eSmrg * This is used when a renderbuffer object is deleted. 7624a49301eSmrg * The spec calls for unbinding. 7634a49301eSmrg */ 7644a49301eSmrgstatic void 7654a49301eSmrgdetach_renderbuffer(GLcontext *ctx, 7664a49301eSmrg struct gl_framebuffer *fb, 7674a49301eSmrg struct gl_renderbuffer *rb) 7684a49301eSmrg{ 7694a49301eSmrg GLuint i; 7704a49301eSmrg for (i = 0; i < BUFFER_COUNT; i++) { 7714a49301eSmrg if (fb->Attachment[i].Renderbuffer == rb) { 7724a49301eSmrg _mesa_remove_attachment(ctx, &fb->Attachment[i]); 7734a49301eSmrg } 7744a49301eSmrg } 7754a49301eSmrg invalidate_framebuffer(fb); 7764a49301eSmrg} 7774a49301eSmrg 7784a49301eSmrg 7797117f1b4Smrgvoid GLAPIENTRY 7807117f1b4Smrg_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) 7817117f1b4Smrg{ 7827117f1b4Smrg GLint i; 7837117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 7847117f1b4Smrg 7857117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 7867117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 7877117f1b4Smrg 7887117f1b4Smrg for (i = 0; i < n; i++) { 7897117f1b4Smrg if (renderbuffers[i] > 0) { 7907117f1b4Smrg struct gl_renderbuffer *rb; 7917117f1b4Smrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); 7927117f1b4Smrg if (rb) { 7937117f1b4Smrg /* check if deleting currently bound renderbuffer object */ 7947117f1b4Smrg if (rb == ctx->CurrentRenderbuffer) { 7957117f1b4Smrg /* bind default */ 7967117f1b4Smrg ASSERT(rb->RefCount >= 2); 7977117f1b4Smrg _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 7987117f1b4Smrg } 7997117f1b4Smrg 8004a49301eSmrg if (ctx->DrawBuffer->Name) { 8014a49301eSmrg detach_renderbuffer(ctx, ctx->DrawBuffer, rb); 8024a49301eSmrg } 8034a49301eSmrg if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) { 8044a49301eSmrg detach_renderbuffer(ctx, ctx->ReadBuffer, rb); 8054a49301eSmrg } 8064a49301eSmrg 8077117f1b4Smrg /* Remove from hash table immediately, to free the ID. 8087117f1b4Smrg * But the object will not be freed until it's no longer 8097117f1b4Smrg * referenced anywhere else. 8107117f1b4Smrg */ 8117117f1b4Smrg _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); 8127117f1b4Smrg 8137117f1b4Smrg if (rb != &DummyRenderbuffer) { 8147117f1b4Smrg /* no longer referenced by hash table */ 8157117f1b4Smrg _mesa_reference_renderbuffer(&rb, NULL); 8167117f1b4Smrg } 8177117f1b4Smrg } 8187117f1b4Smrg } 8197117f1b4Smrg } 8207117f1b4Smrg} 8217117f1b4Smrg 8227117f1b4Smrg 8237117f1b4Smrgvoid GLAPIENTRY 8247117f1b4Smrg_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) 8257117f1b4Smrg{ 8267117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 8277117f1b4Smrg GLuint first; 8287117f1b4Smrg GLint i; 8297117f1b4Smrg 8307117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 8317117f1b4Smrg 8327117f1b4Smrg if (n < 0) { 8337117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); 8347117f1b4Smrg return; 8357117f1b4Smrg } 8367117f1b4Smrg 8377117f1b4Smrg if (!renderbuffers) 8387117f1b4Smrg return; 8397117f1b4Smrg 8407117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); 8417117f1b4Smrg 8427117f1b4Smrg for (i = 0; i < n; i++) { 8437117f1b4Smrg GLuint name = first + i; 8447117f1b4Smrg renderbuffers[i] = name; 8457117f1b4Smrg /* insert dummy placeholder into hash table */ 8467117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 8477117f1b4Smrg _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); 8487117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 8497117f1b4Smrg } 8507117f1b4Smrg} 8517117f1b4Smrg 8527117f1b4Smrg 8537117f1b4Smrg/** 8547117f1b4Smrg * Given an internal format token for a render buffer, return the 8557117f1b4Smrg * corresponding base format. 8567117f1b4Smrg * This is very similar to _mesa_base_tex_format() but the set of valid 8577117f1b4Smrg * internal formats is somewhat different. 8587117f1b4Smrg * 8597117f1b4Smrg * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT 8607117f1b4Smrg * GL_DEPTH_STENCIL_EXT or zero if error. 861cdc920a0Smrg * 862cdc920a0Smrg * XXX in the future when we support red-only and red-green formats 863cdc920a0Smrg * we'll also return GL_RED and GL_RG. 8647117f1b4Smrg */ 8657117f1b4SmrgGLenum 8667117f1b4Smrg_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat) 8677117f1b4Smrg{ 8687117f1b4Smrg switch (internalFormat) { 8697117f1b4Smrg case GL_RGB: 8707117f1b4Smrg case GL_R3_G3_B2: 8717117f1b4Smrg case GL_RGB4: 8727117f1b4Smrg case GL_RGB5: 8737117f1b4Smrg case GL_RGB8: 8747117f1b4Smrg case GL_RGB10: 8757117f1b4Smrg case GL_RGB12: 8767117f1b4Smrg case GL_RGB16: 8777117f1b4Smrg return GL_RGB; 8787117f1b4Smrg case GL_RGBA: 8797117f1b4Smrg case GL_RGBA2: 8807117f1b4Smrg case GL_RGBA4: 8817117f1b4Smrg case GL_RGB5_A1: 8827117f1b4Smrg case GL_RGBA8: 8837117f1b4Smrg case GL_RGB10_A2: 8847117f1b4Smrg case GL_RGBA12: 8857117f1b4Smrg case GL_RGBA16: 8867117f1b4Smrg return GL_RGBA; 8877117f1b4Smrg case GL_STENCIL_INDEX: 8887117f1b4Smrg case GL_STENCIL_INDEX1_EXT: 8897117f1b4Smrg case GL_STENCIL_INDEX4_EXT: 8907117f1b4Smrg case GL_STENCIL_INDEX8_EXT: 8917117f1b4Smrg case GL_STENCIL_INDEX16_EXT: 8927117f1b4Smrg return GL_STENCIL_INDEX; 8937117f1b4Smrg case GL_DEPTH_COMPONENT: 8947117f1b4Smrg case GL_DEPTH_COMPONENT16: 8957117f1b4Smrg case GL_DEPTH_COMPONENT24: 8967117f1b4Smrg case GL_DEPTH_COMPONENT32: 8977117f1b4Smrg return GL_DEPTH_COMPONENT; 8987117f1b4Smrg case GL_DEPTH_STENCIL_EXT: 8997117f1b4Smrg case GL_DEPTH24_STENCIL8_EXT: 9007117f1b4Smrg if (ctx->Extensions.EXT_packed_depth_stencil) 9017117f1b4Smrg return GL_DEPTH_STENCIL_EXT; 9027117f1b4Smrg else 9037117f1b4Smrg return 0; 9047117f1b4Smrg /* XXX add floating point formats eventually */ 9057117f1b4Smrg default: 9067117f1b4Smrg return 0; 9077117f1b4Smrg } 9087117f1b4Smrg} 9097117f1b4Smrg 9107117f1b4Smrg 9114a49301eSmrg/** sentinal value, see below */ 9124a49301eSmrg#define NO_SAMPLES 1000 9134a49301eSmrg 9144a49301eSmrg 9154a49301eSmrg/** 9164a49301eSmrg * Helper function used by _mesa_RenderbufferStorageEXT() and 9174a49301eSmrg * _mesa_RenderbufferStorageMultisample(). 9184a49301eSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT(). 9194a49301eSmrg */ 9204a49301eSmrgstatic void 9214a49301eSmrgrenderbuffer_storage(GLenum target, GLenum internalFormat, 9224a49301eSmrg GLsizei width, GLsizei height, GLsizei samples) 9237117f1b4Smrg{ 9244a49301eSmrg const char *func = samples == NO_SAMPLES ? 9254a49301eSmrg "glRenderbufferStorage" : "RenderbufferStorageMultisample"; 9267117f1b4Smrg struct gl_renderbuffer *rb; 9277117f1b4Smrg GLenum baseFormat; 9287117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9297117f1b4Smrg 9307117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 9317117f1b4Smrg 9327117f1b4Smrg if (target != GL_RENDERBUFFER_EXT) { 9334a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 9347117f1b4Smrg return; 9357117f1b4Smrg } 9367117f1b4Smrg 9377117f1b4Smrg baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 9387117f1b4Smrg if (baseFormat == 0) { 9394a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func); 9407117f1b4Smrg return; 9417117f1b4Smrg } 9427117f1b4Smrg 9437117f1b4Smrg if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { 9444a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); 9457117f1b4Smrg return; 9467117f1b4Smrg } 9477117f1b4Smrg 9487117f1b4Smrg if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { 9494a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); 9507117f1b4Smrg return; 9517117f1b4Smrg } 9527117f1b4Smrg 9534a49301eSmrg if (samples == NO_SAMPLES) { 9544a49301eSmrg /* NumSamples == 0 indicates non-multisampling */ 9554a49301eSmrg samples = 0; 9564a49301eSmrg } 957cdc920a0Smrg else if (samples > (GLsizei) ctx->Const.MaxSamples) { 9584a49301eSmrg /* note: driver may choose to use more samples than what's requested */ 9594a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func); 9604a49301eSmrg return; 9614a49301eSmrg } 9627117f1b4Smrg 9634a49301eSmrg rb = ctx->CurrentRenderbuffer; 9647117f1b4Smrg if (!rb) { 9654a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, func); 9667117f1b4Smrg return; 9677117f1b4Smrg } 9687117f1b4Smrg 9697117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 9707117f1b4Smrg 9717117f1b4Smrg if (rb->InternalFormat == internalFormat && 9727117f1b4Smrg rb->Width == (GLuint) width && 9737117f1b4Smrg rb->Height == (GLuint) height) { 9747117f1b4Smrg /* no change in allocation needed */ 9757117f1b4Smrg return; 9767117f1b4Smrg } 9777117f1b4Smrg 9787117f1b4Smrg /* These MUST get set by the AllocStorage func */ 9794a49301eSmrg rb->Format = MESA_FORMAT_NONE; 9804a49301eSmrg rb->NumSamples = samples; 9817117f1b4Smrg 9827117f1b4Smrg /* Now allocate the storage */ 9837117f1b4Smrg ASSERT(rb->AllocStorage); 9847117f1b4Smrg if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 9857117f1b4Smrg /* No error - check/set fields now */ 9864a49301eSmrg assert(rb->Format != MESA_FORMAT_NONE); 9877117f1b4Smrg assert(rb->Width == (GLuint) width); 9887117f1b4Smrg assert(rb->Height == (GLuint) height); 9897117f1b4Smrg rb->InternalFormat = internalFormat; 990cdc920a0Smrg rb->_BaseFormat = baseFormat; 9914a49301eSmrg assert(rb->_BaseFormat != 0); 9927117f1b4Smrg } 9937117f1b4Smrg else { 9947117f1b4Smrg /* Probably ran out of memory - clear the fields */ 9957117f1b4Smrg rb->Width = 0; 9967117f1b4Smrg rb->Height = 0; 9974a49301eSmrg rb->Format = MESA_FORMAT_NONE; 9987117f1b4Smrg rb->InternalFormat = GL_NONE; 9997117f1b4Smrg rb->_BaseFormat = GL_NONE; 10004a49301eSmrg rb->NumSamples = 0; 10017117f1b4Smrg } 10027117f1b4Smrg 10037117f1b4Smrg /* 10047117f1b4Smrg test_framebuffer_completeness(ctx, fb); 10057117f1b4Smrg */ 10067117f1b4Smrg /* XXX if this renderbuffer is attached anywhere, invalidate attachment 10077117f1b4Smrg * points??? 10087117f1b4Smrg */ 10097117f1b4Smrg} 10107117f1b4Smrg 1011cdc920a0Smrg#if FEATURE_OES_EGL_image 1012cdc920a0Smrgvoid GLAPIENTRY 1013cdc920a0Smrg_mesa_EGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image) 1014cdc920a0Smrg{ 1015cdc920a0Smrg struct gl_renderbuffer *rb; 1016cdc920a0Smrg GET_CURRENT_CONTEXT(ctx); 1017cdc920a0Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 1018cdc920a0Smrg 1019cdc920a0Smrg if (target != GL_RENDERBUFFER) { 1020cdc920a0Smrg _mesa_error(ctx, GL_INVALID_ENUM, "EGLImageTargetRenderbufferStorageOES"); 1021cdc920a0Smrg return; 1022cdc920a0Smrg } 1023cdc920a0Smrg 1024cdc920a0Smrg rb = ctx->CurrentRenderbuffer; 1025cdc920a0Smrg if (!rb) { 1026cdc920a0Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "EGLImageTargetRenderbufferStorageOES"); 1027cdc920a0Smrg return; 1028cdc920a0Smrg } 1029cdc920a0Smrg 1030cdc920a0Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1031cdc920a0Smrg 1032cdc920a0Smrg ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); 1033cdc920a0Smrg} 1034cdc920a0Smrg#endif 10357117f1b4Smrg 10364a49301eSmrg/** 10374a49301eSmrg * Helper function for _mesa_GetRenderbufferParameterivEXT() and 10384a49301eSmrg * _mesa_GetFramebufferAttachmentParameterivEXT() 10394a49301eSmrg * We have to be careful to respect the base format. For example, if a 10404a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the 10414a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE 10424a49301eSmrg * we need to return zero. 10434a49301eSmrg */ 10444a49301eSmrgstatic GLint 10454a49301eSmrgget_component_bits(GLenum pname, GLenum baseFormat, gl_format format) 10464a49301eSmrg{ 10474a49301eSmrg switch (pname) { 10484a49301eSmrg case GL_RENDERBUFFER_RED_SIZE_EXT: 10494a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: 10504a49301eSmrg case GL_RENDERBUFFER_GREEN_SIZE_EXT: 10514a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 10524a49301eSmrg case GL_RENDERBUFFER_BLUE_SIZE_EXT: 10534a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 10544a49301eSmrg if (baseFormat == GL_RGB || baseFormat == GL_RGBA) 10554a49301eSmrg return _mesa_get_format_bits(format, pname); 10564a49301eSmrg else 10574a49301eSmrg return 0; 10584a49301eSmrg case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 10594a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 10604a49301eSmrg if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA) 10614a49301eSmrg return _mesa_get_format_bits(format, pname); 10624a49301eSmrg else 10634a49301eSmrg return 0; 10644a49301eSmrg case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 10654a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 10664a49301eSmrg if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) 10674a49301eSmrg return _mesa_get_format_bits(format, pname); 10684a49301eSmrg else 10694a49301eSmrg return 0; 10704a49301eSmrg case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 10714a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 10724a49301eSmrg if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL) 10734a49301eSmrg return _mesa_get_format_bits(format, pname); 10744a49301eSmrg else 10754a49301eSmrg return 0; 10764a49301eSmrg default: 10774a49301eSmrg return 0; 10784a49301eSmrg } 10794a49301eSmrg} 10804a49301eSmrg 10814a49301eSmrg 10824a49301eSmrg 10834a49301eSmrgvoid GLAPIENTRY 10844a49301eSmrg_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 10854a49301eSmrg GLsizei width, GLsizei height) 10864a49301eSmrg{ 10874a49301eSmrg /* GL_ARB_fbo says calling this function is equivalent to calling 10884a49301eSmrg * glRenderbufferStorageMultisample() with samples=0. We pass in 10894a49301eSmrg * a token value here just for error reporting purposes. 10904a49301eSmrg */ 10914a49301eSmrg renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES); 10924a49301eSmrg} 10934a49301eSmrg 10944a49301eSmrg 10954a49301eSmrgvoid GLAPIENTRY 10964a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, 10974a49301eSmrg GLenum internalFormat, 10984a49301eSmrg GLsizei width, GLsizei height) 10994a49301eSmrg{ 11004a49301eSmrg renderbuffer_storage(target, internalFormat, width, height, samples); 11014a49301eSmrg} 11024a49301eSmrg 11034a49301eSmrg 11044a49301eSmrg 11057117f1b4Smrgvoid GLAPIENTRY 11067117f1b4Smrg_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) 11077117f1b4Smrg{ 11084a49301eSmrg struct gl_renderbuffer *rb; 11097117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 11107117f1b4Smrg 11117117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 11127117f1b4Smrg 11137117f1b4Smrg if (target != GL_RENDERBUFFER_EXT) { 11147117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 11157117f1b4Smrg "glGetRenderbufferParameterivEXT(target)"); 11167117f1b4Smrg return; 11177117f1b4Smrg } 11187117f1b4Smrg 11194a49301eSmrg rb = ctx->CurrentRenderbuffer; 11204a49301eSmrg if (!rb) { 11217117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 11227117f1b4Smrg "glGetRenderbufferParameterivEXT"); 11237117f1b4Smrg return; 11247117f1b4Smrg } 11257117f1b4Smrg 11264a49301eSmrg /* No need to flush here since we're just quering state which is 11274a49301eSmrg * not effected by rendering. 11284a49301eSmrg */ 11297117f1b4Smrg 11307117f1b4Smrg switch (pname) { 11317117f1b4Smrg case GL_RENDERBUFFER_WIDTH_EXT: 11324a49301eSmrg *params = rb->Width; 11337117f1b4Smrg return; 11347117f1b4Smrg case GL_RENDERBUFFER_HEIGHT_EXT: 11354a49301eSmrg *params = rb->Height; 11367117f1b4Smrg return; 11377117f1b4Smrg case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 11384a49301eSmrg *params = rb->InternalFormat; 11397117f1b4Smrg return; 11407117f1b4Smrg case GL_RENDERBUFFER_RED_SIZE_EXT: 11417117f1b4Smrg case GL_RENDERBUFFER_GREEN_SIZE_EXT: 11427117f1b4Smrg case GL_RENDERBUFFER_BLUE_SIZE_EXT: 11437117f1b4Smrg case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 11447117f1b4Smrg case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 11457117f1b4Smrg case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 11464a49301eSmrg *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); 11477117f1b4Smrg break; 11484a49301eSmrg case GL_RENDERBUFFER_SAMPLES: 11494a49301eSmrg if (ctx->Extensions.ARB_framebuffer_object) { 11504a49301eSmrg *params = rb->NumSamples; 11514a49301eSmrg break; 11524a49301eSmrg } 11534a49301eSmrg /* fallthrough */ 11547117f1b4Smrg default: 11557117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 11567117f1b4Smrg "glGetRenderbufferParameterivEXT(target)"); 11577117f1b4Smrg return; 11587117f1b4Smrg } 11597117f1b4Smrg} 11607117f1b4Smrg 11617117f1b4Smrg 11627117f1b4SmrgGLboolean GLAPIENTRY 11637117f1b4Smrg_mesa_IsFramebufferEXT(GLuint framebuffer) 11647117f1b4Smrg{ 11657117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 11667117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 11677117f1b4Smrg if (framebuffer) { 11687117f1b4Smrg struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); 11697117f1b4Smrg if (rb != NULL && rb != &DummyFramebuffer) 11707117f1b4Smrg return GL_TRUE; 11717117f1b4Smrg } 11727117f1b4Smrg return GL_FALSE; 11737117f1b4Smrg} 11747117f1b4Smrg 11757117f1b4Smrg 11764a49301eSmrg/** 11774a49301eSmrg * Check if any of the attachments of the given framebuffer are textures 11784a49301eSmrg * (render to texture). Call ctx->Driver.RenderTexture() for such 11794a49301eSmrg * attachments. 11804a49301eSmrg */ 11817117f1b4Smrgstatic void 11827117f1b4Smrgcheck_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 11837117f1b4Smrg{ 11847117f1b4Smrg GLuint i; 11857117f1b4Smrg ASSERT(ctx->Driver.RenderTexture); 11864a49301eSmrg 11874a49301eSmrg if (fb->Name == 0) 11884a49301eSmrg return; /* can't render to texture with winsys framebuffers */ 11894a49301eSmrg 11907117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 11917117f1b4Smrg struct gl_renderbuffer_attachment *att = fb->Attachment + i; 11927117f1b4Smrg struct gl_texture_object *texObj = att->Texture; 11937117f1b4Smrg if (texObj 11944a49301eSmrg && texObj->Image[att->CubeMapFace][att->TextureLevel]) { 11957117f1b4Smrg ctx->Driver.RenderTexture(ctx, fb, att); 11967117f1b4Smrg } 11977117f1b4Smrg } 11987117f1b4Smrg} 11997117f1b4Smrg 12007117f1b4Smrg 12017117f1b4Smrg/** 12027117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures. 12037117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to 12047117f1b4Smrg * notify the device driver that the texture image may have changed. 12057117f1b4Smrg */ 12067117f1b4Smrgstatic void 12077117f1b4Smrgcheck_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 12087117f1b4Smrg{ 12094a49301eSmrg if (fb->Name == 0) 12104a49301eSmrg return; /* can't render to texture with winsys framebuffers */ 12114a49301eSmrg 12127117f1b4Smrg if (ctx->Driver.FinishRenderTexture) { 12137117f1b4Smrg GLuint i; 12147117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 12157117f1b4Smrg struct gl_renderbuffer_attachment *att = fb->Attachment + i; 1216c1f859d4Smrg if (att->Texture && att->Renderbuffer) { 12177117f1b4Smrg ctx->Driver.FinishRenderTexture(ctx, att); 12187117f1b4Smrg } 12197117f1b4Smrg } 12207117f1b4Smrg } 12217117f1b4Smrg} 12227117f1b4Smrg 12237117f1b4Smrg 12247117f1b4Smrgvoid GLAPIENTRY 12257117f1b4Smrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 12267117f1b4Smrg{ 12274a49301eSmrg struct gl_framebuffer *newDrawFb, *newReadFb; 12284a49301eSmrg struct gl_framebuffer *oldDrawFb, *oldReadFb; 12297117f1b4Smrg GLboolean bindReadBuf, bindDrawBuf; 12307117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 12317117f1b4Smrg 12324a49301eSmrg#ifdef DEBUG 12334a49301eSmrg if (ctx->Extensions.ARB_framebuffer_object) { 12344a49301eSmrg ASSERT(ctx->Extensions.EXT_framebuffer_object); 12354a49301eSmrg ASSERT(ctx->Extensions.EXT_framebuffer_blit); 12364a49301eSmrg } 12374a49301eSmrg#endif 12384a49301eSmrg 12397117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 12407117f1b4Smrg 12417117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_object) { 12427117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 12437117f1b4Smrg "glBindFramebufferEXT(unsupported)"); 12447117f1b4Smrg return; 12457117f1b4Smrg } 12467117f1b4Smrg 12477117f1b4Smrg switch (target) { 12487117f1b4Smrg#if FEATURE_EXT_framebuffer_blit 12497117f1b4Smrg case GL_DRAW_FRAMEBUFFER_EXT: 12507117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_blit) { 12517117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 12527117f1b4Smrg return; 12537117f1b4Smrg } 12547117f1b4Smrg bindDrawBuf = GL_TRUE; 12557117f1b4Smrg bindReadBuf = GL_FALSE; 12567117f1b4Smrg break; 12577117f1b4Smrg case GL_READ_FRAMEBUFFER_EXT: 12587117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_blit) { 12597117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 12607117f1b4Smrg return; 12617117f1b4Smrg } 12627117f1b4Smrg bindDrawBuf = GL_FALSE; 12637117f1b4Smrg bindReadBuf = GL_TRUE; 12647117f1b4Smrg break; 12657117f1b4Smrg#endif 12667117f1b4Smrg case GL_FRAMEBUFFER_EXT: 12677117f1b4Smrg bindDrawBuf = GL_TRUE; 12687117f1b4Smrg bindReadBuf = GL_TRUE; 12697117f1b4Smrg break; 12707117f1b4Smrg default: 12717117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 12727117f1b4Smrg return; 12737117f1b4Smrg } 12747117f1b4Smrg 12757117f1b4Smrg if (framebuffer) { 12767117f1b4Smrg /* Binding a user-created framebuffer object */ 12774a49301eSmrg newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); 12784a49301eSmrg if (newDrawFb == &DummyFramebuffer) { 12797117f1b4Smrg /* ID was reserved, but no real framebuffer object made yet */ 12804a49301eSmrg newDrawFb = NULL; 12817117f1b4Smrg } 12824a49301eSmrg else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) { 12834a49301eSmrg /* All FBO IDs must be Gen'd */ 12844a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); 12854a49301eSmrg return; 12864a49301eSmrg } 12874a49301eSmrg 12884a49301eSmrg if (!newDrawFb) { 12897117f1b4Smrg /* create new framebuffer object */ 12904a49301eSmrg newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 12914a49301eSmrg if (!newDrawFb) { 12927117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 12937117f1b4Smrg return; 12947117f1b4Smrg } 12954a49301eSmrg _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb); 12967117f1b4Smrg } 12974a49301eSmrg newReadFb = newDrawFb; 12987117f1b4Smrg } 12997117f1b4Smrg else { 13007117f1b4Smrg /* Binding the window system framebuffer (which was originally set 13017117f1b4Smrg * with MakeCurrent). 13027117f1b4Smrg */ 13034a49301eSmrg newDrawFb = ctx->WinSysDrawBuffer; 13044a49301eSmrg newReadFb = ctx->WinSysReadBuffer; 13057117f1b4Smrg } 13067117f1b4Smrg 13074a49301eSmrg ASSERT(newDrawFb); 13084a49301eSmrg ASSERT(newDrawFb != &DummyFramebuffer); 13094a49301eSmrg 13104a49301eSmrg /* save pointers to current/old framebuffers */ 13114a49301eSmrg oldDrawFb = ctx->DrawBuffer; 13124a49301eSmrg oldReadFb = ctx->ReadBuffer; 13134a49301eSmrg 13144a49301eSmrg /* check if really changing bindings */ 13154a49301eSmrg if (oldDrawFb == newDrawFb) 13164a49301eSmrg bindDrawBuf = GL_FALSE; 13174a49301eSmrg if (oldReadFb == newReadFb) 13184a49301eSmrg bindReadBuf = GL_FALSE; 13197117f1b4Smrg 13207117f1b4Smrg /* 13214a49301eSmrg * OK, now bind the new Draw/Read framebuffers, if they're changing. 13224a49301eSmrg * 13234a49301eSmrg * We also check if we're beginning and/or ending render-to-texture. 13244a49301eSmrg * When a framebuffer with texture attachments is unbound, call 13254a49301eSmrg * ctx->Driver.FinishRenderTexture(). 13264a49301eSmrg * When a framebuffer with texture attachments is bound, call 13274a49301eSmrg * ctx->Driver.RenderTexture(). 13284a49301eSmrg * 13294a49301eSmrg * Note that if the ReadBuffer has texture attachments we don't consider 13304a49301eSmrg * that a render-to-texture case. 13317117f1b4Smrg */ 13327117f1b4Smrg if (bindReadBuf) { 13334a49301eSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 13344a49301eSmrg 13354a49301eSmrg /* check if old readbuffer was render-to-texture */ 13364a49301eSmrg check_end_texture_render(ctx, oldReadFb); 13374a49301eSmrg 13384a49301eSmrg _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); 13397117f1b4Smrg } 13407117f1b4Smrg 13417117f1b4Smrg if (bindDrawBuf) { 13424a49301eSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 13437117f1b4Smrg 13444a49301eSmrg /* check if old read/draw buffers were render-to-texture */ 13454a49301eSmrg if (!bindReadBuf) 13464a49301eSmrg check_end_texture_render(ctx, oldReadFb); 13477117f1b4Smrg 13484a49301eSmrg if (oldDrawFb != oldReadFb) 13494a49301eSmrg check_end_texture_render(ctx, oldDrawFb); 13504a49301eSmrg 13514a49301eSmrg /* check if newly bound framebuffer has any texture attachments */ 13524a49301eSmrg check_begin_texture_render(ctx, newDrawFb); 13534a49301eSmrg 13544a49301eSmrg _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); 13557117f1b4Smrg } 13567117f1b4Smrg 13574a49301eSmrg if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { 13584a49301eSmrg ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb); 13597117f1b4Smrg } 13607117f1b4Smrg} 13617117f1b4Smrg 13627117f1b4Smrg 13637117f1b4Smrgvoid GLAPIENTRY 13647117f1b4Smrg_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) 13657117f1b4Smrg{ 13667117f1b4Smrg GLint i; 13677117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 13687117f1b4Smrg 13697117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 13707117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 13717117f1b4Smrg 13727117f1b4Smrg for (i = 0; i < n; i++) { 13737117f1b4Smrg if (framebuffers[i] > 0) { 13747117f1b4Smrg struct gl_framebuffer *fb; 13757117f1b4Smrg fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); 13767117f1b4Smrg if (fb) { 13777117f1b4Smrg ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 13787117f1b4Smrg 13797117f1b4Smrg /* check if deleting currently bound framebuffer object */ 13804a49301eSmrg if (ctx->Extensions.EXT_framebuffer_blit) { 13814a49301eSmrg /* separate draw/read binding points */ 13824a49301eSmrg if (fb == ctx->DrawBuffer) { 13834a49301eSmrg /* bind default */ 13844a49301eSmrg ASSERT(fb->RefCount >= 2); 13854a49301eSmrg _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); 13864a49301eSmrg } 13874a49301eSmrg if (fb == ctx->ReadBuffer) { 13884a49301eSmrg /* bind default */ 13894a49301eSmrg ASSERT(fb->RefCount >= 2); 13904a49301eSmrg _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); 13914a49301eSmrg } 13924a49301eSmrg } 13934a49301eSmrg else { 13944a49301eSmrg /* only one binding point for read/draw buffers */ 13954a49301eSmrg if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) { 13964a49301eSmrg /* bind default */ 13974a49301eSmrg ASSERT(fb->RefCount >= 2); 13984a49301eSmrg _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 13994a49301eSmrg } 14007117f1b4Smrg } 14017117f1b4Smrg 14027117f1b4Smrg /* remove from hash table immediately, to free the ID */ 14037117f1b4Smrg _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 14047117f1b4Smrg 14057117f1b4Smrg if (fb != &DummyFramebuffer) { 14067117f1b4Smrg /* But the object will not be freed until it's no longer 14077117f1b4Smrg * bound in any context. 14087117f1b4Smrg */ 14094a49301eSmrg _mesa_reference_framebuffer(&fb, NULL); 14107117f1b4Smrg } 14117117f1b4Smrg } 14127117f1b4Smrg } 14137117f1b4Smrg } 14147117f1b4Smrg} 14157117f1b4Smrg 14167117f1b4Smrg 14177117f1b4Smrgvoid GLAPIENTRY 14187117f1b4Smrg_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) 14197117f1b4Smrg{ 14207117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 14217117f1b4Smrg GLuint first; 14227117f1b4Smrg GLint i; 14237117f1b4Smrg 14247117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 14257117f1b4Smrg 14267117f1b4Smrg if (n < 0) { 14277117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); 14287117f1b4Smrg return; 14297117f1b4Smrg } 14307117f1b4Smrg 14317117f1b4Smrg if (!framebuffers) 14327117f1b4Smrg return; 14337117f1b4Smrg 14347117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 14357117f1b4Smrg 14367117f1b4Smrg for (i = 0; i < n; i++) { 14377117f1b4Smrg GLuint name = first + i; 14387117f1b4Smrg framebuffers[i] = name; 14397117f1b4Smrg /* insert dummy placeholder into hash table */ 14407117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 14417117f1b4Smrg _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); 14427117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 14437117f1b4Smrg } 14447117f1b4Smrg} 14457117f1b4Smrg 14467117f1b4Smrg 14477117f1b4Smrg 14487117f1b4SmrgGLenum GLAPIENTRY 14497117f1b4Smrg_mesa_CheckFramebufferStatusEXT(GLenum target) 14507117f1b4Smrg{ 14517117f1b4Smrg struct gl_framebuffer *buffer; 14527117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 14537117f1b4Smrg 14547117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 14557117f1b4Smrg 14567117f1b4Smrg switch (target) { 14577117f1b4Smrg#if FEATURE_EXT_framebuffer_blit 14587117f1b4Smrg case GL_DRAW_FRAMEBUFFER_EXT: 14597117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_blit) { 14607117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 14617117f1b4Smrg return 0; 14627117f1b4Smrg } 14637117f1b4Smrg buffer = ctx->DrawBuffer; 14647117f1b4Smrg break; 14657117f1b4Smrg case GL_READ_FRAMEBUFFER_EXT: 14667117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_blit) { 14677117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 14687117f1b4Smrg return 0; 14697117f1b4Smrg } 14707117f1b4Smrg buffer = ctx->ReadBuffer; 14717117f1b4Smrg break; 14727117f1b4Smrg#endif 14737117f1b4Smrg case GL_FRAMEBUFFER_EXT: 14747117f1b4Smrg buffer = ctx->DrawBuffer; 14757117f1b4Smrg break; 14767117f1b4Smrg default: 14777117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 14787117f1b4Smrg return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ 14797117f1b4Smrg } 14807117f1b4Smrg 14817117f1b4Smrg if (buffer->Name == 0) { 14827117f1b4Smrg /* The window system / default framebuffer is always complete */ 14837117f1b4Smrg return GL_FRAMEBUFFER_COMPLETE_EXT; 14847117f1b4Smrg } 14857117f1b4Smrg 14864a49301eSmrg /* No need to flush here */ 14874a49301eSmrg 14884a49301eSmrg if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { 14894a49301eSmrg _mesa_test_framebuffer_completeness(ctx, buffer); 14904a49301eSmrg } 14917117f1b4Smrg 14927117f1b4Smrg return buffer->_Status; 14937117f1b4Smrg} 14947117f1b4Smrg 14957117f1b4Smrg 14967117f1b4Smrg 14977117f1b4Smrg/** 14987117f1b4Smrg * Common code called by glFramebufferTexture1D/2D/3DEXT(). 14997117f1b4Smrg */ 15007117f1b4Smrgstatic void 15017117f1b4Smrgframebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, 15027117f1b4Smrg GLenum attachment, GLenum textarget, GLuint texture, 15037117f1b4Smrg GLint level, GLint zoffset) 15047117f1b4Smrg{ 15057117f1b4Smrg struct gl_renderbuffer_attachment *att; 15067117f1b4Smrg struct gl_texture_object *texObj = NULL; 15077117f1b4Smrg struct gl_framebuffer *fb; 15084a49301eSmrg GLboolean error = GL_FALSE; 15097117f1b4Smrg 15107117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 15117117f1b4Smrg 15124a49301eSmrg switch (target) { 15134a49301eSmrg case GL_READ_FRAMEBUFFER_EXT: 15144a49301eSmrg error = !ctx->Extensions.EXT_framebuffer_blit; 15154a49301eSmrg fb = ctx->ReadBuffer; 15164a49301eSmrg break; 15174a49301eSmrg case GL_DRAW_FRAMEBUFFER_EXT: 15184a49301eSmrg error = !ctx->Extensions.EXT_framebuffer_blit; 15194a49301eSmrg /* fall-through */ 15204a49301eSmrg case GL_FRAMEBUFFER_EXT: 15214a49301eSmrg fb = ctx->DrawBuffer; 15224a49301eSmrg break; 15234a49301eSmrg default: 15244a49301eSmrg error = GL_TRUE; 15254a49301eSmrg } 15264a49301eSmrg 15274a49301eSmrg if (error) { 15287117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 15294a49301eSmrg "glFramebufferTexture%sEXT(target=0x%x)", caller, target); 15307117f1b4Smrg return; 15317117f1b4Smrg } 15327117f1b4Smrg 15337117f1b4Smrg ASSERT(fb); 15347117f1b4Smrg 15357117f1b4Smrg /* check framebuffer binding */ 15367117f1b4Smrg if (fb->Name == 0) { 15377117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 15387117f1b4Smrg "glFramebufferTexture%sEXT", caller); 15397117f1b4Smrg return; 15407117f1b4Smrg } 15417117f1b4Smrg 15427117f1b4Smrg 15437117f1b4Smrg /* The textarget, level, and zoffset parameters are only validated if 15447117f1b4Smrg * texture is non-zero. 15457117f1b4Smrg */ 15467117f1b4Smrg if (texture) { 15477117f1b4Smrg GLboolean err = GL_TRUE; 15487117f1b4Smrg 15497117f1b4Smrg texObj = _mesa_lookup_texture(ctx, texture); 15507117f1b4Smrg if (texObj != NULL) { 1551c1f859d4Smrg if (textarget == 0) { 1552c1f859d4Smrg err = (texObj->Target != GL_TEXTURE_3D) && 1553c1f859d4Smrg (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && 1554c1f859d4Smrg (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); 1555c1f859d4Smrg } 1556c1f859d4Smrg else { 1557c1f859d4Smrg err = (texObj->Target == GL_TEXTURE_CUBE_MAP) 1558c1f859d4Smrg ? !IS_CUBE_FACE(textarget) 1559c1f859d4Smrg : (texObj->Target != textarget); 1560c1f859d4Smrg } 15617117f1b4Smrg } 15627117f1b4Smrg 15637117f1b4Smrg if (err) { 15647117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 15657117f1b4Smrg "glFramebufferTexture%sEXT(texture target mismatch)", 15667117f1b4Smrg caller); 15677117f1b4Smrg return; 15687117f1b4Smrg } 15697117f1b4Smrg 15707117f1b4Smrg if (texObj->Target == GL_TEXTURE_3D) { 15717117f1b4Smrg const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 15727117f1b4Smrg if (zoffset < 0 || zoffset >= maxSize) { 15737117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1574c1f859d4Smrg "glFramebufferTexture%sEXT(zoffset)", caller); 15757117f1b4Smrg return; 15767117f1b4Smrg } 15777117f1b4Smrg } 1578c1f859d4Smrg else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || 1579c1f859d4Smrg (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 1580c1f859d4Smrg if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { 1581c1f859d4Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1582c1f859d4Smrg "glFramebufferTexture%sEXT(layer)", caller); 1583c1f859d4Smrg return; 1584c1f859d4Smrg } 1585c1f859d4Smrg } 1586c1f859d4Smrg 15877117f1b4Smrg if ((level < 0) || 15887117f1b4Smrg (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { 15897117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, 15907117f1b4Smrg "glFramebufferTexture%sEXT(level)", caller); 15917117f1b4Smrg return; 15927117f1b4Smrg } 15937117f1b4Smrg } 15947117f1b4Smrg 15957117f1b4Smrg att = _mesa_get_attachment(ctx, fb, attachment); 15967117f1b4Smrg if (att == NULL) { 15977117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 15987117f1b4Smrg "glFramebufferTexture%sEXT(attachment)", caller); 15997117f1b4Smrg return; 16007117f1b4Smrg } 16017117f1b4Smrg 16027117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 16037117f1b4Smrg 16047117f1b4Smrg _glthread_LOCK_MUTEX(fb->Mutex); 16057117f1b4Smrg if (texObj) { 16067117f1b4Smrg _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, 16077117f1b4Smrg level, zoffset); 16084a49301eSmrg /* Set the render-to-texture flag. We'll check this flag in 16094a49301eSmrg * glTexImage() and friends to determine if we need to revalidate 16104a49301eSmrg * any FBOs that might be rendering into this texture. 16114a49301eSmrg * This flag never gets cleared since it's non-trivial to determine 16124a49301eSmrg * when all FBOs might be done rendering to this texture. That's OK 16134a49301eSmrg * though since it's uncommon to render to a texture then repeatedly 16144a49301eSmrg * call glTexImage() to change images in the texture. 16154a49301eSmrg */ 16164a49301eSmrg texObj->_RenderToTexture = GL_TRUE; 16177117f1b4Smrg } 16187117f1b4Smrg else { 16197117f1b4Smrg _mesa_remove_attachment(ctx, att); 16207117f1b4Smrg } 16214a49301eSmrg 16224a49301eSmrg invalidate_framebuffer(fb); 16234a49301eSmrg 16247117f1b4Smrg _glthread_UNLOCK_MUTEX(fb->Mutex); 16257117f1b4Smrg} 16267117f1b4Smrg 16277117f1b4Smrg 16287117f1b4Smrg 16297117f1b4Smrgvoid GLAPIENTRY 16307117f1b4Smrg_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, 16317117f1b4Smrg GLenum textarget, GLuint texture, GLint level) 16327117f1b4Smrg{ 16337117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 16347117f1b4Smrg 16357117f1b4Smrg if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { 16367117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 16377117f1b4Smrg "glFramebufferTexture1DEXT(textarget)"); 16387117f1b4Smrg return; 16397117f1b4Smrg } 16407117f1b4Smrg 16417117f1b4Smrg framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, 16427117f1b4Smrg level, 0); 16437117f1b4Smrg} 16447117f1b4Smrg 16457117f1b4Smrg 16467117f1b4Smrgvoid GLAPIENTRY 16477117f1b4Smrg_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, 16487117f1b4Smrg GLenum textarget, GLuint texture, GLint level) 16497117f1b4Smrg{ 16507117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 16517117f1b4Smrg 16527117f1b4Smrg if ((texture != 0) && 16537117f1b4Smrg (textarget != GL_TEXTURE_2D) && 16547117f1b4Smrg (textarget != GL_TEXTURE_RECTANGLE_ARB) && 16557117f1b4Smrg (!IS_CUBE_FACE(textarget))) { 16567117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 16574a49301eSmrg "glFramebufferTexture2DEXT(textarget=0x%x)", textarget); 16587117f1b4Smrg return; 16597117f1b4Smrg } 16607117f1b4Smrg 16617117f1b4Smrg framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, 16627117f1b4Smrg level, 0); 16637117f1b4Smrg} 16647117f1b4Smrg 16657117f1b4Smrg 16667117f1b4Smrgvoid GLAPIENTRY 16677117f1b4Smrg_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, 16687117f1b4Smrg GLenum textarget, GLuint texture, 16697117f1b4Smrg GLint level, GLint zoffset) 16707117f1b4Smrg{ 16717117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 16727117f1b4Smrg 16737117f1b4Smrg if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { 16747117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 16757117f1b4Smrg "glFramebufferTexture3DEXT(textarget)"); 16767117f1b4Smrg return; 16777117f1b4Smrg } 16787117f1b4Smrg 16797117f1b4Smrg framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, 16807117f1b4Smrg level, zoffset); 16817117f1b4Smrg} 16827117f1b4Smrg 16837117f1b4Smrg 1684c1f859d4Smrgvoid GLAPIENTRY 1685c1f859d4Smrg_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, 1686c1f859d4Smrg GLuint texture, GLint level, GLint layer) 1687c1f859d4Smrg{ 1688c1f859d4Smrg GET_CURRENT_CONTEXT(ctx); 1689c1f859d4Smrg 1690c1f859d4Smrg framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, 1691c1f859d4Smrg level, layer); 1692c1f859d4Smrg} 1693c1f859d4Smrg 1694c1f859d4Smrg 16957117f1b4Smrgvoid GLAPIENTRY 16967117f1b4Smrg_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, 16977117f1b4Smrg GLenum renderbufferTarget, 16987117f1b4Smrg GLuint renderbuffer) 16997117f1b4Smrg{ 17007117f1b4Smrg struct gl_renderbuffer_attachment *att; 17017117f1b4Smrg struct gl_framebuffer *fb; 17027117f1b4Smrg struct gl_renderbuffer *rb; 17037117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 17047117f1b4Smrg 17057117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 17067117f1b4Smrg 17077117f1b4Smrg switch (target) { 17087117f1b4Smrg#if FEATURE_EXT_framebuffer_blit 17097117f1b4Smrg case GL_DRAW_FRAMEBUFFER_EXT: 17107117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_blit) { 17117117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 17127117f1b4Smrg "glFramebufferRenderbufferEXT(target)"); 17137117f1b4Smrg return; 17147117f1b4Smrg } 17157117f1b4Smrg fb = ctx->DrawBuffer; 17167117f1b4Smrg break; 17177117f1b4Smrg case GL_READ_FRAMEBUFFER_EXT: 17187117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_blit) { 17197117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 17207117f1b4Smrg "glFramebufferRenderbufferEXT(target)"); 17217117f1b4Smrg return; 17227117f1b4Smrg } 17237117f1b4Smrg fb = ctx->ReadBuffer; 17247117f1b4Smrg break; 17257117f1b4Smrg#endif 17267117f1b4Smrg case GL_FRAMEBUFFER_EXT: 17277117f1b4Smrg fb = ctx->DrawBuffer; 17287117f1b4Smrg break; 17297117f1b4Smrg default: 17307117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 17317117f1b4Smrg "glFramebufferRenderbufferEXT(target)"); 17327117f1b4Smrg return; 17337117f1b4Smrg } 17347117f1b4Smrg 17357117f1b4Smrg if (renderbufferTarget != GL_RENDERBUFFER_EXT) { 17367117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 17377117f1b4Smrg "glFramebufferRenderbufferEXT(renderbufferTarget)"); 17387117f1b4Smrg return; 17397117f1b4Smrg } 17407117f1b4Smrg 17417117f1b4Smrg if (fb->Name == 0) { 17427117f1b4Smrg /* Can't attach new renderbuffers to a window system framebuffer */ 17437117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); 17447117f1b4Smrg return; 17457117f1b4Smrg } 17467117f1b4Smrg 17477117f1b4Smrg att = _mesa_get_attachment(ctx, fb, attachment); 17487117f1b4Smrg if (att == NULL) { 17497117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 17504a49301eSmrg "glFramebufferRenderbufferEXT(invalid attachment %s)", 17514a49301eSmrg _mesa_lookup_enum_by_nr(attachment)); 17527117f1b4Smrg return; 17537117f1b4Smrg } 17547117f1b4Smrg 17557117f1b4Smrg if (renderbuffer) { 17567117f1b4Smrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 17577117f1b4Smrg if (!rb) { 17587117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 17594a49301eSmrg "glFramebufferRenderbufferEXT(non-existant" 17604a49301eSmrg " renderbuffer %u)", renderbuffer); 17617117f1b4Smrg return; 17627117f1b4Smrg } 17637117f1b4Smrg } 17647117f1b4Smrg else { 17657117f1b4Smrg /* remove renderbuffer attachment */ 17667117f1b4Smrg rb = NULL; 17677117f1b4Smrg } 17687117f1b4Smrg 1769cdc920a0Smrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && 1770cdc920a0Smrg rb && rb->Format != MESA_FORMAT_NONE) { 17714a49301eSmrg /* make sure the renderbuffer is a depth/stencil format */ 1772cdc920a0Smrg const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); 17734a49301eSmrg if (baseFormat != GL_DEPTH_STENCIL) { 17744a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 17754a49301eSmrg "glFramebufferRenderbufferEXT(renderbuffer" 17764a49301eSmrg " is not DEPTH_STENCIL format)"); 17774a49301eSmrg return; 17784a49301eSmrg } 17794a49301eSmrg } 17804a49301eSmrg 17814a49301eSmrg 17827117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 17837117f1b4Smrg 17847117f1b4Smrg assert(ctx->Driver.FramebufferRenderbuffer); 17857117f1b4Smrg ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); 17867117f1b4Smrg 17877117f1b4Smrg /* Some subsequent GL commands may depend on the framebuffer's visual 17887117f1b4Smrg * after the binding is updated. Update visual info now. 17897117f1b4Smrg */ 17907117f1b4Smrg _mesa_update_framebuffer_visual(fb); 17917117f1b4Smrg} 17927117f1b4Smrg 17937117f1b4Smrg 17947117f1b4Smrgvoid GLAPIENTRY 17957117f1b4Smrg_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, 17967117f1b4Smrg GLenum pname, GLint *params) 17977117f1b4Smrg{ 17987117f1b4Smrg const struct gl_renderbuffer_attachment *att; 17997117f1b4Smrg struct gl_framebuffer *buffer; 18007117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 18017117f1b4Smrg 18027117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 18037117f1b4Smrg 18047117f1b4Smrg switch (target) { 18057117f1b4Smrg#if FEATURE_EXT_framebuffer_blit 18067117f1b4Smrg case GL_DRAW_FRAMEBUFFER_EXT: 18077117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_blit) { 18087117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 18097117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(target)"); 18107117f1b4Smrg return; 18117117f1b4Smrg } 18127117f1b4Smrg buffer = ctx->DrawBuffer; 18137117f1b4Smrg break; 18147117f1b4Smrg case GL_READ_FRAMEBUFFER_EXT: 18157117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_blit) { 18167117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 18177117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(target)"); 18187117f1b4Smrg return; 18197117f1b4Smrg } 18207117f1b4Smrg buffer = ctx->ReadBuffer; 18217117f1b4Smrg break; 18227117f1b4Smrg#endif 18237117f1b4Smrg case GL_FRAMEBUFFER_EXT: 18247117f1b4Smrg buffer = ctx->DrawBuffer; 18257117f1b4Smrg break; 18267117f1b4Smrg default: 18277117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 18287117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(target)"); 18297117f1b4Smrg return; 18307117f1b4Smrg } 18317117f1b4Smrg 18327117f1b4Smrg if (buffer->Name == 0) { 18337117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 18347117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT"); 18357117f1b4Smrg return; 18367117f1b4Smrg } 18377117f1b4Smrg 18387117f1b4Smrg att = _mesa_get_attachment(ctx, buffer, attachment); 18397117f1b4Smrg if (att == NULL) { 18407117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 18417117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(attachment)"); 18427117f1b4Smrg return; 18437117f1b4Smrg } 18447117f1b4Smrg 18454a49301eSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 18464a49301eSmrg /* the depth and stencil attachments must point to the same buffer */ 18474a49301eSmrg const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; 18484a49301eSmrg depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); 18494a49301eSmrg stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); 18504a49301eSmrg if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { 18514a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 18524a49301eSmrg "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" 18534a49301eSmrg " attachments differ)"); 18544a49301eSmrg return; 18554a49301eSmrg } 18564a49301eSmrg } 18574a49301eSmrg 18584a49301eSmrg /* No need to flush here */ 18597117f1b4Smrg 18607117f1b4Smrg switch (pname) { 18617117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 18627117f1b4Smrg *params = att->Type; 18637117f1b4Smrg return; 18647117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 18657117f1b4Smrg if (att->Type == GL_RENDERBUFFER_EXT) { 18667117f1b4Smrg *params = att->Renderbuffer->Name; 18677117f1b4Smrg } 18687117f1b4Smrg else if (att->Type == GL_TEXTURE) { 18697117f1b4Smrg *params = att->Texture->Name; 18707117f1b4Smrg } 18717117f1b4Smrg else { 18727117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 18737117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(pname)"); 18747117f1b4Smrg } 18757117f1b4Smrg return; 18767117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 18777117f1b4Smrg if (att->Type == GL_TEXTURE) { 18787117f1b4Smrg *params = att->TextureLevel; 18797117f1b4Smrg } 18807117f1b4Smrg else { 18817117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 18827117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(pname)"); 18837117f1b4Smrg } 18847117f1b4Smrg return; 18857117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 18867117f1b4Smrg if (att->Type == GL_TEXTURE) { 1887c1f859d4Smrg if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { 1888c1f859d4Smrg *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 1889c1f859d4Smrg } 1890c1f859d4Smrg else { 1891c1f859d4Smrg *params = 0; 1892c1f859d4Smrg } 18937117f1b4Smrg } 18947117f1b4Smrg else { 18957117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 18967117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(pname)"); 18977117f1b4Smrg } 18987117f1b4Smrg return; 18997117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 19007117f1b4Smrg if (att->Type == GL_TEXTURE) { 1901c1f859d4Smrg if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { 1902c1f859d4Smrg *params = att->Zoffset; 1903c1f859d4Smrg } 1904c1f859d4Smrg else { 1905c1f859d4Smrg *params = 0; 1906c1f859d4Smrg } 19077117f1b4Smrg } 19087117f1b4Smrg else { 19097117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 19107117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(pname)"); 19117117f1b4Smrg } 19127117f1b4Smrg return; 19134a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: 19144a49301eSmrg if (!ctx->Extensions.ARB_framebuffer_object) { 19154a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, 19164a49301eSmrg "glGetFramebufferAttachmentParameterivEXT(pname)"); 19174a49301eSmrg } 19184a49301eSmrg else { 19194a49301eSmrg *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); 19204a49301eSmrg } 19214a49301eSmrg return; 19224a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: 19234a49301eSmrg if (!ctx->Extensions.ARB_framebuffer_object) { 19244a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, 19254a49301eSmrg "glGetFramebufferAttachmentParameterivEXT(pname)"); 19264a49301eSmrg return; 19274a49301eSmrg } 19284a49301eSmrg else { 19294a49301eSmrg gl_format format = att->Renderbuffer->Format; 19304a49301eSmrg if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) { 19314a49301eSmrg /* special cases */ 19324a49301eSmrg *params = GL_INDEX; 19334a49301eSmrg } 19344a49301eSmrg else { 19354a49301eSmrg *params = _mesa_get_format_datatype(format); 19364a49301eSmrg } 19374a49301eSmrg } 19384a49301eSmrg return; 19394a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: 19404a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 19414a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 19424a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 19434a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 19444a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 19454a49301eSmrg if (!ctx->Extensions.ARB_framebuffer_object) { 19464a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, 19474a49301eSmrg "glGetFramebufferAttachmentParameterivEXT(pname)"); 19484a49301eSmrg } 19494a49301eSmrg else if (att->Texture) { 19504a49301eSmrg const struct gl_texture_image *texImage = 19514a49301eSmrg _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, 19524a49301eSmrg att->TextureLevel); 19534a49301eSmrg if (texImage) { 19544a49301eSmrg *params = get_component_bits(pname, texImage->_BaseFormat, 19554a49301eSmrg texImage->TexFormat); 19564a49301eSmrg } 19574a49301eSmrg else { 19584a49301eSmrg *params = 0; 19594a49301eSmrg } 19604a49301eSmrg } 19614a49301eSmrg else if (att->Renderbuffer) { 19624a49301eSmrg *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, 19634a49301eSmrg att->Renderbuffer->Format); 19644a49301eSmrg } 19654a49301eSmrg else { 19664a49301eSmrg *params = 0; 19674a49301eSmrg } 19684a49301eSmrg return; 19697117f1b4Smrg default: 19707117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 19717117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(pname)"); 19727117f1b4Smrg return; 19737117f1b4Smrg } 19747117f1b4Smrg} 19757117f1b4Smrg 19767117f1b4Smrg 19777117f1b4Smrgvoid GLAPIENTRY 19787117f1b4Smrg_mesa_GenerateMipmapEXT(GLenum target) 19797117f1b4Smrg{ 19807117f1b4Smrg struct gl_texture_object *texObj; 19817117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 19827117f1b4Smrg 19837117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 19847117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 19857117f1b4Smrg 19867117f1b4Smrg switch (target) { 19877117f1b4Smrg case GL_TEXTURE_1D: 19887117f1b4Smrg case GL_TEXTURE_2D: 19897117f1b4Smrg case GL_TEXTURE_3D: 19907117f1b4Smrg case GL_TEXTURE_CUBE_MAP: 19917117f1b4Smrg /* OK, legal value */ 19927117f1b4Smrg break; 19937117f1b4Smrg default: 19947117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); 19957117f1b4Smrg return; 19967117f1b4Smrg } 19977117f1b4Smrg 19984a49301eSmrg texObj = _mesa_get_current_tex_object(ctx, target); 19994a49301eSmrg 20004a49301eSmrg if (texObj->BaseLevel >= texObj->MaxLevel) { 20014a49301eSmrg /* nothing to do */ 20024a49301eSmrg return; 20034a49301eSmrg } 20047117f1b4Smrg 20057117f1b4Smrg _mesa_lock_texture(ctx, texObj); 2006c1f859d4Smrg if (target == GL_TEXTURE_CUBE_MAP) { 20074a49301eSmrg GLuint face; 2008c1f859d4Smrg for (face = 0; face < 6; face++) 2009c1f859d4Smrg ctx->Driver.GenerateMipmap(ctx, 2010c1f859d4Smrg GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, 2011c1f859d4Smrg texObj); 20124a49301eSmrg } 20134a49301eSmrg else { 2014c1f859d4Smrg ctx->Driver.GenerateMipmap(ctx, target, texObj); 2015c1f859d4Smrg } 20167117f1b4Smrg _mesa_unlock_texture(ctx, texObj); 20177117f1b4Smrg} 20187117f1b4Smrg 20197117f1b4Smrg 20207117f1b4Smrg#if FEATURE_EXT_framebuffer_blit 20214a49301eSmrg 20224a49301eSmrgstatic const struct gl_renderbuffer_attachment * 20234a49301eSmrgfind_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb) 20244a49301eSmrg{ 20254a49301eSmrg GLuint i; 20264a49301eSmrg for (i = 0; i < Elements(fb->Attachment); i++) { 20274a49301eSmrg if (fb->Attachment[i].Renderbuffer == rb) 20284a49301eSmrg return &fb->Attachment[i]; 20294a49301eSmrg } 20304a49301eSmrg return NULL; 20314a49301eSmrg} 20324a49301eSmrg 20334a49301eSmrg 20344a49301eSmrg 20354a49301eSmrg/** 20364a49301eSmrg * Blit rectangular region, optionally from one framebuffer to another. 20374a49301eSmrg * 20384a49301eSmrg * Note, if the src buffer is multisampled and the dest is not, this is 20394a49301eSmrg * when the samples must be resolved to a single color. 20404a49301eSmrg */ 20417117f1b4Smrgvoid GLAPIENTRY 20427117f1b4Smrg_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 20437117f1b4Smrg GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 20447117f1b4Smrg GLbitfield mask, GLenum filter) 20457117f1b4Smrg{ 20464a49301eSmrg const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | 20474a49301eSmrg GL_DEPTH_BUFFER_BIT | 20484a49301eSmrg GL_STENCIL_BUFFER_BIT); 20494a49301eSmrg const struct gl_framebuffer *readFb, *drawFb; 20504a49301eSmrg const struct gl_renderbuffer *colorReadRb, *colorDrawRb; 20517117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 20527117f1b4Smrg 20537117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 20547117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 20557117f1b4Smrg 20567117f1b4Smrg if (ctx->NewState) { 20577117f1b4Smrg _mesa_update_state(ctx); 20587117f1b4Smrg } 20597117f1b4Smrg 20604a49301eSmrg readFb = ctx->ReadBuffer; 20614a49301eSmrg drawFb = ctx->DrawBuffer; 20624a49301eSmrg 20634a49301eSmrg if (!readFb || !drawFb) { 20644a49301eSmrg /* This will normally never happen but someday we may want to 20654a49301eSmrg * support MakeCurrent() with no drawables. 20664a49301eSmrg */ 20674a49301eSmrg return; 20687117f1b4Smrg } 20697117f1b4Smrg 20707117f1b4Smrg /* check for complete framebuffers */ 20714a49301eSmrg if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 20724a49301eSmrg readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 20737117f1b4Smrg _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 20747117f1b4Smrg "glBlitFramebufferEXT(incomplete draw/read buffers)"); 20757117f1b4Smrg return; 20767117f1b4Smrg } 20777117f1b4Smrg 20787117f1b4Smrg if (filter != GL_NEAREST && filter != GL_LINEAR) { 20797117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); 20807117f1b4Smrg return; 20817117f1b4Smrg } 20827117f1b4Smrg 20834a49301eSmrg if (mask & ~legalMaskBits) { 20847117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); 20857117f1b4Smrg return; 20867117f1b4Smrg } 20877117f1b4Smrg 20887117f1b4Smrg /* depth/stencil must be blitted with nearest filtering */ 20897117f1b4Smrg if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) 20907117f1b4Smrg && filter != GL_NEAREST) { 20917117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 20927117f1b4Smrg "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); 20937117f1b4Smrg return; 20947117f1b4Smrg } 20957117f1b4Smrg 20964a49301eSmrg /* get color read/draw renderbuffers */ 20974a49301eSmrg if (mask & GL_COLOR_BUFFER_BIT) { 20984a49301eSmrg colorReadRb = readFb->_ColorReadBuffer; 20994a49301eSmrg colorDrawRb = drawFb->_ColorDrawBuffers[0]; 21004a49301eSmrg } 21014a49301eSmrg else { 21024a49301eSmrg colorReadRb = colorDrawRb = NULL; 21034a49301eSmrg } 21044a49301eSmrg 21057117f1b4Smrg if (mask & GL_STENCIL_BUFFER_BIT) { 21064a49301eSmrg struct gl_renderbuffer *readRb = readFb->_StencilBuffer; 21074a49301eSmrg struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer; 21084a49301eSmrg if (!readRb || 21094a49301eSmrg !drawRb || 21104a49301eSmrg _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != 21114a49301eSmrg _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { 21127117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 21137117f1b4Smrg "glBlitFramebufferEXT(stencil buffer size mismatch"); 21147117f1b4Smrg return; 21157117f1b4Smrg } 21167117f1b4Smrg } 21177117f1b4Smrg 21187117f1b4Smrg if (mask & GL_DEPTH_BUFFER_BIT) { 21194a49301eSmrg struct gl_renderbuffer *readRb = readFb->_DepthBuffer; 21204a49301eSmrg struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer; 21214a49301eSmrg if (!readRb || 21224a49301eSmrg !drawRb || 21234a49301eSmrg _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != 21244a49301eSmrg _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) { 21257117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 21267117f1b4Smrg "glBlitFramebufferEXT(depth buffer size mismatch"); 21277117f1b4Smrg return; 21287117f1b4Smrg } 21297117f1b4Smrg } 21307117f1b4Smrg 21314a49301eSmrg if (readFb->Visual.samples > 0 && 21324a49301eSmrg drawFb->Visual.samples > 0 && 21334a49301eSmrg readFb->Visual.samples != drawFb->Visual.samples) { 21344a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 21354a49301eSmrg "glBlitFramebufferEXT(mismatched samples"); 21364a49301eSmrg return; 21374a49301eSmrg } 21384a49301eSmrg 21394a49301eSmrg /* extra checks for multisample copies... */ 21404a49301eSmrg if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { 21414a49301eSmrg /* src and dest region sizes must be the same */ 21424a49301eSmrg if (srcX1 - srcX0 != dstX1 - dstX0 || 21434a49301eSmrg srcY1 - srcY0 != dstY1 - dstY0) { 21444a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 21454a49301eSmrg "glBlitFramebufferEXT(bad src/dst multisample region sizes"); 21464a49301eSmrg return; 21474a49301eSmrg } 21484a49301eSmrg 21494a49301eSmrg /* color formats must match */ 21504a49301eSmrg if (colorReadRb && 21514a49301eSmrg colorDrawRb && 21524a49301eSmrg colorReadRb->Format != colorDrawRb->Format) { 21534a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 21544a49301eSmrg "glBlitFramebufferEXT(bad src/dst multisample pixel formats"); 21554a49301eSmrg return; 21564a49301eSmrg } 21574a49301eSmrg } 21584a49301eSmrg 21597117f1b4Smrg if (!ctx->Extensions.EXT_framebuffer_blit) { 21607117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); 21617117f1b4Smrg return; 21627117f1b4Smrg } 21637117f1b4Smrg 21644a49301eSmrg /* Debug code */ 21654a49301eSmrg if (DEBUG_BLIT) { 2166cdc920a0Smrg printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," 2167cdc920a0Smrg " 0x%x, 0x%x)\n", 2168cdc920a0Smrg srcX0, srcY0, srcX1, srcY1, 2169cdc920a0Smrg dstX0, dstY0, dstX1, dstY1, 2170cdc920a0Smrg mask, filter); 21714a49301eSmrg if (colorReadRb) { 21724a49301eSmrg const struct gl_renderbuffer_attachment *att; 21734a49301eSmrg 21744a49301eSmrg att = find_attachment(readFb, colorReadRb); 2175cdc920a0Smrg printf(" Src FBO %u RB %u (%dx%d) ", 2176cdc920a0Smrg readFb->Name, colorReadRb->Name, 2177cdc920a0Smrg colorReadRb->Width, colorReadRb->Height); 21784a49301eSmrg if (att && att->Texture) { 2179cdc920a0Smrg printf("Tex %u tgt 0x%x level %u face %u", 2180cdc920a0Smrg att->Texture->Name, 2181cdc920a0Smrg att->Texture->Target, 2182cdc920a0Smrg att->TextureLevel, 2183cdc920a0Smrg att->CubeMapFace); 21844a49301eSmrg } 2185cdc920a0Smrg printf("\n"); 21864a49301eSmrg 21874a49301eSmrg att = find_attachment(drawFb, colorDrawRb); 2188cdc920a0Smrg printf(" Dst FBO %u RB %u (%dx%d) ", 2189cdc920a0Smrg drawFb->Name, colorDrawRb->Name, 2190cdc920a0Smrg colorDrawRb->Width, colorDrawRb->Height); 21914a49301eSmrg if (att && att->Texture) { 2192cdc920a0Smrg printf("Tex %u tgt 0x%x level %u face %u", 2193cdc920a0Smrg att->Texture->Name, 2194cdc920a0Smrg att->Texture->Target, 2195cdc920a0Smrg att->TextureLevel, 2196cdc920a0Smrg att->CubeMapFace); 21974a49301eSmrg } 2198cdc920a0Smrg printf("\n"); 21994a49301eSmrg } 22004a49301eSmrg } 22014a49301eSmrg 22027117f1b4Smrg ASSERT(ctx->Driver.BlitFramebuffer); 22037117f1b4Smrg ctx->Driver.BlitFramebuffer(ctx, 22047117f1b4Smrg srcX0, srcY0, srcX1, srcY1, 22057117f1b4Smrg dstX0, dstY0, dstX1, dstY1, 22067117f1b4Smrg mask, filter); 22077117f1b4Smrg} 22087117f1b4Smrg#endif /* FEATURE_EXT_framebuffer_blit */ 2209