fbobject.c revision af69d88d
17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 4c1f859d4Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 54a49301eSmrg * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. 67117f1b4Smrg * 77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 87117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 97117f1b4Smrg * to deal in the Software without restriction, including without limitation 107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 127117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 137117f1b4Smrg * 147117f1b4Smrg * The above copyright notice and this permission notice shall be included 157117f1b4Smrg * in all copies or substantial portions of the Software. 167117f1b4Smrg * 177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 247117f1b4Smrg */ 257117f1b4Smrg 267117f1b4Smrg 277117f1b4Smrg/* 284a49301eSmrg * GL_EXT/ARB_framebuffer_object extensions 294a49301eSmrg * 307117f1b4Smrg * Authors: 317117f1b4Smrg * Brian Paul 327117f1b4Smrg */ 337117f1b4Smrg 34af69d88dSmrg#include <stdbool.h> 357117f1b4Smrg 36c1f859d4Smrg#include "buffers.h" 377117f1b4Smrg#include "context.h" 384a49301eSmrg#include "enums.h" 397117f1b4Smrg#include "fbobject.h" 404a49301eSmrg#include "formats.h" 417117f1b4Smrg#include "framebuffer.h" 42af69d88dSmrg#include "glformats.h" 437117f1b4Smrg#include "hash.h" 444a49301eSmrg#include "macros.h" 45af69d88dSmrg#include "multisample.h" 463464ebd5Sriastradh#include "mtypes.h" 477117f1b4Smrg#include "renderbuffer.h" 487117f1b4Smrg#include "state.h" 497117f1b4Smrg#include "teximage.h" 507117f1b4Smrg#include "texobj.h" 514a49301eSmrg 524a49301eSmrg 537117f1b4Smrg/** 547117f1b4Smrg * Notes: 557117f1b4Smrg * 567117f1b4Smrg * None of the GL_EXT_framebuffer_object functions are compiled into 577117f1b4Smrg * display lists. 587117f1b4Smrg */ 597117f1b4Smrg 607117f1b4Smrg 617117f1b4Smrg 627117f1b4Smrg/* 637117f1b4Smrg * When glGenRender/FramebuffersEXT() is called we insert pointers to 647117f1b4Smrg * these placeholder objects into the hash table. 657117f1b4Smrg * Later, when the object ID is first bound, we replace the placeholder 667117f1b4Smrg * with the real frame/renderbuffer. 677117f1b4Smrg */ 687117f1b4Smrgstatic struct gl_framebuffer DummyFramebuffer; 697117f1b4Smrgstatic struct gl_renderbuffer DummyRenderbuffer; 707117f1b4Smrg 713464ebd5Sriastradh/* We bind this framebuffer when applications pass a NULL 723464ebd5Sriastradh * drawable/surface in make current. */ 733464ebd5Sriastradhstatic struct gl_framebuffer IncompleteFramebuffer; 747117f1b4Smrg 753464ebd5Sriastradh 76c1f859d4Smrgstatic void 77af69d88dSmrgdelete_dummy_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) 78c1f859d4Smrg{ 79c1f859d4Smrg /* no op */ 80c1f859d4Smrg} 81c1f859d4Smrg 82c1f859d4Smrgstatic void 83c1f859d4Smrgdelete_dummy_framebuffer(struct gl_framebuffer *fb) 84c1f859d4Smrg{ 85c1f859d4Smrg /* no op */ 86c1f859d4Smrg} 87c1f859d4Smrg 88c1f859d4Smrg 89c1f859d4Smrgvoid 903464ebd5Sriastradh_mesa_init_fbobjects(struct gl_context *ctx) 91c1f859d4Smrg{ 92af69d88dSmrg mtx_init(&DummyFramebuffer.Mutex, mtx_plain); 93af69d88dSmrg mtx_init(&DummyRenderbuffer.Mutex, mtx_plain); 94af69d88dSmrg mtx_init(&IncompleteFramebuffer.Mutex, mtx_plain); 95c1f859d4Smrg DummyFramebuffer.Delete = delete_dummy_framebuffer; 96c1f859d4Smrg DummyRenderbuffer.Delete = delete_dummy_renderbuffer; 973464ebd5Sriastradh IncompleteFramebuffer.Delete = delete_dummy_framebuffer; 98c1f859d4Smrg} 99c1f859d4Smrg 1003464ebd5Sriastradhstruct gl_framebuffer * 1013464ebd5Sriastradh_mesa_get_incomplete_framebuffer(void) 1023464ebd5Sriastradh{ 1033464ebd5Sriastradh return &IncompleteFramebuffer; 1043464ebd5Sriastradh} 105c1f859d4Smrg 1067117f1b4Smrg/** 1077117f1b4Smrg * Helper routine for getting a gl_renderbuffer. 1087117f1b4Smrg */ 1097117f1b4Smrgstruct gl_renderbuffer * 1103464ebd5Sriastradh_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id) 1117117f1b4Smrg{ 1127117f1b4Smrg struct gl_renderbuffer *rb; 1137117f1b4Smrg 1147117f1b4Smrg if (id == 0) 1157117f1b4Smrg return NULL; 1167117f1b4Smrg 1177117f1b4Smrg rb = (struct gl_renderbuffer *) 1187117f1b4Smrg _mesa_HashLookup(ctx->Shared->RenderBuffers, id); 1197117f1b4Smrg return rb; 1207117f1b4Smrg} 1217117f1b4Smrg 1227117f1b4Smrg 1237117f1b4Smrg/** 1247117f1b4Smrg * Helper routine for getting a gl_framebuffer. 1257117f1b4Smrg */ 1267117f1b4Smrgstruct gl_framebuffer * 1273464ebd5Sriastradh_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) 1287117f1b4Smrg{ 1297117f1b4Smrg struct gl_framebuffer *fb; 1307117f1b4Smrg 1317117f1b4Smrg if (id == 0) 1327117f1b4Smrg return NULL; 1337117f1b4Smrg 1347117f1b4Smrg fb = (struct gl_framebuffer *) 1357117f1b4Smrg _mesa_HashLookup(ctx->Shared->FrameBuffers, id); 1367117f1b4Smrg return fb; 1377117f1b4Smrg} 1387117f1b4Smrg 1397117f1b4Smrg 1404a49301eSmrg/** 1414a49301eSmrg * Mark the given framebuffer as invalid. This will force the 1424a49301eSmrg * test for framebuffer completeness to be done before the framebuffer 1434a49301eSmrg * is used. 1444a49301eSmrg */ 1454a49301eSmrgstatic void 1464a49301eSmrginvalidate_framebuffer(struct gl_framebuffer *fb) 1474a49301eSmrg{ 1484a49301eSmrg fb->_Status = 0; /* "indeterminate" */ 1494a49301eSmrg} 1504a49301eSmrg 1514a49301eSmrg 1523464ebd5Sriastradh/** 1533464ebd5Sriastradh * Return the gl_framebuffer object which corresponds to the given 1543464ebd5Sriastradh * framebuffer target, such as GL_DRAW_FRAMEBUFFER. 1553464ebd5Sriastradh * Check support for GL_EXT_framebuffer_blit to determine if certain 1563464ebd5Sriastradh * targets are legal. 1573464ebd5Sriastradh * \return gl_framebuffer pointer or NULL if target is illegal 1583464ebd5Sriastradh */ 1593464ebd5Sriastradhstatic struct gl_framebuffer * 1603464ebd5Sriastradhget_framebuffer_target(struct gl_context *ctx, GLenum target) 1613464ebd5Sriastradh{ 162af69d88dSmrg bool have_fb_blit = _mesa_is_gles3(ctx) || _mesa_is_desktop_gl(ctx); 1633464ebd5Sriastradh switch (target) { 1643464ebd5Sriastradh case GL_DRAW_FRAMEBUFFER: 165af69d88dSmrg return have_fb_blit ? ctx->DrawBuffer : NULL; 1663464ebd5Sriastradh case GL_READ_FRAMEBUFFER: 167af69d88dSmrg return have_fb_blit ? ctx->ReadBuffer : NULL; 1683464ebd5Sriastradh case GL_FRAMEBUFFER_EXT: 1693464ebd5Sriastradh return ctx->DrawBuffer; 1703464ebd5Sriastradh default: 1713464ebd5Sriastradh return NULL; 1723464ebd5Sriastradh } 1733464ebd5Sriastradh} 1743464ebd5Sriastradh 1753464ebd5Sriastradh 1767117f1b4Smrg/** 1777117f1b4Smrg * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding 1787117f1b4Smrg * gl_renderbuffer_attachment object. 1793464ebd5Sriastradh * This function is only used for user-created FB objects, not the 1803464ebd5Sriastradh * default / window-system FB object. 1814a49301eSmrg * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to 1824a49301eSmrg * the depth buffer attachment point. 1837117f1b4Smrg */ 184af69d88dSmrgstatic struct gl_renderbuffer_attachment * 185af69d88dSmrgget_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, 186af69d88dSmrg GLenum attachment) 1877117f1b4Smrg{ 1887117f1b4Smrg GLuint i; 1897117f1b4Smrg 190af69d88dSmrg assert(_mesa_is_user_fbo(fb)); 1913464ebd5Sriastradh 1927117f1b4Smrg switch (attachment) { 1937117f1b4Smrg case GL_COLOR_ATTACHMENT0_EXT: 1947117f1b4Smrg case GL_COLOR_ATTACHMENT1_EXT: 1957117f1b4Smrg case GL_COLOR_ATTACHMENT2_EXT: 1967117f1b4Smrg case GL_COLOR_ATTACHMENT3_EXT: 1977117f1b4Smrg case GL_COLOR_ATTACHMENT4_EXT: 1987117f1b4Smrg case GL_COLOR_ATTACHMENT5_EXT: 1997117f1b4Smrg case GL_COLOR_ATTACHMENT6_EXT: 2007117f1b4Smrg case GL_COLOR_ATTACHMENT7_EXT: 2017117f1b4Smrg case GL_COLOR_ATTACHMENT8_EXT: 2027117f1b4Smrg case GL_COLOR_ATTACHMENT9_EXT: 2037117f1b4Smrg case GL_COLOR_ATTACHMENT10_EXT: 2047117f1b4Smrg case GL_COLOR_ATTACHMENT11_EXT: 2057117f1b4Smrg case GL_COLOR_ATTACHMENT12_EXT: 2067117f1b4Smrg case GL_COLOR_ATTACHMENT13_EXT: 2077117f1b4Smrg case GL_COLOR_ATTACHMENT14_EXT: 2087117f1b4Smrg case GL_COLOR_ATTACHMENT15_EXT: 209af69d88dSmrg /* Only OpenGL ES 1.x forbids color attachments other than 210af69d88dSmrg * GL_COLOR_ATTACHMENT0. For all other APIs the limit set by the 211af69d88dSmrg * hardware is used. 212af69d88dSmrg */ 2137117f1b4Smrg i = attachment - GL_COLOR_ATTACHMENT0_EXT; 214af69d88dSmrg if (i >= ctx->Const.MaxColorAttachments 215af69d88dSmrg || (i > 0 && ctx->API == API_OPENGLES)) { 2167117f1b4Smrg return NULL; 2177117f1b4Smrg } 2187117f1b4Smrg return &fb->Attachment[BUFFER_COLOR0 + i]; 2194a49301eSmrg case GL_DEPTH_STENCIL_ATTACHMENT: 220af69d88dSmrg if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) 221af69d88dSmrg return NULL; 2224a49301eSmrg /* fall-through */ 2237117f1b4Smrg case GL_DEPTH_ATTACHMENT_EXT: 2247117f1b4Smrg return &fb->Attachment[BUFFER_DEPTH]; 2257117f1b4Smrg case GL_STENCIL_ATTACHMENT_EXT: 2267117f1b4Smrg return &fb->Attachment[BUFFER_STENCIL]; 2277117f1b4Smrg default: 2287117f1b4Smrg return NULL; 2297117f1b4Smrg } 2307117f1b4Smrg} 2317117f1b4Smrg 2327117f1b4Smrg 2333464ebd5Sriastradh/** 2343464ebd5Sriastradh * As above, but only used for getting attachments of the default / 2353464ebd5Sriastradh * window-system framebuffer (not user-created framebuffer objects). 2363464ebd5Sriastradh */ 2373464ebd5Sriastradhstatic struct gl_renderbuffer_attachment * 2383464ebd5Sriastradh_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, 2393464ebd5Sriastradh GLenum attachment) 2403464ebd5Sriastradh{ 241af69d88dSmrg assert(_mesa_is_winsys_fbo(fb)); 242af69d88dSmrg 243af69d88dSmrg if (_mesa_is_gles3(ctx)) { 244af69d88dSmrg assert(attachment == GL_BACK || 245af69d88dSmrg attachment == GL_DEPTH || 246af69d88dSmrg attachment == GL_STENCIL); 247af69d88dSmrg switch (attachment) { 248af69d88dSmrg case GL_BACK: 249af69d88dSmrg /* Since there is no stereo rendering in ES 3.0, only return the 250af69d88dSmrg * LEFT bits. 251af69d88dSmrg */ 252af69d88dSmrg if (ctx->DrawBuffer->Visual.doubleBufferMode) 253af69d88dSmrg return &fb->Attachment[BUFFER_BACK_LEFT]; 254af69d88dSmrg return &fb->Attachment[BUFFER_FRONT_LEFT]; 255af69d88dSmrg case GL_DEPTH: 256af69d88dSmrg return &fb->Attachment[BUFFER_DEPTH]; 257af69d88dSmrg case GL_STENCIL: 258af69d88dSmrg return &fb->Attachment[BUFFER_STENCIL]; 259af69d88dSmrg } 260af69d88dSmrg } 2613464ebd5Sriastradh 2623464ebd5Sriastradh switch (attachment) { 2633464ebd5Sriastradh case GL_FRONT_LEFT: 2643464ebd5Sriastradh return &fb->Attachment[BUFFER_FRONT_LEFT]; 2653464ebd5Sriastradh case GL_FRONT_RIGHT: 2663464ebd5Sriastradh return &fb->Attachment[BUFFER_FRONT_RIGHT]; 2673464ebd5Sriastradh case GL_BACK_LEFT: 2683464ebd5Sriastradh return &fb->Attachment[BUFFER_BACK_LEFT]; 2693464ebd5Sriastradh case GL_BACK_RIGHT: 2703464ebd5Sriastradh return &fb->Attachment[BUFFER_BACK_RIGHT]; 2713464ebd5Sriastradh case GL_AUX0: 2723464ebd5Sriastradh if (fb->Visual.numAuxBuffers == 1) { 2733464ebd5Sriastradh return &fb->Attachment[BUFFER_AUX0]; 2743464ebd5Sriastradh } 2753464ebd5Sriastradh return NULL; 276af69d88dSmrg 277af69d88dSmrg /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says: 278af69d88dSmrg * 279af69d88dSmrg * "If the default framebuffer is bound to target, then attachment must 280af69d88dSmrg * be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi, 281af69d88dSmrg * identifying a color buffer; DEPTH, identifying the depth buffer; or 282af69d88dSmrg * STENCIL, identifying the stencil buffer." 283af69d88dSmrg * 284af69d88dSmrg * Revision #34 of the ARB_framebuffer_object spec has essentially the same 285af69d88dSmrg * language. However, revision #33 of the ARB_framebuffer_object spec 286af69d88dSmrg * says: 287af69d88dSmrg * 288af69d88dSmrg * "If the default framebuffer is bound to <target>, then <attachment> 289af69d88dSmrg * must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi, 290af69d88dSmrg * DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the 291af69d88dSmrg * depth buffer, or the stencil buffer, and <pname> may be 292af69d88dSmrg * FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or 293af69d88dSmrg * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME." 294af69d88dSmrg * 295af69d88dSmrg * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed 296af69d88dSmrg * from glext.h, so shipping apps should not use those values. 297af69d88dSmrg * 298af69d88dSmrg * Note that neither EXT_framebuffer_object nor OES_framebuffer_object 299af69d88dSmrg * support queries of the window system FBO. 300af69d88dSmrg */ 301af69d88dSmrg case GL_DEPTH: 3023464ebd5Sriastradh return &fb->Attachment[BUFFER_DEPTH]; 303af69d88dSmrg case GL_STENCIL: 3043464ebd5Sriastradh return &fb->Attachment[BUFFER_STENCIL]; 3053464ebd5Sriastradh default: 3063464ebd5Sriastradh return NULL; 3073464ebd5Sriastradh } 3083464ebd5Sriastradh} 3093464ebd5Sriastradh 3103464ebd5Sriastradh 3113464ebd5Sriastradh 3127117f1b4Smrg/** 3137117f1b4Smrg * Remove any texture or renderbuffer attached to the given attachment 3147117f1b4Smrg * point. Update reference counts, etc. 3157117f1b4Smrg */ 316af69d88dSmrgstatic void 317af69d88dSmrgremove_attachment(struct gl_context *ctx, 318af69d88dSmrg struct gl_renderbuffer_attachment *att) 3197117f1b4Smrg{ 320af69d88dSmrg struct gl_renderbuffer *rb = att->Renderbuffer; 321af69d88dSmrg 322af69d88dSmrg /* tell driver that we're done rendering to this texture. */ 323af69d88dSmrg if (rb && rb->NeedsFinishRenderTexture) 324af69d88dSmrg ctx->Driver.FinishRenderTexture(ctx, rb); 325af69d88dSmrg 3267117f1b4Smrg if (att->Type == GL_TEXTURE) { 3277117f1b4Smrg ASSERT(att->Texture); 3287117f1b4Smrg _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ 3297117f1b4Smrg ASSERT(!att->Texture); 3307117f1b4Smrg } 3317117f1b4Smrg if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { 3327117f1b4Smrg ASSERT(!att->Texture); 3337117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ 3347117f1b4Smrg ASSERT(!att->Renderbuffer); 3357117f1b4Smrg } 3367117f1b4Smrg att->Type = GL_NONE; 3377117f1b4Smrg att->Complete = GL_TRUE; 3387117f1b4Smrg} 3397117f1b4Smrg 340af69d88dSmrg/** 341af69d88dSmrg * Verify a couple error conditions that will lead to an incomplete FBO and 342af69d88dSmrg * may cause problems for the driver's RenderTexture path. 343af69d88dSmrg */ 344af69d88dSmrgstatic bool 345af69d88dSmrgdriver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att) 346af69d88dSmrg{ 347af69d88dSmrg const struct gl_texture_image *const texImage = 348af69d88dSmrg att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 349af69d88dSmrg 350af69d88dSmrg if (texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0) 351af69d88dSmrg return false; 352af69d88dSmrg 353af69d88dSmrg if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY 354af69d88dSmrg && att->Zoffset >= texImage->Height) 355af69d88dSmrg || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY 356af69d88dSmrg && att->Zoffset >= texImage->Depth)) 357af69d88dSmrg return false; 358af69d88dSmrg 359af69d88dSmrg return true; 360af69d88dSmrg} 361af69d88dSmrg 362af69d88dSmrg/** 363af69d88dSmrg * Create a renderbuffer which will be set up by the driver to wrap the 364af69d88dSmrg * texture image slice. 365af69d88dSmrg * 366af69d88dSmrg * By using a gl_renderbuffer (like user-allocated renderbuffers), drivers get 367af69d88dSmrg * to share most of their framebuffer rendering code between winsys, 368af69d88dSmrg * renderbuffer, and texture attachments. 369af69d88dSmrg * 370af69d88dSmrg * The allocated renderbuffer uses a non-zero Name so that drivers can check 371af69d88dSmrg * it for determining vertical orientation, but we use ~0 to make it fairly 372af69d88dSmrg * unambiguous with actual user (non-texture) renderbuffers. 373af69d88dSmrg */ 374af69d88dSmrgvoid 375af69d88dSmrg_mesa_update_texture_renderbuffer(struct gl_context *ctx, 376af69d88dSmrg struct gl_framebuffer *fb, 377af69d88dSmrg struct gl_renderbuffer_attachment *att) 378af69d88dSmrg{ 379af69d88dSmrg struct gl_texture_image *texImage; 380af69d88dSmrg struct gl_renderbuffer *rb; 381af69d88dSmrg 382af69d88dSmrg texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 383af69d88dSmrg 384af69d88dSmrg rb = att->Renderbuffer; 385af69d88dSmrg if (!rb) { 386af69d88dSmrg rb = ctx->Driver.NewRenderbuffer(ctx, ~0); 387af69d88dSmrg if (!rb) { 388af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); 389af69d88dSmrg return; 390af69d88dSmrg } 391af69d88dSmrg _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 392af69d88dSmrg 393af69d88dSmrg /* This can't get called on a texture renderbuffer, so set it to NULL 394af69d88dSmrg * for clarity compared to user renderbuffers. 395af69d88dSmrg */ 396af69d88dSmrg rb->AllocStorage = NULL; 397af69d88dSmrg 398af69d88dSmrg rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL; 399af69d88dSmrg } 400af69d88dSmrg 401af69d88dSmrg if (!texImage) 402af69d88dSmrg return; 403af69d88dSmrg 404af69d88dSmrg rb->_BaseFormat = texImage->_BaseFormat; 405af69d88dSmrg rb->Format = texImage->TexFormat; 406af69d88dSmrg rb->InternalFormat = texImage->InternalFormat; 407af69d88dSmrg rb->Width = texImage->Width2; 408af69d88dSmrg rb->Height = texImage->Height2; 409af69d88dSmrg rb->Depth = texImage->Depth2; 410af69d88dSmrg rb->NumSamples = texImage->NumSamples; 411af69d88dSmrg rb->TexImage = texImage; 412af69d88dSmrg 413af69d88dSmrg if (driver_RenderTexture_is_safe(att)) 414af69d88dSmrg ctx->Driver.RenderTexture(ctx, fb, att); 415af69d88dSmrg} 4167117f1b4Smrg 4177117f1b4Smrg/** 4187117f1b4Smrg * Bind a texture object to an attachment point. 4197117f1b4Smrg * The previous binding, if any, will be removed first. 4207117f1b4Smrg */ 421af69d88dSmrgstatic void 422af69d88dSmrgset_texture_attachment(struct gl_context *ctx, 423af69d88dSmrg struct gl_framebuffer *fb, 424af69d88dSmrg struct gl_renderbuffer_attachment *att, 425af69d88dSmrg struct gl_texture_object *texObj, 426af69d88dSmrg GLenum texTarget, GLuint level, GLuint zoffset, 427af69d88dSmrg GLboolean layered) 4287117f1b4Smrg{ 429af69d88dSmrg struct gl_renderbuffer *rb = att->Renderbuffer; 430af69d88dSmrg 431af69d88dSmrg if (rb && rb->NeedsFinishRenderTexture) 432af69d88dSmrg ctx->Driver.FinishRenderTexture(ctx, rb); 433af69d88dSmrg 4347117f1b4Smrg if (att->Texture == texObj) { 4357117f1b4Smrg /* re-attaching same texture */ 4367117f1b4Smrg ASSERT(att->Type == GL_TEXTURE); 4377117f1b4Smrg } 4387117f1b4Smrg else { 4397117f1b4Smrg /* new attachment */ 440af69d88dSmrg remove_attachment(ctx, att); 4417117f1b4Smrg att->Type = GL_TEXTURE; 4427117f1b4Smrg assert(!att->Texture); 4437117f1b4Smrg _mesa_reference_texobj(&att->Texture, texObj); 4447117f1b4Smrg } 445af69d88dSmrg invalidate_framebuffer(fb); 4467117f1b4Smrg 4477117f1b4Smrg /* always update these fields */ 4487117f1b4Smrg att->TextureLevel = level; 4494a49301eSmrg att->CubeMapFace = _mesa_tex_target_to_face(texTarget); 4507117f1b4Smrg att->Zoffset = zoffset; 451af69d88dSmrg att->Layered = layered; 4527117f1b4Smrg att->Complete = GL_FALSE; 4537117f1b4Smrg 454af69d88dSmrg _mesa_update_texture_renderbuffer(ctx, fb, att); 4557117f1b4Smrg} 4567117f1b4Smrg 4577117f1b4Smrg 4587117f1b4Smrg/** 4597117f1b4Smrg * Bind a renderbuffer to an attachment point. 4607117f1b4Smrg * The previous binding, if any, will be removed first. 4617117f1b4Smrg */ 462af69d88dSmrgstatic void 463af69d88dSmrgset_renderbuffer_attachment(struct gl_context *ctx, 464af69d88dSmrg struct gl_renderbuffer_attachment *att, 465af69d88dSmrg struct gl_renderbuffer *rb) 4667117f1b4Smrg{ 4677117f1b4Smrg /* XXX check if re-doing same attachment, exit early */ 468af69d88dSmrg remove_attachment(ctx, att); 4697117f1b4Smrg att->Type = GL_RENDERBUFFER_EXT; 4707117f1b4Smrg att->Texture = NULL; /* just to be safe */ 4717117f1b4Smrg att->Complete = GL_FALSE; 4727117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 4737117f1b4Smrg} 4747117f1b4Smrg 4757117f1b4Smrg 4767117f1b4Smrg/** 4777117f1b4Smrg * Fallback for ctx->Driver.FramebufferRenderbuffer() 4787117f1b4Smrg * Attach a renderbuffer object to a framebuffer object. 4797117f1b4Smrg */ 4807117f1b4Smrgvoid 4813464ebd5Sriastradh_mesa_framebuffer_renderbuffer(struct gl_context *ctx, 4823464ebd5Sriastradh struct gl_framebuffer *fb, 4837117f1b4Smrg GLenum attachment, struct gl_renderbuffer *rb) 4847117f1b4Smrg{ 4857117f1b4Smrg struct gl_renderbuffer_attachment *att; 4867117f1b4Smrg 487af69d88dSmrg mtx_lock(&fb->Mutex); 4887117f1b4Smrg 489af69d88dSmrg att = get_attachment(ctx, fb, attachment); 4907117f1b4Smrg ASSERT(att); 4917117f1b4Smrg if (rb) { 492af69d88dSmrg set_renderbuffer_attachment(ctx, att, rb); 4934a49301eSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 4944a49301eSmrg /* do stencil attachment here (depth already done above) */ 495af69d88dSmrg att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); 4964a49301eSmrg assert(att); 497af69d88dSmrg set_renderbuffer_attachment(ctx, att, rb); 4984a49301eSmrg } 4993464ebd5Sriastradh rb->AttachedAnytime = GL_TRUE; 5007117f1b4Smrg } 5017117f1b4Smrg else { 502af69d88dSmrg remove_attachment(ctx, att); 503af69d88dSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 504af69d88dSmrg /* detach stencil (depth was detached above) */ 505af69d88dSmrg att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); 506af69d88dSmrg assert(att); 507af69d88dSmrg remove_attachment(ctx, att); 508af69d88dSmrg } 5097117f1b4Smrg } 5107117f1b4Smrg 5114a49301eSmrg invalidate_framebuffer(fb); 5124a49301eSmrg 513af69d88dSmrg mtx_unlock(&fb->Mutex); 5147117f1b4Smrg} 5157117f1b4Smrg 5167117f1b4Smrg 5173464ebd5Sriastradh/** 5183464ebd5Sriastradh * Fallback for ctx->Driver.ValidateFramebuffer() 5193464ebd5Sriastradh * Check if the renderbuffer's formats are supported by the software 5203464ebd5Sriastradh * renderer. 5213464ebd5Sriastradh * Drivers should probably override this. 5223464ebd5Sriastradh */ 5233464ebd5Sriastradhvoid 5243464ebd5Sriastradh_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) 5253464ebd5Sriastradh{ 5263464ebd5Sriastradh gl_buffer_index buf; 5273464ebd5Sriastradh for (buf = 0; buf < BUFFER_COUNT; buf++) { 5283464ebd5Sriastradh const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer; 5293464ebd5Sriastradh if (rb) { 5303464ebd5Sriastradh switch (rb->_BaseFormat) { 5313464ebd5Sriastradh case GL_ALPHA: 5323464ebd5Sriastradh case GL_LUMINANCE_ALPHA: 5333464ebd5Sriastradh case GL_LUMINANCE: 5343464ebd5Sriastradh case GL_INTENSITY: 5353464ebd5Sriastradh case GL_RED: 5363464ebd5Sriastradh case GL_RG: 5373464ebd5Sriastradh fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 5383464ebd5Sriastradh return; 5393464ebd5Sriastradh 5403464ebd5Sriastradh default: 5413464ebd5Sriastradh switch (rb->Format) { 5423464ebd5Sriastradh /* XXX This list is likely incomplete. */ 543af69d88dSmrg case MESA_FORMAT_R9G9B9E5_FLOAT: 5443464ebd5Sriastradh fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 5453464ebd5Sriastradh return; 5463464ebd5Sriastradh default:; 5473464ebd5Sriastradh /* render buffer format is supported by software rendering */ 5483464ebd5Sriastradh } 5493464ebd5Sriastradh } 5503464ebd5Sriastradh } 5513464ebd5Sriastradh } 5523464ebd5Sriastradh} 5533464ebd5Sriastradh 5543464ebd5Sriastradh 555af69d88dSmrg/** 556af69d88dSmrg * Return true if the framebuffer has a combined depth/stencil 557af69d88dSmrg * renderbuffer attached. 558af69d88dSmrg */ 559af69d88dSmrgGLboolean 560af69d88dSmrg_mesa_has_depthstencil_combined(const struct gl_framebuffer *fb) 561af69d88dSmrg{ 562af69d88dSmrg const struct gl_renderbuffer_attachment *depth = 563af69d88dSmrg &fb->Attachment[BUFFER_DEPTH]; 564af69d88dSmrg const struct gl_renderbuffer_attachment *stencil = 565af69d88dSmrg &fb->Attachment[BUFFER_STENCIL]; 566af69d88dSmrg 567af69d88dSmrg if (depth->Type == stencil->Type) { 568af69d88dSmrg if (depth->Type == GL_RENDERBUFFER_EXT && 569af69d88dSmrg depth->Renderbuffer == stencil->Renderbuffer) 570af69d88dSmrg return GL_TRUE; 571af69d88dSmrg 572af69d88dSmrg if (depth->Type == GL_TEXTURE && 573af69d88dSmrg depth->Texture == stencil->Texture) 574af69d88dSmrg return GL_TRUE; 575af69d88dSmrg } 576af69d88dSmrg 577af69d88dSmrg return GL_FALSE; 578af69d88dSmrg} 579af69d88dSmrg 580af69d88dSmrg 5814a49301eSmrg/** 5824a49301eSmrg * For debug only. 5834a49301eSmrg */ 5844a49301eSmrgstatic void 5854a49301eSmrgatt_incomplete(const char *msg) 5864a49301eSmrg{ 587af69d88dSmrg if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { 588af69d88dSmrg _mesa_debug(NULL, "attachment incomplete: %s\n", msg); 589af69d88dSmrg } 5904a49301eSmrg} 5914a49301eSmrg 5924a49301eSmrg 5934a49301eSmrg/** 5944a49301eSmrg * For debug only. 5954a49301eSmrg */ 5964a49301eSmrgstatic void 597af69d88dSmrgfbo_incomplete(struct gl_context *ctx, const char *msg, int index) 5984a49301eSmrg{ 599af69d88dSmrg static GLuint msg_id; 600af69d88dSmrg 601af69d88dSmrg _mesa_gl_debug(ctx, &msg_id, 602af69d88dSmrg MESA_DEBUG_TYPE_OTHER, 603af69d88dSmrg MESA_DEBUG_SEVERITY_MEDIUM, 604af69d88dSmrg "FBO incomplete: %s [%d]\n", msg, index); 605af69d88dSmrg 606af69d88dSmrg if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { 607af69d88dSmrg _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); 608af69d88dSmrg } 6094a49301eSmrg} 6104a49301eSmrg 6114a49301eSmrg 6123464ebd5Sriastradh/** 6133464ebd5Sriastradh * Is the given base format a legal format for a color renderbuffer? 6143464ebd5Sriastradh */ 6153464ebd5SriastradhGLboolean 6163464ebd5Sriastradh_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) 6173464ebd5Sriastradh{ 6183464ebd5Sriastradh switch (baseFormat) { 6193464ebd5Sriastradh case GL_RGB: 6203464ebd5Sriastradh case GL_RGBA: 6213464ebd5Sriastradh return GL_TRUE; 6223464ebd5Sriastradh case GL_LUMINANCE: 6233464ebd5Sriastradh case GL_LUMINANCE_ALPHA: 6243464ebd5Sriastradh case GL_INTENSITY: 6253464ebd5Sriastradh case GL_ALPHA: 626af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 627af69d88dSmrg ctx->Extensions.ARB_framebuffer_object; 6283464ebd5Sriastradh case GL_RED: 6293464ebd5Sriastradh case GL_RG: 6303464ebd5Sriastradh return ctx->Extensions.ARB_texture_rg; 6313464ebd5Sriastradh default: 6323464ebd5Sriastradh return GL_FALSE; 6333464ebd5Sriastradh } 6343464ebd5Sriastradh} 6353464ebd5Sriastradh 6363464ebd5Sriastradh 637af69d88dSmrg/** 638af69d88dSmrg * Is the given base format a legal format for a color renderbuffer? 639af69d88dSmrg */ 640af69d88dSmrgstatic GLboolean 641af69d88dSmrgis_format_color_renderable(const struct gl_context *ctx, mesa_format format, 642af69d88dSmrg GLenum internalFormat) 643af69d88dSmrg{ 644af69d88dSmrg const GLenum baseFormat = 645af69d88dSmrg _mesa_get_format_base_format(format); 646af69d88dSmrg GLboolean valid; 647af69d88dSmrg 648af69d88dSmrg valid = _mesa_is_legal_color_format(ctx, baseFormat); 649af69d88dSmrg if (!valid || _mesa_is_desktop_gl(ctx)) { 650af69d88dSmrg return valid; 651af69d88dSmrg } 652af69d88dSmrg 653af69d88dSmrg /* Reject additional cases for GLES */ 654af69d88dSmrg switch (internalFormat) { 655af69d88dSmrg case GL_RGBA8_SNORM: 656af69d88dSmrg case GL_RGB32F: 657af69d88dSmrg case GL_RGB32I: 658af69d88dSmrg case GL_RGB32UI: 659af69d88dSmrg case GL_RGB16F: 660af69d88dSmrg case GL_RGB16I: 661af69d88dSmrg case GL_RGB16UI: 662af69d88dSmrg case GL_RGB8_SNORM: 663af69d88dSmrg case GL_RGB8I: 664af69d88dSmrg case GL_RGB8UI: 665af69d88dSmrg case GL_SRGB8: 666af69d88dSmrg case GL_RGB9_E5: 667af69d88dSmrg case GL_RG8_SNORM: 668af69d88dSmrg case GL_R8_SNORM: 669af69d88dSmrg return GL_FALSE; 670af69d88dSmrg default: 671af69d88dSmrg break; 672af69d88dSmrg } 673af69d88dSmrg 674af69d88dSmrg if (format == MESA_FORMAT_B10G10R10A2_UNORM && 675af69d88dSmrg internalFormat != GL_RGB10_A2) { 676af69d88dSmrg return GL_FALSE; 677af69d88dSmrg } 678af69d88dSmrg 679af69d88dSmrg return GL_TRUE; 680af69d88dSmrg} 681af69d88dSmrg 682af69d88dSmrg 6833464ebd5Sriastradh/** 6843464ebd5Sriastradh * Is the given base format a legal format for a depth/stencil renderbuffer? 6853464ebd5Sriastradh */ 6863464ebd5Sriastradhstatic GLboolean 6873464ebd5Sriastradhis_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat) 6883464ebd5Sriastradh{ 6893464ebd5Sriastradh switch (baseFormat) { 6903464ebd5Sriastradh case GL_DEPTH_COMPONENT: 6913464ebd5Sriastradh case GL_DEPTH_STENCIL_EXT: 6923464ebd5Sriastradh return GL_TRUE; 6933464ebd5Sriastradh default: 6943464ebd5Sriastradh return GL_FALSE; 6953464ebd5Sriastradh } 6963464ebd5Sriastradh} 6974a49301eSmrg 6984a49301eSmrg 6997117f1b4Smrg/** 7007117f1b4Smrg * Test if an attachment point is complete and update its Complete field. 7017117f1b4Smrg * \param format if GL_COLOR, this is a color attachment point, 7027117f1b4Smrg * if GL_DEPTH, this is a depth component attachment point, 7037117f1b4Smrg * if GL_STENCIL, this is a stencil component attachment point. 7047117f1b4Smrg */ 7057117f1b4Smrgstatic void 7063464ebd5Sriastradhtest_attachment_completeness(const struct gl_context *ctx, GLenum format, 7077117f1b4Smrg struct gl_renderbuffer_attachment *att) 7087117f1b4Smrg{ 7097117f1b4Smrg assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); 7107117f1b4Smrg 7117117f1b4Smrg /* assume complete */ 7127117f1b4Smrg att->Complete = GL_TRUE; 7137117f1b4Smrg 7147117f1b4Smrg /* Look for reasons why the attachment might be incomplete */ 7157117f1b4Smrg if (att->Type == GL_TEXTURE) { 7167117f1b4Smrg const struct gl_texture_object *texObj = att->Texture; 7177117f1b4Smrg struct gl_texture_image *texImage; 7184a49301eSmrg GLenum baseFormat; 7197117f1b4Smrg 7207117f1b4Smrg if (!texObj) { 7214a49301eSmrg att_incomplete("no texobj"); 7227117f1b4Smrg att->Complete = GL_FALSE; 7237117f1b4Smrg return; 7247117f1b4Smrg } 7257117f1b4Smrg 7267117f1b4Smrg texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; 7277117f1b4Smrg if (!texImage) { 7284a49301eSmrg att_incomplete("no teximage"); 7297117f1b4Smrg att->Complete = GL_FALSE; 7307117f1b4Smrg return; 7317117f1b4Smrg } 7327117f1b4Smrg if (texImage->Width < 1 || texImage->Height < 1) { 7334a49301eSmrg att_incomplete("teximage width/height=0"); 7347117f1b4Smrg att->Complete = GL_FALSE; 7357117f1b4Smrg return; 7367117f1b4Smrg } 737af69d88dSmrg 738af69d88dSmrg switch (texObj->Target) { 739af69d88dSmrg case GL_TEXTURE_3D: 740af69d88dSmrg if (att->Zoffset >= texImage->Depth) { 741af69d88dSmrg att_incomplete("bad z offset"); 742af69d88dSmrg att->Complete = GL_FALSE; 743af69d88dSmrg return; 744af69d88dSmrg } 745af69d88dSmrg break; 746af69d88dSmrg case GL_TEXTURE_1D_ARRAY: 747af69d88dSmrg if (att->Zoffset >= texImage->Height) { 748af69d88dSmrg att_incomplete("bad 1D-array layer"); 749af69d88dSmrg att->Complete = GL_FALSE; 750af69d88dSmrg return; 751af69d88dSmrg } 752af69d88dSmrg break; 753af69d88dSmrg case GL_TEXTURE_2D_ARRAY: 754af69d88dSmrg if (att->Zoffset >= texImage->Depth) { 755af69d88dSmrg att_incomplete("bad 2D-array layer"); 756af69d88dSmrg att->Complete = GL_FALSE; 757af69d88dSmrg return; 758af69d88dSmrg } 759af69d88dSmrg break; 760af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 761af69d88dSmrg if (att->Zoffset >= texImage->Depth) { 762af69d88dSmrg att_incomplete("bad cube-array layer"); 763af69d88dSmrg att->Complete = GL_FALSE; 764af69d88dSmrg return; 765af69d88dSmrg } 766af69d88dSmrg break; 7677117f1b4Smrg } 7687117f1b4Smrg 7694a49301eSmrg baseFormat = _mesa_get_format_base_format(texImage->TexFormat); 7704a49301eSmrg 7717117f1b4Smrg if (format == GL_COLOR) { 7723464ebd5Sriastradh if (!_mesa_is_legal_color_format(ctx, baseFormat)) { 7734a49301eSmrg att_incomplete("bad format"); 7744a49301eSmrg att->Complete = GL_FALSE; 7754a49301eSmrg return; 7764a49301eSmrg } 7774a49301eSmrg if (_mesa_is_format_compressed(texImage->TexFormat)) { 7784a49301eSmrg att_incomplete("compressed internalformat"); 7797117f1b4Smrg att->Complete = GL_FALSE; 7807117f1b4Smrg return; 7817117f1b4Smrg } 7827117f1b4Smrg } 7837117f1b4Smrg else if (format == GL_DEPTH) { 7844a49301eSmrg if (baseFormat == GL_DEPTH_COMPONENT) { 7857117f1b4Smrg /* OK */ 7867117f1b4Smrg } 787af69d88dSmrg else if (ctx->Extensions.ARB_depth_texture && 788af69d88dSmrg baseFormat == GL_DEPTH_STENCIL) { 7897117f1b4Smrg /* OK */ 7907117f1b4Smrg } 7917117f1b4Smrg else { 7927117f1b4Smrg att->Complete = GL_FALSE; 7934a49301eSmrg att_incomplete("bad depth format"); 7947117f1b4Smrg return; 7957117f1b4Smrg } 7967117f1b4Smrg } 7977117f1b4Smrg else { 798c7037ccdSmrg ASSERT(format == GL_STENCIL); 799af69d88dSmrg if (ctx->Extensions.ARB_depth_texture && 800af69d88dSmrg baseFormat == GL_DEPTH_STENCIL) { 801c7037ccdSmrg /* OK */ 802c7037ccdSmrg } 803c7037ccdSmrg else { 804c7037ccdSmrg /* no such thing as stencil-only textures */ 8054a49301eSmrg att_incomplete("illegal stencil texture"); 806c7037ccdSmrg att->Complete = GL_FALSE; 807c7037ccdSmrg return; 808c7037ccdSmrg } 8097117f1b4Smrg } 8107117f1b4Smrg } 8117117f1b4Smrg else if (att->Type == GL_RENDERBUFFER_EXT) { 8124a49301eSmrg const GLenum baseFormat = 8134a49301eSmrg _mesa_get_format_base_format(att->Renderbuffer->Format); 8144a49301eSmrg 8157117f1b4Smrg ASSERT(att->Renderbuffer); 8167117f1b4Smrg if (!att->Renderbuffer->InternalFormat || 8177117f1b4Smrg att->Renderbuffer->Width < 1 || 8187117f1b4Smrg att->Renderbuffer->Height < 1) { 8194a49301eSmrg att_incomplete("0x0 renderbuffer"); 8207117f1b4Smrg att->Complete = GL_FALSE; 8217117f1b4Smrg return; 8227117f1b4Smrg } 8237117f1b4Smrg if (format == GL_COLOR) { 8243464ebd5Sriastradh if (!_mesa_is_legal_color_format(ctx, baseFormat)) { 8254a49301eSmrg att_incomplete("bad renderbuffer color format"); 8267117f1b4Smrg att->Complete = GL_FALSE; 8277117f1b4Smrg return; 8287117f1b4Smrg } 8297117f1b4Smrg } 8307117f1b4Smrg else if (format == GL_DEPTH) { 8314a49301eSmrg if (baseFormat == GL_DEPTH_COMPONENT) { 8327117f1b4Smrg /* OK */ 8337117f1b4Smrg } 834af69d88dSmrg else if (baseFormat == GL_DEPTH_STENCIL) { 8357117f1b4Smrg /* OK */ 8367117f1b4Smrg } 8377117f1b4Smrg else { 8384a49301eSmrg att_incomplete("bad renderbuffer depth format"); 8397117f1b4Smrg att->Complete = GL_FALSE; 8407117f1b4Smrg return; 8417117f1b4Smrg } 8427117f1b4Smrg } 8437117f1b4Smrg else { 8447117f1b4Smrg assert(format == GL_STENCIL); 845af69d88dSmrg if (baseFormat == GL_STENCIL_INDEX || 846af69d88dSmrg baseFormat == GL_DEPTH_STENCIL) { 8477117f1b4Smrg /* OK */ 8487117f1b4Smrg } 8497117f1b4Smrg else { 8507117f1b4Smrg att->Complete = GL_FALSE; 8514a49301eSmrg att_incomplete("bad renderbuffer stencil format"); 8527117f1b4Smrg return; 8537117f1b4Smrg } 8547117f1b4Smrg } 8557117f1b4Smrg } 8567117f1b4Smrg else { 8577117f1b4Smrg ASSERT(att->Type == GL_NONE); 8587117f1b4Smrg /* complete */ 8597117f1b4Smrg return; 8607117f1b4Smrg } 8617117f1b4Smrg} 8627117f1b4Smrg 8637117f1b4Smrg 8647117f1b4Smrg/** 8657117f1b4Smrg * Test if the given framebuffer object is complete and update its 8667117f1b4Smrg * Status field with the results. 8674a49301eSmrg * Calls the ctx->Driver.ValidateFramebuffer() function to allow the 8684a49301eSmrg * driver to make hardware-specific validation/completeness checks. 8697117f1b4Smrg * Also update the framebuffer's Width and Height fields if the 8707117f1b4Smrg * framebuffer is complete. 8717117f1b4Smrg */ 8727117f1b4Smrgvoid 8733464ebd5Sriastradh_mesa_test_framebuffer_completeness(struct gl_context *ctx, 8743464ebd5Sriastradh struct gl_framebuffer *fb) 8757117f1b4Smrg{ 8764a49301eSmrg GLuint numImages; 8774a49301eSmrg GLenum intFormat = GL_NONE; /* color buffers' internal format */ 8784a49301eSmrg GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; 8794a49301eSmrg GLint numSamples = -1; 880af69d88dSmrg GLint fixedSampleLocations = -1; 8817117f1b4Smrg GLint i; 8827117f1b4Smrg GLuint j; 883af69d88dSmrg /* Covers max_layer_count, is_layered, and layer_tex_target */ 884af69d88dSmrg bool layer_info_valid = false; 885af69d88dSmrg GLuint max_layer_count = 0, att_layer_count; 886af69d88dSmrg bool is_layered = false; 887af69d88dSmrg GLenum layer_tex_target = 0; 888af69d88dSmrg 889af69d88dSmrg assert(_mesa_is_user_fbo(fb)); 8907117f1b4Smrg 891af69d88dSmrg /* we're changing framebuffer fields here */ 892af69d88dSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 8937117f1b4Smrg 8947117f1b4Smrg numImages = 0; 8957117f1b4Smrg fb->Width = 0; 8967117f1b4Smrg fb->Height = 0; 897af69d88dSmrg fb->_AllColorBuffersFixedPoint = GL_TRUE; 898af69d88dSmrg fb->_HasSNormOrFloatColorBuffer = GL_FALSE; 8997117f1b4Smrg 9004a49301eSmrg /* Start at -2 to more easily loop over all attachment points. 9014a49301eSmrg * -2: depth buffer 9024a49301eSmrg * -1: stencil buffer 9034a49301eSmrg * >=0: color buffer 9044a49301eSmrg */ 9057117f1b4Smrg for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { 9067117f1b4Smrg struct gl_renderbuffer_attachment *att; 9077117f1b4Smrg GLenum f; 908af69d88dSmrg mesa_format attFormat; 909af69d88dSmrg GLenum att_tex_target = GL_NONE; 9107117f1b4Smrg 9114a49301eSmrg /* 9124a49301eSmrg * XXX for ARB_fbo, only check color buffers that are named by 9134a49301eSmrg * GL_READ_BUFFER and GL_DRAW_BUFFERi. 9144a49301eSmrg */ 9154a49301eSmrg 9164a49301eSmrg /* check for attachment completeness 9174a49301eSmrg */ 9187117f1b4Smrg if (i == -2) { 9197117f1b4Smrg att = &fb->Attachment[BUFFER_DEPTH]; 9207117f1b4Smrg test_attachment_completeness(ctx, GL_DEPTH, att); 9217117f1b4Smrg if (!att->Complete) { 9227117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 923af69d88dSmrg fbo_incomplete(ctx, "depth attachment incomplete", -1); 9247117f1b4Smrg return; 9257117f1b4Smrg } 9267117f1b4Smrg } 9277117f1b4Smrg else if (i == -1) { 9287117f1b4Smrg att = &fb->Attachment[BUFFER_STENCIL]; 9297117f1b4Smrg test_attachment_completeness(ctx, GL_STENCIL, att); 9307117f1b4Smrg if (!att->Complete) { 9317117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 932af69d88dSmrg fbo_incomplete(ctx, "stencil attachment incomplete", -1); 9337117f1b4Smrg return; 9347117f1b4Smrg } 9357117f1b4Smrg } 9367117f1b4Smrg else { 9377117f1b4Smrg att = &fb->Attachment[BUFFER_COLOR0 + i]; 9387117f1b4Smrg test_attachment_completeness(ctx, GL_COLOR, att); 9397117f1b4Smrg if (!att->Complete) { 9407117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 941af69d88dSmrg fbo_incomplete(ctx, "color attachment incomplete", i); 9427117f1b4Smrg return; 9437117f1b4Smrg } 9447117f1b4Smrg } 9457117f1b4Smrg 9464a49301eSmrg /* get width, height, format of the renderbuffer/texture 9474a49301eSmrg */ 9487117f1b4Smrg if (att->Type == GL_TEXTURE) { 949af69d88dSmrg const struct gl_texture_image *texImg = att->Renderbuffer->TexImage; 950af69d88dSmrg att_tex_target = att->Texture->Target; 9514a49301eSmrg minWidth = MIN2(minWidth, texImg->Width); 9524a49301eSmrg maxWidth = MAX2(maxWidth, texImg->Width); 9534a49301eSmrg minHeight = MIN2(minHeight, texImg->Height); 9544a49301eSmrg maxHeight = MAX2(maxHeight, texImg->Height); 9557117f1b4Smrg f = texImg->_BaseFormat; 9563464ebd5Sriastradh attFormat = texImg->TexFormat; 9577117f1b4Smrg numImages++; 958af69d88dSmrg 959af69d88dSmrg if (!is_format_color_renderable(ctx, attFormat, 960af69d88dSmrg texImg->InternalFormat) && 9613464ebd5Sriastradh !is_legal_depth_format(ctx, f)) { 9627117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 963af69d88dSmrg fbo_incomplete(ctx, "texture attachment incomplete", -1); 964af69d88dSmrg return; 965af69d88dSmrg } 966af69d88dSmrg 967af69d88dSmrg if (numSamples < 0) 968af69d88dSmrg numSamples = texImg->NumSamples; 969af69d88dSmrg else if (numSamples != texImg->NumSamples) { 970af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 971af69d88dSmrg fbo_incomplete(ctx, "inconsistent sample count", -1); 972af69d88dSmrg return; 973af69d88dSmrg } 974af69d88dSmrg 975af69d88dSmrg if (fixedSampleLocations < 0) 976af69d88dSmrg fixedSampleLocations = texImg->FixedSampleLocations; 977af69d88dSmrg else if (fixedSampleLocations != texImg->FixedSampleLocations) { 978af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 979af69d88dSmrg fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); 9807117f1b4Smrg return; 9817117f1b4Smrg } 9827117f1b4Smrg } 9837117f1b4Smrg else if (att->Type == GL_RENDERBUFFER_EXT) { 9844a49301eSmrg minWidth = MIN2(minWidth, att->Renderbuffer->Width); 9854a49301eSmrg maxWidth = MAX2(minWidth, att->Renderbuffer->Width); 9864a49301eSmrg minHeight = MIN2(minHeight, att->Renderbuffer->Height); 9874a49301eSmrg maxHeight = MAX2(minHeight, att->Renderbuffer->Height); 9887117f1b4Smrg f = att->Renderbuffer->InternalFormat; 9893464ebd5Sriastradh attFormat = att->Renderbuffer->Format; 9907117f1b4Smrg numImages++; 991af69d88dSmrg 992af69d88dSmrg if (numSamples < 0) 993af69d88dSmrg numSamples = att->Renderbuffer->NumSamples; 994af69d88dSmrg else if (numSamples != att->Renderbuffer->NumSamples) { 995af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 996af69d88dSmrg fbo_incomplete(ctx, "inconsistent sample count", -1); 997af69d88dSmrg return; 998af69d88dSmrg } 999af69d88dSmrg 1000af69d88dSmrg /* RENDERBUFFER has fixedSampleLocations implicitly true */ 1001af69d88dSmrg if (fixedSampleLocations < 0) 1002af69d88dSmrg fixedSampleLocations = GL_TRUE; 1003af69d88dSmrg else if (fixedSampleLocations != GL_TRUE) { 1004af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 1005af69d88dSmrg fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); 1006af69d88dSmrg return; 1007af69d88dSmrg } 10087117f1b4Smrg } 10097117f1b4Smrg else { 10107117f1b4Smrg assert(att->Type == GL_NONE); 10117117f1b4Smrg continue; 10127117f1b4Smrg } 10137117f1b4Smrg 10143464ebd5Sriastradh /* check if integer color */ 10153464ebd5Sriastradh fb->_IntegerColor = _mesa_is_format_integer_color(attFormat); 10163464ebd5Sriastradh 1017af69d88dSmrg /* Update _AllColorBuffersFixedPoint and _HasSNormOrFloatColorBuffer. */ 1018af69d88dSmrg if (i >= 0) { 1019af69d88dSmrg GLenum type = _mesa_get_format_datatype(attFormat); 1020af69d88dSmrg 1021af69d88dSmrg fb->_AllColorBuffersFixedPoint = 1022af69d88dSmrg fb->_AllColorBuffersFixedPoint && 1023af69d88dSmrg (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED); 1024af69d88dSmrg 1025af69d88dSmrg fb->_HasSNormOrFloatColorBuffer = 1026af69d88dSmrg fb->_HasSNormOrFloatColorBuffer || 1027af69d88dSmrg type == GL_SIGNED_NORMALIZED || type == GL_FLOAT; 1028af69d88dSmrg } 1029af69d88dSmrg 1030af69d88dSmrg /* Error-check width, height, format */ 10317117f1b4Smrg if (numImages == 1) { 1032af69d88dSmrg /* save format */ 10334a49301eSmrg if (i >= 0) { 10347117f1b4Smrg intFormat = f; 10354a49301eSmrg } 10367117f1b4Smrg } 10377117f1b4Smrg else { 10384a49301eSmrg if (!ctx->Extensions.ARB_framebuffer_object) { 10394a49301eSmrg /* check that width, height, format are same */ 10404a49301eSmrg if (minWidth != maxWidth || minHeight != maxHeight) { 10414a49301eSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 1042af69d88dSmrg fbo_incomplete(ctx, "width or height mismatch", -1); 10434a49301eSmrg return; 10444a49301eSmrg } 1045af69d88dSmrg /* check that all color buffers are the same format */ 10464a49301eSmrg if (intFormat != GL_NONE && f != intFormat) { 10474a49301eSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 1048af69d88dSmrg fbo_incomplete(ctx, "format mismatch", -1); 10494a49301eSmrg return; 10504a49301eSmrg } 10517117f1b4Smrg } 1052af69d88dSmrg } 1053af69d88dSmrg 1054af69d88dSmrg /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported) 1055af69d88dSmrg */ 1056af69d88dSmrg if (att->Type == GL_RENDERBUFFER && 1057af69d88dSmrg att->Renderbuffer->Format == MESA_FORMAT_NONE) { 1058af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 1059af69d88dSmrg fbo_incomplete(ctx, "unsupported renderbuffer format", i); 1060af69d88dSmrg return; 1061af69d88dSmrg } 10624a49301eSmrg 1063af69d88dSmrg /* Check that layered rendering is consistent. */ 1064af69d88dSmrg if (att->Layered) { 1065af69d88dSmrg if (att_tex_target == GL_TEXTURE_CUBE_MAP) 1066af69d88dSmrg att_layer_count = 6; 1067af69d88dSmrg else if (att_tex_target == GL_TEXTURE_1D_ARRAY) 1068af69d88dSmrg att_layer_count = att->Renderbuffer->Height; 1069af69d88dSmrg else 1070af69d88dSmrg att_layer_count = att->Renderbuffer->Depth; 1071af69d88dSmrg } else { 1072af69d88dSmrg att_layer_count = 0; 1073af69d88dSmrg } 1074af69d88dSmrg if (!layer_info_valid) { 1075af69d88dSmrg is_layered = att->Layered; 1076af69d88dSmrg max_layer_count = att_layer_count; 1077af69d88dSmrg layer_tex_target = att_tex_target; 1078af69d88dSmrg layer_info_valid = true; 1079af69d88dSmrg } else if (max_layer_count > 0 && layer_tex_target != att_tex_target) { 1080af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; 1081af69d88dSmrg fbo_incomplete(ctx, "layered framebuffer has mismatched targets", i); 1082af69d88dSmrg return; 1083af69d88dSmrg } else if (is_layered != att->Layered) { 1084af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; 1085af69d88dSmrg fbo_incomplete(ctx, 1086af69d88dSmrg "framebuffer attachment layer mode is inconsistent", 1087af69d88dSmrg i); 1088af69d88dSmrg return; 1089af69d88dSmrg } else if (att_layer_count > max_layer_count) { 1090af69d88dSmrg max_layer_count = att_layer_count; 10917117f1b4Smrg } 10927117f1b4Smrg } 10937117f1b4Smrg 1094af69d88dSmrg fb->MaxNumLayers = max_layer_count; 1095af69d88dSmrg 1096af69d88dSmrg if (numImages == 0) { 1097af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 1098af69d88dSmrg fbo_incomplete(ctx, "no attachments", -1); 1099af69d88dSmrg return; 1100af69d88dSmrg } 1101af69d88dSmrg 1102af69d88dSmrg if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) { 11033464ebd5Sriastradh /* Check that all DrawBuffers are present */ 11043464ebd5Sriastradh for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { 11053464ebd5Sriastradh if (fb->ColorDrawBuffer[j] != GL_NONE) { 11063464ebd5Sriastradh const struct gl_renderbuffer_attachment *att 1107af69d88dSmrg = get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); 11083464ebd5Sriastradh assert(att); 11093464ebd5Sriastradh if (att->Type == GL_NONE) { 11103464ebd5Sriastradh fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; 1111af69d88dSmrg fbo_incomplete(ctx, "missing drawbuffer", j); 11123464ebd5Sriastradh return; 11133464ebd5Sriastradh } 11143464ebd5Sriastradh } 11157117f1b4Smrg } 11167117f1b4Smrg 11173464ebd5Sriastradh /* Check that the ReadBuffer is present */ 11183464ebd5Sriastradh if (fb->ColorReadBuffer != GL_NONE) { 11193464ebd5Sriastradh const struct gl_renderbuffer_attachment *att 1120af69d88dSmrg = get_attachment(ctx, fb, fb->ColorReadBuffer); 11213464ebd5Sriastradh assert(att); 11223464ebd5Sriastradh if (att->Type == GL_NONE) { 11233464ebd5Sriastradh fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; 1124af69d88dSmrg fbo_incomplete(ctx, "missing readbuffer", -1); 11253464ebd5Sriastradh return; 11263464ebd5Sriastradh } 11277117f1b4Smrg } 11287117f1b4Smrg } 11297117f1b4Smrg 11304a49301eSmrg /* Provisionally set status = COMPLETE ... */ 11317117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 11324a49301eSmrg 11334a49301eSmrg /* ... but the driver may say the FB is incomplete. 11344a49301eSmrg * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED 11354a49301eSmrg * if anything. 11364a49301eSmrg */ 11374a49301eSmrg if (ctx->Driver.ValidateFramebuffer) { 11384a49301eSmrg ctx->Driver.ValidateFramebuffer(ctx, fb); 11394a49301eSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 1140af69d88dSmrg fbo_incomplete(ctx, "driver marked FBO as incomplete", -1); 11414a49301eSmrg } 11424a49301eSmrg } 11434a49301eSmrg 11444a49301eSmrg if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) { 11454a49301eSmrg /* 11464a49301eSmrg * Note that if ARB_framebuffer_object is supported and the attached 11474a49301eSmrg * renderbuffers/textures are different sizes, the framebuffer 11484a49301eSmrg * width/height will be set to the smallest width/height. 11494a49301eSmrg */ 11504a49301eSmrg fb->Width = minWidth; 11514a49301eSmrg fb->Height = minHeight; 11524a49301eSmrg 11534a49301eSmrg /* finally, update the visual info for the framebuffer */ 11543464ebd5Sriastradh _mesa_update_framebuffer_visual(ctx, fb); 11554a49301eSmrg } 11567117f1b4Smrg} 11577117f1b4Smrg 11587117f1b4Smrg 11597117f1b4SmrgGLboolean GLAPIENTRY 1160af69d88dSmrg_mesa_IsRenderbuffer(GLuint renderbuffer) 11617117f1b4Smrg{ 11627117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 11637117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 11647117f1b4Smrg if (renderbuffer) { 1165af69d88dSmrg struct gl_renderbuffer *rb = 1166af69d88dSmrg _mesa_lookup_renderbuffer(ctx, renderbuffer); 11677117f1b4Smrg if (rb != NULL && rb != &DummyRenderbuffer) 11687117f1b4Smrg return GL_TRUE; 11697117f1b4Smrg } 11707117f1b4Smrg return GL_FALSE; 11717117f1b4Smrg} 11727117f1b4Smrg 11737117f1b4Smrg 1174af69d88dSmrgstatic void 1175af69d88dSmrgbind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names) 11767117f1b4Smrg{ 11777117f1b4Smrg struct gl_renderbuffer *newRb; 11787117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 11797117f1b4Smrg 11807117f1b4Smrg if (target != GL_RENDERBUFFER_EXT) { 11814a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); 11827117f1b4Smrg return; 11837117f1b4Smrg } 11847117f1b4Smrg 11854a49301eSmrg /* No need to flush here since the render buffer binding has no 11864a49301eSmrg * effect on rendering state. 11877117f1b4Smrg */ 11887117f1b4Smrg 11897117f1b4Smrg if (renderbuffer) { 11907117f1b4Smrg newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 11917117f1b4Smrg if (newRb == &DummyRenderbuffer) { 11927117f1b4Smrg /* ID was reserved, but no real renderbuffer object made yet */ 11937117f1b4Smrg newRb = NULL; 11947117f1b4Smrg } 1195af69d88dSmrg else if (!newRb && !allow_user_names) { 11964a49301eSmrg /* All RB IDs must be Gen'd */ 11974a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); 11984a49301eSmrg return; 11994a49301eSmrg } 12004a49301eSmrg 12017117f1b4Smrg if (!newRb) { 12027117f1b4Smrg /* create new renderbuffer object */ 12037117f1b4Smrg newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); 12047117f1b4Smrg if (!newRb) { 12057117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); 12067117f1b4Smrg return; 12077117f1b4Smrg } 12087117f1b4Smrg ASSERT(newRb->AllocStorage); 12097117f1b4Smrg _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); 12107117f1b4Smrg newRb->RefCount = 1; /* referenced by hash table */ 12117117f1b4Smrg } 12127117f1b4Smrg } 12137117f1b4Smrg else { 12147117f1b4Smrg newRb = NULL; 12157117f1b4Smrg } 12167117f1b4Smrg 12177117f1b4Smrg ASSERT(newRb != &DummyRenderbuffer); 12187117f1b4Smrg 12197117f1b4Smrg _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); 12207117f1b4Smrg} 12217117f1b4Smrg 1222af69d88dSmrgvoid GLAPIENTRY 1223af69d88dSmrg_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer) 1224af69d88dSmrg{ 1225af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 1226af69d88dSmrg 1227af69d88dSmrg /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same 1228af69d88dSmrg * entry point, but they allow the use of user-generated names. 1229af69d88dSmrg */ 1230af69d88dSmrg bind_renderbuffer(target, renderbuffer, _mesa_is_gles(ctx)); 1231af69d88dSmrg} 1232af69d88dSmrg 1233af69d88dSmrgvoid GLAPIENTRY 1234af69d88dSmrg_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 1235af69d88dSmrg{ 1236af69d88dSmrg /* This function should not be in the dispatch table for core profile / 1237af69d88dSmrg * OpenGL 3.1, so execution should never get here in those cases -- no 1238af69d88dSmrg * need for an explicit test. 1239af69d88dSmrg */ 1240af69d88dSmrg bind_renderbuffer(target, renderbuffer, true); 1241af69d88dSmrg} 1242af69d88dSmrg 12437117f1b4Smrg 12444a49301eSmrg/** 1245af69d88dSmrg * Remove the specified renderbuffer or texture from any attachment point in 1246af69d88dSmrg * the framebuffer. 1247af69d88dSmrg * 1248af69d88dSmrg * \returns 1249af69d88dSmrg * \c true if the renderbuffer was detached from an attachment point. \c 1250af69d88dSmrg * false otherwise. 12514a49301eSmrg */ 1252af69d88dSmrgbool 1253af69d88dSmrg_mesa_detach_renderbuffer(struct gl_context *ctx, 1254af69d88dSmrg struct gl_framebuffer *fb, 1255af69d88dSmrg const void *att) 12564a49301eSmrg{ 1257af69d88dSmrg unsigned i; 1258af69d88dSmrg bool progress = false; 1259af69d88dSmrg 12604a49301eSmrg for (i = 0; i < BUFFER_COUNT; i++) { 1261af69d88dSmrg if (fb->Attachment[i].Texture == att 1262af69d88dSmrg || fb->Attachment[i].Renderbuffer == att) { 1263af69d88dSmrg remove_attachment(ctx, &fb->Attachment[i]); 1264af69d88dSmrg progress = true; 12654a49301eSmrg } 12664a49301eSmrg } 1267af69d88dSmrg 1268af69d88dSmrg /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer 1269af69d88dSmrg * Completeness," of the OpenGL 3.1 spec says: 1270af69d88dSmrg * 1271af69d88dSmrg * "Performing any of the following actions may change whether the 1272af69d88dSmrg * framebuffer is considered complete or incomplete: 1273af69d88dSmrg * 1274af69d88dSmrg * ... 1275af69d88dSmrg * 1276af69d88dSmrg * - Deleting, with DeleteTextures or DeleteRenderbuffers, an object 1277af69d88dSmrg * containing an image that is attached to a framebuffer object 1278af69d88dSmrg * that is bound to the framebuffer." 1279af69d88dSmrg */ 1280af69d88dSmrg if (progress) 1281af69d88dSmrg invalidate_framebuffer(fb); 1282af69d88dSmrg 1283af69d88dSmrg return progress; 12844a49301eSmrg} 12854a49301eSmrg 12864a49301eSmrg 12877117f1b4Smrgvoid GLAPIENTRY 1288af69d88dSmrg_mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) 12897117f1b4Smrg{ 12907117f1b4Smrg GLint i; 12917117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 12927117f1b4Smrg 12937117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 12947117f1b4Smrg 12957117f1b4Smrg for (i = 0; i < n; i++) { 12967117f1b4Smrg if (renderbuffers[i] > 0) { 12977117f1b4Smrg struct gl_renderbuffer *rb; 12987117f1b4Smrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); 12997117f1b4Smrg if (rb) { 13007117f1b4Smrg /* check if deleting currently bound renderbuffer object */ 13017117f1b4Smrg if (rb == ctx->CurrentRenderbuffer) { 13027117f1b4Smrg /* bind default */ 13037117f1b4Smrg ASSERT(rb->RefCount >= 2); 1304af69d88dSmrg _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0); 13057117f1b4Smrg } 13067117f1b4Smrg 1307af69d88dSmrg /* Section 4.4.2 (Attaching Images to Framebuffer Objects), 1308af69d88dSmrg * subsection "Attaching Renderbuffer Images to a Framebuffer," 1309af69d88dSmrg * of the OpenGL 3.1 spec says: 1310af69d88dSmrg * 1311af69d88dSmrg * "If a renderbuffer object is deleted while its image is 1312af69d88dSmrg * attached to one or more attachment points in the currently 1313af69d88dSmrg * bound framebuffer, then it is as if FramebufferRenderbuffer 1314af69d88dSmrg * had been called, with a renderbuffer of 0, for each 1315af69d88dSmrg * attachment point to which this image was attached in the 1316af69d88dSmrg * currently bound framebuffer. In other words, this 1317af69d88dSmrg * renderbuffer image is first detached from all attachment 1318af69d88dSmrg * points in the currently bound framebuffer. Note that the 1319af69d88dSmrg * renderbuffer image is specifically not detached from any 1320af69d88dSmrg * non-bound framebuffers. Detaching the image from any 1321af69d88dSmrg * non-bound framebuffers is the responsibility of the 1322af69d88dSmrg * application. 1323af69d88dSmrg */ 1324af69d88dSmrg if (_mesa_is_user_fbo(ctx->DrawBuffer)) { 1325af69d88dSmrg _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb); 13264a49301eSmrg } 1327af69d88dSmrg if (_mesa_is_user_fbo(ctx->ReadBuffer) 13283464ebd5Sriastradh && ctx->ReadBuffer != ctx->DrawBuffer) { 1329af69d88dSmrg _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb); 13304a49301eSmrg } 13314a49301eSmrg 13327117f1b4Smrg /* Remove from hash table immediately, to free the ID. 13337117f1b4Smrg * But the object will not be freed until it's no longer 13347117f1b4Smrg * referenced anywhere else. 13357117f1b4Smrg */ 13367117f1b4Smrg _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); 13377117f1b4Smrg 13387117f1b4Smrg if (rb != &DummyRenderbuffer) { 13397117f1b4Smrg /* no longer referenced by hash table */ 13407117f1b4Smrg _mesa_reference_renderbuffer(&rb, NULL); 13417117f1b4Smrg } 13427117f1b4Smrg } 13437117f1b4Smrg } 13447117f1b4Smrg } 13457117f1b4Smrg} 13467117f1b4Smrg 13477117f1b4Smrg 13487117f1b4Smrgvoid GLAPIENTRY 1349af69d88dSmrg_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers) 13507117f1b4Smrg{ 13517117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 13527117f1b4Smrg GLuint first; 13537117f1b4Smrg GLint i; 13547117f1b4Smrg 13557117f1b4Smrg if (n < 0) { 13567117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); 13577117f1b4Smrg return; 13587117f1b4Smrg } 13597117f1b4Smrg 13607117f1b4Smrg if (!renderbuffers) 13617117f1b4Smrg return; 13627117f1b4Smrg 13637117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); 13647117f1b4Smrg 13657117f1b4Smrg for (i = 0; i < n; i++) { 13667117f1b4Smrg GLuint name = first + i; 13677117f1b4Smrg renderbuffers[i] = name; 13687117f1b4Smrg /* insert dummy placeholder into hash table */ 1369af69d88dSmrg mtx_lock(&ctx->Shared->Mutex); 13707117f1b4Smrg _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); 1371af69d88dSmrg mtx_unlock(&ctx->Shared->Mutex); 13727117f1b4Smrg } 13737117f1b4Smrg} 13747117f1b4Smrg 13757117f1b4Smrg 13767117f1b4Smrg/** 13777117f1b4Smrg * Given an internal format token for a render buffer, return the 13783464ebd5Sriastradh * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, 13793464ebd5Sriastradh * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE, 13803464ebd5Sriastradh * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc). 13817117f1b4Smrg * 13823464ebd5Sriastradh * This is similar to _mesa_base_tex_format() but the set of valid 13833464ebd5Sriastradh * internal formats is different. 1384cdc920a0Smrg * 13853464ebd5Sriastradh * Note that even if a format is determined to be legal here, validation 13863464ebd5Sriastradh * of the FBO may fail if the format is not supported by the driver/GPU. 13873464ebd5Sriastradh * 13883464ebd5Sriastradh * \param internalFormat as passed to glRenderbufferStorage() 13893464ebd5Sriastradh * \return the base internal format, or 0 if internalFormat is illegal 13907117f1b4Smrg */ 13917117f1b4SmrgGLenum 13923464ebd5Sriastradh_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) 13937117f1b4Smrg{ 13943464ebd5Sriastradh /* 13953464ebd5Sriastradh * Notes: some formats such as alpha, luminance, etc. were added 13963464ebd5Sriastradh * with GL_ARB_framebuffer_object. 13973464ebd5Sriastradh */ 13987117f1b4Smrg switch (internalFormat) { 13993464ebd5Sriastradh case GL_ALPHA: 14003464ebd5Sriastradh case GL_ALPHA4: 14013464ebd5Sriastradh case GL_ALPHA8: 14023464ebd5Sriastradh case GL_ALPHA12: 14033464ebd5Sriastradh case GL_ALPHA16: 1404af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 1405af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_ALPHA : 0; 14063464ebd5Sriastradh case GL_LUMINANCE: 14073464ebd5Sriastradh case GL_LUMINANCE4: 14083464ebd5Sriastradh case GL_LUMINANCE8: 14093464ebd5Sriastradh case GL_LUMINANCE12: 14103464ebd5Sriastradh case GL_LUMINANCE16: 1411af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 1412af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE : 0; 14133464ebd5Sriastradh case GL_LUMINANCE_ALPHA: 14143464ebd5Sriastradh case GL_LUMINANCE4_ALPHA4: 14153464ebd5Sriastradh case GL_LUMINANCE6_ALPHA2: 14163464ebd5Sriastradh case GL_LUMINANCE8_ALPHA8: 14173464ebd5Sriastradh case GL_LUMINANCE12_ALPHA4: 14183464ebd5Sriastradh case GL_LUMINANCE12_ALPHA12: 14193464ebd5Sriastradh case GL_LUMINANCE16_ALPHA16: 1420af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 1421af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE_ALPHA : 0; 14223464ebd5Sriastradh case GL_INTENSITY: 14233464ebd5Sriastradh case GL_INTENSITY4: 14243464ebd5Sriastradh case GL_INTENSITY8: 14253464ebd5Sriastradh case GL_INTENSITY12: 14263464ebd5Sriastradh case GL_INTENSITY16: 1427af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 1428af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_INTENSITY : 0; 1429af69d88dSmrg case GL_RGB8: 1430af69d88dSmrg return GL_RGB; 14317117f1b4Smrg case GL_RGB: 14327117f1b4Smrg case GL_R3_G3_B2: 14337117f1b4Smrg case GL_RGB4: 14347117f1b4Smrg case GL_RGB5: 14357117f1b4Smrg case GL_RGB10: 14367117f1b4Smrg case GL_RGB12: 14377117f1b4Smrg case GL_RGB16: 1438af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; 14393464ebd5Sriastradh case GL_SRGB8_EXT: 1440af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; 14417117f1b4Smrg case GL_RGBA4: 14427117f1b4Smrg case GL_RGB5_A1: 14437117f1b4Smrg case GL_RGBA8: 1444af69d88dSmrg return GL_RGBA; 1445af69d88dSmrg case GL_RGBA: 1446af69d88dSmrg case GL_RGBA2: 14477117f1b4Smrg case GL_RGBA12: 14487117f1b4Smrg case GL_RGBA16: 1449af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0; 1450af69d88dSmrg case GL_RGB10_A2: 14513464ebd5Sriastradh case GL_SRGB8_ALPHA8_EXT: 1452af69d88dSmrg return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0; 14537117f1b4Smrg case GL_STENCIL_INDEX: 14547117f1b4Smrg case GL_STENCIL_INDEX1_EXT: 14557117f1b4Smrg case GL_STENCIL_INDEX4_EXT: 14567117f1b4Smrg case GL_STENCIL_INDEX16_EXT: 1457af69d88dSmrg /* There are extensions for GL_STENCIL_INDEX1 and GL_STENCIL_INDEX4 in 1458af69d88dSmrg * OpenGL ES, but Mesa does not currently support them. 1459af69d88dSmrg */ 1460af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_STENCIL_INDEX : 0; 1461af69d88dSmrg case GL_STENCIL_INDEX8_EXT: 14627117f1b4Smrg return GL_STENCIL_INDEX; 14637117f1b4Smrg case GL_DEPTH_COMPONENT: 1464af69d88dSmrg case GL_DEPTH_COMPONENT32: 1465af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_COMPONENT : 0; 14667117f1b4Smrg case GL_DEPTH_COMPONENT16: 14677117f1b4Smrg case GL_DEPTH_COMPONENT24: 14687117f1b4Smrg return GL_DEPTH_COMPONENT; 1469af69d88dSmrg case GL_DEPTH_STENCIL: 1470af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_STENCIL : 0; 1471af69d88dSmrg case GL_DEPTH24_STENCIL8: 1472af69d88dSmrg return GL_DEPTH_STENCIL; 1473af69d88dSmrg case GL_DEPTH_COMPONENT32F: 1474af69d88dSmrg return ctx->Version >= 30 1475af69d88dSmrg || (ctx->API == API_OPENGL_COMPAT && 1476af69d88dSmrg ctx->Extensions.ARB_depth_buffer_float) 1477af69d88dSmrg ? GL_DEPTH_COMPONENT : 0; 1478af69d88dSmrg case GL_DEPTH32F_STENCIL8: 1479af69d88dSmrg return ctx->Version >= 30 1480af69d88dSmrg || (ctx->API == API_OPENGL_COMPAT && 1481af69d88dSmrg ctx->Extensions.ARB_depth_buffer_float) 1482af69d88dSmrg ? GL_DEPTH_STENCIL : 0; 14833464ebd5Sriastradh case GL_RED: 14843464ebd5Sriastradh case GL_R16: 1485af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg 1486af69d88dSmrg ? GL_RED : 0; 1487af69d88dSmrg case GL_R8: 1488af69d88dSmrg return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg 1489af69d88dSmrg ? GL_RED : 0; 14903464ebd5Sriastradh case GL_RG: 14913464ebd5Sriastradh case GL_RG16: 1492af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg 1493af69d88dSmrg ? GL_RG : 0; 1494af69d88dSmrg case GL_RG8: 1495af69d88dSmrg return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg 1496af69d88dSmrg ? GL_RG : 0; 14973464ebd5Sriastradh /* signed normalized texture formats */ 14983464ebd5Sriastradh case GL_RED_SNORM: 14993464ebd5Sriastradh case GL_R8_SNORM: 15003464ebd5Sriastradh case GL_R16_SNORM: 1501af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 1502af69d88dSmrg ? GL_RED : 0; 15033464ebd5Sriastradh case GL_RG_SNORM: 15043464ebd5Sriastradh case GL_RG8_SNORM: 15053464ebd5Sriastradh case GL_RG16_SNORM: 1506af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 1507af69d88dSmrg ? GL_RG : 0; 15083464ebd5Sriastradh case GL_RGB_SNORM: 15093464ebd5Sriastradh case GL_RGB8_SNORM: 15103464ebd5Sriastradh case GL_RGB16_SNORM: 1511af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 1512af69d88dSmrg ? GL_RGB : 0; 15133464ebd5Sriastradh case GL_RGBA_SNORM: 15143464ebd5Sriastradh case GL_RGBA8_SNORM: 15153464ebd5Sriastradh case GL_RGBA16_SNORM: 1516af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 1517af69d88dSmrg ? GL_RGBA : 0; 15183464ebd5Sriastradh case GL_ALPHA_SNORM: 15193464ebd5Sriastradh case GL_ALPHA8_SNORM: 15203464ebd5Sriastradh case GL_ALPHA16_SNORM: 1521af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 1522af69d88dSmrg ctx->Extensions.EXT_texture_snorm && 15233464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; 15243464ebd5Sriastradh case GL_LUMINANCE_SNORM: 15253464ebd5Sriastradh case GL_LUMINANCE8_SNORM: 15263464ebd5Sriastradh case GL_LUMINANCE16_SNORM: 1527af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 1528af69d88dSmrg ? GL_LUMINANCE : 0; 15293464ebd5Sriastradh case GL_LUMINANCE_ALPHA_SNORM: 15303464ebd5Sriastradh case GL_LUMINANCE8_ALPHA8_SNORM: 15313464ebd5Sriastradh case GL_LUMINANCE16_ALPHA16_SNORM: 1532af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 1533af69d88dSmrg ? GL_LUMINANCE_ALPHA : 0; 15343464ebd5Sriastradh case GL_INTENSITY_SNORM: 15353464ebd5Sriastradh case GL_INTENSITY8_SNORM: 15363464ebd5Sriastradh case GL_INTENSITY16_SNORM: 1537af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 1538af69d88dSmrg ? GL_INTENSITY : 0; 1539af69d88dSmrg 15403464ebd5Sriastradh case GL_R16F: 15413464ebd5Sriastradh case GL_R32F: 1542af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && 1543af69d88dSmrg ctx->Extensions.ARB_texture_rg && 1544af69d88dSmrg ctx->Extensions.ARB_texture_float) || 1545af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 1546af69d88dSmrg ? GL_RED : 0; 15473464ebd5Sriastradh case GL_RG16F: 15483464ebd5Sriastradh case GL_RG32F: 1549af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && 1550af69d88dSmrg ctx->Extensions.ARB_texture_rg && 1551af69d88dSmrg ctx->Extensions.ARB_texture_float) || 1552af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 1553af69d88dSmrg ? GL_RG : 0; 15543464ebd5Sriastradh case GL_RGB16F: 15553464ebd5Sriastradh case GL_RGB32F: 1556af69d88dSmrg return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float) 1557af69d88dSmrg ? GL_RGB : 0; 15583464ebd5Sriastradh case GL_RGBA16F: 15593464ebd5Sriastradh case GL_RGBA32F: 1560af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && 1561af69d88dSmrg ctx->Extensions.ARB_texture_float) || 1562af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 1563af69d88dSmrg ? GL_RGBA : 0; 15643464ebd5Sriastradh case GL_ALPHA16F_ARB: 15653464ebd5Sriastradh case GL_ALPHA32F_ARB: 1566af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 1567af69d88dSmrg ctx->Extensions.ARB_texture_float && 15683464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; 15693464ebd5Sriastradh case GL_LUMINANCE16F_ARB: 15703464ebd5Sriastradh case GL_LUMINANCE32F_ARB: 1571af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 1572af69d88dSmrg ctx->Extensions.ARB_texture_float && 15733464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; 15743464ebd5Sriastradh case GL_LUMINANCE_ALPHA16F_ARB: 15753464ebd5Sriastradh case GL_LUMINANCE_ALPHA32F_ARB: 1576af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 1577af69d88dSmrg ctx->Extensions.ARB_texture_float && 15783464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; 15793464ebd5Sriastradh case GL_INTENSITY16F_ARB: 15803464ebd5Sriastradh case GL_INTENSITY32F_ARB: 1581af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 1582af69d88dSmrg ctx->Extensions.ARB_texture_float && 15833464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; 15843464ebd5Sriastradh case GL_R11F_G11F_B10F: 1585af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) || 1586af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 1587af69d88dSmrg ? GL_RGB : 0; 1588af69d88dSmrg 1589af69d88dSmrg case GL_RGBA8UI_EXT: 1590af69d88dSmrg case GL_RGBA16UI_EXT: 1591af69d88dSmrg case GL_RGBA32UI_EXT: 1592af69d88dSmrg case GL_RGBA8I_EXT: 1593af69d88dSmrg case GL_RGBA16I_EXT: 1594af69d88dSmrg case GL_RGBA32I_EXT: 1595af69d88dSmrg return ctx->Version >= 30 1596af69d88dSmrg || (_mesa_is_desktop_gl(ctx) && 1597af69d88dSmrg ctx->Extensions.EXT_texture_integer) ? GL_RGBA : 0; 1598af69d88dSmrg 1599af69d88dSmrg case GL_RGB8UI_EXT: 1600af69d88dSmrg case GL_RGB16UI_EXT: 1601af69d88dSmrg case GL_RGB32UI_EXT: 1602af69d88dSmrg case GL_RGB8I_EXT: 1603af69d88dSmrg case GL_RGB16I_EXT: 1604af69d88dSmrg case GL_RGB32I_EXT: 1605af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_integer 1606af69d88dSmrg ? GL_RGB : 0; 1607af69d88dSmrg case GL_R8UI: 1608af69d88dSmrg case GL_R8I: 1609af69d88dSmrg case GL_R16UI: 1610af69d88dSmrg case GL_R16I: 1611af69d88dSmrg case GL_R32UI: 1612af69d88dSmrg case GL_R32I: 1613af69d88dSmrg return ctx->Version >= 30 1614af69d88dSmrg || (_mesa_is_desktop_gl(ctx) && 1615af69d88dSmrg ctx->Extensions.ARB_texture_rg && 1616af69d88dSmrg ctx->Extensions.EXT_texture_integer) ? GL_RED : 0; 1617af69d88dSmrg 1618af69d88dSmrg case GL_RG8UI: 1619af69d88dSmrg case GL_RG8I: 1620af69d88dSmrg case GL_RG16UI: 1621af69d88dSmrg case GL_RG16I: 1622af69d88dSmrg case GL_RG32UI: 1623af69d88dSmrg case GL_RG32I: 1624af69d88dSmrg return ctx->Version >= 30 1625af69d88dSmrg || (_mesa_is_desktop_gl(ctx) && 1626af69d88dSmrg ctx->Extensions.ARB_texture_rg && 1627af69d88dSmrg ctx->Extensions.EXT_texture_integer) ? GL_RG : 0; 1628af69d88dSmrg 1629af69d88dSmrg case GL_INTENSITY8I_EXT: 1630af69d88dSmrg case GL_INTENSITY8UI_EXT: 1631af69d88dSmrg case GL_INTENSITY16I_EXT: 1632af69d88dSmrg case GL_INTENSITY16UI_EXT: 1633af69d88dSmrg case GL_INTENSITY32I_EXT: 1634af69d88dSmrg case GL_INTENSITY32UI_EXT: 1635af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 1636af69d88dSmrg ctx->Extensions.EXT_texture_integer && 1637af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; 1638af69d88dSmrg 1639af69d88dSmrg case GL_LUMINANCE8I_EXT: 1640af69d88dSmrg case GL_LUMINANCE8UI_EXT: 1641af69d88dSmrg case GL_LUMINANCE16I_EXT: 1642af69d88dSmrg case GL_LUMINANCE16UI_EXT: 1643af69d88dSmrg case GL_LUMINANCE32I_EXT: 1644af69d88dSmrg case GL_LUMINANCE32UI_EXT: 1645af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 1646af69d88dSmrg ctx->Extensions.EXT_texture_integer && 1647af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; 1648af69d88dSmrg 1649af69d88dSmrg case GL_LUMINANCE_ALPHA8I_EXT: 1650af69d88dSmrg case GL_LUMINANCE_ALPHA8UI_EXT: 1651af69d88dSmrg case GL_LUMINANCE_ALPHA16I_EXT: 1652af69d88dSmrg case GL_LUMINANCE_ALPHA16UI_EXT: 1653af69d88dSmrg case GL_LUMINANCE_ALPHA32I_EXT: 1654af69d88dSmrg case GL_LUMINANCE_ALPHA32UI_EXT: 1655af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 1656af69d88dSmrg ctx->Extensions.EXT_texture_integer && 1657af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; 1658af69d88dSmrg 1659af69d88dSmrg case GL_ALPHA8I_EXT: 1660af69d88dSmrg case GL_ALPHA8UI_EXT: 1661af69d88dSmrg case GL_ALPHA16I_EXT: 1662af69d88dSmrg case GL_ALPHA16UI_EXT: 1663af69d88dSmrg case GL_ALPHA32I_EXT: 1664af69d88dSmrg case GL_ALPHA32UI_EXT: 1665af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 1666af69d88dSmrg ctx->Extensions.EXT_texture_integer && 1667af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; 1668af69d88dSmrg 1669af69d88dSmrg case GL_RGB10_A2UI: 1670af69d88dSmrg return (_mesa_is_desktop_gl(ctx) && 1671af69d88dSmrg ctx->Extensions.ARB_texture_rgb10_a2ui) 1672af69d88dSmrg || _mesa_is_gles3(ctx) ? GL_RGBA : 0; 1673af69d88dSmrg 1674af69d88dSmrg case GL_RGB565: 1675af69d88dSmrg return _mesa_is_gles(ctx) || ctx->Extensions.ARB_ES2_compatibility 1676af69d88dSmrg ? GL_RGB : 0; 1677af69d88dSmrg default: 1678af69d88dSmrg return 0; 1679af69d88dSmrg } 16807117f1b4Smrg} 16817117f1b4Smrg 16827117f1b4Smrg 16833464ebd5Sriastradh/** 16843464ebd5Sriastradh * Invalidate a renderbuffer attachment. Called from _mesa_HashWalk(). 16853464ebd5Sriastradh */ 16863464ebd5Sriastradhstatic void 16873464ebd5Sriastradhinvalidate_rb(GLuint key, void *data, void *userData) 16883464ebd5Sriastradh{ 16893464ebd5Sriastradh struct gl_framebuffer *fb = (struct gl_framebuffer *) data; 16903464ebd5Sriastradh struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData; 16913464ebd5Sriastradh 16923464ebd5Sriastradh /* If this is a user-created FBO */ 1693af69d88dSmrg if (_mesa_is_user_fbo(fb)) { 16943464ebd5Sriastradh GLuint i; 16953464ebd5Sriastradh for (i = 0; i < BUFFER_COUNT; i++) { 16963464ebd5Sriastradh struct gl_renderbuffer_attachment *att = fb->Attachment + i; 16973464ebd5Sriastradh if (att->Type == GL_RENDERBUFFER && 16983464ebd5Sriastradh att->Renderbuffer == rb) { 16993464ebd5Sriastradh /* Mark fb status as indeterminate to force re-validation */ 17003464ebd5Sriastradh fb->_Status = 0; 17013464ebd5Sriastradh return; 17023464ebd5Sriastradh } 17033464ebd5Sriastradh } 17043464ebd5Sriastradh } 17053464ebd5Sriastradh} 17063464ebd5Sriastradh 17073464ebd5Sriastradh 17084a49301eSmrg/** sentinal value, see below */ 17094a49301eSmrg#define NO_SAMPLES 1000 17104a49301eSmrg 17114a49301eSmrg 17124a49301eSmrg/** 1713af69d88dSmrg * Helper function used by _mesa_RenderbufferStorage() and 17144a49301eSmrg * _mesa_RenderbufferStorageMultisample(). 1715af69d88dSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorage(). 17164a49301eSmrg */ 17174a49301eSmrgstatic void 17184a49301eSmrgrenderbuffer_storage(GLenum target, GLenum internalFormat, 17194a49301eSmrg GLsizei width, GLsizei height, GLsizei samples) 17207117f1b4Smrg{ 17214a49301eSmrg const char *func = samples == NO_SAMPLES ? 1722af69d88dSmrg "glRenderbufferStorage" : "glRenderbufferStorageMultisample"; 17237117f1b4Smrg struct gl_renderbuffer *rb; 17247117f1b4Smrg GLenum baseFormat; 1725af69d88dSmrg GLenum sample_count_error; 17267117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 17277117f1b4Smrg 1728af69d88dSmrg if (MESA_VERBOSE & VERBOSE_API) { 1729af69d88dSmrg if (samples == NO_SAMPLES) 1730af69d88dSmrg _mesa_debug(ctx, "%s(%s, %s, %d, %d)\n", 1731af69d88dSmrg func, 1732af69d88dSmrg _mesa_lookup_enum_by_nr(target), 1733af69d88dSmrg _mesa_lookup_enum_by_nr(internalFormat), 1734af69d88dSmrg width, height); 1735af69d88dSmrg else 1736af69d88dSmrg _mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n", 1737af69d88dSmrg func, 1738af69d88dSmrg _mesa_lookup_enum_by_nr(target), 1739af69d88dSmrg _mesa_lookup_enum_by_nr(internalFormat), 1740af69d88dSmrg width, height, samples); 1741af69d88dSmrg } 17427117f1b4Smrg 17437117f1b4Smrg if (target != GL_RENDERBUFFER_EXT) { 17444a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 17457117f1b4Smrg return; 17467117f1b4Smrg } 17477117f1b4Smrg 17487117f1b4Smrg baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 17497117f1b4Smrg if (baseFormat == 0) { 1750af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)", 1751af69d88dSmrg func, _mesa_lookup_enum_by_nr(internalFormat)); 17527117f1b4Smrg return; 17537117f1b4Smrg } 17547117f1b4Smrg 1755af69d88dSmrg if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { 17564a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); 17577117f1b4Smrg return; 17587117f1b4Smrg } 17597117f1b4Smrg 1760af69d88dSmrg if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { 17614a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); 17627117f1b4Smrg return; 17637117f1b4Smrg } 17647117f1b4Smrg 17654a49301eSmrg if (samples == NO_SAMPLES) { 17664a49301eSmrg /* NumSamples == 0 indicates non-multisampling */ 17674a49301eSmrg samples = 0; 17684a49301eSmrg } 1769af69d88dSmrg else { 1770af69d88dSmrg /* check the sample count; 1771af69d88dSmrg * note: driver may choose to use more samples than what's requested 1772af69d88dSmrg */ 1773af69d88dSmrg sample_count_error = _mesa_check_sample_count(ctx, target, 1774af69d88dSmrg internalFormat, samples); 1775af69d88dSmrg if (sample_count_error != GL_NO_ERROR) { 1776af69d88dSmrg _mesa_error(ctx, sample_count_error, "%s(samples)", func); 1777af69d88dSmrg return; 1778af69d88dSmrg } 17794a49301eSmrg } 17807117f1b4Smrg 17814a49301eSmrg rb = ctx->CurrentRenderbuffer; 17827117f1b4Smrg if (!rb) { 17833464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); 17847117f1b4Smrg return; 17857117f1b4Smrg } 17867117f1b4Smrg 17877117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 17887117f1b4Smrg 17897117f1b4Smrg if (rb->InternalFormat == internalFormat && 17907117f1b4Smrg rb->Width == (GLuint) width && 1791af69d88dSmrg rb->Height == (GLuint) height && 1792af69d88dSmrg rb->NumSamples == samples) { 17937117f1b4Smrg /* no change in allocation needed */ 17947117f1b4Smrg return; 17957117f1b4Smrg } 17967117f1b4Smrg 17977117f1b4Smrg /* These MUST get set by the AllocStorage func */ 17984a49301eSmrg rb->Format = MESA_FORMAT_NONE; 17994a49301eSmrg rb->NumSamples = samples; 18007117f1b4Smrg 18017117f1b4Smrg /* Now allocate the storage */ 18027117f1b4Smrg ASSERT(rb->AllocStorage); 18037117f1b4Smrg if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 18047117f1b4Smrg /* No error - check/set fields now */ 1805af69d88dSmrg /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */ 18067117f1b4Smrg assert(rb->Width == (GLuint) width); 18077117f1b4Smrg assert(rb->Height == (GLuint) height); 18087117f1b4Smrg rb->InternalFormat = internalFormat; 1809cdc920a0Smrg rb->_BaseFormat = baseFormat; 18104a49301eSmrg assert(rb->_BaseFormat != 0); 18117117f1b4Smrg } 18127117f1b4Smrg else { 18137117f1b4Smrg /* Probably ran out of memory - clear the fields */ 18147117f1b4Smrg rb->Width = 0; 18157117f1b4Smrg rb->Height = 0; 18164a49301eSmrg rb->Format = MESA_FORMAT_NONE; 18177117f1b4Smrg rb->InternalFormat = GL_NONE; 18187117f1b4Smrg rb->_BaseFormat = GL_NONE; 18194a49301eSmrg rb->NumSamples = 0; 18207117f1b4Smrg } 18217117f1b4Smrg 18223464ebd5Sriastradh /* Invalidate the framebuffers the renderbuffer is attached in. */ 18233464ebd5Sriastradh if (rb->AttachedAnytime) { 18243464ebd5Sriastradh _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb); 18253464ebd5Sriastradh } 18267117f1b4Smrg} 18277117f1b4Smrg 18283464ebd5Sriastradh 1829cdc920a0Smrgvoid GLAPIENTRY 18303464ebd5Sriastradh_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) 1831cdc920a0Smrg{ 1832cdc920a0Smrg struct gl_renderbuffer *rb; 1833cdc920a0Smrg GET_CURRENT_CONTEXT(ctx); 1834cdc920a0Smrg 18353464ebd5Sriastradh if (!ctx->Extensions.OES_EGL_image) { 18363464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 18373464ebd5Sriastradh "glEGLImageTargetRenderbufferStorageOES(unsupported)"); 18383464ebd5Sriastradh return; 18393464ebd5Sriastradh } 18403464ebd5Sriastradh 1841cdc920a0Smrg if (target != GL_RENDERBUFFER) { 18423464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_ENUM, 18433464ebd5Sriastradh "EGLImageTargetRenderbufferStorageOES"); 1844cdc920a0Smrg return; 1845cdc920a0Smrg } 1846cdc920a0Smrg 1847cdc920a0Smrg rb = ctx->CurrentRenderbuffer; 1848cdc920a0Smrg if (!rb) { 18493464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 18503464ebd5Sriastradh "EGLImageTargetRenderbufferStorageOES"); 1851cdc920a0Smrg return; 1852cdc920a0Smrg } 1853cdc920a0Smrg 1854cdc920a0Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1855cdc920a0Smrg 1856cdc920a0Smrg ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); 1857cdc920a0Smrg} 18587117f1b4Smrg 18593464ebd5Sriastradh 18604a49301eSmrg/** 1861af69d88dSmrg * Helper function for _mesa_GetRenderbufferParameteriv() and 1862af69d88dSmrg * _mesa_GetFramebufferAttachmentParameteriv() 18634a49301eSmrg * We have to be careful to respect the base format. For example, if a 18644a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the 18654a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE 18664a49301eSmrg * we need to return zero. 18674a49301eSmrg */ 18684a49301eSmrgstatic GLint 1869af69d88dSmrgget_component_bits(GLenum pname, GLenum baseFormat, mesa_format format) 18704a49301eSmrg{ 1871af69d88dSmrg if (_mesa_base_format_has_channel(baseFormat, pname)) 1872af69d88dSmrg return _mesa_get_format_bits(format, pname); 1873af69d88dSmrg else 18744a49301eSmrg return 0; 18754a49301eSmrg} 18764a49301eSmrg 18774a49301eSmrg 18784a49301eSmrg 18794a49301eSmrgvoid GLAPIENTRY 1880af69d88dSmrg_mesa_RenderbufferStorage(GLenum target, GLenum internalFormat, 18814a49301eSmrg GLsizei width, GLsizei height) 18824a49301eSmrg{ 18834a49301eSmrg /* GL_ARB_fbo says calling this function is equivalent to calling 18844a49301eSmrg * glRenderbufferStorageMultisample() with samples=0. We pass in 18854a49301eSmrg * a token value here just for error reporting purposes. 18864a49301eSmrg */ 18874a49301eSmrg renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES); 18884a49301eSmrg} 18894a49301eSmrg 18904a49301eSmrg 18914a49301eSmrgvoid GLAPIENTRY 18924a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, 18934a49301eSmrg GLenum internalFormat, 18944a49301eSmrg GLsizei width, GLsizei height) 18954a49301eSmrg{ 18964a49301eSmrg renderbuffer_storage(target, internalFormat, width, height, samples); 18974a49301eSmrg} 18984a49301eSmrg 18994a49301eSmrg 19003464ebd5Sriastradh/** 19013464ebd5Sriastradh * OpenGL ES version of glRenderBufferStorage. 19023464ebd5Sriastradh */ 19033464ebd5Sriastradhvoid GLAPIENTRY 19043464ebd5Sriastradh_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 19053464ebd5Sriastradh GLsizei width, GLsizei height) 19063464ebd5Sriastradh{ 19073464ebd5Sriastradh switch (internalFormat) { 19083464ebd5Sriastradh case GL_RGB565: 19093464ebd5Sriastradh /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */ 19103464ebd5Sriastradh /* choose a closest format */ 19113464ebd5Sriastradh internalFormat = GL_RGB5; 19123464ebd5Sriastradh break; 19133464ebd5Sriastradh default: 19143464ebd5Sriastradh break; 19153464ebd5Sriastradh } 19163464ebd5Sriastradh 19173464ebd5Sriastradh renderbuffer_storage(target, internalFormat, width, height, 0); 19183464ebd5Sriastradh} 19193464ebd5Sriastradh 19204a49301eSmrg 19217117f1b4Smrgvoid GLAPIENTRY 1922af69d88dSmrg_mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) 19237117f1b4Smrg{ 19244a49301eSmrg struct gl_renderbuffer *rb; 19257117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 19267117f1b4Smrg 19277117f1b4Smrg if (target != GL_RENDERBUFFER_EXT) { 19287117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 19297117f1b4Smrg "glGetRenderbufferParameterivEXT(target)"); 19307117f1b4Smrg return; 19317117f1b4Smrg } 19327117f1b4Smrg 19334a49301eSmrg rb = ctx->CurrentRenderbuffer; 19344a49301eSmrg if (!rb) { 19357117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 19367117f1b4Smrg "glGetRenderbufferParameterivEXT"); 19377117f1b4Smrg return; 19387117f1b4Smrg } 19397117f1b4Smrg 19404a49301eSmrg /* No need to flush here since we're just quering state which is 19414a49301eSmrg * not effected by rendering. 19424a49301eSmrg */ 19437117f1b4Smrg 19447117f1b4Smrg switch (pname) { 19457117f1b4Smrg case GL_RENDERBUFFER_WIDTH_EXT: 19464a49301eSmrg *params = rb->Width; 19477117f1b4Smrg return; 19487117f1b4Smrg case GL_RENDERBUFFER_HEIGHT_EXT: 19494a49301eSmrg *params = rb->Height; 19507117f1b4Smrg return; 19517117f1b4Smrg case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 19524a49301eSmrg *params = rb->InternalFormat; 19537117f1b4Smrg return; 19547117f1b4Smrg case GL_RENDERBUFFER_RED_SIZE_EXT: 19557117f1b4Smrg case GL_RENDERBUFFER_GREEN_SIZE_EXT: 19567117f1b4Smrg case GL_RENDERBUFFER_BLUE_SIZE_EXT: 19577117f1b4Smrg case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 19587117f1b4Smrg case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 19597117f1b4Smrg case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 19604a49301eSmrg *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); 19617117f1b4Smrg break; 19624a49301eSmrg case GL_RENDERBUFFER_SAMPLES: 1963af69d88dSmrg if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object) 1964af69d88dSmrg || _mesa_is_gles3(ctx)) { 19654a49301eSmrg *params = rb->NumSamples; 19664a49301eSmrg break; 19674a49301eSmrg } 19684a49301eSmrg /* fallthrough */ 19697117f1b4Smrg default: 19707117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 19717117f1b4Smrg "glGetRenderbufferParameterivEXT(target)"); 19727117f1b4Smrg return; 19737117f1b4Smrg } 19747117f1b4Smrg} 19757117f1b4Smrg 19767117f1b4Smrg 19777117f1b4SmrgGLboolean GLAPIENTRY 1978af69d88dSmrg_mesa_IsFramebuffer(GLuint framebuffer) 19797117f1b4Smrg{ 19807117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 19817117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 19827117f1b4Smrg if (framebuffer) { 19837117f1b4Smrg struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); 19847117f1b4Smrg if (rb != NULL && rb != &DummyFramebuffer) 19857117f1b4Smrg return GL_TRUE; 19867117f1b4Smrg } 19877117f1b4Smrg return GL_FALSE; 19887117f1b4Smrg} 19897117f1b4Smrg 19907117f1b4Smrg 19914a49301eSmrg/** 19924a49301eSmrg * Check if any of the attachments of the given framebuffer are textures 19934a49301eSmrg * (render to texture). Call ctx->Driver.RenderTexture() for such 19944a49301eSmrg * attachments. 19954a49301eSmrg */ 19967117f1b4Smrgstatic void 19973464ebd5Sriastradhcheck_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) 19987117f1b4Smrg{ 19997117f1b4Smrg GLuint i; 20007117f1b4Smrg ASSERT(ctx->Driver.RenderTexture); 20014a49301eSmrg 2002af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) 20034a49301eSmrg return; /* can't render to texture with winsys framebuffers */ 20044a49301eSmrg 20057117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 20067117f1b4Smrg struct gl_renderbuffer_attachment *att = fb->Attachment + i; 2007af69d88dSmrg if (att->Texture && att->Renderbuffer->TexImage 2008af69d88dSmrg && driver_RenderTexture_is_safe(att)) { 20097117f1b4Smrg ctx->Driver.RenderTexture(ctx, fb, att); 20107117f1b4Smrg } 20117117f1b4Smrg } 20127117f1b4Smrg} 20137117f1b4Smrg 20147117f1b4Smrg 20157117f1b4Smrg/** 20167117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures. 20177117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to 20187117f1b4Smrg * notify the device driver that the texture image may have changed. 20197117f1b4Smrg */ 20207117f1b4Smrgstatic void 20213464ebd5Sriastradhcheck_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) 20227117f1b4Smrg{ 2023af69d88dSmrg /* Skip if we know NeedsFinishRenderTexture won't be set. */ 2024af69d88dSmrg if (_mesa_is_winsys_fbo(fb) && !ctx->Driver.BindRenderbufferTexImage) 2025af69d88dSmrg return; 20264a49301eSmrg 20277117f1b4Smrg if (ctx->Driver.FinishRenderTexture) { 20287117f1b4Smrg GLuint i; 20297117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 20307117f1b4Smrg struct gl_renderbuffer_attachment *att = fb->Attachment + i; 2031af69d88dSmrg struct gl_renderbuffer *rb = att->Renderbuffer; 2032af69d88dSmrg if (rb && rb->NeedsFinishRenderTexture) { 2033af69d88dSmrg ctx->Driver.FinishRenderTexture(ctx, rb); 20347117f1b4Smrg } 20357117f1b4Smrg } 20367117f1b4Smrg } 20377117f1b4Smrg} 20387117f1b4Smrg 20397117f1b4Smrg 2040af69d88dSmrgstatic void 2041af69d88dSmrgbind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names) 20427117f1b4Smrg{ 20434a49301eSmrg struct gl_framebuffer *newDrawFb, *newReadFb; 20444a49301eSmrg struct gl_framebuffer *oldDrawFb, *oldReadFb; 20457117f1b4Smrg GLboolean bindReadBuf, bindDrawBuf; 20467117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 20477117f1b4Smrg 20487117f1b4Smrg switch (target) { 20497117f1b4Smrg case GL_DRAW_FRAMEBUFFER_EXT: 20507117f1b4Smrg bindDrawBuf = GL_TRUE; 20517117f1b4Smrg bindReadBuf = GL_FALSE; 20527117f1b4Smrg break; 20537117f1b4Smrg case GL_READ_FRAMEBUFFER_EXT: 20547117f1b4Smrg bindDrawBuf = GL_FALSE; 20557117f1b4Smrg bindReadBuf = GL_TRUE; 20567117f1b4Smrg break; 20577117f1b4Smrg case GL_FRAMEBUFFER_EXT: 20587117f1b4Smrg bindDrawBuf = GL_TRUE; 20597117f1b4Smrg bindReadBuf = GL_TRUE; 20607117f1b4Smrg break; 20617117f1b4Smrg default: 20627117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 20637117f1b4Smrg return; 20647117f1b4Smrg } 20657117f1b4Smrg 20667117f1b4Smrg if (framebuffer) { 20677117f1b4Smrg /* Binding a user-created framebuffer object */ 20684a49301eSmrg newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); 20694a49301eSmrg if (newDrawFb == &DummyFramebuffer) { 20707117f1b4Smrg /* ID was reserved, but no real framebuffer object made yet */ 20714a49301eSmrg newDrawFb = NULL; 20727117f1b4Smrg } 2073af69d88dSmrg else if (!newDrawFb && !allow_user_names) { 20744a49301eSmrg /* All FBO IDs must be Gen'd */ 20754a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); 20764a49301eSmrg return; 20774a49301eSmrg } 20784a49301eSmrg 20794a49301eSmrg if (!newDrawFb) { 20807117f1b4Smrg /* create new framebuffer object */ 20814a49301eSmrg newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 20824a49301eSmrg if (!newDrawFb) { 20837117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 20847117f1b4Smrg return; 20857117f1b4Smrg } 20864a49301eSmrg _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb); 20877117f1b4Smrg } 20884a49301eSmrg newReadFb = newDrawFb; 20897117f1b4Smrg } 20907117f1b4Smrg else { 20917117f1b4Smrg /* Binding the window system framebuffer (which was originally set 20927117f1b4Smrg * with MakeCurrent). 20937117f1b4Smrg */ 20944a49301eSmrg newDrawFb = ctx->WinSysDrawBuffer; 20954a49301eSmrg newReadFb = ctx->WinSysReadBuffer; 20967117f1b4Smrg } 20977117f1b4Smrg 20984a49301eSmrg ASSERT(newDrawFb); 20994a49301eSmrg ASSERT(newDrawFb != &DummyFramebuffer); 21004a49301eSmrg 21014a49301eSmrg /* save pointers to current/old framebuffers */ 21024a49301eSmrg oldDrawFb = ctx->DrawBuffer; 21034a49301eSmrg oldReadFb = ctx->ReadBuffer; 21044a49301eSmrg 21054a49301eSmrg /* check if really changing bindings */ 21064a49301eSmrg if (oldDrawFb == newDrawFb) 21074a49301eSmrg bindDrawBuf = GL_FALSE; 21084a49301eSmrg if (oldReadFb == newReadFb) 21094a49301eSmrg bindReadBuf = GL_FALSE; 21107117f1b4Smrg 21117117f1b4Smrg /* 21124a49301eSmrg * OK, now bind the new Draw/Read framebuffers, if they're changing. 21134a49301eSmrg * 21144a49301eSmrg * We also check if we're beginning and/or ending render-to-texture. 21154a49301eSmrg * When a framebuffer with texture attachments is unbound, call 21164a49301eSmrg * ctx->Driver.FinishRenderTexture(). 21174a49301eSmrg * When a framebuffer with texture attachments is bound, call 21184a49301eSmrg * ctx->Driver.RenderTexture(). 21194a49301eSmrg * 21204a49301eSmrg * Note that if the ReadBuffer has texture attachments we don't consider 21214a49301eSmrg * that a render-to-texture case. 21227117f1b4Smrg */ 21237117f1b4Smrg if (bindReadBuf) { 21244a49301eSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 21254a49301eSmrg 21264a49301eSmrg /* check if old readbuffer was render-to-texture */ 21274a49301eSmrg check_end_texture_render(ctx, oldReadFb); 21284a49301eSmrg 21294a49301eSmrg _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); 21307117f1b4Smrg } 21317117f1b4Smrg 21327117f1b4Smrg if (bindDrawBuf) { 21334a49301eSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 21347117f1b4Smrg 2135af69d88dSmrg /* check if old framebuffer had any texture attachments */ 2136af69d88dSmrg if (oldDrawFb) 21374a49301eSmrg check_end_texture_render(ctx, oldDrawFb); 21384a49301eSmrg 21394a49301eSmrg /* check if newly bound framebuffer has any texture attachments */ 21404a49301eSmrg check_begin_texture_render(ctx, newDrawFb); 21414a49301eSmrg 21424a49301eSmrg _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); 21437117f1b4Smrg } 21447117f1b4Smrg 21454a49301eSmrg if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { 21464a49301eSmrg ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb); 21477117f1b4Smrg } 21487117f1b4Smrg} 21497117f1b4Smrg 2150af69d88dSmrgvoid GLAPIENTRY 2151af69d88dSmrg_mesa_BindFramebuffer(GLenum target, GLuint framebuffer) 2152af69d88dSmrg{ 2153af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 2154af69d88dSmrg 2155af69d88dSmrg /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry 2156af69d88dSmrg * point, but they allow the use of user-generated names. 2157af69d88dSmrg */ 2158af69d88dSmrg bind_framebuffer(target, framebuffer, _mesa_is_gles(ctx)); 2159af69d88dSmrg} 2160af69d88dSmrg 21617117f1b4Smrg 21627117f1b4Smrgvoid GLAPIENTRY 2163af69d88dSmrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 2164af69d88dSmrg{ 2165af69d88dSmrg /* This function should not be in the dispatch table for core profile / 2166af69d88dSmrg * OpenGL 3.1, so execution should never get here in those cases -- no 2167af69d88dSmrg * need for an explicit test. 2168af69d88dSmrg */ 2169af69d88dSmrg bind_framebuffer(target, framebuffer, true); 2170af69d88dSmrg} 2171af69d88dSmrg 2172af69d88dSmrg 2173af69d88dSmrgvoid GLAPIENTRY 2174af69d88dSmrg_mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) 21757117f1b4Smrg{ 21767117f1b4Smrg GLint i; 21777117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 21787117f1b4Smrg 21797117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 21807117f1b4Smrg 21817117f1b4Smrg for (i = 0; i < n; i++) { 21827117f1b4Smrg if (framebuffers[i] > 0) { 21837117f1b4Smrg struct gl_framebuffer *fb; 21847117f1b4Smrg fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); 21857117f1b4Smrg if (fb) { 21867117f1b4Smrg ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 21877117f1b4Smrg 21887117f1b4Smrg /* check if deleting currently bound framebuffer object */ 2189af69d88dSmrg if (fb == ctx->DrawBuffer) { 2190af69d88dSmrg /* bind default */ 2191af69d88dSmrg ASSERT(fb->RefCount >= 2); 2192af69d88dSmrg _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 21934a49301eSmrg } 2194af69d88dSmrg if (fb == ctx->ReadBuffer) { 2195af69d88dSmrg /* bind default */ 2196af69d88dSmrg ASSERT(fb->RefCount >= 2); 2197af69d88dSmrg _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, 0); 21987117f1b4Smrg } 21997117f1b4Smrg 22007117f1b4Smrg /* remove from hash table immediately, to free the ID */ 22017117f1b4Smrg _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 22027117f1b4Smrg 22037117f1b4Smrg if (fb != &DummyFramebuffer) { 22047117f1b4Smrg /* But the object will not be freed until it's no longer 22057117f1b4Smrg * bound in any context. 22067117f1b4Smrg */ 22074a49301eSmrg _mesa_reference_framebuffer(&fb, NULL); 22087117f1b4Smrg } 22097117f1b4Smrg } 22107117f1b4Smrg } 22117117f1b4Smrg } 22127117f1b4Smrg} 22137117f1b4Smrg 22147117f1b4Smrg 22157117f1b4Smrgvoid GLAPIENTRY 2216af69d88dSmrg_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers) 22177117f1b4Smrg{ 22187117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 22197117f1b4Smrg GLuint first; 22207117f1b4Smrg GLint i; 22217117f1b4Smrg 22227117f1b4Smrg if (n < 0) { 22237117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); 22247117f1b4Smrg return; 22257117f1b4Smrg } 22267117f1b4Smrg 22277117f1b4Smrg if (!framebuffers) 22287117f1b4Smrg return; 22297117f1b4Smrg 22307117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 22317117f1b4Smrg 22327117f1b4Smrg for (i = 0; i < n; i++) { 22337117f1b4Smrg GLuint name = first + i; 22347117f1b4Smrg framebuffers[i] = name; 22357117f1b4Smrg /* insert dummy placeholder into hash table */ 2236af69d88dSmrg mtx_lock(&ctx->Shared->Mutex); 22377117f1b4Smrg _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); 2238af69d88dSmrg mtx_unlock(&ctx->Shared->Mutex); 22397117f1b4Smrg } 22407117f1b4Smrg} 22417117f1b4Smrg 22427117f1b4Smrg 22437117f1b4SmrgGLenum GLAPIENTRY 2244af69d88dSmrg_mesa_CheckFramebufferStatus(GLenum target) 22457117f1b4Smrg{ 22467117f1b4Smrg struct gl_framebuffer *buffer; 22477117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 22487117f1b4Smrg 22497117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 22507117f1b4Smrg 2251af69d88dSmrg if (MESA_VERBOSE & VERBOSE_API) 2252af69d88dSmrg _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n", 2253af69d88dSmrg _mesa_lookup_enum_by_nr(target)); 2254af69d88dSmrg 22553464ebd5Sriastradh buffer = get_framebuffer_target(ctx, target); 22563464ebd5Sriastradh if (!buffer) { 22577117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 22583464ebd5Sriastradh return 0; 22597117f1b4Smrg } 22607117f1b4Smrg 2261af69d88dSmrg if (_mesa_is_winsys_fbo(buffer)) { 2262af69d88dSmrg /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */ 2263af69d88dSmrg if (buffer != &IncompleteFramebuffer) { 2264af69d88dSmrg return GL_FRAMEBUFFER_COMPLETE_EXT; 2265af69d88dSmrg } else { 2266af69d88dSmrg return GL_FRAMEBUFFER_UNDEFINED; 2267af69d88dSmrg } 22687117f1b4Smrg } 22697117f1b4Smrg 22704a49301eSmrg /* No need to flush here */ 22714a49301eSmrg 22724a49301eSmrg if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { 22734a49301eSmrg _mesa_test_framebuffer_completeness(ctx, buffer); 22744a49301eSmrg } 22757117f1b4Smrg 22767117f1b4Smrg return buffer->_Status; 22777117f1b4Smrg} 22787117f1b4Smrg 22797117f1b4Smrg 2280af69d88dSmrg/** 2281af69d88dSmrg * Replicate the src attachment point. Used by framebuffer_texture() when 2282af69d88dSmrg * the same texture is attached at GL_DEPTH_ATTACHMENT and 2283af69d88dSmrg * GL_STENCIL_ATTACHMENT. 2284af69d88dSmrg */ 2285af69d88dSmrgstatic void 2286af69d88dSmrgreuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, 2287af69d88dSmrg gl_buffer_index dst, 2288af69d88dSmrg gl_buffer_index src) 2289af69d88dSmrg{ 2290af69d88dSmrg struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst]; 2291af69d88dSmrg struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src]; 2292af69d88dSmrg 2293af69d88dSmrg assert(src_att->Texture != NULL); 2294af69d88dSmrg assert(src_att->Renderbuffer != NULL); 2295af69d88dSmrg 2296af69d88dSmrg _mesa_reference_texobj(&dst_att->Texture, src_att->Texture); 2297af69d88dSmrg _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer); 2298af69d88dSmrg dst_att->Type = src_att->Type; 2299af69d88dSmrg dst_att->Complete = src_att->Complete; 2300af69d88dSmrg dst_att->TextureLevel = src_att->TextureLevel; 2301af69d88dSmrg dst_att->Zoffset = src_att->Zoffset; 2302af69d88dSmrg} 2303af69d88dSmrg 23047117f1b4Smrg 23057117f1b4Smrg/** 2306af69d88dSmrg * Common code called by glFramebufferTexture1D/2D/3DEXT() and 2307af69d88dSmrg * glFramebufferTextureLayerEXT(). 2308af69d88dSmrg * 2309af69d88dSmrg * \param textarget is the textarget that was passed to the 2310af69d88dSmrg * glFramebufferTexture...() function, or 0 if the corresponding function 2311af69d88dSmrg * doesn't have a textarget parameter. 2312af69d88dSmrg * 2313af69d88dSmrg * \param layered is true if this function was called from 2314af69d88dSmrg * glFramebufferTexture(), false otherwise. 23157117f1b4Smrg */ 23167117f1b4Smrgstatic void 2317af69d88dSmrgframebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, 23187117f1b4Smrg GLenum attachment, GLenum textarget, GLuint texture, 2319af69d88dSmrg GLint level, GLint zoffset, GLboolean layered) 23207117f1b4Smrg{ 23217117f1b4Smrg struct gl_renderbuffer_attachment *att; 23227117f1b4Smrg struct gl_texture_object *texObj = NULL; 23237117f1b4Smrg struct gl_framebuffer *fb; 2324af69d88dSmrg GLenum maxLevelsTarget; 23257117f1b4Smrg 23263464ebd5Sriastradh fb = get_framebuffer_target(ctx, target); 23273464ebd5Sriastradh if (!fb) { 23287117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 23294a49301eSmrg "glFramebufferTexture%sEXT(target=0x%x)", caller, target); 23307117f1b4Smrg return; 23317117f1b4Smrg } 23327117f1b4Smrg 23337117f1b4Smrg /* check framebuffer binding */ 2334af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) { 23357117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 23367117f1b4Smrg "glFramebufferTexture%sEXT", caller); 23377117f1b4Smrg return; 23387117f1b4Smrg } 23397117f1b4Smrg 23407117f1b4Smrg /* The textarget, level, and zoffset parameters are only validated if 23417117f1b4Smrg * texture is non-zero. 23427117f1b4Smrg */ 23437117f1b4Smrg if (texture) { 23447117f1b4Smrg GLboolean err = GL_TRUE; 23457117f1b4Smrg 23467117f1b4Smrg texObj = _mesa_lookup_texture(ctx, texture); 23477117f1b4Smrg if (texObj != NULL) { 2348c1f859d4Smrg if (textarget == 0) { 2349af69d88dSmrg if (layered) { 2350af69d88dSmrg /* We're being called by glFramebufferTexture() and textarget 2351af69d88dSmrg * is not used. 2352af69d88dSmrg */ 2353af69d88dSmrg switch (texObj->Target) { 2354af69d88dSmrg case GL_TEXTURE_3D: 2355af69d88dSmrg case GL_TEXTURE_1D_ARRAY_EXT: 2356af69d88dSmrg case GL_TEXTURE_2D_ARRAY_EXT: 2357af69d88dSmrg case GL_TEXTURE_CUBE_MAP: 2358af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 2359af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 2360af69d88dSmrg err = false; 2361af69d88dSmrg break; 2362af69d88dSmrg case GL_TEXTURE_1D: 2363af69d88dSmrg case GL_TEXTURE_2D: 2364af69d88dSmrg case GL_TEXTURE_RECTANGLE: 2365af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE: 2366af69d88dSmrg /* These texture types are valid to pass to 2367af69d88dSmrg * glFramebufferTexture(), but since they aren't layered, it 2368af69d88dSmrg * is equivalent to calling glFramebufferTexture{1D,2D}(). 2369af69d88dSmrg */ 2370af69d88dSmrg err = false; 2371af69d88dSmrg layered = false; 2372af69d88dSmrg textarget = texObj->Target; 2373af69d88dSmrg break; 2374af69d88dSmrg default: 2375af69d88dSmrg err = true; 2376af69d88dSmrg break; 2377af69d88dSmrg } 2378af69d88dSmrg } else { 2379af69d88dSmrg /* We're being called by glFramebufferTextureLayer() and 2380af69d88dSmrg * textarget is not used. The only legal texture types for 2381af69d88dSmrg * that function are 3D and 1D/2D arrays textures. 2382af69d88dSmrg */ 2383af69d88dSmrg err = (texObj->Target != GL_TEXTURE_3D) && 2384af69d88dSmrg (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && 2385af69d88dSmrg (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT) && 2386af69d88dSmrg (texObj->Target != GL_TEXTURE_CUBE_MAP_ARRAY) && 2387af69d88dSmrg (texObj->Target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY); 2388af69d88dSmrg } 2389c1f859d4Smrg } 2390c1f859d4Smrg else { 2391af69d88dSmrg /* Make sure textarget is consistent with the texture's type */ 2392c1f859d4Smrg err = (texObj->Target == GL_TEXTURE_CUBE_MAP) 2393af69d88dSmrg ? !_mesa_is_cube_face(textarget) 2394c1f859d4Smrg : (texObj->Target != textarget); 2395c1f859d4Smrg } 23967117f1b4Smrg } 23973464ebd5Sriastradh else { 23983464ebd5Sriastradh /* can't render to a non-existant texture */ 23993464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 24003464ebd5Sriastradh "glFramebufferTexture%sEXT(non existant texture)", 24013464ebd5Sriastradh caller); 24023464ebd5Sriastradh return; 24033464ebd5Sriastradh } 24047117f1b4Smrg 24057117f1b4Smrg if (err) { 24067117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 24077117f1b4Smrg "glFramebufferTexture%sEXT(texture target mismatch)", 24087117f1b4Smrg caller); 24097117f1b4Smrg return; 24107117f1b4Smrg } 24117117f1b4Smrg 24127117f1b4Smrg if (texObj->Target == GL_TEXTURE_3D) { 24137117f1b4Smrg const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 24147117f1b4Smrg if (zoffset < 0 || zoffset >= maxSize) { 24157117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2416c1f859d4Smrg "glFramebufferTexture%sEXT(zoffset)", caller); 24177117f1b4Smrg return; 24187117f1b4Smrg } 24197117f1b4Smrg } 2420c1f859d4Smrg else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || 2421af69d88dSmrg (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT) || 2422af69d88dSmrg (texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) || 2423af69d88dSmrg (texObj->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { 2424af69d88dSmrg if (zoffset < 0 || 2425af69d88dSmrg zoffset >= (GLint) ctx->Const.MaxArrayTextureLayers) { 2426c1f859d4Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2427c1f859d4Smrg "glFramebufferTexture%sEXT(layer)", caller); 2428c1f859d4Smrg return; 2429c1f859d4Smrg } 2430c1f859d4Smrg } 2431c1f859d4Smrg 2432af69d88dSmrg maxLevelsTarget = textarget ? textarget : texObj->Target; 2433af69d88dSmrg if ((level < 0) || 2434af69d88dSmrg (level >= _mesa_max_texture_levels(ctx, maxLevelsTarget))) { 24357117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, 24367117f1b4Smrg "glFramebufferTexture%sEXT(level)", caller); 24377117f1b4Smrg return; 24387117f1b4Smrg } 24397117f1b4Smrg } 24407117f1b4Smrg 2441af69d88dSmrg att = get_attachment(ctx, fb, attachment); 24427117f1b4Smrg if (att == NULL) { 24437117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 24447117f1b4Smrg "glFramebufferTexture%sEXT(attachment)", caller); 24457117f1b4Smrg return; 24467117f1b4Smrg } 24477117f1b4Smrg 24487117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 24497117f1b4Smrg 2450af69d88dSmrg mtx_lock(&fb->Mutex); 24517117f1b4Smrg if (texObj) { 2452af69d88dSmrg if (attachment == GL_DEPTH_ATTACHMENT && 2453af69d88dSmrg texObj == fb->Attachment[BUFFER_STENCIL].Texture && 2454af69d88dSmrg level == fb->Attachment[BUFFER_STENCIL].TextureLevel && 2455af69d88dSmrg _mesa_tex_target_to_face(textarget) == 2456af69d88dSmrg fb->Attachment[BUFFER_STENCIL].CubeMapFace && 2457af69d88dSmrg zoffset == fb->Attachment[BUFFER_STENCIL].Zoffset) { 2458af69d88dSmrg /* The texture object is already attached to the stencil attachment 2459af69d88dSmrg * point. Don't create a new renderbuffer; just reuse the stencil 2460af69d88dSmrg * attachment's. This is required to prevent a GL error in 2461af69d88dSmrg * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL). 2462af69d88dSmrg */ 2463af69d88dSmrg reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH, 2464af69d88dSmrg BUFFER_STENCIL); 2465af69d88dSmrg } else if (attachment == GL_STENCIL_ATTACHMENT && 2466af69d88dSmrg texObj == fb->Attachment[BUFFER_DEPTH].Texture && 2467af69d88dSmrg level == fb->Attachment[BUFFER_DEPTH].TextureLevel && 2468af69d88dSmrg _mesa_tex_target_to_face(textarget) == 2469af69d88dSmrg fb->Attachment[BUFFER_DEPTH].CubeMapFace && 2470af69d88dSmrg zoffset == fb->Attachment[BUFFER_DEPTH].Zoffset) { 2471af69d88dSmrg /* As above, but with depth and stencil transposed. */ 2472af69d88dSmrg reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL, 2473af69d88dSmrg BUFFER_DEPTH); 2474af69d88dSmrg } else { 2475af69d88dSmrg set_texture_attachment(ctx, fb, att, texObj, textarget, 2476af69d88dSmrg level, zoffset, layered); 2477af69d88dSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 2478af69d88dSmrg /* Above we created a new renderbuffer and attached it to the 2479af69d88dSmrg * depth attachment point. Now attach it to the stencil attachment 2480af69d88dSmrg * point too. 2481af69d88dSmrg */ 2482af69d88dSmrg assert(att == &fb->Attachment[BUFFER_DEPTH]); 2483af69d88dSmrg reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL, 2484af69d88dSmrg BUFFER_DEPTH); 2485af69d88dSmrg } 2486af69d88dSmrg } 2487af69d88dSmrg 24884a49301eSmrg /* Set the render-to-texture flag. We'll check this flag in 24894a49301eSmrg * glTexImage() and friends to determine if we need to revalidate 24904a49301eSmrg * any FBOs that might be rendering into this texture. 24914a49301eSmrg * This flag never gets cleared since it's non-trivial to determine 24924a49301eSmrg * when all FBOs might be done rendering to this texture. That's OK 24934a49301eSmrg * though since it's uncommon to render to a texture then repeatedly 24944a49301eSmrg * call glTexImage() to change images in the texture. 24954a49301eSmrg */ 24964a49301eSmrg texObj->_RenderToTexture = GL_TRUE; 24977117f1b4Smrg } 24987117f1b4Smrg else { 2499af69d88dSmrg remove_attachment(ctx, att); 2500af69d88dSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 2501af69d88dSmrg assert(att == &fb->Attachment[BUFFER_DEPTH]); 2502af69d88dSmrg remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]); 2503af69d88dSmrg } 25047117f1b4Smrg } 25054a49301eSmrg 25064a49301eSmrg invalidate_framebuffer(fb); 25074a49301eSmrg 2508af69d88dSmrg mtx_unlock(&fb->Mutex); 25097117f1b4Smrg} 25107117f1b4Smrg 25117117f1b4Smrg 25127117f1b4Smrgvoid GLAPIENTRY 2513af69d88dSmrg_mesa_FramebufferTexture1D(GLenum target, GLenum attachment, 2514af69d88dSmrg GLenum textarget, GLuint texture, GLint level) 25157117f1b4Smrg{ 25167117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 25177117f1b4Smrg 2518af69d88dSmrg if (texture != 0) { 2519af69d88dSmrg GLboolean error; 2520af69d88dSmrg 2521af69d88dSmrg switch (textarget) { 2522af69d88dSmrg case GL_TEXTURE_1D: 2523af69d88dSmrg error = GL_FALSE; 2524af69d88dSmrg break; 2525af69d88dSmrg case GL_TEXTURE_1D_ARRAY: 2526af69d88dSmrg error = !ctx->Extensions.EXT_texture_array; 2527af69d88dSmrg break; 2528af69d88dSmrg default: 2529af69d88dSmrg error = GL_TRUE; 2530af69d88dSmrg } 2531af69d88dSmrg 2532af69d88dSmrg if (error) { 2533af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 2534af69d88dSmrg "glFramebufferTexture1DEXT(textarget=%s)", 2535af69d88dSmrg _mesa_lookup_enum_by_nr(textarget)); 2536af69d88dSmrg return; 2537af69d88dSmrg } 25387117f1b4Smrg } 25397117f1b4Smrg 25407117f1b4Smrg framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, 2541af69d88dSmrg level, 0, GL_FALSE); 25427117f1b4Smrg} 25437117f1b4Smrg 25447117f1b4Smrg 25457117f1b4Smrgvoid GLAPIENTRY 2546af69d88dSmrg_mesa_FramebufferTexture2D(GLenum target, GLenum attachment, 2547af69d88dSmrg GLenum textarget, GLuint texture, GLint level) 25487117f1b4Smrg{ 25497117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 25507117f1b4Smrg 2551af69d88dSmrg if (texture != 0) { 2552af69d88dSmrg GLboolean error; 2553af69d88dSmrg 2554af69d88dSmrg switch (textarget) { 2555af69d88dSmrg case GL_TEXTURE_2D: 2556af69d88dSmrg error = GL_FALSE; 2557af69d88dSmrg break; 2558af69d88dSmrg case GL_TEXTURE_RECTANGLE: 2559af69d88dSmrg error = _mesa_is_gles(ctx) 2560af69d88dSmrg || !ctx->Extensions.NV_texture_rectangle; 2561af69d88dSmrg break; 2562af69d88dSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 2563af69d88dSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 2564af69d88dSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 2565af69d88dSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 2566af69d88dSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 2567af69d88dSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 2568af69d88dSmrg error = !ctx->Extensions.ARB_texture_cube_map; 2569af69d88dSmrg break; 2570af69d88dSmrg case GL_TEXTURE_2D_ARRAY: 2571af69d88dSmrg error = (_mesa_is_gles(ctx) && ctx->Version < 30) 2572af69d88dSmrg || !ctx->Extensions.EXT_texture_array; 2573af69d88dSmrg break; 2574af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE: 2575af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 2576af69d88dSmrg error = _mesa_is_gles(ctx) 2577af69d88dSmrg || !ctx->Extensions.ARB_texture_multisample; 2578af69d88dSmrg break; 2579af69d88dSmrg default: 2580af69d88dSmrg error = GL_TRUE; 2581af69d88dSmrg } 2582af69d88dSmrg 2583af69d88dSmrg if (error) { 2584af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 2585af69d88dSmrg "glFramebufferTexture2DEXT(textarget=%s)", 2586af69d88dSmrg _mesa_lookup_enum_by_nr(textarget)); 2587af69d88dSmrg return; 2588af69d88dSmrg } 25897117f1b4Smrg } 25907117f1b4Smrg 25917117f1b4Smrg framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, 2592af69d88dSmrg level, 0, GL_FALSE); 25937117f1b4Smrg} 25947117f1b4Smrg 25957117f1b4Smrg 25967117f1b4Smrgvoid GLAPIENTRY 2597af69d88dSmrg_mesa_FramebufferTexture3D(GLenum target, GLenum attachment, 2598af69d88dSmrg GLenum textarget, GLuint texture, 2599af69d88dSmrg GLint level, GLint zoffset) 26007117f1b4Smrg{ 26017117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 26027117f1b4Smrg 26037117f1b4Smrg if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { 26043464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 26057117f1b4Smrg "glFramebufferTexture3DEXT(textarget)"); 26067117f1b4Smrg return; 26077117f1b4Smrg } 26087117f1b4Smrg 26097117f1b4Smrg framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, 2610af69d88dSmrg level, zoffset, GL_FALSE); 26117117f1b4Smrg} 26127117f1b4Smrg 26137117f1b4Smrg 2614c1f859d4Smrgvoid GLAPIENTRY 2615af69d88dSmrg_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, 2616af69d88dSmrg GLuint texture, GLint level, GLint layer) 2617c1f859d4Smrg{ 2618c1f859d4Smrg GET_CURRENT_CONTEXT(ctx); 2619c1f859d4Smrg 2620c1f859d4Smrg framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, 2621af69d88dSmrg level, layer, GL_FALSE); 2622af69d88dSmrg} 2623af69d88dSmrg 2624af69d88dSmrg 2625af69d88dSmrgvoid GLAPIENTRY 2626af69d88dSmrg_mesa_FramebufferTexture(GLenum target, GLenum attachment, 2627af69d88dSmrg GLuint texture, GLint level) 2628af69d88dSmrg{ 2629af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 2630af69d88dSmrg 2631af69d88dSmrg if (_mesa_has_geometry_shaders(ctx)) { 2632af69d88dSmrg framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, 2633af69d88dSmrg level, 0, GL_TRUE); 2634af69d88dSmrg } else { 2635af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 2636af69d88dSmrg "unsupported function (glFramebufferTexture) called"); 2637af69d88dSmrg } 2638c1f859d4Smrg} 2639c1f859d4Smrg 2640c1f859d4Smrg 26417117f1b4Smrgvoid GLAPIENTRY 2642af69d88dSmrg_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, 2643af69d88dSmrg GLenum renderbufferTarget, 2644af69d88dSmrg GLuint renderbuffer) 26457117f1b4Smrg{ 26467117f1b4Smrg struct gl_renderbuffer_attachment *att; 26477117f1b4Smrg struct gl_framebuffer *fb; 26487117f1b4Smrg struct gl_renderbuffer *rb; 26497117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 26507117f1b4Smrg 26513464ebd5Sriastradh fb = get_framebuffer_target(ctx, target); 26523464ebd5Sriastradh if (!fb) { 2653af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 2654af69d88dSmrg "glFramebufferRenderbufferEXT(target)"); 26557117f1b4Smrg return; 26567117f1b4Smrg } 26577117f1b4Smrg 26587117f1b4Smrg if (renderbufferTarget != GL_RENDERBUFFER_EXT) { 26597117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 26607117f1b4Smrg "glFramebufferRenderbufferEXT(renderbufferTarget)"); 26617117f1b4Smrg return; 26627117f1b4Smrg } 26637117f1b4Smrg 2664af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) { 26657117f1b4Smrg /* Can't attach new renderbuffers to a window system framebuffer */ 26667117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); 26677117f1b4Smrg return; 26687117f1b4Smrg } 26697117f1b4Smrg 2670af69d88dSmrg att = get_attachment(ctx, fb, attachment); 26717117f1b4Smrg if (att == NULL) { 26727117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 26734a49301eSmrg "glFramebufferRenderbufferEXT(invalid attachment %s)", 26744a49301eSmrg _mesa_lookup_enum_by_nr(attachment)); 26757117f1b4Smrg return; 26767117f1b4Smrg } 26777117f1b4Smrg 26787117f1b4Smrg if (renderbuffer) { 26797117f1b4Smrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 26807117f1b4Smrg if (!rb) { 26817117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 26824a49301eSmrg "glFramebufferRenderbufferEXT(non-existant" 26834a49301eSmrg " renderbuffer %u)", renderbuffer); 26847117f1b4Smrg return; 26857117f1b4Smrg } 26863464ebd5Sriastradh else if (rb == &DummyRenderbuffer) { 2687af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 26883464ebd5Sriastradh "glFramebufferRenderbufferEXT(renderbuffer %u)", 26893464ebd5Sriastradh renderbuffer); 26903464ebd5Sriastradh return; 26913464ebd5Sriastradh } 26927117f1b4Smrg } 26937117f1b4Smrg else { 26947117f1b4Smrg /* remove renderbuffer attachment */ 26957117f1b4Smrg rb = NULL; 26967117f1b4Smrg } 26977117f1b4Smrg 2698cdc920a0Smrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && 2699cdc920a0Smrg rb && rb->Format != MESA_FORMAT_NONE) { 27004a49301eSmrg /* make sure the renderbuffer is a depth/stencil format */ 2701cdc920a0Smrg const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); 27024a49301eSmrg if (baseFormat != GL_DEPTH_STENCIL) { 27034a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 27044a49301eSmrg "glFramebufferRenderbufferEXT(renderbuffer" 27054a49301eSmrg " is not DEPTH_STENCIL format)"); 27064a49301eSmrg return; 27074a49301eSmrg } 27084a49301eSmrg } 27094a49301eSmrg 27107117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 27117117f1b4Smrg 27127117f1b4Smrg assert(ctx->Driver.FramebufferRenderbuffer); 27137117f1b4Smrg ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); 27147117f1b4Smrg 27157117f1b4Smrg /* Some subsequent GL commands may depend on the framebuffer's visual 27167117f1b4Smrg * after the binding is updated. Update visual info now. 27177117f1b4Smrg */ 27183464ebd5Sriastradh _mesa_update_framebuffer_visual(ctx, fb); 27197117f1b4Smrg} 27207117f1b4Smrg 27217117f1b4Smrg 27227117f1b4Smrgvoid GLAPIENTRY 2723af69d88dSmrg_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, 2724af69d88dSmrg GLenum pname, GLint *params) 27257117f1b4Smrg{ 27267117f1b4Smrg const struct gl_renderbuffer_attachment *att; 27277117f1b4Smrg struct gl_framebuffer *buffer; 27283464ebd5Sriastradh GLenum err; 27297117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 27307117f1b4Smrg 2731af69d88dSmrg /* The error differs in GL and GLES. */ 2732af69d88dSmrg err = _mesa_is_desktop_gl(ctx) ? GL_INVALID_OPERATION : GL_INVALID_ENUM; 27333464ebd5Sriastradh 27343464ebd5Sriastradh buffer = get_framebuffer_target(ctx, target); 27353464ebd5Sriastradh if (!buffer) { 27367117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 27377117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(target)"); 27387117f1b4Smrg return; 27397117f1b4Smrg } 27407117f1b4Smrg 2741af69d88dSmrg if (_mesa_is_winsys_fbo(buffer)) { 2742af69d88dSmrg /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec 2743af69d88dSmrg * says: 2744af69d88dSmrg * 2745af69d88dSmrg * "If the framebuffer currently bound to target is zero, then 2746af69d88dSmrg * INVALID_OPERATION is generated." 2747af69d88dSmrg * 2748af69d88dSmrg * The EXT_framebuffer_object spec has the same wording, and the 2749af69d88dSmrg * OES_framebuffer_object spec refers to the EXT_framebuffer_object 2750af69d88dSmrg * spec. 2751af69d88dSmrg */ 2752af69d88dSmrg if ((!_mesa_is_desktop_gl(ctx) || 2753af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 2754af69d88dSmrg && !_mesa_is_gles3(ctx)) { 2755af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 2756af69d88dSmrg "glGetFramebufferAttachmentParameteriv(bound FBO = 0)"); 2757af69d88dSmrg return; 2758af69d88dSmrg } 2759af69d88dSmrg 2760af69d88dSmrg if (_mesa_is_gles3(ctx) && attachment != GL_BACK && 2761af69d88dSmrg attachment != GL_DEPTH && attachment != GL_STENCIL) { 2762af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 2763af69d88dSmrg "glGetFramebufferAttachmentParameteriv(attachment)"); 2764af69d88dSmrg return; 2765af69d88dSmrg } 27663464ebd5Sriastradh /* the default / window-system FBO */ 27673464ebd5Sriastradh att = _mesa_get_fb0_attachment(ctx, buffer, attachment); 27683464ebd5Sriastradh } 27693464ebd5Sriastradh else { 27703464ebd5Sriastradh /* user-created framebuffer FBO */ 2771af69d88dSmrg att = get_attachment(ctx, buffer, attachment); 27727117f1b4Smrg } 27737117f1b4Smrg 27747117f1b4Smrg if (att == NULL) { 27757117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 27767117f1b4Smrg "glGetFramebufferAttachmentParameterivEXT(attachment)"); 27777117f1b4Smrg return; 27787117f1b4Smrg } 27797117f1b4Smrg 27804a49301eSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 27814a49301eSmrg const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; 2782af69d88dSmrg if (pname == GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) { 2783af69d88dSmrg /* This behavior is first specified in OpenGL 4.4 specification. 2784af69d88dSmrg * 2785af69d88dSmrg * From the OpenGL 4.4 spec page 275: 2786af69d88dSmrg * "This query cannot be performed for a combined depth+stencil 2787af69d88dSmrg * attachment, since it does not have a single format." 2788af69d88dSmrg */ 2789af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 2790af69d88dSmrg "glGetFramebufferAttachmentParameteriv(" 2791af69d88dSmrg "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE" 2792af69d88dSmrg " is invalid for depth+stencil attachment)"); 2793af69d88dSmrg return; 2794af69d88dSmrg } 2795af69d88dSmrg /* the depth and stencil attachments must point to the same buffer */ 2796af69d88dSmrg depthAtt = get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); 2797af69d88dSmrg stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); 27984a49301eSmrg if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { 27994a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 28004a49301eSmrg "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" 28014a49301eSmrg " attachments differ)"); 28024a49301eSmrg return; 28034a49301eSmrg } 28044a49301eSmrg } 28054a49301eSmrg 28064a49301eSmrg /* No need to flush here */ 28077117f1b4Smrg 28087117f1b4Smrg switch (pname) { 28097117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 2810af69d88dSmrg *params = _mesa_is_winsys_fbo(buffer) 2811af69d88dSmrg ? GL_FRAMEBUFFER_DEFAULT : att->Type; 28127117f1b4Smrg return; 28137117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 28147117f1b4Smrg if (att->Type == GL_RENDERBUFFER_EXT) { 28157117f1b4Smrg *params = att->Renderbuffer->Name; 28167117f1b4Smrg } 28177117f1b4Smrg else if (att->Type == GL_TEXTURE) { 28187117f1b4Smrg *params = att->Texture->Name; 28197117f1b4Smrg } 28207117f1b4Smrg else { 28213464ebd5Sriastradh assert(att->Type == GL_NONE); 2822af69d88dSmrg if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { 28233464ebd5Sriastradh *params = 0; 28243464ebd5Sriastradh } else { 2825af69d88dSmrg goto invalid_pname_enum; 28263464ebd5Sriastradh } 28277117f1b4Smrg } 28287117f1b4Smrg return; 28297117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 28307117f1b4Smrg if (att->Type == GL_TEXTURE) { 28317117f1b4Smrg *params = att->TextureLevel; 28327117f1b4Smrg } 28333464ebd5Sriastradh else if (att->Type == GL_NONE) { 28343464ebd5Sriastradh _mesa_error(ctx, err, 28353464ebd5Sriastradh "glGetFramebufferAttachmentParameterivEXT(pname)"); 28363464ebd5Sriastradh } 28377117f1b4Smrg else { 2838af69d88dSmrg goto invalid_pname_enum; 28397117f1b4Smrg } 28407117f1b4Smrg return; 28417117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 28427117f1b4Smrg if (att->Type == GL_TEXTURE) { 2843c1f859d4Smrg if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { 2844c1f859d4Smrg *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 2845c1f859d4Smrg } 2846c1f859d4Smrg else { 2847c1f859d4Smrg *params = 0; 2848c1f859d4Smrg } 28497117f1b4Smrg } 28503464ebd5Sriastradh else if (att->Type == GL_NONE) { 28513464ebd5Sriastradh _mesa_error(ctx, err, 28523464ebd5Sriastradh "glGetFramebufferAttachmentParameterivEXT(pname)"); 28533464ebd5Sriastradh } 28547117f1b4Smrg else { 2855af69d88dSmrg goto invalid_pname_enum; 28567117f1b4Smrg } 28577117f1b4Smrg return; 28587117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 2859af69d88dSmrg if (ctx->API == API_OPENGLES) { 2860af69d88dSmrg goto invalid_pname_enum; 2861af69d88dSmrg } else if (att->Type == GL_NONE) { 2862af69d88dSmrg _mesa_error(ctx, err, 2863af69d88dSmrg "glGetFramebufferAttachmentParameterivEXT(pname)"); 2864af69d88dSmrg } else if (att->Type == GL_TEXTURE) { 2865c1f859d4Smrg if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { 2866c1f859d4Smrg *params = att->Zoffset; 2867c1f859d4Smrg } 2868c1f859d4Smrg else { 2869c1f859d4Smrg *params = 0; 2870c1f859d4Smrg } 28717117f1b4Smrg } 28727117f1b4Smrg else { 2873af69d88dSmrg goto invalid_pname_enum; 28747117f1b4Smrg } 28757117f1b4Smrg return; 28764a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: 2877af69d88dSmrg if ((!_mesa_is_desktop_gl(ctx) || 2878af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 2879af69d88dSmrg && !_mesa_is_gles3(ctx)) { 2880af69d88dSmrg goto invalid_pname_enum; 28814a49301eSmrg } 28823464ebd5Sriastradh else if (att->Type == GL_NONE) { 28833464ebd5Sriastradh _mesa_error(ctx, err, 28843464ebd5Sriastradh "glGetFramebufferAttachmentParameterivEXT(pname)"); 28853464ebd5Sriastradh } 28864a49301eSmrg else { 2887af69d88dSmrg if (ctx->Extensions.EXT_framebuffer_sRGB) { 2888af69d88dSmrg *params = 2889af69d88dSmrg _mesa_get_format_color_encoding(att->Renderbuffer->Format); 28903464ebd5Sriastradh } 28913464ebd5Sriastradh else { 28923464ebd5Sriastradh /* According to ARB_framebuffer_sRGB, we should return LINEAR 28933464ebd5Sriastradh * if the sRGB conversion is unsupported. */ 28943464ebd5Sriastradh *params = GL_LINEAR; 28953464ebd5Sriastradh } 28964a49301eSmrg } 28974a49301eSmrg return; 28984a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: 2899af69d88dSmrg if ((ctx->API != API_OPENGL_COMPAT || 2900af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 2901af69d88dSmrg && ctx->API != API_OPENGL_CORE 2902af69d88dSmrg && !_mesa_is_gles3(ctx)) { 2903af69d88dSmrg goto invalid_pname_enum; 29044a49301eSmrg } 29053464ebd5Sriastradh else if (att->Type == GL_NONE) { 29063464ebd5Sriastradh _mesa_error(ctx, err, 29073464ebd5Sriastradh "glGetFramebufferAttachmentParameterivEXT(pname)"); 29083464ebd5Sriastradh } 29094a49301eSmrg else { 2910af69d88dSmrg mesa_format format = att->Renderbuffer->Format; 2911af69d88dSmrg 2912af69d88dSmrg /* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES 2913af69d88dSmrg * 3.0.1 spec says: 2914af69d88dSmrg * 2915af69d88dSmrg * "If pname is FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE.... If 2916af69d88dSmrg * attachment is DEPTH_STENCIL_ATTACHMENT the query will fail and 2917af69d88dSmrg * generate an INVALID_OPERATION error. 2918af69d88dSmrg */ 2919af69d88dSmrg if (_mesa_is_gles3(ctx) && 2920af69d88dSmrg attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 2921af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 2922af69d88dSmrg "glGetFramebufferAttachmentParameteriv(cannot query " 2923af69d88dSmrg "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of " 2924af69d88dSmrg "GL_DEPTH_STENCIL_ATTACHMENT"); 2925af69d88dSmrg return; 2926af69d88dSmrg } 2927af69d88dSmrg 2928af69d88dSmrg if (format == MESA_FORMAT_S_UINT8) { 29294a49301eSmrg /* special cases */ 29304a49301eSmrg *params = GL_INDEX; 29314a49301eSmrg } 2932af69d88dSmrg else if (format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) { 2933af69d88dSmrg /* depends on the attachment parameter */ 2934af69d88dSmrg if (attachment == GL_STENCIL_ATTACHMENT) { 2935af69d88dSmrg *params = GL_INDEX; 2936af69d88dSmrg } 2937af69d88dSmrg else { 2938af69d88dSmrg *params = GL_FLOAT; 2939af69d88dSmrg } 2940af69d88dSmrg } 29414a49301eSmrg else { 29424a49301eSmrg *params = _mesa_get_format_datatype(format); 29434a49301eSmrg } 29444a49301eSmrg } 29454a49301eSmrg return; 29464a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: 29474a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 29484a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 29494a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 29504a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 29514a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 2952af69d88dSmrg if ((!_mesa_is_desktop_gl(ctx) || 2953af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 2954af69d88dSmrg && !_mesa_is_gles3(ctx)) { 2955af69d88dSmrg goto invalid_pname_enum; 29564a49301eSmrg } 29573464ebd5Sriastradh else if (att->Type == GL_NONE) { 29583464ebd5Sriastradh _mesa_error(ctx, err, 29593464ebd5Sriastradh "glGetFramebufferAttachmentParameterivEXT(pname)"); 29603464ebd5Sriastradh } 29614a49301eSmrg else if (att->Texture) { 29624a49301eSmrg const struct gl_texture_image *texImage = 29634a49301eSmrg _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, 29644a49301eSmrg att->TextureLevel); 29654a49301eSmrg if (texImage) { 29664a49301eSmrg *params = get_component_bits(pname, texImage->_BaseFormat, 29674a49301eSmrg texImage->TexFormat); 29684a49301eSmrg } 29694a49301eSmrg else { 29704a49301eSmrg *params = 0; 29714a49301eSmrg } 29724a49301eSmrg } 29734a49301eSmrg else if (att->Renderbuffer) { 29744a49301eSmrg *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, 29754a49301eSmrg att->Renderbuffer->Format); 29764a49301eSmrg } 29774a49301eSmrg else { 29783464ebd5Sriastradh _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:" 29793464ebd5Sriastradh " invalid FBO attachment structure"); 29804a49301eSmrg } 29814a49301eSmrg return; 2982af69d88dSmrg case GL_FRAMEBUFFER_ATTACHMENT_LAYERED: 2983af69d88dSmrg if (!_mesa_has_geometry_shaders(ctx)) { 2984af69d88dSmrg goto invalid_pname_enum; 2985af69d88dSmrg } else if (att->Type == GL_TEXTURE) { 2986af69d88dSmrg *params = att->Layered; 2987af69d88dSmrg } else if (att->Type == GL_NONE) { 2988af69d88dSmrg _mesa_error(ctx, err, 2989af69d88dSmrg "glGetFramebufferAttachmentParameteriv(pname)"); 2990af69d88dSmrg } else { 2991af69d88dSmrg goto invalid_pname_enum; 2992af69d88dSmrg } 29937117f1b4Smrg return; 2994af69d88dSmrg default: 2995af69d88dSmrg goto invalid_pname_enum; 29967117f1b4Smrg } 2997af69d88dSmrg 2998af69d88dSmrg return; 2999af69d88dSmrg 3000af69d88dSmrginvalid_pname_enum: 3001af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 3002af69d88dSmrg "glGetFramebufferAttachmentParameteriv(pname)"); 3003af69d88dSmrg return; 30047117f1b4Smrg} 30057117f1b4Smrg 30067117f1b4Smrg 3007af69d88dSmrgstatic void 3008af69d88dSmrginvalidate_framebuffer_storage(GLenum target, GLsizei numAttachments, 3009af69d88dSmrg const GLenum *attachments, GLint x, GLint y, 3010af69d88dSmrg GLsizei width, GLsizei height, const char *name) 30117117f1b4Smrg{ 3012af69d88dSmrg int i; 3013af69d88dSmrg struct gl_framebuffer *fb; 30147117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 30157117f1b4Smrg 3016af69d88dSmrg fb = get_framebuffer_target(ctx, target); 3017af69d88dSmrg if (!fb) { 3018af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", name); 30197117f1b4Smrg return; 30207117f1b4Smrg } 30217117f1b4Smrg 3022af69d88dSmrg if (numAttachments < 0) { 3023af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 3024af69d88dSmrg "%s(numAttachments < 0)", name); 30254a49301eSmrg return; 30264a49301eSmrg } 30277117f1b4Smrg 3028af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 3029af69d88dSmrg * 3030af69d88dSmrg * "If an attachment is specified that does not exist in the 3031af69d88dSmrg * framebuffer bound to <target>, it is ignored." 3032af69d88dSmrg * 3033af69d88dSmrg * It also says: 3034af69d88dSmrg * 3035af69d88dSmrg * "If <attachments> contains COLOR_ATTACHMENTm and m is greater than 3036af69d88dSmrg * or equal to the value of MAX_COLOR_ATTACHMENTS, then the error 3037af69d88dSmrg * INVALID_OPERATION is generated." 3038af69d88dSmrg * 3039af69d88dSmrg * No mention is made of GL_AUXi being out of range. Therefore, we allow 3040af69d88dSmrg * any enum that can be allowed by the API (OpenGL ES 3.0 has a different 3041af69d88dSmrg * set of retrictions). 3042af69d88dSmrg */ 3043af69d88dSmrg for (i = 0; i < numAttachments; i++) { 3044af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) { 3045af69d88dSmrg switch (attachments[i]) { 3046af69d88dSmrg case GL_ACCUM: 3047af69d88dSmrg case GL_AUX0: 3048af69d88dSmrg case GL_AUX1: 3049af69d88dSmrg case GL_AUX2: 3050af69d88dSmrg case GL_AUX3: 3051af69d88dSmrg /* Accumulation buffers and auxilary buffers were removed in 3052af69d88dSmrg * OpenGL 3.1, and they never existed in OpenGL ES. 3053af69d88dSmrg */ 3054af69d88dSmrg if (ctx->API != API_OPENGL_COMPAT) 3055af69d88dSmrg goto invalid_enum; 3056af69d88dSmrg break; 3057af69d88dSmrg case GL_COLOR: 3058af69d88dSmrg case GL_DEPTH: 3059af69d88dSmrg case GL_STENCIL: 3060af69d88dSmrg break; 3061af69d88dSmrg case GL_BACK_LEFT: 3062af69d88dSmrg case GL_BACK_RIGHT: 3063af69d88dSmrg case GL_FRONT_LEFT: 3064af69d88dSmrg case GL_FRONT_RIGHT: 3065af69d88dSmrg if (!_mesa_is_desktop_gl(ctx)) 3066af69d88dSmrg goto invalid_enum; 3067af69d88dSmrg break; 3068af69d88dSmrg default: 3069af69d88dSmrg goto invalid_enum; 3070af69d88dSmrg } 3071af69d88dSmrg } else { 3072af69d88dSmrg switch (attachments[i]) { 3073af69d88dSmrg case GL_DEPTH_ATTACHMENT: 3074af69d88dSmrg case GL_STENCIL_ATTACHMENT: 3075af69d88dSmrg break; 3076af69d88dSmrg case GL_COLOR_ATTACHMENT0: 3077af69d88dSmrg case GL_COLOR_ATTACHMENT1: 3078af69d88dSmrg case GL_COLOR_ATTACHMENT2: 3079af69d88dSmrg case GL_COLOR_ATTACHMENT3: 3080af69d88dSmrg case GL_COLOR_ATTACHMENT4: 3081af69d88dSmrg case GL_COLOR_ATTACHMENT5: 3082af69d88dSmrg case GL_COLOR_ATTACHMENT6: 3083af69d88dSmrg case GL_COLOR_ATTACHMENT7: 3084af69d88dSmrg case GL_COLOR_ATTACHMENT8: 3085af69d88dSmrg case GL_COLOR_ATTACHMENT9: 3086af69d88dSmrg case GL_COLOR_ATTACHMENT10: 3087af69d88dSmrg case GL_COLOR_ATTACHMENT11: 3088af69d88dSmrg case GL_COLOR_ATTACHMENT12: 3089af69d88dSmrg case GL_COLOR_ATTACHMENT13: 3090af69d88dSmrg case GL_COLOR_ATTACHMENT14: 3091af69d88dSmrg case GL_COLOR_ATTACHMENT15: { 3092af69d88dSmrg unsigned k = attachments[i] - GL_COLOR_ATTACHMENT0; 3093af69d88dSmrg if (k >= ctx->Const.MaxColorAttachments) { 3094af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 3095af69d88dSmrg "%s(attachment >= max. color attachments)", name); 3096af69d88dSmrg return; 3097af69d88dSmrg } 3098af69d88dSmrg break; 3099af69d88dSmrg } 3100af69d88dSmrg default: 3101af69d88dSmrg goto invalid_enum; 3102af69d88dSmrg } 3103af69d88dSmrg } 31043464ebd5Sriastradh } 31053464ebd5Sriastradh 3106af69d88dSmrg /* We don't actually do anything for this yet. Just return after 3107af69d88dSmrg * validating the parameters and generating the required errors. 3108af69d88dSmrg */ 3109af69d88dSmrg return; 31107117f1b4Smrg 3111af69d88dSmrginvalid_enum: 3112af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(attachment)", name); 3113af69d88dSmrg return; 3114af69d88dSmrg} 31157117f1b4Smrg 31164a49301eSmrg 3117af69d88dSmrgvoid GLAPIENTRY 3118af69d88dSmrg_mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, 3119af69d88dSmrg const GLenum *attachments, GLint x, GLint y, 3120af69d88dSmrg GLsizei width, GLsizei height) 31214a49301eSmrg{ 3122af69d88dSmrg invalidate_framebuffer_storage(target, numAttachments, attachments, 3123af69d88dSmrg x, y, width, height, 3124af69d88dSmrg "glInvalidateSubFramebuffer"); 31254a49301eSmrg} 31264a49301eSmrg 31274a49301eSmrg 31287117f1b4Smrgvoid GLAPIENTRY 3129af69d88dSmrg_mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, 3130af69d88dSmrg const GLenum *attachments) 31317117f1b4Smrg{ 3132af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 3133af69d88dSmrg * 3134af69d88dSmrg * "The command 3135af69d88dSmrg * 3136af69d88dSmrg * void InvalidateFramebuffer(enum target, 3137af69d88dSmrg * sizei numAttachments, 3138af69d88dSmrg * const enum *attachments); 3139af69d88dSmrg * 3140af69d88dSmrg * is equivalent to the command InvalidateSubFramebuffer with <x>, <y>, 3141af69d88dSmrg * <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>, 3142af69d88dSmrg * <MAX_VIEWPORT_DIMS[1]> respectively." 3143af69d88dSmrg */ 3144af69d88dSmrg invalidate_framebuffer_storage(target, numAttachments, attachments, 3145af69d88dSmrg 0, 0, 3146af69d88dSmrg MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT, 3147af69d88dSmrg "glInvalidateFramebuffer"); 3148af69d88dSmrg} 31494a49301eSmrg 31503464ebd5Sriastradh 3151af69d88dSmrgvoid GLAPIENTRY 3152af69d88dSmrg_mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, 3153af69d88dSmrg const GLenum *attachments) 3154af69d88dSmrg{ 3155af69d88dSmrg struct gl_framebuffer *fb; 3156af69d88dSmrg GLint i; 31573464ebd5Sriastradh 3158af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 31597117f1b4Smrg 3160af69d88dSmrg fb = get_framebuffer_target(ctx, target); 3161af69d88dSmrg if (!fb) { 3162af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 3163af69d88dSmrg "glDiscardFramebufferEXT(target %s)", 3164af69d88dSmrg _mesa_lookup_enum_by_nr(target)); 31654a49301eSmrg return; 31664a49301eSmrg } 31674a49301eSmrg 3168af69d88dSmrg if (numAttachments < 0) { 3169af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 3170af69d88dSmrg "glDiscardFramebufferEXT(numAttachments < 0)"); 31717117f1b4Smrg return; 31727117f1b4Smrg } 31737117f1b4Smrg 3174af69d88dSmrg for (i = 0; i < numAttachments; i++) { 3175af69d88dSmrg switch (attachments[i]) { 3176af69d88dSmrg case GL_COLOR: 3177af69d88dSmrg case GL_DEPTH: 3178af69d88dSmrg case GL_STENCIL: 3179af69d88dSmrg if (_mesa_is_user_fbo(fb)) 3180af69d88dSmrg goto invalid_enum; 3181af69d88dSmrg break; 3182af69d88dSmrg case GL_COLOR_ATTACHMENT0: 3183af69d88dSmrg case GL_DEPTH_ATTACHMENT: 3184af69d88dSmrg case GL_STENCIL_ATTACHMENT: 3185af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) 3186af69d88dSmrg goto invalid_enum; 3187af69d88dSmrg break; 3188af69d88dSmrg default: 3189af69d88dSmrg goto invalid_enum; 31904a49301eSmrg } 31914a49301eSmrg } 31924a49301eSmrg 3193af69d88dSmrg if (ctx->Driver.DiscardFramebuffer) 3194af69d88dSmrg ctx->Driver.DiscardFramebuffer(ctx, target, numAttachments, attachments); 31953464ebd5Sriastradh 3196af69d88dSmrg return; 31973464ebd5Sriastradh 3198af69d88dSmrginvalid_enum: 3199af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 3200af69d88dSmrg "glDiscardFramebufferEXT(attachment %s)", 3201af69d88dSmrg _mesa_lookup_enum_by_nr(attachments[i])); 32023464ebd5Sriastradh} 3203