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" 3801e04c3fSmrg#include "debug_output.h" 397ec681f3Smrg#include "draw_validate.h" 404a49301eSmrg#include "enums.h" 417117f1b4Smrg#include "fbobject.h" 424a49301eSmrg#include "formats.h" 437117f1b4Smrg#include "framebuffer.h" 44af69d88dSmrg#include "glformats.h" 457117f1b4Smrg#include "hash.h" 464a49301eSmrg#include "macros.h" 47af69d88dSmrg#include "multisample.h" 483464ebd5Sriastradh#include "mtypes.h" 497117f1b4Smrg#include "renderbuffer.h" 507117f1b4Smrg#include "state.h" 517117f1b4Smrg#include "teximage.h" 527117f1b4Smrg#include "texobj.h" 534a49301eSmrg 544a49301eSmrg 557117f1b4Smrg/** 567117f1b4Smrg * Notes: 577117f1b4Smrg * 587117f1b4Smrg * None of the GL_EXT_framebuffer_object functions are compiled into 597117f1b4Smrg * display lists. 607117f1b4Smrg */ 617117f1b4Smrg 627117f1b4Smrg 637117f1b4Smrg 64c1f859d4Smrgstatic void 65af69d88dSmrgdelete_dummy_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) 66c1f859d4Smrg{ 67c1f859d4Smrg /* no op */ 68c1f859d4Smrg} 69c1f859d4Smrg 70c1f859d4Smrgstatic void 71c1f859d4Smrgdelete_dummy_framebuffer(struct gl_framebuffer *fb) 72c1f859d4Smrg{ 73c1f859d4Smrg /* no op */ 74c1f859d4Smrg} 75c1f859d4Smrg 76c1f859d4Smrg 777ec681f3Smrg/* 787ec681f3Smrg * When glGenRender/FramebuffersEXT() is called we insert pointers to 797ec681f3Smrg * these placeholder objects into the hash table. 807ec681f3Smrg * Later, when the object ID is first bound, we replace the placeholder 817ec681f3Smrg * with the real frame/renderbuffer. 827ec681f3Smrg */ 837ec681f3Smrgstatic struct gl_framebuffer DummyFramebuffer = { 847ec681f3Smrg .Mutex = _SIMPLE_MTX_INITIALIZER_NP, 857ec681f3Smrg .Delete = delete_dummy_framebuffer, 867ec681f3Smrg}; 877ec681f3Smrgstatic struct gl_renderbuffer DummyRenderbuffer = { 887ec681f3Smrg .Delete = delete_dummy_renderbuffer, 897ec681f3Smrg}; 907ec681f3Smrg 917ec681f3Smrg/* We bind this framebuffer when applications pass a NULL 927ec681f3Smrg * drawable/surface in make current. */ 937ec681f3Smrgstatic struct gl_framebuffer IncompleteFramebuffer = { 947ec681f3Smrg .Mutex = _SIMPLE_MTX_INITIALIZER_NP, 957ec681f3Smrg .Delete = delete_dummy_framebuffer, 967ec681f3Smrg}; 977ec681f3Smrg 98c1f859d4Smrg 993464ebd5Sriastradhstruct gl_framebuffer * 1003464ebd5Sriastradh_mesa_get_incomplete_framebuffer(void) 1013464ebd5Sriastradh{ 1023464ebd5Sriastradh return &IncompleteFramebuffer; 1033464ebd5Sriastradh} 104c1f859d4Smrg 1057117f1b4Smrg/** 1067117f1b4Smrg * Helper routine for getting a gl_renderbuffer. 1077117f1b4Smrg */ 1087117f1b4Smrgstruct gl_renderbuffer * 1093464ebd5Sriastradh_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id) 1107117f1b4Smrg{ 1117117f1b4Smrg struct gl_renderbuffer *rb; 1127117f1b4Smrg 1137117f1b4Smrg if (id == 0) 1147117f1b4Smrg return NULL; 1157117f1b4Smrg 1167117f1b4Smrg rb = (struct gl_renderbuffer *) 1177117f1b4Smrg _mesa_HashLookup(ctx->Shared->RenderBuffers, id); 1187117f1b4Smrg return rb; 1197117f1b4Smrg} 1207117f1b4Smrg 1217117f1b4Smrg 12201e04c3fSmrg/** 12301e04c3fSmrg * A convenience function for direct state access that throws 12401e04c3fSmrg * GL_INVALID_OPERATION if the renderbuffer doesn't exist. 12501e04c3fSmrg */ 12601e04c3fSmrgstruct gl_renderbuffer * 12701e04c3fSmrg_mesa_lookup_renderbuffer_err(struct gl_context *ctx, GLuint id, 12801e04c3fSmrg const char *func) 12901e04c3fSmrg{ 13001e04c3fSmrg struct gl_renderbuffer *rb; 13101e04c3fSmrg 13201e04c3fSmrg rb = _mesa_lookup_renderbuffer(ctx, id); 13301e04c3fSmrg if (!rb || rb == &DummyRenderbuffer) { 13401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 13501e04c3fSmrg "%s(non-existent renderbuffer %u)", func, id); 13601e04c3fSmrg return NULL; 13701e04c3fSmrg } 13801e04c3fSmrg 13901e04c3fSmrg return rb; 14001e04c3fSmrg} 14101e04c3fSmrg 14201e04c3fSmrg 1437117f1b4Smrg/** 1447117f1b4Smrg * Helper routine for getting a gl_framebuffer. 1457117f1b4Smrg */ 1467117f1b4Smrgstruct gl_framebuffer * 1473464ebd5Sriastradh_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) 1487117f1b4Smrg{ 1497117f1b4Smrg struct gl_framebuffer *fb; 1507117f1b4Smrg 1517117f1b4Smrg if (id == 0) 1527117f1b4Smrg return NULL; 1537117f1b4Smrg 1547117f1b4Smrg fb = (struct gl_framebuffer *) 1557117f1b4Smrg _mesa_HashLookup(ctx->Shared->FrameBuffers, id); 1567ec681f3Smrg 1577ec681f3Smrg return fb; 1587ec681f3Smrg} 1597ec681f3Smrg 1607ec681f3Smrg 1617ec681f3Smrgstruct gl_framebuffer * 1627ec681f3Smrg_mesa_lookup_framebuffer_dsa(struct gl_context *ctx, GLuint id, 1637ec681f3Smrg const char* func) 1647ec681f3Smrg{ 1657ec681f3Smrg struct gl_framebuffer *fb; 1667ec681f3Smrg 1677ec681f3Smrg if (id == 0) 1687ec681f3Smrg return NULL; 1697ec681f3Smrg 1707ec681f3Smrg fb = _mesa_lookup_framebuffer(ctx, id); 1717ec681f3Smrg 1727ec681f3Smrg /* Name exists but buffer is not initialized */ 1737ec681f3Smrg if (fb == &DummyFramebuffer) { 1747ec681f3Smrg fb = ctx->Driver.NewFramebuffer(ctx, id); 1757ec681f3Smrg _mesa_HashInsert(ctx->Shared->FrameBuffers, id, fb, true); 1767ec681f3Smrg } 1777ec681f3Smrg /* Name doesn't exist */ 1787ec681f3Smrg else if (!fb) { 1797ec681f3Smrg fb = ctx->Driver.NewFramebuffer(ctx, id); 1807ec681f3Smrg if (!fb) { 1817ec681f3Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 1827ec681f3Smrg return NULL; 1837ec681f3Smrg } 1847ec681f3Smrg _mesa_HashInsert(ctx->Shared->FrameBuffers, id, fb, false); 1857ec681f3Smrg } 1867117f1b4Smrg return fb; 1877117f1b4Smrg} 1887117f1b4Smrg 1897117f1b4Smrg 19001e04c3fSmrg/** 19101e04c3fSmrg * A convenience function for direct state access that throws 19201e04c3fSmrg * GL_INVALID_OPERATION if the framebuffer doesn't exist. 19301e04c3fSmrg */ 19401e04c3fSmrgstruct gl_framebuffer * 19501e04c3fSmrg_mesa_lookup_framebuffer_err(struct gl_context *ctx, GLuint id, 19601e04c3fSmrg const char *func) 19701e04c3fSmrg{ 19801e04c3fSmrg struct gl_framebuffer *fb; 19901e04c3fSmrg 20001e04c3fSmrg fb = _mesa_lookup_framebuffer(ctx, id); 20101e04c3fSmrg if (!fb || fb == &DummyFramebuffer) { 20201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 20301e04c3fSmrg "%s(non-existent framebuffer %u)", func, id); 20401e04c3fSmrg return NULL; 20501e04c3fSmrg } 20601e04c3fSmrg 20701e04c3fSmrg return fb; 20801e04c3fSmrg} 20901e04c3fSmrg 21001e04c3fSmrg 2114a49301eSmrg/** 2124a49301eSmrg * Mark the given framebuffer as invalid. This will force the 2134a49301eSmrg * test for framebuffer completeness to be done before the framebuffer 2144a49301eSmrg * is used. 2154a49301eSmrg */ 2164a49301eSmrgstatic void 2174a49301eSmrginvalidate_framebuffer(struct gl_framebuffer *fb) 2184a49301eSmrg{ 2194a49301eSmrg fb->_Status = 0; /* "indeterminate" */ 2204a49301eSmrg} 2214a49301eSmrg 2224a49301eSmrg 2233464ebd5Sriastradh/** 2243464ebd5Sriastradh * Return the gl_framebuffer object which corresponds to the given 2253464ebd5Sriastradh * framebuffer target, such as GL_DRAW_FRAMEBUFFER. 2263464ebd5Sriastradh * Check support for GL_EXT_framebuffer_blit to determine if certain 2273464ebd5Sriastradh * targets are legal. 2283464ebd5Sriastradh * \return gl_framebuffer pointer or NULL if target is illegal 2293464ebd5Sriastradh */ 2303464ebd5Sriastradhstatic struct gl_framebuffer * 2313464ebd5Sriastradhget_framebuffer_target(struct gl_context *ctx, GLenum target) 2323464ebd5Sriastradh{ 233af69d88dSmrg bool have_fb_blit = _mesa_is_gles3(ctx) || _mesa_is_desktop_gl(ctx); 2343464ebd5Sriastradh switch (target) { 2353464ebd5Sriastradh case GL_DRAW_FRAMEBUFFER: 236af69d88dSmrg return have_fb_blit ? ctx->DrawBuffer : NULL; 2373464ebd5Sriastradh case GL_READ_FRAMEBUFFER: 238af69d88dSmrg return have_fb_blit ? ctx->ReadBuffer : NULL; 2393464ebd5Sriastradh case GL_FRAMEBUFFER_EXT: 2403464ebd5Sriastradh return ctx->DrawBuffer; 2413464ebd5Sriastradh default: 2423464ebd5Sriastradh return NULL; 2433464ebd5Sriastradh } 2443464ebd5Sriastradh} 2453464ebd5Sriastradh 2463464ebd5Sriastradh 2477117f1b4Smrg/** 2487117f1b4Smrg * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding 2497117f1b4Smrg * gl_renderbuffer_attachment object. 2503464ebd5Sriastradh * This function is only used for user-created FB objects, not the 2513464ebd5Sriastradh * default / window-system FB object. 2524a49301eSmrg * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to 2534a49301eSmrg * the depth buffer attachment point. 25401e04c3fSmrg * Returns if the attachment is a GL_COLOR_ATTACHMENTm_EXT on 25501e04c3fSmrg * is_color_attachment, because several callers would return different errors 25601e04c3fSmrg * if they don't find the attachment. 2577117f1b4Smrg */ 258af69d88dSmrgstatic struct gl_renderbuffer_attachment * 259af69d88dSmrgget_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, 26001e04c3fSmrg GLenum attachment, bool *is_color_attachment) 2617117f1b4Smrg{ 2627117f1b4Smrg GLuint i; 2637117f1b4Smrg 264af69d88dSmrg assert(_mesa_is_user_fbo(fb)); 2653464ebd5Sriastradh 26601e04c3fSmrg if (is_color_attachment) 26701e04c3fSmrg *is_color_attachment = false; 26801e04c3fSmrg 2697117f1b4Smrg switch (attachment) { 2707117f1b4Smrg case GL_COLOR_ATTACHMENT0_EXT: 2717117f1b4Smrg case GL_COLOR_ATTACHMENT1_EXT: 2727117f1b4Smrg case GL_COLOR_ATTACHMENT2_EXT: 2737117f1b4Smrg case GL_COLOR_ATTACHMENT3_EXT: 2747117f1b4Smrg case GL_COLOR_ATTACHMENT4_EXT: 2757117f1b4Smrg case GL_COLOR_ATTACHMENT5_EXT: 2767117f1b4Smrg case GL_COLOR_ATTACHMENT6_EXT: 2777117f1b4Smrg case GL_COLOR_ATTACHMENT7_EXT: 2787117f1b4Smrg case GL_COLOR_ATTACHMENT8_EXT: 2797117f1b4Smrg case GL_COLOR_ATTACHMENT9_EXT: 2807117f1b4Smrg case GL_COLOR_ATTACHMENT10_EXT: 2817117f1b4Smrg case GL_COLOR_ATTACHMENT11_EXT: 2827117f1b4Smrg case GL_COLOR_ATTACHMENT12_EXT: 2837117f1b4Smrg case GL_COLOR_ATTACHMENT13_EXT: 2847117f1b4Smrg case GL_COLOR_ATTACHMENT14_EXT: 2857117f1b4Smrg case GL_COLOR_ATTACHMENT15_EXT: 28601e04c3fSmrg if (is_color_attachment) 28701e04c3fSmrg *is_color_attachment = true; 288af69d88dSmrg /* Only OpenGL ES 1.x forbids color attachments other than 289af69d88dSmrg * GL_COLOR_ATTACHMENT0. For all other APIs the limit set by the 290af69d88dSmrg * hardware is used. 291af69d88dSmrg */ 2927117f1b4Smrg i = attachment - GL_COLOR_ATTACHMENT0_EXT; 293af69d88dSmrg if (i >= ctx->Const.MaxColorAttachments 29401e04c3fSmrg || (i > 0 && ctx->API == API_OPENGLES)) { 29501e04c3fSmrg return NULL; 2967117f1b4Smrg } 2977ec681f3Smrg assert(BUFFER_COLOR0 + i < ARRAY_SIZE(fb->Attachment)); 2987117f1b4Smrg return &fb->Attachment[BUFFER_COLOR0 + i]; 2994a49301eSmrg case GL_DEPTH_STENCIL_ATTACHMENT: 300af69d88dSmrg if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) 30101e04c3fSmrg return NULL; 3027ec681f3Smrg FALLTHROUGH; 3037117f1b4Smrg case GL_DEPTH_ATTACHMENT_EXT: 3047117f1b4Smrg return &fb->Attachment[BUFFER_DEPTH]; 3057117f1b4Smrg case GL_STENCIL_ATTACHMENT_EXT: 3067117f1b4Smrg return &fb->Attachment[BUFFER_STENCIL]; 3077117f1b4Smrg default: 3087117f1b4Smrg return NULL; 3097117f1b4Smrg } 3107117f1b4Smrg} 3117117f1b4Smrg 3127117f1b4Smrg 3133464ebd5Sriastradh/** 3143464ebd5Sriastradh * As above, but only used for getting attachments of the default / 3153464ebd5Sriastradh * window-system framebuffer (not user-created framebuffer objects). 3163464ebd5Sriastradh */ 3173464ebd5Sriastradhstatic struct gl_renderbuffer_attachment * 31801e04c3fSmrgget_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, 31901e04c3fSmrg GLenum attachment) 3203464ebd5Sriastradh{ 321af69d88dSmrg assert(_mesa_is_winsys_fbo(fb)); 322af69d88dSmrg 3237ec681f3Smrg attachment = _mesa_back_to_front_if_single_buffered(fb, attachment); 3247ec681f3Smrg 325af69d88dSmrg if (_mesa_is_gles3(ctx)) { 326af69d88dSmrg switch (attachment) { 327af69d88dSmrg case GL_BACK: 328af69d88dSmrg /* Since there is no stereo rendering in ES 3.0, only return the 329af69d88dSmrg * LEFT bits. 330af69d88dSmrg */ 3317ec681f3Smrg return &fb->Attachment[BUFFER_BACK_LEFT]; 3327ec681f3Smrg case GL_FRONT: 3337ec681f3Smrg /* We might get this if back_to_front triggers above */ 334af69d88dSmrg return &fb->Attachment[BUFFER_FRONT_LEFT]; 335af69d88dSmrg case GL_DEPTH: 33601e04c3fSmrg return &fb->Attachment[BUFFER_DEPTH]; 337af69d88dSmrg case GL_STENCIL: 338af69d88dSmrg return &fb->Attachment[BUFFER_STENCIL]; 3397ec681f3Smrg default: 3407ec681f3Smrg unreachable("invalid attachment"); 341af69d88dSmrg } 342af69d88dSmrg } 3433464ebd5Sriastradh 3443464ebd5Sriastradh switch (attachment) { 3457ec681f3Smrg case GL_FRONT: 3463464ebd5Sriastradh case GL_FRONT_LEFT: 34701e04c3fSmrg /* Front buffers can be allocated on the first use, but 34801e04c3fSmrg * glGetFramebufferAttachmentParameteriv must work even if that 34901e04c3fSmrg * allocation hasn't happened yet. In such case, use the back buffer, 35001e04c3fSmrg * which should be the same. 35101e04c3fSmrg */ 35201e04c3fSmrg if (fb->Attachment[BUFFER_FRONT_LEFT].Type == GL_NONE) 35301e04c3fSmrg return &fb->Attachment[BUFFER_BACK_LEFT]; 35401e04c3fSmrg else 35501e04c3fSmrg return &fb->Attachment[BUFFER_FRONT_LEFT]; 3563464ebd5Sriastradh case GL_FRONT_RIGHT: 35701e04c3fSmrg /* Same as above. */ 35801e04c3fSmrg if (fb->Attachment[BUFFER_FRONT_RIGHT].Type == GL_NONE) 35901e04c3fSmrg return &fb->Attachment[BUFFER_BACK_RIGHT]; 36001e04c3fSmrg else 36101e04c3fSmrg return &fb->Attachment[BUFFER_FRONT_RIGHT]; 3623464ebd5Sriastradh case GL_BACK_LEFT: 3633464ebd5Sriastradh return &fb->Attachment[BUFFER_BACK_LEFT]; 3643464ebd5Sriastradh case GL_BACK_RIGHT: 3653464ebd5Sriastradh return &fb->Attachment[BUFFER_BACK_RIGHT]; 36601e04c3fSmrg case GL_BACK: 36701e04c3fSmrg /* The ARB_ES3_1_compatibility spec says: 36801e04c3fSmrg * 36901e04c3fSmrg * "Since this command can only query a single framebuffer 37001e04c3fSmrg * attachment, BACK is equivalent to BACK_LEFT." 37101e04c3fSmrg */ 37201e04c3fSmrg if (ctx->Extensions.ARB_ES3_1_compatibility) 37301e04c3fSmrg return &fb->Attachment[BUFFER_BACK_LEFT]; 37401e04c3fSmrg return NULL; 3753464ebd5Sriastradh case GL_AUX0: 3763464ebd5Sriastradh return NULL; 377af69d88dSmrg 378af69d88dSmrg /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says: 379af69d88dSmrg * 380af69d88dSmrg * "If the default framebuffer is bound to target, then attachment must 381af69d88dSmrg * be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi, 382af69d88dSmrg * identifying a color buffer; DEPTH, identifying the depth buffer; or 383af69d88dSmrg * STENCIL, identifying the stencil buffer." 384af69d88dSmrg * 385af69d88dSmrg * Revision #34 of the ARB_framebuffer_object spec has essentially the same 386af69d88dSmrg * language. However, revision #33 of the ARB_framebuffer_object spec 387af69d88dSmrg * says: 388af69d88dSmrg * 389af69d88dSmrg * "If the default framebuffer is bound to <target>, then <attachment> 390af69d88dSmrg * must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi, 391af69d88dSmrg * DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the 392af69d88dSmrg * depth buffer, or the stencil buffer, and <pname> may be 393af69d88dSmrg * FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or 394af69d88dSmrg * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME." 395af69d88dSmrg * 396af69d88dSmrg * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed 397af69d88dSmrg * from glext.h, so shipping apps should not use those values. 398af69d88dSmrg * 399af69d88dSmrg * Note that neither EXT_framebuffer_object nor OES_framebuffer_object 400af69d88dSmrg * support queries of the window system FBO. 401af69d88dSmrg */ 402af69d88dSmrg case GL_DEPTH: 4033464ebd5Sriastradh return &fb->Attachment[BUFFER_DEPTH]; 404af69d88dSmrg case GL_STENCIL: 4053464ebd5Sriastradh return &fb->Attachment[BUFFER_STENCIL]; 4063464ebd5Sriastradh default: 4073464ebd5Sriastradh return NULL; 4083464ebd5Sriastradh } 4093464ebd5Sriastradh} 4103464ebd5Sriastradh 4113464ebd5Sriastradh 4123464ebd5Sriastradh 4137117f1b4Smrg/** 4147117f1b4Smrg * Remove any texture or renderbuffer attached to the given attachment 4157117f1b4Smrg * point. Update reference counts, etc. 4167117f1b4Smrg */ 417af69d88dSmrgstatic void 418af69d88dSmrgremove_attachment(struct gl_context *ctx, 419af69d88dSmrg struct gl_renderbuffer_attachment *att) 4207117f1b4Smrg{ 421af69d88dSmrg struct gl_renderbuffer *rb = att->Renderbuffer; 422af69d88dSmrg 423af69d88dSmrg /* tell driver that we're done rendering to this texture. */ 424af69d88dSmrg if (rb && rb->NeedsFinishRenderTexture) 425af69d88dSmrg ctx->Driver.FinishRenderTexture(ctx, rb); 426af69d88dSmrg 4277117f1b4Smrg if (att->Type == GL_TEXTURE) { 42801e04c3fSmrg assert(att->Texture); 4297117f1b4Smrg _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ 43001e04c3fSmrg assert(!att->Texture); 4317117f1b4Smrg } 4327117f1b4Smrg if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { 43301e04c3fSmrg assert(!att->Texture); 4347117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ 43501e04c3fSmrg assert(!att->Renderbuffer); 4367117f1b4Smrg } 4377117f1b4Smrg att->Type = GL_NONE; 4387117f1b4Smrg att->Complete = GL_TRUE; 4397117f1b4Smrg} 4407117f1b4Smrg 441af69d88dSmrg/** 442af69d88dSmrg * Verify a couple error conditions that will lead to an incomplete FBO and 443af69d88dSmrg * may cause problems for the driver's RenderTexture path. 444af69d88dSmrg */ 445af69d88dSmrgstatic bool 446af69d88dSmrgdriver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att) 447af69d88dSmrg{ 448af69d88dSmrg const struct gl_texture_image *const texImage = 449af69d88dSmrg att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 450af69d88dSmrg 45101e04c3fSmrg if (!texImage || 45201e04c3fSmrg texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0) 453af69d88dSmrg return false; 454af69d88dSmrg 455af69d88dSmrg if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY 456af69d88dSmrg && att->Zoffset >= texImage->Height) 457af69d88dSmrg || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY 458af69d88dSmrg && att->Zoffset >= texImage->Depth)) 459af69d88dSmrg return false; 460af69d88dSmrg 461af69d88dSmrg return true; 462af69d88dSmrg} 463af69d88dSmrg 464af69d88dSmrg/** 465af69d88dSmrg * Create a renderbuffer which will be set up by the driver to wrap the 466af69d88dSmrg * texture image slice. 467af69d88dSmrg * 468af69d88dSmrg * By using a gl_renderbuffer (like user-allocated renderbuffers), drivers get 469af69d88dSmrg * to share most of their framebuffer rendering code between winsys, 470af69d88dSmrg * renderbuffer, and texture attachments. 471af69d88dSmrg * 472af69d88dSmrg * The allocated renderbuffer uses a non-zero Name so that drivers can check 473af69d88dSmrg * it for determining vertical orientation, but we use ~0 to make it fairly 474af69d88dSmrg * unambiguous with actual user (non-texture) renderbuffers. 475af69d88dSmrg */ 476af69d88dSmrgvoid 477af69d88dSmrg_mesa_update_texture_renderbuffer(struct gl_context *ctx, 478af69d88dSmrg struct gl_framebuffer *fb, 479af69d88dSmrg struct gl_renderbuffer_attachment *att) 480af69d88dSmrg{ 481af69d88dSmrg struct gl_texture_image *texImage; 482af69d88dSmrg struct gl_renderbuffer *rb; 483af69d88dSmrg 484af69d88dSmrg texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 485af69d88dSmrg 486af69d88dSmrg rb = att->Renderbuffer; 487af69d88dSmrg if (!rb) { 488af69d88dSmrg rb = ctx->Driver.NewRenderbuffer(ctx, ~0); 489af69d88dSmrg if (!rb) { 490af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); 491af69d88dSmrg return; 492af69d88dSmrg } 49301e04c3fSmrg att->Renderbuffer = rb; 494af69d88dSmrg 495af69d88dSmrg /* This can't get called on a texture renderbuffer, so set it to NULL 496af69d88dSmrg * for clarity compared to user renderbuffers. 497af69d88dSmrg */ 498af69d88dSmrg rb->AllocStorage = NULL; 499af69d88dSmrg 500af69d88dSmrg rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL; 501af69d88dSmrg } 502af69d88dSmrg 503af69d88dSmrg if (!texImage) 504af69d88dSmrg return; 505af69d88dSmrg 506af69d88dSmrg rb->_BaseFormat = texImage->_BaseFormat; 507af69d88dSmrg rb->Format = texImage->TexFormat; 508af69d88dSmrg rb->InternalFormat = texImage->InternalFormat; 509af69d88dSmrg rb->Width = texImage->Width2; 510af69d88dSmrg rb->Height = texImage->Height2; 511af69d88dSmrg rb->Depth = texImage->Depth2; 512af69d88dSmrg rb->NumSamples = texImage->NumSamples; 51301e04c3fSmrg rb->NumStorageSamples = texImage->NumSamples; 514af69d88dSmrg rb->TexImage = texImage; 515af69d88dSmrg 516af69d88dSmrg if (driver_RenderTexture_is_safe(att)) 517af69d88dSmrg ctx->Driver.RenderTexture(ctx, fb, att); 518af69d88dSmrg} 5197117f1b4Smrg 5207117f1b4Smrg/** 5217117f1b4Smrg * Bind a texture object to an attachment point. 5227117f1b4Smrg * The previous binding, if any, will be removed first. 5237117f1b4Smrg */ 524af69d88dSmrgstatic void 525af69d88dSmrgset_texture_attachment(struct gl_context *ctx, 526af69d88dSmrg struct gl_framebuffer *fb, 527af69d88dSmrg struct gl_renderbuffer_attachment *att, 528af69d88dSmrg struct gl_texture_object *texObj, 529a8bb7a65Smaya GLenum texTarget, GLuint level, GLsizei samples, 530a8bb7a65Smaya GLuint layer, GLboolean layered) 5317117f1b4Smrg{ 532af69d88dSmrg struct gl_renderbuffer *rb = att->Renderbuffer; 533af69d88dSmrg 534af69d88dSmrg if (rb && rb->NeedsFinishRenderTexture) 535af69d88dSmrg ctx->Driver.FinishRenderTexture(ctx, rb); 536af69d88dSmrg 5377117f1b4Smrg if (att->Texture == texObj) { 5387117f1b4Smrg /* re-attaching same texture */ 53901e04c3fSmrg assert(att->Type == GL_TEXTURE); 5407117f1b4Smrg } 5417117f1b4Smrg else { 5427117f1b4Smrg /* new attachment */ 543af69d88dSmrg remove_attachment(ctx, att); 5447117f1b4Smrg att->Type = GL_TEXTURE; 5457117f1b4Smrg assert(!att->Texture); 5467117f1b4Smrg _mesa_reference_texobj(&att->Texture, texObj); 5477117f1b4Smrg } 548af69d88dSmrg invalidate_framebuffer(fb); 5497117f1b4Smrg 5507117f1b4Smrg /* always update these fields */ 5517117f1b4Smrg att->TextureLevel = level; 552a8bb7a65Smaya att->NumSamples = samples; 5534a49301eSmrg att->CubeMapFace = _mesa_tex_target_to_face(texTarget); 55401e04c3fSmrg att->Zoffset = layer; 555af69d88dSmrg att->Layered = layered; 5567117f1b4Smrg att->Complete = GL_FALSE; 5577117f1b4Smrg 558af69d88dSmrg _mesa_update_texture_renderbuffer(ctx, fb, att); 5597117f1b4Smrg} 5607117f1b4Smrg 5617117f1b4Smrg 5627117f1b4Smrg/** 5637117f1b4Smrg * Bind a renderbuffer to an attachment point. 5647117f1b4Smrg * The previous binding, if any, will be removed first. 5657117f1b4Smrg */ 566af69d88dSmrgstatic void 567af69d88dSmrgset_renderbuffer_attachment(struct gl_context *ctx, 568af69d88dSmrg struct gl_renderbuffer_attachment *att, 569af69d88dSmrg struct gl_renderbuffer *rb) 5707117f1b4Smrg{ 5717117f1b4Smrg /* XXX check if re-doing same attachment, exit early */ 572af69d88dSmrg remove_attachment(ctx, att); 5737117f1b4Smrg att->Type = GL_RENDERBUFFER_EXT; 5747117f1b4Smrg att->Texture = NULL; /* just to be safe */ 57501e04c3fSmrg att->Layered = GL_FALSE; 5767117f1b4Smrg att->Complete = GL_FALSE; 5777117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 5787117f1b4Smrg} 5797117f1b4Smrg 5807117f1b4Smrg 5817117f1b4Smrg/** 5827117f1b4Smrg * Fallback for ctx->Driver.FramebufferRenderbuffer() 5837117f1b4Smrg * Attach a renderbuffer object to a framebuffer object. 5847117f1b4Smrg */ 5857117f1b4Smrgvoid 58601e04c3fSmrg_mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx, 58701e04c3fSmrg struct gl_framebuffer *fb, 58801e04c3fSmrg GLenum attachment, 58901e04c3fSmrg struct gl_renderbuffer *rb) 5907117f1b4Smrg{ 5917117f1b4Smrg struct gl_renderbuffer_attachment *att; 5927117f1b4Smrg 59301e04c3fSmrg simple_mtx_lock(&fb->Mutex); 5947117f1b4Smrg 59501e04c3fSmrg att = get_attachment(ctx, fb, attachment, NULL); 59601e04c3fSmrg assert(att); 5977117f1b4Smrg if (rb) { 598af69d88dSmrg set_renderbuffer_attachment(ctx, att, rb); 5994a49301eSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 6004a49301eSmrg /* do stencil attachment here (depth already done above) */ 60101e04c3fSmrg att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL); 6024a49301eSmrg assert(att); 603af69d88dSmrg set_renderbuffer_attachment(ctx, att, rb); 6044a49301eSmrg } 6053464ebd5Sriastradh rb->AttachedAnytime = GL_TRUE; 6067117f1b4Smrg } 6077117f1b4Smrg else { 608af69d88dSmrg remove_attachment(ctx, att); 609af69d88dSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 610af69d88dSmrg /* detach stencil (depth was detached above) */ 61101e04c3fSmrg att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL); 612af69d88dSmrg assert(att); 613af69d88dSmrg remove_attachment(ctx, att); 614af69d88dSmrg } 6157117f1b4Smrg } 6167117f1b4Smrg 6174a49301eSmrg invalidate_framebuffer(fb); 6184a49301eSmrg 61901e04c3fSmrg simple_mtx_unlock(&fb->Mutex); 6207117f1b4Smrg} 6217117f1b4Smrg 6227117f1b4Smrg 6233464ebd5Sriastradh/** 6243464ebd5Sriastradh * Fallback for ctx->Driver.ValidateFramebuffer() 6253464ebd5Sriastradh * Check if the renderbuffer's formats are supported by the software 6263464ebd5Sriastradh * renderer. 6273464ebd5Sriastradh * Drivers should probably override this. 6283464ebd5Sriastradh */ 6293464ebd5Sriastradhvoid 6303464ebd5Sriastradh_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) 6313464ebd5Sriastradh{ 6323464ebd5Sriastradh gl_buffer_index buf; 6333464ebd5Sriastradh for (buf = 0; buf < BUFFER_COUNT; buf++) { 6343464ebd5Sriastradh const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer; 6353464ebd5Sriastradh if (rb) { 6363464ebd5Sriastradh switch (rb->_BaseFormat) { 6373464ebd5Sriastradh case GL_ALPHA: 6383464ebd5Sriastradh case GL_LUMINANCE_ALPHA: 6393464ebd5Sriastradh case GL_LUMINANCE: 6403464ebd5Sriastradh case GL_INTENSITY: 6413464ebd5Sriastradh case GL_RED: 6423464ebd5Sriastradh case GL_RG: 6433464ebd5Sriastradh fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 6443464ebd5Sriastradh return; 6453464ebd5Sriastradh 6463464ebd5Sriastradh default: 6473464ebd5Sriastradh switch (rb->Format) { 6483464ebd5Sriastradh /* XXX This list is likely incomplete. */ 649af69d88dSmrg case MESA_FORMAT_R9G9B9E5_FLOAT: 6503464ebd5Sriastradh fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 6513464ebd5Sriastradh return; 6523464ebd5Sriastradh default:; 6533464ebd5Sriastradh /* render buffer format is supported by software rendering */ 6543464ebd5Sriastradh } 6553464ebd5Sriastradh } 6563464ebd5Sriastradh } 6573464ebd5Sriastradh } 6583464ebd5Sriastradh} 6593464ebd5Sriastradh 6603464ebd5Sriastradh 661af69d88dSmrg/** 662af69d88dSmrg * Return true if the framebuffer has a combined depth/stencil 663af69d88dSmrg * renderbuffer attached. 664af69d88dSmrg */ 665af69d88dSmrgGLboolean 666af69d88dSmrg_mesa_has_depthstencil_combined(const struct gl_framebuffer *fb) 667af69d88dSmrg{ 668af69d88dSmrg const struct gl_renderbuffer_attachment *depth = 669af69d88dSmrg &fb->Attachment[BUFFER_DEPTH]; 670af69d88dSmrg const struct gl_renderbuffer_attachment *stencil = 671af69d88dSmrg &fb->Attachment[BUFFER_STENCIL]; 672af69d88dSmrg 673af69d88dSmrg if (depth->Type == stencil->Type) { 674af69d88dSmrg if (depth->Type == GL_RENDERBUFFER_EXT && 675af69d88dSmrg depth->Renderbuffer == stencil->Renderbuffer) 676af69d88dSmrg return GL_TRUE; 677af69d88dSmrg 678af69d88dSmrg if (depth->Type == GL_TEXTURE && 679af69d88dSmrg depth->Texture == stencil->Texture) 680af69d88dSmrg return GL_TRUE; 681af69d88dSmrg } 682af69d88dSmrg 683af69d88dSmrg return GL_FALSE; 684af69d88dSmrg} 685af69d88dSmrg 686af69d88dSmrg 6874a49301eSmrg/** 6884a49301eSmrg * For debug only. 6894a49301eSmrg */ 6904a49301eSmrgstatic void 6914a49301eSmrgatt_incomplete(const char *msg) 6924a49301eSmrg{ 693af69d88dSmrg if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { 694af69d88dSmrg _mesa_debug(NULL, "attachment incomplete: %s\n", msg); 695af69d88dSmrg } 6964a49301eSmrg} 6974a49301eSmrg 6984a49301eSmrg 6994a49301eSmrg/** 7004a49301eSmrg * For debug only. 7014a49301eSmrg */ 7024a49301eSmrgstatic void 703af69d88dSmrgfbo_incomplete(struct gl_context *ctx, const char *msg, int index) 7044a49301eSmrg{ 705af69d88dSmrg static GLuint msg_id; 706af69d88dSmrg 707a8bb7a65Smaya _mesa_gl_debugf(ctx, &msg_id, 708a8bb7a65Smaya MESA_DEBUG_SOURCE_API, 709a8bb7a65Smaya MESA_DEBUG_TYPE_OTHER, 710a8bb7a65Smaya MESA_DEBUG_SEVERITY_MEDIUM, 711a8bb7a65Smaya "FBO incomplete: %s [%d]\n", msg, index); 712af69d88dSmrg 713af69d88dSmrg if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { 714af69d88dSmrg _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); 715af69d88dSmrg } 7167ec681f3Smrg 7177ec681f3Smrg _mesa_update_valid_to_render_state(ctx); 7184a49301eSmrg} 7194a49301eSmrg 7204a49301eSmrg 7213464ebd5Sriastradh/** 7223464ebd5Sriastradh * Is the given base format a legal format for a color renderbuffer? 7233464ebd5Sriastradh */ 7243464ebd5SriastradhGLboolean 7253464ebd5Sriastradh_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) 7263464ebd5Sriastradh{ 7273464ebd5Sriastradh switch (baseFormat) { 7283464ebd5Sriastradh case GL_RGB: 7293464ebd5Sriastradh case GL_RGBA: 7303464ebd5Sriastradh return GL_TRUE; 7313464ebd5Sriastradh case GL_LUMINANCE: 7323464ebd5Sriastradh case GL_LUMINANCE_ALPHA: 7333464ebd5Sriastradh case GL_INTENSITY: 7343464ebd5Sriastradh case GL_ALPHA: 735af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 736af69d88dSmrg ctx->Extensions.ARB_framebuffer_object; 7373464ebd5Sriastradh case GL_RED: 7383464ebd5Sriastradh case GL_RG: 7393464ebd5Sriastradh return ctx->Extensions.ARB_texture_rg; 7403464ebd5Sriastradh default: 7413464ebd5Sriastradh return GL_FALSE; 7423464ebd5Sriastradh } 7433464ebd5Sriastradh} 7443464ebd5Sriastradh 7457ec681f3Smrgstatic GLboolean 7467ec681f3Smrgis_float_format(GLenum internalFormat) 7477ec681f3Smrg{ 7487ec681f3Smrg switch (internalFormat) { 7497ec681f3Smrg case GL_R16F: 7507ec681f3Smrg case GL_RG16F: 7517ec681f3Smrg case GL_RGB16F: 7527ec681f3Smrg case GL_RGBA16F: 7537ec681f3Smrg case GL_R32F: 7547ec681f3Smrg case GL_RG32F: 7557ec681f3Smrg case GL_RGB32F: 7567ec681f3Smrg case GL_RGBA32F: 7577ec681f3Smrg return true; 7587ec681f3Smrg default: 7597ec681f3Smrg return false; 7607ec681f3Smrg } 7617ec681f3Smrg} 7623464ebd5Sriastradh 763af69d88dSmrg/** 764af69d88dSmrg * Is the given base format a legal format for a color renderbuffer? 765af69d88dSmrg */ 766af69d88dSmrgstatic GLboolean 767af69d88dSmrgis_format_color_renderable(const struct gl_context *ctx, mesa_format format, 768af69d88dSmrg GLenum internalFormat) 769af69d88dSmrg{ 770af69d88dSmrg const GLenum baseFormat = 771af69d88dSmrg _mesa_get_format_base_format(format); 772af69d88dSmrg GLboolean valid; 773af69d88dSmrg 774af69d88dSmrg valid = _mesa_is_legal_color_format(ctx, baseFormat); 775af69d88dSmrg if (!valid || _mesa_is_desktop_gl(ctx)) { 776af69d88dSmrg return valid; 777af69d88dSmrg } 778af69d88dSmrg 779af69d88dSmrg /* Reject additional cases for GLES */ 780af69d88dSmrg switch (internalFormat) { 78101e04c3fSmrg case GL_R8_SNORM: 78201e04c3fSmrg case GL_RG8_SNORM: 783af69d88dSmrg case GL_RGBA8_SNORM: 78401e04c3fSmrg return _mesa_has_EXT_render_snorm(ctx); 78501e04c3fSmrg case GL_R16_SNORM: 78601e04c3fSmrg case GL_RG16_SNORM: 78701e04c3fSmrg case GL_RGBA16_SNORM: 78801e04c3fSmrg return _mesa_has_EXT_texture_norm16(ctx) && 78901e04c3fSmrg _mesa_has_EXT_render_snorm(ctx); 7907ec681f3Smrg case GL_R: 7917ec681f3Smrg case GL_RG: 7927ec681f3Smrg return _mesa_has_EXT_texture_rg(ctx); 7937ec681f3Smrg case GL_R16F: 7947ec681f3Smrg case GL_RG16F: 7957ec681f3Smrg return _mesa_is_gles3(ctx) || 7967ec681f3Smrg (_mesa_has_EXT_color_buffer_half_float(ctx) && 7977ec681f3Smrg _mesa_has_EXT_texture_rg(ctx)); 7987ec681f3Smrg case GL_RGBA16F: 7997ec681f3Smrg return _mesa_is_gles3(ctx) || 8007ec681f3Smrg _mesa_has_EXT_color_buffer_half_float(ctx); 8017ec681f3Smrg case GL_RGBA32F: 8027ec681f3Smrg return _mesa_has_EXT_color_buffer_float(ctx); 8037ec681f3Smrg case GL_RGB16F: 8047ec681f3Smrg return _mesa_has_EXT_color_buffer_half_float(ctx); 8057ec681f3Smrg case GL_RGB10_A2: 8067ec681f3Smrg return _mesa_is_gles3(ctx); 807af69d88dSmrg case GL_RGB32F: 808af69d88dSmrg case GL_RGB32I: 809af69d88dSmrg case GL_RGB32UI: 810af69d88dSmrg case GL_RGB16I: 811af69d88dSmrg case GL_RGB16UI: 812af69d88dSmrg case GL_RGB8_SNORM: 813af69d88dSmrg case GL_RGB8I: 814af69d88dSmrg case GL_RGB8UI: 815af69d88dSmrg case GL_SRGB8: 81601e04c3fSmrg case GL_RGB10: 817af69d88dSmrg case GL_RGB9_E5: 818a8bb7a65Smaya case GL_SR8_EXT: 8197ec681f3Smrg case GL_SRG8_EXT: 820af69d88dSmrg return GL_FALSE; 821af69d88dSmrg default: 822af69d88dSmrg break; 823af69d88dSmrg } 824af69d88dSmrg 82501e04c3fSmrg if (internalFormat != GL_RGB10_A2 && 82601e04c3fSmrg (format == MESA_FORMAT_B10G10R10A2_UNORM || 82701e04c3fSmrg format == MESA_FORMAT_B10G10R10X2_UNORM || 82801e04c3fSmrg format == MESA_FORMAT_R10G10B10A2_UNORM || 82901e04c3fSmrg format == MESA_FORMAT_R10G10B10X2_UNORM)) { 830af69d88dSmrg return GL_FALSE; 831af69d88dSmrg } 832af69d88dSmrg 833af69d88dSmrg return GL_TRUE; 834af69d88dSmrg} 835af69d88dSmrg 8367ec681f3Smrg/** 8377ec681f3Smrg * Check that implements various limitations of floating point 8387ec681f3Smrg * rendering extensions on OpenGL ES. 8397ec681f3Smrg * 8407ec681f3Smrg * Check passes if texture format is not floating point or 8417ec681f3Smrg * is floating point and is color renderable. 8427ec681f3Smrg * 8437ec681f3Smrg * Check fails if texture format is floating point and cannot 8447ec681f3Smrg * be rendered to with current context and set of supported 8457ec681f3Smrg * extensions. 8467ec681f3Smrg */ 8477ec681f3Smrgstatic GLboolean 8487ec681f3Smrggles_check_float_renderable(const struct gl_context *ctx, 8497ec681f3Smrg struct gl_renderbuffer_attachment *att) 8507ec681f3Smrg{ 8517ec681f3Smrg /* Only check floating point texture cases. */ 8527ec681f3Smrg if (!att->Texture || !is_float_format(att->Renderbuffer->InternalFormat)) 8537ec681f3Smrg return true; 8547ec681f3Smrg 8557ec681f3Smrg /* GL_RGBA with unsized GL_FLOAT type, no extension can make this 8567ec681f3Smrg * color renderable. 8577ec681f3Smrg */ 8587ec681f3Smrg if (att->Texture->_IsFloat && att->Renderbuffer->_BaseFormat == GL_RGBA) 8597ec681f3Smrg return false; 8607ec681f3Smrg 8617ec681f3Smrg /* Unsized GL_HALF_FLOAT supported only with EXT_color_buffer_half_float. */ 8627ec681f3Smrg if (att->Texture->_IsHalfFloat && !_mesa_has_EXT_color_buffer_half_float(ctx)) 8637ec681f3Smrg return false; 8647ec681f3Smrg 8657ec681f3Smrg const struct gl_texture_object *texObj = att->Texture; 8667ec681f3Smrg const struct gl_texture_image *texImage = 8677ec681f3Smrg texObj->Image[att->CubeMapFace][att->TextureLevel]; 8687ec681f3Smrg 8697ec681f3Smrg return is_format_color_renderable(ctx, texImage->TexFormat, 8707ec681f3Smrg att->Renderbuffer->InternalFormat); 8717ec681f3Smrg} 872af69d88dSmrg 8733464ebd5Sriastradh/** 8743464ebd5Sriastradh * Is the given base format a legal format for a depth/stencil renderbuffer? 8753464ebd5Sriastradh */ 8763464ebd5Sriastradhstatic GLboolean 8773464ebd5Sriastradhis_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat) 8783464ebd5Sriastradh{ 8793464ebd5Sriastradh switch (baseFormat) { 8803464ebd5Sriastradh case GL_DEPTH_COMPONENT: 8813464ebd5Sriastradh case GL_DEPTH_STENCIL_EXT: 8823464ebd5Sriastradh return GL_TRUE; 8833464ebd5Sriastradh default: 8843464ebd5Sriastradh return GL_FALSE; 8853464ebd5Sriastradh } 8863464ebd5Sriastradh} 8874a49301eSmrg 8884a49301eSmrg 8897117f1b4Smrg/** 8907117f1b4Smrg * Test if an attachment point is complete and update its Complete field. 8917117f1b4Smrg * \param format if GL_COLOR, this is a color attachment point, 8927117f1b4Smrg * if GL_DEPTH, this is a depth component attachment point, 8937117f1b4Smrg * if GL_STENCIL, this is a stencil component attachment point. 8947117f1b4Smrg */ 8957117f1b4Smrgstatic void 8963464ebd5Sriastradhtest_attachment_completeness(const struct gl_context *ctx, GLenum format, 8977117f1b4Smrg struct gl_renderbuffer_attachment *att) 8987117f1b4Smrg{ 8997117f1b4Smrg assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); 9007117f1b4Smrg 9017117f1b4Smrg /* assume complete */ 9027117f1b4Smrg att->Complete = GL_TRUE; 9037117f1b4Smrg 9047117f1b4Smrg /* Look for reasons why the attachment might be incomplete */ 9057117f1b4Smrg if (att->Type == GL_TEXTURE) { 9067117f1b4Smrg const struct gl_texture_object *texObj = att->Texture; 90701e04c3fSmrg const struct gl_texture_image *texImage; 9084a49301eSmrg GLenum baseFormat; 9097117f1b4Smrg 9107117f1b4Smrg if (!texObj) { 9114a49301eSmrg att_incomplete("no texobj"); 9127117f1b4Smrg att->Complete = GL_FALSE; 9137117f1b4Smrg return; 9147117f1b4Smrg } 9157117f1b4Smrg 9167117f1b4Smrg texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; 9177117f1b4Smrg if (!texImage) { 9184a49301eSmrg att_incomplete("no teximage"); 9197117f1b4Smrg att->Complete = GL_FALSE; 9207117f1b4Smrg return; 9217117f1b4Smrg } 9227ec681f3Smrg 9237ec681f3Smrg /* Mutable non base level texture as framebuffer attachment 9247ec681f3Smrg * must be mipmap complete. 9257ec681f3Smrg */ 9267ec681f3Smrg if (texImage->Level > texObj->Attrib.BaseLevel && 9277ec681f3Smrg !texObj->_MipmapComplete) { 9287ec681f3Smrg /* Test if texture has become mipmap complete meanwhile. */ 9297ec681f3Smrg _mesa_test_texobj_completeness(ctx, att->Texture); 9307ec681f3Smrg if (!texObj->_MipmapComplete) { 9317ec681f3Smrg att_incomplete("texture attachment not mipmap complete"); 9327ec681f3Smrg att->Complete = GL_FALSE; 9337ec681f3Smrg return; 9347ec681f3Smrg } 9357ec681f3Smrg } 9367ec681f3Smrg 9377117f1b4Smrg if (texImage->Width < 1 || texImage->Height < 1) { 9384a49301eSmrg att_incomplete("teximage width/height=0"); 9397117f1b4Smrg att->Complete = GL_FALSE; 9407117f1b4Smrg return; 9417117f1b4Smrg } 942af69d88dSmrg 943af69d88dSmrg switch (texObj->Target) { 944af69d88dSmrg case GL_TEXTURE_3D: 945af69d88dSmrg if (att->Zoffset >= texImage->Depth) { 946af69d88dSmrg att_incomplete("bad z offset"); 947af69d88dSmrg att->Complete = GL_FALSE; 948af69d88dSmrg return; 949af69d88dSmrg } 950af69d88dSmrg break; 951af69d88dSmrg case GL_TEXTURE_1D_ARRAY: 952af69d88dSmrg if (att->Zoffset >= texImage->Height) { 953af69d88dSmrg att_incomplete("bad 1D-array layer"); 954af69d88dSmrg att->Complete = GL_FALSE; 955af69d88dSmrg return; 956af69d88dSmrg } 957af69d88dSmrg break; 958af69d88dSmrg case GL_TEXTURE_2D_ARRAY: 959af69d88dSmrg if (att->Zoffset >= texImage->Depth) { 960af69d88dSmrg att_incomplete("bad 2D-array layer"); 961af69d88dSmrg att->Complete = GL_FALSE; 962af69d88dSmrg return; 963af69d88dSmrg } 964af69d88dSmrg break; 965af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 966af69d88dSmrg if (att->Zoffset >= texImage->Depth) { 967af69d88dSmrg att_incomplete("bad cube-array layer"); 968af69d88dSmrg att->Complete = GL_FALSE; 969af69d88dSmrg return; 970af69d88dSmrg } 971af69d88dSmrg break; 9727117f1b4Smrg } 9737117f1b4Smrg 97401e04c3fSmrg baseFormat = texImage->_BaseFormat; 9754a49301eSmrg 9767117f1b4Smrg if (format == GL_COLOR) { 9773464ebd5Sriastradh if (!_mesa_is_legal_color_format(ctx, baseFormat)) { 9784a49301eSmrg att_incomplete("bad format"); 9794a49301eSmrg att->Complete = GL_FALSE; 9804a49301eSmrg return; 9814a49301eSmrg } 9824a49301eSmrg if (_mesa_is_format_compressed(texImage->TexFormat)) { 9834a49301eSmrg att_incomplete("compressed internalformat"); 9847117f1b4Smrg att->Complete = GL_FALSE; 9857117f1b4Smrg return; 9867117f1b4Smrg } 98701e04c3fSmrg 98801e04c3fSmrg /* OES_texture_float allows creation and use of floating point 98901e04c3fSmrg * textures with GL_FLOAT, GL_HALF_FLOAT but it does not allow 99001e04c3fSmrg * these textures to be used as a render target, this is done via 99101e04c3fSmrg * GL_EXT_color_buffer(_half)_float with set of new sized types. 99201e04c3fSmrg */ 9937ec681f3Smrg if (_mesa_is_gles(ctx) && !gles_check_float_renderable(ctx, att)) { 99401e04c3fSmrg att_incomplete("bad internal format"); 99501e04c3fSmrg att->Complete = GL_FALSE; 99601e04c3fSmrg return; 99701e04c3fSmrg } 9987117f1b4Smrg } 9997117f1b4Smrg else if (format == GL_DEPTH) { 10004a49301eSmrg if (baseFormat == GL_DEPTH_COMPONENT) { 10017117f1b4Smrg /* OK */ 10027117f1b4Smrg } 1003af69d88dSmrg else if (ctx->Extensions.ARB_depth_texture && 1004af69d88dSmrg baseFormat == GL_DEPTH_STENCIL) { 10057117f1b4Smrg /* OK */ 10067117f1b4Smrg } 10077117f1b4Smrg else { 10087117f1b4Smrg att->Complete = GL_FALSE; 10094a49301eSmrg att_incomplete("bad depth format"); 10107117f1b4Smrg return; 10117117f1b4Smrg } 10127117f1b4Smrg } 10137117f1b4Smrg else { 101401e04c3fSmrg assert(format == GL_STENCIL); 1015af69d88dSmrg if (ctx->Extensions.ARB_depth_texture && 1016af69d88dSmrg baseFormat == GL_DEPTH_STENCIL) { 1017c7037ccdSmrg /* OK */ 101801e04c3fSmrg } else if (ctx->Extensions.ARB_texture_stencil8 && 101901e04c3fSmrg baseFormat == GL_STENCIL_INDEX) { 102001e04c3fSmrg /* OK */ 102101e04c3fSmrg } else { 1022c7037ccdSmrg /* no such thing as stencil-only textures */ 10234a49301eSmrg att_incomplete("illegal stencil texture"); 1024c7037ccdSmrg att->Complete = GL_FALSE; 1025c7037ccdSmrg return; 1026c7037ccdSmrg } 10277117f1b4Smrg } 10287117f1b4Smrg } 10297117f1b4Smrg else if (att->Type == GL_RENDERBUFFER_EXT) { 103001e04c3fSmrg const GLenum baseFormat = att->Renderbuffer->_BaseFormat; 10314a49301eSmrg 103201e04c3fSmrg assert(att->Renderbuffer); 10337117f1b4Smrg if (!att->Renderbuffer->InternalFormat || 10347117f1b4Smrg att->Renderbuffer->Width < 1 || 10357117f1b4Smrg att->Renderbuffer->Height < 1) { 10364a49301eSmrg att_incomplete("0x0 renderbuffer"); 10377117f1b4Smrg att->Complete = GL_FALSE; 10387117f1b4Smrg return; 10397117f1b4Smrg } 10407117f1b4Smrg if (format == GL_COLOR) { 10413464ebd5Sriastradh if (!_mesa_is_legal_color_format(ctx, baseFormat)) { 10424a49301eSmrg att_incomplete("bad renderbuffer color format"); 10437117f1b4Smrg att->Complete = GL_FALSE; 10447117f1b4Smrg return; 10457117f1b4Smrg } 10467117f1b4Smrg } 10477117f1b4Smrg else if (format == GL_DEPTH) { 10484a49301eSmrg if (baseFormat == GL_DEPTH_COMPONENT) { 10497117f1b4Smrg /* OK */ 10507117f1b4Smrg } 1051af69d88dSmrg else if (baseFormat == GL_DEPTH_STENCIL) { 10527117f1b4Smrg /* OK */ 10537117f1b4Smrg } 10547117f1b4Smrg else { 10554a49301eSmrg att_incomplete("bad renderbuffer depth format"); 10567117f1b4Smrg att->Complete = GL_FALSE; 10577117f1b4Smrg return; 10587117f1b4Smrg } 10597117f1b4Smrg } 10607117f1b4Smrg else { 10617117f1b4Smrg assert(format == GL_STENCIL); 1062af69d88dSmrg if (baseFormat == GL_STENCIL_INDEX || 1063af69d88dSmrg baseFormat == GL_DEPTH_STENCIL) { 10647117f1b4Smrg /* OK */ 10657117f1b4Smrg } 10667117f1b4Smrg else { 10677117f1b4Smrg att->Complete = GL_FALSE; 10684a49301eSmrg att_incomplete("bad renderbuffer stencil format"); 10697117f1b4Smrg return; 10707117f1b4Smrg } 10717117f1b4Smrg } 10727117f1b4Smrg } 10737117f1b4Smrg else { 107401e04c3fSmrg assert(att->Type == GL_NONE); 10757117f1b4Smrg /* complete */ 10767117f1b4Smrg return; 10777117f1b4Smrg } 10787117f1b4Smrg} 10797117f1b4Smrg 10807117f1b4Smrg 10817117f1b4Smrg/** 10827117f1b4Smrg * Test if the given framebuffer object is complete and update its 10837117f1b4Smrg * Status field with the results. 10844a49301eSmrg * Calls the ctx->Driver.ValidateFramebuffer() function to allow the 10854a49301eSmrg * driver to make hardware-specific validation/completeness checks. 10867117f1b4Smrg * Also update the framebuffer's Width and Height fields if the 10877117f1b4Smrg * framebuffer is complete. 10887117f1b4Smrg */ 10897117f1b4Smrgvoid 10903464ebd5Sriastradh_mesa_test_framebuffer_completeness(struct gl_context *ctx, 10913464ebd5Sriastradh struct gl_framebuffer *fb) 10927117f1b4Smrg{ 10934a49301eSmrg GLuint numImages; 10944a49301eSmrg GLenum intFormat = GL_NONE; /* color buffers' internal format */ 10954a49301eSmrg GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; 109601e04c3fSmrg GLint numColorSamples = -1; 109701e04c3fSmrg GLint numColorStorageSamples = -1; 109801e04c3fSmrg GLint numDepthSamples = -1; 1099af69d88dSmrg GLint fixedSampleLocations = -1; 11007117f1b4Smrg GLint i; 11017117f1b4Smrg GLuint j; 1102af69d88dSmrg /* Covers max_layer_count, is_layered, and layer_tex_target */ 1103af69d88dSmrg bool layer_info_valid = false; 1104af69d88dSmrg GLuint max_layer_count = 0, att_layer_count; 1105af69d88dSmrg bool is_layered = false; 1106af69d88dSmrg GLenum layer_tex_target = 0; 110701e04c3fSmrg bool has_depth_attachment = false; 110801e04c3fSmrg bool has_stencil_attachment = false; 1109af69d88dSmrg 1110af69d88dSmrg assert(_mesa_is_user_fbo(fb)); 11117117f1b4Smrg 1112af69d88dSmrg /* we're changing framebuffer fields here */ 11137ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0); 11147117f1b4Smrg 11157117f1b4Smrg numImages = 0; 11167117f1b4Smrg fb->Width = 0; 11177117f1b4Smrg fb->Height = 0; 1118af69d88dSmrg fb->_AllColorBuffersFixedPoint = GL_TRUE; 1119af69d88dSmrg fb->_HasSNormOrFloatColorBuffer = GL_FALSE; 112001e04c3fSmrg fb->_HasAttachments = true; 112101e04c3fSmrg fb->_IntegerBuffers = 0; 1122a8bb7a65Smaya fb->_RGBBuffers = 0; 1123a8bb7a65Smaya fb->_FP32Buffers = 0; 11247117f1b4Smrg 11254a49301eSmrg /* Start at -2 to more easily loop over all attachment points. 11264a49301eSmrg * -2: depth buffer 11274a49301eSmrg * -1: stencil buffer 11284a49301eSmrg * >=0: color buffer 11294a49301eSmrg */ 11307117f1b4Smrg for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { 11317117f1b4Smrg struct gl_renderbuffer_attachment *att; 11327117f1b4Smrg GLenum f; 1133a8bb7a65Smaya GLenum baseFormat; 1134af69d88dSmrg mesa_format attFormat; 1135af69d88dSmrg GLenum att_tex_target = GL_NONE; 11367117f1b4Smrg 11374a49301eSmrg /* 11384a49301eSmrg * XXX for ARB_fbo, only check color buffers that are named by 11394a49301eSmrg * GL_READ_BUFFER and GL_DRAW_BUFFERi. 11404a49301eSmrg */ 11414a49301eSmrg 11424a49301eSmrg /* check for attachment completeness 11434a49301eSmrg */ 11447117f1b4Smrg if (i == -2) { 11457117f1b4Smrg att = &fb->Attachment[BUFFER_DEPTH]; 11467117f1b4Smrg test_attachment_completeness(ctx, GL_DEPTH, att); 11477117f1b4Smrg if (!att->Complete) { 11487117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 1149af69d88dSmrg fbo_incomplete(ctx, "depth attachment incomplete", -1); 11507117f1b4Smrg return; 115101e04c3fSmrg } else if (att->Type != GL_NONE) { 115201e04c3fSmrg has_depth_attachment = true; 11537117f1b4Smrg } 11547117f1b4Smrg } 11557117f1b4Smrg else if (i == -1) { 11567117f1b4Smrg att = &fb->Attachment[BUFFER_STENCIL]; 11577117f1b4Smrg test_attachment_completeness(ctx, GL_STENCIL, att); 11587117f1b4Smrg if (!att->Complete) { 11597117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 1160af69d88dSmrg fbo_incomplete(ctx, "stencil attachment incomplete", -1); 11617117f1b4Smrg return; 116201e04c3fSmrg } else if (att->Type != GL_NONE) { 116301e04c3fSmrg has_stencil_attachment = true; 11647117f1b4Smrg } 11657117f1b4Smrg } 11667117f1b4Smrg else { 11677117f1b4Smrg att = &fb->Attachment[BUFFER_COLOR0 + i]; 11687117f1b4Smrg test_attachment_completeness(ctx, GL_COLOR, att); 11697117f1b4Smrg if (!att->Complete) { 11707ec681f3Smrg /* With EXT_color_buffer_half_float, check if attachment was incomplete 11717ec681f3Smrg * due to invalid format. This is special case for the extension where 11727ec681f3Smrg * CTS tests expect unsupported framebuffer status instead of incomplete. 11737ec681f3Smrg */ 11747ec681f3Smrg if ((_mesa_is_gles(ctx) && _mesa_has_EXT_color_buffer_half_float(ctx)) && 11757ec681f3Smrg !gles_check_float_renderable(ctx, att)) { 11767ec681f3Smrg fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 11777ec681f3Smrg return; 11787ec681f3Smrg } 11797ec681f3Smrg 11807117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 1181af69d88dSmrg fbo_incomplete(ctx, "color attachment incomplete", i); 11827117f1b4Smrg return; 11837117f1b4Smrg } 11847117f1b4Smrg } 11857117f1b4Smrg 11864a49301eSmrg /* get width, height, format of the renderbuffer/texture 11874a49301eSmrg */ 118801e04c3fSmrg unsigned attNumSamples, attNumStorageSamples; 118901e04c3fSmrg 11907117f1b4Smrg if (att->Type == GL_TEXTURE) { 1191af69d88dSmrg const struct gl_texture_image *texImg = att->Renderbuffer->TexImage; 1192af69d88dSmrg att_tex_target = att->Texture->Target; 11934a49301eSmrg minWidth = MIN2(minWidth, texImg->Width); 11944a49301eSmrg maxWidth = MAX2(maxWidth, texImg->Width); 11954a49301eSmrg minHeight = MIN2(minHeight, texImg->Height); 11964a49301eSmrg maxHeight = MAX2(maxHeight, texImg->Height); 11977117f1b4Smrg f = texImg->_BaseFormat; 1198a8bb7a65Smaya baseFormat = f; 11993464ebd5Sriastradh attFormat = texImg->TexFormat; 12007117f1b4Smrg numImages++; 1201af69d88dSmrg 1202af69d88dSmrg if (!is_format_color_renderable(ctx, attFormat, 1203af69d88dSmrg texImg->InternalFormat) && 120401e04c3fSmrg !is_legal_depth_format(ctx, f) && 120501e04c3fSmrg f != GL_STENCIL_INDEX) { 120601e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 1207af69d88dSmrg fbo_incomplete(ctx, "texture attachment incomplete", -1); 1208af69d88dSmrg return; 1209af69d88dSmrg } 1210af69d88dSmrg 1211af69d88dSmrg if (fixedSampleLocations < 0) 1212af69d88dSmrg fixedSampleLocations = texImg->FixedSampleLocations; 1213af69d88dSmrg else if (fixedSampleLocations != texImg->FixedSampleLocations) { 1214af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 1215af69d88dSmrg fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); 12167117f1b4Smrg return; 12177117f1b4Smrg } 121801e04c3fSmrg 1219a8bb7a65Smaya if (att->NumSamples > 0) 1220a8bb7a65Smaya attNumSamples = att->NumSamples; 1221a8bb7a65Smaya else 1222a8bb7a65Smaya attNumSamples = texImg->NumSamples; 1223a8bb7a65Smaya attNumStorageSamples = attNumSamples; 12247117f1b4Smrg } 12257117f1b4Smrg else if (att->Type == GL_RENDERBUFFER_EXT) { 12264a49301eSmrg minWidth = MIN2(minWidth, att->Renderbuffer->Width); 12277ec681f3Smrg maxWidth = MAX2(maxWidth, att->Renderbuffer->Width); 12284a49301eSmrg minHeight = MIN2(minHeight, att->Renderbuffer->Height); 12297ec681f3Smrg maxHeight = MAX2(maxHeight, att->Renderbuffer->Height); 12307117f1b4Smrg f = att->Renderbuffer->InternalFormat; 1231a8bb7a65Smaya baseFormat = att->Renderbuffer->_BaseFormat; 12323464ebd5Sriastradh attFormat = att->Renderbuffer->Format; 12337117f1b4Smrg numImages++; 1234af69d88dSmrg 1235af69d88dSmrg /* RENDERBUFFER has fixedSampleLocations implicitly true */ 1236af69d88dSmrg if (fixedSampleLocations < 0) 1237af69d88dSmrg fixedSampleLocations = GL_TRUE; 1238af69d88dSmrg else if (fixedSampleLocations != GL_TRUE) { 1239af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 1240af69d88dSmrg fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); 1241af69d88dSmrg return; 1242af69d88dSmrg } 124301e04c3fSmrg 124401e04c3fSmrg attNumSamples = att->Renderbuffer->NumSamples; 124501e04c3fSmrg attNumStorageSamples = att->Renderbuffer->NumStorageSamples; 12467117f1b4Smrg } 12477117f1b4Smrg else { 12487117f1b4Smrg assert(att->Type == GL_NONE); 12497117f1b4Smrg continue; 12507117f1b4Smrg } 12517117f1b4Smrg 125201e04c3fSmrg if (i >= 0) { 125301e04c3fSmrg /* Color buffers. */ 125401e04c3fSmrg if (numColorSamples < 0) { 125501e04c3fSmrg assert(numColorStorageSamples < 0); 125601e04c3fSmrg numColorSamples = attNumSamples; 125701e04c3fSmrg numColorStorageSamples = attNumStorageSamples; 125801e04c3fSmrg } else if (numColorSamples != attNumSamples || 125901e04c3fSmrg numColorStorageSamples != attNumStorageSamples) { 126001e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 126101e04c3fSmrg fbo_incomplete(ctx, "inconsistent sample counts", -1); 126201e04c3fSmrg return; 126301e04c3fSmrg } 126401e04c3fSmrg } else { 126501e04c3fSmrg /* Depth/stencil buffers. */ 126601e04c3fSmrg if (numDepthSamples < 0) { 126701e04c3fSmrg numDepthSamples = attNumSamples; 126801e04c3fSmrg } else if (numDepthSamples != attNumSamples) { 126901e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 127001e04c3fSmrg fbo_incomplete(ctx, "inconsistent sample counts", -1); 127101e04c3fSmrg return; 127201e04c3fSmrg } 127301e04c3fSmrg } 12743464ebd5Sriastradh 127501e04c3fSmrg /* Update flags describing color buffer datatypes */ 1276af69d88dSmrg if (i >= 0) { 1277af69d88dSmrg GLenum type = _mesa_get_format_datatype(attFormat); 1278af69d88dSmrg 127901e04c3fSmrg /* check if integer color */ 128001e04c3fSmrg if (_mesa_is_format_integer_color(attFormat)) 128101e04c3fSmrg fb->_IntegerBuffers |= (1 << i); 128201e04c3fSmrg 1283a8bb7a65Smaya if (baseFormat == GL_RGB) 1284a8bb7a65Smaya fb->_RGBBuffers |= (1 << i); 1285a8bb7a65Smaya 1286a8bb7a65Smaya if (type == GL_FLOAT && _mesa_get_format_max_bits(attFormat) > 16) 1287a8bb7a65Smaya fb->_FP32Buffers |= (1 << i); 1288a8bb7a65Smaya 1289af69d88dSmrg fb->_AllColorBuffersFixedPoint = 1290af69d88dSmrg fb->_AllColorBuffersFixedPoint && 1291af69d88dSmrg (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED); 1292af69d88dSmrg 1293af69d88dSmrg fb->_HasSNormOrFloatColorBuffer = 1294af69d88dSmrg fb->_HasSNormOrFloatColorBuffer || 1295af69d88dSmrg type == GL_SIGNED_NORMALIZED || type == GL_FLOAT; 1296af69d88dSmrg } 1297af69d88dSmrg 1298af69d88dSmrg /* Error-check width, height, format */ 12997117f1b4Smrg if (numImages == 1) { 1300af69d88dSmrg /* save format */ 13014a49301eSmrg if (i >= 0) { 13027117f1b4Smrg intFormat = f; 13034a49301eSmrg } 13047117f1b4Smrg } 13057117f1b4Smrg else { 13067ec681f3Smrg if (!_mesa_has_ARB_framebuffer_object(ctx) && 13077ec681f3Smrg !_mesa_is_gles3(ctx)) { 13084a49301eSmrg /* check that width, height, format are same */ 13094a49301eSmrg if (minWidth != maxWidth || minHeight != maxHeight) { 13104a49301eSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 1311af69d88dSmrg fbo_incomplete(ctx, "width or height mismatch", -1); 13124a49301eSmrg return; 13134a49301eSmrg } 1314af69d88dSmrg /* check that all color buffers are the same format */ 13157ec681f3Smrg if (ctx->API != API_OPENGLES2 && intFormat != GL_NONE && f != intFormat) { 13164a49301eSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 1317af69d88dSmrg fbo_incomplete(ctx, "format mismatch", -1); 13184a49301eSmrg return; 13194a49301eSmrg } 13207117f1b4Smrg } 1321af69d88dSmrg } 1322af69d88dSmrg 1323af69d88dSmrg /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported) 1324af69d88dSmrg */ 1325af69d88dSmrg if (att->Type == GL_RENDERBUFFER && 1326af69d88dSmrg att->Renderbuffer->Format == MESA_FORMAT_NONE) { 1327af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 1328af69d88dSmrg fbo_incomplete(ctx, "unsupported renderbuffer format", i); 1329af69d88dSmrg return; 1330af69d88dSmrg } 13314a49301eSmrg 1332af69d88dSmrg /* Check that layered rendering is consistent. */ 1333af69d88dSmrg if (att->Layered) { 13347ec681f3Smrg if (att_tex_target == GL_TEXTURE_CUBE_MAP) { 13357ec681f3Smrg /* Each layer's format and size must match to the base layer. */ 13367ec681f3Smrg if (!_mesa_cube_complete(att->Texture)) { 13377ec681f3Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 13387ec681f3Smrg fbo_incomplete(ctx, "attachment not cube complete", i); 13397ec681f3Smrg return; 13407ec681f3Smrg } 1341af69d88dSmrg att_layer_count = 6; 13427ec681f3Smrg } else if (att_tex_target == GL_TEXTURE_1D_ARRAY) 1343af69d88dSmrg att_layer_count = att->Renderbuffer->Height; 1344af69d88dSmrg else 1345af69d88dSmrg att_layer_count = att->Renderbuffer->Depth; 13467ec681f3Smrg 13477ec681f3Smrg /* From OpenGL ES 3.2 spec, chapter 9.4. FRAMEBUFFER COMPLETENESS: 13487ec681f3Smrg * 13497ec681f3Smrg * "If any framebuffer attachment is layered, all populated 13507ec681f3Smrg * attachments must be layered. Additionally, all populated color 13517ec681f3Smrg * attachments must be from textures of the same target 13527ec681f3Smrg * (three-dimensional, one- or two-dimensional array, cube map, or 13537ec681f3Smrg * cube map array textures)." 13547ec681f3Smrg * 13557ec681f3Smrg * Same text can be found from OpenGL 4.6 spec. 13567ec681f3Smrg * 13577ec681f3Smrg * Setup the checked layer target with first color attachment here 13587ec681f3Smrg * so that mismatch check below will not trigger between depth, 13597ec681f3Smrg * stencil, only between color attachments. 13607ec681f3Smrg */ 13617ec681f3Smrg if (i == 0) 13627ec681f3Smrg layer_tex_target = att_tex_target; 13637ec681f3Smrg 1364af69d88dSmrg } else { 1365af69d88dSmrg att_layer_count = 0; 1366af69d88dSmrg } 1367af69d88dSmrg if (!layer_info_valid) { 1368af69d88dSmrg is_layered = att->Layered; 1369af69d88dSmrg max_layer_count = att_layer_count; 1370af69d88dSmrg layer_info_valid = true; 13717ec681f3Smrg } else if (max_layer_count > 0 && layer_tex_target && 13727ec681f3Smrg layer_tex_target != att_tex_target) { 1373af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; 1374af69d88dSmrg fbo_incomplete(ctx, "layered framebuffer has mismatched targets", i); 1375af69d88dSmrg return; 1376af69d88dSmrg } else if (is_layered != att->Layered) { 1377af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; 1378af69d88dSmrg fbo_incomplete(ctx, 1379af69d88dSmrg "framebuffer attachment layer mode is inconsistent", 1380af69d88dSmrg i); 1381af69d88dSmrg return; 1382af69d88dSmrg } else if (att_layer_count > max_layer_count) { 1383af69d88dSmrg max_layer_count = att_layer_count; 13847117f1b4Smrg } 138501e04c3fSmrg 138601e04c3fSmrg /* 138701e04c3fSmrg * The extension GL_ARB_framebuffer_no_attachments places additional 138801e04c3fSmrg * requirement on each attachment. Those additional requirements are 138901e04c3fSmrg * tighter that those of previous versions of GL. In interest of better 139001e04c3fSmrg * compatibility, we will not enforce these restrictions. For the record 139101e04c3fSmrg * those additional restrictions are quoted below: 139201e04c3fSmrg * 139301e04c3fSmrg * "The width and height of image are greater than zero and less than or 139401e04c3fSmrg * equal to the values of the implementation-dependent limits 139501e04c3fSmrg * MAX_FRAMEBUFFER_WIDTH and MAX_FRAMEBUFFER_HEIGHT, respectively." 139601e04c3fSmrg * 139701e04c3fSmrg * "If <image> is a three-dimensional texture or a one- or two-dimensional 139801e04c3fSmrg * array texture and the attachment is layered, the depth or layer count 139901e04c3fSmrg * of the texture is less than or equal to the implementation-dependent 140001e04c3fSmrg * limit MAX_FRAMEBUFFER_LAYERS." 140101e04c3fSmrg * 140201e04c3fSmrg * "If image has multiple samples, its sample count is less than or equal 140301e04c3fSmrg * to the value of the implementation-dependent limit 140401e04c3fSmrg * MAX_FRAMEBUFFER_SAMPLES." 140501e04c3fSmrg * 140601e04c3fSmrg * The same requirements are also in place for GL 4.5, 140701e04c3fSmrg * Section 9.4.1 "Framebuffer Attachment Completeness", pg 310-311 140801e04c3fSmrg */ 140901e04c3fSmrg } 141001e04c3fSmrg 141101e04c3fSmrg if (ctx->Extensions.AMD_framebuffer_multisample_advanced) { 141201e04c3fSmrg /* See if non-matching sample counts are supported. */ 141301e04c3fSmrg if (numColorSamples >= 0 && numDepthSamples >= 0) { 141401e04c3fSmrg bool found = false; 141501e04c3fSmrg 141601e04c3fSmrg assert(numColorStorageSamples != -1); 141701e04c3fSmrg 141801e04c3fSmrg numColorSamples = MAX2(numColorSamples, 1); 141901e04c3fSmrg numColorStorageSamples = MAX2(numColorStorageSamples, 1); 142001e04c3fSmrg numDepthSamples = MAX2(numDepthSamples, 1); 142101e04c3fSmrg 142201e04c3fSmrg if (numColorSamples == 1 && numColorStorageSamples == 1 && 142301e04c3fSmrg numDepthSamples == 1) { 142401e04c3fSmrg found = true; 142501e04c3fSmrg } else { 142601e04c3fSmrg for (i = 0; i < ctx->Const.NumSupportedMultisampleModes; i++) { 142701e04c3fSmrg GLint *counts = 142801e04c3fSmrg &ctx->Const.SupportedMultisampleModes[i].NumColorSamples; 142901e04c3fSmrg 143001e04c3fSmrg if (counts[0] == numColorSamples && 143101e04c3fSmrg counts[1] == numColorStorageSamples && 143201e04c3fSmrg counts[2] == numDepthSamples) { 143301e04c3fSmrg found = true; 143401e04c3fSmrg break; 143501e04c3fSmrg } 143601e04c3fSmrg } 143701e04c3fSmrg } 143801e04c3fSmrg 143901e04c3fSmrg if (!found) { 144001e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 144101e04c3fSmrg fbo_incomplete(ctx, "unsupported sample counts", -1); 144201e04c3fSmrg return; 144301e04c3fSmrg } 144401e04c3fSmrg } 144501e04c3fSmrg } else { 144601e04c3fSmrg /* If the extension is unsupported, all sample counts must be equal. */ 144701e04c3fSmrg if (numColorSamples >= 0 && 144801e04c3fSmrg (numColorSamples != numColorStorageSamples || 144901e04c3fSmrg (numDepthSamples >= 0 && numColorSamples != numDepthSamples))) { 145001e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 145101e04c3fSmrg fbo_incomplete(ctx, "inconsistent sample counts", -1); 145201e04c3fSmrg return; 145301e04c3fSmrg } 14547117f1b4Smrg } 14557117f1b4Smrg 1456af69d88dSmrg fb->MaxNumLayers = max_layer_count; 1457af69d88dSmrg 1458af69d88dSmrg if (numImages == 0) { 145901e04c3fSmrg fb->_HasAttachments = false; 146001e04c3fSmrg 146101e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments) { 146201e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 146301e04c3fSmrg fbo_incomplete(ctx, "no attachments", -1); 146401e04c3fSmrg return; 146501e04c3fSmrg } 146601e04c3fSmrg 146701e04c3fSmrg if (fb->DefaultGeometry.Width == 0 || fb->DefaultGeometry.Height == 0) { 146801e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 146901e04c3fSmrg fbo_incomplete(ctx, "no attachments and default width or height is 0", -1); 147001e04c3fSmrg return; 147101e04c3fSmrg } 1472af69d88dSmrg } 1473af69d88dSmrg 1474af69d88dSmrg if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) { 14753464ebd5Sriastradh /* Check that all DrawBuffers are present */ 14763464ebd5Sriastradh for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { 147701e04c3fSmrg if (fb->ColorDrawBuffer[j] != GL_NONE) { 147801e04c3fSmrg const struct gl_renderbuffer_attachment *att 147901e04c3fSmrg = get_attachment(ctx, fb, fb->ColorDrawBuffer[j], NULL); 148001e04c3fSmrg assert(att); 148101e04c3fSmrg if (att->Type == GL_NONE) { 148201e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; 148301e04c3fSmrg fbo_incomplete(ctx, "missing drawbuffer", j); 148401e04c3fSmrg return; 148501e04c3fSmrg } 148601e04c3fSmrg } 14877117f1b4Smrg } 14887117f1b4Smrg 14893464ebd5Sriastradh /* Check that the ReadBuffer is present */ 14903464ebd5Sriastradh if (fb->ColorReadBuffer != GL_NONE) { 149101e04c3fSmrg const struct gl_renderbuffer_attachment *att 149201e04c3fSmrg = get_attachment(ctx, fb, fb->ColorReadBuffer, NULL); 149301e04c3fSmrg assert(att); 149401e04c3fSmrg if (att->Type == GL_NONE) { 149501e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; 1496af69d88dSmrg fbo_incomplete(ctx, "missing readbuffer", -1); 149701e04c3fSmrg return; 149801e04c3fSmrg } 14997117f1b4Smrg } 15007117f1b4Smrg } 15017117f1b4Smrg 150201e04c3fSmrg /* The OpenGL ES3 spec, in chapter 9.4. FRAMEBUFFER COMPLETENESS, says: 150301e04c3fSmrg * 150401e04c3fSmrg * "Depth and stencil attachments, if present, are the same image." 150501e04c3fSmrg * 150601e04c3fSmrg * This restriction is not present in the OpenGL ES2 spec. 150701e04c3fSmrg */ 150801e04c3fSmrg if (_mesa_is_gles3(ctx) && 150901e04c3fSmrg has_stencil_attachment && has_depth_attachment && 151001e04c3fSmrg !_mesa_has_depthstencil_combined(fb)) { 151101e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 151201e04c3fSmrg fbo_incomplete(ctx, "Depth and stencil attachments must be the same image", -1); 151301e04c3fSmrg return; 151401e04c3fSmrg } 151501e04c3fSmrg 15164a49301eSmrg /* Provisionally set status = COMPLETE ... */ 15177117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 15184a49301eSmrg 15194a49301eSmrg /* ... but the driver may say the FB is incomplete. 15204a49301eSmrg * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED 15214a49301eSmrg * if anything. 15224a49301eSmrg */ 15234a49301eSmrg if (ctx->Driver.ValidateFramebuffer) { 15244a49301eSmrg ctx->Driver.ValidateFramebuffer(ctx, fb); 15254a49301eSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 1526af69d88dSmrg fbo_incomplete(ctx, "driver marked FBO as incomplete", -1); 152701e04c3fSmrg return; 15284a49301eSmrg } 15294a49301eSmrg } 15304a49301eSmrg 153101e04c3fSmrg /* 153201e04c3fSmrg * Note that if ARB_framebuffer_object is supported and the attached 153301e04c3fSmrg * renderbuffers/textures are different sizes, the framebuffer 153401e04c3fSmrg * width/height will be set to the smallest width/height. 153501e04c3fSmrg */ 153601e04c3fSmrg if (numImages != 0) { 15374a49301eSmrg fb->Width = minWidth; 15384a49301eSmrg fb->Height = minHeight; 15394a49301eSmrg } 154001e04c3fSmrg 154101e04c3fSmrg /* finally, update the visual info for the framebuffer */ 154201e04c3fSmrg _mesa_update_framebuffer_visual(ctx, fb); 15437117f1b4Smrg} 15447117f1b4Smrg 15457117f1b4Smrg 15467117f1b4SmrgGLboolean GLAPIENTRY 1547af69d88dSmrg_mesa_IsRenderbuffer(GLuint renderbuffer) 15487117f1b4Smrg{ 154901e04c3fSmrg struct gl_renderbuffer *rb; 155001e04c3fSmrg 15517117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 155201e04c3fSmrg 15537117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 155401e04c3fSmrg 155501e04c3fSmrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 155601e04c3fSmrg return rb != NULL && rb != &DummyRenderbuffer; 155701e04c3fSmrg} 155801e04c3fSmrg 155901e04c3fSmrg 156001e04c3fSmrgstatic struct gl_renderbuffer * 156101e04c3fSmrgallocate_renderbuffer_locked(struct gl_context *ctx, GLuint renderbuffer, 15627ec681f3Smrg bool isGenName, 156301e04c3fSmrg const char *func) 156401e04c3fSmrg{ 156501e04c3fSmrg struct gl_renderbuffer *newRb; 156601e04c3fSmrg 156701e04c3fSmrg /* create new renderbuffer object */ 156801e04c3fSmrg newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); 156901e04c3fSmrg if (!newRb) { 157001e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 157101e04c3fSmrg return NULL; 15727117f1b4Smrg } 157301e04c3fSmrg assert(newRb->AllocStorage); 15747ec681f3Smrg _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, renderbuffer, 15757ec681f3Smrg newRb, isGenName); 157601e04c3fSmrg 157701e04c3fSmrg return newRb; 15787117f1b4Smrg} 15797117f1b4Smrg 15807117f1b4Smrg 1581af69d88dSmrgstatic void 158201e04c3fSmrgbind_renderbuffer(GLenum target, GLuint renderbuffer) 15837117f1b4Smrg{ 15847117f1b4Smrg struct gl_renderbuffer *newRb; 15857117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 15867117f1b4Smrg 15877117f1b4Smrg if (target != GL_RENDERBUFFER_EXT) { 15884a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); 15897117f1b4Smrg return; 15907117f1b4Smrg } 15917117f1b4Smrg 15924a49301eSmrg /* No need to flush here since the render buffer binding has no 15934a49301eSmrg * effect on rendering state. 15947117f1b4Smrg */ 15957117f1b4Smrg 15967117f1b4Smrg if (renderbuffer) { 15977ec681f3Smrg bool isGenName = false; 15987117f1b4Smrg newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 15997117f1b4Smrg if (newRb == &DummyRenderbuffer) { 16007117f1b4Smrg /* ID was reserved, but no real renderbuffer object made yet */ 16017117f1b4Smrg newRb = NULL; 16027ec681f3Smrg isGenName = true; 16037117f1b4Smrg } 160401e04c3fSmrg else if (!newRb && ctx->API == API_OPENGL_CORE) { 16054a49301eSmrg /* All RB IDs must be Gen'd */ 160601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 160701e04c3fSmrg "glBindRenderbuffer(non-gen name)"); 16084a49301eSmrg return; 16094a49301eSmrg } 16104a49301eSmrg 16117117f1b4Smrg if (!newRb) { 161201e04c3fSmrg _mesa_HashLockMutex(ctx->Shared->RenderBuffers); 161301e04c3fSmrg newRb = allocate_renderbuffer_locked(ctx, renderbuffer, 16147ec681f3Smrg isGenName, "glBindRenderbufferEXT"); 161501e04c3fSmrg _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); 16167117f1b4Smrg } 16177117f1b4Smrg } 16187117f1b4Smrg else { 16197117f1b4Smrg newRb = NULL; 16207117f1b4Smrg } 16217117f1b4Smrg 162201e04c3fSmrg assert(newRb != &DummyRenderbuffer); 16237117f1b4Smrg 16247117f1b4Smrg _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); 16257117f1b4Smrg} 16267117f1b4Smrg 1627af69d88dSmrgvoid GLAPIENTRY 1628af69d88dSmrg_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer) 1629af69d88dSmrg{ 1630af69d88dSmrg /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same 1631af69d88dSmrg * entry point, but they allow the use of user-generated names. 1632af69d88dSmrg */ 163301e04c3fSmrg bind_renderbuffer(target, renderbuffer); 1634af69d88dSmrg} 1635af69d88dSmrg 1636af69d88dSmrgvoid GLAPIENTRY 1637af69d88dSmrg_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 1638af69d88dSmrg{ 163901e04c3fSmrg bind_renderbuffer(target, renderbuffer); 1640af69d88dSmrg} 1641af69d88dSmrg 16424a49301eSmrg/** 164301e04c3fSmrg * ARB_framebuffer_no_attachment and ARB_sample_locations - Application passes 164401e04c3fSmrg * requested param's here. NOTE: NumSamples requested need not be _NumSamples 164501e04c3fSmrg * which is what the hw supports. 16464a49301eSmrg */ 164701e04c3fSmrgstatic void 164801e04c3fSmrgframebuffer_parameteri(struct gl_context *ctx, struct gl_framebuffer *fb, 164901e04c3fSmrg GLenum pname, GLint param, const char *func) 16504a49301eSmrg{ 165101e04c3fSmrg bool cannot_be_winsys_fbo = false; 1652af69d88dSmrg 165301e04c3fSmrg switch (pname) { 165401e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_WIDTH: 165501e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_HEIGHT: 165601e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_LAYERS: 165701e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_SAMPLES: 165801e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: 165901e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments) 166001e04c3fSmrg goto invalid_pname_enum; 166101e04c3fSmrg cannot_be_winsys_fbo = true; 166201e04c3fSmrg break; 166301e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 166401e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 166501e04c3fSmrg if (!ctx->Extensions.ARB_sample_locations) 166601e04c3fSmrg goto invalid_pname_enum; 166701e04c3fSmrg break; 166801e04c3fSmrg case GL_FRAMEBUFFER_FLIP_Y_MESA: 166901e04c3fSmrg if (!ctx->Extensions.MESA_framebuffer_flip_y) 167001e04c3fSmrg goto invalid_pname_enum; 167101e04c3fSmrg cannot_be_winsys_fbo = true; 167201e04c3fSmrg break; 167301e04c3fSmrg default: 167401e04c3fSmrg goto invalid_pname_enum; 167501e04c3fSmrg } 167601e04c3fSmrg 167701e04c3fSmrg if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) { 167801e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 167901e04c3fSmrg "%s(invalid pname=0x%x for default framebuffer)", func, pname); 168001e04c3fSmrg return; 168101e04c3fSmrg } 168201e04c3fSmrg 168301e04c3fSmrg switch (pname) { 168401e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_WIDTH: 168501e04c3fSmrg if (param < 0 || param > ctx->Const.MaxFramebufferWidth) 168601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s", func); 168701e04c3fSmrg else 168801e04c3fSmrg fb->DefaultGeometry.Width = param; 168901e04c3fSmrg break; 169001e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_HEIGHT: 169101e04c3fSmrg if (param < 0 || param > ctx->Const.MaxFramebufferHeight) 169201e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s", func); 169301e04c3fSmrg else 169401e04c3fSmrg fb->DefaultGeometry.Height = param; 169501e04c3fSmrg break; 169601e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_LAYERS: 169701e04c3fSmrg /* 169801e04c3fSmrg * According to the OpenGL ES 3.1 specification section 9.2.1, the 169901e04c3fSmrg * GL_FRAMEBUFFER_DEFAULT_LAYERS parameter name is not supported. 170001e04c3fSmrg */ 170101e04c3fSmrg if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) { 170201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 170301e04c3fSmrg break; 17044a49301eSmrg } 170501e04c3fSmrg if (param < 0 || param > ctx->Const.MaxFramebufferLayers) 170601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s", func); 170701e04c3fSmrg else 170801e04c3fSmrg fb->DefaultGeometry.Layers = param; 170901e04c3fSmrg break; 171001e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_SAMPLES: 171101e04c3fSmrg if (param < 0 || param > ctx->Const.MaxFramebufferSamples) 171201e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s", func); 171301e04c3fSmrg else 171401e04c3fSmrg fb->DefaultGeometry.NumSamples = param; 171501e04c3fSmrg break; 171601e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: 171701e04c3fSmrg fb->DefaultGeometry.FixedSampleLocations = param; 171801e04c3fSmrg break; 171901e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 172001e04c3fSmrg fb->ProgrammableSampleLocations = !!param; 172101e04c3fSmrg break; 172201e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 172301e04c3fSmrg fb->SampleLocationPixelGrid = !!param; 172401e04c3fSmrg break; 172501e04c3fSmrg case GL_FRAMEBUFFER_FLIP_Y_MESA: 172601e04c3fSmrg fb->FlipY = param; 172701e04c3fSmrg break; 17284a49301eSmrg } 1729af69d88dSmrg 173001e04c3fSmrg switch (pname) { 173101e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 173201e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 173301e04c3fSmrg if (fb == ctx->DrawBuffer) 173401e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations; 173501e04c3fSmrg break; 173601e04c3fSmrg default: 1737af69d88dSmrg invalidate_framebuffer(fb); 173801e04c3fSmrg ctx->NewState |= _NEW_BUFFERS; 173901e04c3fSmrg break; 174001e04c3fSmrg } 1741af69d88dSmrg 174201e04c3fSmrg return; 17434a49301eSmrg 174401e04c3fSmrginvalid_pname_enum: 174501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 174601e04c3fSmrg} 17474a49301eSmrg 17487ec681f3Smrgstatic bool 17497ec681f3Smrgvalidate_framebuffer_parameter_extensions(GLenum pname, const char *func) 17507ec681f3Smrg{ 17517ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 17527ec681f3Smrg 17537ec681f3Smrg if (!ctx->Extensions.ARB_framebuffer_no_attachments && 17547ec681f3Smrg !ctx->Extensions.ARB_sample_locations && 17557ec681f3Smrg !ctx->Extensions.MESA_framebuffer_flip_y) { 17567ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 17577ec681f3Smrg "%s not supported " 17587ec681f3Smrg "(none of ARB_framebuffer_no_attachments," 17597ec681f3Smrg " ARB_sample_locations, or" 17607ec681f3Smrg " MESA_framebuffer_flip_y extensions are available)", 17617ec681f3Smrg func); 17627ec681f3Smrg return false; 17637ec681f3Smrg } 17647ec681f3Smrg 17657ec681f3Smrg /* 17667ec681f3Smrg * If only the MESA_framebuffer_flip_y extension is enabled 17677ec681f3Smrg * pname can only be GL_FRAMEBUFFER_FLIP_Y_MESA 17687ec681f3Smrg */ 17697ec681f3Smrg if (ctx->Extensions.MESA_framebuffer_flip_y && 17707ec681f3Smrg pname != GL_FRAMEBUFFER_FLIP_Y_MESA && 17717ec681f3Smrg !(ctx->Extensions.ARB_framebuffer_no_attachments || 17727ec681f3Smrg ctx->Extensions.ARB_sample_locations)) { 17737ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 17747ec681f3Smrg return false; 17757ec681f3Smrg } 17767ec681f3Smrg 17777ec681f3Smrg return true; 17787ec681f3Smrg} 17797ec681f3Smrg 17807117f1b4Smrgvoid GLAPIENTRY 178101e04c3fSmrg_mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param) 17827117f1b4Smrg{ 17837117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 178401e04c3fSmrg struct gl_framebuffer *fb; 17857117f1b4Smrg 17867ec681f3Smrg if (!validate_framebuffer_parameter_extensions(pname, 17877ec681f3Smrg "glFramebufferParameteri")) { 178801e04c3fSmrg return; 178901e04c3fSmrg } 17907117f1b4Smrg 179101e04c3fSmrg fb = get_framebuffer_target(ctx, target); 179201e04c3fSmrg if (!fb) { 179301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 179401e04c3fSmrg "glFramebufferParameteri(target=0x%x)", target); 179501e04c3fSmrg return; 179601e04c3fSmrg } 17977117f1b4Smrg 179801e04c3fSmrg framebuffer_parameteri(ctx, fb, pname, param, "glFramebufferParameteri"); 179901e04c3fSmrg} 180001e04c3fSmrg 18017ec681f3Smrgvoid GLAPIENTRY 18027ec681f3Smrg_mesa_FramebufferParameteriMESA(GLenum target, GLenum pname, GLint param) 18037ec681f3Smrg{ 18047ec681f3Smrg _mesa_FramebufferParameteri(target, pname, param); 18057ec681f3Smrg} 18067ec681f3Smrg 180701e04c3fSmrgstatic bool 180801e04c3fSmrgvalidate_get_framebuffer_parameteriv_pname(struct gl_context *ctx, 180901e04c3fSmrg struct gl_framebuffer *fb, 181001e04c3fSmrg GLuint pname, const char *func) 181101e04c3fSmrg{ 181201e04c3fSmrg bool cannot_be_winsys_fbo = true; 181301e04c3fSmrg 181401e04c3fSmrg switch (pname) { 181501e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_LAYERS: 181601e04c3fSmrg /* 181701e04c3fSmrg * According to the OpenGL ES 3.1 specification section 9.2.3, the 181801e04c3fSmrg * GL_FRAMEBUFFER_LAYERS parameter name is not supported. 181901e04c3fSmrg */ 182001e04c3fSmrg if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) { 182101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 182201e04c3fSmrg return false; 182301e04c3fSmrg } 182401e04c3fSmrg break; 182501e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_WIDTH: 182601e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_HEIGHT: 182701e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_SAMPLES: 182801e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: 182901e04c3fSmrg break; 183001e04c3fSmrg case GL_DOUBLEBUFFER: 183101e04c3fSmrg case GL_IMPLEMENTATION_COLOR_READ_FORMAT: 183201e04c3fSmrg case GL_IMPLEMENTATION_COLOR_READ_TYPE: 183301e04c3fSmrg case GL_SAMPLES: 183401e04c3fSmrg case GL_SAMPLE_BUFFERS: 183501e04c3fSmrg case GL_STEREO: 183601e04c3fSmrg /* From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries: 183701e04c3fSmrg * 183801e04c3fSmrg * "An INVALID_OPERATION error is generated by GetFramebufferParameteriv 183901e04c3fSmrg * if the default framebuffer is bound to target and pname is not one 184001e04c3fSmrg * of the accepted values from table 23.73, other than 184101e04c3fSmrg * SAMPLE_POSITION." 184201e04c3fSmrg * 184301e04c3fSmrg * For OpenGL ES, using default framebuffer raises INVALID_OPERATION 184401e04c3fSmrg * for any pname. 184501e04c3fSmrg */ 184601e04c3fSmrg cannot_be_winsys_fbo = !_mesa_is_desktop_gl(ctx); 184701e04c3fSmrg break; 184801e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 184901e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 185001e04c3fSmrg if (!ctx->Extensions.ARB_sample_locations) 185101e04c3fSmrg goto invalid_pname_enum; 185201e04c3fSmrg cannot_be_winsys_fbo = false; 185301e04c3fSmrg break; 185401e04c3fSmrg case GL_FRAMEBUFFER_FLIP_Y_MESA: 185501e04c3fSmrg if (!ctx->Extensions.MESA_framebuffer_flip_y) { 185601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 185701e04c3fSmrg return false; 185801e04c3fSmrg } 185901e04c3fSmrg break; 186001e04c3fSmrg default: 186101e04c3fSmrg goto invalid_pname_enum; 186201e04c3fSmrg } 186301e04c3fSmrg 186401e04c3fSmrg if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) { 186501e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 186601e04c3fSmrg "%s(invalid pname=0x%x for default framebuffer)", func, pname); 186701e04c3fSmrg return false; 186801e04c3fSmrg } 186901e04c3fSmrg 187001e04c3fSmrg return true; 187101e04c3fSmrg 187201e04c3fSmrginvalid_pname_enum: 187301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 187401e04c3fSmrg return false; 187501e04c3fSmrg} 187601e04c3fSmrg 187701e04c3fSmrgstatic void 187801e04c3fSmrgget_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb, 187901e04c3fSmrg GLenum pname, GLint *params, const char *func) 188001e04c3fSmrg{ 188101e04c3fSmrg if (!validate_get_framebuffer_parameteriv_pname(ctx, fb, pname, func)) 188201e04c3fSmrg return; 188301e04c3fSmrg 188401e04c3fSmrg switch (pname) { 188501e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_WIDTH: 188601e04c3fSmrg *params = fb->DefaultGeometry.Width; 188701e04c3fSmrg break; 188801e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_HEIGHT: 188901e04c3fSmrg *params = fb->DefaultGeometry.Height; 189001e04c3fSmrg break; 189101e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_LAYERS: 189201e04c3fSmrg *params = fb->DefaultGeometry.Layers; 189301e04c3fSmrg break; 189401e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_SAMPLES: 189501e04c3fSmrg *params = fb->DefaultGeometry.NumSamples; 189601e04c3fSmrg break; 189701e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: 189801e04c3fSmrg *params = fb->DefaultGeometry.FixedSampleLocations; 189901e04c3fSmrg break; 190001e04c3fSmrg case GL_DOUBLEBUFFER: 190101e04c3fSmrg *params = fb->Visual.doubleBufferMode; 190201e04c3fSmrg break; 190301e04c3fSmrg case GL_IMPLEMENTATION_COLOR_READ_FORMAT: 190401e04c3fSmrg *params = _mesa_get_color_read_format(ctx, fb, func); 190501e04c3fSmrg break; 190601e04c3fSmrg case GL_IMPLEMENTATION_COLOR_READ_TYPE: 190701e04c3fSmrg *params = _mesa_get_color_read_type(ctx, fb, func); 190801e04c3fSmrg break; 190901e04c3fSmrg case GL_SAMPLES: 191001e04c3fSmrg *params = _mesa_geometric_samples(fb); 191101e04c3fSmrg break; 191201e04c3fSmrg case GL_SAMPLE_BUFFERS: 191301e04c3fSmrg *params = _mesa_geometric_samples(fb) > 0; 191401e04c3fSmrg break; 191501e04c3fSmrg case GL_STEREO: 191601e04c3fSmrg *params = fb->Visual.stereoMode; 191701e04c3fSmrg break; 191801e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 191901e04c3fSmrg *params = fb->ProgrammableSampleLocations; 192001e04c3fSmrg break; 192101e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 192201e04c3fSmrg *params = fb->SampleLocationPixelGrid; 192301e04c3fSmrg break; 192401e04c3fSmrg case GL_FRAMEBUFFER_FLIP_Y_MESA: 192501e04c3fSmrg *params = fb->FlipY; 192601e04c3fSmrg break; 192701e04c3fSmrg } 192801e04c3fSmrg} 192901e04c3fSmrg 193001e04c3fSmrgvoid GLAPIENTRY 193101e04c3fSmrg_mesa_GetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params) 193201e04c3fSmrg{ 193301e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 193401e04c3fSmrg struct gl_framebuffer *fb; 193501e04c3fSmrg 19367ec681f3Smrg if (!validate_framebuffer_parameter_extensions(pname, 19377ec681f3Smrg "glGetFramebufferParameteriv")) { 193801e04c3fSmrg return; 193901e04c3fSmrg } 194001e04c3fSmrg 194101e04c3fSmrg fb = get_framebuffer_target(ctx, target); 194201e04c3fSmrg if (!fb) { 194301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 194401e04c3fSmrg "glGetFramebufferParameteriv(target=0x%x)", target); 194501e04c3fSmrg return; 194601e04c3fSmrg } 194701e04c3fSmrg 194801e04c3fSmrg get_framebuffer_parameteriv(ctx, fb, pname, params, 194901e04c3fSmrg "glGetFramebufferParameteriv"); 195001e04c3fSmrg} 195101e04c3fSmrg 19527ec681f3Smrgvoid GLAPIENTRY 19537ec681f3Smrg_mesa_GetFramebufferParameterivMESA(GLenum target, GLenum pname, GLint *params) 19547ec681f3Smrg{ 19557ec681f3Smrg _mesa_GetFramebufferParameteriv(target, pname, params); 19567ec681f3Smrg} 195701e04c3fSmrg 195801e04c3fSmrg/** 195901e04c3fSmrg * Remove the specified renderbuffer or texture from any attachment point in 196001e04c3fSmrg * the framebuffer. 196101e04c3fSmrg * 196201e04c3fSmrg * \returns 196301e04c3fSmrg * \c true if the renderbuffer was detached from an attachment point. \c 196401e04c3fSmrg * false otherwise. 196501e04c3fSmrg */ 196601e04c3fSmrgbool 196701e04c3fSmrg_mesa_detach_renderbuffer(struct gl_context *ctx, 196801e04c3fSmrg struct gl_framebuffer *fb, 196901e04c3fSmrg const void *att) 197001e04c3fSmrg{ 197101e04c3fSmrg unsigned i; 197201e04c3fSmrg bool progress = false; 197301e04c3fSmrg 197401e04c3fSmrg for (i = 0; i < BUFFER_COUNT; i++) { 197501e04c3fSmrg if (fb->Attachment[i].Texture == att 197601e04c3fSmrg || fb->Attachment[i].Renderbuffer == att) { 197701e04c3fSmrg remove_attachment(ctx, &fb->Attachment[i]); 197801e04c3fSmrg progress = true; 197901e04c3fSmrg } 198001e04c3fSmrg } 198101e04c3fSmrg 198201e04c3fSmrg /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer 198301e04c3fSmrg * Completeness," of the OpenGL 3.1 spec says: 198401e04c3fSmrg * 198501e04c3fSmrg * "Performing any of the following actions may change whether the 198601e04c3fSmrg * framebuffer is considered complete or incomplete: 198701e04c3fSmrg * 198801e04c3fSmrg * ... 198901e04c3fSmrg * 199001e04c3fSmrg * - Deleting, with DeleteTextures or DeleteRenderbuffers, an object 199101e04c3fSmrg * containing an image that is attached to a framebuffer object 199201e04c3fSmrg * that is bound to the framebuffer." 199301e04c3fSmrg */ 199401e04c3fSmrg if (progress) 199501e04c3fSmrg invalidate_framebuffer(fb); 199601e04c3fSmrg 199701e04c3fSmrg return progress; 199801e04c3fSmrg} 199901e04c3fSmrg 200001e04c3fSmrg 200101e04c3fSmrgvoid GLAPIENTRY 200201e04c3fSmrg_mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) 200301e04c3fSmrg{ 200401e04c3fSmrg GLint i; 200501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 200601e04c3fSmrg 200701e04c3fSmrg if (n < 0) { 200801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteRenderbuffers(n < 0)"); 200901e04c3fSmrg return; 201001e04c3fSmrg } 201101e04c3fSmrg 20127ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0); 201301e04c3fSmrg 201401e04c3fSmrg for (i = 0; i < n; i++) { 201501e04c3fSmrg if (renderbuffers[i] > 0) { 201601e04c3fSmrg struct gl_renderbuffer *rb; 201701e04c3fSmrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); 201801e04c3fSmrg if (rb) { 201901e04c3fSmrg /* check if deleting currently bound renderbuffer object */ 202001e04c3fSmrg if (rb == ctx->CurrentRenderbuffer) { 202101e04c3fSmrg /* bind default */ 202201e04c3fSmrg assert(rb->RefCount >= 2); 202301e04c3fSmrg _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0); 202401e04c3fSmrg } 202501e04c3fSmrg 202601e04c3fSmrg /* Section 4.4.2 (Attaching Images to Framebuffer Objects), 202701e04c3fSmrg * subsection "Attaching Renderbuffer Images to a Framebuffer," 202801e04c3fSmrg * of the OpenGL 3.1 spec says: 202901e04c3fSmrg * 203001e04c3fSmrg * "If a renderbuffer object is deleted while its image is 203101e04c3fSmrg * attached to one or more attachment points in the currently 203201e04c3fSmrg * bound framebuffer, then it is as if FramebufferRenderbuffer 203301e04c3fSmrg * had been called, with a renderbuffer of 0, for each 203401e04c3fSmrg * attachment point to which this image was attached in the 203501e04c3fSmrg * currently bound framebuffer. In other words, this 203601e04c3fSmrg * renderbuffer image is first detached from all attachment 203701e04c3fSmrg * points in the currently bound framebuffer. Note that the 203801e04c3fSmrg * renderbuffer image is specifically not detached from any 203901e04c3fSmrg * non-bound framebuffers. Detaching the image from any 204001e04c3fSmrg * non-bound framebuffers is the responsibility of the 2041af69d88dSmrg * application. 2042af69d88dSmrg */ 2043af69d88dSmrg if (_mesa_is_user_fbo(ctx->DrawBuffer)) { 2044af69d88dSmrg _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb); 20454a49301eSmrg } 2046af69d88dSmrg if (_mesa_is_user_fbo(ctx->ReadBuffer) 20473464ebd5Sriastradh && ctx->ReadBuffer != ctx->DrawBuffer) { 2048af69d88dSmrg _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb); 20494a49301eSmrg } 20504a49301eSmrg 205101e04c3fSmrg /* Remove from hash table immediately, to free the ID. 20527117f1b4Smrg * But the object will not be freed until it's no longer 20537117f1b4Smrg * referenced anywhere else. 20547117f1b4Smrg */ 205501e04c3fSmrg _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); 20567117f1b4Smrg 20577117f1b4Smrg if (rb != &DummyRenderbuffer) { 20587117f1b4Smrg /* no longer referenced by hash table */ 20597117f1b4Smrg _mesa_reference_renderbuffer(&rb, NULL); 206001e04c3fSmrg } 206101e04c3fSmrg } 20627117f1b4Smrg } 20637117f1b4Smrg } 20647117f1b4Smrg} 20657117f1b4Smrg 206601e04c3fSmrgstatic void 206701e04c3fSmrgcreate_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers, 206801e04c3fSmrg bool dsa) 20697117f1b4Smrg{ 207001e04c3fSmrg const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers"; 20717117f1b4Smrg GLint i; 20727117f1b4Smrg 20737117f1b4Smrg if (!renderbuffers) 20747117f1b4Smrg return; 20757117f1b4Smrg 207601e04c3fSmrg _mesa_HashLockMutex(ctx->Shared->RenderBuffers); 207701e04c3fSmrg 20787ec681f3Smrg _mesa_HashFindFreeKeys(ctx->Shared->RenderBuffers, renderbuffers, n); 20797117f1b4Smrg 20807117f1b4Smrg for (i = 0; i < n; i++) { 208101e04c3fSmrg if (dsa) { 20827ec681f3Smrg allocate_renderbuffer_locked(ctx, renderbuffers[i], true, func); 208301e04c3fSmrg } else { 208401e04c3fSmrg /* insert a dummy renderbuffer into the hash table */ 20857ec681f3Smrg _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, renderbuffers[i], 20867ec681f3Smrg &DummyRenderbuffer, true); 208701e04c3fSmrg } 208801e04c3fSmrg } 208901e04c3fSmrg 209001e04c3fSmrg _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); 209101e04c3fSmrg} 209201e04c3fSmrg 209301e04c3fSmrg 209401e04c3fSmrgstatic void 209501e04c3fSmrgcreate_render_buffers_err(struct gl_context *ctx, GLsizei n, 209601e04c3fSmrg GLuint *renderbuffers, bool dsa) 209701e04c3fSmrg{ 209801e04c3fSmrg const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers"; 209901e04c3fSmrg 210001e04c3fSmrg if (n < 0) { 210101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", func); 210201e04c3fSmrg return; 21037117f1b4Smrg } 210401e04c3fSmrg 210501e04c3fSmrg create_render_buffers(ctx, n, renderbuffers, dsa); 210601e04c3fSmrg} 210701e04c3fSmrg 210801e04c3fSmrg 210901e04c3fSmrgvoid GLAPIENTRY 211001e04c3fSmrg_mesa_GenRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers) 211101e04c3fSmrg{ 211201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 211301e04c3fSmrg create_render_buffers(ctx, n, renderbuffers, false); 211401e04c3fSmrg} 211501e04c3fSmrg 211601e04c3fSmrg 211701e04c3fSmrgvoid GLAPIENTRY 211801e04c3fSmrg_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers) 211901e04c3fSmrg{ 212001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 212101e04c3fSmrg create_render_buffers_err(ctx, n, renderbuffers, false); 212201e04c3fSmrg} 212301e04c3fSmrg 212401e04c3fSmrg 212501e04c3fSmrgvoid GLAPIENTRY 212601e04c3fSmrg_mesa_CreateRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers) 212701e04c3fSmrg{ 212801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 212901e04c3fSmrg create_render_buffers(ctx, n, renderbuffers, true); 213001e04c3fSmrg} 213101e04c3fSmrg 213201e04c3fSmrg 213301e04c3fSmrgvoid GLAPIENTRY 213401e04c3fSmrg_mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers) 213501e04c3fSmrg{ 213601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 213701e04c3fSmrg create_render_buffers_err(ctx, n, renderbuffers, true); 21387117f1b4Smrg} 21397117f1b4Smrg 21407117f1b4Smrg 21417117f1b4Smrg/** 21427117f1b4Smrg * Given an internal format token for a render buffer, return the 21433464ebd5Sriastradh * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, 21443464ebd5Sriastradh * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE, 21453464ebd5Sriastradh * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc). 21467117f1b4Smrg * 21473464ebd5Sriastradh * This is similar to _mesa_base_tex_format() but the set of valid 21483464ebd5Sriastradh * internal formats is different. 2149cdc920a0Smrg * 21503464ebd5Sriastradh * Note that even if a format is determined to be legal here, validation 21513464ebd5Sriastradh * of the FBO may fail if the format is not supported by the driver/GPU. 21523464ebd5Sriastradh * 21533464ebd5Sriastradh * \param internalFormat as passed to glRenderbufferStorage() 21543464ebd5Sriastradh * \return the base internal format, or 0 if internalFormat is illegal 21557117f1b4Smrg */ 21567117f1b4SmrgGLenum 215701e04c3fSmrg_mesa_base_fbo_format(const struct gl_context *ctx, GLenum internalFormat) 21587117f1b4Smrg{ 21593464ebd5Sriastradh /* 21603464ebd5Sriastradh * Notes: some formats such as alpha, luminance, etc. were added 21613464ebd5Sriastradh * with GL_ARB_framebuffer_object. 21623464ebd5Sriastradh */ 21637117f1b4Smrg switch (internalFormat) { 21643464ebd5Sriastradh case GL_ALPHA: 21653464ebd5Sriastradh case GL_ALPHA4: 21663464ebd5Sriastradh case GL_ALPHA8: 21673464ebd5Sriastradh case GL_ALPHA12: 21683464ebd5Sriastradh case GL_ALPHA16: 2169af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 2170af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_ALPHA : 0; 21713464ebd5Sriastradh case GL_LUMINANCE: 21723464ebd5Sriastradh case GL_LUMINANCE4: 21733464ebd5Sriastradh case GL_LUMINANCE8: 21743464ebd5Sriastradh case GL_LUMINANCE12: 21753464ebd5Sriastradh case GL_LUMINANCE16: 2176af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 2177af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE : 0; 21783464ebd5Sriastradh case GL_LUMINANCE_ALPHA: 21793464ebd5Sriastradh case GL_LUMINANCE4_ALPHA4: 21803464ebd5Sriastradh case GL_LUMINANCE6_ALPHA2: 21813464ebd5Sriastradh case GL_LUMINANCE8_ALPHA8: 21823464ebd5Sriastradh case GL_LUMINANCE12_ALPHA4: 21833464ebd5Sriastradh case GL_LUMINANCE12_ALPHA12: 21843464ebd5Sriastradh case GL_LUMINANCE16_ALPHA16: 2185af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 2186af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE_ALPHA : 0; 21873464ebd5Sriastradh case GL_INTENSITY: 21883464ebd5Sriastradh case GL_INTENSITY4: 21893464ebd5Sriastradh case GL_INTENSITY8: 21903464ebd5Sriastradh case GL_INTENSITY12: 21913464ebd5Sriastradh case GL_INTENSITY16: 2192af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 2193af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_INTENSITY : 0; 2194af69d88dSmrg case GL_RGB8: 2195af69d88dSmrg return GL_RGB; 21967117f1b4Smrg case GL_RGB: 21977117f1b4Smrg case GL_R3_G3_B2: 21987117f1b4Smrg case GL_RGB4: 21997117f1b4Smrg case GL_RGB5: 22007117f1b4Smrg case GL_RGB10: 22017117f1b4Smrg case GL_RGB12: 22027117f1b4Smrg case GL_RGB16: 2203af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; 22043464ebd5Sriastradh case GL_SRGB8_EXT: 2205af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; 22067117f1b4Smrg case GL_RGBA4: 22077117f1b4Smrg case GL_RGB5_A1: 22087117f1b4Smrg case GL_RGBA8: 2209af69d88dSmrg return GL_RGBA; 2210af69d88dSmrg case GL_RGBA: 2211af69d88dSmrg case GL_RGBA2: 22127117f1b4Smrg case GL_RGBA12: 2213af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0; 221401e04c3fSmrg case GL_RGBA16: 221501e04c3fSmrg return _mesa_is_desktop_gl(ctx) || _mesa_has_EXT_texture_norm16(ctx) 221601e04c3fSmrg ? GL_RGBA : 0; 2217af69d88dSmrg case GL_RGB10_A2: 22183464ebd5Sriastradh case GL_SRGB8_ALPHA8_EXT: 2219af69d88dSmrg return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0; 22207117f1b4Smrg case GL_STENCIL_INDEX: 22217117f1b4Smrg case GL_STENCIL_INDEX1_EXT: 22227117f1b4Smrg case GL_STENCIL_INDEX4_EXT: 22237117f1b4Smrg case GL_STENCIL_INDEX16_EXT: 2224af69d88dSmrg /* There are extensions for GL_STENCIL_INDEX1 and GL_STENCIL_INDEX4 in 2225af69d88dSmrg * OpenGL ES, but Mesa does not currently support them. 2226af69d88dSmrg */ 2227af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_STENCIL_INDEX : 0; 2228af69d88dSmrg case GL_STENCIL_INDEX8_EXT: 22297117f1b4Smrg return GL_STENCIL_INDEX; 22307117f1b4Smrg case GL_DEPTH_COMPONENT: 2231af69d88dSmrg case GL_DEPTH_COMPONENT32: 2232af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_COMPONENT : 0; 22337117f1b4Smrg case GL_DEPTH_COMPONENT16: 22347117f1b4Smrg case GL_DEPTH_COMPONENT24: 22357117f1b4Smrg return GL_DEPTH_COMPONENT; 2236af69d88dSmrg case GL_DEPTH_STENCIL: 2237af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_STENCIL : 0; 2238af69d88dSmrg case GL_DEPTH24_STENCIL8: 2239af69d88dSmrg return GL_DEPTH_STENCIL; 2240af69d88dSmrg case GL_DEPTH_COMPONENT32F: 2241af69d88dSmrg return ctx->Version >= 30 2242af69d88dSmrg || (ctx->API == API_OPENGL_COMPAT && 2243af69d88dSmrg ctx->Extensions.ARB_depth_buffer_float) 2244af69d88dSmrg ? GL_DEPTH_COMPONENT : 0; 2245af69d88dSmrg case GL_DEPTH32F_STENCIL8: 2246af69d88dSmrg return ctx->Version >= 30 2247af69d88dSmrg || (ctx->API == API_OPENGL_COMPAT && 2248af69d88dSmrg ctx->Extensions.ARB_depth_buffer_float) 2249af69d88dSmrg ? GL_DEPTH_STENCIL : 0; 22503464ebd5Sriastradh case GL_RED: 225101e04c3fSmrg return _mesa_has_ARB_texture_rg(ctx) ? GL_RED : 0; 22523464ebd5Sriastradh case GL_R16: 225301e04c3fSmrg return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx) 2254af69d88dSmrg ? GL_RED : 0; 2255af69d88dSmrg case GL_R8: 2256af69d88dSmrg return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg 2257af69d88dSmrg ? GL_RED : 0; 22583464ebd5Sriastradh case GL_RG: 225901e04c3fSmrg return _mesa_has_ARB_texture_rg(ctx) ? GL_RG : 0; 22603464ebd5Sriastradh case GL_RG16: 226101e04c3fSmrg return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx) 2262af69d88dSmrg ? GL_RG : 0; 2263af69d88dSmrg case GL_RG8: 2264af69d88dSmrg return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg 2265af69d88dSmrg ? GL_RG : 0; 22663464ebd5Sriastradh /* signed normalized texture formats */ 22673464ebd5Sriastradh case GL_R8_SNORM: 226801e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx) 226901e04c3fSmrg ? GL_RED : 0; 227001e04c3fSmrg case GL_RED_SNORM: 227101e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) ? GL_RED : 0; 22723464ebd5Sriastradh case GL_R16_SNORM: 227301e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || 227401e04c3fSmrg (_mesa_has_EXT_render_snorm(ctx) && 227501e04c3fSmrg _mesa_has_EXT_texture_norm16(ctx)) 2276af69d88dSmrg ? GL_RED : 0; 22773464ebd5Sriastradh case GL_RG8_SNORM: 227801e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx) 227901e04c3fSmrg ? GL_RG : 0; 228001e04c3fSmrg case GL_RG_SNORM: 228101e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) ? GL_RG : 0; 22823464ebd5Sriastradh case GL_RG16_SNORM: 228301e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || 228401e04c3fSmrg (_mesa_has_EXT_render_snorm(ctx) && 228501e04c3fSmrg _mesa_has_EXT_texture_norm16(ctx)) 2286af69d88dSmrg ? GL_RG : 0; 22873464ebd5Sriastradh case GL_RGB_SNORM: 22883464ebd5Sriastradh case GL_RGB8_SNORM: 22893464ebd5Sriastradh case GL_RGB16_SNORM: 2290af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 2291af69d88dSmrg ? GL_RGB : 0; 22923464ebd5Sriastradh case GL_RGBA8_SNORM: 229301e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx) 229401e04c3fSmrg ? GL_RGBA : 0; 229501e04c3fSmrg case GL_RGBA_SNORM: 229601e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) ? GL_RGBA : 0; 22973464ebd5Sriastradh case GL_RGBA16_SNORM: 229801e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || 229901e04c3fSmrg (_mesa_has_EXT_render_snorm(ctx) && 230001e04c3fSmrg _mesa_has_EXT_texture_norm16(ctx)) 2301af69d88dSmrg ? GL_RGBA : 0; 23023464ebd5Sriastradh case GL_ALPHA_SNORM: 23033464ebd5Sriastradh case GL_ALPHA8_SNORM: 23043464ebd5Sriastradh case GL_ALPHA16_SNORM: 2305af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2306af69d88dSmrg ctx->Extensions.EXT_texture_snorm && 23073464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; 23083464ebd5Sriastradh case GL_LUMINANCE_SNORM: 23093464ebd5Sriastradh case GL_LUMINANCE8_SNORM: 23103464ebd5Sriastradh case GL_LUMINANCE16_SNORM: 2311af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 2312af69d88dSmrg ? GL_LUMINANCE : 0; 23133464ebd5Sriastradh case GL_LUMINANCE_ALPHA_SNORM: 23143464ebd5Sriastradh case GL_LUMINANCE8_ALPHA8_SNORM: 23153464ebd5Sriastradh case GL_LUMINANCE16_ALPHA16_SNORM: 2316af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 2317af69d88dSmrg ? GL_LUMINANCE_ALPHA : 0; 23183464ebd5Sriastradh case GL_INTENSITY_SNORM: 23193464ebd5Sriastradh case GL_INTENSITY8_SNORM: 23203464ebd5Sriastradh case GL_INTENSITY16_SNORM: 2321af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 2322af69d88dSmrg ? GL_INTENSITY : 0; 2323af69d88dSmrg 23243464ebd5Sriastradh case GL_R16F: 23257ec681f3Smrg return ((_mesa_is_desktop_gl(ctx) && 23267ec681f3Smrg ctx->Extensions.ARB_texture_rg && 23277ec681f3Smrg ctx->Extensions.ARB_texture_float) || 23287ec681f3Smrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ || 23297ec681f3Smrg (_mesa_has_EXT_color_buffer_half_float(ctx) && 23307ec681f3Smrg _mesa_has_EXT_texture_rg(ctx))) 23317ec681f3Smrg ? GL_RED : 0; 23323464ebd5Sriastradh case GL_R32F: 2333af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && 2334af69d88dSmrg ctx->Extensions.ARB_texture_rg && 2335af69d88dSmrg ctx->Extensions.ARB_texture_float) || 2336af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 2337af69d88dSmrg ? GL_RED : 0; 23383464ebd5Sriastradh case GL_RG16F: 23397ec681f3Smrg return ((_mesa_is_desktop_gl(ctx) && 23407ec681f3Smrg ctx->Extensions.ARB_texture_rg && 23417ec681f3Smrg ctx->Extensions.ARB_texture_float) || 23427ec681f3Smrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ || 23437ec681f3Smrg (_mesa_has_EXT_color_buffer_half_float(ctx) && 23447ec681f3Smrg _mesa_has_EXT_texture_rg(ctx))) 23457ec681f3Smrg ? GL_RG : 0; 23463464ebd5Sriastradh case GL_RG32F: 2347af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && 2348af69d88dSmrg ctx->Extensions.ARB_texture_rg && 2349af69d88dSmrg ctx->Extensions.ARB_texture_float) || 2350af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 2351af69d88dSmrg ? GL_RG : 0; 23523464ebd5Sriastradh case GL_RGB16F: 23537ec681f3Smrg return (_mesa_has_ARB_texture_float(ctx) || 23547ec681f3Smrg _mesa_has_EXT_color_buffer_half_float(ctx)) 23557ec681f3Smrg ? GL_RGB : 0; 23563464ebd5Sriastradh case GL_RGB32F: 2357af69d88dSmrg return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float) 2358af69d88dSmrg ? GL_RGB : 0; 23593464ebd5Sriastradh case GL_RGBA16F: 23607ec681f3Smrg return (_mesa_has_ARB_texture_float(ctx) || 23617ec681f3Smrg _mesa_is_gles3(ctx) || 23627ec681f3Smrg _mesa_has_EXT_color_buffer_half_float(ctx)) 23637ec681f3Smrg ? GL_RGBA : 0; 23643464ebd5Sriastradh case GL_RGBA32F: 2365af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && 2366af69d88dSmrg ctx->Extensions.ARB_texture_float) || 2367af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 2368af69d88dSmrg ? GL_RGBA : 0; 236901e04c3fSmrg case GL_RGB9_E5: 237001e04c3fSmrg return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_shared_exponent) 237101e04c3fSmrg ? GL_RGB: 0; 23723464ebd5Sriastradh case GL_ALPHA16F_ARB: 23733464ebd5Sriastradh case GL_ALPHA32F_ARB: 2374af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2375af69d88dSmrg ctx->Extensions.ARB_texture_float && 23763464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; 23773464ebd5Sriastradh case GL_LUMINANCE16F_ARB: 23783464ebd5Sriastradh case GL_LUMINANCE32F_ARB: 2379af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2380af69d88dSmrg ctx->Extensions.ARB_texture_float && 23813464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; 23823464ebd5Sriastradh case GL_LUMINANCE_ALPHA16F_ARB: 23833464ebd5Sriastradh case GL_LUMINANCE_ALPHA32F_ARB: 2384af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2385af69d88dSmrg ctx->Extensions.ARB_texture_float && 23863464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; 23873464ebd5Sriastradh case GL_INTENSITY16F_ARB: 23883464ebd5Sriastradh case GL_INTENSITY32F_ARB: 2389af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2390af69d88dSmrg ctx->Extensions.ARB_texture_float && 23913464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; 23923464ebd5Sriastradh case GL_R11F_G11F_B10F: 2393af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) || 2394af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 2395af69d88dSmrg ? GL_RGB : 0; 2396af69d88dSmrg 2397af69d88dSmrg case GL_RGBA8UI_EXT: 2398af69d88dSmrg case GL_RGBA16UI_EXT: 2399af69d88dSmrg case GL_RGBA32UI_EXT: 2400af69d88dSmrg case GL_RGBA8I_EXT: 2401af69d88dSmrg case GL_RGBA16I_EXT: 2402af69d88dSmrg case GL_RGBA32I_EXT: 2403af69d88dSmrg return ctx->Version >= 30 2404af69d88dSmrg || (_mesa_is_desktop_gl(ctx) && 2405af69d88dSmrg ctx->Extensions.EXT_texture_integer) ? GL_RGBA : 0; 2406af69d88dSmrg 2407af69d88dSmrg case GL_RGB8UI_EXT: 2408af69d88dSmrg case GL_RGB16UI_EXT: 2409af69d88dSmrg case GL_RGB32UI_EXT: 2410af69d88dSmrg case GL_RGB8I_EXT: 2411af69d88dSmrg case GL_RGB16I_EXT: 2412af69d88dSmrg case GL_RGB32I_EXT: 2413af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_integer 2414af69d88dSmrg ? GL_RGB : 0; 2415af69d88dSmrg case GL_R8UI: 2416af69d88dSmrg case GL_R8I: 2417af69d88dSmrg case GL_R16UI: 2418af69d88dSmrg case GL_R16I: 2419af69d88dSmrg case GL_R32UI: 2420af69d88dSmrg case GL_R32I: 2421af69d88dSmrg return ctx->Version >= 30 2422af69d88dSmrg || (_mesa_is_desktop_gl(ctx) && 2423af69d88dSmrg ctx->Extensions.ARB_texture_rg && 2424af69d88dSmrg ctx->Extensions.EXT_texture_integer) ? GL_RED : 0; 2425af69d88dSmrg 2426af69d88dSmrg case GL_RG8UI: 2427af69d88dSmrg case GL_RG8I: 2428af69d88dSmrg case GL_RG16UI: 2429af69d88dSmrg case GL_RG16I: 2430af69d88dSmrg case GL_RG32UI: 2431af69d88dSmrg case GL_RG32I: 2432af69d88dSmrg return ctx->Version >= 30 2433af69d88dSmrg || (_mesa_is_desktop_gl(ctx) && 2434af69d88dSmrg ctx->Extensions.ARB_texture_rg && 2435af69d88dSmrg ctx->Extensions.EXT_texture_integer) ? GL_RG : 0; 2436af69d88dSmrg 2437af69d88dSmrg case GL_INTENSITY8I_EXT: 2438af69d88dSmrg case GL_INTENSITY8UI_EXT: 2439af69d88dSmrg case GL_INTENSITY16I_EXT: 2440af69d88dSmrg case GL_INTENSITY16UI_EXT: 2441af69d88dSmrg case GL_INTENSITY32I_EXT: 2442af69d88dSmrg case GL_INTENSITY32UI_EXT: 2443af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2444af69d88dSmrg ctx->Extensions.EXT_texture_integer && 2445af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; 2446af69d88dSmrg 2447af69d88dSmrg case GL_LUMINANCE8I_EXT: 2448af69d88dSmrg case GL_LUMINANCE8UI_EXT: 2449af69d88dSmrg case GL_LUMINANCE16I_EXT: 2450af69d88dSmrg case GL_LUMINANCE16UI_EXT: 2451af69d88dSmrg case GL_LUMINANCE32I_EXT: 2452af69d88dSmrg case GL_LUMINANCE32UI_EXT: 2453af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2454af69d88dSmrg ctx->Extensions.EXT_texture_integer && 2455af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; 2456af69d88dSmrg 2457af69d88dSmrg case GL_LUMINANCE_ALPHA8I_EXT: 2458af69d88dSmrg case GL_LUMINANCE_ALPHA8UI_EXT: 2459af69d88dSmrg case GL_LUMINANCE_ALPHA16I_EXT: 2460af69d88dSmrg case GL_LUMINANCE_ALPHA16UI_EXT: 2461af69d88dSmrg case GL_LUMINANCE_ALPHA32I_EXT: 2462af69d88dSmrg case GL_LUMINANCE_ALPHA32UI_EXT: 2463af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2464af69d88dSmrg ctx->Extensions.EXT_texture_integer && 2465af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; 2466af69d88dSmrg 2467af69d88dSmrg case GL_ALPHA8I_EXT: 2468af69d88dSmrg case GL_ALPHA8UI_EXT: 2469af69d88dSmrg case GL_ALPHA16I_EXT: 2470af69d88dSmrg case GL_ALPHA16UI_EXT: 2471af69d88dSmrg case GL_ALPHA32I_EXT: 2472af69d88dSmrg case GL_ALPHA32UI_EXT: 2473af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2474af69d88dSmrg ctx->Extensions.EXT_texture_integer && 2475af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; 2476af69d88dSmrg 2477af69d88dSmrg case GL_RGB10_A2UI: 2478af69d88dSmrg return (_mesa_is_desktop_gl(ctx) && 2479af69d88dSmrg ctx->Extensions.ARB_texture_rgb10_a2ui) 2480af69d88dSmrg || _mesa_is_gles3(ctx) ? GL_RGBA : 0; 2481af69d88dSmrg 2482af69d88dSmrg case GL_RGB565: 2483af69d88dSmrg return _mesa_is_gles(ctx) || ctx->Extensions.ARB_ES2_compatibility 2484af69d88dSmrg ? GL_RGB : 0; 2485af69d88dSmrg default: 2486af69d88dSmrg return 0; 2487af69d88dSmrg } 24887117f1b4Smrg} 24897117f1b4Smrg 24907117f1b4Smrg 24913464ebd5Sriastradh/** 24923464ebd5Sriastradh * Invalidate a renderbuffer attachment. Called from _mesa_HashWalk(). 24933464ebd5Sriastradh */ 24943464ebd5Sriastradhstatic void 24957ec681f3Smrginvalidate_rb(void *data, void *userData) 24963464ebd5Sriastradh{ 24973464ebd5Sriastradh struct gl_framebuffer *fb = (struct gl_framebuffer *) data; 24983464ebd5Sriastradh struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData; 24993464ebd5Sriastradh 25003464ebd5Sriastradh /* If this is a user-created FBO */ 2501af69d88dSmrg if (_mesa_is_user_fbo(fb)) { 25023464ebd5Sriastradh GLuint i; 25033464ebd5Sriastradh for (i = 0; i < BUFFER_COUNT; i++) { 25043464ebd5Sriastradh struct gl_renderbuffer_attachment *att = fb->Attachment + i; 25053464ebd5Sriastradh if (att->Type == GL_RENDERBUFFER && 25063464ebd5Sriastradh att->Renderbuffer == rb) { 25073464ebd5Sriastradh /* Mark fb status as indeterminate to force re-validation */ 25083464ebd5Sriastradh fb->_Status = 0; 25093464ebd5Sriastradh return; 25103464ebd5Sriastradh } 25113464ebd5Sriastradh } 25123464ebd5Sriastradh } 25133464ebd5Sriastradh} 25143464ebd5Sriastradh 25153464ebd5Sriastradh 25164a49301eSmrg/** sentinal value, see below */ 25174a49301eSmrg#define NO_SAMPLES 1000 25184a49301eSmrg 251901e04c3fSmrgvoid 252001e04c3fSmrg_mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 252101e04c3fSmrg GLenum internalFormat, GLsizei width, 252201e04c3fSmrg GLsizei height, GLsizei samples, 252301e04c3fSmrg GLsizei storageSamples) 25247117f1b4Smrg{ 252501e04c3fSmrg const GLenum baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 252601e04c3fSmrg 252701e04c3fSmrg assert(baseFormat != 0); 252801e04c3fSmrg assert(width >= 0 && width <= (GLsizei) ctx->Const.MaxRenderbufferSize); 252901e04c3fSmrg assert(height >= 0 && height <= (GLsizei) ctx->Const.MaxRenderbufferSize); 253001e04c3fSmrg assert(samples != NO_SAMPLES); 253101e04c3fSmrg if (samples != 0) { 253201e04c3fSmrg assert(samples > 0); 253301e04c3fSmrg assert(_mesa_check_sample_count(ctx, GL_RENDERBUFFER, 253401e04c3fSmrg internalFormat, samples, 253501e04c3fSmrg storageSamples) == GL_NO_ERROR); 25367117f1b4Smrg } 25377117f1b4Smrg 25387ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0); 25397117f1b4Smrg 254001e04c3fSmrg if (rb->InternalFormat == internalFormat && 254101e04c3fSmrg rb->Width == (GLuint) width && 254201e04c3fSmrg rb->Height == (GLuint) height && 254301e04c3fSmrg rb->NumSamples == samples && 254401e04c3fSmrg rb->NumStorageSamples == storageSamples) { 254501e04c3fSmrg /* no change in allocation needed */ 25467117f1b4Smrg return; 25477117f1b4Smrg } 25487117f1b4Smrg 25497117f1b4Smrg /* These MUST get set by the AllocStorage func */ 25504a49301eSmrg rb->Format = MESA_FORMAT_NONE; 25514a49301eSmrg rb->NumSamples = samples; 255201e04c3fSmrg rb->NumStorageSamples = storageSamples; 25537117f1b4Smrg 25547117f1b4Smrg /* Now allocate the storage */ 255501e04c3fSmrg assert(rb->AllocStorage); 25567117f1b4Smrg if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 25577117f1b4Smrg /* No error - check/set fields now */ 2558af69d88dSmrg /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */ 25597117f1b4Smrg assert(rb->Width == (GLuint) width); 25607117f1b4Smrg assert(rb->Height == (GLuint) height); 25617117f1b4Smrg rb->InternalFormat = internalFormat; 2562cdc920a0Smrg rb->_BaseFormat = baseFormat; 25634a49301eSmrg assert(rb->_BaseFormat != 0); 25647117f1b4Smrg } 25657117f1b4Smrg else { 25667117f1b4Smrg /* Probably ran out of memory - clear the fields */ 25677117f1b4Smrg rb->Width = 0; 25687117f1b4Smrg rb->Height = 0; 25694a49301eSmrg rb->Format = MESA_FORMAT_NONE; 25707117f1b4Smrg rb->InternalFormat = GL_NONE; 25717117f1b4Smrg rb->_BaseFormat = GL_NONE; 25724a49301eSmrg rb->NumSamples = 0; 257301e04c3fSmrg rb->NumStorageSamples = 0; 25747117f1b4Smrg } 25757117f1b4Smrg 25763464ebd5Sriastradh /* Invalidate the framebuffers the renderbuffer is attached in. */ 25773464ebd5Sriastradh if (rb->AttachedAnytime) { 25783464ebd5Sriastradh _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb); 25793464ebd5Sriastradh } 25807117f1b4Smrg} 25817117f1b4Smrg 258201e04c3fSmrg/** 258301e04c3fSmrg * Helper function used by renderbuffer_storage_direct() and 258401e04c3fSmrg * renderbuffer_storage_target(). 258501e04c3fSmrg * samples will be NO_SAMPLES if called by a non-multisample function. 258601e04c3fSmrg */ 258701e04c3fSmrgstatic void 258801e04c3fSmrgrenderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 258901e04c3fSmrg GLenum internalFormat, GLsizei width, 259001e04c3fSmrg GLsizei height, GLsizei samples, GLsizei storageSamples, 259101e04c3fSmrg const char *func) 259201e04c3fSmrg{ 259301e04c3fSmrg GLenum baseFormat; 259401e04c3fSmrg GLenum sample_count_error; 259501e04c3fSmrg 259601e04c3fSmrg baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 259701e04c3fSmrg if (baseFormat == 0) { 259801e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)", 259901e04c3fSmrg func, _mesa_enum_to_string(internalFormat)); 260001e04c3fSmrg return; 260101e04c3fSmrg } 260201e04c3fSmrg 260301e04c3fSmrg if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { 260401e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid width %d)", func, 260501e04c3fSmrg width); 260601e04c3fSmrg return; 260701e04c3fSmrg } 260801e04c3fSmrg 260901e04c3fSmrg if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { 261001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid height %d)", func, 261101e04c3fSmrg height); 261201e04c3fSmrg return; 261301e04c3fSmrg } 261401e04c3fSmrg 261501e04c3fSmrg if (samples == NO_SAMPLES) { 261601e04c3fSmrg /* NumSamples == 0 indicates non-multisampling */ 261701e04c3fSmrg samples = 0; 261801e04c3fSmrg storageSamples = 0; 261901e04c3fSmrg } 262001e04c3fSmrg else { 262101e04c3fSmrg /* check the sample count; 262201e04c3fSmrg * note: driver may choose to use more samples than what's requested 262301e04c3fSmrg */ 262401e04c3fSmrg sample_count_error = _mesa_check_sample_count(ctx, GL_RENDERBUFFER, 262501e04c3fSmrg internalFormat, samples, storageSamples); 262601e04c3fSmrg 262701e04c3fSmrg /* Section 2.5 (GL Errors) of OpenGL 3.0 specification, page 16: 262801e04c3fSmrg * 262901e04c3fSmrg * "If a negative number is provided where an argument of type sizei or 263001e04c3fSmrg * sizeiptr is specified, the error INVALID VALUE is generated." 263101e04c3fSmrg */ 263201e04c3fSmrg if (samples < 0 || storageSamples < 0) { 263301e04c3fSmrg sample_count_error = GL_INVALID_VALUE; 263401e04c3fSmrg } 263501e04c3fSmrg 263601e04c3fSmrg if (sample_count_error != GL_NO_ERROR) { 263701e04c3fSmrg _mesa_error(ctx, sample_count_error, 263801e04c3fSmrg "%s(samples=%d, storageSamples=%d)", func, samples, 263901e04c3fSmrg storageSamples); 264001e04c3fSmrg return; 264101e04c3fSmrg } 264201e04c3fSmrg } 264301e04c3fSmrg 264401e04c3fSmrg _mesa_renderbuffer_storage(ctx, rb, internalFormat, width, height, samples, 264501e04c3fSmrg storageSamples); 264601e04c3fSmrg} 264701e04c3fSmrg 264801e04c3fSmrg/** 264901e04c3fSmrg * Helper function used by _mesa_NamedRenderbufferStorage*(). 265001e04c3fSmrg * samples will be NO_SAMPLES if called by a non-multisample function. 265101e04c3fSmrg */ 265201e04c3fSmrgstatic void 265301e04c3fSmrgrenderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat, 265401e04c3fSmrg GLsizei width, GLsizei height, GLsizei samples, 265501e04c3fSmrg GLsizei storageSamples, const char *func) 265601e04c3fSmrg{ 265701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 265801e04c3fSmrg 265901e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 266001e04c3fSmrg if (samples == NO_SAMPLES) 266101e04c3fSmrg _mesa_debug(ctx, "%s(%u, %s, %d, %d)\n", 266201e04c3fSmrg func, renderbuffer, 266301e04c3fSmrg _mesa_enum_to_string(internalFormat), 266401e04c3fSmrg width, height); 266501e04c3fSmrg else 266601e04c3fSmrg _mesa_debug(ctx, "%s(%u, %s, %d, %d, %d)\n", 266701e04c3fSmrg func, renderbuffer, 266801e04c3fSmrg _mesa_enum_to_string(internalFormat), 266901e04c3fSmrg width, height, samples); 267001e04c3fSmrg } 267101e04c3fSmrg 267201e04c3fSmrg struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 267301e04c3fSmrg if (!rb || rb == &DummyRenderbuffer) { 267401e04c3fSmrg /* ID was reserved, but no real renderbuffer object made yet */ 267501e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid renderbuffer %u)", 267601e04c3fSmrg func, renderbuffer); 267701e04c3fSmrg return; 267801e04c3fSmrg } 267901e04c3fSmrg 268001e04c3fSmrg renderbuffer_storage(ctx, rb, internalFormat, width, height, samples, 268101e04c3fSmrg storageSamples, func); 268201e04c3fSmrg} 268301e04c3fSmrg 268401e04c3fSmrg/** 268501e04c3fSmrg * Helper function used by _mesa_RenderbufferStorage() and 268601e04c3fSmrg * _mesa_RenderbufferStorageMultisample(). 268701e04c3fSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorage(). 268801e04c3fSmrg */ 268901e04c3fSmrgstatic void 269001e04c3fSmrgrenderbuffer_storage_target(GLenum target, GLenum internalFormat, 269101e04c3fSmrg GLsizei width, GLsizei height, GLsizei samples, 269201e04c3fSmrg GLsizei storageSamples, const char *func) 269301e04c3fSmrg{ 269401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 269501e04c3fSmrg 269601e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 269701e04c3fSmrg if (samples == NO_SAMPLES) 269801e04c3fSmrg _mesa_debug(ctx, "%s(%s, %s, %d, %d)\n", 269901e04c3fSmrg func, 270001e04c3fSmrg _mesa_enum_to_string(target), 270101e04c3fSmrg _mesa_enum_to_string(internalFormat), 270201e04c3fSmrg width, height); 270301e04c3fSmrg else 270401e04c3fSmrg _mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n", 270501e04c3fSmrg func, 270601e04c3fSmrg _mesa_enum_to_string(target), 270701e04c3fSmrg _mesa_enum_to_string(internalFormat), 270801e04c3fSmrg width, height, samples); 270901e04c3fSmrg } 271001e04c3fSmrg 271101e04c3fSmrg if (target != GL_RENDERBUFFER_EXT) { 271201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 271301e04c3fSmrg return; 271401e04c3fSmrg } 271501e04c3fSmrg 271601e04c3fSmrg if (!ctx->CurrentRenderbuffer) { 271701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no renderbuffer bound)", 271801e04c3fSmrg func); 271901e04c3fSmrg return; 272001e04c3fSmrg } 272101e04c3fSmrg 272201e04c3fSmrg renderbuffer_storage(ctx, ctx->CurrentRenderbuffer, internalFormat, width, 272301e04c3fSmrg height, samples, storageSamples, func); 272401e04c3fSmrg} 272501e04c3fSmrg 27263464ebd5Sriastradh 2727cdc920a0Smrgvoid GLAPIENTRY 27283464ebd5Sriastradh_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) 2729cdc920a0Smrg{ 2730cdc920a0Smrg struct gl_renderbuffer *rb; 2731cdc920a0Smrg GET_CURRENT_CONTEXT(ctx); 2732cdc920a0Smrg 27333464ebd5Sriastradh if (!ctx->Extensions.OES_EGL_image) { 27343464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 27353464ebd5Sriastradh "glEGLImageTargetRenderbufferStorageOES(unsupported)"); 27363464ebd5Sriastradh return; 27373464ebd5Sriastradh } 27383464ebd5Sriastradh 2739cdc920a0Smrg if (target != GL_RENDERBUFFER) { 27403464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_ENUM, 27413464ebd5Sriastradh "EGLImageTargetRenderbufferStorageOES"); 2742cdc920a0Smrg return; 2743cdc920a0Smrg } 2744cdc920a0Smrg 2745cdc920a0Smrg rb = ctx->CurrentRenderbuffer; 2746cdc920a0Smrg if (!rb) { 27473464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 27483464ebd5Sriastradh "EGLImageTargetRenderbufferStorageOES"); 2749cdc920a0Smrg return; 2750cdc920a0Smrg } 2751cdc920a0Smrg 27527ec681f3Smrg if (!image || (ctx->Driver.ValidateEGLImage && 27537ec681f3Smrg !ctx->Driver.ValidateEGLImage(ctx, image))) { 27547ec681f3Smrg _mesa_error(ctx, GL_INVALID_VALUE, 27557ec681f3Smrg "EGLImageTargetRenderbufferStorageOES"); 27567ec681f3Smrg return; 27577ec681f3Smrg } 27587ec681f3Smrg 27597ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0); 2760cdc920a0Smrg 2761cdc920a0Smrg ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); 2762cdc920a0Smrg} 27637117f1b4Smrg 27643464ebd5Sriastradh 27654a49301eSmrg/** 2766af69d88dSmrg * Helper function for _mesa_GetRenderbufferParameteriv() and 2767af69d88dSmrg * _mesa_GetFramebufferAttachmentParameteriv() 27684a49301eSmrg * We have to be careful to respect the base format. For example, if a 27694a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the 27704a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE 27714a49301eSmrg * we need to return zero. 27724a49301eSmrg */ 27734a49301eSmrgstatic GLint 2774af69d88dSmrgget_component_bits(GLenum pname, GLenum baseFormat, mesa_format format) 27754a49301eSmrg{ 2776af69d88dSmrg if (_mesa_base_format_has_channel(baseFormat, pname)) 2777af69d88dSmrg return _mesa_get_format_bits(format, pname); 2778af69d88dSmrg else 27794a49301eSmrg return 0; 27804a49301eSmrg} 27814a49301eSmrg 27824a49301eSmrg 27834a49301eSmrg 27844a49301eSmrgvoid GLAPIENTRY 2785af69d88dSmrg_mesa_RenderbufferStorage(GLenum target, GLenum internalFormat, 27864a49301eSmrg GLsizei width, GLsizei height) 27874a49301eSmrg{ 27884a49301eSmrg /* GL_ARB_fbo says calling this function is equivalent to calling 27894a49301eSmrg * glRenderbufferStorageMultisample() with samples=0. We pass in 27904a49301eSmrg * a token value here just for error reporting purposes. 27914a49301eSmrg */ 279201e04c3fSmrg renderbuffer_storage_target(target, internalFormat, width, height, 279301e04c3fSmrg NO_SAMPLES, 0, "glRenderbufferStorage"); 27944a49301eSmrg} 27954a49301eSmrg 27964a49301eSmrg 27974a49301eSmrgvoid GLAPIENTRY 27984a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, 27994a49301eSmrg GLenum internalFormat, 28004a49301eSmrg GLsizei width, GLsizei height) 28014a49301eSmrg{ 280201e04c3fSmrg renderbuffer_storage_target(target, internalFormat, width, height, 280301e04c3fSmrg samples, samples, 280401e04c3fSmrg "glRenderbufferStorageMultisample"); 280501e04c3fSmrg} 280601e04c3fSmrg 280701e04c3fSmrg 280801e04c3fSmrgvoid GLAPIENTRY 280901e04c3fSmrg_mesa_RenderbufferStorageMultisampleAdvancedAMD( 281001e04c3fSmrg GLenum target, GLsizei samples, GLsizei storageSamples, 281101e04c3fSmrg GLenum internalFormat, GLsizei width, GLsizei height) 281201e04c3fSmrg{ 281301e04c3fSmrg renderbuffer_storage_target(target, internalFormat, width, height, 281401e04c3fSmrg samples, storageSamples, 281501e04c3fSmrg "glRenderbufferStorageMultisampleAdvancedAMD"); 28164a49301eSmrg} 28174a49301eSmrg 28184a49301eSmrg 28193464ebd5Sriastradh/** 28203464ebd5Sriastradh * OpenGL ES version of glRenderBufferStorage. 28213464ebd5Sriastradh */ 28223464ebd5Sriastradhvoid GLAPIENTRY 28233464ebd5Sriastradh_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 282401e04c3fSmrg GLsizei width, GLsizei height) 28253464ebd5Sriastradh{ 28263464ebd5Sriastradh switch (internalFormat) { 28273464ebd5Sriastradh case GL_RGB565: 28283464ebd5Sriastradh /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */ 28293464ebd5Sriastradh /* choose a closest format */ 28303464ebd5Sriastradh internalFormat = GL_RGB5; 28313464ebd5Sriastradh break; 28323464ebd5Sriastradh default: 28333464ebd5Sriastradh break; 28343464ebd5Sriastradh } 28353464ebd5Sriastradh 283601e04c3fSmrg renderbuffer_storage_target(target, internalFormat, width, height, 0, 0, 283701e04c3fSmrg "glRenderbufferStorageEXT"); 28383464ebd5Sriastradh} 28393464ebd5Sriastradh 284001e04c3fSmrgvoid GLAPIENTRY 284101e04c3fSmrg_mesa_NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, 284201e04c3fSmrg GLsizei width, GLsizei height) 284301e04c3fSmrg{ 284401e04c3fSmrg /* GL_ARB_fbo says calling this function is equivalent to calling 284501e04c3fSmrg * glRenderbufferStorageMultisample() with samples=0. We pass in 284601e04c3fSmrg * a token value here just for error reporting purposes. 284701e04c3fSmrg */ 284801e04c3fSmrg renderbuffer_storage_named(renderbuffer, internalformat, width, height, 284901e04c3fSmrg NO_SAMPLES, 0, "glNamedRenderbufferStorage"); 285001e04c3fSmrg} 28514a49301eSmrg 28527ec681f3Smrgvoid GLAPIENTRY 28537ec681f3Smrg_mesa_NamedRenderbufferStorageEXT(GLuint renderbuffer, GLenum internalformat, 28547ec681f3Smrg GLsizei width, GLsizei height) 28557ec681f3Smrg{ 28567ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 28577ec681f3Smrg struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 28587ec681f3Smrg if (!rb || rb == &DummyRenderbuffer) { 28597ec681f3Smrg _mesa_HashLockMutex(ctx->Shared->RenderBuffers); 28607ec681f3Smrg rb = allocate_renderbuffer_locked(ctx, renderbuffer, rb != NULL, 28617ec681f3Smrg "glNamedRenderbufferStorageEXT"); 28627ec681f3Smrg _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); 28637ec681f3Smrg } 28647ec681f3Smrg renderbuffer_storage(ctx, rb, internalformat, width, height, NO_SAMPLES, 28657ec681f3Smrg 0, "glNamedRenderbufferStorageEXT"); 28667ec681f3Smrg} 28677ec681f3Smrg 28687ec681f3Smrg 28697117f1b4Smrgvoid GLAPIENTRY 287001e04c3fSmrg_mesa_NamedRenderbufferStorageMultisample(GLuint renderbuffer, GLsizei samples, 287101e04c3fSmrg GLenum internalformat, 287201e04c3fSmrg GLsizei width, GLsizei height) 28737117f1b4Smrg{ 287401e04c3fSmrg renderbuffer_storage_named(renderbuffer, internalformat, width, height, 287501e04c3fSmrg samples, samples, 287601e04c3fSmrg "glNamedRenderbufferStorageMultisample"); 287701e04c3fSmrg} 28787117f1b4Smrg 28797117f1b4Smrg 28807ec681f3Smrgvoid GLAPIENTRY 28817ec681f3Smrg_mesa_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer, GLsizei samples, 28827ec681f3Smrg GLenum internalformat, 28837ec681f3Smrg GLsizei width, GLsizei height) 28847ec681f3Smrg{ 28857ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 28867ec681f3Smrg struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 28877ec681f3Smrg if (!rb || rb == &DummyRenderbuffer) { 28887ec681f3Smrg _mesa_HashLockMutex(ctx->Shared->RenderBuffers); 28897ec681f3Smrg rb = allocate_renderbuffer_locked(ctx, renderbuffer, rb != NULL, 28907ec681f3Smrg "glNamedRenderbufferStorageMultisampleEXT"); 28917ec681f3Smrg _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); 28927ec681f3Smrg } 28937ec681f3Smrg renderbuffer_storage(ctx, rb, internalformat, width, height, 28947ec681f3Smrg samples, samples, 28957ec681f3Smrg "glNamedRenderbufferStorageMultisample"); 28967ec681f3Smrg} 28977ec681f3Smrg 28987ec681f3Smrg 289901e04c3fSmrgvoid GLAPIENTRY 290001e04c3fSmrg_mesa_NamedRenderbufferStorageMultisampleAdvancedAMD( 290101e04c3fSmrg GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, 290201e04c3fSmrg GLenum internalformat, GLsizei width, GLsizei height) 290301e04c3fSmrg{ 290401e04c3fSmrg renderbuffer_storage_named(renderbuffer, internalformat, width, height, 290501e04c3fSmrg samples, storageSamples, 290601e04c3fSmrg "glNamedRenderbufferStorageMultisampleAdvancedAMD"); 290701e04c3fSmrg} 290801e04c3fSmrg 29097117f1b4Smrg 291001e04c3fSmrgstatic void 291101e04c3fSmrgget_render_buffer_parameteriv(struct gl_context *ctx, 291201e04c3fSmrg struct gl_renderbuffer *rb, GLenum pname, 291301e04c3fSmrg GLint *params, const char *func) 291401e04c3fSmrg{ 29154a49301eSmrg /* No need to flush here since we're just quering state which is 29164a49301eSmrg * not effected by rendering. 29174a49301eSmrg */ 29187117f1b4Smrg 29197117f1b4Smrg switch (pname) { 29207117f1b4Smrg case GL_RENDERBUFFER_WIDTH_EXT: 29214a49301eSmrg *params = rb->Width; 29227117f1b4Smrg return; 29237117f1b4Smrg case GL_RENDERBUFFER_HEIGHT_EXT: 29244a49301eSmrg *params = rb->Height; 29257117f1b4Smrg return; 29267117f1b4Smrg case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 29274a49301eSmrg *params = rb->InternalFormat; 29287117f1b4Smrg return; 29297117f1b4Smrg case GL_RENDERBUFFER_RED_SIZE_EXT: 29307117f1b4Smrg case GL_RENDERBUFFER_GREEN_SIZE_EXT: 29317117f1b4Smrg case GL_RENDERBUFFER_BLUE_SIZE_EXT: 29327117f1b4Smrg case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 29337117f1b4Smrg case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 29347117f1b4Smrg case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 29354a49301eSmrg *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); 293601e04c3fSmrg return; 29374a49301eSmrg case GL_RENDERBUFFER_SAMPLES: 2938af69d88dSmrg if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object) 2939af69d88dSmrg || _mesa_is_gles3(ctx)) { 29404a49301eSmrg *params = rb->NumSamples; 294101e04c3fSmrg return; 29424a49301eSmrg } 294301e04c3fSmrg break; 294401e04c3fSmrg case GL_RENDERBUFFER_STORAGE_SAMPLES_AMD: 294501e04c3fSmrg if (ctx->Extensions.AMD_framebuffer_multisample_advanced) { 294601e04c3fSmrg *params = rb->NumStorageSamples; 294701e04c3fSmrg return; 294801e04c3fSmrg } 294901e04c3fSmrg break; 295001e04c3fSmrg } 295101e04c3fSmrg 295201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname=%s)", func, 295301e04c3fSmrg _mesa_enum_to_string(pname)); 295401e04c3fSmrg} 295501e04c3fSmrg 295601e04c3fSmrg 295701e04c3fSmrgvoid GLAPIENTRY 295801e04c3fSmrg_mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) 295901e04c3fSmrg{ 296001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 296101e04c3fSmrg 296201e04c3fSmrg if (target != GL_RENDERBUFFER_EXT) { 29637117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 29647117f1b4Smrg "glGetRenderbufferParameterivEXT(target)"); 29657117f1b4Smrg return; 29667117f1b4Smrg } 296701e04c3fSmrg 296801e04c3fSmrg if (!ctx->CurrentRenderbuffer) { 296901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetRenderbufferParameterivEXT" 297001e04c3fSmrg "(no renderbuffer bound)"); 297101e04c3fSmrg return; 297201e04c3fSmrg } 297301e04c3fSmrg 297401e04c3fSmrg get_render_buffer_parameteriv(ctx, ctx->CurrentRenderbuffer, pname, 297501e04c3fSmrg params, "glGetRenderbufferParameteriv"); 297601e04c3fSmrg} 297701e04c3fSmrg 297801e04c3fSmrg 297901e04c3fSmrgvoid GLAPIENTRY 298001e04c3fSmrg_mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, 298101e04c3fSmrg GLint *params) 298201e04c3fSmrg{ 298301e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 298401e04c3fSmrg 298501e04c3fSmrg struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 298601e04c3fSmrg if (!rb || rb == &DummyRenderbuffer) { 298701e04c3fSmrg /* ID was reserved, but no real renderbuffer object made yet */ 298801e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetNamedRenderbufferParameteriv" 298901e04c3fSmrg "(invalid renderbuffer %i)", renderbuffer); 299001e04c3fSmrg return; 299101e04c3fSmrg } 299201e04c3fSmrg 299301e04c3fSmrg get_render_buffer_parameteriv(ctx, rb, pname, params, 299401e04c3fSmrg "glGetNamedRenderbufferParameteriv"); 29957117f1b4Smrg} 29967117f1b4Smrg 29977117f1b4Smrg 29987ec681f3Smrgvoid GLAPIENTRY 29997ec681f3Smrg_mesa_GetNamedRenderbufferParameterivEXT(GLuint renderbuffer, GLenum pname, 30007ec681f3Smrg GLint *params) 30017ec681f3Smrg{ 30027ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 30037ec681f3Smrg 30047ec681f3Smrg struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 30057ec681f3Smrg if (!rb || rb == &DummyRenderbuffer) { 30067ec681f3Smrg _mesa_HashLockMutex(ctx->Shared->RenderBuffers); 30077ec681f3Smrg rb = allocate_renderbuffer_locked(ctx, renderbuffer, rb != NULL, 30087ec681f3Smrg "glGetNamedRenderbufferParameterivEXT"); 30097ec681f3Smrg _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); 30107ec681f3Smrg } 30117ec681f3Smrg 30127ec681f3Smrg get_render_buffer_parameteriv(ctx, rb, pname, params, 30137ec681f3Smrg "glGetNamedRenderbufferParameterivEXT"); 30147ec681f3Smrg} 30157ec681f3Smrg 30167ec681f3Smrg 30177117f1b4SmrgGLboolean GLAPIENTRY 3018af69d88dSmrg_mesa_IsFramebuffer(GLuint framebuffer) 30197117f1b4Smrg{ 30207117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 30217117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 30227117f1b4Smrg if (framebuffer) { 30237117f1b4Smrg struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); 30247117f1b4Smrg if (rb != NULL && rb != &DummyFramebuffer) 30257117f1b4Smrg return GL_TRUE; 30267117f1b4Smrg } 30277117f1b4Smrg return GL_FALSE; 30287117f1b4Smrg} 30297117f1b4Smrg 30307117f1b4Smrg 30314a49301eSmrg/** 30324a49301eSmrg * Check if any of the attachments of the given framebuffer are textures 30334a49301eSmrg * (render to texture). Call ctx->Driver.RenderTexture() for such 30344a49301eSmrg * attachments. 30354a49301eSmrg */ 30367117f1b4Smrgstatic void 30373464ebd5Sriastradhcheck_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) 30387117f1b4Smrg{ 30397117f1b4Smrg GLuint i; 304001e04c3fSmrg assert(ctx->Driver.RenderTexture); 30414a49301eSmrg 3042af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) 30434a49301eSmrg return; /* can't render to texture with winsys framebuffers */ 30444a49301eSmrg 30457117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 30467117f1b4Smrg struct gl_renderbuffer_attachment *att = fb->Attachment + i; 3047af69d88dSmrg if (att->Texture && att->Renderbuffer->TexImage 3048af69d88dSmrg && driver_RenderTexture_is_safe(att)) { 30497117f1b4Smrg ctx->Driver.RenderTexture(ctx, fb, att); 30507117f1b4Smrg } 30517117f1b4Smrg } 30527117f1b4Smrg} 30537117f1b4Smrg 30547117f1b4Smrg 30557117f1b4Smrg/** 30567117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures. 30577117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to 30587117f1b4Smrg * notify the device driver that the texture image may have changed. 30597117f1b4Smrg */ 30607117f1b4Smrgstatic void 30613464ebd5Sriastradhcheck_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) 30627117f1b4Smrg{ 3063af69d88dSmrg /* Skip if we know NeedsFinishRenderTexture won't be set. */ 3064af69d88dSmrg if (_mesa_is_winsys_fbo(fb) && !ctx->Driver.BindRenderbufferTexImage) 3065af69d88dSmrg return; 30664a49301eSmrg 30677117f1b4Smrg if (ctx->Driver.FinishRenderTexture) { 30687117f1b4Smrg GLuint i; 30697117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 30707117f1b4Smrg struct gl_renderbuffer_attachment *att = fb->Attachment + i; 3071af69d88dSmrg struct gl_renderbuffer *rb = att->Renderbuffer; 3072af69d88dSmrg if (rb && rb->NeedsFinishRenderTexture) { 3073af69d88dSmrg ctx->Driver.FinishRenderTexture(ctx, rb); 30747117f1b4Smrg } 30757117f1b4Smrg } 30767117f1b4Smrg } 30777117f1b4Smrg} 30787117f1b4Smrg 30797117f1b4Smrg 3080af69d88dSmrgstatic void 308101e04c3fSmrgbind_framebuffer(GLenum target, GLuint framebuffer) 30827117f1b4Smrg{ 30834a49301eSmrg struct gl_framebuffer *newDrawFb, *newReadFb; 30847117f1b4Smrg GLboolean bindReadBuf, bindDrawBuf; 30857117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 30867117f1b4Smrg 30877117f1b4Smrg switch (target) { 30887117f1b4Smrg case GL_DRAW_FRAMEBUFFER_EXT: 30897117f1b4Smrg bindDrawBuf = GL_TRUE; 30907117f1b4Smrg bindReadBuf = GL_FALSE; 30917117f1b4Smrg break; 30927117f1b4Smrg case GL_READ_FRAMEBUFFER_EXT: 30937117f1b4Smrg bindDrawBuf = GL_FALSE; 30947117f1b4Smrg bindReadBuf = GL_TRUE; 30957117f1b4Smrg break; 30967117f1b4Smrg case GL_FRAMEBUFFER_EXT: 30977117f1b4Smrg bindDrawBuf = GL_TRUE; 30987117f1b4Smrg bindReadBuf = GL_TRUE; 30997117f1b4Smrg break; 31007117f1b4Smrg default: 31017117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 31027117f1b4Smrg return; 31037117f1b4Smrg } 31047117f1b4Smrg 31057117f1b4Smrg if (framebuffer) { 31067ec681f3Smrg bool isGenName = false; 31077117f1b4Smrg /* Binding a user-created framebuffer object */ 31084a49301eSmrg newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); 31094a49301eSmrg if (newDrawFb == &DummyFramebuffer) { 31107117f1b4Smrg /* ID was reserved, but no real framebuffer object made yet */ 31114a49301eSmrg newDrawFb = NULL; 31127ec681f3Smrg isGenName = true; 31137117f1b4Smrg } 311401e04c3fSmrg else if (!newDrawFb && ctx->API == API_OPENGL_CORE) { 31154a49301eSmrg /* All FBO IDs must be Gen'd */ 311601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 311701e04c3fSmrg "glBindFramebuffer(non-gen name)"); 31184a49301eSmrg return; 31194a49301eSmrg } 31204a49301eSmrg 31214a49301eSmrg if (!newDrawFb) { 312201e04c3fSmrg /* create new framebuffer object */ 312301e04c3fSmrg newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 312401e04c3fSmrg if (!newDrawFb) { 312501e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 312601e04c3fSmrg return; 312701e04c3fSmrg } 31287ec681f3Smrg _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb, isGenName); 31297117f1b4Smrg } 31304a49301eSmrg newReadFb = newDrawFb; 31317117f1b4Smrg } 31327117f1b4Smrg else { 31337117f1b4Smrg /* Binding the window system framebuffer (which was originally set 31347117f1b4Smrg * with MakeCurrent). 31357117f1b4Smrg */ 31364a49301eSmrg newDrawFb = ctx->WinSysDrawBuffer; 31374a49301eSmrg newReadFb = ctx->WinSysReadBuffer; 31387117f1b4Smrg } 31397117f1b4Smrg 314001e04c3fSmrg _mesa_bind_framebuffers(ctx, 314101e04c3fSmrg bindDrawBuf ? newDrawFb : ctx->DrawBuffer, 314201e04c3fSmrg bindReadBuf ? newReadFb : ctx->ReadBuffer); 314301e04c3fSmrg} 31444a49301eSmrg 314501e04c3fSmrgvoid 314601e04c3fSmrg_mesa_bind_framebuffers(struct gl_context *ctx, 314701e04c3fSmrg struct gl_framebuffer *newDrawFb, 314801e04c3fSmrg struct gl_framebuffer *newReadFb) 314901e04c3fSmrg{ 315001e04c3fSmrg struct gl_framebuffer *const oldDrawFb = ctx->DrawBuffer; 315101e04c3fSmrg struct gl_framebuffer *const oldReadFb = ctx->ReadBuffer; 315201e04c3fSmrg const bool bindDrawBuf = oldDrawFb != newDrawFb; 315301e04c3fSmrg const bool bindReadBuf = oldReadFb != newReadFb; 31544a49301eSmrg 315501e04c3fSmrg assert(newDrawFb); 315601e04c3fSmrg assert(newDrawFb != &DummyFramebuffer); 31577117f1b4Smrg 31587117f1b4Smrg /* 31594a49301eSmrg * OK, now bind the new Draw/Read framebuffers, if they're changing. 31604a49301eSmrg * 31614a49301eSmrg * We also check if we're beginning and/or ending render-to-texture. 31624a49301eSmrg * When a framebuffer with texture attachments is unbound, call 31634a49301eSmrg * ctx->Driver.FinishRenderTexture(). 31644a49301eSmrg * When a framebuffer with texture attachments is bound, call 31654a49301eSmrg * ctx->Driver.RenderTexture(). 31664a49301eSmrg * 31674a49301eSmrg * Note that if the ReadBuffer has texture attachments we don't consider 31684a49301eSmrg * that a render-to-texture case. 31697117f1b4Smrg */ 31707117f1b4Smrg if (bindReadBuf) { 31717ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0); 31724a49301eSmrg 31734a49301eSmrg _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); 31747117f1b4Smrg } 31757117f1b4Smrg 31767117f1b4Smrg if (bindDrawBuf) { 31777ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0); 317801e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations; 31797117f1b4Smrg 3180af69d88dSmrg /* check if old framebuffer had any texture attachments */ 3181af69d88dSmrg if (oldDrawFb) 31824a49301eSmrg check_end_texture_render(ctx, oldDrawFb); 31834a49301eSmrg 31844a49301eSmrg /* check if newly bound framebuffer has any texture attachments */ 31854a49301eSmrg check_begin_texture_render(ctx, newDrawFb); 31864a49301eSmrg 31874a49301eSmrg _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); 31887ec681f3Smrg _mesa_update_allow_draw_out_of_order(ctx); 31897ec681f3Smrg _mesa_update_valid_to_render_state(ctx); 31907117f1b4Smrg } 31917117f1b4Smrg 31924a49301eSmrg if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { 319301e04c3fSmrg /* The few classic drivers that actually hook this function really only 319401e04c3fSmrg * want to know if the draw framebuffer changed. 319501e04c3fSmrg */ 319601e04c3fSmrg ctx->Driver.BindFramebuffer(ctx, 319701e04c3fSmrg bindDrawBuf ? GL_FRAMEBUFFER : GL_READ_FRAMEBUFFER, 319801e04c3fSmrg newDrawFb, newReadFb); 31997117f1b4Smrg } 32007117f1b4Smrg} 32017117f1b4Smrg 3202af69d88dSmrgvoid GLAPIENTRY 3203af69d88dSmrg_mesa_BindFramebuffer(GLenum target, GLuint framebuffer) 3204af69d88dSmrg{ 3205af69d88dSmrg /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry 3206af69d88dSmrg * point, but they allow the use of user-generated names. 3207af69d88dSmrg */ 320801e04c3fSmrg bind_framebuffer(target, framebuffer); 3209af69d88dSmrg} 3210af69d88dSmrg 32117117f1b4Smrg 32127117f1b4Smrgvoid GLAPIENTRY 3213af69d88dSmrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 3214af69d88dSmrg{ 321501e04c3fSmrg bind_framebuffer(target, framebuffer); 3216af69d88dSmrg} 3217af69d88dSmrg 3218af69d88dSmrg 3219af69d88dSmrgvoid GLAPIENTRY 3220af69d88dSmrg_mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) 32217117f1b4Smrg{ 32227117f1b4Smrg GLint i; 32237117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 32247117f1b4Smrg 322501e04c3fSmrg if (n < 0) { 322601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteFramebuffers(n < 0)"); 322701e04c3fSmrg return; 322801e04c3fSmrg } 322901e04c3fSmrg 32307ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0); 32317117f1b4Smrg 32327117f1b4Smrg for (i = 0; i < n; i++) { 32337117f1b4Smrg if (framebuffers[i] > 0) { 323401e04c3fSmrg struct gl_framebuffer *fb; 323501e04c3fSmrg fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); 323601e04c3fSmrg if (fb) { 323701e04c3fSmrg assert(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 32387117f1b4Smrg 32397117f1b4Smrg /* check if deleting currently bound framebuffer object */ 3240af69d88dSmrg if (fb == ctx->DrawBuffer) { 3241af69d88dSmrg /* bind default */ 324201e04c3fSmrg assert(fb->RefCount >= 2); 3243af69d88dSmrg _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 32444a49301eSmrg } 3245af69d88dSmrg if (fb == ctx->ReadBuffer) { 3246af69d88dSmrg /* bind default */ 324701e04c3fSmrg assert(fb->RefCount >= 2); 3248af69d88dSmrg _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, 0); 32497117f1b4Smrg } 32507117f1b4Smrg 325101e04c3fSmrg /* remove from hash table immediately, to free the ID */ 325201e04c3fSmrg _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 32537117f1b4Smrg 32547117f1b4Smrg if (fb != &DummyFramebuffer) { 32557117f1b4Smrg /* But the object will not be freed until it's no longer 32567117f1b4Smrg * bound in any context. 32577117f1b4Smrg */ 32584a49301eSmrg _mesa_reference_framebuffer(&fb, NULL); 325901e04c3fSmrg } 326001e04c3fSmrg } 32617117f1b4Smrg } 32627117f1b4Smrg } 32637117f1b4Smrg} 32647117f1b4Smrg 32657117f1b4Smrg 326601e04c3fSmrg/** 326701e04c3fSmrg * This is the implementation for glGenFramebuffers and glCreateFramebuffers. 326801e04c3fSmrg * It is not exposed to the rest of Mesa to encourage the use of 326901e04c3fSmrg * nameless buffers in driver internals. 327001e04c3fSmrg */ 327101e04c3fSmrgstatic void 327201e04c3fSmrgcreate_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa) 32737117f1b4Smrg{ 32747117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 32757117f1b4Smrg GLint i; 327601e04c3fSmrg struct gl_framebuffer *fb; 327701e04c3fSmrg 327801e04c3fSmrg const char *func = dsa ? "glCreateFramebuffers" : "glGenFramebuffers"; 32797117f1b4Smrg 32807117f1b4Smrg if (n < 0) { 328101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); 32827117f1b4Smrg return; 32837117f1b4Smrg } 32847117f1b4Smrg 32857117f1b4Smrg if (!framebuffers) 32867117f1b4Smrg return; 32877117f1b4Smrg 328801e04c3fSmrg _mesa_HashLockMutex(ctx->Shared->FrameBuffers); 328901e04c3fSmrg 32907ec681f3Smrg _mesa_HashFindFreeKeys(ctx->Shared->FrameBuffers, framebuffers, n); 32917117f1b4Smrg 32927117f1b4Smrg for (i = 0; i < n; i++) { 329301e04c3fSmrg if (dsa) { 329401e04c3fSmrg fb = ctx->Driver.NewFramebuffer(ctx, framebuffers[i]); 329501e04c3fSmrg if (!fb) { 329601e04c3fSmrg _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers); 329701e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 329801e04c3fSmrg return; 329901e04c3fSmrg } 330001e04c3fSmrg } 330101e04c3fSmrg else 330201e04c3fSmrg fb = &DummyFramebuffer; 330301e04c3fSmrg 33047ec681f3Smrg _mesa_HashInsertLocked(ctx->Shared->FrameBuffers, framebuffers[i], 33057ec681f3Smrg fb, true); 33067117f1b4Smrg } 330701e04c3fSmrg 330801e04c3fSmrg _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers); 33097117f1b4Smrg} 33107117f1b4Smrg 33117117f1b4Smrg 331201e04c3fSmrgvoid GLAPIENTRY 331301e04c3fSmrg_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers) 33147117f1b4Smrg{ 331501e04c3fSmrg create_framebuffers(n, framebuffers, false); 331601e04c3fSmrg} 33177117f1b4Smrg 33187117f1b4Smrg 331901e04c3fSmrgvoid GLAPIENTRY 332001e04c3fSmrg_mesa_CreateFramebuffers(GLsizei n, GLuint *framebuffers) 332101e04c3fSmrg{ 332201e04c3fSmrg create_framebuffers(n, framebuffers, true); 332301e04c3fSmrg} 3324af69d88dSmrg 332501e04c3fSmrg 332601e04c3fSmrgGLenum 332701e04c3fSmrg_mesa_check_framebuffer_status(struct gl_context *ctx, 332801e04c3fSmrg struct gl_framebuffer *buffer) 332901e04c3fSmrg{ 333001e04c3fSmrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 33317117f1b4Smrg 3332af69d88dSmrg if (_mesa_is_winsys_fbo(buffer)) { 3333af69d88dSmrg /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */ 3334af69d88dSmrg if (buffer != &IncompleteFramebuffer) { 3335af69d88dSmrg return GL_FRAMEBUFFER_COMPLETE_EXT; 3336af69d88dSmrg } else { 3337af69d88dSmrg return GL_FRAMEBUFFER_UNDEFINED; 3338af69d88dSmrg } 33397117f1b4Smrg } 33407117f1b4Smrg 33414a49301eSmrg /* No need to flush here */ 33424a49301eSmrg 33434a49301eSmrg if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { 33444a49301eSmrg _mesa_test_framebuffer_completeness(ctx, buffer); 33454a49301eSmrg } 33467117f1b4Smrg 33477117f1b4Smrg return buffer->_Status; 33487117f1b4Smrg} 33497117f1b4Smrg 33507117f1b4Smrg 335101e04c3fSmrgGLenum GLAPIENTRY 335201e04c3fSmrg_mesa_CheckFramebufferStatus_no_error(GLenum target) 3353af69d88dSmrg{ 335401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 3355af69d88dSmrg 335601e04c3fSmrg struct gl_framebuffer *fb = get_framebuffer_target(ctx, target); 335701e04c3fSmrg return _mesa_check_framebuffer_status(ctx, fb); 335801e04c3fSmrg} 335901e04c3fSmrg 336001e04c3fSmrg 336101e04c3fSmrgGLenum GLAPIENTRY 336201e04c3fSmrg_mesa_CheckFramebufferStatus(GLenum target) 336301e04c3fSmrg{ 336401e04c3fSmrg struct gl_framebuffer *fb; 336501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 336601e04c3fSmrg 336701e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 336801e04c3fSmrg _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n", 336901e04c3fSmrg _mesa_enum_to_string(target)); 337001e04c3fSmrg 337101e04c3fSmrg fb = get_framebuffer_target(ctx, target); 337201e04c3fSmrg if (!fb) { 337301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 337401e04c3fSmrg "glCheckFramebufferStatus(invalid target %s)", 337501e04c3fSmrg _mesa_enum_to_string(target)); 337601e04c3fSmrg return 0; 337701e04c3fSmrg } 337801e04c3fSmrg 337901e04c3fSmrg return _mesa_check_framebuffer_status(ctx, fb); 338001e04c3fSmrg} 338101e04c3fSmrg 338201e04c3fSmrg 338301e04c3fSmrgGLenum GLAPIENTRY 338401e04c3fSmrg_mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) 338501e04c3fSmrg{ 338601e04c3fSmrg struct gl_framebuffer *fb; 338701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 338801e04c3fSmrg 338901e04c3fSmrg /* Validate the target (for conformance's sake) and grab a reference to the 339001e04c3fSmrg * default framebuffer in case framebuffer = 0. 339101e04c3fSmrg * Section 9.4 Framebuffer Completeness of the OpenGL 4.5 core spec 339201e04c3fSmrg * (30.10.2014, PDF page 336) says: 339301e04c3fSmrg * "If framebuffer is zero, then the status of the default read or 339401e04c3fSmrg * draw framebuffer (as determined by target) is returned." 339501e04c3fSmrg */ 339601e04c3fSmrg switch (target) { 339701e04c3fSmrg case GL_DRAW_FRAMEBUFFER: 339801e04c3fSmrg case GL_FRAMEBUFFER: 339901e04c3fSmrg fb = ctx->WinSysDrawBuffer; 340001e04c3fSmrg break; 340101e04c3fSmrg case GL_READ_FRAMEBUFFER: 340201e04c3fSmrg fb = ctx->WinSysReadBuffer; 340301e04c3fSmrg break; 340401e04c3fSmrg default: 340501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 340601e04c3fSmrg "glCheckNamedFramebufferStatus(invalid target %s)", 340701e04c3fSmrg _mesa_enum_to_string(target)); 340801e04c3fSmrg return 0; 340901e04c3fSmrg } 341001e04c3fSmrg 341101e04c3fSmrg if (framebuffer) { 341201e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 341301e04c3fSmrg "glCheckNamedFramebufferStatus"); 341401e04c3fSmrg if (!fb) 341501e04c3fSmrg return 0; 341601e04c3fSmrg } 341701e04c3fSmrg 341801e04c3fSmrg return _mesa_check_framebuffer_status(ctx, fb); 341901e04c3fSmrg} 342001e04c3fSmrg 342101e04c3fSmrg 34227ec681f3SmrgGLenum GLAPIENTRY 34237ec681f3Smrg_mesa_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target) 34247ec681f3Smrg{ 34257ec681f3Smrg struct gl_framebuffer *fb; 34267ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 34277ec681f3Smrg 34287ec681f3Smrg switch (target) { 34297ec681f3Smrg case GL_DRAW_FRAMEBUFFER: 34307ec681f3Smrg case GL_FRAMEBUFFER: 34317ec681f3Smrg case GL_READ_FRAMEBUFFER: 34327ec681f3Smrg break; 34337ec681f3Smrg default: 34347ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, 34357ec681f3Smrg "glCheckNamedFramebufferStatusEXT(invalid target %s)", 34367ec681f3Smrg _mesa_enum_to_string(target)); 34377ec681f3Smrg return 0; 34387ec681f3Smrg } 34397ec681f3Smrg 34407ec681f3Smrg if (framebuffer == 0) { 34417ec681f3Smrg return _mesa_CheckNamedFramebufferStatus(0, target); 34427ec681f3Smrg } 34437ec681f3Smrg 34447ec681f3Smrg fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, 34457ec681f3Smrg "glCheckNamedFramebufferStatusEXT"); 34467ec681f3Smrg if (!fb) 34477ec681f3Smrg return 0; 34487ec681f3Smrg 34497ec681f3Smrg return _mesa_check_framebuffer_status(ctx, fb); 34507ec681f3Smrg} 34517ec681f3Smrg 34527ec681f3Smrg 345301e04c3fSmrg/** 345401e04c3fSmrg * Replicate the src attachment point. Used by framebuffer_texture() when 345501e04c3fSmrg * the same texture is attached at GL_DEPTH_ATTACHMENT and 345601e04c3fSmrg * GL_STENCIL_ATTACHMENT. 345701e04c3fSmrg */ 345801e04c3fSmrgstatic void 345901e04c3fSmrgreuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, 346001e04c3fSmrg gl_buffer_index dst, 346101e04c3fSmrg gl_buffer_index src) 346201e04c3fSmrg{ 346301e04c3fSmrg struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst]; 346401e04c3fSmrg struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src]; 346501e04c3fSmrg 346601e04c3fSmrg assert(src_att->Texture != NULL); 346701e04c3fSmrg assert(src_att->Renderbuffer != NULL); 3468af69d88dSmrg 3469af69d88dSmrg _mesa_reference_texobj(&dst_att->Texture, src_att->Texture); 3470af69d88dSmrg _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer); 3471af69d88dSmrg dst_att->Type = src_att->Type; 3472af69d88dSmrg dst_att->Complete = src_att->Complete; 3473af69d88dSmrg dst_att->TextureLevel = src_att->TextureLevel; 347401e04c3fSmrg dst_att->CubeMapFace = src_att->CubeMapFace; 3475af69d88dSmrg dst_att->Zoffset = src_att->Zoffset; 347601e04c3fSmrg dst_att->Layered = src_att->Layered; 347701e04c3fSmrg} 347801e04c3fSmrg 347901e04c3fSmrg 348001e04c3fSmrgstatic struct gl_texture_object * 348101e04c3fSmrgget_texture_for_framebuffer(struct gl_context *ctx, GLuint texture) 348201e04c3fSmrg{ 348301e04c3fSmrg if (!texture) 348401e04c3fSmrg return NULL; 348501e04c3fSmrg 348601e04c3fSmrg return _mesa_lookup_texture(ctx, texture); 3487af69d88dSmrg} 3488af69d88dSmrg 34897117f1b4Smrg 34907117f1b4Smrg/** 349101e04c3fSmrg * Common code called by gl*FramebufferTexture*() to retrieve the correct 349201e04c3fSmrg * texture object pointer. 3493af69d88dSmrg * 349401e04c3fSmrg * \param texObj where the pointer to the texture object is returned. Note 349501e04c3fSmrg * that a successful call may return texObj = NULL. 3496af69d88dSmrg * 349701e04c3fSmrg * \return true if no errors, false if errors 34987117f1b4Smrg */ 349901e04c3fSmrgstatic bool 350001e04c3fSmrgget_texture_for_framebuffer_err(struct gl_context *ctx, GLuint texture, 350101e04c3fSmrg bool layered, const char *caller, 350201e04c3fSmrg struct gl_texture_object **texObj) 35037117f1b4Smrg{ 350401e04c3fSmrg *texObj = NULL; /* This will get returned if texture = 0. */ 35057117f1b4Smrg 350601e04c3fSmrg if (!texture) 350701e04c3fSmrg return true; 350801e04c3fSmrg 350901e04c3fSmrg *texObj = _mesa_lookup_texture(ctx, texture); 351001e04c3fSmrg if (*texObj == NULL || (*texObj)->Target == 0) { 351101e04c3fSmrg /* Can't render to a non-existent texture object. 351201e04c3fSmrg * 351301e04c3fSmrg * The OpenGL 4.5 core spec (02.02.2015) in Section 9.2 Binding and 351401e04c3fSmrg * Managing Framebuffer Objects specifies a different error 351501e04c3fSmrg * depending upon the calling function (PDF pages 325-328). 351601e04c3fSmrg * *FramebufferTexture (where layered = GL_TRUE) throws invalid 351701e04c3fSmrg * value, while the other commands throw invalid operation (where 351801e04c3fSmrg * layered = GL_FALSE). 351901e04c3fSmrg */ 352001e04c3fSmrg const GLenum error = layered ? GL_INVALID_VALUE : 352101e04c3fSmrg GL_INVALID_OPERATION; 352201e04c3fSmrg _mesa_error(ctx, error, 352301e04c3fSmrg "%s(non-existent texture %u)", caller, texture); 352401e04c3fSmrg return false; 352501e04c3fSmrg } 352601e04c3fSmrg 352701e04c3fSmrg return true; 352801e04c3fSmrg} 352901e04c3fSmrg 353001e04c3fSmrg 353101e04c3fSmrg/** 353201e04c3fSmrg * Common code called by gl*FramebufferTexture() to verify the texture target 353301e04c3fSmrg * and decide whether or not the attachment should truly be considered 353401e04c3fSmrg * layered. 353501e04c3fSmrg * 353601e04c3fSmrg * \param layered true if attachment should be considered layered, false if 353701e04c3fSmrg * not 353801e04c3fSmrg * 353901e04c3fSmrg * \return true if no errors, false if errors 354001e04c3fSmrg */ 354101e04c3fSmrgstatic bool 354201e04c3fSmrgcheck_layered_texture_target(struct gl_context *ctx, GLenum target, 354301e04c3fSmrg const char *caller, GLboolean *layered) 354401e04c3fSmrg{ 354501e04c3fSmrg *layered = GL_TRUE; 354601e04c3fSmrg 354701e04c3fSmrg switch (target) { 354801e04c3fSmrg case GL_TEXTURE_3D: 354901e04c3fSmrg case GL_TEXTURE_1D_ARRAY_EXT: 355001e04c3fSmrg case GL_TEXTURE_2D_ARRAY_EXT: 355101e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 355201e04c3fSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 355301e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 355401e04c3fSmrg return true; 355501e04c3fSmrg case GL_TEXTURE_1D: 355601e04c3fSmrg case GL_TEXTURE_2D: 355701e04c3fSmrg case GL_TEXTURE_RECTANGLE: 355801e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE: 355901e04c3fSmrg /* These texture types are valid to pass to 356001e04c3fSmrg * glFramebufferTexture(), but since they aren't layered, it 356101e04c3fSmrg * is equivalent to calling glFramebufferTexture{1D,2D}(). 356201e04c3fSmrg */ 356301e04c3fSmrg *layered = GL_FALSE; 356401e04c3fSmrg return true; 356501e04c3fSmrg } 356601e04c3fSmrg 356701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 356801e04c3fSmrg "%s(invalid texture target %s)", caller, 356901e04c3fSmrg _mesa_enum_to_string(target)); 357001e04c3fSmrg return false; 357101e04c3fSmrg} 357201e04c3fSmrg 357301e04c3fSmrg 357401e04c3fSmrg/** 357501e04c3fSmrg * Common code called by gl*FramebufferTextureLayer() to verify the texture 357601e04c3fSmrg * target. 357701e04c3fSmrg * 357801e04c3fSmrg * \return true if no errors, false if errors 357901e04c3fSmrg */ 358001e04c3fSmrgstatic bool 358101e04c3fSmrgcheck_texture_target(struct gl_context *ctx, GLenum target, 358201e04c3fSmrg const char *caller) 358301e04c3fSmrg{ 358401e04c3fSmrg /* We're being called by glFramebufferTextureLayer(). 358501e04c3fSmrg * The only legal texture types for that function are 3D, 358601e04c3fSmrg * cube-map, and 1D/2D/cube-map array textures. 358701e04c3fSmrg * 358801e04c3fSmrg * We don't need to check for GL_ARB_texture_cube_map_array because the 358901e04c3fSmrg * application wouldn't have been able to create a texture with a 359001e04c3fSmrg * GL_TEXTURE_CUBE_MAP_ARRAY target if the extension were not enabled. 359101e04c3fSmrg */ 359201e04c3fSmrg switch (target) { 359301e04c3fSmrg case GL_TEXTURE_3D: 359401e04c3fSmrg case GL_TEXTURE_1D_ARRAY: 359501e04c3fSmrg case GL_TEXTURE_2D_ARRAY: 359601e04c3fSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 359701e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 359801e04c3fSmrg return true; 359901e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 360001e04c3fSmrg /* GL_TEXTURE_CUBE_MAP is only allowed by OpenGL 4.5 here, which 360101e04c3fSmrg * includes the DSA API. 360201e04c3fSmrg * 360301e04c3fSmrg * Because DSA is only enabled for GL 3.1+ and this can be called 360401e04c3fSmrg * from _mesa_FramebufferTextureLayer in compatibility profile, 360501e04c3fSmrg * we need to check the version. 360601e04c3fSmrg */ 360701e04c3fSmrg return _mesa_is_desktop_gl(ctx) && ctx->Version >= 31; 360801e04c3fSmrg } 360901e04c3fSmrg 361001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 361101e04c3fSmrg "%s(invalid texture target %s)", caller, 361201e04c3fSmrg _mesa_enum_to_string(target)); 361301e04c3fSmrg return false; 361401e04c3fSmrg} 361501e04c3fSmrg 361601e04c3fSmrg 361701e04c3fSmrg/** 361801e04c3fSmrg * Common code called by glFramebufferTexture*D() to verify the texture 361901e04c3fSmrg * target. 362001e04c3fSmrg * 362101e04c3fSmrg * \return true if no errors, false if errors 362201e04c3fSmrg */ 362301e04c3fSmrgstatic bool 362401e04c3fSmrgcheck_textarget(struct gl_context *ctx, int dims, GLenum target, 362501e04c3fSmrg GLenum textarget, const char *caller) 362601e04c3fSmrg{ 362701e04c3fSmrg bool err = false; 362801e04c3fSmrg 362901e04c3fSmrg switch (textarget) { 363001e04c3fSmrg case GL_TEXTURE_1D: 363101e04c3fSmrg err = dims != 1; 363201e04c3fSmrg break; 363301e04c3fSmrg case GL_TEXTURE_1D_ARRAY: 363401e04c3fSmrg err = dims != 1 || !ctx->Extensions.EXT_texture_array; 363501e04c3fSmrg break; 363601e04c3fSmrg case GL_TEXTURE_2D: 363701e04c3fSmrg err = dims != 2; 363801e04c3fSmrg break; 363901e04c3fSmrg case GL_TEXTURE_2D_ARRAY: 364001e04c3fSmrg err = dims != 2 || !ctx->Extensions.EXT_texture_array || 364101e04c3fSmrg (_mesa_is_gles(ctx) && ctx->Version < 30); 364201e04c3fSmrg break; 364301e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE: 364401e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 364501e04c3fSmrg err = dims != 2 || 364601e04c3fSmrg !ctx->Extensions.ARB_texture_multisample || 364701e04c3fSmrg (_mesa_is_gles(ctx) && ctx->Version < 31); 364801e04c3fSmrg break; 364901e04c3fSmrg case GL_TEXTURE_RECTANGLE: 365001e04c3fSmrg err = dims != 2 || _mesa_is_gles(ctx) || 365101e04c3fSmrg !ctx->Extensions.NV_texture_rectangle; 365201e04c3fSmrg break; 365301e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 365401e04c3fSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 365501e04c3fSmrg err = true; 365601e04c3fSmrg break; 365701e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 365801e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 365901e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 366001e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 366101e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 366201e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 366301e04c3fSmrg err = dims != 2 || !ctx->Extensions.ARB_texture_cube_map; 366401e04c3fSmrg break; 366501e04c3fSmrg case GL_TEXTURE_3D: 366601e04c3fSmrg err = dims != 3; 366701e04c3fSmrg break; 366801e04c3fSmrg default: 36697117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 367001e04c3fSmrg "%s(unknown textarget 0x%x)", caller, textarget); 367101e04c3fSmrg return false; 36727117f1b4Smrg } 36737117f1b4Smrg 367401e04c3fSmrg if (err) { 36757117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 367601e04c3fSmrg "%s(invalid textarget %s)", 367701e04c3fSmrg caller, _mesa_enum_to_string(textarget)); 367801e04c3fSmrg return false; 36797117f1b4Smrg } 36807117f1b4Smrg 368101e04c3fSmrg /* Make sure textarget is consistent with the texture's type */ 368201e04c3fSmrg err = (target == GL_TEXTURE_CUBE_MAP) ? 368301e04c3fSmrg !_mesa_is_cube_face(textarget): (target != textarget); 36847117f1b4Smrg 368501e04c3fSmrg if (err) { 368601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 368701e04c3fSmrg "%s(mismatched texture target)", caller); 368801e04c3fSmrg return false; 368901e04c3fSmrg } 36907117f1b4Smrg 369101e04c3fSmrg return true; 369201e04c3fSmrg} 369301e04c3fSmrg 369401e04c3fSmrg 369501e04c3fSmrg/** 369601e04c3fSmrg * Common code called by gl*FramebufferTextureLayer() and 369701e04c3fSmrg * glFramebufferTexture3D() to validate the layer. 369801e04c3fSmrg * 369901e04c3fSmrg * \return true if no errors, false if errors 370001e04c3fSmrg */ 370101e04c3fSmrgstatic bool 370201e04c3fSmrgcheck_layer(struct gl_context *ctx, GLenum target, GLint layer, 370301e04c3fSmrg const char *caller) 370401e04c3fSmrg{ 370501e04c3fSmrg /* Page 306 (page 328 of the PDF) of the OpenGL 4.5 (Core Profile) 370601e04c3fSmrg * spec says: 370701e04c3fSmrg * 370801e04c3fSmrg * "An INVALID_VALUE error is generated if texture is non-zero 370901e04c3fSmrg * and layer is negative." 371001e04c3fSmrg */ 371101e04c3fSmrg if (layer < 0) { 371201e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(layer %d < 0)", caller, layer); 371301e04c3fSmrg return false; 371401e04c3fSmrg } 371501e04c3fSmrg 371601e04c3fSmrg if (target == GL_TEXTURE_3D) { 371701e04c3fSmrg const GLuint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 371801e04c3fSmrg if (layer >= maxSize) { 371901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 372001e04c3fSmrg "%s(invalid layer %u)", caller, layer); 372101e04c3fSmrg return false; 37227117f1b4Smrg } 372301e04c3fSmrg } 372401e04c3fSmrg else if ((target == GL_TEXTURE_1D_ARRAY) || 372501e04c3fSmrg (target == GL_TEXTURE_2D_ARRAY) || 372601e04c3fSmrg (target == GL_TEXTURE_CUBE_MAP_ARRAY) || 372701e04c3fSmrg (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { 372801e04c3fSmrg if (layer >= ctx->Const.MaxArrayTextureLayers) { 372901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 373001e04c3fSmrg "%s(layer %u >= GL_MAX_ARRAY_TEXTURE_LAYERS)", 373101e04c3fSmrg caller, layer); 373201e04c3fSmrg return false; 3733c1f859d4Smrg } 373401e04c3fSmrg } 373501e04c3fSmrg else if (target == GL_TEXTURE_CUBE_MAP) { 373601e04c3fSmrg if (layer >= 6) { 37377117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, 373801e04c3fSmrg "%s(layer %u >= 6)", caller, layer); 373901e04c3fSmrg return false; 37407117f1b4Smrg } 37417117f1b4Smrg } 37427117f1b4Smrg 374301e04c3fSmrg return true; 374401e04c3fSmrg} 374501e04c3fSmrg 374601e04c3fSmrg 374701e04c3fSmrg/** 374801e04c3fSmrg * Common code called by all gl*FramebufferTexture*() entry points to verify 374901e04c3fSmrg * the level. 375001e04c3fSmrg * 375101e04c3fSmrg * \return true if no errors, false if errors 375201e04c3fSmrg */ 375301e04c3fSmrgstatic bool 375401e04c3fSmrgcheck_level(struct gl_context *ctx, struct gl_texture_object *texObj, 375501e04c3fSmrg GLenum target, GLint level, const char *caller) 375601e04c3fSmrg{ 375701e04c3fSmrg /* Section 9.2.8 of the OpenGL 4.6 specification says: 375801e04c3fSmrg * 375901e04c3fSmrg * "If texture refers to an immutable-format texture, level must be 376001e04c3fSmrg * greater than or equal to zero and smaller than the value of 376101e04c3fSmrg * TEXTURE_VIEW_NUM_LEVELS for texture." 376201e04c3fSmrg */ 37637ec681f3Smrg const int max_levels = texObj->Immutable ? texObj->Attrib.ImmutableLevels : 376401e04c3fSmrg _mesa_max_texture_levels(ctx, target); 376501e04c3fSmrg 376601e04c3fSmrg if (level < 0 || level >= max_levels) { 376701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 376801e04c3fSmrg "%s(invalid level %d)", caller, level); 376901e04c3fSmrg return false; 377001e04c3fSmrg } 377101e04c3fSmrg 377201e04c3fSmrg return true; 377301e04c3fSmrg} 377401e04c3fSmrg 377501e04c3fSmrg 377601e04c3fSmrgstruct gl_renderbuffer_attachment * 377701e04c3fSmrg_mesa_get_and_validate_attachment(struct gl_context *ctx, 377801e04c3fSmrg struct gl_framebuffer *fb, 377901e04c3fSmrg GLenum attachment, const char *caller) 378001e04c3fSmrg{ 378101e04c3fSmrg /* The window-system framebuffer object is immutable */ 378201e04c3fSmrg if (_mesa_is_winsys_fbo(fb)) { 378301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(window-system framebuffer)", 378401e04c3fSmrg caller); 378501e04c3fSmrg return NULL; 378601e04c3fSmrg } 378701e04c3fSmrg 378801e04c3fSmrg /* Not a hash lookup, so we can afford to get the attachment here. */ 378901e04c3fSmrg bool is_color_attachment; 379001e04c3fSmrg struct gl_renderbuffer_attachment *att = 379101e04c3fSmrg get_attachment(ctx, fb, attachment, &is_color_attachment); 37927117f1b4Smrg if (att == NULL) { 379301e04c3fSmrg if (is_color_attachment) { 379401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 379501e04c3fSmrg "%s(invalid color attachment %s)", caller, 379601e04c3fSmrg _mesa_enum_to_string(attachment)); 379701e04c3fSmrg } else { 379801e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 379901e04c3fSmrg "%s(invalid attachment %s)", caller, 380001e04c3fSmrg _mesa_enum_to_string(attachment)); 380101e04c3fSmrg } 380201e04c3fSmrg return NULL; 38037117f1b4Smrg } 38047117f1b4Smrg 380501e04c3fSmrg return att; 380601e04c3fSmrg} 380701e04c3fSmrg 380801e04c3fSmrg 380901e04c3fSmrgvoid 381001e04c3fSmrg_mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb, 381101e04c3fSmrg GLenum attachment, 381201e04c3fSmrg struct gl_renderbuffer_attachment *att, 381301e04c3fSmrg struct gl_texture_object *texObj, GLenum textarget, 3814a8bb7a65Smaya GLint level, GLsizei samples, 3815a8bb7a65Smaya GLuint layer, GLboolean layered) 381601e04c3fSmrg{ 38177ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0); 38187117f1b4Smrg 381901e04c3fSmrg simple_mtx_lock(&fb->Mutex); 38207117f1b4Smrg if (texObj) { 3821af69d88dSmrg if (attachment == GL_DEPTH_ATTACHMENT && 3822af69d88dSmrg texObj == fb->Attachment[BUFFER_STENCIL].Texture && 3823af69d88dSmrg level == fb->Attachment[BUFFER_STENCIL].TextureLevel && 3824af69d88dSmrg _mesa_tex_target_to_face(textarget) == 3825af69d88dSmrg fb->Attachment[BUFFER_STENCIL].CubeMapFace && 3826a8bb7a65Smaya samples == fb->Attachment[BUFFER_STENCIL].NumSamples && 382701e04c3fSmrg layer == fb->Attachment[BUFFER_STENCIL].Zoffset) { 382801e04c3fSmrg /* The texture object is already attached to the stencil attachment 382901e04c3fSmrg * point. Don't create a new renderbuffer; just reuse the stencil 383001e04c3fSmrg * attachment's. This is required to prevent a GL error in 383101e04c3fSmrg * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL). 383201e04c3fSmrg */ 383301e04c3fSmrg reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH, 383401e04c3fSmrg BUFFER_STENCIL); 3835af69d88dSmrg } else if (attachment == GL_STENCIL_ATTACHMENT && 383601e04c3fSmrg texObj == fb->Attachment[BUFFER_DEPTH].Texture && 3837af69d88dSmrg level == fb->Attachment[BUFFER_DEPTH].TextureLevel && 3838af69d88dSmrg _mesa_tex_target_to_face(textarget) == 3839af69d88dSmrg fb->Attachment[BUFFER_DEPTH].CubeMapFace && 3840a8bb7a65Smaya samples == fb->Attachment[BUFFER_DEPTH].NumSamples && 384101e04c3fSmrg layer == fb->Attachment[BUFFER_DEPTH].Zoffset) { 384201e04c3fSmrg /* As above, but with depth and stencil transposed. */ 384301e04c3fSmrg reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL, 384401e04c3fSmrg BUFFER_DEPTH); 3845af69d88dSmrg } else { 384601e04c3fSmrg set_texture_attachment(ctx, fb, att, texObj, textarget, 3847a8bb7a65Smaya level, samples, layer, layered); 384801e04c3fSmrg 384901e04c3fSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 385001e04c3fSmrg /* Above we created a new renderbuffer and attached it to the 385101e04c3fSmrg * depth attachment point. Now attach it to the stencil attachment 385201e04c3fSmrg * point too. 385301e04c3fSmrg */ 385401e04c3fSmrg assert(att == &fb->Attachment[BUFFER_DEPTH]); 385501e04c3fSmrg reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL, 385601e04c3fSmrg BUFFER_DEPTH); 385701e04c3fSmrg } 3858af69d88dSmrg } 3859af69d88dSmrg 38604a49301eSmrg /* Set the render-to-texture flag. We'll check this flag in 38614a49301eSmrg * glTexImage() and friends to determine if we need to revalidate 38624a49301eSmrg * any FBOs that might be rendering into this texture. 38634a49301eSmrg * This flag never gets cleared since it's non-trivial to determine 38644a49301eSmrg * when all FBOs might be done rendering to this texture. That's OK 38654a49301eSmrg * though since it's uncommon to render to a texture then repeatedly 38664a49301eSmrg * call glTexImage() to change images in the texture. 38674a49301eSmrg */ 38684a49301eSmrg texObj->_RenderToTexture = GL_TRUE; 38697117f1b4Smrg } 38707117f1b4Smrg else { 3871af69d88dSmrg remove_attachment(ctx, att); 3872af69d88dSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 387301e04c3fSmrg assert(att == &fb->Attachment[BUFFER_DEPTH]); 387401e04c3fSmrg remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]); 3875af69d88dSmrg } 38767117f1b4Smrg } 38774a49301eSmrg 38784a49301eSmrg invalidate_framebuffer(fb); 38794a49301eSmrg 388001e04c3fSmrg simple_mtx_unlock(&fb->Mutex); 38817117f1b4Smrg} 38827117f1b4Smrg 38837117f1b4Smrg 388401e04c3fSmrgstatic void 388501e04c3fSmrgframebuffer_texture_with_dims_no_error(GLenum target, GLenum attachment, 388601e04c3fSmrg GLenum textarget, GLuint texture, 388701e04c3fSmrg GLint level, GLint layer) 38887117f1b4Smrg{ 38897117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 38907117f1b4Smrg 389101e04c3fSmrg /* Get the framebuffer object */ 389201e04c3fSmrg struct gl_framebuffer *fb = get_framebuffer_target(ctx, target); 3893af69d88dSmrg 389401e04c3fSmrg /* Get the texture object */ 389501e04c3fSmrg struct gl_texture_object *texObj = 389601e04c3fSmrg get_texture_for_framebuffer(ctx, texture); 3897af69d88dSmrg 389801e04c3fSmrg struct gl_renderbuffer_attachment *att = 389901e04c3fSmrg get_attachment(ctx, fb, attachment, NULL); 390001e04c3fSmrg 390101e04c3fSmrg _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, 3902a8bb7a65Smaya level, 0, layer, GL_FALSE); 390301e04c3fSmrg} 390401e04c3fSmrg 390501e04c3fSmrg 390601e04c3fSmrgstatic void 39077ec681f3Smrgframebuffer_texture_with_dims(int dims, GLenum target, GLuint framebuffer, 390801e04c3fSmrg GLenum attachment, GLenum textarget, 3909a8bb7a65Smaya GLuint texture, GLint level, GLsizei samples, 39107ec681f3Smrg GLint layer, const char *caller, bool dsa) 391101e04c3fSmrg{ 391201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 391301e04c3fSmrg struct gl_framebuffer *fb; 391401e04c3fSmrg struct gl_texture_object *texObj; 391501e04c3fSmrg 391601e04c3fSmrg /* Get the framebuffer object */ 39177ec681f3Smrg if (dsa) { 39187ec681f3Smrg fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, caller); 39197ec681f3Smrg } else { 39207ec681f3Smrg fb = get_framebuffer_target(ctx, target); 39217ec681f3Smrg } 392201e04c3fSmrg if (!fb) { 392301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller, 392401e04c3fSmrg _mesa_enum_to_string(target)); 392501e04c3fSmrg return; 392601e04c3fSmrg } 392701e04c3fSmrg 392801e04c3fSmrg /* Get the texture object */ 392901e04c3fSmrg if (!get_texture_for_framebuffer_err(ctx, texture, false, caller, &texObj)) 393001e04c3fSmrg return; 393101e04c3fSmrg 393201e04c3fSmrg if (texObj) { 393301e04c3fSmrg if (!check_textarget(ctx, dims, texObj->Target, textarget, caller)) 393401e04c3fSmrg return; 393501e04c3fSmrg 393601e04c3fSmrg if ((dims == 3) && !check_layer(ctx, texObj->Target, layer, caller)) 393701e04c3fSmrg return; 393801e04c3fSmrg 393901e04c3fSmrg if (!check_level(ctx, texObj, textarget, level, caller)) 3940af69d88dSmrg return; 39417117f1b4Smrg } 39427117f1b4Smrg 394301e04c3fSmrg struct gl_renderbuffer_attachment *att = 394401e04c3fSmrg _mesa_get_and_validate_attachment(ctx, fb, attachment, caller); 394501e04c3fSmrg if (!att) 394601e04c3fSmrg return; 394701e04c3fSmrg 394801e04c3fSmrg _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, 3949a8bb7a65Smaya level, samples, layer, GL_FALSE); 39507117f1b4Smrg} 39517117f1b4Smrg 39527117f1b4Smrg 39537117f1b4Smrgvoid GLAPIENTRY 395401e04c3fSmrg_mesa_FramebufferTexture1D_no_error(GLenum target, GLenum attachment, 395501e04c3fSmrg GLenum textarget, GLuint texture, 395601e04c3fSmrg GLint level) 395701e04c3fSmrg{ 395801e04c3fSmrg framebuffer_texture_with_dims_no_error(target, attachment, textarget, 395901e04c3fSmrg texture, level, 0); 396001e04c3fSmrg} 396101e04c3fSmrg 396201e04c3fSmrg 396301e04c3fSmrgvoid GLAPIENTRY 396401e04c3fSmrg_mesa_FramebufferTexture1D(GLenum target, GLenum attachment, 3965af69d88dSmrg GLenum textarget, GLuint texture, GLint level) 39667117f1b4Smrg{ 39677ec681f3Smrg framebuffer_texture_with_dims(1, target, 0, attachment, textarget, texture, 39687ec681f3Smrg level, 0, 0, "glFramebufferTexture1D", false); 396901e04c3fSmrg} 39707117f1b4Smrg 3971af69d88dSmrg 397201e04c3fSmrgvoid GLAPIENTRY 397301e04c3fSmrg_mesa_FramebufferTexture2D_no_error(GLenum target, GLenum attachment, 397401e04c3fSmrg GLenum textarget, GLuint texture, 397501e04c3fSmrg GLint level) 397601e04c3fSmrg{ 397701e04c3fSmrg framebuffer_texture_with_dims_no_error(target, attachment, textarget, 397801e04c3fSmrg texture, level, 0); 397901e04c3fSmrg} 3980af69d88dSmrg 39817117f1b4Smrg 398201e04c3fSmrgvoid GLAPIENTRY 398301e04c3fSmrg_mesa_FramebufferTexture2D(GLenum target, GLenum attachment, 398401e04c3fSmrg GLenum textarget, GLuint texture, GLint level) 398501e04c3fSmrg{ 39867ec681f3Smrg framebuffer_texture_with_dims(2, target, 0, attachment, textarget, texture, 39877ec681f3Smrg level, 0, 0, "glFramebufferTexture2D", false); 3988a8bb7a65Smaya} 3989a8bb7a65Smaya 3990a8bb7a65Smaya 3991a8bb7a65Smayavoid GLAPIENTRY 3992a8bb7a65Smaya_mesa_FramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, 3993a8bb7a65Smaya GLenum textarget, GLuint texture, 3994a8bb7a65Smaya GLint level, GLsizei samples) 3995a8bb7a65Smaya{ 39967ec681f3Smrg framebuffer_texture_with_dims(2, target, 0, attachment, textarget, texture, 39977ec681f3Smrg level, samples, 0, 39987ec681f3Smrg "glFramebufferTexture2DMultisampleEXT", 39997ec681f3Smrg false); 400001e04c3fSmrg} 400101e04c3fSmrg 400201e04c3fSmrg 400301e04c3fSmrgvoid GLAPIENTRY 400401e04c3fSmrg_mesa_FramebufferTexture3D_no_error(GLenum target, GLenum attachment, 400501e04c3fSmrg GLenum textarget, GLuint texture, 400601e04c3fSmrg GLint level, GLint layer) 400701e04c3fSmrg{ 400801e04c3fSmrg framebuffer_texture_with_dims_no_error(target, attachment, textarget, 400901e04c3fSmrg texture, level, layer); 40107117f1b4Smrg} 40117117f1b4Smrg 40127117f1b4Smrg 40137117f1b4Smrgvoid GLAPIENTRY 4014af69d88dSmrg_mesa_FramebufferTexture3D(GLenum target, GLenum attachment, 4015af69d88dSmrg GLenum textarget, GLuint texture, 401601e04c3fSmrg GLint level, GLint layer) 401701e04c3fSmrg{ 40187ec681f3Smrg framebuffer_texture_with_dims(3, target, 0, attachment, textarget, texture, 40197ec681f3Smrg level, 0, layer, "glFramebufferTexture3D", false); 402001e04c3fSmrg} 402101e04c3fSmrg 402201e04c3fSmrg 402301e04c3fSmrgstatic ALWAYS_INLINE void 402401e04c3fSmrgframe_buffer_texture(GLuint framebuffer, GLenum target, 402501e04c3fSmrg GLenum attachment, GLuint texture, 402601e04c3fSmrg GLint level, GLint layer, const char *func, 402701e04c3fSmrg bool dsa, bool no_error, bool check_layered) 40287117f1b4Smrg{ 40297117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 403001e04c3fSmrg GLboolean layered = GL_FALSE; 40317117f1b4Smrg 403201e04c3fSmrg if (!no_error && check_layered) { 403301e04c3fSmrg if (!_mesa_has_geometry_shaders(ctx)) { 403401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 403501e04c3fSmrg "unsupported function (%s) called", func); 403601e04c3fSmrg return; 403701e04c3fSmrg } 40387117f1b4Smrg } 40397117f1b4Smrg 404001e04c3fSmrg /* Get the framebuffer object */ 404101e04c3fSmrg struct gl_framebuffer *fb; 404201e04c3fSmrg if (no_error) { 404301e04c3fSmrg if (dsa) { 404401e04c3fSmrg fb = _mesa_lookup_framebuffer(ctx, framebuffer); 404501e04c3fSmrg } else { 404601e04c3fSmrg fb = get_framebuffer_target(ctx, target); 404701e04c3fSmrg } 404801e04c3fSmrg } else { 404901e04c3fSmrg if (dsa) { 405001e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func); 405101e04c3fSmrg if (!fb) 405201e04c3fSmrg return; 405301e04c3fSmrg } else { 405401e04c3fSmrg fb = get_framebuffer_target(ctx, target); 405501e04c3fSmrg if (!fb) { 405601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", 405701e04c3fSmrg func, _mesa_enum_to_string(target)); 405801e04c3fSmrg return; 405901e04c3fSmrg } 406001e04c3fSmrg } 406101e04c3fSmrg } 406201e04c3fSmrg 406301e04c3fSmrg /* Get the texture object and framebuffer attachment*/ 406401e04c3fSmrg struct gl_renderbuffer_attachment *att; 406501e04c3fSmrg struct gl_texture_object *texObj; 406601e04c3fSmrg if (no_error) { 406701e04c3fSmrg texObj = get_texture_for_framebuffer(ctx, texture); 406801e04c3fSmrg att = get_attachment(ctx, fb, attachment, NULL); 406901e04c3fSmrg } else { 407001e04c3fSmrg if (!get_texture_for_framebuffer_err(ctx, texture, check_layered, func, 407101e04c3fSmrg &texObj)) 407201e04c3fSmrg return; 407301e04c3fSmrg 407401e04c3fSmrg att = _mesa_get_and_validate_attachment(ctx, fb, attachment, func); 407501e04c3fSmrg if (!att) 407601e04c3fSmrg return; 407701e04c3fSmrg } 407801e04c3fSmrg 407901e04c3fSmrg GLenum textarget = 0; 408001e04c3fSmrg if (texObj) { 408101e04c3fSmrg if (check_layered) { 408201e04c3fSmrg /* We do this regardless of no_error because this sets layered */ 408301e04c3fSmrg if (!check_layered_texture_target(ctx, texObj->Target, func, 408401e04c3fSmrg &layered)) 408501e04c3fSmrg return; 408601e04c3fSmrg } 408701e04c3fSmrg 408801e04c3fSmrg if (!no_error) { 408901e04c3fSmrg if (!check_layered) { 409001e04c3fSmrg if (!check_texture_target(ctx, texObj->Target, func)) 409101e04c3fSmrg return; 409201e04c3fSmrg 409301e04c3fSmrg if (!check_layer(ctx, texObj->Target, layer, func)) 409401e04c3fSmrg return; 409501e04c3fSmrg } 409601e04c3fSmrg 409701e04c3fSmrg if (!check_level(ctx, texObj, texObj->Target, level, func)) 409801e04c3fSmrg return; 409901e04c3fSmrg } 410001e04c3fSmrg 410101e04c3fSmrg if (!check_layered && texObj->Target == GL_TEXTURE_CUBE_MAP) { 410201e04c3fSmrg assert(layer >= 0 && layer < 6); 410301e04c3fSmrg textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; 410401e04c3fSmrg layer = 0; 410501e04c3fSmrg } 410601e04c3fSmrg } 410701e04c3fSmrg 410801e04c3fSmrg _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, 4109a8bb7a65Smaya level, 0, layer, layered); 411001e04c3fSmrg} 411101e04c3fSmrg 411201e04c3fSmrgvoid GLAPIENTRY 411301e04c3fSmrg_mesa_FramebufferTextureLayer_no_error(GLenum target, GLenum attachment, 411401e04c3fSmrg GLuint texture, GLint level, 411501e04c3fSmrg GLint layer) 411601e04c3fSmrg{ 411701e04c3fSmrg frame_buffer_texture(0, target, attachment, texture, level, layer, 411801e04c3fSmrg "glFramebufferTextureLayer", false, true, false); 41197117f1b4Smrg} 41207117f1b4Smrg 41217117f1b4Smrg 4122c1f859d4Smrgvoid GLAPIENTRY 4123af69d88dSmrg_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, 4124af69d88dSmrg GLuint texture, GLint level, GLint layer) 4125c1f859d4Smrg{ 412601e04c3fSmrg frame_buffer_texture(0, target, attachment, texture, level, layer, 412701e04c3fSmrg "glFramebufferTextureLayer", false, false, false); 412801e04c3fSmrg} 412901e04c3fSmrg 413001e04c3fSmrg 413101e04c3fSmrgvoid GLAPIENTRY 413201e04c3fSmrg_mesa_NamedFramebufferTextureLayer_no_error(GLuint framebuffer, 413301e04c3fSmrg GLenum attachment, 413401e04c3fSmrg GLuint texture, GLint level, 413501e04c3fSmrg GLint layer) 413601e04c3fSmrg{ 413701e04c3fSmrg frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer, 413801e04c3fSmrg "glNamedFramebufferTextureLayer", true, true, false); 413901e04c3fSmrg} 414001e04c3fSmrg 414101e04c3fSmrg 414201e04c3fSmrgvoid GLAPIENTRY 414301e04c3fSmrg_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment, 414401e04c3fSmrg GLuint texture, GLint level, GLint layer) 414501e04c3fSmrg{ 414601e04c3fSmrg frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer, 414701e04c3fSmrg "glNamedFramebufferTextureLayer", true, false, false); 414801e04c3fSmrg} 4149c1f859d4Smrg 415001e04c3fSmrg 415101e04c3fSmrgvoid GLAPIENTRY 415201e04c3fSmrg_mesa_FramebufferTexture_no_error(GLenum target, GLenum attachment, 415301e04c3fSmrg GLuint texture, GLint level) 415401e04c3fSmrg{ 415501e04c3fSmrg frame_buffer_texture(0, target, attachment, texture, level, 0, 415601e04c3fSmrg "glFramebufferTexture", false, true, true); 4157af69d88dSmrg} 4158af69d88dSmrg 4159af69d88dSmrg 4160af69d88dSmrgvoid GLAPIENTRY 4161af69d88dSmrg_mesa_FramebufferTexture(GLenum target, GLenum attachment, 4162af69d88dSmrg GLuint texture, GLint level) 4163af69d88dSmrg{ 416401e04c3fSmrg frame_buffer_texture(0, target, attachment, texture, level, 0, 416501e04c3fSmrg "glFramebufferTexture", false, false, true); 416601e04c3fSmrg} 4167af69d88dSmrg 416801e04c3fSmrgvoid GLAPIENTRY 416901e04c3fSmrg_mesa_NamedFramebufferTexture_no_error(GLuint framebuffer, GLenum attachment, 417001e04c3fSmrg GLuint texture, GLint level) 417101e04c3fSmrg{ 417201e04c3fSmrg frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0, 417301e04c3fSmrg "glNamedFramebufferTexture", true, true, true); 4174c1f859d4Smrg} 4175c1f859d4Smrg 4176c1f859d4Smrg 41777117f1b4Smrgvoid GLAPIENTRY 417801e04c3fSmrg_mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, 417901e04c3fSmrg GLuint texture, GLint level) 41807117f1b4Smrg{ 418101e04c3fSmrg frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0, 418201e04c3fSmrg "glNamedFramebufferTexture", true, false, true); 418301e04c3fSmrg} 41847117f1b4Smrg 41857117f1b4Smrg 41867ec681f3Smrgvoid GLAPIENTRY 41877ec681f3Smrg_mesa_NamedFramebufferTexture1DEXT(GLuint framebuffer, GLenum attachment, 41887ec681f3Smrg GLenum textarget, GLuint texture, GLint level) 41897ec681f3Smrg{ 41907ec681f3Smrg framebuffer_texture_with_dims(1, GL_FRAMEBUFFER, framebuffer, attachment, 41917ec681f3Smrg textarget, texture, level, 0, 0, 41927ec681f3Smrg "glNamedFramebufferTexture1DEXT", true); 41937ec681f3Smrg} 41947ec681f3Smrg 41957ec681f3Smrg 41967ec681f3Smrgvoid GLAPIENTRY 41977ec681f3Smrg_mesa_NamedFramebufferTexture2DEXT(GLuint framebuffer, GLenum attachment, 41987ec681f3Smrg GLenum textarget, GLuint texture, GLint level) 41997ec681f3Smrg{ 42007ec681f3Smrg framebuffer_texture_with_dims(2, GL_FRAMEBUFFER, framebuffer, attachment, 42017ec681f3Smrg textarget, texture, level, 0, 0, 42027ec681f3Smrg "glNamedFramebufferTexture2DEXT", true); 42037ec681f3Smrg} 42047ec681f3Smrg 42057ec681f3Smrg 42067ec681f3Smrgvoid GLAPIENTRY 42077ec681f3Smrg_mesa_NamedFramebufferTexture3DEXT(GLuint framebuffer, GLenum attachment, 42087ec681f3Smrg GLenum textarget, GLuint texture, 42097ec681f3Smrg GLint level, GLint zoffset) 42107ec681f3Smrg{ 42117ec681f3Smrg framebuffer_texture_with_dims(3, GL_FRAMEBUFFER, framebuffer, attachment, 42127ec681f3Smrg textarget, texture, level, 0, zoffset, 42137ec681f3Smrg "glNamedFramebufferTexture3DEXT", true); 42147ec681f3Smrg} 42157ec681f3Smrg 42167ec681f3Smrg 421701e04c3fSmrgvoid 421801e04c3fSmrg_mesa_framebuffer_renderbuffer(struct gl_context *ctx, 421901e04c3fSmrg struct gl_framebuffer *fb, 422001e04c3fSmrg GLenum attachment, 422101e04c3fSmrg struct gl_renderbuffer *rb) 422201e04c3fSmrg{ 422301e04c3fSmrg assert(!_mesa_is_winsys_fbo(fb)); 42247117f1b4Smrg 42257ec681f3Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0); 42267117f1b4Smrg 422701e04c3fSmrg assert(ctx->Driver.FramebufferRenderbuffer); 422801e04c3fSmrg ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); 422901e04c3fSmrg 423001e04c3fSmrg /* Some subsequent GL commands may depend on the framebuffer's visual 423101e04c3fSmrg * after the binding is updated. Update visual info now. 423201e04c3fSmrg */ 423301e04c3fSmrg _mesa_update_framebuffer_visual(ctx, fb); 423401e04c3fSmrg} 423501e04c3fSmrg 423601e04c3fSmrgstatic ALWAYS_INLINE void 423701e04c3fSmrgframebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 423801e04c3fSmrg GLenum attachment, GLenum renderbuffertarget, 423901e04c3fSmrg GLuint renderbuffer, const char *func, bool no_error) 424001e04c3fSmrg{ 424101e04c3fSmrg struct gl_renderbuffer_attachment *att; 424201e04c3fSmrg struct gl_renderbuffer *rb; 424301e04c3fSmrg bool is_color_attachment; 424401e04c3fSmrg 424501e04c3fSmrg if (!no_error && renderbuffertarget != GL_RENDERBUFFER) { 42467117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 424701e04c3fSmrg "%s(renderbuffertarget is not GL_RENDERBUFFER)", func); 42487117f1b4Smrg return; 42497117f1b4Smrg } 42507117f1b4Smrg 42517117f1b4Smrg if (renderbuffer) { 425201e04c3fSmrg if (!no_error) { 425301e04c3fSmrg rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, func); 425401e04c3fSmrg if (!rb) 425501e04c3fSmrg return; 425601e04c3fSmrg } else { 425701e04c3fSmrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 42583464ebd5Sriastradh } 425901e04c3fSmrg } else { 42607117f1b4Smrg /* remove renderbuffer attachment */ 42617117f1b4Smrg rb = NULL; 42627117f1b4Smrg } 42637117f1b4Smrg 426401e04c3fSmrg if (!no_error) { 426501e04c3fSmrg if (_mesa_is_winsys_fbo(fb)) { 426601e04c3fSmrg /* Can't attach new renderbuffers to a window system framebuffer */ 42674a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 426801e04c3fSmrg "%s(window-system framebuffer)", func); 42694a49301eSmrg return; 42704a49301eSmrg } 42714a49301eSmrg 427201e04c3fSmrg att = get_attachment(ctx, fb, attachment, &is_color_attachment); 427301e04c3fSmrg if (att == NULL) { 427401e04c3fSmrg /* 427501e04c3fSmrg * From OpenGL 4.5 spec, section 9.2.7 "Attaching Renderbuffer Images 427601e04c3fSmrg * to a Framebuffer": 427701e04c3fSmrg * 427801e04c3fSmrg * "An INVALID_OPERATION error is generated if attachment is 427901e04c3fSmrg * COLOR_- ATTACHMENTm where m is greater than or equal to the 428001e04c3fSmrg * value of MAX_COLOR_- ATTACHMENTS ." 428101e04c3fSmrg * 428201e04c3fSmrg * If we are at this point, is because the attachment is not valid, so 428301e04c3fSmrg * if is_color_attachment is true, is because of the previous reason. 428401e04c3fSmrg */ 428501e04c3fSmrg if (is_color_attachment) { 428601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 428701e04c3fSmrg "%s(invalid color attachment %s)", func, 428801e04c3fSmrg _mesa_enum_to_string(attachment)); 428901e04c3fSmrg } else { 429001e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 429101e04c3fSmrg "%s(invalid attachment %s)", func, 429201e04c3fSmrg _mesa_enum_to_string(attachment)); 429301e04c3fSmrg } 42947117f1b4Smrg 429501e04c3fSmrg return; 429601e04c3fSmrg } 42977117f1b4Smrg 429801e04c3fSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && 429901e04c3fSmrg rb && rb->Format != MESA_FORMAT_NONE) { 430001e04c3fSmrg /* make sure the renderbuffer is a depth/stencil format */ 430101e04c3fSmrg const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); 430201e04c3fSmrg if (baseFormat != GL_DEPTH_STENCIL) { 430301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 430401e04c3fSmrg "%s(renderbuffer is not DEPTH_STENCIL format)", func); 430501e04c3fSmrg return; 430601e04c3fSmrg } 430701e04c3fSmrg } 430801e04c3fSmrg } 430901e04c3fSmrg 431001e04c3fSmrg _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 43117117f1b4Smrg} 43127117f1b4Smrg 431301e04c3fSmrgstatic void 431401e04c3fSmrgframebuffer_renderbuffer_error(struct gl_context *ctx, 431501e04c3fSmrg struct gl_framebuffer *fb, GLenum attachment, 431601e04c3fSmrg GLenum renderbuffertarget, 431701e04c3fSmrg GLuint renderbuffer, const char *func) 431801e04c3fSmrg{ 431901e04c3fSmrg framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget, 432001e04c3fSmrg renderbuffer, func, false); 432101e04c3fSmrg} 432201e04c3fSmrg 432301e04c3fSmrgstatic void 432401e04c3fSmrgframebuffer_renderbuffer_no_error(struct gl_context *ctx, 432501e04c3fSmrg struct gl_framebuffer *fb, GLenum attachment, 432601e04c3fSmrg GLenum renderbuffertarget, 432701e04c3fSmrg GLuint renderbuffer, const char *func) 432801e04c3fSmrg{ 432901e04c3fSmrg framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget, 433001e04c3fSmrg renderbuffer, func, true); 433101e04c3fSmrg} 43327117f1b4Smrg 43337117f1b4Smrgvoid GLAPIENTRY 433401e04c3fSmrg_mesa_FramebufferRenderbuffer_no_error(GLenum target, GLenum attachment, 433501e04c3fSmrg GLenum renderbuffertarget, 433601e04c3fSmrg GLuint renderbuffer) 43377117f1b4Smrg{ 43387117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 43397117f1b4Smrg 434001e04c3fSmrg struct gl_framebuffer *fb = get_framebuffer_target(ctx, target); 434101e04c3fSmrg framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget, 434201e04c3fSmrg renderbuffer, "glFramebufferRenderbuffer"); 434301e04c3fSmrg} 43443464ebd5Sriastradh 434501e04c3fSmrgvoid GLAPIENTRY 434601e04c3fSmrg_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, 434701e04c3fSmrg GLenum renderbuffertarget, 434801e04c3fSmrg GLuint renderbuffer) 434901e04c3fSmrg{ 435001e04c3fSmrg struct gl_framebuffer *fb; 435101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 435201e04c3fSmrg 435301e04c3fSmrg fb = get_framebuffer_target(ctx, target); 435401e04c3fSmrg if (!fb) { 43557117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 435601e04c3fSmrg "glFramebufferRenderbuffer(invalid target %s)", 435701e04c3fSmrg _mesa_enum_to_string(target)); 43587117f1b4Smrg return; 43597117f1b4Smrg } 43607117f1b4Smrg 436101e04c3fSmrg framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget, 436201e04c3fSmrg renderbuffer, "glFramebufferRenderbuffer"); 436301e04c3fSmrg} 436401e04c3fSmrg 436501e04c3fSmrgvoid GLAPIENTRY 436601e04c3fSmrg_mesa_NamedFramebufferRenderbuffer_no_error(GLuint framebuffer, 436701e04c3fSmrg GLenum attachment, 436801e04c3fSmrg GLenum renderbuffertarget, 436901e04c3fSmrg GLuint renderbuffer) 437001e04c3fSmrg{ 437101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 437201e04c3fSmrg 437301e04c3fSmrg struct gl_framebuffer *fb = _mesa_lookup_framebuffer(ctx, framebuffer); 437401e04c3fSmrg framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget, 437501e04c3fSmrg renderbuffer, 437601e04c3fSmrg "glNamedFramebufferRenderbuffer"); 437701e04c3fSmrg} 437801e04c3fSmrg 437901e04c3fSmrgvoid GLAPIENTRY 438001e04c3fSmrg_mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, 438101e04c3fSmrg GLenum renderbuffertarget, 438201e04c3fSmrg GLuint renderbuffer) 438301e04c3fSmrg{ 438401e04c3fSmrg struct gl_framebuffer *fb; 438501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 438601e04c3fSmrg 438701e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 438801e04c3fSmrg "glNamedFramebufferRenderbuffer"); 438901e04c3fSmrg if (!fb) 439001e04c3fSmrg return; 439101e04c3fSmrg 439201e04c3fSmrg framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget, 439301e04c3fSmrg renderbuffer, 439401e04c3fSmrg "glNamedFramebufferRenderbuffer"); 439501e04c3fSmrg} 439601e04c3fSmrg 439701e04c3fSmrg 43987ec681f3Smrgvoid GLAPIENTRY 43997ec681f3Smrg_mesa_NamedFramebufferRenderbufferEXT(GLuint framebuffer, GLenum attachment, 44007ec681f3Smrg GLenum renderbuffertarget, 44017ec681f3Smrg GLuint renderbuffer) 44027ec681f3Smrg{ 44037ec681f3Smrg struct gl_framebuffer *fb; 44047ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 44057ec681f3Smrg 44067ec681f3Smrg fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, 44077ec681f3Smrg "glNamedFramebufferRenderbufferEXT"); 44087ec681f3Smrg if (!fb) 44097ec681f3Smrg return; 44107ec681f3Smrg 44117ec681f3Smrg framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget, 44127ec681f3Smrg renderbuffer, 44137ec681f3Smrg "glNamedFramebufferRenderbuffer"); 44147ec681f3Smrg} 44157ec681f3Smrg 44167ec681f3Smrg 441701e04c3fSmrgstatic void 441801e04c3fSmrgget_framebuffer_attachment_parameter(struct gl_context *ctx, 441901e04c3fSmrg struct gl_framebuffer *buffer, 442001e04c3fSmrg GLenum attachment, GLenum pname, 442101e04c3fSmrg GLint *params, const char *caller) 442201e04c3fSmrg{ 442301e04c3fSmrg const struct gl_renderbuffer_attachment *att; 442401e04c3fSmrg bool is_color_attachment = false; 442501e04c3fSmrg GLenum err; 442601e04c3fSmrg 442701e04c3fSmrg /* The error code for an attachment type of GL_NONE differs between APIs. 442801e04c3fSmrg * 442901e04c3fSmrg * From the ES 2.0.25 specification, page 127: 443001e04c3fSmrg * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then 443101e04c3fSmrg * querying any other pname will generate INVALID_ENUM." 443201e04c3fSmrg * 443301e04c3fSmrg * From the OpenGL 3.0 specification, page 337, or identically, 443401e04c3fSmrg * the OpenGL ES 3.0.4 specification, page 240: 443501e04c3fSmrg * 443601e04c3fSmrg * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, no 443701e04c3fSmrg * framebuffer is bound to target. In this case querying pname 443801e04c3fSmrg * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero, and all other 443901e04c3fSmrg * queries will generate an INVALID_OPERATION error." 444001e04c3fSmrg */ 444101e04c3fSmrg err = ctx->API == API_OPENGLES2 && ctx->Version < 30 ? 444201e04c3fSmrg GL_INVALID_ENUM : GL_INVALID_OPERATION; 444301e04c3fSmrg 4444af69d88dSmrg if (_mesa_is_winsys_fbo(buffer)) { 4445af69d88dSmrg /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec 4446af69d88dSmrg * says: 4447af69d88dSmrg * 4448af69d88dSmrg * "If the framebuffer currently bound to target is zero, then 4449af69d88dSmrg * INVALID_OPERATION is generated." 4450af69d88dSmrg * 4451af69d88dSmrg * The EXT_framebuffer_object spec has the same wording, and the 4452af69d88dSmrg * OES_framebuffer_object spec refers to the EXT_framebuffer_object 4453af69d88dSmrg * spec. 4454af69d88dSmrg */ 4455af69d88dSmrg if ((!_mesa_is_desktop_gl(ctx) || 4456af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 4457af69d88dSmrg && !_mesa_is_gles3(ctx)) { 445801e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 445901e04c3fSmrg "%s(window-system framebuffer)", caller); 446001e04c3fSmrg return; 4461af69d88dSmrg } 4462af69d88dSmrg 4463af69d88dSmrg if (_mesa_is_gles3(ctx) && attachment != GL_BACK && 4464af69d88dSmrg attachment != GL_DEPTH && attachment != GL_STENCIL) { 446501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 446601e04c3fSmrg "%s(invalid attachment %s)", caller, 446701e04c3fSmrg _mesa_enum_to_string(attachment)); 446801e04c3fSmrg return; 446901e04c3fSmrg } 447001e04c3fSmrg 447101e04c3fSmrg /* The specs are not clear about how to handle 447201e04c3fSmrg * GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME with the default framebuffer, 447301e04c3fSmrg * but dEQP-GLES3 expects an INVALID_ENUM error. This has also been 447401e04c3fSmrg * discussed in: 447501e04c3fSmrg * 447601e04c3fSmrg * https://cvs.khronos.org/bugzilla/show_bug.cgi?id=12928#c1 447701e04c3fSmrg * and https://bugs.freedesktop.org/show_bug.cgi?id=31947 447801e04c3fSmrg */ 447901e04c3fSmrg if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) { 448001e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 448101e04c3fSmrg "%s(requesting GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME " 448201e04c3fSmrg "when GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is " 448301e04c3fSmrg "GL_FRAMEBUFFER_DEFAULT is not allowed)", caller); 4484af69d88dSmrg return; 4485af69d88dSmrg } 448601e04c3fSmrg 44873464ebd5Sriastradh /* the default / window-system FBO */ 448801e04c3fSmrg att = get_fb0_attachment(ctx, buffer, attachment); 44893464ebd5Sriastradh } 44903464ebd5Sriastradh else { 44913464ebd5Sriastradh /* user-created framebuffer FBO */ 449201e04c3fSmrg att = get_attachment(ctx, buffer, attachment, &is_color_attachment); 44937117f1b4Smrg } 44947117f1b4Smrg 44957117f1b4Smrg if (att == NULL) { 449601e04c3fSmrg /* 449701e04c3fSmrg * From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries": 449801e04c3fSmrg * 449901e04c3fSmrg * "An INVALID_OPERATION error is generated if a framebuffer object 450001e04c3fSmrg * is bound to target and attachment is COLOR_ATTACHMENTm where m is 450101e04c3fSmrg * greater than or equal to the value of MAX_COLOR_ATTACHMENTS." 450201e04c3fSmrg * 450301e04c3fSmrg * If we are at this point, is because the attachment is not valid, so 450401e04c3fSmrg * if is_color_attachment is true, is because of the previous reason. 450501e04c3fSmrg */ 450601e04c3fSmrg if (is_color_attachment) { 450701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid color attachment %s)", 450801e04c3fSmrg caller, _mesa_enum_to_string(attachment)); 450901e04c3fSmrg } else { 451001e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller, 451101e04c3fSmrg _mesa_enum_to_string(attachment)); 451201e04c3fSmrg } 45137117f1b4Smrg return; 45147117f1b4Smrg } 45157117f1b4Smrg 45164a49301eSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 45174a49301eSmrg const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; 4518af69d88dSmrg if (pname == GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) { 4519af69d88dSmrg /* This behavior is first specified in OpenGL 4.4 specification. 4520af69d88dSmrg * 4521af69d88dSmrg * From the OpenGL 4.4 spec page 275: 4522af69d88dSmrg * "This query cannot be performed for a combined depth+stencil 4523af69d88dSmrg * attachment, since it does not have a single format." 4524af69d88dSmrg */ 4525af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 452601e04c3fSmrg "%s(GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE" 452701e04c3fSmrg " is invalid for depth+stencil attachment)", caller); 4528af69d88dSmrg return; 4529af69d88dSmrg } 4530af69d88dSmrg /* the depth and stencil attachments must point to the same buffer */ 453101e04c3fSmrg depthAtt = get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT, NULL); 453201e04c3fSmrg stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT, NULL); 45334a49301eSmrg if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { 45344a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 453501e04c3fSmrg "%s(DEPTH/STENCIL attachments differ)", caller); 45364a49301eSmrg return; 45374a49301eSmrg } 45384a49301eSmrg } 45394a49301eSmrg 45404a49301eSmrg /* No need to flush here */ 45417117f1b4Smrg 45427117f1b4Smrg switch (pname) { 45437117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 454401e04c3fSmrg /* From the OpenGL spec, 9.2. Binding and Managing Framebuffer Objects: 454501e04c3fSmrg * 454601e04c3fSmrg * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then 454701e04c3fSmrg * either no framebuffer is bound to target; or the default framebuffer 454801e04c3fSmrg * is bound, attachment is DEPTH or STENCIL, and the number of depth or 454901e04c3fSmrg * stencil bits, respectively, is zero." 455001e04c3fSmrg * 455101e04c3fSmrg * Note that we don't need explicit checks on DEPTH and STENCIL, because 455201e04c3fSmrg * on the case the spec is pointing, att->Type is already NONE, so we 455301e04c3fSmrg * just need to check att->Type. 455401e04c3fSmrg */ 455501e04c3fSmrg *params = (_mesa_is_winsys_fbo(buffer) && att->Type != GL_NONE) ? 455601e04c3fSmrg GL_FRAMEBUFFER_DEFAULT : att->Type; 45577117f1b4Smrg return; 45587117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 45597117f1b4Smrg if (att->Type == GL_RENDERBUFFER_EXT) { 456001e04c3fSmrg *params = att->Renderbuffer->Name; 45617117f1b4Smrg } 45627117f1b4Smrg else if (att->Type == GL_TEXTURE) { 456301e04c3fSmrg *params = att->Texture->Name; 45647117f1b4Smrg } 45657117f1b4Smrg else { 45663464ebd5Sriastradh assert(att->Type == GL_NONE); 4567af69d88dSmrg if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { 45683464ebd5Sriastradh *params = 0; 45693464ebd5Sriastradh } else { 4570af69d88dSmrg goto invalid_pname_enum; 45713464ebd5Sriastradh } 45727117f1b4Smrg } 45737117f1b4Smrg return; 45747117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 45757117f1b4Smrg if (att->Type == GL_TEXTURE) { 457601e04c3fSmrg *params = att->TextureLevel; 45777117f1b4Smrg } 45783464ebd5Sriastradh else if (att->Type == GL_NONE) { 457901e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 458001e04c3fSmrg _mesa_enum_to_string(pname)); 45813464ebd5Sriastradh } 45827117f1b4Smrg else { 4583af69d88dSmrg goto invalid_pname_enum; 45847117f1b4Smrg } 45857117f1b4Smrg return; 45867117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 45877117f1b4Smrg if (att->Type == GL_TEXTURE) { 4588c1f859d4Smrg if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { 4589c1f859d4Smrg *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 4590c1f859d4Smrg } 4591c1f859d4Smrg else { 4592c1f859d4Smrg *params = 0; 4593c1f859d4Smrg } 45947117f1b4Smrg } 45953464ebd5Sriastradh else if (att->Type == GL_NONE) { 459601e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 459701e04c3fSmrg _mesa_enum_to_string(pname)); 45983464ebd5Sriastradh } 45997117f1b4Smrg else { 4600af69d88dSmrg goto invalid_pname_enum; 46017117f1b4Smrg } 46027117f1b4Smrg return; 46037117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 4604af69d88dSmrg if (ctx->API == API_OPENGLES) { 4605af69d88dSmrg goto invalid_pname_enum; 4606af69d88dSmrg } else if (att->Type == GL_NONE) { 460701e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 460801e04c3fSmrg _mesa_enum_to_string(pname)); 4609af69d88dSmrg } else if (att->Type == GL_TEXTURE) { 461001e04c3fSmrg if (att->Texture && (att->Texture->Target == GL_TEXTURE_3D || 461101e04c3fSmrg att->Texture->Target == GL_TEXTURE_2D_ARRAY)) { 4612c1f859d4Smrg *params = att->Zoffset; 4613c1f859d4Smrg } 4614c1f859d4Smrg else { 4615c1f859d4Smrg *params = 0; 4616c1f859d4Smrg } 46177117f1b4Smrg } 46187117f1b4Smrg else { 4619af69d88dSmrg goto invalid_pname_enum; 46207117f1b4Smrg } 46217117f1b4Smrg return; 46224a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: 4623af69d88dSmrg if ((!_mesa_is_desktop_gl(ctx) || 4624af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 4625af69d88dSmrg && !_mesa_is_gles3(ctx)) { 4626af69d88dSmrg goto invalid_pname_enum; 46274a49301eSmrg } 46283464ebd5Sriastradh else if (att->Type == GL_NONE) { 462901e04c3fSmrg if (_mesa_is_winsys_fbo(buffer) && 463001e04c3fSmrg (attachment == GL_DEPTH || attachment == GL_STENCIL)) { 463101e04c3fSmrg *params = GL_LINEAR; 463201e04c3fSmrg } else { 463301e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 463401e04c3fSmrg _mesa_enum_to_string(pname)); 463501e04c3fSmrg } 46363464ebd5Sriastradh } 46374a49301eSmrg else { 4638a8bb7a65Smaya if (ctx->Extensions.EXT_sRGB) { 46397ec681f3Smrg *params = (_mesa_is_format_srgb(att->Renderbuffer->Format) ? 46407ec681f3Smrg GL_SRGB : GL_LINEAR); 46413464ebd5Sriastradh } 46423464ebd5Sriastradh else { 46433464ebd5Sriastradh /* According to ARB_framebuffer_sRGB, we should return LINEAR 46443464ebd5Sriastradh * if the sRGB conversion is unsupported. */ 46453464ebd5Sriastradh *params = GL_LINEAR; 46463464ebd5Sriastradh } 46474a49301eSmrg } 46484a49301eSmrg return; 46494a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: 4650af69d88dSmrg if ((ctx->API != API_OPENGL_COMPAT || 4651af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 4652af69d88dSmrg && ctx->API != API_OPENGL_CORE 4653af69d88dSmrg && !_mesa_is_gles3(ctx)) { 4654af69d88dSmrg goto invalid_pname_enum; 46554a49301eSmrg } 46563464ebd5Sriastradh else if (att->Type == GL_NONE) { 465701e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 465801e04c3fSmrg _mesa_enum_to_string(pname)); 46593464ebd5Sriastradh } 46604a49301eSmrg else { 4661af69d88dSmrg mesa_format format = att->Renderbuffer->Format; 4662af69d88dSmrg 4663af69d88dSmrg /* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES 4664af69d88dSmrg * 3.0.1 spec says: 4665af69d88dSmrg * 4666af69d88dSmrg * "If pname is FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE.... If 4667af69d88dSmrg * attachment is DEPTH_STENCIL_ATTACHMENT the query will fail and 4668af69d88dSmrg * generate an INVALID_OPERATION error. 4669af69d88dSmrg */ 4670af69d88dSmrg if (_mesa_is_gles3(ctx) && 4671af69d88dSmrg attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 4672af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 467301e04c3fSmrg "%s(cannot query " 4674af69d88dSmrg "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of " 467501e04c3fSmrg "GL_DEPTH_STENCIL_ATTACHMENT)", caller); 4676af69d88dSmrg return; 4677af69d88dSmrg } 4678af69d88dSmrg 4679af69d88dSmrg if (format == MESA_FORMAT_S_UINT8) { 46804a49301eSmrg /* special cases */ 46814a49301eSmrg *params = GL_INDEX; 46824a49301eSmrg } 4683af69d88dSmrg else if (format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) { 4684af69d88dSmrg /* depends on the attachment parameter */ 4685af69d88dSmrg if (attachment == GL_STENCIL_ATTACHMENT) { 4686af69d88dSmrg *params = GL_INDEX; 4687af69d88dSmrg } 4688af69d88dSmrg else { 4689af69d88dSmrg *params = GL_FLOAT; 4690af69d88dSmrg } 4691af69d88dSmrg } 46924a49301eSmrg else { 46934a49301eSmrg *params = _mesa_get_format_datatype(format); 46944a49301eSmrg } 46954a49301eSmrg } 46964a49301eSmrg return; 46974a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: 46984a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 46994a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 47004a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 47014a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 47024a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 4703af69d88dSmrg if ((!_mesa_is_desktop_gl(ctx) || 4704af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 4705af69d88dSmrg && !_mesa_is_gles3(ctx)) { 4706af69d88dSmrg goto invalid_pname_enum; 47074a49301eSmrg } 47084a49301eSmrg else if (att->Texture) { 47094a49301eSmrg const struct gl_texture_image *texImage = 471001e04c3fSmrg _mesa_select_tex_image(att->Texture, att->Texture->Target, 47114a49301eSmrg att->TextureLevel); 47124a49301eSmrg if (texImage) { 47134a49301eSmrg *params = get_component_bits(pname, texImage->_BaseFormat, 47144a49301eSmrg texImage->TexFormat); 47154a49301eSmrg } 47164a49301eSmrg else { 47174a49301eSmrg *params = 0; 47184a49301eSmrg } 47194a49301eSmrg } 47204a49301eSmrg else if (att->Renderbuffer) { 47214a49301eSmrg *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, 47224a49301eSmrg att->Renderbuffer->Format); 47234a49301eSmrg } 47244a49301eSmrg else { 472501e04c3fSmrg assert(att->Type == GL_NONE); 472601e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 472701e04c3fSmrg _mesa_enum_to_string(pname)); 47284a49301eSmrg } 47294a49301eSmrg return; 4730af69d88dSmrg case GL_FRAMEBUFFER_ATTACHMENT_LAYERED: 4731af69d88dSmrg if (!_mesa_has_geometry_shaders(ctx)) { 4732af69d88dSmrg goto invalid_pname_enum; 4733af69d88dSmrg } else if (att->Type == GL_TEXTURE) { 4734af69d88dSmrg *params = att->Layered; 4735af69d88dSmrg } else if (att->Type == GL_NONE) { 473601e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 473701e04c3fSmrg _mesa_enum_to_string(pname)); 4738af69d88dSmrg } else { 4739af69d88dSmrg goto invalid_pname_enum; 4740af69d88dSmrg } 47417117f1b4Smrg return; 4742a8bb7a65Smaya case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT: 4743a8bb7a65Smaya if (!ctx->Extensions.EXT_multisampled_render_to_texture) { 4744a8bb7a65Smaya goto invalid_pname_enum; 4745a8bb7a65Smaya } else if (att->Type == GL_TEXTURE) { 4746a8bb7a65Smaya *params = att->NumSamples; 4747a8bb7a65Smaya } else if (att->Type == GL_NONE) { 4748a8bb7a65Smaya _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 4749a8bb7a65Smaya _mesa_enum_to_string(pname)); 4750a8bb7a65Smaya } else { 4751a8bb7a65Smaya goto invalid_pname_enum; 4752a8bb7a65Smaya } 4753a8bb7a65Smaya return; 4754af69d88dSmrg default: 4755af69d88dSmrg goto invalid_pname_enum; 47567117f1b4Smrg } 4757af69d88dSmrg 4758af69d88dSmrg return; 4759af69d88dSmrg 4760af69d88dSmrginvalid_pname_enum: 476101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname %s)", caller, 476201e04c3fSmrg _mesa_enum_to_string(pname)); 4763af69d88dSmrg return; 47647117f1b4Smrg} 47657117f1b4Smrg 47667117f1b4Smrg 476701e04c3fSmrgvoid GLAPIENTRY 476801e04c3fSmrg_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, 476901e04c3fSmrg GLenum pname, GLint *params) 477001e04c3fSmrg{ 477101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 477201e04c3fSmrg struct gl_framebuffer *buffer; 477301e04c3fSmrg 477401e04c3fSmrg buffer = get_framebuffer_target(ctx, target); 477501e04c3fSmrg if (!buffer) { 477601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 477701e04c3fSmrg "glGetFramebufferAttachmentParameteriv(invalid target %s)", 477801e04c3fSmrg _mesa_enum_to_string(target)); 477901e04c3fSmrg return; 478001e04c3fSmrg } 478101e04c3fSmrg 478201e04c3fSmrg get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, 478301e04c3fSmrg params, 478401e04c3fSmrg "glGetFramebufferAttachmentParameteriv"); 478501e04c3fSmrg} 478601e04c3fSmrg 478701e04c3fSmrg 478801e04c3fSmrgvoid GLAPIENTRY 478901e04c3fSmrg_mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, 479001e04c3fSmrg GLenum attachment, 479101e04c3fSmrg GLenum pname, GLint *params) 479201e04c3fSmrg{ 479301e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 479401e04c3fSmrg struct gl_framebuffer *buffer; 479501e04c3fSmrg 479601e04c3fSmrg if (framebuffer) { 479701e04c3fSmrg buffer = _mesa_lookup_framebuffer_err(ctx, framebuffer, 479801e04c3fSmrg "glGetNamedFramebufferAttachmentParameteriv"); 479901e04c3fSmrg if (!buffer) 480001e04c3fSmrg return; 480101e04c3fSmrg } 480201e04c3fSmrg else { 480301e04c3fSmrg /* 480401e04c3fSmrg * Section 9.2 Binding and Managing Framebuffer Objects of the OpenGL 480501e04c3fSmrg * 4.5 core spec (30.10.2014, PDF page 314): 480601e04c3fSmrg * "If framebuffer is zero, then the default draw framebuffer is 480701e04c3fSmrg * queried." 480801e04c3fSmrg */ 480901e04c3fSmrg buffer = ctx->WinSysDrawBuffer; 481001e04c3fSmrg } 481101e04c3fSmrg 481201e04c3fSmrg get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, 481301e04c3fSmrg params, 481401e04c3fSmrg "glGetNamedFramebufferAttachmentParameteriv"); 481501e04c3fSmrg} 481601e04c3fSmrg 481701e04c3fSmrg 48187ec681f3Smrgvoid GLAPIENTRY 48197ec681f3Smrg_mesa_GetNamedFramebufferAttachmentParameterivEXT(GLuint framebuffer, 48207ec681f3Smrg GLenum attachment, 48217ec681f3Smrg GLenum pname, GLint *params) 48227ec681f3Smrg{ 48237ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 48247ec681f3Smrg struct gl_framebuffer *buffer; 48257ec681f3Smrg 48267ec681f3Smrg if (framebuffer) { 48277ec681f3Smrg buffer = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, 48287ec681f3Smrg "glGetNamedFramebufferAttachmentParameterivEXT"); 48297ec681f3Smrg if (!buffer) 48307ec681f3Smrg return; 48317ec681f3Smrg } 48327ec681f3Smrg else { 48337ec681f3Smrg /* 48347ec681f3Smrg * Section 9.2 Binding and Managing Framebuffer Objects of the OpenGL 48357ec681f3Smrg * 4.5 core spec (30.10.2014, PDF page 314): 48367ec681f3Smrg * "If framebuffer is zero, then the default draw framebuffer is 48377ec681f3Smrg * queried." 48387ec681f3Smrg */ 48397ec681f3Smrg buffer = ctx->WinSysDrawBuffer; 48407ec681f3Smrg } 48417ec681f3Smrg 48427ec681f3Smrg get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, 48437ec681f3Smrg params, 48447ec681f3Smrg "glGetNamedFramebufferAttachmentParameterivEXT"); 48457ec681f3Smrg} 48467ec681f3Smrg 48477ec681f3Smrg 484801e04c3fSmrgvoid GLAPIENTRY 484901e04c3fSmrg_mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, 485001e04c3fSmrg GLint param) 485101e04c3fSmrg{ 485201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 485301e04c3fSmrg struct gl_framebuffer *fb = NULL; 485401e04c3fSmrg 485501e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments && 485601e04c3fSmrg !ctx->Extensions.ARB_sample_locations) { 485701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 485801e04c3fSmrg "glNamedFramebufferParameteri(" 485901e04c3fSmrg "neither ARB_framebuffer_no_attachments nor " 486001e04c3fSmrg "ARB_sample_locations is available)"); 486101e04c3fSmrg return; 486201e04c3fSmrg } 486301e04c3fSmrg 486401e04c3fSmrg if (framebuffer) { 486501e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 486601e04c3fSmrg "glNamedFramebufferParameteri"); 486701e04c3fSmrg } else { 486801e04c3fSmrg fb = ctx->WinSysDrawBuffer; 486901e04c3fSmrg } 487001e04c3fSmrg 487101e04c3fSmrg if (fb) { 487201e04c3fSmrg framebuffer_parameteri(ctx, fb, pname, param, 487301e04c3fSmrg "glNamedFramebufferParameteriv"); 487401e04c3fSmrg } 487501e04c3fSmrg} 487601e04c3fSmrg 487701e04c3fSmrg 48787ec681f3Smrg/* Helper function for ARB_framebuffer_no_attachments functions interacting with EXT_direct_state_access */ 48797ec681f3Smrgstatic struct gl_framebuffer * 48807ec681f3Smrglookup_named_framebuffer_ext_dsa(struct gl_context *ctx, GLuint framebuffer, const char* caller) 48817ec681f3Smrg{ 48827ec681f3Smrg struct gl_framebuffer *fb = NULL; 48837ec681f3Smrg 48847ec681f3Smrg if (framebuffer) { 48857ec681f3Smrg /* The ARB_framebuffer_no_attachments spec says: 48867ec681f3Smrg * 48877ec681f3Smrg * "The error INVALID_VALUE is generated if <framebuffer> is not 48887ec681f3Smrg * a name returned by GenFramebuffers. If a framebuffer object 48897ec681f3Smrg * named <framebuffer> does not yet exist, it will be created." 48907ec681f3Smrg * 48917ec681f3Smrg * This is different from the EXT_direct_state_access spec which says: 48927ec681f3Smrg * 48937ec681f3Smrg * "If the framebuffer object named by the framebuffer parameter has not 48947ec681f3Smrg * been previously bound or has been deleted since the last binding, 48957ec681f3Smrg * the GL first creates a new state vector in the same manner as when 48967ec681f3Smrg * BindFramebuffer creates a new framebuffer object" 48977ec681f3Smrg * 48987ec681f3Smrg * So first we verify that the name exists. 48997ec681f3Smrg */ 49007ec681f3Smrg fb = _mesa_lookup_framebuffer(ctx, framebuffer); 49017ec681f3Smrg if (!fb) { 49027ec681f3Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(frameBuffer)", caller); 49037ec681f3Smrg return NULL; 49047ec681f3Smrg } 49057ec681f3Smrg /* Then, make sure it's initialized */ 49067ec681f3Smrg if (fb == &DummyFramebuffer) { 49077ec681f3Smrg fb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 49087ec681f3Smrg _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, fb, true); 49097ec681f3Smrg } 49107ec681f3Smrg } 49117ec681f3Smrg else 49127ec681f3Smrg fb = ctx->WinSysDrawBuffer; 49137ec681f3Smrg 49147ec681f3Smrg return fb; 49157ec681f3Smrg} 49167ec681f3Smrg 49177ec681f3Smrg 49187ec681f3Smrgvoid GLAPIENTRY 49197ec681f3Smrg_mesa_NamedFramebufferParameteriEXT(GLuint framebuffer, GLenum pname, 49207ec681f3Smrg GLint param) 49217ec681f3Smrg{ 49227ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 49237ec681f3Smrg struct gl_framebuffer *fb = 49247ec681f3Smrg lookup_named_framebuffer_ext_dsa(ctx, framebuffer, 49257ec681f3Smrg "glNamedFramebufferParameteriEXT"); 49267ec681f3Smrg 49277ec681f3Smrg if (!fb) 49287ec681f3Smrg return; 49297ec681f3Smrg 49307ec681f3Smrg framebuffer_parameteri(ctx, fb, pname, param, 49317ec681f3Smrg "glNamedFramebufferParameteriEXT"); 49327ec681f3Smrg} 49337ec681f3Smrg 49347ec681f3Smrg 49357ec681f3Smrgvoid GLAPIENTRY 49367ec681f3Smrg_mesa_GetFramebufferParameterivEXT(GLuint framebuffer, GLenum pname, 49377ec681f3Smrg GLint *param) 49387ec681f3Smrg{ 49397ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 49407ec681f3Smrg struct gl_framebuffer *fb; 49417ec681f3Smrg 49427ec681f3Smrg if (framebuffer) 49437ec681f3Smrg fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, 49447ec681f3Smrg "glGetFramebufferParameterivEXT"); 49457ec681f3Smrg else 49467ec681f3Smrg fb = ctx->WinSysDrawBuffer; 49477ec681f3Smrg 49487ec681f3Smrg if (fb) { 49497ec681f3Smrg /* The GL_EXT_direct_state_access says: 49507ec681f3Smrg * 49517ec681f3Smrg * The pname parameter must be one of framebuffer dependent values 49527ec681f3Smrg * listed in either table 4.nnn (namely DRAW_BUFFER, READ_BUFFER, 49537ec681f3Smrg * or DRAW_BUFFER0 through DRAW_BUFFER15). 49547ec681f3Smrg */ 49557ec681f3Smrg if (pname == GL_DRAW_BUFFER) { 49567ec681f3Smrg *param = fb->ColorDrawBuffer[0]; 49577ec681f3Smrg 49587ec681f3Smrg } 49597ec681f3Smrg else if (pname == GL_READ_BUFFER) { 49607ec681f3Smrg *param = fb->ColorReadBuffer; 49617ec681f3Smrg } 49627ec681f3Smrg else if (GL_DRAW_BUFFER0 <= pname && pname <= GL_DRAW_BUFFER15) { 49637ec681f3Smrg unsigned buffer = pname - GL_DRAW_BUFFER0; 49647ec681f3Smrg if (buffer < ARRAY_SIZE(fb->ColorDrawBuffer)) 49657ec681f3Smrg *param = fb->ColorDrawBuffer[buffer]; 49667ec681f3Smrg else 49677ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferParameterivEXT(pname)"); 49687ec681f3Smrg } 49697ec681f3Smrg else { 49707ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferParameterivEXT(pname)"); 49717ec681f3Smrg } 49727ec681f3Smrg } 49737ec681f3Smrg} 49747ec681f3Smrg 49757ec681f3Smrg 497601e04c3fSmrgvoid GLAPIENTRY 497701e04c3fSmrg_mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, 497801e04c3fSmrg GLint *param) 497901e04c3fSmrg{ 498001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 498101e04c3fSmrg struct gl_framebuffer *fb; 498201e04c3fSmrg 498301e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments) { 498401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 498501e04c3fSmrg "glNamedFramebufferParameteriv(" 498601e04c3fSmrg "neither ARB_framebuffer_no_attachments nor ARB_sample_locations" 498701e04c3fSmrg " is available)"); 498801e04c3fSmrg return; 498901e04c3fSmrg } 499001e04c3fSmrg 499101e04c3fSmrg if (framebuffer) 499201e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 499301e04c3fSmrg "glGetNamedFramebufferParameteriv"); 499401e04c3fSmrg else 499501e04c3fSmrg fb = ctx->WinSysDrawBuffer; 499601e04c3fSmrg 499701e04c3fSmrg if (fb) { 499801e04c3fSmrg get_framebuffer_parameteriv(ctx, fb, pname, param, 499901e04c3fSmrg "glGetNamedFramebufferParameteriv"); 500001e04c3fSmrg } 500101e04c3fSmrg} 500201e04c3fSmrg 500301e04c3fSmrg 50047ec681f3Smrgvoid GLAPIENTRY 50057ec681f3Smrg_mesa_GetNamedFramebufferParameterivEXT(GLuint framebuffer, GLenum pname, 50067ec681f3Smrg GLint *param) 50077ec681f3Smrg{ 50087ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 50097ec681f3Smrg struct gl_framebuffer *fb = 50107ec681f3Smrg lookup_named_framebuffer_ext_dsa(ctx, framebuffer, 50117ec681f3Smrg "glGetNamedFramebufferParameterivEXT"); 50127ec681f3Smrg 50137ec681f3Smrg if (!fb) 50147ec681f3Smrg return; 50157ec681f3Smrg 50167ec681f3Smrg get_framebuffer_parameteriv(ctx, fb, pname, param, 50177ec681f3Smrg "glGetNamedFramebufferParameterivEXT"); 50187ec681f3Smrg} 50197ec681f3Smrg 50207ec681f3Smrg 5021af69d88dSmrgstatic void 502201e04c3fSmrginvalidate_framebuffer_storage(struct gl_context *ctx, 502301e04c3fSmrg struct gl_framebuffer *fb, 502401e04c3fSmrg GLsizei numAttachments, 5025af69d88dSmrg const GLenum *attachments, GLint x, GLint y, 5026af69d88dSmrg GLsizei width, GLsizei height, const char *name) 50277117f1b4Smrg{ 5028af69d88dSmrg int i; 50297117f1b4Smrg 503001e04c3fSmrg /* Section 17.4 Whole Framebuffer Operations of the OpenGL 4.5 Core 503101e04c3fSmrg * Spec (2.2.2015, PDF page 522) says: 503201e04c3fSmrg * "An INVALID_VALUE error is generated if numAttachments, width, or 503301e04c3fSmrg * height is negative." 503401e04c3fSmrg */ 503501e04c3fSmrg if (numAttachments < 0) { 503601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 503701e04c3fSmrg "%s(numAttachments < 0)", name); 50387117f1b4Smrg return; 50397117f1b4Smrg } 50407117f1b4Smrg 504101e04c3fSmrg if (width < 0) { 5042af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 504301e04c3fSmrg "%s(width < 0)", name); 504401e04c3fSmrg return; 504501e04c3fSmrg } 504601e04c3fSmrg 504701e04c3fSmrg if (height < 0) { 504801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 504901e04c3fSmrg "%s(height < 0)", name); 50504a49301eSmrg return; 50514a49301eSmrg } 50527117f1b4Smrg 5053af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 5054af69d88dSmrg * 5055af69d88dSmrg * "If an attachment is specified that does not exist in the 5056af69d88dSmrg * framebuffer bound to <target>, it is ignored." 5057af69d88dSmrg * 5058af69d88dSmrg * It also says: 5059af69d88dSmrg * 5060af69d88dSmrg * "If <attachments> contains COLOR_ATTACHMENTm and m is greater than 5061af69d88dSmrg * or equal to the value of MAX_COLOR_ATTACHMENTS, then the error 5062af69d88dSmrg * INVALID_OPERATION is generated." 5063af69d88dSmrg * 5064af69d88dSmrg * No mention is made of GL_AUXi being out of range. Therefore, we allow 5065af69d88dSmrg * any enum that can be allowed by the API (OpenGL ES 3.0 has a different 5066af69d88dSmrg * set of retrictions). 5067af69d88dSmrg */ 5068af69d88dSmrg for (i = 0; i < numAttachments; i++) { 5069af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) { 5070af69d88dSmrg switch (attachments[i]) { 5071af69d88dSmrg case GL_ACCUM: 5072af69d88dSmrg case GL_AUX0: 5073af69d88dSmrg case GL_AUX1: 5074af69d88dSmrg case GL_AUX2: 5075af69d88dSmrg case GL_AUX3: 5076af69d88dSmrg /* Accumulation buffers and auxilary buffers were removed in 5077af69d88dSmrg * OpenGL 3.1, and they never existed in OpenGL ES. 5078af69d88dSmrg */ 5079af69d88dSmrg if (ctx->API != API_OPENGL_COMPAT) 5080af69d88dSmrg goto invalid_enum; 5081af69d88dSmrg break; 5082af69d88dSmrg case GL_COLOR: 5083af69d88dSmrg case GL_DEPTH: 5084af69d88dSmrg case GL_STENCIL: 5085af69d88dSmrg break; 5086af69d88dSmrg case GL_BACK_LEFT: 5087af69d88dSmrg case GL_BACK_RIGHT: 5088af69d88dSmrg case GL_FRONT_LEFT: 5089af69d88dSmrg case GL_FRONT_RIGHT: 5090af69d88dSmrg if (!_mesa_is_desktop_gl(ctx)) 5091af69d88dSmrg goto invalid_enum; 5092af69d88dSmrg break; 5093af69d88dSmrg default: 5094af69d88dSmrg goto invalid_enum; 5095af69d88dSmrg } 5096af69d88dSmrg } else { 5097af69d88dSmrg switch (attachments[i]) { 5098af69d88dSmrg case GL_DEPTH_ATTACHMENT: 5099af69d88dSmrg case GL_STENCIL_ATTACHMENT: 5100af69d88dSmrg break; 510101e04c3fSmrg case GL_DEPTH_STENCIL_ATTACHMENT: 510201e04c3fSmrg /* GL_DEPTH_STENCIL_ATTACHMENT is a valid attachment point only 510301e04c3fSmrg * in desktop and ES 3.0 profiles. Note that OES_packed_depth_stencil 510401e04c3fSmrg * extension does not make this attachment point valid on ES 2.0. 510501e04c3fSmrg */ 510601e04c3fSmrg if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) 510701e04c3fSmrg break; 51087ec681f3Smrg FALLTHROUGH; 5109af69d88dSmrg case GL_COLOR_ATTACHMENT0: 5110af69d88dSmrg case GL_COLOR_ATTACHMENT1: 5111af69d88dSmrg case GL_COLOR_ATTACHMENT2: 5112af69d88dSmrg case GL_COLOR_ATTACHMENT3: 5113af69d88dSmrg case GL_COLOR_ATTACHMENT4: 5114af69d88dSmrg case GL_COLOR_ATTACHMENT5: 5115af69d88dSmrg case GL_COLOR_ATTACHMENT6: 5116af69d88dSmrg case GL_COLOR_ATTACHMENT7: 5117af69d88dSmrg case GL_COLOR_ATTACHMENT8: 5118af69d88dSmrg case GL_COLOR_ATTACHMENT9: 5119af69d88dSmrg case GL_COLOR_ATTACHMENT10: 5120af69d88dSmrg case GL_COLOR_ATTACHMENT11: 5121af69d88dSmrg case GL_COLOR_ATTACHMENT12: 5122af69d88dSmrg case GL_COLOR_ATTACHMENT13: 5123af69d88dSmrg case GL_COLOR_ATTACHMENT14: 5124af69d88dSmrg case GL_COLOR_ATTACHMENT15: { 5125af69d88dSmrg unsigned k = attachments[i] - GL_COLOR_ATTACHMENT0; 5126af69d88dSmrg if (k >= ctx->Const.MaxColorAttachments) { 5127af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 5128af69d88dSmrg "%s(attachment >= max. color attachments)", name); 5129af69d88dSmrg return; 5130af69d88dSmrg } 5131af69d88dSmrg break; 5132af69d88dSmrg } 5133af69d88dSmrg default: 5134af69d88dSmrg goto invalid_enum; 5135af69d88dSmrg } 5136af69d88dSmrg } 51373464ebd5Sriastradh } 51383464ebd5Sriastradh 5139af69d88dSmrg /* We don't actually do anything for this yet. Just return after 5140af69d88dSmrg * validating the parameters and generating the required errors. 5141af69d88dSmrg */ 5142af69d88dSmrg return; 51437117f1b4Smrg 5144af69d88dSmrginvalid_enum: 514501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", name, 514601e04c3fSmrg _mesa_enum_to_string(attachments[i])); 5147af69d88dSmrg return; 5148af69d88dSmrg} 51497117f1b4Smrg 5150a8bb7a65Smayastatic struct gl_renderbuffer_attachment * 5151a8bb7a65Smayaget_fb_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, 5152a8bb7a65Smaya const GLenum attachment) 5153a8bb7a65Smaya{ 5154a8bb7a65Smaya switch (attachment) { 5155a8bb7a65Smaya case GL_COLOR: 5156a8bb7a65Smaya return &fb->Attachment[BUFFER_BACK_LEFT]; 5157a8bb7a65Smaya case GL_COLOR_ATTACHMENT0: 5158a8bb7a65Smaya case GL_COLOR_ATTACHMENT1: 5159a8bb7a65Smaya case GL_COLOR_ATTACHMENT2: 5160a8bb7a65Smaya case GL_COLOR_ATTACHMENT3: 5161a8bb7a65Smaya case GL_COLOR_ATTACHMENT4: 5162a8bb7a65Smaya case GL_COLOR_ATTACHMENT5: 5163a8bb7a65Smaya case GL_COLOR_ATTACHMENT6: 5164a8bb7a65Smaya case GL_COLOR_ATTACHMENT7: 5165a8bb7a65Smaya case GL_COLOR_ATTACHMENT8: 5166a8bb7a65Smaya case GL_COLOR_ATTACHMENT9: 5167a8bb7a65Smaya case GL_COLOR_ATTACHMENT10: 5168a8bb7a65Smaya case GL_COLOR_ATTACHMENT11: 5169a8bb7a65Smaya case GL_COLOR_ATTACHMENT12: 5170a8bb7a65Smaya case GL_COLOR_ATTACHMENT13: 5171a8bb7a65Smaya case GL_COLOR_ATTACHMENT14: 5172a8bb7a65Smaya case GL_COLOR_ATTACHMENT15: { 5173a8bb7a65Smaya const unsigned i = attachment - GL_COLOR_ATTACHMENT0; 5174a8bb7a65Smaya if (i >= ctx->Const.MaxColorAttachments) 5175a8bb7a65Smaya return NULL; 51767ec681f3Smrg assert(BUFFER_COLOR0 + i < ARRAY_SIZE(fb->Attachment)); 5177a8bb7a65Smaya return &fb->Attachment[BUFFER_COLOR0 + i]; 5178a8bb7a65Smaya } 5179a8bb7a65Smaya case GL_DEPTH: 5180a8bb7a65Smaya case GL_DEPTH_ATTACHMENT: 5181a8bb7a65Smaya case GL_DEPTH_STENCIL_ATTACHMENT: 5182a8bb7a65Smaya return &fb->Attachment[BUFFER_DEPTH]; 5183a8bb7a65Smaya case GL_STENCIL: 5184a8bb7a65Smaya case GL_STENCIL_ATTACHMENT: 5185a8bb7a65Smaya return &fb->Attachment[BUFFER_STENCIL]; 5186a8bb7a65Smaya default: 5187a8bb7a65Smaya return NULL; 5188a8bb7a65Smaya } 5189a8bb7a65Smaya} 5190a8bb7a65Smaya 5191a8bb7a65Smayastatic void 5192a8bb7a65Smayadiscard_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 5193a8bb7a65Smaya GLsizei numAttachments, const GLenum *attachments) 5194a8bb7a65Smaya{ 5195a8bb7a65Smaya if (!ctx->Driver.DiscardFramebuffer) 5196a8bb7a65Smaya return; 5197a8bb7a65Smaya 5198a8bb7a65Smaya for (int i = 0; i < numAttachments; i++) { 5199a8bb7a65Smaya struct gl_renderbuffer_attachment *att = 5200a8bb7a65Smaya get_fb_attachment(ctx, fb, attachments[i]); 5201a8bb7a65Smaya 5202a8bb7a65Smaya if (!att) 5203a8bb7a65Smaya continue; 5204a8bb7a65Smaya 5205a8bb7a65Smaya /* If we're asked to invalidate just depth or just stencil, but the 5206a8bb7a65Smaya * attachment is packed depth/stencil, then we can only use 5207a8bb7a65Smaya * Driver.DiscardFramebuffer if the attachments list includes both depth 5208a8bb7a65Smaya * and stencil and they both point at the same renderbuffer. 5209a8bb7a65Smaya */ 5210a8bb7a65Smaya if ((attachments[i] == GL_DEPTH_ATTACHMENT || 5211a8bb7a65Smaya attachments[i] == GL_STENCIL_ATTACHMENT) && 5212a8bb7a65Smaya (!att->Renderbuffer || 5213a8bb7a65Smaya att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL)) { 5214a8bb7a65Smaya GLenum other_format = (attachments[i] == GL_DEPTH_ATTACHMENT ? 5215a8bb7a65Smaya GL_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT); 5216a8bb7a65Smaya bool has_both = false; 5217a8bb7a65Smaya for (int j = 0; j < numAttachments; j++) { 52187ec681f3Smrg if (attachments[j] == other_format) { 5219a8bb7a65Smaya has_both = true; 52207ec681f3Smrg break; 52217ec681f3Smrg } 5222a8bb7a65Smaya } 5223a8bb7a65Smaya 5224a8bb7a65Smaya if (fb->Attachment[BUFFER_DEPTH].Renderbuffer != 5225a8bb7a65Smaya fb->Attachment[BUFFER_STENCIL].Renderbuffer || !has_both) 5226a8bb7a65Smaya continue; 5227a8bb7a65Smaya } 5228a8bb7a65Smaya 5229a8bb7a65Smaya ctx->Driver.DiscardFramebuffer(ctx, fb, att); 5230a8bb7a65Smaya } 5231a8bb7a65Smaya} 52324a49301eSmrg 523301e04c3fSmrgvoid GLAPIENTRY 523401e04c3fSmrg_mesa_InvalidateSubFramebuffer_no_error(GLenum target, GLsizei numAttachments, 523501e04c3fSmrg const GLenum *attachments, GLint x, 523601e04c3fSmrg GLint y, GLsizei width, GLsizei height) 523701e04c3fSmrg{ 523801e04c3fSmrg /* no-op */ 523901e04c3fSmrg} 524001e04c3fSmrg 524101e04c3fSmrg 5242af69d88dSmrgvoid GLAPIENTRY 5243af69d88dSmrg_mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, 5244af69d88dSmrg const GLenum *attachments, GLint x, GLint y, 5245af69d88dSmrg GLsizei width, GLsizei height) 52464a49301eSmrg{ 524701e04c3fSmrg struct gl_framebuffer *fb; 524801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 524901e04c3fSmrg 525001e04c3fSmrg fb = get_framebuffer_target(ctx, target); 525101e04c3fSmrg if (!fb) { 525201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 525301e04c3fSmrg "glInvalidateSubFramebuffer(invalid target %s)", 525401e04c3fSmrg _mesa_enum_to_string(target)); 525501e04c3fSmrg return; 525601e04c3fSmrg } 525701e04c3fSmrg 525801e04c3fSmrg invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 5259af69d88dSmrg x, y, width, height, 5260af69d88dSmrg "glInvalidateSubFramebuffer"); 52614a49301eSmrg} 52624a49301eSmrg 52634a49301eSmrg 526401e04c3fSmrgvoid GLAPIENTRY 526501e04c3fSmrg_mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer, 526601e04c3fSmrg GLsizei numAttachments, 526701e04c3fSmrg const GLenum *attachments, 526801e04c3fSmrg GLint x, GLint y, 526901e04c3fSmrg GLsizei width, GLsizei height) 527001e04c3fSmrg{ 527101e04c3fSmrg struct gl_framebuffer *fb; 527201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 527301e04c3fSmrg 527401e04c3fSmrg /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole 527501e04c3fSmrg * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the 527601e04c3fSmrg * default draw framebuffer is affected." 527701e04c3fSmrg */ 527801e04c3fSmrg if (framebuffer) { 527901e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 528001e04c3fSmrg "glInvalidateNamedFramebufferSubData"); 528101e04c3fSmrg if (!fb) 528201e04c3fSmrg return; 528301e04c3fSmrg } 528401e04c3fSmrg else 528501e04c3fSmrg fb = ctx->WinSysDrawBuffer; 528601e04c3fSmrg 528701e04c3fSmrg invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 528801e04c3fSmrg x, y, width, height, 528901e04c3fSmrg "glInvalidateNamedFramebufferSubData"); 529001e04c3fSmrg} 529101e04c3fSmrg 529201e04c3fSmrgvoid GLAPIENTRY 529301e04c3fSmrg_mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments, 529401e04c3fSmrg const GLenum *attachments) 529501e04c3fSmrg{ 5296a8bb7a65Smaya struct gl_framebuffer *fb; 5297a8bb7a65Smaya GET_CURRENT_CONTEXT(ctx); 5298a8bb7a65Smaya 5299a8bb7a65Smaya fb = get_framebuffer_target(ctx, target); 5300a8bb7a65Smaya if (!fb) 5301a8bb7a65Smaya return; 5302a8bb7a65Smaya 5303a8bb7a65Smaya discard_framebuffer(ctx, fb, numAttachments, attachments); 530401e04c3fSmrg} 530501e04c3fSmrg 530601e04c3fSmrg 53077117f1b4Smrgvoid GLAPIENTRY 5308af69d88dSmrg_mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, 5309af69d88dSmrg const GLenum *attachments) 53107117f1b4Smrg{ 531101e04c3fSmrg struct gl_framebuffer *fb; 531201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 531301e04c3fSmrg 531401e04c3fSmrg fb = get_framebuffer_target(ctx, target); 531501e04c3fSmrg if (!fb) { 531601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 531701e04c3fSmrg "glInvalidateFramebuffer(invalid target %s)", 531801e04c3fSmrg _mesa_enum_to_string(target)); 531901e04c3fSmrg return; 532001e04c3fSmrg } 532101e04c3fSmrg 5322af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 5323af69d88dSmrg * 5324af69d88dSmrg * "The command 5325af69d88dSmrg * 5326af69d88dSmrg * void InvalidateFramebuffer(enum target, 5327af69d88dSmrg * sizei numAttachments, 5328af69d88dSmrg * const enum *attachments); 5329af69d88dSmrg * 5330af69d88dSmrg * is equivalent to the command InvalidateSubFramebuffer with <x>, <y>, 5331af69d88dSmrg * <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>, 5332af69d88dSmrg * <MAX_VIEWPORT_DIMS[1]> respectively." 5333af69d88dSmrg */ 533401e04c3fSmrg invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 5335af69d88dSmrg 0, 0, 533601e04c3fSmrg ctx->Const.MaxViewportWidth, 533701e04c3fSmrg ctx->Const.MaxViewportHeight, 5338af69d88dSmrg "glInvalidateFramebuffer"); 5339a8bb7a65Smaya 5340a8bb7a65Smaya discard_framebuffer(ctx, fb, numAttachments, attachments); 5341af69d88dSmrg} 53424a49301eSmrg 53433464ebd5Sriastradh 534401e04c3fSmrgvoid GLAPIENTRY 534501e04c3fSmrg_mesa_InvalidateNamedFramebufferData(GLuint framebuffer, 534601e04c3fSmrg GLsizei numAttachments, 534701e04c3fSmrg const GLenum *attachments) 534801e04c3fSmrg{ 534901e04c3fSmrg struct gl_framebuffer *fb; 535001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 535101e04c3fSmrg 535201e04c3fSmrg /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole 535301e04c3fSmrg * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the 535401e04c3fSmrg * default draw framebuffer is affected." 535501e04c3fSmrg */ 535601e04c3fSmrg if (framebuffer) { 535701e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 535801e04c3fSmrg "glInvalidateNamedFramebufferData"); 535901e04c3fSmrg if (!fb) 536001e04c3fSmrg return; 536101e04c3fSmrg } 536201e04c3fSmrg else 536301e04c3fSmrg fb = ctx->WinSysDrawBuffer; 536401e04c3fSmrg 536501e04c3fSmrg /* The GL_ARB_invalidate_subdata spec says: 536601e04c3fSmrg * 536701e04c3fSmrg * "The command 536801e04c3fSmrg * 536901e04c3fSmrg * void InvalidateFramebuffer(enum target, 537001e04c3fSmrg * sizei numAttachments, 537101e04c3fSmrg * const enum *attachments); 537201e04c3fSmrg * 537301e04c3fSmrg * is equivalent to the command InvalidateSubFramebuffer with <x>, <y>, 537401e04c3fSmrg * <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>, 537501e04c3fSmrg * <MAX_VIEWPORT_DIMS[1]> respectively." 537601e04c3fSmrg */ 537701e04c3fSmrg invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 537801e04c3fSmrg 0, 0, 537901e04c3fSmrg ctx->Const.MaxViewportWidth, 538001e04c3fSmrg ctx->Const.MaxViewportHeight, 538101e04c3fSmrg "glInvalidateNamedFramebufferData"); 538201e04c3fSmrg} 538301e04c3fSmrg 538401e04c3fSmrg 5385af69d88dSmrgvoid GLAPIENTRY 5386af69d88dSmrg_mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, 5387af69d88dSmrg const GLenum *attachments) 5388af69d88dSmrg{ 5389af69d88dSmrg struct gl_framebuffer *fb; 5390af69d88dSmrg GLint i; 53913464ebd5Sriastradh 5392af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 53937117f1b4Smrg 5394af69d88dSmrg fb = get_framebuffer_target(ctx, target); 5395af69d88dSmrg if (!fb) { 5396af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 5397af69d88dSmrg "glDiscardFramebufferEXT(target %s)", 539801e04c3fSmrg _mesa_enum_to_string(target)); 53994a49301eSmrg return; 54004a49301eSmrg } 54014a49301eSmrg 5402af69d88dSmrg if (numAttachments < 0) { 5403af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 5404af69d88dSmrg "glDiscardFramebufferEXT(numAttachments < 0)"); 54057117f1b4Smrg return; 54067117f1b4Smrg } 54077117f1b4Smrg 5408af69d88dSmrg for (i = 0; i < numAttachments; i++) { 5409af69d88dSmrg switch (attachments[i]) { 5410af69d88dSmrg case GL_COLOR: 5411af69d88dSmrg case GL_DEPTH: 5412af69d88dSmrg case GL_STENCIL: 5413af69d88dSmrg if (_mesa_is_user_fbo(fb)) 5414af69d88dSmrg goto invalid_enum; 5415af69d88dSmrg break; 5416af69d88dSmrg case GL_COLOR_ATTACHMENT0: 5417af69d88dSmrg case GL_DEPTH_ATTACHMENT: 5418af69d88dSmrg case GL_STENCIL_ATTACHMENT: 5419af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) 5420af69d88dSmrg goto invalid_enum; 5421af69d88dSmrg break; 5422af69d88dSmrg default: 5423af69d88dSmrg goto invalid_enum; 54244a49301eSmrg } 54254a49301eSmrg } 54264a49301eSmrg 5427a8bb7a65Smaya discard_framebuffer(ctx, fb, numAttachments, attachments); 54283464ebd5Sriastradh 5429af69d88dSmrg return; 54303464ebd5Sriastradh 5431af69d88dSmrginvalid_enum: 5432af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 5433af69d88dSmrg "glDiscardFramebufferEXT(attachment %s)", 543401e04c3fSmrg _mesa_enum_to_string(attachments[i])); 543501e04c3fSmrg} 543601e04c3fSmrg 543701e04c3fSmrgstatic void 543801e04c3fSmrgsample_locations(struct gl_context *ctx, struct gl_framebuffer *fb, 543901e04c3fSmrg GLuint start, GLsizei count, const GLfloat *v, bool no_error, 544001e04c3fSmrg const char *name) 544101e04c3fSmrg{ 544201e04c3fSmrg GLsizei i; 544301e04c3fSmrg 544401e04c3fSmrg if (!no_error) { 544501e04c3fSmrg if (!ctx->Extensions.ARB_sample_locations) { 544601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 544701e04c3fSmrg "%s not supported " 544801e04c3fSmrg "(ARB_sample_locations not available)", name); 544901e04c3fSmrg return; 545001e04c3fSmrg } 545101e04c3fSmrg 545201e04c3fSmrg if (start + count > MAX_SAMPLE_LOCATION_TABLE_SIZE) { 545301e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 545401e04c3fSmrg "%s(start+size > sample location table size)", name); 545501e04c3fSmrg return; 545601e04c3fSmrg } 545701e04c3fSmrg } 545801e04c3fSmrg 545901e04c3fSmrg if (!fb->SampleLocationTable) { 546001e04c3fSmrg size_t size = MAX_SAMPLE_LOCATION_TABLE_SIZE * 2 * sizeof(GLfloat); 546101e04c3fSmrg fb->SampleLocationTable = malloc(size); 546201e04c3fSmrg if (!fb->SampleLocationTable) { 546301e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 546401e04c3fSmrg "Cannot allocate sample location table"); 546501e04c3fSmrg return; 546601e04c3fSmrg } 546701e04c3fSmrg for (i = 0; i < MAX_SAMPLE_LOCATION_TABLE_SIZE * 2; i++) 546801e04c3fSmrg fb->SampleLocationTable[i] = 0.5f; 546901e04c3fSmrg } 547001e04c3fSmrg 547101e04c3fSmrg for (i = 0; i < count * 2; i++) { 547201e04c3fSmrg /* The ARB_sample_locations spec says: 547301e04c3fSmrg * 547401e04c3fSmrg * Sample locations outside of [0,1] result in undefined 547501e04c3fSmrg * behavior. 547601e04c3fSmrg * 547701e04c3fSmrg * To simplify driver implementations, we choose to clamp to 547801e04c3fSmrg * [0,1] and change NaN into 0.5. 547901e04c3fSmrg */ 548001e04c3fSmrg if (isnan(v[i]) || v[i] < 0.0f || v[i] > 1.0f) { 548101e04c3fSmrg static GLuint msg_id = 0; 548201e04c3fSmrg static const char* msg = "Invalid sample location specified"; 548301e04c3fSmrg _mesa_debug_get_id(&msg_id); 548401e04c3fSmrg 548501e04c3fSmrg _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_UNDEFINED, 548601e04c3fSmrg msg_id, MESA_DEBUG_SEVERITY_HIGH, strlen(msg), msg); 548701e04c3fSmrg } 548801e04c3fSmrg 548901e04c3fSmrg if (isnan(v[i])) 549001e04c3fSmrg fb->SampleLocationTable[start * 2 + i] = 0.5f; 549101e04c3fSmrg else 54927ec681f3Smrg fb->SampleLocationTable[start * 2 + i] = SATURATE(v[i]); 549301e04c3fSmrg } 549401e04c3fSmrg 549501e04c3fSmrg if (fb == ctx->DrawBuffer) 549601e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations; 549701e04c3fSmrg} 549801e04c3fSmrg 549901e04c3fSmrgvoid GLAPIENTRY 550001e04c3fSmrg_mesa_FramebufferSampleLocationsfvARB(GLenum target, GLuint start, 550101e04c3fSmrg GLsizei count, const GLfloat *v) 550201e04c3fSmrg{ 550301e04c3fSmrg struct gl_framebuffer *fb; 550401e04c3fSmrg 550501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 550601e04c3fSmrg 550701e04c3fSmrg fb = get_framebuffer_target(ctx, target); 550801e04c3fSmrg if (!fb) { 550901e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 551001e04c3fSmrg "glFramebufferSampleLocationsfvARB(target %s)", 551101e04c3fSmrg _mesa_enum_to_string(target)); 551201e04c3fSmrg return; 551301e04c3fSmrg } 551401e04c3fSmrg 551501e04c3fSmrg sample_locations(ctx, fb, start, count, v, false, 551601e04c3fSmrg "glFramebufferSampleLocationsfvARB"); 551701e04c3fSmrg} 551801e04c3fSmrg 551901e04c3fSmrgvoid GLAPIENTRY 552001e04c3fSmrg_mesa_NamedFramebufferSampleLocationsfvARB(GLuint framebuffer, GLuint start, 552101e04c3fSmrg GLsizei count, const GLfloat *v) 552201e04c3fSmrg{ 552301e04c3fSmrg struct gl_framebuffer *fb; 552401e04c3fSmrg 552501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 552601e04c3fSmrg 552701e04c3fSmrg if (framebuffer) { 552801e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 552901e04c3fSmrg "glNamedFramebufferSampleLocationsfvARB"); 553001e04c3fSmrg if (!fb) 553101e04c3fSmrg return; 553201e04c3fSmrg } 553301e04c3fSmrg else 553401e04c3fSmrg fb = ctx->WinSysDrawBuffer; 553501e04c3fSmrg 553601e04c3fSmrg sample_locations(ctx, fb, start, count, v, false, 553701e04c3fSmrg "glNamedFramebufferSampleLocationsfvARB"); 553801e04c3fSmrg} 553901e04c3fSmrg 554001e04c3fSmrgvoid GLAPIENTRY 554101e04c3fSmrg_mesa_FramebufferSampleLocationsfvARB_no_error(GLenum target, GLuint start, 554201e04c3fSmrg GLsizei count, const GLfloat *v) 554301e04c3fSmrg{ 554401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 554501e04c3fSmrg sample_locations(ctx, get_framebuffer_target(ctx, target), start, 554601e04c3fSmrg count, v, true, "glFramebufferSampleLocationsfvARB"); 554701e04c3fSmrg} 554801e04c3fSmrg 554901e04c3fSmrgvoid GLAPIENTRY 555001e04c3fSmrg_mesa_NamedFramebufferSampleLocationsfvARB_no_error(GLuint framebuffer, 555101e04c3fSmrg GLuint start, GLsizei count, 555201e04c3fSmrg const GLfloat *v) 555301e04c3fSmrg{ 555401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 555501e04c3fSmrg sample_locations(ctx, _mesa_lookup_framebuffer(ctx, framebuffer), start, 555601e04c3fSmrg count, v, true, "glNamedFramebufferSampleLocationsfvARB"); 555701e04c3fSmrg} 555801e04c3fSmrg 555901e04c3fSmrgvoid GLAPIENTRY 556001e04c3fSmrg_mesa_EvaluateDepthValuesARB(void) 556101e04c3fSmrg{ 556201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 556301e04c3fSmrg 556401e04c3fSmrg if (!ctx->Extensions.ARB_sample_locations) { 556501e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 556601e04c3fSmrg "EvaluateDepthValuesARB not supported (neither " 556701e04c3fSmrg "ARB_sample_locations nor NV_sample_locations is available)"); 556801e04c3fSmrg return; 556901e04c3fSmrg } 557001e04c3fSmrg 557101e04c3fSmrg if (ctx->Driver.EvaluateDepthValues) 557201e04c3fSmrg ctx->Driver.EvaluateDepthValues(ctx); 55733464ebd5Sriastradh} 5574