fbobject.c revision 01e04c3f
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" 394a49301eSmrg#include "enums.h" 407117f1b4Smrg#include "fbobject.h" 414a49301eSmrg#include "formats.h" 427117f1b4Smrg#include "framebuffer.h" 43af69d88dSmrg#include "glformats.h" 447117f1b4Smrg#include "hash.h" 454a49301eSmrg#include "macros.h" 46af69d88dSmrg#include "multisample.h" 473464ebd5Sriastradh#include "mtypes.h" 487117f1b4Smrg#include "renderbuffer.h" 497117f1b4Smrg#include "state.h" 507117f1b4Smrg#include "teximage.h" 517117f1b4Smrg#include "texobj.h" 524a49301eSmrg 534a49301eSmrg 547117f1b4Smrg/** 557117f1b4Smrg * Notes: 567117f1b4Smrg * 577117f1b4Smrg * None of the GL_EXT_framebuffer_object functions are compiled into 587117f1b4Smrg * display lists. 597117f1b4Smrg */ 607117f1b4Smrg 617117f1b4Smrg 627117f1b4Smrg 637117f1b4Smrg/* 647117f1b4Smrg * When glGenRender/FramebuffersEXT() is called we insert pointers to 657117f1b4Smrg * these placeholder objects into the hash table. 667117f1b4Smrg * Later, when the object ID is first bound, we replace the placeholder 677117f1b4Smrg * with the real frame/renderbuffer. 687117f1b4Smrg */ 697117f1b4Smrgstatic struct gl_framebuffer DummyFramebuffer; 707117f1b4Smrgstatic struct gl_renderbuffer DummyRenderbuffer; 717117f1b4Smrg 723464ebd5Sriastradh/* We bind this framebuffer when applications pass a NULL 733464ebd5Sriastradh * drawable/surface in make current. */ 743464ebd5Sriastradhstatic struct gl_framebuffer IncompleteFramebuffer; 757117f1b4Smrg 763464ebd5Sriastradh 77c1f859d4Smrgstatic void 78af69d88dSmrgdelete_dummy_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) 79c1f859d4Smrg{ 80c1f859d4Smrg /* no op */ 81c1f859d4Smrg} 82c1f859d4Smrg 83c1f859d4Smrgstatic void 84c1f859d4Smrgdelete_dummy_framebuffer(struct gl_framebuffer *fb) 85c1f859d4Smrg{ 86c1f859d4Smrg /* no op */ 87c1f859d4Smrg} 88c1f859d4Smrg 89c1f859d4Smrg 90c1f859d4Smrgvoid 913464ebd5Sriastradh_mesa_init_fbobjects(struct gl_context *ctx) 92c1f859d4Smrg{ 9301e04c3fSmrg simple_mtx_init(&DummyFramebuffer.Mutex, mtx_plain); 9401e04c3fSmrg simple_mtx_init(&DummyRenderbuffer.Mutex, mtx_plain); 9501e04c3fSmrg simple_mtx_init(&IncompleteFramebuffer.Mutex, mtx_plain); 96c1f859d4Smrg DummyFramebuffer.Delete = delete_dummy_framebuffer; 97c1f859d4Smrg DummyRenderbuffer.Delete = delete_dummy_renderbuffer; 983464ebd5Sriastradh IncompleteFramebuffer.Delete = delete_dummy_framebuffer; 99c1f859d4Smrg} 100c1f859d4Smrg 1013464ebd5Sriastradhstruct gl_framebuffer * 1023464ebd5Sriastradh_mesa_get_incomplete_framebuffer(void) 1033464ebd5Sriastradh{ 1043464ebd5Sriastradh return &IncompleteFramebuffer; 1053464ebd5Sriastradh} 106c1f859d4Smrg 1077117f1b4Smrg/** 1087117f1b4Smrg * Helper routine for getting a gl_renderbuffer. 1097117f1b4Smrg */ 1107117f1b4Smrgstruct gl_renderbuffer * 1113464ebd5Sriastradh_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id) 1127117f1b4Smrg{ 1137117f1b4Smrg struct gl_renderbuffer *rb; 1147117f1b4Smrg 1157117f1b4Smrg if (id == 0) 1167117f1b4Smrg return NULL; 1177117f1b4Smrg 1187117f1b4Smrg rb = (struct gl_renderbuffer *) 1197117f1b4Smrg _mesa_HashLookup(ctx->Shared->RenderBuffers, id); 1207117f1b4Smrg return rb; 1217117f1b4Smrg} 1227117f1b4Smrg 1237117f1b4Smrg 12401e04c3fSmrg/** 12501e04c3fSmrg * A convenience function for direct state access that throws 12601e04c3fSmrg * GL_INVALID_OPERATION if the renderbuffer doesn't exist. 12701e04c3fSmrg */ 12801e04c3fSmrgstruct gl_renderbuffer * 12901e04c3fSmrg_mesa_lookup_renderbuffer_err(struct gl_context *ctx, GLuint id, 13001e04c3fSmrg const char *func) 13101e04c3fSmrg{ 13201e04c3fSmrg struct gl_renderbuffer *rb; 13301e04c3fSmrg 13401e04c3fSmrg rb = _mesa_lookup_renderbuffer(ctx, id); 13501e04c3fSmrg if (!rb || rb == &DummyRenderbuffer) { 13601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 13701e04c3fSmrg "%s(non-existent renderbuffer %u)", func, id); 13801e04c3fSmrg return NULL; 13901e04c3fSmrg } 14001e04c3fSmrg 14101e04c3fSmrg return rb; 14201e04c3fSmrg} 14301e04c3fSmrg 14401e04c3fSmrg 1457117f1b4Smrg/** 1467117f1b4Smrg * Helper routine for getting a gl_framebuffer. 1477117f1b4Smrg */ 1487117f1b4Smrgstruct gl_framebuffer * 1493464ebd5Sriastradh_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) 1507117f1b4Smrg{ 1517117f1b4Smrg struct gl_framebuffer *fb; 1527117f1b4Smrg 1537117f1b4Smrg if (id == 0) 1547117f1b4Smrg return NULL; 1557117f1b4Smrg 1567117f1b4Smrg fb = (struct gl_framebuffer *) 1577117f1b4Smrg _mesa_HashLookup(ctx->Shared->FrameBuffers, id); 1587117f1b4Smrg return fb; 1597117f1b4Smrg} 1607117f1b4Smrg 1617117f1b4Smrg 16201e04c3fSmrg/** 16301e04c3fSmrg * A convenience function for direct state access that throws 16401e04c3fSmrg * GL_INVALID_OPERATION if the framebuffer doesn't exist. 16501e04c3fSmrg */ 16601e04c3fSmrgstruct gl_framebuffer * 16701e04c3fSmrg_mesa_lookup_framebuffer_err(struct gl_context *ctx, GLuint id, 16801e04c3fSmrg const char *func) 16901e04c3fSmrg{ 17001e04c3fSmrg struct gl_framebuffer *fb; 17101e04c3fSmrg 17201e04c3fSmrg fb = _mesa_lookup_framebuffer(ctx, id); 17301e04c3fSmrg if (!fb || fb == &DummyFramebuffer) { 17401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 17501e04c3fSmrg "%s(non-existent framebuffer %u)", func, id); 17601e04c3fSmrg return NULL; 17701e04c3fSmrg } 17801e04c3fSmrg 17901e04c3fSmrg return fb; 18001e04c3fSmrg} 18101e04c3fSmrg 18201e04c3fSmrg 1834a49301eSmrg/** 1844a49301eSmrg * Mark the given framebuffer as invalid. This will force the 1854a49301eSmrg * test for framebuffer completeness to be done before the framebuffer 1864a49301eSmrg * is used. 1874a49301eSmrg */ 1884a49301eSmrgstatic void 1894a49301eSmrginvalidate_framebuffer(struct gl_framebuffer *fb) 1904a49301eSmrg{ 1914a49301eSmrg fb->_Status = 0; /* "indeterminate" */ 1924a49301eSmrg} 1934a49301eSmrg 1944a49301eSmrg 1953464ebd5Sriastradh/** 1963464ebd5Sriastradh * Return the gl_framebuffer object which corresponds to the given 1973464ebd5Sriastradh * framebuffer target, such as GL_DRAW_FRAMEBUFFER. 1983464ebd5Sriastradh * Check support for GL_EXT_framebuffer_blit to determine if certain 1993464ebd5Sriastradh * targets are legal. 2003464ebd5Sriastradh * \return gl_framebuffer pointer or NULL if target is illegal 2013464ebd5Sriastradh */ 2023464ebd5Sriastradhstatic struct gl_framebuffer * 2033464ebd5Sriastradhget_framebuffer_target(struct gl_context *ctx, GLenum target) 2043464ebd5Sriastradh{ 205af69d88dSmrg bool have_fb_blit = _mesa_is_gles3(ctx) || _mesa_is_desktop_gl(ctx); 2063464ebd5Sriastradh switch (target) { 2073464ebd5Sriastradh case GL_DRAW_FRAMEBUFFER: 208af69d88dSmrg return have_fb_blit ? ctx->DrawBuffer : NULL; 2093464ebd5Sriastradh case GL_READ_FRAMEBUFFER: 210af69d88dSmrg return have_fb_blit ? ctx->ReadBuffer : NULL; 2113464ebd5Sriastradh case GL_FRAMEBUFFER_EXT: 2123464ebd5Sriastradh return ctx->DrawBuffer; 2133464ebd5Sriastradh default: 2143464ebd5Sriastradh return NULL; 2153464ebd5Sriastradh } 2163464ebd5Sriastradh} 2173464ebd5Sriastradh 2183464ebd5Sriastradh 2197117f1b4Smrg/** 2207117f1b4Smrg * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding 2217117f1b4Smrg * gl_renderbuffer_attachment object. 2223464ebd5Sriastradh * This function is only used for user-created FB objects, not the 2233464ebd5Sriastradh * default / window-system FB object. 2244a49301eSmrg * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to 2254a49301eSmrg * the depth buffer attachment point. 22601e04c3fSmrg * Returns if the attachment is a GL_COLOR_ATTACHMENTm_EXT on 22701e04c3fSmrg * is_color_attachment, because several callers would return different errors 22801e04c3fSmrg * if they don't find the attachment. 2297117f1b4Smrg */ 230af69d88dSmrgstatic struct gl_renderbuffer_attachment * 231af69d88dSmrgget_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, 23201e04c3fSmrg GLenum attachment, bool *is_color_attachment) 2337117f1b4Smrg{ 2347117f1b4Smrg GLuint i; 2357117f1b4Smrg 236af69d88dSmrg assert(_mesa_is_user_fbo(fb)); 2373464ebd5Sriastradh 23801e04c3fSmrg if (is_color_attachment) 23901e04c3fSmrg *is_color_attachment = false; 24001e04c3fSmrg 2417117f1b4Smrg switch (attachment) { 2427117f1b4Smrg case GL_COLOR_ATTACHMENT0_EXT: 2437117f1b4Smrg case GL_COLOR_ATTACHMENT1_EXT: 2447117f1b4Smrg case GL_COLOR_ATTACHMENT2_EXT: 2457117f1b4Smrg case GL_COLOR_ATTACHMENT3_EXT: 2467117f1b4Smrg case GL_COLOR_ATTACHMENT4_EXT: 2477117f1b4Smrg case GL_COLOR_ATTACHMENT5_EXT: 2487117f1b4Smrg case GL_COLOR_ATTACHMENT6_EXT: 2497117f1b4Smrg case GL_COLOR_ATTACHMENT7_EXT: 2507117f1b4Smrg case GL_COLOR_ATTACHMENT8_EXT: 2517117f1b4Smrg case GL_COLOR_ATTACHMENT9_EXT: 2527117f1b4Smrg case GL_COLOR_ATTACHMENT10_EXT: 2537117f1b4Smrg case GL_COLOR_ATTACHMENT11_EXT: 2547117f1b4Smrg case GL_COLOR_ATTACHMENT12_EXT: 2557117f1b4Smrg case GL_COLOR_ATTACHMENT13_EXT: 2567117f1b4Smrg case GL_COLOR_ATTACHMENT14_EXT: 2577117f1b4Smrg case GL_COLOR_ATTACHMENT15_EXT: 25801e04c3fSmrg if (is_color_attachment) 25901e04c3fSmrg *is_color_attachment = true; 260af69d88dSmrg /* Only OpenGL ES 1.x forbids color attachments other than 261af69d88dSmrg * GL_COLOR_ATTACHMENT0. For all other APIs the limit set by the 262af69d88dSmrg * hardware is used. 263af69d88dSmrg */ 2647117f1b4Smrg i = attachment - GL_COLOR_ATTACHMENT0_EXT; 265af69d88dSmrg if (i >= ctx->Const.MaxColorAttachments 26601e04c3fSmrg || (i > 0 && ctx->API == API_OPENGLES)) { 26701e04c3fSmrg return NULL; 2687117f1b4Smrg } 2697117f1b4Smrg return &fb->Attachment[BUFFER_COLOR0 + i]; 2704a49301eSmrg case GL_DEPTH_STENCIL_ATTACHMENT: 271af69d88dSmrg if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) 27201e04c3fSmrg return NULL; 2734a49301eSmrg /* fall-through */ 2747117f1b4Smrg case GL_DEPTH_ATTACHMENT_EXT: 2757117f1b4Smrg return &fb->Attachment[BUFFER_DEPTH]; 2767117f1b4Smrg case GL_STENCIL_ATTACHMENT_EXT: 2777117f1b4Smrg return &fb->Attachment[BUFFER_STENCIL]; 2787117f1b4Smrg default: 2797117f1b4Smrg return NULL; 2807117f1b4Smrg } 2817117f1b4Smrg} 2827117f1b4Smrg 2837117f1b4Smrg 2843464ebd5Sriastradh/** 2853464ebd5Sriastradh * As above, but only used for getting attachments of the default / 2863464ebd5Sriastradh * window-system framebuffer (not user-created framebuffer objects). 2873464ebd5Sriastradh */ 2883464ebd5Sriastradhstatic struct gl_renderbuffer_attachment * 28901e04c3fSmrgget_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, 29001e04c3fSmrg GLenum attachment) 2913464ebd5Sriastradh{ 292af69d88dSmrg assert(_mesa_is_winsys_fbo(fb)); 293af69d88dSmrg 294af69d88dSmrg if (_mesa_is_gles3(ctx)) { 295af69d88dSmrg assert(attachment == GL_BACK || 296af69d88dSmrg attachment == GL_DEPTH || 297af69d88dSmrg attachment == GL_STENCIL); 298af69d88dSmrg switch (attachment) { 299af69d88dSmrg case GL_BACK: 300af69d88dSmrg /* Since there is no stereo rendering in ES 3.0, only return the 301af69d88dSmrg * LEFT bits. 302af69d88dSmrg */ 303af69d88dSmrg if (ctx->DrawBuffer->Visual.doubleBufferMode) 304af69d88dSmrg return &fb->Attachment[BUFFER_BACK_LEFT]; 305af69d88dSmrg return &fb->Attachment[BUFFER_FRONT_LEFT]; 306af69d88dSmrg case GL_DEPTH: 30701e04c3fSmrg return &fb->Attachment[BUFFER_DEPTH]; 308af69d88dSmrg case GL_STENCIL: 309af69d88dSmrg return &fb->Attachment[BUFFER_STENCIL]; 310af69d88dSmrg } 311af69d88dSmrg } 3123464ebd5Sriastradh 3133464ebd5Sriastradh switch (attachment) { 3143464ebd5Sriastradh case GL_FRONT_LEFT: 31501e04c3fSmrg /* Front buffers can be allocated on the first use, but 31601e04c3fSmrg * glGetFramebufferAttachmentParameteriv must work even if that 31701e04c3fSmrg * allocation hasn't happened yet. In such case, use the back buffer, 31801e04c3fSmrg * which should be the same. 31901e04c3fSmrg */ 32001e04c3fSmrg if (fb->Attachment[BUFFER_FRONT_LEFT].Type == GL_NONE) 32101e04c3fSmrg return &fb->Attachment[BUFFER_BACK_LEFT]; 32201e04c3fSmrg else 32301e04c3fSmrg return &fb->Attachment[BUFFER_FRONT_LEFT]; 3243464ebd5Sriastradh case GL_FRONT_RIGHT: 32501e04c3fSmrg /* Same as above. */ 32601e04c3fSmrg if (fb->Attachment[BUFFER_FRONT_RIGHT].Type == GL_NONE) 32701e04c3fSmrg return &fb->Attachment[BUFFER_BACK_RIGHT]; 32801e04c3fSmrg else 32901e04c3fSmrg return &fb->Attachment[BUFFER_FRONT_RIGHT]; 3303464ebd5Sriastradh case GL_BACK_LEFT: 3313464ebd5Sriastradh return &fb->Attachment[BUFFER_BACK_LEFT]; 3323464ebd5Sriastradh case GL_BACK_RIGHT: 3333464ebd5Sriastradh return &fb->Attachment[BUFFER_BACK_RIGHT]; 33401e04c3fSmrg case GL_BACK: 33501e04c3fSmrg /* The ARB_ES3_1_compatibility spec says: 33601e04c3fSmrg * 33701e04c3fSmrg * "Since this command can only query a single framebuffer 33801e04c3fSmrg * attachment, BACK is equivalent to BACK_LEFT." 33901e04c3fSmrg */ 34001e04c3fSmrg if (ctx->Extensions.ARB_ES3_1_compatibility) 34101e04c3fSmrg return &fb->Attachment[BUFFER_BACK_LEFT]; 34201e04c3fSmrg return NULL; 3433464ebd5Sriastradh case GL_AUX0: 3443464ebd5Sriastradh if (fb->Visual.numAuxBuffers == 1) { 3453464ebd5Sriastradh return &fb->Attachment[BUFFER_AUX0]; 3463464ebd5Sriastradh } 3473464ebd5Sriastradh return NULL; 348af69d88dSmrg 349af69d88dSmrg /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says: 350af69d88dSmrg * 351af69d88dSmrg * "If the default framebuffer is bound to target, then attachment must 352af69d88dSmrg * be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi, 353af69d88dSmrg * identifying a color buffer; DEPTH, identifying the depth buffer; or 354af69d88dSmrg * STENCIL, identifying the stencil buffer." 355af69d88dSmrg * 356af69d88dSmrg * Revision #34 of the ARB_framebuffer_object spec has essentially the same 357af69d88dSmrg * language. However, revision #33 of the ARB_framebuffer_object spec 358af69d88dSmrg * says: 359af69d88dSmrg * 360af69d88dSmrg * "If the default framebuffer is bound to <target>, then <attachment> 361af69d88dSmrg * must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi, 362af69d88dSmrg * DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the 363af69d88dSmrg * depth buffer, or the stencil buffer, and <pname> may be 364af69d88dSmrg * FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or 365af69d88dSmrg * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME." 366af69d88dSmrg * 367af69d88dSmrg * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed 368af69d88dSmrg * from glext.h, so shipping apps should not use those values. 369af69d88dSmrg * 370af69d88dSmrg * Note that neither EXT_framebuffer_object nor OES_framebuffer_object 371af69d88dSmrg * support queries of the window system FBO. 372af69d88dSmrg */ 373af69d88dSmrg case GL_DEPTH: 3743464ebd5Sriastradh return &fb->Attachment[BUFFER_DEPTH]; 375af69d88dSmrg case GL_STENCIL: 3763464ebd5Sriastradh return &fb->Attachment[BUFFER_STENCIL]; 3773464ebd5Sriastradh default: 3783464ebd5Sriastradh return NULL; 3793464ebd5Sriastradh } 3803464ebd5Sriastradh} 3813464ebd5Sriastradh 3823464ebd5Sriastradh 3833464ebd5Sriastradh 3847117f1b4Smrg/** 3857117f1b4Smrg * Remove any texture or renderbuffer attached to the given attachment 3867117f1b4Smrg * point. Update reference counts, etc. 3877117f1b4Smrg */ 388af69d88dSmrgstatic void 389af69d88dSmrgremove_attachment(struct gl_context *ctx, 390af69d88dSmrg struct gl_renderbuffer_attachment *att) 3917117f1b4Smrg{ 392af69d88dSmrg struct gl_renderbuffer *rb = att->Renderbuffer; 393af69d88dSmrg 394af69d88dSmrg /* tell driver that we're done rendering to this texture. */ 395af69d88dSmrg if (rb && rb->NeedsFinishRenderTexture) 396af69d88dSmrg ctx->Driver.FinishRenderTexture(ctx, rb); 397af69d88dSmrg 3987117f1b4Smrg if (att->Type == GL_TEXTURE) { 39901e04c3fSmrg assert(att->Texture); 4007117f1b4Smrg _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ 40101e04c3fSmrg assert(!att->Texture); 4027117f1b4Smrg } 4037117f1b4Smrg if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { 40401e04c3fSmrg assert(!att->Texture); 4057117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ 40601e04c3fSmrg assert(!att->Renderbuffer); 4077117f1b4Smrg } 4087117f1b4Smrg att->Type = GL_NONE; 4097117f1b4Smrg att->Complete = GL_TRUE; 4107117f1b4Smrg} 4117117f1b4Smrg 412af69d88dSmrg/** 413af69d88dSmrg * Verify a couple error conditions that will lead to an incomplete FBO and 414af69d88dSmrg * may cause problems for the driver's RenderTexture path. 415af69d88dSmrg */ 416af69d88dSmrgstatic bool 417af69d88dSmrgdriver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att) 418af69d88dSmrg{ 419af69d88dSmrg const struct gl_texture_image *const texImage = 420af69d88dSmrg att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 421af69d88dSmrg 42201e04c3fSmrg if (!texImage || 42301e04c3fSmrg texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0) 424af69d88dSmrg return false; 425af69d88dSmrg 426af69d88dSmrg if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY 427af69d88dSmrg && att->Zoffset >= texImage->Height) 428af69d88dSmrg || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY 429af69d88dSmrg && att->Zoffset >= texImage->Depth)) 430af69d88dSmrg return false; 431af69d88dSmrg 432af69d88dSmrg return true; 433af69d88dSmrg} 434af69d88dSmrg 435af69d88dSmrg/** 436af69d88dSmrg * Create a renderbuffer which will be set up by the driver to wrap the 437af69d88dSmrg * texture image slice. 438af69d88dSmrg * 439af69d88dSmrg * By using a gl_renderbuffer (like user-allocated renderbuffers), drivers get 440af69d88dSmrg * to share most of their framebuffer rendering code between winsys, 441af69d88dSmrg * renderbuffer, and texture attachments. 442af69d88dSmrg * 443af69d88dSmrg * The allocated renderbuffer uses a non-zero Name so that drivers can check 444af69d88dSmrg * it for determining vertical orientation, but we use ~0 to make it fairly 445af69d88dSmrg * unambiguous with actual user (non-texture) renderbuffers. 446af69d88dSmrg */ 447af69d88dSmrgvoid 448af69d88dSmrg_mesa_update_texture_renderbuffer(struct gl_context *ctx, 449af69d88dSmrg struct gl_framebuffer *fb, 450af69d88dSmrg struct gl_renderbuffer_attachment *att) 451af69d88dSmrg{ 452af69d88dSmrg struct gl_texture_image *texImage; 453af69d88dSmrg struct gl_renderbuffer *rb; 454af69d88dSmrg 455af69d88dSmrg texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 456af69d88dSmrg 457af69d88dSmrg rb = att->Renderbuffer; 458af69d88dSmrg if (!rb) { 459af69d88dSmrg rb = ctx->Driver.NewRenderbuffer(ctx, ~0); 460af69d88dSmrg if (!rb) { 461af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); 462af69d88dSmrg return; 463af69d88dSmrg } 46401e04c3fSmrg att->Renderbuffer = rb; 465af69d88dSmrg 466af69d88dSmrg /* This can't get called on a texture renderbuffer, so set it to NULL 467af69d88dSmrg * for clarity compared to user renderbuffers. 468af69d88dSmrg */ 469af69d88dSmrg rb->AllocStorage = NULL; 470af69d88dSmrg 471af69d88dSmrg rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL; 472af69d88dSmrg } 473af69d88dSmrg 474af69d88dSmrg if (!texImage) 475af69d88dSmrg return; 476af69d88dSmrg 477af69d88dSmrg rb->_BaseFormat = texImage->_BaseFormat; 478af69d88dSmrg rb->Format = texImage->TexFormat; 479af69d88dSmrg rb->InternalFormat = texImage->InternalFormat; 480af69d88dSmrg rb->Width = texImage->Width2; 481af69d88dSmrg rb->Height = texImage->Height2; 482af69d88dSmrg rb->Depth = texImage->Depth2; 483af69d88dSmrg rb->NumSamples = texImage->NumSamples; 48401e04c3fSmrg rb->NumStorageSamples = texImage->NumSamples; 485af69d88dSmrg rb->TexImage = texImage; 486af69d88dSmrg 487af69d88dSmrg if (driver_RenderTexture_is_safe(att)) 488af69d88dSmrg ctx->Driver.RenderTexture(ctx, fb, att); 489af69d88dSmrg} 4907117f1b4Smrg 4917117f1b4Smrg/** 4927117f1b4Smrg * Bind a texture object to an attachment point. 4937117f1b4Smrg * The previous binding, if any, will be removed first. 4947117f1b4Smrg */ 495af69d88dSmrgstatic void 496af69d88dSmrgset_texture_attachment(struct gl_context *ctx, 497af69d88dSmrg struct gl_framebuffer *fb, 498af69d88dSmrg struct gl_renderbuffer_attachment *att, 499af69d88dSmrg struct gl_texture_object *texObj, 50001e04c3fSmrg GLenum texTarget, GLuint level, GLuint layer, 501af69d88dSmrg GLboolean layered) 5027117f1b4Smrg{ 503af69d88dSmrg struct gl_renderbuffer *rb = att->Renderbuffer; 504af69d88dSmrg 505af69d88dSmrg if (rb && rb->NeedsFinishRenderTexture) 506af69d88dSmrg ctx->Driver.FinishRenderTexture(ctx, rb); 507af69d88dSmrg 5087117f1b4Smrg if (att->Texture == texObj) { 5097117f1b4Smrg /* re-attaching same texture */ 51001e04c3fSmrg assert(att->Type == GL_TEXTURE); 5117117f1b4Smrg } 5127117f1b4Smrg else { 5137117f1b4Smrg /* new attachment */ 514af69d88dSmrg remove_attachment(ctx, att); 5157117f1b4Smrg att->Type = GL_TEXTURE; 5167117f1b4Smrg assert(!att->Texture); 5177117f1b4Smrg _mesa_reference_texobj(&att->Texture, texObj); 5187117f1b4Smrg } 519af69d88dSmrg invalidate_framebuffer(fb); 5207117f1b4Smrg 5217117f1b4Smrg /* always update these fields */ 5227117f1b4Smrg att->TextureLevel = level; 5234a49301eSmrg att->CubeMapFace = _mesa_tex_target_to_face(texTarget); 52401e04c3fSmrg att->Zoffset = layer; 525af69d88dSmrg att->Layered = layered; 5267117f1b4Smrg att->Complete = GL_FALSE; 5277117f1b4Smrg 528af69d88dSmrg _mesa_update_texture_renderbuffer(ctx, fb, att); 5297117f1b4Smrg} 5307117f1b4Smrg 5317117f1b4Smrg 5327117f1b4Smrg/** 5337117f1b4Smrg * Bind a renderbuffer to an attachment point. 5347117f1b4Smrg * The previous binding, if any, will be removed first. 5357117f1b4Smrg */ 536af69d88dSmrgstatic void 537af69d88dSmrgset_renderbuffer_attachment(struct gl_context *ctx, 538af69d88dSmrg struct gl_renderbuffer_attachment *att, 539af69d88dSmrg struct gl_renderbuffer *rb) 5407117f1b4Smrg{ 5417117f1b4Smrg /* XXX check if re-doing same attachment, exit early */ 542af69d88dSmrg remove_attachment(ctx, att); 5437117f1b4Smrg att->Type = GL_RENDERBUFFER_EXT; 5447117f1b4Smrg att->Texture = NULL; /* just to be safe */ 54501e04c3fSmrg att->Layered = GL_FALSE; 5467117f1b4Smrg att->Complete = GL_FALSE; 5477117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 5487117f1b4Smrg} 5497117f1b4Smrg 5507117f1b4Smrg 5517117f1b4Smrg/** 5527117f1b4Smrg * Fallback for ctx->Driver.FramebufferRenderbuffer() 5537117f1b4Smrg * Attach a renderbuffer object to a framebuffer object. 5547117f1b4Smrg */ 5557117f1b4Smrgvoid 55601e04c3fSmrg_mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx, 55701e04c3fSmrg struct gl_framebuffer *fb, 55801e04c3fSmrg GLenum attachment, 55901e04c3fSmrg struct gl_renderbuffer *rb) 5607117f1b4Smrg{ 5617117f1b4Smrg struct gl_renderbuffer_attachment *att; 5627117f1b4Smrg 56301e04c3fSmrg simple_mtx_lock(&fb->Mutex); 5647117f1b4Smrg 56501e04c3fSmrg att = get_attachment(ctx, fb, attachment, NULL); 56601e04c3fSmrg assert(att); 5677117f1b4Smrg if (rb) { 568af69d88dSmrg set_renderbuffer_attachment(ctx, att, rb); 5694a49301eSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 5704a49301eSmrg /* do stencil attachment here (depth already done above) */ 57101e04c3fSmrg att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL); 5724a49301eSmrg assert(att); 573af69d88dSmrg set_renderbuffer_attachment(ctx, att, rb); 5744a49301eSmrg } 5753464ebd5Sriastradh rb->AttachedAnytime = GL_TRUE; 5767117f1b4Smrg } 5777117f1b4Smrg else { 578af69d88dSmrg remove_attachment(ctx, att); 579af69d88dSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 580af69d88dSmrg /* detach stencil (depth was detached above) */ 58101e04c3fSmrg att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL); 582af69d88dSmrg assert(att); 583af69d88dSmrg remove_attachment(ctx, att); 584af69d88dSmrg } 5857117f1b4Smrg } 5867117f1b4Smrg 5874a49301eSmrg invalidate_framebuffer(fb); 5884a49301eSmrg 58901e04c3fSmrg simple_mtx_unlock(&fb->Mutex); 5907117f1b4Smrg} 5917117f1b4Smrg 5927117f1b4Smrg 5933464ebd5Sriastradh/** 5943464ebd5Sriastradh * Fallback for ctx->Driver.ValidateFramebuffer() 5953464ebd5Sriastradh * Check if the renderbuffer's formats are supported by the software 5963464ebd5Sriastradh * renderer. 5973464ebd5Sriastradh * Drivers should probably override this. 5983464ebd5Sriastradh */ 5993464ebd5Sriastradhvoid 6003464ebd5Sriastradh_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) 6013464ebd5Sriastradh{ 6023464ebd5Sriastradh gl_buffer_index buf; 6033464ebd5Sriastradh for (buf = 0; buf < BUFFER_COUNT; buf++) { 6043464ebd5Sriastradh const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer; 6053464ebd5Sriastradh if (rb) { 6063464ebd5Sriastradh switch (rb->_BaseFormat) { 6073464ebd5Sriastradh case GL_ALPHA: 6083464ebd5Sriastradh case GL_LUMINANCE_ALPHA: 6093464ebd5Sriastradh case GL_LUMINANCE: 6103464ebd5Sriastradh case GL_INTENSITY: 6113464ebd5Sriastradh case GL_RED: 6123464ebd5Sriastradh case GL_RG: 6133464ebd5Sriastradh fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 6143464ebd5Sriastradh return; 6153464ebd5Sriastradh 6163464ebd5Sriastradh default: 6173464ebd5Sriastradh switch (rb->Format) { 6183464ebd5Sriastradh /* XXX This list is likely incomplete. */ 619af69d88dSmrg case MESA_FORMAT_R9G9B9E5_FLOAT: 6203464ebd5Sriastradh fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 6213464ebd5Sriastradh return; 6223464ebd5Sriastradh default:; 6233464ebd5Sriastradh /* render buffer format is supported by software rendering */ 6243464ebd5Sriastradh } 6253464ebd5Sriastradh } 6263464ebd5Sriastradh } 6273464ebd5Sriastradh } 6283464ebd5Sriastradh} 6293464ebd5Sriastradh 6303464ebd5Sriastradh 631af69d88dSmrg/** 632af69d88dSmrg * Return true if the framebuffer has a combined depth/stencil 633af69d88dSmrg * renderbuffer attached. 634af69d88dSmrg */ 635af69d88dSmrgGLboolean 636af69d88dSmrg_mesa_has_depthstencil_combined(const struct gl_framebuffer *fb) 637af69d88dSmrg{ 638af69d88dSmrg const struct gl_renderbuffer_attachment *depth = 639af69d88dSmrg &fb->Attachment[BUFFER_DEPTH]; 640af69d88dSmrg const struct gl_renderbuffer_attachment *stencil = 641af69d88dSmrg &fb->Attachment[BUFFER_STENCIL]; 642af69d88dSmrg 643af69d88dSmrg if (depth->Type == stencil->Type) { 644af69d88dSmrg if (depth->Type == GL_RENDERBUFFER_EXT && 645af69d88dSmrg depth->Renderbuffer == stencil->Renderbuffer) 646af69d88dSmrg return GL_TRUE; 647af69d88dSmrg 648af69d88dSmrg if (depth->Type == GL_TEXTURE && 649af69d88dSmrg depth->Texture == stencil->Texture) 650af69d88dSmrg return GL_TRUE; 651af69d88dSmrg } 652af69d88dSmrg 653af69d88dSmrg return GL_FALSE; 654af69d88dSmrg} 655af69d88dSmrg 656af69d88dSmrg 6574a49301eSmrg/** 6584a49301eSmrg * For debug only. 6594a49301eSmrg */ 6604a49301eSmrgstatic void 6614a49301eSmrgatt_incomplete(const char *msg) 6624a49301eSmrg{ 663af69d88dSmrg if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { 664af69d88dSmrg _mesa_debug(NULL, "attachment incomplete: %s\n", msg); 665af69d88dSmrg } 6664a49301eSmrg} 6674a49301eSmrg 6684a49301eSmrg 6694a49301eSmrg/** 6704a49301eSmrg * For debug only. 6714a49301eSmrg */ 6724a49301eSmrgstatic void 673af69d88dSmrgfbo_incomplete(struct gl_context *ctx, const char *msg, int index) 6744a49301eSmrg{ 675af69d88dSmrg static GLuint msg_id; 676af69d88dSmrg 677af69d88dSmrg _mesa_gl_debug(ctx, &msg_id, 67801e04c3fSmrg MESA_DEBUG_SOURCE_API, 679af69d88dSmrg MESA_DEBUG_TYPE_OTHER, 680af69d88dSmrg MESA_DEBUG_SEVERITY_MEDIUM, 681af69d88dSmrg "FBO incomplete: %s [%d]\n", msg, index); 682af69d88dSmrg 683af69d88dSmrg if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { 684af69d88dSmrg _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); 685af69d88dSmrg } 6864a49301eSmrg} 6874a49301eSmrg 6884a49301eSmrg 6893464ebd5Sriastradh/** 6903464ebd5Sriastradh * Is the given base format a legal format for a color renderbuffer? 6913464ebd5Sriastradh */ 6923464ebd5SriastradhGLboolean 6933464ebd5Sriastradh_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) 6943464ebd5Sriastradh{ 6953464ebd5Sriastradh switch (baseFormat) { 6963464ebd5Sriastradh case GL_RGB: 6973464ebd5Sriastradh case GL_RGBA: 6983464ebd5Sriastradh return GL_TRUE; 6993464ebd5Sriastradh case GL_LUMINANCE: 7003464ebd5Sriastradh case GL_LUMINANCE_ALPHA: 7013464ebd5Sriastradh case GL_INTENSITY: 7023464ebd5Sriastradh case GL_ALPHA: 703af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 704af69d88dSmrg ctx->Extensions.ARB_framebuffer_object; 7053464ebd5Sriastradh case GL_RED: 7063464ebd5Sriastradh case GL_RG: 7073464ebd5Sriastradh return ctx->Extensions.ARB_texture_rg; 7083464ebd5Sriastradh default: 7093464ebd5Sriastradh return GL_FALSE; 7103464ebd5Sriastradh } 7113464ebd5Sriastradh} 7123464ebd5Sriastradh 7133464ebd5Sriastradh 714af69d88dSmrg/** 715af69d88dSmrg * Is the given base format a legal format for a color renderbuffer? 716af69d88dSmrg */ 717af69d88dSmrgstatic GLboolean 718af69d88dSmrgis_format_color_renderable(const struct gl_context *ctx, mesa_format format, 719af69d88dSmrg GLenum internalFormat) 720af69d88dSmrg{ 721af69d88dSmrg const GLenum baseFormat = 722af69d88dSmrg _mesa_get_format_base_format(format); 723af69d88dSmrg GLboolean valid; 724af69d88dSmrg 725af69d88dSmrg valid = _mesa_is_legal_color_format(ctx, baseFormat); 726af69d88dSmrg if (!valid || _mesa_is_desktop_gl(ctx)) { 727af69d88dSmrg return valid; 728af69d88dSmrg } 729af69d88dSmrg 730af69d88dSmrg /* Reject additional cases for GLES */ 731af69d88dSmrg switch (internalFormat) { 73201e04c3fSmrg case GL_R8_SNORM: 73301e04c3fSmrg case GL_RG8_SNORM: 734af69d88dSmrg case GL_RGBA8_SNORM: 73501e04c3fSmrg return _mesa_has_EXT_render_snorm(ctx); 73601e04c3fSmrg case GL_R16_SNORM: 73701e04c3fSmrg case GL_RG16_SNORM: 73801e04c3fSmrg case GL_RGBA16_SNORM: 73901e04c3fSmrg return _mesa_has_EXT_texture_norm16(ctx) && 74001e04c3fSmrg _mesa_has_EXT_render_snorm(ctx); 741af69d88dSmrg case GL_RGB32F: 742af69d88dSmrg case GL_RGB32I: 743af69d88dSmrg case GL_RGB32UI: 744af69d88dSmrg case GL_RGB16F: 745af69d88dSmrg case GL_RGB16I: 746af69d88dSmrg case GL_RGB16UI: 747af69d88dSmrg case GL_RGB8_SNORM: 748af69d88dSmrg case GL_RGB8I: 749af69d88dSmrg case GL_RGB8UI: 750af69d88dSmrg case GL_SRGB8: 75101e04c3fSmrg case GL_RGB10: 752af69d88dSmrg case GL_RGB9_E5: 753af69d88dSmrg return GL_FALSE; 754af69d88dSmrg default: 755af69d88dSmrg break; 756af69d88dSmrg } 757af69d88dSmrg 75801e04c3fSmrg if (internalFormat != GL_RGB10_A2 && 75901e04c3fSmrg (format == MESA_FORMAT_B10G10R10A2_UNORM || 76001e04c3fSmrg format == MESA_FORMAT_B10G10R10X2_UNORM || 76101e04c3fSmrg format == MESA_FORMAT_R10G10B10A2_UNORM || 76201e04c3fSmrg format == MESA_FORMAT_R10G10B10X2_UNORM)) { 763af69d88dSmrg return GL_FALSE; 764af69d88dSmrg } 765af69d88dSmrg 766af69d88dSmrg return GL_TRUE; 767af69d88dSmrg} 768af69d88dSmrg 769af69d88dSmrg 7703464ebd5Sriastradh/** 7713464ebd5Sriastradh * Is the given base format a legal format for a depth/stencil renderbuffer? 7723464ebd5Sriastradh */ 7733464ebd5Sriastradhstatic GLboolean 7743464ebd5Sriastradhis_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat) 7753464ebd5Sriastradh{ 7763464ebd5Sriastradh switch (baseFormat) { 7773464ebd5Sriastradh case GL_DEPTH_COMPONENT: 7783464ebd5Sriastradh case GL_DEPTH_STENCIL_EXT: 7793464ebd5Sriastradh return GL_TRUE; 7803464ebd5Sriastradh default: 7813464ebd5Sriastradh return GL_FALSE; 7823464ebd5Sriastradh } 7833464ebd5Sriastradh} 7844a49301eSmrg 7854a49301eSmrg 7867117f1b4Smrg/** 7877117f1b4Smrg * Test if an attachment point is complete and update its Complete field. 7887117f1b4Smrg * \param format if GL_COLOR, this is a color attachment point, 7897117f1b4Smrg * if GL_DEPTH, this is a depth component attachment point, 7907117f1b4Smrg * if GL_STENCIL, this is a stencil component attachment point. 7917117f1b4Smrg */ 7927117f1b4Smrgstatic void 7933464ebd5Sriastradhtest_attachment_completeness(const struct gl_context *ctx, GLenum format, 7947117f1b4Smrg struct gl_renderbuffer_attachment *att) 7957117f1b4Smrg{ 7967117f1b4Smrg assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); 7977117f1b4Smrg 7987117f1b4Smrg /* assume complete */ 7997117f1b4Smrg att->Complete = GL_TRUE; 8007117f1b4Smrg 8017117f1b4Smrg /* Look for reasons why the attachment might be incomplete */ 8027117f1b4Smrg if (att->Type == GL_TEXTURE) { 8037117f1b4Smrg const struct gl_texture_object *texObj = att->Texture; 80401e04c3fSmrg const struct gl_texture_image *texImage; 8054a49301eSmrg GLenum baseFormat; 8067117f1b4Smrg 8077117f1b4Smrg if (!texObj) { 8084a49301eSmrg att_incomplete("no texobj"); 8097117f1b4Smrg att->Complete = GL_FALSE; 8107117f1b4Smrg return; 8117117f1b4Smrg } 8127117f1b4Smrg 8137117f1b4Smrg texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; 8147117f1b4Smrg if (!texImage) { 8154a49301eSmrg att_incomplete("no teximage"); 8167117f1b4Smrg att->Complete = GL_FALSE; 8177117f1b4Smrg return; 8187117f1b4Smrg } 8197117f1b4Smrg if (texImage->Width < 1 || texImage->Height < 1) { 8204a49301eSmrg att_incomplete("teximage width/height=0"); 8217117f1b4Smrg att->Complete = GL_FALSE; 8227117f1b4Smrg return; 8237117f1b4Smrg } 824af69d88dSmrg 825af69d88dSmrg switch (texObj->Target) { 826af69d88dSmrg case GL_TEXTURE_3D: 827af69d88dSmrg if (att->Zoffset >= texImage->Depth) { 828af69d88dSmrg att_incomplete("bad z offset"); 829af69d88dSmrg att->Complete = GL_FALSE; 830af69d88dSmrg return; 831af69d88dSmrg } 832af69d88dSmrg break; 833af69d88dSmrg case GL_TEXTURE_1D_ARRAY: 834af69d88dSmrg if (att->Zoffset >= texImage->Height) { 835af69d88dSmrg att_incomplete("bad 1D-array layer"); 836af69d88dSmrg att->Complete = GL_FALSE; 837af69d88dSmrg return; 838af69d88dSmrg } 839af69d88dSmrg break; 840af69d88dSmrg case GL_TEXTURE_2D_ARRAY: 841af69d88dSmrg if (att->Zoffset >= texImage->Depth) { 842af69d88dSmrg att_incomplete("bad 2D-array layer"); 843af69d88dSmrg att->Complete = GL_FALSE; 844af69d88dSmrg return; 845af69d88dSmrg } 846af69d88dSmrg break; 847af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 848af69d88dSmrg if (att->Zoffset >= texImage->Depth) { 849af69d88dSmrg att_incomplete("bad cube-array layer"); 850af69d88dSmrg att->Complete = GL_FALSE; 851af69d88dSmrg return; 852af69d88dSmrg } 853af69d88dSmrg break; 8547117f1b4Smrg } 8557117f1b4Smrg 85601e04c3fSmrg baseFormat = texImage->_BaseFormat; 8574a49301eSmrg 8587117f1b4Smrg if (format == GL_COLOR) { 8593464ebd5Sriastradh if (!_mesa_is_legal_color_format(ctx, baseFormat)) { 8604a49301eSmrg att_incomplete("bad format"); 8614a49301eSmrg att->Complete = GL_FALSE; 8624a49301eSmrg return; 8634a49301eSmrg } 8644a49301eSmrg if (_mesa_is_format_compressed(texImage->TexFormat)) { 8654a49301eSmrg att_incomplete("compressed internalformat"); 8667117f1b4Smrg att->Complete = GL_FALSE; 8677117f1b4Smrg return; 8687117f1b4Smrg } 86901e04c3fSmrg 87001e04c3fSmrg /* OES_texture_float allows creation and use of floating point 87101e04c3fSmrg * textures with GL_FLOAT, GL_HALF_FLOAT but it does not allow 87201e04c3fSmrg * these textures to be used as a render target, this is done via 87301e04c3fSmrg * GL_EXT_color_buffer(_half)_float with set of new sized types. 87401e04c3fSmrg */ 87501e04c3fSmrg if (_mesa_is_gles(ctx) && (texObj->_IsFloat || texObj->_IsHalfFloat)) { 87601e04c3fSmrg att_incomplete("bad internal format"); 87701e04c3fSmrg att->Complete = GL_FALSE; 87801e04c3fSmrg return; 87901e04c3fSmrg } 8807117f1b4Smrg } 8817117f1b4Smrg else if (format == GL_DEPTH) { 8824a49301eSmrg if (baseFormat == GL_DEPTH_COMPONENT) { 8837117f1b4Smrg /* OK */ 8847117f1b4Smrg } 885af69d88dSmrg else if (ctx->Extensions.ARB_depth_texture && 886af69d88dSmrg baseFormat == GL_DEPTH_STENCIL) { 8877117f1b4Smrg /* OK */ 8887117f1b4Smrg } 8897117f1b4Smrg else { 8907117f1b4Smrg att->Complete = GL_FALSE; 8914a49301eSmrg att_incomplete("bad depth format"); 8927117f1b4Smrg return; 8937117f1b4Smrg } 8947117f1b4Smrg } 8957117f1b4Smrg else { 89601e04c3fSmrg assert(format == GL_STENCIL); 897af69d88dSmrg if (ctx->Extensions.ARB_depth_texture && 898af69d88dSmrg baseFormat == GL_DEPTH_STENCIL) { 899c7037ccdSmrg /* OK */ 90001e04c3fSmrg } else if (ctx->Extensions.ARB_texture_stencil8 && 90101e04c3fSmrg baseFormat == GL_STENCIL_INDEX) { 90201e04c3fSmrg /* OK */ 90301e04c3fSmrg } else { 904c7037ccdSmrg /* no such thing as stencil-only textures */ 9054a49301eSmrg att_incomplete("illegal stencil texture"); 906c7037ccdSmrg att->Complete = GL_FALSE; 907c7037ccdSmrg return; 908c7037ccdSmrg } 9097117f1b4Smrg } 9107117f1b4Smrg } 9117117f1b4Smrg else if (att->Type == GL_RENDERBUFFER_EXT) { 91201e04c3fSmrg const GLenum baseFormat = att->Renderbuffer->_BaseFormat; 9134a49301eSmrg 91401e04c3fSmrg assert(att->Renderbuffer); 9157117f1b4Smrg if (!att->Renderbuffer->InternalFormat || 9167117f1b4Smrg att->Renderbuffer->Width < 1 || 9177117f1b4Smrg att->Renderbuffer->Height < 1) { 9184a49301eSmrg att_incomplete("0x0 renderbuffer"); 9197117f1b4Smrg att->Complete = GL_FALSE; 9207117f1b4Smrg return; 9217117f1b4Smrg } 9227117f1b4Smrg if (format == GL_COLOR) { 9233464ebd5Sriastradh if (!_mesa_is_legal_color_format(ctx, baseFormat)) { 9244a49301eSmrg att_incomplete("bad renderbuffer color format"); 9257117f1b4Smrg att->Complete = GL_FALSE; 9267117f1b4Smrg return; 9277117f1b4Smrg } 9287117f1b4Smrg } 9297117f1b4Smrg else if (format == GL_DEPTH) { 9304a49301eSmrg if (baseFormat == GL_DEPTH_COMPONENT) { 9317117f1b4Smrg /* OK */ 9327117f1b4Smrg } 933af69d88dSmrg else if (baseFormat == GL_DEPTH_STENCIL) { 9347117f1b4Smrg /* OK */ 9357117f1b4Smrg } 9367117f1b4Smrg else { 9374a49301eSmrg att_incomplete("bad renderbuffer depth format"); 9387117f1b4Smrg att->Complete = GL_FALSE; 9397117f1b4Smrg return; 9407117f1b4Smrg } 9417117f1b4Smrg } 9427117f1b4Smrg else { 9437117f1b4Smrg assert(format == GL_STENCIL); 944af69d88dSmrg if (baseFormat == GL_STENCIL_INDEX || 945af69d88dSmrg baseFormat == GL_DEPTH_STENCIL) { 9467117f1b4Smrg /* OK */ 9477117f1b4Smrg } 9487117f1b4Smrg else { 9497117f1b4Smrg att->Complete = GL_FALSE; 9504a49301eSmrg att_incomplete("bad renderbuffer stencil format"); 9517117f1b4Smrg return; 9527117f1b4Smrg } 9537117f1b4Smrg } 9547117f1b4Smrg } 9557117f1b4Smrg else { 95601e04c3fSmrg assert(att->Type == GL_NONE); 9577117f1b4Smrg /* complete */ 9587117f1b4Smrg return; 9597117f1b4Smrg } 9607117f1b4Smrg} 9617117f1b4Smrg 9627117f1b4Smrg 9637117f1b4Smrg/** 9647117f1b4Smrg * Test if the given framebuffer object is complete and update its 9657117f1b4Smrg * Status field with the results. 9664a49301eSmrg * Calls the ctx->Driver.ValidateFramebuffer() function to allow the 9674a49301eSmrg * driver to make hardware-specific validation/completeness checks. 9687117f1b4Smrg * Also update the framebuffer's Width and Height fields if the 9697117f1b4Smrg * framebuffer is complete. 9707117f1b4Smrg */ 9717117f1b4Smrgvoid 9723464ebd5Sriastradh_mesa_test_framebuffer_completeness(struct gl_context *ctx, 9733464ebd5Sriastradh struct gl_framebuffer *fb) 9747117f1b4Smrg{ 9754a49301eSmrg GLuint numImages; 9764a49301eSmrg GLenum intFormat = GL_NONE; /* color buffers' internal format */ 9774a49301eSmrg GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; 97801e04c3fSmrg GLint numColorSamples = -1; 97901e04c3fSmrg GLint numColorStorageSamples = -1; 98001e04c3fSmrg GLint numDepthSamples = -1; 981af69d88dSmrg GLint fixedSampleLocations = -1; 9827117f1b4Smrg GLint i; 9837117f1b4Smrg GLuint j; 984af69d88dSmrg /* Covers max_layer_count, is_layered, and layer_tex_target */ 985af69d88dSmrg bool layer_info_valid = false; 986af69d88dSmrg GLuint max_layer_count = 0, att_layer_count; 987af69d88dSmrg bool is_layered = false; 988af69d88dSmrg GLenum layer_tex_target = 0; 98901e04c3fSmrg bool has_depth_attachment = false; 99001e04c3fSmrg bool has_stencil_attachment = false; 991af69d88dSmrg 992af69d88dSmrg assert(_mesa_is_user_fbo(fb)); 9937117f1b4Smrg 994af69d88dSmrg /* we're changing framebuffer fields here */ 995af69d88dSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 9967117f1b4Smrg 9977117f1b4Smrg numImages = 0; 9987117f1b4Smrg fb->Width = 0; 9997117f1b4Smrg fb->Height = 0; 1000af69d88dSmrg fb->_AllColorBuffersFixedPoint = GL_TRUE; 1001af69d88dSmrg fb->_HasSNormOrFloatColorBuffer = GL_FALSE; 100201e04c3fSmrg fb->_HasAttachments = true; 100301e04c3fSmrg fb->_IntegerBuffers = 0; 10047117f1b4Smrg 10054a49301eSmrg /* Start at -2 to more easily loop over all attachment points. 10064a49301eSmrg * -2: depth buffer 10074a49301eSmrg * -1: stencil buffer 10084a49301eSmrg * >=0: color buffer 10094a49301eSmrg */ 10107117f1b4Smrg for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { 10117117f1b4Smrg struct gl_renderbuffer_attachment *att; 10127117f1b4Smrg GLenum f; 1013af69d88dSmrg mesa_format attFormat; 1014af69d88dSmrg GLenum att_tex_target = GL_NONE; 10157117f1b4Smrg 10164a49301eSmrg /* 10174a49301eSmrg * XXX for ARB_fbo, only check color buffers that are named by 10184a49301eSmrg * GL_READ_BUFFER and GL_DRAW_BUFFERi. 10194a49301eSmrg */ 10204a49301eSmrg 10214a49301eSmrg /* check for attachment completeness 10224a49301eSmrg */ 10237117f1b4Smrg if (i == -2) { 10247117f1b4Smrg att = &fb->Attachment[BUFFER_DEPTH]; 10257117f1b4Smrg test_attachment_completeness(ctx, GL_DEPTH, att); 10267117f1b4Smrg if (!att->Complete) { 10277117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 1028af69d88dSmrg fbo_incomplete(ctx, "depth attachment incomplete", -1); 10297117f1b4Smrg return; 103001e04c3fSmrg } else if (att->Type != GL_NONE) { 103101e04c3fSmrg has_depth_attachment = true; 10327117f1b4Smrg } 10337117f1b4Smrg } 10347117f1b4Smrg else if (i == -1) { 10357117f1b4Smrg att = &fb->Attachment[BUFFER_STENCIL]; 10367117f1b4Smrg test_attachment_completeness(ctx, GL_STENCIL, att); 10377117f1b4Smrg if (!att->Complete) { 10387117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 1039af69d88dSmrg fbo_incomplete(ctx, "stencil attachment incomplete", -1); 10407117f1b4Smrg return; 104101e04c3fSmrg } else if (att->Type != GL_NONE) { 104201e04c3fSmrg has_stencil_attachment = true; 10437117f1b4Smrg } 10447117f1b4Smrg } 10457117f1b4Smrg else { 10467117f1b4Smrg att = &fb->Attachment[BUFFER_COLOR0 + i]; 10477117f1b4Smrg test_attachment_completeness(ctx, GL_COLOR, att); 10487117f1b4Smrg if (!att->Complete) { 10497117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 1050af69d88dSmrg fbo_incomplete(ctx, "color attachment incomplete", i); 10517117f1b4Smrg return; 10527117f1b4Smrg } 10537117f1b4Smrg } 10547117f1b4Smrg 10554a49301eSmrg /* get width, height, format of the renderbuffer/texture 10564a49301eSmrg */ 105701e04c3fSmrg unsigned attNumSamples, attNumStorageSamples; 105801e04c3fSmrg 10597117f1b4Smrg if (att->Type == GL_TEXTURE) { 1060af69d88dSmrg const struct gl_texture_image *texImg = att->Renderbuffer->TexImage; 1061af69d88dSmrg att_tex_target = att->Texture->Target; 10624a49301eSmrg minWidth = MIN2(minWidth, texImg->Width); 10634a49301eSmrg maxWidth = MAX2(maxWidth, texImg->Width); 10644a49301eSmrg minHeight = MIN2(minHeight, texImg->Height); 10654a49301eSmrg maxHeight = MAX2(maxHeight, texImg->Height); 10667117f1b4Smrg f = texImg->_BaseFormat; 10673464ebd5Sriastradh attFormat = texImg->TexFormat; 10687117f1b4Smrg numImages++; 1069af69d88dSmrg 1070af69d88dSmrg if (!is_format_color_renderable(ctx, attFormat, 1071af69d88dSmrg texImg->InternalFormat) && 107201e04c3fSmrg !is_legal_depth_format(ctx, f) && 107301e04c3fSmrg f != GL_STENCIL_INDEX) { 107401e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 1075af69d88dSmrg fbo_incomplete(ctx, "texture attachment incomplete", -1); 1076af69d88dSmrg return; 1077af69d88dSmrg } 1078af69d88dSmrg 1079af69d88dSmrg if (fixedSampleLocations < 0) 1080af69d88dSmrg fixedSampleLocations = texImg->FixedSampleLocations; 1081af69d88dSmrg else if (fixedSampleLocations != texImg->FixedSampleLocations) { 1082af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 1083af69d88dSmrg fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); 10847117f1b4Smrg return; 10857117f1b4Smrg } 108601e04c3fSmrg 108701e04c3fSmrg attNumSamples = texImg->NumSamples; 108801e04c3fSmrg attNumStorageSamples = texImg->NumSamples; 10897117f1b4Smrg } 10907117f1b4Smrg else if (att->Type == GL_RENDERBUFFER_EXT) { 10914a49301eSmrg minWidth = MIN2(minWidth, att->Renderbuffer->Width); 10924a49301eSmrg maxWidth = MAX2(minWidth, att->Renderbuffer->Width); 10934a49301eSmrg minHeight = MIN2(minHeight, att->Renderbuffer->Height); 10944a49301eSmrg maxHeight = MAX2(minHeight, att->Renderbuffer->Height); 10957117f1b4Smrg f = att->Renderbuffer->InternalFormat; 10963464ebd5Sriastradh attFormat = att->Renderbuffer->Format; 10977117f1b4Smrg numImages++; 1098af69d88dSmrg 1099af69d88dSmrg /* RENDERBUFFER has fixedSampleLocations implicitly true */ 1100af69d88dSmrg if (fixedSampleLocations < 0) 1101af69d88dSmrg fixedSampleLocations = GL_TRUE; 1102af69d88dSmrg else if (fixedSampleLocations != GL_TRUE) { 1103af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 1104af69d88dSmrg fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); 1105af69d88dSmrg return; 1106af69d88dSmrg } 110701e04c3fSmrg 110801e04c3fSmrg attNumSamples = att->Renderbuffer->NumSamples; 110901e04c3fSmrg attNumStorageSamples = att->Renderbuffer->NumStorageSamples; 11107117f1b4Smrg } 11117117f1b4Smrg else { 11127117f1b4Smrg assert(att->Type == GL_NONE); 11137117f1b4Smrg continue; 11147117f1b4Smrg } 11157117f1b4Smrg 111601e04c3fSmrg if (i >= 0) { 111701e04c3fSmrg /* Color buffers. */ 111801e04c3fSmrg if (numColorSamples < 0) { 111901e04c3fSmrg assert(numColorStorageSamples < 0); 112001e04c3fSmrg numColorSamples = attNumSamples; 112101e04c3fSmrg numColorStorageSamples = attNumStorageSamples; 112201e04c3fSmrg } else if (numColorSamples != attNumSamples || 112301e04c3fSmrg numColorStorageSamples != attNumStorageSamples) { 112401e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 112501e04c3fSmrg fbo_incomplete(ctx, "inconsistent sample counts", -1); 112601e04c3fSmrg return; 112701e04c3fSmrg } 112801e04c3fSmrg } else { 112901e04c3fSmrg /* Depth/stencil buffers. */ 113001e04c3fSmrg if (numDepthSamples < 0) { 113101e04c3fSmrg numDepthSamples = attNumSamples; 113201e04c3fSmrg } else if (numDepthSamples != attNumSamples) { 113301e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 113401e04c3fSmrg fbo_incomplete(ctx, "inconsistent sample counts", -1); 113501e04c3fSmrg return; 113601e04c3fSmrg } 113701e04c3fSmrg } 11383464ebd5Sriastradh 113901e04c3fSmrg /* Update flags describing color buffer datatypes */ 1140af69d88dSmrg if (i >= 0) { 1141af69d88dSmrg GLenum type = _mesa_get_format_datatype(attFormat); 1142af69d88dSmrg 114301e04c3fSmrg /* check if integer color */ 114401e04c3fSmrg if (_mesa_is_format_integer_color(attFormat)) 114501e04c3fSmrg fb->_IntegerBuffers |= (1 << i); 114601e04c3fSmrg 1147af69d88dSmrg fb->_AllColorBuffersFixedPoint = 1148af69d88dSmrg fb->_AllColorBuffersFixedPoint && 1149af69d88dSmrg (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED); 1150af69d88dSmrg 1151af69d88dSmrg fb->_HasSNormOrFloatColorBuffer = 1152af69d88dSmrg fb->_HasSNormOrFloatColorBuffer || 1153af69d88dSmrg type == GL_SIGNED_NORMALIZED || type == GL_FLOAT; 1154af69d88dSmrg } 1155af69d88dSmrg 1156af69d88dSmrg /* Error-check width, height, format */ 11577117f1b4Smrg if (numImages == 1) { 1158af69d88dSmrg /* save format */ 11594a49301eSmrg if (i >= 0) { 11607117f1b4Smrg intFormat = f; 11614a49301eSmrg } 11627117f1b4Smrg } 11637117f1b4Smrg else { 11644a49301eSmrg if (!ctx->Extensions.ARB_framebuffer_object) { 11654a49301eSmrg /* check that width, height, format are same */ 11664a49301eSmrg if (minWidth != maxWidth || minHeight != maxHeight) { 11674a49301eSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 1168af69d88dSmrg fbo_incomplete(ctx, "width or height mismatch", -1); 11694a49301eSmrg return; 11704a49301eSmrg } 1171af69d88dSmrg /* check that all color buffers are the same format */ 11724a49301eSmrg if (intFormat != GL_NONE && f != intFormat) { 11734a49301eSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 1174af69d88dSmrg fbo_incomplete(ctx, "format mismatch", -1); 11754a49301eSmrg return; 11764a49301eSmrg } 11777117f1b4Smrg } 1178af69d88dSmrg } 1179af69d88dSmrg 1180af69d88dSmrg /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported) 1181af69d88dSmrg */ 1182af69d88dSmrg if (att->Type == GL_RENDERBUFFER && 1183af69d88dSmrg att->Renderbuffer->Format == MESA_FORMAT_NONE) { 1184af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 1185af69d88dSmrg fbo_incomplete(ctx, "unsupported renderbuffer format", i); 1186af69d88dSmrg return; 1187af69d88dSmrg } 11884a49301eSmrg 1189af69d88dSmrg /* Check that layered rendering is consistent. */ 1190af69d88dSmrg if (att->Layered) { 1191af69d88dSmrg if (att_tex_target == GL_TEXTURE_CUBE_MAP) 1192af69d88dSmrg att_layer_count = 6; 1193af69d88dSmrg else if (att_tex_target == GL_TEXTURE_1D_ARRAY) 1194af69d88dSmrg att_layer_count = att->Renderbuffer->Height; 1195af69d88dSmrg else 1196af69d88dSmrg att_layer_count = att->Renderbuffer->Depth; 1197af69d88dSmrg } else { 1198af69d88dSmrg att_layer_count = 0; 1199af69d88dSmrg } 1200af69d88dSmrg if (!layer_info_valid) { 1201af69d88dSmrg is_layered = att->Layered; 1202af69d88dSmrg max_layer_count = att_layer_count; 1203af69d88dSmrg layer_tex_target = att_tex_target; 1204af69d88dSmrg layer_info_valid = true; 1205af69d88dSmrg } else if (max_layer_count > 0 && layer_tex_target != att_tex_target) { 1206af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; 1207af69d88dSmrg fbo_incomplete(ctx, "layered framebuffer has mismatched targets", i); 1208af69d88dSmrg return; 1209af69d88dSmrg } else if (is_layered != att->Layered) { 1210af69d88dSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; 1211af69d88dSmrg fbo_incomplete(ctx, 1212af69d88dSmrg "framebuffer attachment layer mode is inconsistent", 1213af69d88dSmrg i); 1214af69d88dSmrg return; 1215af69d88dSmrg } else if (att_layer_count > max_layer_count) { 1216af69d88dSmrg max_layer_count = att_layer_count; 12177117f1b4Smrg } 121801e04c3fSmrg 121901e04c3fSmrg /* 122001e04c3fSmrg * The extension GL_ARB_framebuffer_no_attachments places additional 122101e04c3fSmrg * requirement on each attachment. Those additional requirements are 122201e04c3fSmrg * tighter that those of previous versions of GL. In interest of better 122301e04c3fSmrg * compatibility, we will not enforce these restrictions. For the record 122401e04c3fSmrg * those additional restrictions are quoted below: 122501e04c3fSmrg * 122601e04c3fSmrg * "The width and height of image are greater than zero and less than or 122701e04c3fSmrg * equal to the values of the implementation-dependent limits 122801e04c3fSmrg * MAX_FRAMEBUFFER_WIDTH and MAX_FRAMEBUFFER_HEIGHT, respectively." 122901e04c3fSmrg * 123001e04c3fSmrg * "If <image> is a three-dimensional texture or a one- or two-dimensional 123101e04c3fSmrg * array texture and the attachment is layered, the depth or layer count 123201e04c3fSmrg * of the texture is less than or equal to the implementation-dependent 123301e04c3fSmrg * limit MAX_FRAMEBUFFER_LAYERS." 123401e04c3fSmrg * 123501e04c3fSmrg * "If image has multiple samples, its sample count is less than or equal 123601e04c3fSmrg * to the value of the implementation-dependent limit 123701e04c3fSmrg * MAX_FRAMEBUFFER_SAMPLES." 123801e04c3fSmrg * 123901e04c3fSmrg * The same requirements are also in place for GL 4.5, 124001e04c3fSmrg * Section 9.4.1 "Framebuffer Attachment Completeness", pg 310-311 124101e04c3fSmrg */ 124201e04c3fSmrg } 124301e04c3fSmrg 124401e04c3fSmrg if (ctx->Extensions.AMD_framebuffer_multisample_advanced) { 124501e04c3fSmrg /* See if non-matching sample counts are supported. */ 124601e04c3fSmrg if (numColorSamples >= 0 && numDepthSamples >= 0) { 124701e04c3fSmrg bool found = false; 124801e04c3fSmrg 124901e04c3fSmrg assert(numColorStorageSamples != -1); 125001e04c3fSmrg 125101e04c3fSmrg numColorSamples = MAX2(numColorSamples, 1); 125201e04c3fSmrg numColorStorageSamples = MAX2(numColorStorageSamples, 1); 125301e04c3fSmrg numDepthSamples = MAX2(numDepthSamples, 1); 125401e04c3fSmrg 125501e04c3fSmrg if (numColorSamples == 1 && numColorStorageSamples == 1 && 125601e04c3fSmrg numDepthSamples == 1) { 125701e04c3fSmrg found = true; 125801e04c3fSmrg } else { 125901e04c3fSmrg for (i = 0; i < ctx->Const.NumSupportedMultisampleModes; i++) { 126001e04c3fSmrg GLint *counts = 126101e04c3fSmrg &ctx->Const.SupportedMultisampleModes[i].NumColorSamples; 126201e04c3fSmrg 126301e04c3fSmrg if (counts[0] == numColorSamples && 126401e04c3fSmrg counts[1] == numColorStorageSamples && 126501e04c3fSmrg counts[2] == numDepthSamples) { 126601e04c3fSmrg found = true; 126701e04c3fSmrg break; 126801e04c3fSmrg } 126901e04c3fSmrg } 127001e04c3fSmrg } 127101e04c3fSmrg 127201e04c3fSmrg if (!found) { 127301e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 127401e04c3fSmrg fbo_incomplete(ctx, "unsupported sample counts", -1); 127501e04c3fSmrg return; 127601e04c3fSmrg } 127701e04c3fSmrg } 127801e04c3fSmrg } else { 127901e04c3fSmrg /* If the extension is unsupported, all sample counts must be equal. */ 128001e04c3fSmrg if (numColorSamples >= 0 && 128101e04c3fSmrg (numColorSamples != numColorStorageSamples || 128201e04c3fSmrg (numDepthSamples >= 0 && numColorSamples != numDepthSamples))) { 128301e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 128401e04c3fSmrg fbo_incomplete(ctx, "inconsistent sample counts", -1); 128501e04c3fSmrg return; 128601e04c3fSmrg } 12877117f1b4Smrg } 12887117f1b4Smrg 1289af69d88dSmrg fb->MaxNumLayers = max_layer_count; 1290af69d88dSmrg 1291af69d88dSmrg if (numImages == 0) { 129201e04c3fSmrg fb->_HasAttachments = false; 129301e04c3fSmrg 129401e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments) { 129501e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 129601e04c3fSmrg fbo_incomplete(ctx, "no attachments", -1); 129701e04c3fSmrg return; 129801e04c3fSmrg } 129901e04c3fSmrg 130001e04c3fSmrg if (fb->DefaultGeometry.Width == 0 || fb->DefaultGeometry.Height == 0) { 130101e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 130201e04c3fSmrg fbo_incomplete(ctx, "no attachments and default width or height is 0", -1); 130301e04c3fSmrg return; 130401e04c3fSmrg } 1305af69d88dSmrg } 1306af69d88dSmrg 1307af69d88dSmrg if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) { 13083464ebd5Sriastradh /* Check that all DrawBuffers are present */ 13093464ebd5Sriastradh for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { 131001e04c3fSmrg if (fb->ColorDrawBuffer[j] != GL_NONE) { 131101e04c3fSmrg const struct gl_renderbuffer_attachment *att 131201e04c3fSmrg = get_attachment(ctx, fb, fb->ColorDrawBuffer[j], NULL); 131301e04c3fSmrg assert(att); 131401e04c3fSmrg if (att->Type == GL_NONE) { 131501e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; 131601e04c3fSmrg fbo_incomplete(ctx, "missing drawbuffer", j); 131701e04c3fSmrg return; 131801e04c3fSmrg } 131901e04c3fSmrg } 13207117f1b4Smrg } 13217117f1b4Smrg 13223464ebd5Sriastradh /* Check that the ReadBuffer is present */ 13233464ebd5Sriastradh if (fb->ColorReadBuffer != GL_NONE) { 132401e04c3fSmrg const struct gl_renderbuffer_attachment *att 132501e04c3fSmrg = get_attachment(ctx, fb, fb->ColorReadBuffer, NULL); 132601e04c3fSmrg assert(att); 132701e04c3fSmrg if (att->Type == GL_NONE) { 132801e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; 1329af69d88dSmrg fbo_incomplete(ctx, "missing readbuffer", -1); 133001e04c3fSmrg return; 133101e04c3fSmrg } 13327117f1b4Smrg } 13337117f1b4Smrg } 13347117f1b4Smrg 133501e04c3fSmrg /* The OpenGL ES3 spec, in chapter 9.4. FRAMEBUFFER COMPLETENESS, says: 133601e04c3fSmrg * 133701e04c3fSmrg * "Depth and stencil attachments, if present, are the same image." 133801e04c3fSmrg * 133901e04c3fSmrg * This restriction is not present in the OpenGL ES2 spec. 134001e04c3fSmrg */ 134101e04c3fSmrg if (_mesa_is_gles3(ctx) && 134201e04c3fSmrg has_stencil_attachment && has_depth_attachment && 134301e04c3fSmrg !_mesa_has_depthstencil_combined(fb)) { 134401e04c3fSmrg fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; 134501e04c3fSmrg fbo_incomplete(ctx, "Depth and stencil attachments must be the same image", -1); 134601e04c3fSmrg return; 134701e04c3fSmrg } 134801e04c3fSmrg 13494a49301eSmrg /* Provisionally set status = COMPLETE ... */ 13507117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 13514a49301eSmrg 13524a49301eSmrg /* ... but the driver may say the FB is incomplete. 13534a49301eSmrg * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED 13544a49301eSmrg * if anything. 13554a49301eSmrg */ 13564a49301eSmrg if (ctx->Driver.ValidateFramebuffer) { 13574a49301eSmrg ctx->Driver.ValidateFramebuffer(ctx, fb); 13584a49301eSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 1359af69d88dSmrg fbo_incomplete(ctx, "driver marked FBO as incomplete", -1); 136001e04c3fSmrg return; 13614a49301eSmrg } 13624a49301eSmrg } 13634a49301eSmrg 136401e04c3fSmrg /* 136501e04c3fSmrg * Note that if ARB_framebuffer_object is supported and the attached 136601e04c3fSmrg * renderbuffers/textures are different sizes, the framebuffer 136701e04c3fSmrg * width/height will be set to the smallest width/height. 136801e04c3fSmrg */ 136901e04c3fSmrg if (numImages != 0) { 13704a49301eSmrg fb->Width = minWidth; 13714a49301eSmrg fb->Height = minHeight; 13724a49301eSmrg } 137301e04c3fSmrg 137401e04c3fSmrg /* finally, update the visual info for the framebuffer */ 137501e04c3fSmrg _mesa_update_framebuffer_visual(ctx, fb); 13767117f1b4Smrg} 13777117f1b4Smrg 13787117f1b4Smrg 13797117f1b4SmrgGLboolean GLAPIENTRY 1380af69d88dSmrg_mesa_IsRenderbuffer(GLuint renderbuffer) 13817117f1b4Smrg{ 138201e04c3fSmrg struct gl_renderbuffer *rb; 138301e04c3fSmrg 13847117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 138501e04c3fSmrg 13867117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 138701e04c3fSmrg 138801e04c3fSmrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 138901e04c3fSmrg return rb != NULL && rb != &DummyRenderbuffer; 139001e04c3fSmrg} 139101e04c3fSmrg 139201e04c3fSmrg 139301e04c3fSmrgstatic struct gl_renderbuffer * 139401e04c3fSmrgallocate_renderbuffer_locked(struct gl_context *ctx, GLuint renderbuffer, 139501e04c3fSmrg const char *func) 139601e04c3fSmrg{ 139701e04c3fSmrg struct gl_renderbuffer *newRb; 139801e04c3fSmrg 139901e04c3fSmrg /* create new renderbuffer object */ 140001e04c3fSmrg newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); 140101e04c3fSmrg if (!newRb) { 140201e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 140301e04c3fSmrg return NULL; 14047117f1b4Smrg } 140501e04c3fSmrg assert(newRb->AllocStorage); 140601e04c3fSmrg _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, renderbuffer, newRb); 140701e04c3fSmrg 140801e04c3fSmrg return newRb; 14097117f1b4Smrg} 14107117f1b4Smrg 14117117f1b4Smrg 1412af69d88dSmrgstatic void 141301e04c3fSmrgbind_renderbuffer(GLenum target, GLuint renderbuffer) 14147117f1b4Smrg{ 14157117f1b4Smrg struct gl_renderbuffer *newRb; 14167117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 14177117f1b4Smrg 14187117f1b4Smrg if (target != GL_RENDERBUFFER_EXT) { 14194a49301eSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); 14207117f1b4Smrg return; 14217117f1b4Smrg } 14227117f1b4Smrg 14234a49301eSmrg /* No need to flush here since the render buffer binding has no 14244a49301eSmrg * effect on rendering state. 14257117f1b4Smrg */ 14267117f1b4Smrg 14277117f1b4Smrg if (renderbuffer) { 14287117f1b4Smrg newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 14297117f1b4Smrg if (newRb == &DummyRenderbuffer) { 14307117f1b4Smrg /* ID was reserved, but no real renderbuffer object made yet */ 14317117f1b4Smrg newRb = NULL; 14327117f1b4Smrg } 143301e04c3fSmrg else if (!newRb && ctx->API == API_OPENGL_CORE) { 14344a49301eSmrg /* All RB IDs must be Gen'd */ 143501e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 143601e04c3fSmrg "glBindRenderbuffer(non-gen name)"); 14374a49301eSmrg return; 14384a49301eSmrg } 14394a49301eSmrg 14407117f1b4Smrg if (!newRb) { 144101e04c3fSmrg _mesa_HashLockMutex(ctx->Shared->RenderBuffers); 144201e04c3fSmrg newRb = allocate_renderbuffer_locked(ctx, renderbuffer, 144301e04c3fSmrg "glBindRenderbufferEXT"); 144401e04c3fSmrg _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); 14457117f1b4Smrg } 14467117f1b4Smrg } 14477117f1b4Smrg else { 14487117f1b4Smrg newRb = NULL; 14497117f1b4Smrg } 14507117f1b4Smrg 145101e04c3fSmrg assert(newRb != &DummyRenderbuffer); 14527117f1b4Smrg 14537117f1b4Smrg _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); 14547117f1b4Smrg} 14557117f1b4Smrg 1456af69d88dSmrgvoid GLAPIENTRY 1457af69d88dSmrg_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer) 1458af69d88dSmrg{ 1459af69d88dSmrg /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same 1460af69d88dSmrg * entry point, but they allow the use of user-generated names. 1461af69d88dSmrg */ 146201e04c3fSmrg bind_renderbuffer(target, renderbuffer); 1463af69d88dSmrg} 1464af69d88dSmrg 1465af69d88dSmrgvoid GLAPIENTRY 1466af69d88dSmrg_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 1467af69d88dSmrg{ 146801e04c3fSmrg bind_renderbuffer(target, renderbuffer); 1469af69d88dSmrg} 1470af69d88dSmrg 14714a49301eSmrg/** 147201e04c3fSmrg * ARB_framebuffer_no_attachment and ARB_sample_locations - Application passes 147301e04c3fSmrg * requested param's here. NOTE: NumSamples requested need not be _NumSamples 147401e04c3fSmrg * which is what the hw supports. 14754a49301eSmrg */ 147601e04c3fSmrgstatic void 147701e04c3fSmrgframebuffer_parameteri(struct gl_context *ctx, struct gl_framebuffer *fb, 147801e04c3fSmrg GLenum pname, GLint param, const char *func) 14794a49301eSmrg{ 148001e04c3fSmrg bool cannot_be_winsys_fbo = false; 1481af69d88dSmrg 148201e04c3fSmrg switch (pname) { 148301e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_WIDTH: 148401e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_HEIGHT: 148501e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_LAYERS: 148601e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_SAMPLES: 148701e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: 148801e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments) 148901e04c3fSmrg goto invalid_pname_enum; 149001e04c3fSmrg cannot_be_winsys_fbo = true; 149101e04c3fSmrg break; 149201e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 149301e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 149401e04c3fSmrg if (!ctx->Extensions.ARB_sample_locations) 149501e04c3fSmrg goto invalid_pname_enum; 149601e04c3fSmrg break; 149701e04c3fSmrg case GL_FRAMEBUFFER_FLIP_Y_MESA: 149801e04c3fSmrg if (!ctx->Extensions.MESA_framebuffer_flip_y) 149901e04c3fSmrg goto invalid_pname_enum; 150001e04c3fSmrg cannot_be_winsys_fbo = true; 150101e04c3fSmrg break; 150201e04c3fSmrg default: 150301e04c3fSmrg goto invalid_pname_enum; 150401e04c3fSmrg } 150501e04c3fSmrg 150601e04c3fSmrg if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) { 150701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 150801e04c3fSmrg "%s(invalid pname=0x%x for default framebuffer)", func, pname); 150901e04c3fSmrg return; 151001e04c3fSmrg } 151101e04c3fSmrg 151201e04c3fSmrg switch (pname) { 151301e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_WIDTH: 151401e04c3fSmrg if (param < 0 || param > ctx->Const.MaxFramebufferWidth) 151501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s", func); 151601e04c3fSmrg else 151701e04c3fSmrg fb->DefaultGeometry.Width = param; 151801e04c3fSmrg break; 151901e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_HEIGHT: 152001e04c3fSmrg if (param < 0 || param > ctx->Const.MaxFramebufferHeight) 152101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s", func); 152201e04c3fSmrg else 152301e04c3fSmrg fb->DefaultGeometry.Height = param; 152401e04c3fSmrg break; 152501e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_LAYERS: 152601e04c3fSmrg /* 152701e04c3fSmrg * According to the OpenGL ES 3.1 specification section 9.2.1, the 152801e04c3fSmrg * GL_FRAMEBUFFER_DEFAULT_LAYERS parameter name is not supported. 152901e04c3fSmrg */ 153001e04c3fSmrg if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) { 153101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 153201e04c3fSmrg break; 15334a49301eSmrg } 153401e04c3fSmrg if (param < 0 || param > ctx->Const.MaxFramebufferLayers) 153501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s", func); 153601e04c3fSmrg else 153701e04c3fSmrg fb->DefaultGeometry.Layers = param; 153801e04c3fSmrg break; 153901e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_SAMPLES: 154001e04c3fSmrg if (param < 0 || param > ctx->Const.MaxFramebufferSamples) 154101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s", func); 154201e04c3fSmrg else 154301e04c3fSmrg fb->DefaultGeometry.NumSamples = param; 154401e04c3fSmrg break; 154501e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: 154601e04c3fSmrg fb->DefaultGeometry.FixedSampleLocations = param; 154701e04c3fSmrg break; 154801e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 154901e04c3fSmrg fb->ProgrammableSampleLocations = !!param; 155001e04c3fSmrg break; 155101e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 155201e04c3fSmrg fb->SampleLocationPixelGrid = !!param; 155301e04c3fSmrg break; 155401e04c3fSmrg case GL_FRAMEBUFFER_FLIP_Y_MESA: 155501e04c3fSmrg fb->FlipY = param; 155601e04c3fSmrg break; 15574a49301eSmrg } 1558af69d88dSmrg 155901e04c3fSmrg switch (pname) { 156001e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 156101e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 156201e04c3fSmrg if (fb == ctx->DrawBuffer) 156301e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations; 156401e04c3fSmrg break; 156501e04c3fSmrg default: 1566af69d88dSmrg invalidate_framebuffer(fb); 156701e04c3fSmrg ctx->NewState |= _NEW_BUFFERS; 156801e04c3fSmrg break; 156901e04c3fSmrg } 1570af69d88dSmrg 157101e04c3fSmrg return; 15724a49301eSmrg 157301e04c3fSmrginvalid_pname_enum: 157401e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 157501e04c3fSmrg} 15764a49301eSmrg 15777117f1b4Smrgvoid GLAPIENTRY 157801e04c3fSmrg_mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param) 15797117f1b4Smrg{ 15807117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 158101e04c3fSmrg struct gl_framebuffer *fb; 15827117f1b4Smrg 158301e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments && 158401e04c3fSmrg !ctx->Extensions.ARB_sample_locations) { 158501e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 158601e04c3fSmrg "glFramebufferParameteriv not supported " 158701e04c3fSmrg "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations" 158801e04c3fSmrg " is available)"); 158901e04c3fSmrg return; 159001e04c3fSmrg } 15917117f1b4Smrg 159201e04c3fSmrg fb = get_framebuffer_target(ctx, target); 159301e04c3fSmrg if (!fb) { 159401e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 159501e04c3fSmrg "glFramebufferParameteri(target=0x%x)", target); 159601e04c3fSmrg return; 159701e04c3fSmrg } 15987117f1b4Smrg 159901e04c3fSmrg framebuffer_parameteri(ctx, fb, pname, param, "glFramebufferParameteri"); 160001e04c3fSmrg} 160101e04c3fSmrg 160201e04c3fSmrgstatic bool 160301e04c3fSmrgvalidate_get_framebuffer_parameteriv_pname(struct gl_context *ctx, 160401e04c3fSmrg struct gl_framebuffer *fb, 160501e04c3fSmrg GLuint pname, const char *func) 160601e04c3fSmrg{ 160701e04c3fSmrg bool cannot_be_winsys_fbo = true; 160801e04c3fSmrg 160901e04c3fSmrg switch (pname) { 161001e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_LAYERS: 161101e04c3fSmrg /* 161201e04c3fSmrg * According to the OpenGL ES 3.1 specification section 9.2.3, the 161301e04c3fSmrg * GL_FRAMEBUFFER_LAYERS parameter name is not supported. 161401e04c3fSmrg */ 161501e04c3fSmrg if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) { 161601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 161701e04c3fSmrg return false; 161801e04c3fSmrg } 161901e04c3fSmrg break; 162001e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_WIDTH: 162101e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_HEIGHT: 162201e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_SAMPLES: 162301e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: 162401e04c3fSmrg break; 162501e04c3fSmrg case GL_DOUBLEBUFFER: 162601e04c3fSmrg case GL_IMPLEMENTATION_COLOR_READ_FORMAT: 162701e04c3fSmrg case GL_IMPLEMENTATION_COLOR_READ_TYPE: 162801e04c3fSmrg case GL_SAMPLES: 162901e04c3fSmrg case GL_SAMPLE_BUFFERS: 163001e04c3fSmrg case GL_STEREO: 163101e04c3fSmrg /* From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries: 163201e04c3fSmrg * 163301e04c3fSmrg * "An INVALID_OPERATION error is generated by GetFramebufferParameteriv 163401e04c3fSmrg * if the default framebuffer is bound to target and pname is not one 163501e04c3fSmrg * of the accepted values from table 23.73, other than 163601e04c3fSmrg * SAMPLE_POSITION." 163701e04c3fSmrg * 163801e04c3fSmrg * For OpenGL ES, using default framebuffer raises INVALID_OPERATION 163901e04c3fSmrg * for any pname. 164001e04c3fSmrg */ 164101e04c3fSmrg cannot_be_winsys_fbo = !_mesa_is_desktop_gl(ctx); 164201e04c3fSmrg break; 164301e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 164401e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 164501e04c3fSmrg if (!ctx->Extensions.ARB_sample_locations) 164601e04c3fSmrg goto invalid_pname_enum; 164701e04c3fSmrg cannot_be_winsys_fbo = false; 164801e04c3fSmrg break; 164901e04c3fSmrg case GL_FRAMEBUFFER_FLIP_Y_MESA: 165001e04c3fSmrg if (!ctx->Extensions.MESA_framebuffer_flip_y) { 165101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 165201e04c3fSmrg return false; 165301e04c3fSmrg } 165401e04c3fSmrg break; 165501e04c3fSmrg default: 165601e04c3fSmrg goto invalid_pname_enum; 165701e04c3fSmrg } 165801e04c3fSmrg 165901e04c3fSmrg if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) { 166001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 166101e04c3fSmrg "%s(invalid pname=0x%x for default framebuffer)", func, pname); 166201e04c3fSmrg return false; 166301e04c3fSmrg } 166401e04c3fSmrg 166501e04c3fSmrg return true; 166601e04c3fSmrg 166701e04c3fSmrginvalid_pname_enum: 166801e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); 166901e04c3fSmrg return false; 167001e04c3fSmrg} 167101e04c3fSmrg 167201e04c3fSmrgstatic void 167301e04c3fSmrgget_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb, 167401e04c3fSmrg GLenum pname, GLint *params, const char *func) 167501e04c3fSmrg{ 167601e04c3fSmrg if (!validate_get_framebuffer_parameteriv_pname(ctx, fb, pname, func)) 167701e04c3fSmrg return; 167801e04c3fSmrg 167901e04c3fSmrg switch (pname) { 168001e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_WIDTH: 168101e04c3fSmrg *params = fb->DefaultGeometry.Width; 168201e04c3fSmrg break; 168301e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_HEIGHT: 168401e04c3fSmrg *params = fb->DefaultGeometry.Height; 168501e04c3fSmrg break; 168601e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_LAYERS: 168701e04c3fSmrg *params = fb->DefaultGeometry.Layers; 168801e04c3fSmrg break; 168901e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_SAMPLES: 169001e04c3fSmrg *params = fb->DefaultGeometry.NumSamples; 169101e04c3fSmrg break; 169201e04c3fSmrg case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: 169301e04c3fSmrg *params = fb->DefaultGeometry.FixedSampleLocations; 169401e04c3fSmrg break; 169501e04c3fSmrg case GL_DOUBLEBUFFER: 169601e04c3fSmrg *params = fb->Visual.doubleBufferMode; 169701e04c3fSmrg break; 169801e04c3fSmrg case GL_IMPLEMENTATION_COLOR_READ_FORMAT: 169901e04c3fSmrg *params = _mesa_get_color_read_format(ctx, fb, func); 170001e04c3fSmrg break; 170101e04c3fSmrg case GL_IMPLEMENTATION_COLOR_READ_TYPE: 170201e04c3fSmrg *params = _mesa_get_color_read_type(ctx, fb, func); 170301e04c3fSmrg break; 170401e04c3fSmrg case GL_SAMPLES: 170501e04c3fSmrg *params = _mesa_geometric_samples(fb); 170601e04c3fSmrg break; 170701e04c3fSmrg case GL_SAMPLE_BUFFERS: 170801e04c3fSmrg *params = _mesa_geometric_samples(fb) > 0; 170901e04c3fSmrg break; 171001e04c3fSmrg case GL_STEREO: 171101e04c3fSmrg *params = fb->Visual.stereoMode; 171201e04c3fSmrg break; 171301e04c3fSmrg case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB: 171401e04c3fSmrg *params = fb->ProgrammableSampleLocations; 171501e04c3fSmrg break; 171601e04c3fSmrg case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB: 171701e04c3fSmrg *params = fb->SampleLocationPixelGrid; 171801e04c3fSmrg break; 171901e04c3fSmrg case GL_FRAMEBUFFER_FLIP_Y_MESA: 172001e04c3fSmrg *params = fb->FlipY; 172101e04c3fSmrg break; 172201e04c3fSmrg } 172301e04c3fSmrg} 172401e04c3fSmrg 172501e04c3fSmrgvoid GLAPIENTRY 172601e04c3fSmrg_mesa_GetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params) 172701e04c3fSmrg{ 172801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 172901e04c3fSmrg struct gl_framebuffer *fb; 173001e04c3fSmrg 173101e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments && 173201e04c3fSmrg !ctx->Extensions.ARB_sample_locations) { 173301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 173401e04c3fSmrg "glGetFramebufferParameteriv not supported " 173501e04c3fSmrg "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations" 173601e04c3fSmrg " is available)"); 173701e04c3fSmrg return; 173801e04c3fSmrg } 173901e04c3fSmrg 174001e04c3fSmrg fb = get_framebuffer_target(ctx, target); 174101e04c3fSmrg if (!fb) { 174201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 174301e04c3fSmrg "glGetFramebufferParameteriv(target=0x%x)", target); 174401e04c3fSmrg return; 174501e04c3fSmrg } 174601e04c3fSmrg 174701e04c3fSmrg get_framebuffer_parameteriv(ctx, fb, pname, params, 174801e04c3fSmrg "glGetFramebufferParameteriv"); 174901e04c3fSmrg} 175001e04c3fSmrg 175101e04c3fSmrg 175201e04c3fSmrg/** 175301e04c3fSmrg * Remove the specified renderbuffer or texture from any attachment point in 175401e04c3fSmrg * the framebuffer. 175501e04c3fSmrg * 175601e04c3fSmrg * \returns 175701e04c3fSmrg * \c true if the renderbuffer was detached from an attachment point. \c 175801e04c3fSmrg * false otherwise. 175901e04c3fSmrg */ 176001e04c3fSmrgbool 176101e04c3fSmrg_mesa_detach_renderbuffer(struct gl_context *ctx, 176201e04c3fSmrg struct gl_framebuffer *fb, 176301e04c3fSmrg const void *att) 176401e04c3fSmrg{ 176501e04c3fSmrg unsigned i; 176601e04c3fSmrg bool progress = false; 176701e04c3fSmrg 176801e04c3fSmrg for (i = 0; i < BUFFER_COUNT; i++) { 176901e04c3fSmrg if (fb->Attachment[i].Texture == att 177001e04c3fSmrg || fb->Attachment[i].Renderbuffer == att) { 177101e04c3fSmrg remove_attachment(ctx, &fb->Attachment[i]); 177201e04c3fSmrg progress = true; 177301e04c3fSmrg } 177401e04c3fSmrg } 177501e04c3fSmrg 177601e04c3fSmrg /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer 177701e04c3fSmrg * Completeness," of the OpenGL 3.1 spec says: 177801e04c3fSmrg * 177901e04c3fSmrg * "Performing any of the following actions may change whether the 178001e04c3fSmrg * framebuffer is considered complete or incomplete: 178101e04c3fSmrg * 178201e04c3fSmrg * ... 178301e04c3fSmrg * 178401e04c3fSmrg * - Deleting, with DeleteTextures or DeleteRenderbuffers, an object 178501e04c3fSmrg * containing an image that is attached to a framebuffer object 178601e04c3fSmrg * that is bound to the framebuffer." 178701e04c3fSmrg */ 178801e04c3fSmrg if (progress) 178901e04c3fSmrg invalidate_framebuffer(fb); 179001e04c3fSmrg 179101e04c3fSmrg return progress; 179201e04c3fSmrg} 179301e04c3fSmrg 179401e04c3fSmrg 179501e04c3fSmrgvoid GLAPIENTRY 179601e04c3fSmrg_mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) 179701e04c3fSmrg{ 179801e04c3fSmrg GLint i; 179901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 180001e04c3fSmrg 180101e04c3fSmrg if (n < 0) { 180201e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteRenderbuffers(n < 0)"); 180301e04c3fSmrg return; 180401e04c3fSmrg } 180501e04c3fSmrg 180601e04c3fSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 180701e04c3fSmrg 180801e04c3fSmrg for (i = 0; i < n; i++) { 180901e04c3fSmrg if (renderbuffers[i] > 0) { 181001e04c3fSmrg struct gl_renderbuffer *rb; 181101e04c3fSmrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); 181201e04c3fSmrg if (rb) { 181301e04c3fSmrg /* check if deleting currently bound renderbuffer object */ 181401e04c3fSmrg if (rb == ctx->CurrentRenderbuffer) { 181501e04c3fSmrg /* bind default */ 181601e04c3fSmrg assert(rb->RefCount >= 2); 181701e04c3fSmrg _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0); 181801e04c3fSmrg } 181901e04c3fSmrg 182001e04c3fSmrg /* Section 4.4.2 (Attaching Images to Framebuffer Objects), 182101e04c3fSmrg * subsection "Attaching Renderbuffer Images to a Framebuffer," 182201e04c3fSmrg * of the OpenGL 3.1 spec says: 182301e04c3fSmrg * 182401e04c3fSmrg * "If a renderbuffer object is deleted while its image is 182501e04c3fSmrg * attached to one or more attachment points in the currently 182601e04c3fSmrg * bound framebuffer, then it is as if FramebufferRenderbuffer 182701e04c3fSmrg * had been called, with a renderbuffer of 0, for each 182801e04c3fSmrg * attachment point to which this image was attached in the 182901e04c3fSmrg * currently bound framebuffer. In other words, this 183001e04c3fSmrg * renderbuffer image is first detached from all attachment 183101e04c3fSmrg * points in the currently bound framebuffer. Note that the 183201e04c3fSmrg * renderbuffer image is specifically not detached from any 183301e04c3fSmrg * non-bound framebuffers. Detaching the image from any 183401e04c3fSmrg * non-bound framebuffers is the responsibility of the 1835af69d88dSmrg * application. 1836af69d88dSmrg */ 1837af69d88dSmrg if (_mesa_is_user_fbo(ctx->DrawBuffer)) { 1838af69d88dSmrg _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb); 18394a49301eSmrg } 1840af69d88dSmrg if (_mesa_is_user_fbo(ctx->ReadBuffer) 18413464ebd5Sriastradh && ctx->ReadBuffer != ctx->DrawBuffer) { 1842af69d88dSmrg _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb); 18434a49301eSmrg } 18444a49301eSmrg 184501e04c3fSmrg /* Remove from hash table immediately, to free the ID. 18467117f1b4Smrg * But the object will not be freed until it's no longer 18477117f1b4Smrg * referenced anywhere else. 18487117f1b4Smrg */ 184901e04c3fSmrg _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); 18507117f1b4Smrg 18517117f1b4Smrg if (rb != &DummyRenderbuffer) { 18527117f1b4Smrg /* no longer referenced by hash table */ 18537117f1b4Smrg _mesa_reference_renderbuffer(&rb, NULL); 185401e04c3fSmrg } 185501e04c3fSmrg } 18567117f1b4Smrg } 18577117f1b4Smrg } 18587117f1b4Smrg} 18597117f1b4Smrg 186001e04c3fSmrgstatic void 186101e04c3fSmrgcreate_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers, 186201e04c3fSmrg bool dsa) 18637117f1b4Smrg{ 186401e04c3fSmrg const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers"; 18657117f1b4Smrg GLuint first; 18667117f1b4Smrg GLint i; 18677117f1b4Smrg 18687117f1b4Smrg if (!renderbuffers) 18697117f1b4Smrg return; 18707117f1b4Smrg 187101e04c3fSmrg _mesa_HashLockMutex(ctx->Shared->RenderBuffers); 187201e04c3fSmrg 18737117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); 18747117f1b4Smrg 18757117f1b4Smrg for (i = 0; i < n; i++) { 18767117f1b4Smrg GLuint name = first + i; 18777117f1b4Smrg renderbuffers[i] = name; 187801e04c3fSmrg 187901e04c3fSmrg if (dsa) { 188001e04c3fSmrg allocate_renderbuffer_locked(ctx, name, func); 188101e04c3fSmrg } else { 188201e04c3fSmrg /* insert a dummy renderbuffer into the hash table */ 188301e04c3fSmrg _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, name, 188401e04c3fSmrg &DummyRenderbuffer); 188501e04c3fSmrg } 188601e04c3fSmrg } 188701e04c3fSmrg 188801e04c3fSmrg _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers); 188901e04c3fSmrg} 189001e04c3fSmrg 189101e04c3fSmrg 189201e04c3fSmrgstatic void 189301e04c3fSmrgcreate_render_buffers_err(struct gl_context *ctx, GLsizei n, 189401e04c3fSmrg GLuint *renderbuffers, bool dsa) 189501e04c3fSmrg{ 189601e04c3fSmrg const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers"; 189701e04c3fSmrg 189801e04c3fSmrg if (n < 0) { 189901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", func); 190001e04c3fSmrg return; 19017117f1b4Smrg } 190201e04c3fSmrg 190301e04c3fSmrg create_render_buffers(ctx, n, renderbuffers, dsa); 190401e04c3fSmrg} 190501e04c3fSmrg 190601e04c3fSmrg 190701e04c3fSmrgvoid GLAPIENTRY 190801e04c3fSmrg_mesa_GenRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers) 190901e04c3fSmrg{ 191001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 191101e04c3fSmrg create_render_buffers(ctx, n, renderbuffers, false); 191201e04c3fSmrg} 191301e04c3fSmrg 191401e04c3fSmrg 191501e04c3fSmrgvoid GLAPIENTRY 191601e04c3fSmrg_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers) 191701e04c3fSmrg{ 191801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 191901e04c3fSmrg create_render_buffers_err(ctx, n, renderbuffers, false); 192001e04c3fSmrg} 192101e04c3fSmrg 192201e04c3fSmrg 192301e04c3fSmrgvoid GLAPIENTRY 192401e04c3fSmrg_mesa_CreateRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers) 192501e04c3fSmrg{ 192601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 192701e04c3fSmrg create_render_buffers(ctx, n, renderbuffers, true); 192801e04c3fSmrg} 192901e04c3fSmrg 193001e04c3fSmrg 193101e04c3fSmrgvoid GLAPIENTRY 193201e04c3fSmrg_mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers) 193301e04c3fSmrg{ 193401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 193501e04c3fSmrg create_render_buffers_err(ctx, n, renderbuffers, true); 19367117f1b4Smrg} 19377117f1b4Smrg 19387117f1b4Smrg 19397117f1b4Smrg/** 19407117f1b4Smrg * Given an internal format token for a render buffer, return the 19413464ebd5Sriastradh * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, 19423464ebd5Sriastradh * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE, 19433464ebd5Sriastradh * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc). 19447117f1b4Smrg * 19453464ebd5Sriastradh * This is similar to _mesa_base_tex_format() but the set of valid 19463464ebd5Sriastradh * internal formats is different. 1947cdc920a0Smrg * 19483464ebd5Sriastradh * Note that even if a format is determined to be legal here, validation 19493464ebd5Sriastradh * of the FBO may fail if the format is not supported by the driver/GPU. 19503464ebd5Sriastradh * 19513464ebd5Sriastradh * \param internalFormat as passed to glRenderbufferStorage() 19523464ebd5Sriastradh * \return the base internal format, or 0 if internalFormat is illegal 19537117f1b4Smrg */ 19547117f1b4SmrgGLenum 195501e04c3fSmrg_mesa_base_fbo_format(const struct gl_context *ctx, GLenum internalFormat) 19567117f1b4Smrg{ 19573464ebd5Sriastradh /* 19583464ebd5Sriastradh * Notes: some formats such as alpha, luminance, etc. were added 19593464ebd5Sriastradh * with GL_ARB_framebuffer_object. 19603464ebd5Sriastradh */ 19617117f1b4Smrg switch (internalFormat) { 19623464ebd5Sriastradh case GL_ALPHA: 19633464ebd5Sriastradh case GL_ALPHA4: 19643464ebd5Sriastradh case GL_ALPHA8: 19653464ebd5Sriastradh case GL_ALPHA12: 19663464ebd5Sriastradh case GL_ALPHA16: 1967af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 1968af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_ALPHA : 0; 19693464ebd5Sriastradh case GL_LUMINANCE: 19703464ebd5Sriastradh case GL_LUMINANCE4: 19713464ebd5Sriastradh case GL_LUMINANCE8: 19723464ebd5Sriastradh case GL_LUMINANCE12: 19733464ebd5Sriastradh case GL_LUMINANCE16: 1974af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 1975af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE : 0; 19763464ebd5Sriastradh case GL_LUMINANCE_ALPHA: 19773464ebd5Sriastradh case GL_LUMINANCE4_ALPHA4: 19783464ebd5Sriastradh case GL_LUMINANCE6_ALPHA2: 19793464ebd5Sriastradh case GL_LUMINANCE8_ALPHA8: 19803464ebd5Sriastradh case GL_LUMINANCE12_ALPHA4: 19813464ebd5Sriastradh case GL_LUMINANCE12_ALPHA12: 19823464ebd5Sriastradh case GL_LUMINANCE16_ALPHA16: 1983af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 1984af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE_ALPHA : 0; 19853464ebd5Sriastradh case GL_INTENSITY: 19863464ebd5Sriastradh case GL_INTENSITY4: 19873464ebd5Sriastradh case GL_INTENSITY8: 19883464ebd5Sriastradh case GL_INTENSITY12: 19893464ebd5Sriastradh case GL_INTENSITY16: 1990af69d88dSmrg return (ctx->API == API_OPENGL_COMPAT && 1991af69d88dSmrg ctx->Extensions.ARB_framebuffer_object) ? GL_INTENSITY : 0; 1992af69d88dSmrg case GL_RGB8: 1993af69d88dSmrg return GL_RGB; 19947117f1b4Smrg case GL_RGB: 19957117f1b4Smrg case GL_R3_G3_B2: 19967117f1b4Smrg case GL_RGB4: 19977117f1b4Smrg case GL_RGB5: 19987117f1b4Smrg case GL_RGB10: 19997117f1b4Smrg case GL_RGB12: 20007117f1b4Smrg case GL_RGB16: 2001af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; 20023464ebd5Sriastradh case GL_SRGB8_EXT: 2003af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; 20047117f1b4Smrg case GL_RGBA4: 20057117f1b4Smrg case GL_RGB5_A1: 20067117f1b4Smrg case GL_RGBA8: 2007af69d88dSmrg return GL_RGBA; 2008af69d88dSmrg case GL_RGBA: 2009af69d88dSmrg case GL_RGBA2: 20107117f1b4Smrg case GL_RGBA12: 2011af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0; 201201e04c3fSmrg case GL_RGBA16: 201301e04c3fSmrg return _mesa_is_desktop_gl(ctx) || _mesa_has_EXT_texture_norm16(ctx) 201401e04c3fSmrg ? GL_RGBA : 0; 2015af69d88dSmrg case GL_RGB10_A2: 20163464ebd5Sriastradh case GL_SRGB8_ALPHA8_EXT: 2017af69d88dSmrg return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0; 20187117f1b4Smrg case GL_STENCIL_INDEX: 20197117f1b4Smrg case GL_STENCIL_INDEX1_EXT: 20207117f1b4Smrg case GL_STENCIL_INDEX4_EXT: 20217117f1b4Smrg case GL_STENCIL_INDEX16_EXT: 2022af69d88dSmrg /* There are extensions for GL_STENCIL_INDEX1 and GL_STENCIL_INDEX4 in 2023af69d88dSmrg * OpenGL ES, but Mesa does not currently support them. 2024af69d88dSmrg */ 2025af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_STENCIL_INDEX : 0; 2026af69d88dSmrg case GL_STENCIL_INDEX8_EXT: 20277117f1b4Smrg return GL_STENCIL_INDEX; 20287117f1b4Smrg case GL_DEPTH_COMPONENT: 2029af69d88dSmrg case GL_DEPTH_COMPONENT32: 2030af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_COMPONENT : 0; 20317117f1b4Smrg case GL_DEPTH_COMPONENT16: 20327117f1b4Smrg case GL_DEPTH_COMPONENT24: 20337117f1b4Smrg return GL_DEPTH_COMPONENT; 2034af69d88dSmrg case GL_DEPTH_STENCIL: 2035af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_STENCIL : 0; 2036af69d88dSmrg case GL_DEPTH24_STENCIL8: 2037af69d88dSmrg return GL_DEPTH_STENCIL; 2038af69d88dSmrg case GL_DEPTH_COMPONENT32F: 2039af69d88dSmrg return ctx->Version >= 30 2040af69d88dSmrg || (ctx->API == API_OPENGL_COMPAT && 2041af69d88dSmrg ctx->Extensions.ARB_depth_buffer_float) 2042af69d88dSmrg ? GL_DEPTH_COMPONENT : 0; 2043af69d88dSmrg case GL_DEPTH32F_STENCIL8: 2044af69d88dSmrg return ctx->Version >= 30 2045af69d88dSmrg || (ctx->API == API_OPENGL_COMPAT && 2046af69d88dSmrg ctx->Extensions.ARB_depth_buffer_float) 2047af69d88dSmrg ? GL_DEPTH_STENCIL : 0; 20483464ebd5Sriastradh case GL_RED: 204901e04c3fSmrg return _mesa_has_ARB_texture_rg(ctx) ? GL_RED : 0; 20503464ebd5Sriastradh case GL_R16: 205101e04c3fSmrg return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx) 2052af69d88dSmrg ? GL_RED : 0; 2053af69d88dSmrg case GL_R8: 2054af69d88dSmrg return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg 2055af69d88dSmrg ? GL_RED : 0; 20563464ebd5Sriastradh case GL_RG: 205701e04c3fSmrg return _mesa_has_ARB_texture_rg(ctx) ? GL_RG : 0; 20583464ebd5Sriastradh case GL_RG16: 205901e04c3fSmrg return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx) 2060af69d88dSmrg ? GL_RG : 0; 2061af69d88dSmrg case GL_RG8: 2062af69d88dSmrg return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg 2063af69d88dSmrg ? GL_RG : 0; 20643464ebd5Sriastradh /* signed normalized texture formats */ 20653464ebd5Sriastradh case GL_R8_SNORM: 206601e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx) 206701e04c3fSmrg ? GL_RED : 0; 206801e04c3fSmrg case GL_RED_SNORM: 206901e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) ? GL_RED : 0; 20703464ebd5Sriastradh case GL_R16_SNORM: 207101e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || 207201e04c3fSmrg (_mesa_has_EXT_render_snorm(ctx) && 207301e04c3fSmrg _mesa_has_EXT_texture_norm16(ctx)) 2074af69d88dSmrg ? GL_RED : 0; 20753464ebd5Sriastradh case GL_RG8_SNORM: 207601e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx) 207701e04c3fSmrg ? GL_RG : 0; 207801e04c3fSmrg case GL_RG_SNORM: 207901e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) ? GL_RG : 0; 20803464ebd5Sriastradh case GL_RG16_SNORM: 208101e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || 208201e04c3fSmrg (_mesa_has_EXT_render_snorm(ctx) && 208301e04c3fSmrg _mesa_has_EXT_texture_norm16(ctx)) 2084af69d88dSmrg ? GL_RG : 0; 20853464ebd5Sriastradh case GL_RGB_SNORM: 20863464ebd5Sriastradh case GL_RGB8_SNORM: 20873464ebd5Sriastradh case GL_RGB16_SNORM: 2088af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 2089af69d88dSmrg ? GL_RGB : 0; 20903464ebd5Sriastradh case GL_RGBA8_SNORM: 209101e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx) 209201e04c3fSmrg ? GL_RGBA : 0; 209301e04c3fSmrg case GL_RGBA_SNORM: 209401e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) ? GL_RGBA : 0; 20953464ebd5Sriastradh case GL_RGBA16_SNORM: 209601e04c3fSmrg return _mesa_has_EXT_texture_snorm(ctx) || 209701e04c3fSmrg (_mesa_has_EXT_render_snorm(ctx) && 209801e04c3fSmrg _mesa_has_EXT_texture_norm16(ctx)) 2099af69d88dSmrg ? GL_RGBA : 0; 21003464ebd5Sriastradh case GL_ALPHA_SNORM: 21013464ebd5Sriastradh case GL_ALPHA8_SNORM: 21023464ebd5Sriastradh case GL_ALPHA16_SNORM: 2103af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2104af69d88dSmrg ctx->Extensions.EXT_texture_snorm && 21053464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; 21063464ebd5Sriastradh case GL_LUMINANCE_SNORM: 21073464ebd5Sriastradh case GL_LUMINANCE8_SNORM: 21083464ebd5Sriastradh case GL_LUMINANCE16_SNORM: 2109af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 2110af69d88dSmrg ? GL_LUMINANCE : 0; 21113464ebd5Sriastradh case GL_LUMINANCE_ALPHA_SNORM: 21123464ebd5Sriastradh case GL_LUMINANCE8_ALPHA8_SNORM: 21133464ebd5Sriastradh case GL_LUMINANCE16_ALPHA16_SNORM: 2114af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 2115af69d88dSmrg ? GL_LUMINANCE_ALPHA : 0; 21163464ebd5Sriastradh case GL_INTENSITY_SNORM: 21173464ebd5Sriastradh case GL_INTENSITY8_SNORM: 21183464ebd5Sriastradh case GL_INTENSITY16_SNORM: 2119af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm 2120af69d88dSmrg ? GL_INTENSITY : 0; 2121af69d88dSmrg 21223464ebd5Sriastradh case GL_R16F: 21233464ebd5Sriastradh case GL_R32F: 2124af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && 2125af69d88dSmrg ctx->Extensions.ARB_texture_rg && 2126af69d88dSmrg ctx->Extensions.ARB_texture_float) || 2127af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 2128af69d88dSmrg ? GL_RED : 0; 21293464ebd5Sriastradh case GL_RG16F: 21303464ebd5Sriastradh case GL_RG32F: 2131af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && 2132af69d88dSmrg ctx->Extensions.ARB_texture_rg && 2133af69d88dSmrg ctx->Extensions.ARB_texture_float) || 2134af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 2135af69d88dSmrg ? GL_RG : 0; 21363464ebd5Sriastradh case GL_RGB16F: 21373464ebd5Sriastradh case GL_RGB32F: 2138af69d88dSmrg return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float) 2139af69d88dSmrg ? GL_RGB : 0; 21403464ebd5Sriastradh case GL_RGBA16F: 21413464ebd5Sriastradh case GL_RGBA32F: 2142af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && 2143af69d88dSmrg ctx->Extensions.ARB_texture_float) || 2144af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 2145af69d88dSmrg ? GL_RGBA : 0; 214601e04c3fSmrg case GL_RGB9_E5: 214701e04c3fSmrg return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_shared_exponent) 214801e04c3fSmrg ? GL_RGB: 0; 21493464ebd5Sriastradh case GL_ALPHA16F_ARB: 21503464ebd5Sriastradh case GL_ALPHA32F_ARB: 2151af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2152af69d88dSmrg ctx->Extensions.ARB_texture_float && 21533464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; 21543464ebd5Sriastradh case GL_LUMINANCE16F_ARB: 21553464ebd5Sriastradh case GL_LUMINANCE32F_ARB: 2156af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2157af69d88dSmrg ctx->Extensions.ARB_texture_float && 21583464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; 21593464ebd5Sriastradh case GL_LUMINANCE_ALPHA16F_ARB: 21603464ebd5Sriastradh case GL_LUMINANCE_ALPHA32F_ARB: 2161af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2162af69d88dSmrg ctx->Extensions.ARB_texture_float && 21633464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; 21643464ebd5Sriastradh case GL_INTENSITY16F_ARB: 21653464ebd5Sriastradh case GL_INTENSITY32F_ARB: 2166af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2167af69d88dSmrg ctx->Extensions.ARB_texture_float && 21683464ebd5Sriastradh ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; 21693464ebd5Sriastradh case GL_R11F_G11F_B10F: 2170af69d88dSmrg return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) || 2171af69d88dSmrg _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) 2172af69d88dSmrg ? GL_RGB : 0; 2173af69d88dSmrg 2174af69d88dSmrg case GL_RGBA8UI_EXT: 2175af69d88dSmrg case GL_RGBA16UI_EXT: 2176af69d88dSmrg case GL_RGBA32UI_EXT: 2177af69d88dSmrg case GL_RGBA8I_EXT: 2178af69d88dSmrg case GL_RGBA16I_EXT: 2179af69d88dSmrg case GL_RGBA32I_EXT: 2180af69d88dSmrg return ctx->Version >= 30 2181af69d88dSmrg || (_mesa_is_desktop_gl(ctx) && 2182af69d88dSmrg ctx->Extensions.EXT_texture_integer) ? GL_RGBA : 0; 2183af69d88dSmrg 2184af69d88dSmrg case GL_RGB8UI_EXT: 2185af69d88dSmrg case GL_RGB16UI_EXT: 2186af69d88dSmrg case GL_RGB32UI_EXT: 2187af69d88dSmrg case GL_RGB8I_EXT: 2188af69d88dSmrg case GL_RGB16I_EXT: 2189af69d88dSmrg case GL_RGB32I_EXT: 2190af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_integer 2191af69d88dSmrg ? GL_RGB : 0; 2192af69d88dSmrg case GL_R8UI: 2193af69d88dSmrg case GL_R8I: 2194af69d88dSmrg case GL_R16UI: 2195af69d88dSmrg case GL_R16I: 2196af69d88dSmrg case GL_R32UI: 2197af69d88dSmrg case GL_R32I: 2198af69d88dSmrg return ctx->Version >= 30 2199af69d88dSmrg || (_mesa_is_desktop_gl(ctx) && 2200af69d88dSmrg ctx->Extensions.ARB_texture_rg && 2201af69d88dSmrg ctx->Extensions.EXT_texture_integer) ? GL_RED : 0; 2202af69d88dSmrg 2203af69d88dSmrg case GL_RG8UI: 2204af69d88dSmrg case GL_RG8I: 2205af69d88dSmrg case GL_RG16UI: 2206af69d88dSmrg case GL_RG16I: 2207af69d88dSmrg case GL_RG32UI: 2208af69d88dSmrg case GL_RG32I: 2209af69d88dSmrg return ctx->Version >= 30 2210af69d88dSmrg || (_mesa_is_desktop_gl(ctx) && 2211af69d88dSmrg ctx->Extensions.ARB_texture_rg && 2212af69d88dSmrg ctx->Extensions.EXT_texture_integer) ? GL_RG : 0; 2213af69d88dSmrg 2214af69d88dSmrg case GL_INTENSITY8I_EXT: 2215af69d88dSmrg case GL_INTENSITY8UI_EXT: 2216af69d88dSmrg case GL_INTENSITY16I_EXT: 2217af69d88dSmrg case GL_INTENSITY16UI_EXT: 2218af69d88dSmrg case GL_INTENSITY32I_EXT: 2219af69d88dSmrg case GL_INTENSITY32UI_EXT: 2220af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2221af69d88dSmrg ctx->Extensions.EXT_texture_integer && 2222af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; 2223af69d88dSmrg 2224af69d88dSmrg case GL_LUMINANCE8I_EXT: 2225af69d88dSmrg case GL_LUMINANCE8UI_EXT: 2226af69d88dSmrg case GL_LUMINANCE16I_EXT: 2227af69d88dSmrg case GL_LUMINANCE16UI_EXT: 2228af69d88dSmrg case GL_LUMINANCE32I_EXT: 2229af69d88dSmrg case GL_LUMINANCE32UI_EXT: 2230af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2231af69d88dSmrg ctx->Extensions.EXT_texture_integer && 2232af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; 2233af69d88dSmrg 2234af69d88dSmrg case GL_LUMINANCE_ALPHA8I_EXT: 2235af69d88dSmrg case GL_LUMINANCE_ALPHA8UI_EXT: 2236af69d88dSmrg case GL_LUMINANCE_ALPHA16I_EXT: 2237af69d88dSmrg case GL_LUMINANCE_ALPHA16UI_EXT: 2238af69d88dSmrg case GL_LUMINANCE_ALPHA32I_EXT: 2239af69d88dSmrg case GL_LUMINANCE_ALPHA32UI_EXT: 2240af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2241af69d88dSmrg ctx->Extensions.EXT_texture_integer && 2242af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; 2243af69d88dSmrg 2244af69d88dSmrg case GL_ALPHA8I_EXT: 2245af69d88dSmrg case GL_ALPHA8UI_EXT: 2246af69d88dSmrg case GL_ALPHA16I_EXT: 2247af69d88dSmrg case GL_ALPHA16UI_EXT: 2248af69d88dSmrg case GL_ALPHA32I_EXT: 2249af69d88dSmrg case GL_ALPHA32UI_EXT: 2250af69d88dSmrg return ctx->API == API_OPENGL_COMPAT && 2251af69d88dSmrg ctx->Extensions.EXT_texture_integer && 2252af69d88dSmrg ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; 2253af69d88dSmrg 2254af69d88dSmrg case GL_RGB10_A2UI: 2255af69d88dSmrg return (_mesa_is_desktop_gl(ctx) && 2256af69d88dSmrg ctx->Extensions.ARB_texture_rgb10_a2ui) 2257af69d88dSmrg || _mesa_is_gles3(ctx) ? GL_RGBA : 0; 2258af69d88dSmrg 2259af69d88dSmrg case GL_RGB565: 2260af69d88dSmrg return _mesa_is_gles(ctx) || ctx->Extensions.ARB_ES2_compatibility 2261af69d88dSmrg ? GL_RGB : 0; 2262af69d88dSmrg default: 2263af69d88dSmrg return 0; 2264af69d88dSmrg } 22657117f1b4Smrg} 22667117f1b4Smrg 22677117f1b4Smrg 22683464ebd5Sriastradh/** 22693464ebd5Sriastradh * Invalidate a renderbuffer attachment. Called from _mesa_HashWalk(). 22703464ebd5Sriastradh */ 22713464ebd5Sriastradhstatic void 22723464ebd5Sriastradhinvalidate_rb(GLuint key, void *data, void *userData) 22733464ebd5Sriastradh{ 22743464ebd5Sriastradh struct gl_framebuffer *fb = (struct gl_framebuffer *) data; 22753464ebd5Sriastradh struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData; 22763464ebd5Sriastradh 22773464ebd5Sriastradh /* If this is a user-created FBO */ 2278af69d88dSmrg if (_mesa_is_user_fbo(fb)) { 22793464ebd5Sriastradh GLuint i; 22803464ebd5Sriastradh for (i = 0; i < BUFFER_COUNT; i++) { 22813464ebd5Sriastradh struct gl_renderbuffer_attachment *att = fb->Attachment + i; 22823464ebd5Sriastradh if (att->Type == GL_RENDERBUFFER && 22833464ebd5Sriastradh att->Renderbuffer == rb) { 22843464ebd5Sriastradh /* Mark fb status as indeterminate to force re-validation */ 22853464ebd5Sriastradh fb->_Status = 0; 22863464ebd5Sriastradh return; 22873464ebd5Sriastradh } 22883464ebd5Sriastradh } 22893464ebd5Sriastradh } 22903464ebd5Sriastradh} 22913464ebd5Sriastradh 22923464ebd5Sriastradh 22934a49301eSmrg/** sentinal value, see below */ 22944a49301eSmrg#define NO_SAMPLES 1000 22954a49301eSmrg 229601e04c3fSmrgvoid 229701e04c3fSmrg_mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 229801e04c3fSmrg GLenum internalFormat, GLsizei width, 229901e04c3fSmrg GLsizei height, GLsizei samples, 230001e04c3fSmrg GLsizei storageSamples) 23017117f1b4Smrg{ 230201e04c3fSmrg const GLenum baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 230301e04c3fSmrg 230401e04c3fSmrg assert(baseFormat != 0); 230501e04c3fSmrg assert(width >= 0 && width <= (GLsizei) ctx->Const.MaxRenderbufferSize); 230601e04c3fSmrg assert(height >= 0 && height <= (GLsizei) ctx->Const.MaxRenderbufferSize); 230701e04c3fSmrg assert(samples != NO_SAMPLES); 230801e04c3fSmrg if (samples != 0) { 230901e04c3fSmrg assert(samples > 0); 231001e04c3fSmrg assert(_mesa_check_sample_count(ctx, GL_RENDERBUFFER, 231101e04c3fSmrg internalFormat, samples, 231201e04c3fSmrg storageSamples) == GL_NO_ERROR); 23137117f1b4Smrg } 23147117f1b4Smrg 231501e04c3fSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 23167117f1b4Smrg 231701e04c3fSmrg if (rb->InternalFormat == internalFormat && 231801e04c3fSmrg rb->Width == (GLuint) width && 231901e04c3fSmrg rb->Height == (GLuint) height && 232001e04c3fSmrg rb->NumSamples == samples && 232101e04c3fSmrg rb->NumStorageSamples == storageSamples) { 232201e04c3fSmrg /* no change in allocation needed */ 23237117f1b4Smrg return; 23247117f1b4Smrg } 23257117f1b4Smrg 23267117f1b4Smrg /* These MUST get set by the AllocStorage func */ 23274a49301eSmrg rb->Format = MESA_FORMAT_NONE; 23284a49301eSmrg rb->NumSamples = samples; 232901e04c3fSmrg rb->NumStorageSamples = storageSamples; 23307117f1b4Smrg 23317117f1b4Smrg /* Now allocate the storage */ 233201e04c3fSmrg assert(rb->AllocStorage); 23337117f1b4Smrg if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 23347117f1b4Smrg /* No error - check/set fields now */ 2335af69d88dSmrg /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */ 23367117f1b4Smrg assert(rb->Width == (GLuint) width); 23377117f1b4Smrg assert(rb->Height == (GLuint) height); 23387117f1b4Smrg rb->InternalFormat = internalFormat; 2339cdc920a0Smrg rb->_BaseFormat = baseFormat; 23404a49301eSmrg assert(rb->_BaseFormat != 0); 23417117f1b4Smrg } 23427117f1b4Smrg else { 23437117f1b4Smrg /* Probably ran out of memory - clear the fields */ 23447117f1b4Smrg rb->Width = 0; 23457117f1b4Smrg rb->Height = 0; 23464a49301eSmrg rb->Format = MESA_FORMAT_NONE; 23477117f1b4Smrg rb->InternalFormat = GL_NONE; 23487117f1b4Smrg rb->_BaseFormat = GL_NONE; 23494a49301eSmrg rb->NumSamples = 0; 235001e04c3fSmrg rb->NumStorageSamples = 0; 23517117f1b4Smrg } 23527117f1b4Smrg 23533464ebd5Sriastradh /* Invalidate the framebuffers the renderbuffer is attached in. */ 23543464ebd5Sriastradh if (rb->AttachedAnytime) { 23553464ebd5Sriastradh _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb); 23563464ebd5Sriastradh } 23577117f1b4Smrg} 23587117f1b4Smrg 235901e04c3fSmrg/** 236001e04c3fSmrg * Helper function used by renderbuffer_storage_direct() and 236101e04c3fSmrg * renderbuffer_storage_target(). 236201e04c3fSmrg * samples will be NO_SAMPLES if called by a non-multisample function. 236301e04c3fSmrg */ 236401e04c3fSmrgstatic void 236501e04c3fSmrgrenderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 236601e04c3fSmrg GLenum internalFormat, GLsizei width, 236701e04c3fSmrg GLsizei height, GLsizei samples, GLsizei storageSamples, 236801e04c3fSmrg const char *func) 236901e04c3fSmrg{ 237001e04c3fSmrg GLenum baseFormat; 237101e04c3fSmrg GLenum sample_count_error; 237201e04c3fSmrg 237301e04c3fSmrg baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 237401e04c3fSmrg if (baseFormat == 0) { 237501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)", 237601e04c3fSmrg func, _mesa_enum_to_string(internalFormat)); 237701e04c3fSmrg return; 237801e04c3fSmrg } 237901e04c3fSmrg 238001e04c3fSmrg if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { 238101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid width %d)", func, 238201e04c3fSmrg width); 238301e04c3fSmrg return; 238401e04c3fSmrg } 238501e04c3fSmrg 238601e04c3fSmrg if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { 238701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid height %d)", func, 238801e04c3fSmrg height); 238901e04c3fSmrg return; 239001e04c3fSmrg } 239101e04c3fSmrg 239201e04c3fSmrg if (samples == NO_SAMPLES) { 239301e04c3fSmrg /* NumSamples == 0 indicates non-multisampling */ 239401e04c3fSmrg samples = 0; 239501e04c3fSmrg storageSamples = 0; 239601e04c3fSmrg } 239701e04c3fSmrg else { 239801e04c3fSmrg /* check the sample count; 239901e04c3fSmrg * note: driver may choose to use more samples than what's requested 240001e04c3fSmrg */ 240101e04c3fSmrg sample_count_error = _mesa_check_sample_count(ctx, GL_RENDERBUFFER, 240201e04c3fSmrg internalFormat, samples, storageSamples); 240301e04c3fSmrg 240401e04c3fSmrg /* Section 2.5 (GL Errors) of OpenGL 3.0 specification, page 16: 240501e04c3fSmrg * 240601e04c3fSmrg * "If a negative number is provided where an argument of type sizei or 240701e04c3fSmrg * sizeiptr is specified, the error INVALID VALUE is generated." 240801e04c3fSmrg */ 240901e04c3fSmrg if (samples < 0 || storageSamples < 0) { 241001e04c3fSmrg sample_count_error = GL_INVALID_VALUE; 241101e04c3fSmrg } 241201e04c3fSmrg 241301e04c3fSmrg if (sample_count_error != GL_NO_ERROR) { 241401e04c3fSmrg _mesa_error(ctx, sample_count_error, 241501e04c3fSmrg "%s(samples=%d, storageSamples=%d)", func, samples, 241601e04c3fSmrg storageSamples); 241701e04c3fSmrg return; 241801e04c3fSmrg } 241901e04c3fSmrg } 242001e04c3fSmrg 242101e04c3fSmrg _mesa_renderbuffer_storage(ctx, rb, internalFormat, width, height, samples, 242201e04c3fSmrg storageSamples); 242301e04c3fSmrg} 242401e04c3fSmrg 242501e04c3fSmrg/** 242601e04c3fSmrg * Helper function used by _mesa_NamedRenderbufferStorage*(). 242701e04c3fSmrg * samples will be NO_SAMPLES if called by a non-multisample function. 242801e04c3fSmrg */ 242901e04c3fSmrgstatic void 243001e04c3fSmrgrenderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat, 243101e04c3fSmrg GLsizei width, GLsizei height, GLsizei samples, 243201e04c3fSmrg GLsizei storageSamples, const char *func) 243301e04c3fSmrg{ 243401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 243501e04c3fSmrg 243601e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 243701e04c3fSmrg if (samples == NO_SAMPLES) 243801e04c3fSmrg _mesa_debug(ctx, "%s(%u, %s, %d, %d)\n", 243901e04c3fSmrg func, renderbuffer, 244001e04c3fSmrg _mesa_enum_to_string(internalFormat), 244101e04c3fSmrg width, height); 244201e04c3fSmrg else 244301e04c3fSmrg _mesa_debug(ctx, "%s(%u, %s, %d, %d, %d)\n", 244401e04c3fSmrg func, renderbuffer, 244501e04c3fSmrg _mesa_enum_to_string(internalFormat), 244601e04c3fSmrg width, height, samples); 244701e04c3fSmrg } 244801e04c3fSmrg 244901e04c3fSmrg struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 245001e04c3fSmrg if (!rb || rb == &DummyRenderbuffer) { 245101e04c3fSmrg /* ID was reserved, but no real renderbuffer object made yet */ 245201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid renderbuffer %u)", 245301e04c3fSmrg func, renderbuffer); 245401e04c3fSmrg return; 245501e04c3fSmrg } 245601e04c3fSmrg 245701e04c3fSmrg renderbuffer_storage(ctx, rb, internalFormat, width, height, samples, 245801e04c3fSmrg storageSamples, func); 245901e04c3fSmrg} 246001e04c3fSmrg 246101e04c3fSmrg/** 246201e04c3fSmrg * Helper function used by _mesa_RenderbufferStorage() and 246301e04c3fSmrg * _mesa_RenderbufferStorageMultisample(). 246401e04c3fSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorage(). 246501e04c3fSmrg */ 246601e04c3fSmrgstatic void 246701e04c3fSmrgrenderbuffer_storage_target(GLenum target, GLenum internalFormat, 246801e04c3fSmrg GLsizei width, GLsizei height, GLsizei samples, 246901e04c3fSmrg GLsizei storageSamples, const char *func) 247001e04c3fSmrg{ 247101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 247201e04c3fSmrg 247301e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 247401e04c3fSmrg if (samples == NO_SAMPLES) 247501e04c3fSmrg _mesa_debug(ctx, "%s(%s, %s, %d, %d)\n", 247601e04c3fSmrg func, 247701e04c3fSmrg _mesa_enum_to_string(target), 247801e04c3fSmrg _mesa_enum_to_string(internalFormat), 247901e04c3fSmrg width, height); 248001e04c3fSmrg else 248101e04c3fSmrg _mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n", 248201e04c3fSmrg func, 248301e04c3fSmrg _mesa_enum_to_string(target), 248401e04c3fSmrg _mesa_enum_to_string(internalFormat), 248501e04c3fSmrg width, height, samples); 248601e04c3fSmrg } 248701e04c3fSmrg 248801e04c3fSmrg if (target != GL_RENDERBUFFER_EXT) { 248901e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 249001e04c3fSmrg return; 249101e04c3fSmrg } 249201e04c3fSmrg 249301e04c3fSmrg if (!ctx->CurrentRenderbuffer) { 249401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no renderbuffer bound)", 249501e04c3fSmrg func); 249601e04c3fSmrg return; 249701e04c3fSmrg } 249801e04c3fSmrg 249901e04c3fSmrg renderbuffer_storage(ctx, ctx->CurrentRenderbuffer, internalFormat, width, 250001e04c3fSmrg height, samples, storageSamples, func); 250101e04c3fSmrg} 250201e04c3fSmrg 25033464ebd5Sriastradh 2504cdc920a0Smrgvoid GLAPIENTRY 25053464ebd5Sriastradh_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) 2506cdc920a0Smrg{ 2507cdc920a0Smrg struct gl_renderbuffer *rb; 2508cdc920a0Smrg GET_CURRENT_CONTEXT(ctx); 2509cdc920a0Smrg 25103464ebd5Sriastradh if (!ctx->Extensions.OES_EGL_image) { 25113464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 25123464ebd5Sriastradh "glEGLImageTargetRenderbufferStorageOES(unsupported)"); 25133464ebd5Sriastradh return; 25143464ebd5Sriastradh } 25153464ebd5Sriastradh 2516cdc920a0Smrg if (target != GL_RENDERBUFFER) { 25173464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_ENUM, 25183464ebd5Sriastradh "EGLImageTargetRenderbufferStorageOES"); 2519cdc920a0Smrg return; 2520cdc920a0Smrg } 2521cdc920a0Smrg 2522cdc920a0Smrg rb = ctx->CurrentRenderbuffer; 2523cdc920a0Smrg if (!rb) { 25243464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 25253464ebd5Sriastradh "EGLImageTargetRenderbufferStorageOES"); 2526cdc920a0Smrg return; 2527cdc920a0Smrg } 2528cdc920a0Smrg 2529cdc920a0Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 2530cdc920a0Smrg 2531cdc920a0Smrg ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); 2532cdc920a0Smrg} 25337117f1b4Smrg 25343464ebd5Sriastradh 25354a49301eSmrg/** 2536af69d88dSmrg * Helper function for _mesa_GetRenderbufferParameteriv() and 2537af69d88dSmrg * _mesa_GetFramebufferAttachmentParameteriv() 25384a49301eSmrg * We have to be careful to respect the base format. For example, if a 25394a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the 25404a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE 25414a49301eSmrg * we need to return zero. 25424a49301eSmrg */ 25434a49301eSmrgstatic GLint 2544af69d88dSmrgget_component_bits(GLenum pname, GLenum baseFormat, mesa_format format) 25454a49301eSmrg{ 2546af69d88dSmrg if (_mesa_base_format_has_channel(baseFormat, pname)) 2547af69d88dSmrg return _mesa_get_format_bits(format, pname); 2548af69d88dSmrg else 25494a49301eSmrg return 0; 25504a49301eSmrg} 25514a49301eSmrg 25524a49301eSmrg 25534a49301eSmrg 25544a49301eSmrgvoid GLAPIENTRY 2555af69d88dSmrg_mesa_RenderbufferStorage(GLenum target, GLenum internalFormat, 25564a49301eSmrg GLsizei width, GLsizei height) 25574a49301eSmrg{ 25584a49301eSmrg /* GL_ARB_fbo says calling this function is equivalent to calling 25594a49301eSmrg * glRenderbufferStorageMultisample() with samples=0. We pass in 25604a49301eSmrg * a token value here just for error reporting purposes. 25614a49301eSmrg */ 256201e04c3fSmrg renderbuffer_storage_target(target, internalFormat, width, height, 256301e04c3fSmrg NO_SAMPLES, 0, "glRenderbufferStorage"); 25644a49301eSmrg} 25654a49301eSmrg 25664a49301eSmrg 25674a49301eSmrgvoid GLAPIENTRY 25684a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, 25694a49301eSmrg GLenum internalFormat, 25704a49301eSmrg GLsizei width, GLsizei height) 25714a49301eSmrg{ 257201e04c3fSmrg renderbuffer_storage_target(target, internalFormat, width, height, 257301e04c3fSmrg samples, samples, 257401e04c3fSmrg "glRenderbufferStorageMultisample"); 257501e04c3fSmrg} 257601e04c3fSmrg 257701e04c3fSmrg 257801e04c3fSmrgvoid GLAPIENTRY 257901e04c3fSmrg_mesa_RenderbufferStorageMultisampleAdvancedAMD( 258001e04c3fSmrg GLenum target, GLsizei samples, GLsizei storageSamples, 258101e04c3fSmrg GLenum internalFormat, GLsizei width, GLsizei height) 258201e04c3fSmrg{ 258301e04c3fSmrg renderbuffer_storage_target(target, internalFormat, width, height, 258401e04c3fSmrg samples, storageSamples, 258501e04c3fSmrg "glRenderbufferStorageMultisampleAdvancedAMD"); 25864a49301eSmrg} 25874a49301eSmrg 25884a49301eSmrg 25893464ebd5Sriastradh/** 25903464ebd5Sriastradh * OpenGL ES version of glRenderBufferStorage. 25913464ebd5Sriastradh */ 25923464ebd5Sriastradhvoid GLAPIENTRY 25933464ebd5Sriastradh_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 259401e04c3fSmrg GLsizei width, GLsizei height) 25953464ebd5Sriastradh{ 25963464ebd5Sriastradh switch (internalFormat) { 25973464ebd5Sriastradh case GL_RGB565: 25983464ebd5Sriastradh /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */ 25993464ebd5Sriastradh /* choose a closest format */ 26003464ebd5Sriastradh internalFormat = GL_RGB5; 26013464ebd5Sriastradh break; 26023464ebd5Sriastradh default: 26033464ebd5Sriastradh break; 26043464ebd5Sriastradh } 26053464ebd5Sriastradh 260601e04c3fSmrg renderbuffer_storage_target(target, internalFormat, width, height, 0, 0, 260701e04c3fSmrg "glRenderbufferStorageEXT"); 26083464ebd5Sriastradh} 26093464ebd5Sriastradh 261001e04c3fSmrgvoid GLAPIENTRY 261101e04c3fSmrg_mesa_NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, 261201e04c3fSmrg GLsizei width, GLsizei height) 261301e04c3fSmrg{ 261401e04c3fSmrg /* GL_ARB_fbo says calling this function is equivalent to calling 261501e04c3fSmrg * glRenderbufferStorageMultisample() with samples=0. We pass in 261601e04c3fSmrg * a token value here just for error reporting purposes. 261701e04c3fSmrg */ 261801e04c3fSmrg renderbuffer_storage_named(renderbuffer, internalformat, width, height, 261901e04c3fSmrg NO_SAMPLES, 0, "glNamedRenderbufferStorage"); 262001e04c3fSmrg} 26214a49301eSmrg 26227117f1b4Smrgvoid GLAPIENTRY 262301e04c3fSmrg_mesa_NamedRenderbufferStorageMultisample(GLuint renderbuffer, GLsizei samples, 262401e04c3fSmrg GLenum internalformat, 262501e04c3fSmrg GLsizei width, GLsizei height) 26267117f1b4Smrg{ 262701e04c3fSmrg renderbuffer_storage_named(renderbuffer, internalformat, width, height, 262801e04c3fSmrg samples, samples, 262901e04c3fSmrg "glNamedRenderbufferStorageMultisample"); 263001e04c3fSmrg} 26317117f1b4Smrg 26327117f1b4Smrg 263301e04c3fSmrgvoid GLAPIENTRY 263401e04c3fSmrg_mesa_NamedRenderbufferStorageMultisampleAdvancedAMD( 263501e04c3fSmrg GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, 263601e04c3fSmrg GLenum internalformat, GLsizei width, GLsizei height) 263701e04c3fSmrg{ 263801e04c3fSmrg renderbuffer_storage_named(renderbuffer, internalformat, width, height, 263901e04c3fSmrg samples, storageSamples, 264001e04c3fSmrg "glNamedRenderbufferStorageMultisampleAdvancedAMD"); 264101e04c3fSmrg} 264201e04c3fSmrg 26437117f1b4Smrg 264401e04c3fSmrgstatic void 264501e04c3fSmrgget_render_buffer_parameteriv(struct gl_context *ctx, 264601e04c3fSmrg struct gl_renderbuffer *rb, GLenum pname, 264701e04c3fSmrg GLint *params, const char *func) 264801e04c3fSmrg{ 26494a49301eSmrg /* No need to flush here since we're just quering state which is 26504a49301eSmrg * not effected by rendering. 26514a49301eSmrg */ 26527117f1b4Smrg 26537117f1b4Smrg switch (pname) { 26547117f1b4Smrg case GL_RENDERBUFFER_WIDTH_EXT: 26554a49301eSmrg *params = rb->Width; 26567117f1b4Smrg return; 26577117f1b4Smrg case GL_RENDERBUFFER_HEIGHT_EXT: 26584a49301eSmrg *params = rb->Height; 26597117f1b4Smrg return; 26607117f1b4Smrg case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 26614a49301eSmrg *params = rb->InternalFormat; 26627117f1b4Smrg return; 26637117f1b4Smrg case GL_RENDERBUFFER_RED_SIZE_EXT: 26647117f1b4Smrg case GL_RENDERBUFFER_GREEN_SIZE_EXT: 26657117f1b4Smrg case GL_RENDERBUFFER_BLUE_SIZE_EXT: 26667117f1b4Smrg case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 26677117f1b4Smrg case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 26687117f1b4Smrg case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 26694a49301eSmrg *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); 267001e04c3fSmrg return; 26714a49301eSmrg case GL_RENDERBUFFER_SAMPLES: 2672af69d88dSmrg if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object) 2673af69d88dSmrg || _mesa_is_gles3(ctx)) { 26744a49301eSmrg *params = rb->NumSamples; 267501e04c3fSmrg return; 26764a49301eSmrg } 267701e04c3fSmrg break; 267801e04c3fSmrg case GL_RENDERBUFFER_STORAGE_SAMPLES_AMD: 267901e04c3fSmrg if (ctx->Extensions.AMD_framebuffer_multisample_advanced) { 268001e04c3fSmrg *params = rb->NumStorageSamples; 268101e04c3fSmrg return; 268201e04c3fSmrg } 268301e04c3fSmrg break; 268401e04c3fSmrg } 268501e04c3fSmrg 268601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname=%s)", func, 268701e04c3fSmrg _mesa_enum_to_string(pname)); 268801e04c3fSmrg} 268901e04c3fSmrg 269001e04c3fSmrg 269101e04c3fSmrgvoid GLAPIENTRY 269201e04c3fSmrg_mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) 269301e04c3fSmrg{ 269401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 269501e04c3fSmrg 269601e04c3fSmrg if (target != GL_RENDERBUFFER_EXT) { 26977117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 26987117f1b4Smrg "glGetRenderbufferParameterivEXT(target)"); 26997117f1b4Smrg return; 27007117f1b4Smrg } 270101e04c3fSmrg 270201e04c3fSmrg if (!ctx->CurrentRenderbuffer) { 270301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetRenderbufferParameterivEXT" 270401e04c3fSmrg "(no renderbuffer bound)"); 270501e04c3fSmrg return; 270601e04c3fSmrg } 270701e04c3fSmrg 270801e04c3fSmrg get_render_buffer_parameteriv(ctx, ctx->CurrentRenderbuffer, pname, 270901e04c3fSmrg params, "glGetRenderbufferParameteriv"); 271001e04c3fSmrg} 271101e04c3fSmrg 271201e04c3fSmrg 271301e04c3fSmrgvoid GLAPIENTRY 271401e04c3fSmrg_mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, 271501e04c3fSmrg GLint *params) 271601e04c3fSmrg{ 271701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 271801e04c3fSmrg 271901e04c3fSmrg struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 272001e04c3fSmrg if (!rb || rb == &DummyRenderbuffer) { 272101e04c3fSmrg /* ID was reserved, but no real renderbuffer object made yet */ 272201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetNamedRenderbufferParameteriv" 272301e04c3fSmrg "(invalid renderbuffer %i)", renderbuffer); 272401e04c3fSmrg return; 272501e04c3fSmrg } 272601e04c3fSmrg 272701e04c3fSmrg get_render_buffer_parameteriv(ctx, rb, pname, params, 272801e04c3fSmrg "glGetNamedRenderbufferParameteriv"); 27297117f1b4Smrg} 27307117f1b4Smrg 27317117f1b4Smrg 27327117f1b4SmrgGLboolean GLAPIENTRY 2733af69d88dSmrg_mesa_IsFramebuffer(GLuint framebuffer) 27347117f1b4Smrg{ 27357117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 27367117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 27377117f1b4Smrg if (framebuffer) { 27387117f1b4Smrg struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); 27397117f1b4Smrg if (rb != NULL && rb != &DummyFramebuffer) 27407117f1b4Smrg return GL_TRUE; 27417117f1b4Smrg } 27427117f1b4Smrg return GL_FALSE; 27437117f1b4Smrg} 27447117f1b4Smrg 27457117f1b4Smrg 27464a49301eSmrg/** 27474a49301eSmrg * Check if any of the attachments of the given framebuffer are textures 27484a49301eSmrg * (render to texture). Call ctx->Driver.RenderTexture() for such 27494a49301eSmrg * attachments. 27504a49301eSmrg */ 27517117f1b4Smrgstatic void 27523464ebd5Sriastradhcheck_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) 27537117f1b4Smrg{ 27547117f1b4Smrg GLuint i; 275501e04c3fSmrg assert(ctx->Driver.RenderTexture); 27564a49301eSmrg 2757af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) 27584a49301eSmrg return; /* can't render to texture with winsys framebuffers */ 27594a49301eSmrg 27607117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 27617117f1b4Smrg struct gl_renderbuffer_attachment *att = fb->Attachment + i; 2762af69d88dSmrg if (att->Texture && att->Renderbuffer->TexImage 2763af69d88dSmrg && driver_RenderTexture_is_safe(att)) { 27647117f1b4Smrg ctx->Driver.RenderTexture(ctx, fb, att); 27657117f1b4Smrg } 27667117f1b4Smrg } 27677117f1b4Smrg} 27687117f1b4Smrg 27697117f1b4Smrg 27707117f1b4Smrg/** 27717117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures. 27727117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to 27737117f1b4Smrg * notify the device driver that the texture image may have changed. 27747117f1b4Smrg */ 27757117f1b4Smrgstatic void 27763464ebd5Sriastradhcheck_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) 27777117f1b4Smrg{ 2778af69d88dSmrg /* Skip if we know NeedsFinishRenderTexture won't be set. */ 2779af69d88dSmrg if (_mesa_is_winsys_fbo(fb) && !ctx->Driver.BindRenderbufferTexImage) 2780af69d88dSmrg return; 27814a49301eSmrg 27827117f1b4Smrg if (ctx->Driver.FinishRenderTexture) { 27837117f1b4Smrg GLuint i; 27847117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 27857117f1b4Smrg struct gl_renderbuffer_attachment *att = fb->Attachment + i; 2786af69d88dSmrg struct gl_renderbuffer *rb = att->Renderbuffer; 2787af69d88dSmrg if (rb && rb->NeedsFinishRenderTexture) { 2788af69d88dSmrg ctx->Driver.FinishRenderTexture(ctx, rb); 27897117f1b4Smrg } 27907117f1b4Smrg } 27917117f1b4Smrg } 27927117f1b4Smrg} 27937117f1b4Smrg 27947117f1b4Smrg 2795af69d88dSmrgstatic void 279601e04c3fSmrgbind_framebuffer(GLenum target, GLuint framebuffer) 27977117f1b4Smrg{ 27984a49301eSmrg struct gl_framebuffer *newDrawFb, *newReadFb; 27997117f1b4Smrg GLboolean bindReadBuf, bindDrawBuf; 28007117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 28017117f1b4Smrg 28027117f1b4Smrg switch (target) { 28037117f1b4Smrg case GL_DRAW_FRAMEBUFFER_EXT: 28047117f1b4Smrg bindDrawBuf = GL_TRUE; 28057117f1b4Smrg bindReadBuf = GL_FALSE; 28067117f1b4Smrg break; 28077117f1b4Smrg case GL_READ_FRAMEBUFFER_EXT: 28087117f1b4Smrg bindDrawBuf = GL_FALSE; 28097117f1b4Smrg bindReadBuf = GL_TRUE; 28107117f1b4Smrg break; 28117117f1b4Smrg case GL_FRAMEBUFFER_EXT: 28127117f1b4Smrg bindDrawBuf = GL_TRUE; 28137117f1b4Smrg bindReadBuf = GL_TRUE; 28147117f1b4Smrg break; 28157117f1b4Smrg default: 28167117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 28177117f1b4Smrg return; 28187117f1b4Smrg } 28197117f1b4Smrg 28207117f1b4Smrg if (framebuffer) { 28217117f1b4Smrg /* Binding a user-created framebuffer object */ 28224a49301eSmrg newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); 28234a49301eSmrg if (newDrawFb == &DummyFramebuffer) { 28247117f1b4Smrg /* ID was reserved, but no real framebuffer object made yet */ 28254a49301eSmrg newDrawFb = NULL; 28267117f1b4Smrg } 282701e04c3fSmrg else if (!newDrawFb && ctx->API == API_OPENGL_CORE) { 28284a49301eSmrg /* All FBO IDs must be Gen'd */ 282901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 283001e04c3fSmrg "glBindFramebuffer(non-gen name)"); 28314a49301eSmrg return; 28324a49301eSmrg } 28334a49301eSmrg 28344a49301eSmrg if (!newDrawFb) { 283501e04c3fSmrg /* create new framebuffer object */ 283601e04c3fSmrg newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 283701e04c3fSmrg if (!newDrawFb) { 283801e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 283901e04c3fSmrg return; 284001e04c3fSmrg } 28414a49301eSmrg _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb); 28427117f1b4Smrg } 28434a49301eSmrg newReadFb = newDrawFb; 28447117f1b4Smrg } 28457117f1b4Smrg else { 28467117f1b4Smrg /* Binding the window system framebuffer (which was originally set 28477117f1b4Smrg * with MakeCurrent). 28487117f1b4Smrg */ 28494a49301eSmrg newDrawFb = ctx->WinSysDrawBuffer; 28504a49301eSmrg newReadFb = ctx->WinSysReadBuffer; 28517117f1b4Smrg } 28527117f1b4Smrg 285301e04c3fSmrg _mesa_bind_framebuffers(ctx, 285401e04c3fSmrg bindDrawBuf ? newDrawFb : ctx->DrawBuffer, 285501e04c3fSmrg bindReadBuf ? newReadFb : ctx->ReadBuffer); 285601e04c3fSmrg} 28574a49301eSmrg 285801e04c3fSmrgvoid 285901e04c3fSmrg_mesa_bind_framebuffers(struct gl_context *ctx, 286001e04c3fSmrg struct gl_framebuffer *newDrawFb, 286101e04c3fSmrg struct gl_framebuffer *newReadFb) 286201e04c3fSmrg{ 286301e04c3fSmrg struct gl_framebuffer *const oldDrawFb = ctx->DrawBuffer; 286401e04c3fSmrg struct gl_framebuffer *const oldReadFb = ctx->ReadBuffer; 286501e04c3fSmrg const bool bindDrawBuf = oldDrawFb != newDrawFb; 286601e04c3fSmrg const bool bindReadBuf = oldReadFb != newReadFb; 28674a49301eSmrg 286801e04c3fSmrg assert(newDrawFb); 286901e04c3fSmrg assert(newDrawFb != &DummyFramebuffer); 28707117f1b4Smrg 28717117f1b4Smrg /* 28724a49301eSmrg * OK, now bind the new Draw/Read framebuffers, if they're changing. 28734a49301eSmrg * 28744a49301eSmrg * We also check if we're beginning and/or ending render-to-texture. 28754a49301eSmrg * When a framebuffer with texture attachments is unbound, call 28764a49301eSmrg * ctx->Driver.FinishRenderTexture(). 28774a49301eSmrg * When a framebuffer with texture attachments is bound, call 28784a49301eSmrg * ctx->Driver.RenderTexture(). 28794a49301eSmrg * 28804a49301eSmrg * Note that if the ReadBuffer has texture attachments we don't consider 28814a49301eSmrg * that a render-to-texture case. 28827117f1b4Smrg */ 28837117f1b4Smrg if (bindReadBuf) { 28844a49301eSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 28854a49301eSmrg 28864a49301eSmrg /* check if old readbuffer was render-to-texture */ 28874a49301eSmrg check_end_texture_render(ctx, oldReadFb); 28884a49301eSmrg 28894a49301eSmrg _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); 28907117f1b4Smrg } 28917117f1b4Smrg 28927117f1b4Smrg if (bindDrawBuf) { 28934a49301eSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 289401e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations; 28957117f1b4Smrg 2896af69d88dSmrg /* check if old framebuffer had any texture attachments */ 2897af69d88dSmrg if (oldDrawFb) 28984a49301eSmrg check_end_texture_render(ctx, oldDrawFb); 28994a49301eSmrg 29004a49301eSmrg /* check if newly bound framebuffer has any texture attachments */ 29014a49301eSmrg check_begin_texture_render(ctx, newDrawFb); 29024a49301eSmrg 29034a49301eSmrg _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); 29047117f1b4Smrg } 29057117f1b4Smrg 29064a49301eSmrg if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { 290701e04c3fSmrg /* The few classic drivers that actually hook this function really only 290801e04c3fSmrg * want to know if the draw framebuffer changed. 290901e04c3fSmrg */ 291001e04c3fSmrg ctx->Driver.BindFramebuffer(ctx, 291101e04c3fSmrg bindDrawBuf ? GL_FRAMEBUFFER : GL_READ_FRAMEBUFFER, 291201e04c3fSmrg newDrawFb, newReadFb); 29137117f1b4Smrg } 29147117f1b4Smrg} 29157117f1b4Smrg 2916af69d88dSmrgvoid GLAPIENTRY 2917af69d88dSmrg_mesa_BindFramebuffer(GLenum target, GLuint framebuffer) 2918af69d88dSmrg{ 2919af69d88dSmrg /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry 2920af69d88dSmrg * point, but they allow the use of user-generated names. 2921af69d88dSmrg */ 292201e04c3fSmrg bind_framebuffer(target, framebuffer); 2923af69d88dSmrg} 2924af69d88dSmrg 29257117f1b4Smrg 29267117f1b4Smrgvoid GLAPIENTRY 2927af69d88dSmrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 2928af69d88dSmrg{ 292901e04c3fSmrg bind_framebuffer(target, framebuffer); 2930af69d88dSmrg} 2931af69d88dSmrg 2932af69d88dSmrg 2933af69d88dSmrgvoid GLAPIENTRY 2934af69d88dSmrg_mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) 29357117f1b4Smrg{ 29367117f1b4Smrg GLint i; 29377117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 29387117f1b4Smrg 293901e04c3fSmrg if (n < 0) { 294001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteFramebuffers(n < 0)"); 294101e04c3fSmrg return; 294201e04c3fSmrg } 294301e04c3fSmrg 29447117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 29457117f1b4Smrg 29467117f1b4Smrg for (i = 0; i < n; i++) { 29477117f1b4Smrg if (framebuffers[i] > 0) { 294801e04c3fSmrg struct gl_framebuffer *fb; 294901e04c3fSmrg fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); 295001e04c3fSmrg if (fb) { 295101e04c3fSmrg assert(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 29527117f1b4Smrg 29537117f1b4Smrg /* check if deleting currently bound framebuffer object */ 2954af69d88dSmrg if (fb == ctx->DrawBuffer) { 2955af69d88dSmrg /* bind default */ 295601e04c3fSmrg assert(fb->RefCount >= 2); 2957af69d88dSmrg _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 29584a49301eSmrg } 2959af69d88dSmrg if (fb == ctx->ReadBuffer) { 2960af69d88dSmrg /* bind default */ 296101e04c3fSmrg assert(fb->RefCount >= 2); 2962af69d88dSmrg _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, 0); 29637117f1b4Smrg } 29647117f1b4Smrg 296501e04c3fSmrg /* remove from hash table immediately, to free the ID */ 296601e04c3fSmrg _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 29677117f1b4Smrg 29687117f1b4Smrg if (fb != &DummyFramebuffer) { 29697117f1b4Smrg /* But the object will not be freed until it's no longer 29707117f1b4Smrg * bound in any context. 29717117f1b4Smrg */ 29724a49301eSmrg _mesa_reference_framebuffer(&fb, NULL); 297301e04c3fSmrg } 297401e04c3fSmrg } 29757117f1b4Smrg } 29767117f1b4Smrg } 29777117f1b4Smrg} 29787117f1b4Smrg 29797117f1b4Smrg 298001e04c3fSmrg/** 298101e04c3fSmrg * This is the implementation for glGenFramebuffers and glCreateFramebuffers. 298201e04c3fSmrg * It is not exposed to the rest of Mesa to encourage the use of 298301e04c3fSmrg * nameless buffers in driver internals. 298401e04c3fSmrg */ 298501e04c3fSmrgstatic void 298601e04c3fSmrgcreate_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa) 29877117f1b4Smrg{ 29887117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 29897117f1b4Smrg GLuint first; 29907117f1b4Smrg GLint i; 299101e04c3fSmrg struct gl_framebuffer *fb; 299201e04c3fSmrg 299301e04c3fSmrg const char *func = dsa ? "glCreateFramebuffers" : "glGenFramebuffers"; 29947117f1b4Smrg 29957117f1b4Smrg if (n < 0) { 299601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); 29977117f1b4Smrg return; 29987117f1b4Smrg } 29997117f1b4Smrg 30007117f1b4Smrg if (!framebuffers) 30017117f1b4Smrg return; 30027117f1b4Smrg 300301e04c3fSmrg _mesa_HashLockMutex(ctx->Shared->FrameBuffers); 300401e04c3fSmrg 30057117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 30067117f1b4Smrg 30077117f1b4Smrg for (i = 0; i < n; i++) { 30087117f1b4Smrg GLuint name = first + i; 30097117f1b4Smrg framebuffers[i] = name; 301001e04c3fSmrg 301101e04c3fSmrg if (dsa) { 301201e04c3fSmrg fb = ctx->Driver.NewFramebuffer(ctx, framebuffers[i]); 301301e04c3fSmrg if (!fb) { 301401e04c3fSmrg _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers); 301501e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 301601e04c3fSmrg return; 301701e04c3fSmrg } 301801e04c3fSmrg } 301901e04c3fSmrg else 302001e04c3fSmrg fb = &DummyFramebuffer; 302101e04c3fSmrg 302201e04c3fSmrg _mesa_HashInsertLocked(ctx->Shared->FrameBuffers, name, fb); 30237117f1b4Smrg } 302401e04c3fSmrg 302501e04c3fSmrg _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers); 30267117f1b4Smrg} 30277117f1b4Smrg 30287117f1b4Smrg 302901e04c3fSmrgvoid GLAPIENTRY 303001e04c3fSmrg_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers) 30317117f1b4Smrg{ 303201e04c3fSmrg create_framebuffers(n, framebuffers, false); 303301e04c3fSmrg} 30347117f1b4Smrg 30357117f1b4Smrg 303601e04c3fSmrgvoid GLAPIENTRY 303701e04c3fSmrg_mesa_CreateFramebuffers(GLsizei n, GLuint *framebuffers) 303801e04c3fSmrg{ 303901e04c3fSmrg create_framebuffers(n, framebuffers, true); 304001e04c3fSmrg} 3041af69d88dSmrg 304201e04c3fSmrg 304301e04c3fSmrgGLenum 304401e04c3fSmrg_mesa_check_framebuffer_status(struct gl_context *ctx, 304501e04c3fSmrg struct gl_framebuffer *buffer) 304601e04c3fSmrg{ 304701e04c3fSmrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 30487117f1b4Smrg 3049af69d88dSmrg if (_mesa_is_winsys_fbo(buffer)) { 3050af69d88dSmrg /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */ 3051af69d88dSmrg if (buffer != &IncompleteFramebuffer) { 3052af69d88dSmrg return GL_FRAMEBUFFER_COMPLETE_EXT; 3053af69d88dSmrg } else { 3054af69d88dSmrg return GL_FRAMEBUFFER_UNDEFINED; 3055af69d88dSmrg } 30567117f1b4Smrg } 30577117f1b4Smrg 30584a49301eSmrg /* No need to flush here */ 30594a49301eSmrg 30604a49301eSmrg if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { 30614a49301eSmrg _mesa_test_framebuffer_completeness(ctx, buffer); 30624a49301eSmrg } 30637117f1b4Smrg 30647117f1b4Smrg return buffer->_Status; 30657117f1b4Smrg} 30667117f1b4Smrg 30677117f1b4Smrg 306801e04c3fSmrgGLenum GLAPIENTRY 306901e04c3fSmrg_mesa_CheckFramebufferStatus_no_error(GLenum target) 3070af69d88dSmrg{ 307101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 3072af69d88dSmrg 307301e04c3fSmrg struct gl_framebuffer *fb = get_framebuffer_target(ctx, target); 307401e04c3fSmrg return _mesa_check_framebuffer_status(ctx, fb); 307501e04c3fSmrg} 307601e04c3fSmrg 307701e04c3fSmrg 307801e04c3fSmrgGLenum GLAPIENTRY 307901e04c3fSmrg_mesa_CheckFramebufferStatus(GLenum target) 308001e04c3fSmrg{ 308101e04c3fSmrg struct gl_framebuffer *fb; 308201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 308301e04c3fSmrg 308401e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 308501e04c3fSmrg _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n", 308601e04c3fSmrg _mesa_enum_to_string(target)); 308701e04c3fSmrg 308801e04c3fSmrg fb = get_framebuffer_target(ctx, target); 308901e04c3fSmrg if (!fb) { 309001e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 309101e04c3fSmrg "glCheckFramebufferStatus(invalid target %s)", 309201e04c3fSmrg _mesa_enum_to_string(target)); 309301e04c3fSmrg return 0; 309401e04c3fSmrg } 309501e04c3fSmrg 309601e04c3fSmrg return _mesa_check_framebuffer_status(ctx, fb); 309701e04c3fSmrg} 309801e04c3fSmrg 309901e04c3fSmrg 310001e04c3fSmrgGLenum GLAPIENTRY 310101e04c3fSmrg_mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) 310201e04c3fSmrg{ 310301e04c3fSmrg struct gl_framebuffer *fb; 310401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 310501e04c3fSmrg 310601e04c3fSmrg /* Validate the target (for conformance's sake) and grab a reference to the 310701e04c3fSmrg * default framebuffer in case framebuffer = 0. 310801e04c3fSmrg * Section 9.4 Framebuffer Completeness of the OpenGL 4.5 core spec 310901e04c3fSmrg * (30.10.2014, PDF page 336) says: 311001e04c3fSmrg * "If framebuffer is zero, then the status of the default read or 311101e04c3fSmrg * draw framebuffer (as determined by target) is returned." 311201e04c3fSmrg */ 311301e04c3fSmrg switch (target) { 311401e04c3fSmrg case GL_DRAW_FRAMEBUFFER: 311501e04c3fSmrg case GL_FRAMEBUFFER: 311601e04c3fSmrg fb = ctx->WinSysDrawBuffer; 311701e04c3fSmrg break; 311801e04c3fSmrg case GL_READ_FRAMEBUFFER: 311901e04c3fSmrg fb = ctx->WinSysReadBuffer; 312001e04c3fSmrg break; 312101e04c3fSmrg default: 312201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 312301e04c3fSmrg "glCheckNamedFramebufferStatus(invalid target %s)", 312401e04c3fSmrg _mesa_enum_to_string(target)); 312501e04c3fSmrg return 0; 312601e04c3fSmrg } 312701e04c3fSmrg 312801e04c3fSmrg if (framebuffer) { 312901e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 313001e04c3fSmrg "glCheckNamedFramebufferStatus"); 313101e04c3fSmrg if (!fb) 313201e04c3fSmrg return 0; 313301e04c3fSmrg } 313401e04c3fSmrg 313501e04c3fSmrg return _mesa_check_framebuffer_status(ctx, fb); 313601e04c3fSmrg} 313701e04c3fSmrg 313801e04c3fSmrg 313901e04c3fSmrg/** 314001e04c3fSmrg * Replicate the src attachment point. Used by framebuffer_texture() when 314101e04c3fSmrg * the same texture is attached at GL_DEPTH_ATTACHMENT and 314201e04c3fSmrg * GL_STENCIL_ATTACHMENT. 314301e04c3fSmrg */ 314401e04c3fSmrgstatic void 314501e04c3fSmrgreuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, 314601e04c3fSmrg gl_buffer_index dst, 314701e04c3fSmrg gl_buffer_index src) 314801e04c3fSmrg{ 314901e04c3fSmrg struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst]; 315001e04c3fSmrg struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src]; 315101e04c3fSmrg 315201e04c3fSmrg assert(src_att->Texture != NULL); 315301e04c3fSmrg assert(src_att->Renderbuffer != NULL); 3154af69d88dSmrg 3155af69d88dSmrg _mesa_reference_texobj(&dst_att->Texture, src_att->Texture); 3156af69d88dSmrg _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer); 3157af69d88dSmrg dst_att->Type = src_att->Type; 3158af69d88dSmrg dst_att->Complete = src_att->Complete; 3159af69d88dSmrg dst_att->TextureLevel = src_att->TextureLevel; 316001e04c3fSmrg dst_att->CubeMapFace = src_att->CubeMapFace; 3161af69d88dSmrg dst_att->Zoffset = src_att->Zoffset; 316201e04c3fSmrg dst_att->Layered = src_att->Layered; 316301e04c3fSmrg} 316401e04c3fSmrg 316501e04c3fSmrg 316601e04c3fSmrgstatic struct gl_texture_object * 316701e04c3fSmrgget_texture_for_framebuffer(struct gl_context *ctx, GLuint texture) 316801e04c3fSmrg{ 316901e04c3fSmrg if (!texture) 317001e04c3fSmrg return NULL; 317101e04c3fSmrg 317201e04c3fSmrg return _mesa_lookup_texture(ctx, texture); 3173af69d88dSmrg} 3174af69d88dSmrg 31757117f1b4Smrg 31767117f1b4Smrg/** 317701e04c3fSmrg * Common code called by gl*FramebufferTexture*() to retrieve the correct 317801e04c3fSmrg * texture object pointer. 3179af69d88dSmrg * 318001e04c3fSmrg * \param texObj where the pointer to the texture object is returned. Note 318101e04c3fSmrg * that a successful call may return texObj = NULL. 3182af69d88dSmrg * 318301e04c3fSmrg * \return true if no errors, false if errors 31847117f1b4Smrg */ 318501e04c3fSmrgstatic bool 318601e04c3fSmrgget_texture_for_framebuffer_err(struct gl_context *ctx, GLuint texture, 318701e04c3fSmrg bool layered, const char *caller, 318801e04c3fSmrg struct gl_texture_object **texObj) 31897117f1b4Smrg{ 319001e04c3fSmrg *texObj = NULL; /* This will get returned if texture = 0. */ 31917117f1b4Smrg 319201e04c3fSmrg if (!texture) 319301e04c3fSmrg return true; 319401e04c3fSmrg 319501e04c3fSmrg *texObj = _mesa_lookup_texture(ctx, texture); 319601e04c3fSmrg if (*texObj == NULL || (*texObj)->Target == 0) { 319701e04c3fSmrg /* Can't render to a non-existent texture object. 319801e04c3fSmrg * 319901e04c3fSmrg * The OpenGL 4.5 core spec (02.02.2015) in Section 9.2 Binding and 320001e04c3fSmrg * Managing Framebuffer Objects specifies a different error 320101e04c3fSmrg * depending upon the calling function (PDF pages 325-328). 320201e04c3fSmrg * *FramebufferTexture (where layered = GL_TRUE) throws invalid 320301e04c3fSmrg * value, while the other commands throw invalid operation (where 320401e04c3fSmrg * layered = GL_FALSE). 320501e04c3fSmrg */ 320601e04c3fSmrg const GLenum error = layered ? GL_INVALID_VALUE : 320701e04c3fSmrg GL_INVALID_OPERATION; 320801e04c3fSmrg _mesa_error(ctx, error, 320901e04c3fSmrg "%s(non-existent texture %u)", caller, texture); 321001e04c3fSmrg return false; 321101e04c3fSmrg } 321201e04c3fSmrg 321301e04c3fSmrg return true; 321401e04c3fSmrg} 321501e04c3fSmrg 321601e04c3fSmrg 321701e04c3fSmrg/** 321801e04c3fSmrg * Common code called by gl*FramebufferTexture() to verify the texture target 321901e04c3fSmrg * and decide whether or not the attachment should truly be considered 322001e04c3fSmrg * layered. 322101e04c3fSmrg * 322201e04c3fSmrg * \param layered true if attachment should be considered layered, false if 322301e04c3fSmrg * not 322401e04c3fSmrg * 322501e04c3fSmrg * \return true if no errors, false if errors 322601e04c3fSmrg */ 322701e04c3fSmrgstatic bool 322801e04c3fSmrgcheck_layered_texture_target(struct gl_context *ctx, GLenum target, 322901e04c3fSmrg const char *caller, GLboolean *layered) 323001e04c3fSmrg{ 323101e04c3fSmrg *layered = GL_TRUE; 323201e04c3fSmrg 323301e04c3fSmrg switch (target) { 323401e04c3fSmrg case GL_TEXTURE_3D: 323501e04c3fSmrg case GL_TEXTURE_1D_ARRAY_EXT: 323601e04c3fSmrg case GL_TEXTURE_2D_ARRAY_EXT: 323701e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 323801e04c3fSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 323901e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 324001e04c3fSmrg return true; 324101e04c3fSmrg case GL_TEXTURE_1D: 324201e04c3fSmrg case GL_TEXTURE_2D: 324301e04c3fSmrg case GL_TEXTURE_RECTANGLE: 324401e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE: 324501e04c3fSmrg /* These texture types are valid to pass to 324601e04c3fSmrg * glFramebufferTexture(), but since they aren't layered, it 324701e04c3fSmrg * is equivalent to calling glFramebufferTexture{1D,2D}(). 324801e04c3fSmrg */ 324901e04c3fSmrg *layered = GL_FALSE; 325001e04c3fSmrg return true; 325101e04c3fSmrg } 325201e04c3fSmrg 325301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 325401e04c3fSmrg "%s(invalid texture target %s)", caller, 325501e04c3fSmrg _mesa_enum_to_string(target)); 325601e04c3fSmrg return false; 325701e04c3fSmrg} 325801e04c3fSmrg 325901e04c3fSmrg 326001e04c3fSmrg/** 326101e04c3fSmrg * Common code called by gl*FramebufferTextureLayer() to verify the texture 326201e04c3fSmrg * target. 326301e04c3fSmrg * 326401e04c3fSmrg * \return true if no errors, false if errors 326501e04c3fSmrg */ 326601e04c3fSmrgstatic bool 326701e04c3fSmrgcheck_texture_target(struct gl_context *ctx, GLenum target, 326801e04c3fSmrg const char *caller) 326901e04c3fSmrg{ 327001e04c3fSmrg /* We're being called by glFramebufferTextureLayer(). 327101e04c3fSmrg * The only legal texture types for that function are 3D, 327201e04c3fSmrg * cube-map, and 1D/2D/cube-map array textures. 327301e04c3fSmrg * 327401e04c3fSmrg * We don't need to check for GL_ARB_texture_cube_map_array because the 327501e04c3fSmrg * application wouldn't have been able to create a texture with a 327601e04c3fSmrg * GL_TEXTURE_CUBE_MAP_ARRAY target if the extension were not enabled. 327701e04c3fSmrg */ 327801e04c3fSmrg switch (target) { 327901e04c3fSmrg case GL_TEXTURE_3D: 328001e04c3fSmrg case GL_TEXTURE_1D_ARRAY: 328101e04c3fSmrg case GL_TEXTURE_2D_ARRAY: 328201e04c3fSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 328301e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 328401e04c3fSmrg return true; 328501e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 328601e04c3fSmrg /* GL_TEXTURE_CUBE_MAP is only allowed by OpenGL 4.5 here, which 328701e04c3fSmrg * includes the DSA API. 328801e04c3fSmrg * 328901e04c3fSmrg * Because DSA is only enabled for GL 3.1+ and this can be called 329001e04c3fSmrg * from _mesa_FramebufferTextureLayer in compatibility profile, 329101e04c3fSmrg * we need to check the version. 329201e04c3fSmrg */ 329301e04c3fSmrg return _mesa_is_desktop_gl(ctx) && ctx->Version >= 31; 329401e04c3fSmrg } 329501e04c3fSmrg 329601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 329701e04c3fSmrg "%s(invalid texture target %s)", caller, 329801e04c3fSmrg _mesa_enum_to_string(target)); 329901e04c3fSmrg return false; 330001e04c3fSmrg} 330101e04c3fSmrg 330201e04c3fSmrg 330301e04c3fSmrg/** 330401e04c3fSmrg * Common code called by glFramebufferTexture*D() to verify the texture 330501e04c3fSmrg * target. 330601e04c3fSmrg * 330701e04c3fSmrg * \return true if no errors, false if errors 330801e04c3fSmrg */ 330901e04c3fSmrgstatic bool 331001e04c3fSmrgcheck_textarget(struct gl_context *ctx, int dims, GLenum target, 331101e04c3fSmrg GLenum textarget, const char *caller) 331201e04c3fSmrg{ 331301e04c3fSmrg bool err = false; 331401e04c3fSmrg 331501e04c3fSmrg switch (textarget) { 331601e04c3fSmrg case GL_TEXTURE_1D: 331701e04c3fSmrg err = dims != 1; 331801e04c3fSmrg break; 331901e04c3fSmrg case GL_TEXTURE_1D_ARRAY: 332001e04c3fSmrg err = dims != 1 || !ctx->Extensions.EXT_texture_array; 332101e04c3fSmrg break; 332201e04c3fSmrg case GL_TEXTURE_2D: 332301e04c3fSmrg err = dims != 2; 332401e04c3fSmrg break; 332501e04c3fSmrg case GL_TEXTURE_2D_ARRAY: 332601e04c3fSmrg err = dims != 2 || !ctx->Extensions.EXT_texture_array || 332701e04c3fSmrg (_mesa_is_gles(ctx) && ctx->Version < 30); 332801e04c3fSmrg break; 332901e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE: 333001e04c3fSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 333101e04c3fSmrg err = dims != 2 || 333201e04c3fSmrg !ctx->Extensions.ARB_texture_multisample || 333301e04c3fSmrg (_mesa_is_gles(ctx) && ctx->Version < 31); 333401e04c3fSmrg break; 333501e04c3fSmrg case GL_TEXTURE_RECTANGLE: 333601e04c3fSmrg err = dims != 2 || _mesa_is_gles(ctx) || 333701e04c3fSmrg !ctx->Extensions.NV_texture_rectangle; 333801e04c3fSmrg break; 333901e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 334001e04c3fSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 334101e04c3fSmrg err = true; 334201e04c3fSmrg break; 334301e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 334401e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 334501e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 334601e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 334701e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 334801e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 334901e04c3fSmrg err = dims != 2 || !ctx->Extensions.ARB_texture_cube_map; 335001e04c3fSmrg break; 335101e04c3fSmrg case GL_TEXTURE_3D: 335201e04c3fSmrg err = dims != 3; 335301e04c3fSmrg break; 335401e04c3fSmrg default: 33557117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 335601e04c3fSmrg "%s(unknown textarget 0x%x)", caller, textarget); 335701e04c3fSmrg return false; 33587117f1b4Smrg } 33597117f1b4Smrg 336001e04c3fSmrg if (err) { 33617117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 336201e04c3fSmrg "%s(invalid textarget %s)", 336301e04c3fSmrg caller, _mesa_enum_to_string(textarget)); 336401e04c3fSmrg return false; 33657117f1b4Smrg } 33667117f1b4Smrg 336701e04c3fSmrg /* Make sure textarget is consistent with the texture's type */ 336801e04c3fSmrg err = (target == GL_TEXTURE_CUBE_MAP) ? 336901e04c3fSmrg !_mesa_is_cube_face(textarget): (target != textarget); 33707117f1b4Smrg 337101e04c3fSmrg if (err) { 337201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 337301e04c3fSmrg "%s(mismatched texture target)", caller); 337401e04c3fSmrg return false; 337501e04c3fSmrg } 33767117f1b4Smrg 337701e04c3fSmrg return true; 337801e04c3fSmrg} 337901e04c3fSmrg 338001e04c3fSmrg 338101e04c3fSmrg/** 338201e04c3fSmrg * Common code called by gl*FramebufferTextureLayer() and 338301e04c3fSmrg * glFramebufferTexture3D() to validate the layer. 338401e04c3fSmrg * 338501e04c3fSmrg * \return true if no errors, false if errors 338601e04c3fSmrg */ 338701e04c3fSmrgstatic bool 338801e04c3fSmrgcheck_layer(struct gl_context *ctx, GLenum target, GLint layer, 338901e04c3fSmrg const char *caller) 339001e04c3fSmrg{ 339101e04c3fSmrg /* Page 306 (page 328 of the PDF) of the OpenGL 4.5 (Core Profile) 339201e04c3fSmrg * spec says: 339301e04c3fSmrg * 339401e04c3fSmrg * "An INVALID_VALUE error is generated if texture is non-zero 339501e04c3fSmrg * and layer is negative." 339601e04c3fSmrg */ 339701e04c3fSmrg if (layer < 0) { 339801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(layer %d < 0)", caller, layer); 339901e04c3fSmrg return false; 340001e04c3fSmrg } 340101e04c3fSmrg 340201e04c3fSmrg if (target == GL_TEXTURE_3D) { 340301e04c3fSmrg const GLuint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 340401e04c3fSmrg if (layer >= maxSize) { 340501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 340601e04c3fSmrg "%s(invalid layer %u)", caller, layer); 340701e04c3fSmrg return false; 34087117f1b4Smrg } 340901e04c3fSmrg } 341001e04c3fSmrg else if ((target == GL_TEXTURE_1D_ARRAY) || 341101e04c3fSmrg (target == GL_TEXTURE_2D_ARRAY) || 341201e04c3fSmrg (target == GL_TEXTURE_CUBE_MAP_ARRAY) || 341301e04c3fSmrg (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { 341401e04c3fSmrg if (layer >= ctx->Const.MaxArrayTextureLayers) { 341501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 341601e04c3fSmrg "%s(layer %u >= GL_MAX_ARRAY_TEXTURE_LAYERS)", 341701e04c3fSmrg caller, layer); 341801e04c3fSmrg return false; 3419c1f859d4Smrg } 342001e04c3fSmrg } 342101e04c3fSmrg else if (target == GL_TEXTURE_CUBE_MAP) { 342201e04c3fSmrg if (layer >= 6) { 34237117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, 342401e04c3fSmrg "%s(layer %u >= 6)", caller, layer); 342501e04c3fSmrg return false; 34267117f1b4Smrg } 34277117f1b4Smrg } 34287117f1b4Smrg 342901e04c3fSmrg return true; 343001e04c3fSmrg} 343101e04c3fSmrg 343201e04c3fSmrg 343301e04c3fSmrg/** 343401e04c3fSmrg * Common code called by all gl*FramebufferTexture*() entry points to verify 343501e04c3fSmrg * the level. 343601e04c3fSmrg * 343701e04c3fSmrg * \return true if no errors, false if errors 343801e04c3fSmrg */ 343901e04c3fSmrgstatic bool 344001e04c3fSmrgcheck_level(struct gl_context *ctx, struct gl_texture_object *texObj, 344101e04c3fSmrg GLenum target, GLint level, const char *caller) 344201e04c3fSmrg{ 344301e04c3fSmrg /* Section 9.2.8 of the OpenGL 4.6 specification says: 344401e04c3fSmrg * 344501e04c3fSmrg * "If texture refers to an immutable-format texture, level must be 344601e04c3fSmrg * greater than or equal to zero and smaller than the value of 344701e04c3fSmrg * TEXTURE_VIEW_NUM_LEVELS for texture." 344801e04c3fSmrg */ 344901e04c3fSmrg const int max_levels = texObj->Immutable ? texObj->ImmutableLevels : 345001e04c3fSmrg _mesa_max_texture_levels(ctx, target); 345101e04c3fSmrg 345201e04c3fSmrg if (level < 0 || level >= max_levels) { 345301e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 345401e04c3fSmrg "%s(invalid level %d)", caller, level); 345501e04c3fSmrg return false; 345601e04c3fSmrg } 345701e04c3fSmrg 345801e04c3fSmrg return true; 345901e04c3fSmrg} 346001e04c3fSmrg 346101e04c3fSmrg 346201e04c3fSmrgstruct gl_renderbuffer_attachment * 346301e04c3fSmrg_mesa_get_and_validate_attachment(struct gl_context *ctx, 346401e04c3fSmrg struct gl_framebuffer *fb, 346501e04c3fSmrg GLenum attachment, const char *caller) 346601e04c3fSmrg{ 346701e04c3fSmrg /* The window-system framebuffer object is immutable */ 346801e04c3fSmrg if (_mesa_is_winsys_fbo(fb)) { 346901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(window-system framebuffer)", 347001e04c3fSmrg caller); 347101e04c3fSmrg return NULL; 347201e04c3fSmrg } 347301e04c3fSmrg 347401e04c3fSmrg /* Not a hash lookup, so we can afford to get the attachment here. */ 347501e04c3fSmrg bool is_color_attachment; 347601e04c3fSmrg struct gl_renderbuffer_attachment *att = 347701e04c3fSmrg get_attachment(ctx, fb, attachment, &is_color_attachment); 34787117f1b4Smrg if (att == NULL) { 347901e04c3fSmrg if (is_color_attachment) { 348001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 348101e04c3fSmrg "%s(invalid color attachment %s)", caller, 348201e04c3fSmrg _mesa_enum_to_string(attachment)); 348301e04c3fSmrg } else { 348401e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 348501e04c3fSmrg "%s(invalid attachment %s)", caller, 348601e04c3fSmrg _mesa_enum_to_string(attachment)); 348701e04c3fSmrg } 348801e04c3fSmrg return NULL; 34897117f1b4Smrg } 34907117f1b4Smrg 349101e04c3fSmrg return att; 349201e04c3fSmrg} 349301e04c3fSmrg 349401e04c3fSmrg 349501e04c3fSmrgvoid 349601e04c3fSmrg_mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb, 349701e04c3fSmrg GLenum attachment, 349801e04c3fSmrg struct gl_renderbuffer_attachment *att, 349901e04c3fSmrg struct gl_texture_object *texObj, GLenum textarget, 350001e04c3fSmrg GLint level, GLuint layer, GLboolean layered) 350101e04c3fSmrg{ 35027117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 35037117f1b4Smrg 350401e04c3fSmrg simple_mtx_lock(&fb->Mutex); 35057117f1b4Smrg if (texObj) { 3506af69d88dSmrg if (attachment == GL_DEPTH_ATTACHMENT && 3507af69d88dSmrg texObj == fb->Attachment[BUFFER_STENCIL].Texture && 3508af69d88dSmrg level == fb->Attachment[BUFFER_STENCIL].TextureLevel && 3509af69d88dSmrg _mesa_tex_target_to_face(textarget) == 3510af69d88dSmrg fb->Attachment[BUFFER_STENCIL].CubeMapFace && 351101e04c3fSmrg layer == fb->Attachment[BUFFER_STENCIL].Zoffset) { 351201e04c3fSmrg /* The texture object is already attached to the stencil attachment 351301e04c3fSmrg * point. Don't create a new renderbuffer; just reuse the stencil 351401e04c3fSmrg * attachment's. This is required to prevent a GL error in 351501e04c3fSmrg * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL). 351601e04c3fSmrg */ 351701e04c3fSmrg reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH, 351801e04c3fSmrg BUFFER_STENCIL); 3519af69d88dSmrg } else if (attachment == GL_STENCIL_ATTACHMENT && 352001e04c3fSmrg texObj == fb->Attachment[BUFFER_DEPTH].Texture && 3521af69d88dSmrg level == fb->Attachment[BUFFER_DEPTH].TextureLevel && 3522af69d88dSmrg _mesa_tex_target_to_face(textarget) == 3523af69d88dSmrg fb->Attachment[BUFFER_DEPTH].CubeMapFace && 352401e04c3fSmrg layer == fb->Attachment[BUFFER_DEPTH].Zoffset) { 352501e04c3fSmrg /* As above, but with depth and stencil transposed. */ 352601e04c3fSmrg reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL, 352701e04c3fSmrg BUFFER_DEPTH); 3528af69d88dSmrg } else { 352901e04c3fSmrg set_texture_attachment(ctx, fb, att, texObj, textarget, 353001e04c3fSmrg level, layer, layered); 353101e04c3fSmrg 353201e04c3fSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 353301e04c3fSmrg /* Above we created a new renderbuffer and attached it to the 353401e04c3fSmrg * depth attachment point. Now attach it to the stencil attachment 353501e04c3fSmrg * point too. 353601e04c3fSmrg */ 353701e04c3fSmrg assert(att == &fb->Attachment[BUFFER_DEPTH]); 353801e04c3fSmrg reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL, 353901e04c3fSmrg BUFFER_DEPTH); 354001e04c3fSmrg } 3541af69d88dSmrg } 3542af69d88dSmrg 35434a49301eSmrg /* Set the render-to-texture flag. We'll check this flag in 35444a49301eSmrg * glTexImage() and friends to determine if we need to revalidate 35454a49301eSmrg * any FBOs that might be rendering into this texture. 35464a49301eSmrg * This flag never gets cleared since it's non-trivial to determine 35474a49301eSmrg * when all FBOs might be done rendering to this texture. That's OK 35484a49301eSmrg * though since it's uncommon to render to a texture then repeatedly 35494a49301eSmrg * call glTexImage() to change images in the texture. 35504a49301eSmrg */ 35514a49301eSmrg texObj->_RenderToTexture = GL_TRUE; 35527117f1b4Smrg } 35537117f1b4Smrg else { 3554af69d88dSmrg remove_attachment(ctx, att); 3555af69d88dSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 355601e04c3fSmrg assert(att == &fb->Attachment[BUFFER_DEPTH]); 355701e04c3fSmrg remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]); 3558af69d88dSmrg } 35597117f1b4Smrg } 35604a49301eSmrg 35614a49301eSmrg invalidate_framebuffer(fb); 35624a49301eSmrg 356301e04c3fSmrg simple_mtx_unlock(&fb->Mutex); 35647117f1b4Smrg} 35657117f1b4Smrg 35667117f1b4Smrg 356701e04c3fSmrgstatic void 356801e04c3fSmrgframebuffer_texture_with_dims_no_error(GLenum target, GLenum attachment, 356901e04c3fSmrg GLenum textarget, GLuint texture, 357001e04c3fSmrg GLint level, GLint layer) 35717117f1b4Smrg{ 35727117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 35737117f1b4Smrg 357401e04c3fSmrg /* Get the framebuffer object */ 357501e04c3fSmrg struct gl_framebuffer *fb = get_framebuffer_target(ctx, target); 3576af69d88dSmrg 357701e04c3fSmrg /* Get the texture object */ 357801e04c3fSmrg struct gl_texture_object *texObj = 357901e04c3fSmrg get_texture_for_framebuffer(ctx, texture); 3580af69d88dSmrg 358101e04c3fSmrg struct gl_renderbuffer_attachment *att = 358201e04c3fSmrg get_attachment(ctx, fb, attachment, NULL); 358301e04c3fSmrg 358401e04c3fSmrg _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, 358501e04c3fSmrg level, layer, GL_FALSE); 358601e04c3fSmrg} 358701e04c3fSmrg 358801e04c3fSmrg 358901e04c3fSmrgstatic void 359001e04c3fSmrgframebuffer_texture_with_dims(int dims, GLenum target, 359101e04c3fSmrg GLenum attachment, GLenum textarget, 359201e04c3fSmrg GLuint texture, GLint level, GLint layer, 359301e04c3fSmrg const char *caller) 359401e04c3fSmrg{ 359501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 359601e04c3fSmrg struct gl_framebuffer *fb; 359701e04c3fSmrg struct gl_texture_object *texObj; 359801e04c3fSmrg 359901e04c3fSmrg /* Get the framebuffer object */ 360001e04c3fSmrg fb = get_framebuffer_target(ctx, target); 360101e04c3fSmrg if (!fb) { 360201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller, 360301e04c3fSmrg _mesa_enum_to_string(target)); 360401e04c3fSmrg return; 360501e04c3fSmrg } 360601e04c3fSmrg 360701e04c3fSmrg /* Get the texture object */ 360801e04c3fSmrg if (!get_texture_for_framebuffer_err(ctx, texture, false, caller, &texObj)) 360901e04c3fSmrg return; 361001e04c3fSmrg 361101e04c3fSmrg if (texObj) { 361201e04c3fSmrg if (!check_textarget(ctx, dims, texObj->Target, textarget, caller)) 361301e04c3fSmrg return; 361401e04c3fSmrg 361501e04c3fSmrg if ((dims == 3) && !check_layer(ctx, texObj->Target, layer, caller)) 361601e04c3fSmrg return; 361701e04c3fSmrg 361801e04c3fSmrg if (!check_level(ctx, texObj, textarget, level, caller)) 3619af69d88dSmrg return; 36207117f1b4Smrg } 36217117f1b4Smrg 362201e04c3fSmrg struct gl_renderbuffer_attachment *att = 362301e04c3fSmrg _mesa_get_and_validate_attachment(ctx, fb, attachment, caller); 362401e04c3fSmrg if (!att) 362501e04c3fSmrg return; 362601e04c3fSmrg 362701e04c3fSmrg _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, 362801e04c3fSmrg level, layer, GL_FALSE); 36297117f1b4Smrg} 36307117f1b4Smrg 36317117f1b4Smrg 36327117f1b4Smrgvoid GLAPIENTRY 363301e04c3fSmrg_mesa_FramebufferTexture1D_no_error(GLenum target, GLenum attachment, 363401e04c3fSmrg GLenum textarget, GLuint texture, 363501e04c3fSmrg GLint level) 363601e04c3fSmrg{ 363701e04c3fSmrg framebuffer_texture_with_dims_no_error(target, attachment, textarget, 363801e04c3fSmrg texture, level, 0); 363901e04c3fSmrg} 364001e04c3fSmrg 364101e04c3fSmrg 364201e04c3fSmrgvoid GLAPIENTRY 364301e04c3fSmrg_mesa_FramebufferTexture1D(GLenum target, GLenum attachment, 3644af69d88dSmrg GLenum textarget, GLuint texture, GLint level) 36457117f1b4Smrg{ 364601e04c3fSmrg framebuffer_texture_with_dims(1, target, attachment, textarget, texture, 364701e04c3fSmrg level, 0, "glFramebufferTexture1D"); 364801e04c3fSmrg} 36497117f1b4Smrg 3650af69d88dSmrg 365101e04c3fSmrgvoid GLAPIENTRY 365201e04c3fSmrg_mesa_FramebufferTexture2D_no_error(GLenum target, GLenum attachment, 365301e04c3fSmrg GLenum textarget, GLuint texture, 365401e04c3fSmrg GLint level) 365501e04c3fSmrg{ 365601e04c3fSmrg framebuffer_texture_with_dims_no_error(target, attachment, textarget, 365701e04c3fSmrg texture, level, 0); 365801e04c3fSmrg} 3659af69d88dSmrg 36607117f1b4Smrg 366101e04c3fSmrgvoid GLAPIENTRY 366201e04c3fSmrg_mesa_FramebufferTexture2D(GLenum target, GLenum attachment, 366301e04c3fSmrg GLenum textarget, GLuint texture, GLint level) 366401e04c3fSmrg{ 366501e04c3fSmrg framebuffer_texture_with_dims(2, target, attachment, textarget, texture, 366601e04c3fSmrg level, 0, "glFramebufferTexture2D"); 366701e04c3fSmrg} 366801e04c3fSmrg 366901e04c3fSmrg 367001e04c3fSmrgvoid GLAPIENTRY 367101e04c3fSmrg_mesa_FramebufferTexture3D_no_error(GLenum target, GLenum attachment, 367201e04c3fSmrg GLenum textarget, GLuint texture, 367301e04c3fSmrg GLint level, GLint layer) 367401e04c3fSmrg{ 367501e04c3fSmrg framebuffer_texture_with_dims_no_error(target, attachment, textarget, 367601e04c3fSmrg texture, level, layer); 36777117f1b4Smrg} 36787117f1b4Smrg 36797117f1b4Smrg 36807117f1b4Smrgvoid GLAPIENTRY 3681af69d88dSmrg_mesa_FramebufferTexture3D(GLenum target, GLenum attachment, 3682af69d88dSmrg GLenum textarget, GLuint texture, 368301e04c3fSmrg GLint level, GLint layer) 368401e04c3fSmrg{ 368501e04c3fSmrg framebuffer_texture_with_dims(3, target, attachment, textarget, texture, 368601e04c3fSmrg level, layer, "glFramebufferTexture3D"); 368701e04c3fSmrg} 368801e04c3fSmrg 368901e04c3fSmrg 369001e04c3fSmrgstatic ALWAYS_INLINE void 369101e04c3fSmrgframe_buffer_texture(GLuint framebuffer, GLenum target, 369201e04c3fSmrg GLenum attachment, GLuint texture, 369301e04c3fSmrg GLint level, GLint layer, const char *func, 369401e04c3fSmrg bool dsa, bool no_error, bool check_layered) 36957117f1b4Smrg{ 36967117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 369701e04c3fSmrg GLboolean layered = GL_FALSE; 36987117f1b4Smrg 369901e04c3fSmrg if (!no_error && check_layered) { 370001e04c3fSmrg if (!_mesa_has_geometry_shaders(ctx)) { 370101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 370201e04c3fSmrg "unsupported function (%s) called", func); 370301e04c3fSmrg return; 370401e04c3fSmrg } 37057117f1b4Smrg } 37067117f1b4Smrg 370701e04c3fSmrg /* Get the framebuffer object */ 370801e04c3fSmrg struct gl_framebuffer *fb; 370901e04c3fSmrg if (no_error) { 371001e04c3fSmrg if (dsa) { 371101e04c3fSmrg fb = _mesa_lookup_framebuffer(ctx, framebuffer); 371201e04c3fSmrg } else { 371301e04c3fSmrg fb = get_framebuffer_target(ctx, target); 371401e04c3fSmrg } 371501e04c3fSmrg } else { 371601e04c3fSmrg if (dsa) { 371701e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func); 371801e04c3fSmrg if (!fb) 371901e04c3fSmrg return; 372001e04c3fSmrg } else { 372101e04c3fSmrg fb = get_framebuffer_target(ctx, target); 372201e04c3fSmrg if (!fb) { 372301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", 372401e04c3fSmrg func, _mesa_enum_to_string(target)); 372501e04c3fSmrg return; 372601e04c3fSmrg } 372701e04c3fSmrg } 372801e04c3fSmrg } 372901e04c3fSmrg 373001e04c3fSmrg /* Get the texture object and framebuffer attachment*/ 373101e04c3fSmrg struct gl_renderbuffer_attachment *att; 373201e04c3fSmrg struct gl_texture_object *texObj; 373301e04c3fSmrg if (no_error) { 373401e04c3fSmrg texObj = get_texture_for_framebuffer(ctx, texture); 373501e04c3fSmrg att = get_attachment(ctx, fb, attachment, NULL); 373601e04c3fSmrg } else { 373701e04c3fSmrg if (!get_texture_for_framebuffer_err(ctx, texture, check_layered, func, 373801e04c3fSmrg &texObj)) 373901e04c3fSmrg return; 374001e04c3fSmrg 374101e04c3fSmrg att = _mesa_get_and_validate_attachment(ctx, fb, attachment, func); 374201e04c3fSmrg if (!att) 374301e04c3fSmrg return; 374401e04c3fSmrg } 374501e04c3fSmrg 374601e04c3fSmrg GLenum textarget = 0; 374701e04c3fSmrg if (texObj) { 374801e04c3fSmrg if (check_layered) { 374901e04c3fSmrg /* We do this regardless of no_error because this sets layered */ 375001e04c3fSmrg if (!check_layered_texture_target(ctx, texObj->Target, func, 375101e04c3fSmrg &layered)) 375201e04c3fSmrg return; 375301e04c3fSmrg } 375401e04c3fSmrg 375501e04c3fSmrg if (!no_error) { 375601e04c3fSmrg if (!check_layered) { 375701e04c3fSmrg if (!check_texture_target(ctx, texObj->Target, func)) 375801e04c3fSmrg return; 375901e04c3fSmrg 376001e04c3fSmrg if (!check_layer(ctx, texObj->Target, layer, func)) 376101e04c3fSmrg return; 376201e04c3fSmrg } 376301e04c3fSmrg 376401e04c3fSmrg if (!check_level(ctx, texObj, texObj->Target, level, func)) 376501e04c3fSmrg return; 376601e04c3fSmrg } 376701e04c3fSmrg 376801e04c3fSmrg if (!check_layered && texObj->Target == GL_TEXTURE_CUBE_MAP) { 376901e04c3fSmrg assert(layer >= 0 && layer < 6); 377001e04c3fSmrg textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; 377101e04c3fSmrg layer = 0; 377201e04c3fSmrg } 377301e04c3fSmrg } 377401e04c3fSmrg 377501e04c3fSmrg _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget, 377601e04c3fSmrg level, layer, layered); 377701e04c3fSmrg} 377801e04c3fSmrg 377901e04c3fSmrgvoid GLAPIENTRY 378001e04c3fSmrg_mesa_FramebufferTextureLayer_no_error(GLenum target, GLenum attachment, 378101e04c3fSmrg GLuint texture, GLint level, 378201e04c3fSmrg GLint layer) 378301e04c3fSmrg{ 378401e04c3fSmrg frame_buffer_texture(0, target, attachment, texture, level, layer, 378501e04c3fSmrg "glFramebufferTextureLayer", false, true, false); 37867117f1b4Smrg} 37877117f1b4Smrg 37887117f1b4Smrg 3789c1f859d4Smrgvoid GLAPIENTRY 3790af69d88dSmrg_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, 3791af69d88dSmrg GLuint texture, GLint level, GLint layer) 3792c1f859d4Smrg{ 379301e04c3fSmrg frame_buffer_texture(0, target, attachment, texture, level, layer, 379401e04c3fSmrg "glFramebufferTextureLayer", false, false, false); 379501e04c3fSmrg} 379601e04c3fSmrg 379701e04c3fSmrg 379801e04c3fSmrgvoid GLAPIENTRY 379901e04c3fSmrg_mesa_NamedFramebufferTextureLayer_no_error(GLuint framebuffer, 380001e04c3fSmrg GLenum attachment, 380101e04c3fSmrg GLuint texture, GLint level, 380201e04c3fSmrg GLint layer) 380301e04c3fSmrg{ 380401e04c3fSmrg frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer, 380501e04c3fSmrg "glNamedFramebufferTextureLayer", true, true, false); 380601e04c3fSmrg} 380701e04c3fSmrg 380801e04c3fSmrg 380901e04c3fSmrgvoid GLAPIENTRY 381001e04c3fSmrg_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment, 381101e04c3fSmrg GLuint texture, GLint level, GLint layer) 381201e04c3fSmrg{ 381301e04c3fSmrg frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer, 381401e04c3fSmrg "glNamedFramebufferTextureLayer", true, false, false); 381501e04c3fSmrg} 3816c1f859d4Smrg 381701e04c3fSmrg 381801e04c3fSmrgvoid GLAPIENTRY 381901e04c3fSmrg_mesa_FramebufferTexture_no_error(GLenum target, GLenum attachment, 382001e04c3fSmrg GLuint texture, GLint level) 382101e04c3fSmrg{ 382201e04c3fSmrg frame_buffer_texture(0, target, attachment, texture, level, 0, 382301e04c3fSmrg "glFramebufferTexture", false, true, true); 3824af69d88dSmrg} 3825af69d88dSmrg 3826af69d88dSmrg 3827af69d88dSmrgvoid GLAPIENTRY 3828af69d88dSmrg_mesa_FramebufferTexture(GLenum target, GLenum attachment, 3829af69d88dSmrg GLuint texture, GLint level) 3830af69d88dSmrg{ 383101e04c3fSmrg frame_buffer_texture(0, target, attachment, texture, level, 0, 383201e04c3fSmrg "glFramebufferTexture", false, false, true); 383301e04c3fSmrg} 3834af69d88dSmrg 383501e04c3fSmrgvoid GLAPIENTRY 383601e04c3fSmrg_mesa_NamedFramebufferTexture_no_error(GLuint framebuffer, GLenum attachment, 383701e04c3fSmrg GLuint texture, GLint level) 383801e04c3fSmrg{ 383901e04c3fSmrg frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0, 384001e04c3fSmrg "glNamedFramebufferTexture", true, true, true); 3841c1f859d4Smrg} 3842c1f859d4Smrg 3843c1f859d4Smrg 38447117f1b4Smrgvoid GLAPIENTRY 384501e04c3fSmrg_mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, 384601e04c3fSmrg GLuint texture, GLint level) 38477117f1b4Smrg{ 384801e04c3fSmrg frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0, 384901e04c3fSmrg "glNamedFramebufferTexture", true, false, true); 385001e04c3fSmrg} 38517117f1b4Smrg 38527117f1b4Smrg 385301e04c3fSmrgvoid 385401e04c3fSmrg_mesa_framebuffer_renderbuffer(struct gl_context *ctx, 385501e04c3fSmrg struct gl_framebuffer *fb, 385601e04c3fSmrg GLenum attachment, 385701e04c3fSmrg struct gl_renderbuffer *rb) 385801e04c3fSmrg{ 385901e04c3fSmrg assert(!_mesa_is_winsys_fbo(fb)); 38607117f1b4Smrg 386101e04c3fSmrg FLUSH_VERTICES(ctx, _NEW_BUFFERS); 38627117f1b4Smrg 386301e04c3fSmrg assert(ctx->Driver.FramebufferRenderbuffer); 386401e04c3fSmrg ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); 386501e04c3fSmrg 386601e04c3fSmrg /* Some subsequent GL commands may depend on the framebuffer's visual 386701e04c3fSmrg * after the binding is updated. Update visual info now. 386801e04c3fSmrg */ 386901e04c3fSmrg _mesa_update_framebuffer_visual(ctx, fb); 387001e04c3fSmrg} 387101e04c3fSmrg 387201e04c3fSmrgstatic ALWAYS_INLINE void 387301e04c3fSmrgframebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 387401e04c3fSmrg GLenum attachment, GLenum renderbuffertarget, 387501e04c3fSmrg GLuint renderbuffer, const char *func, bool no_error) 387601e04c3fSmrg{ 387701e04c3fSmrg struct gl_renderbuffer_attachment *att; 387801e04c3fSmrg struct gl_renderbuffer *rb; 387901e04c3fSmrg bool is_color_attachment; 388001e04c3fSmrg 388101e04c3fSmrg if (!no_error && renderbuffertarget != GL_RENDERBUFFER) { 38827117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 388301e04c3fSmrg "%s(renderbuffertarget is not GL_RENDERBUFFER)", func); 38847117f1b4Smrg return; 38857117f1b4Smrg } 38867117f1b4Smrg 38877117f1b4Smrg if (renderbuffer) { 388801e04c3fSmrg if (!no_error) { 388901e04c3fSmrg rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, func); 389001e04c3fSmrg if (!rb) 389101e04c3fSmrg return; 389201e04c3fSmrg } else { 389301e04c3fSmrg rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 38943464ebd5Sriastradh } 389501e04c3fSmrg } else { 38967117f1b4Smrg /* remove renderbuffer attachment */ 38977117f1b4Smrg rb = NULL; 38987117f1b4Smrg } 38997117f1b4Smrg 390001e04c3fSmrg if (!no_error) { 390101e04c3fSmrg if (_mesa_is_winsys_fbo(fb)) { 390201e04c3fSmrg /* Can't attach new renderbuffers to a window system framebuffer */ 39034a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 390401e04c3fSmrg "%s(window-system framebuffer)", func); 39054a49301eSmrg return; 39064a49301eSmrg } 39074a49301eSmrg 390801e04c3fSmrg att = get_attachment(ctx, fb, attachment, &is_color_attachment); 390901e04c3fSmrg if (att == NULL) { 391001e04c3fSmrg /* 391101e04c3fSmrg * From OpenGL 4.5 spec, section 9.2.7 "Attaching Renderbuffer Images 391201e04c3fSmrg * to a Framebuffer": 391301e04c3fSmrg * 391401e04c3fSmrg * "An INVALID_OPERATION error is generated if attachment is 391501e04c3fSmrg * COLOR_- ATTACHMENTm where m is greater than or equal to the 391601e04c3fSmrg * value of MAX_COLOR_- ATTACHMENTS ." 391701e04c3fSmrg * 391801e04c3fSmrg * If we are at this point, is because the attachment is not valid, so 391901e04c3fSmrg * if is_color_attachment is true, is because of the previous reason. 392001e04c3fSmrg */ 392101e04c3fSmrg if (is_color_attachment) { 392201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 392301e04c3fSmrg "%s(invalid color attachment %s)", func, 392401e04c3fSmrg _mesa_enum_to_string(attachment)); 392501e04c3fSmrg } else { 392601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 392701e04c3fSmrg "%s(invalid attachment %s)", func, 392801e04c3fSmrg _mesa_enum_to_string(attachment)); 392901e04c3fSmrg } 39307117f1b4Smrg 393101e04c3fSmrg return; 393201e04c3fSmrg } 39337117f1b4Smrg 393401e04c3fSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && 393501e04c3fSmrg rb && rb->Format != MESA_FORMAT_NONE) { 393601e04c3fSmrg /* make sure the renderbuffer is a depth/stencil format */ 393701e04c3fSmrg const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); 393801e04c3fSmrg if (baseFormat != GL_DEPTH_STENCIL) { 393901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 394001e04c3fSmrg "%s(renderbuffer is not DEPTH_STENCIL format)", func); 394101e04c3fSmrg return; 394201e04c3fSmrg } 394301e04c3fSmrg } 394401e04c3fSmrg } 394501e04c3fSmrg 394601e04c3fSmrg _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 39477117f1b4Smrg} 39487117f1b4Smrg 394901e04c3fSmrgstatic void 395001e04c3fSmrgframebuffer_renderbuffer_error(struct gl_context *ctx, 395101e04c3fSmrg struct gl_framebuffer *fb, GLenum attachment, 395201e04c3fSmrg GLenum renderbuffertarget, 395301e04c3fSmrg GLuint renderbuffer, const char *func) 395401e04c3fSmrg{ 395501e04c3fSmrg framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget, 395601e04c3fSmrg renderbuffer, func, false); 395701e04c3fSmrg} 395801e04c3fSmrg 395901e04c3fSmrgstatic void 396001e04c3fSmrgframebuffer_renderbuffer_no_error(struct gl_context *ctx, 396101e04c3fSmrg struct gl_framebuffer *fb, GLenum attachment, 396201e04c3fSmrg GLenum renderbuffertarget, 396301e04c3fSmrg GLuint renderbuffer, const char *func) 396401e04c3fSmrg{ 396501e04c3fSmrg framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget, 396601e04c3fSmrg renderbuffer, func, true); 396701e04c3fSmrg} 39687117f1b4Smrg 39697117f1b4Smrgvoid GLAPIENTRY 397001e04c3fSmrg_mesa_FramebufferRenderbuffer_no_error(GLenum target, GLenum attachment, 397101e04c3fSmrg GLenum renderbuffertarget, 397201e04c3fSmrg GLuint renderbuffer) 39737117f1b4Smrg{ 39747117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 39757117f1b4Smrg 397601e04c3fSmrg struct gl_framebuffer *fb = get_framebuffer_target(ctx, target); 397701e04c3fSmrg framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget, 397801e04c3fSmrg renderbuffer, "glFramebufferRenderbuffer"); 397901e04c3fSmrg} 39803464ebd5Sriastradh 398101e04c3fSmrgvoid GLAPIENTRY 398201e04c3fSmrg_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, 398301e04c3fSmrg GLenum renderbuffertarget, 398401e04c3fSmrg GLuint renderbuffer) 398501e04c3fSmrg{ 398601e04c3fSmrg struct gl_framebuffer *fb; 398701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 398801e04c3fSmrg 398901e04c3fSmrg fb = get_framebuffer_target(ctx, target); 399001e04c3fSmrg if (!fb) { 39917117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, 399201e04c3fSmrg "glFramebufferRenderbuffer(invalid target %s)", 399301e04c3fSmrg _mesa_enum_to_string(target)); 39947117f1b4Smrg return; 39957117f1b4Smrg } 39967117f1b4Smrg 399701e04c3fSmrg framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget, 399801e04c3fSmrg renderbuffer, "glFramebufferRenderbuffer"); 399901e04c3fSmrg} 400001e04c3fSmrg 400101e04c3fSmrgvoid GLAPIENTRY 400201e04c3fSmrg_mesa_NamedFramebufferRenderbuffer_no_error(GLuint framebuffer, 400301e04c3fSmrg GLenum attachment, 400401e04c3fSmrg GLenum renderbuffertarget, 400501e04c3fSmrg GLuint renderbuffer) 400601e04c3fSmrg{ 400701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 400801e04c3fSmrg 400901e04c3fSmrg struct gl_framebuffer *fb = _mesa_lookup_framebuffer(ctx, framebuffer); 401001e04c3fSmrg framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget, 401101e04c3fSmrg renderbuffer, 401201e04c3fSmrg "glNamedFramebufferRenderbuffer"); 401301e04c3fSmrg} 401401e04c3fSmrg 401501e04c3fSmrgvoid GLAPIENTRY 401601e04c3fSmrg_mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, 401701e04c3fSmrg GLenum renderbuffertarget, 401801e04c3fSmrg GLuint renderbuffer) 401901e04c3fSmrg{ 402001e04c3fSmrg struct gl_framebuffer *fb; 402101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 402201e04c3fSmrg 402301e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 402401e04c3fSmrg "glNamedFramebufferRenderbuffer"); 402501e04c3fSmrg if (!fb) 402601e04c3fSmrg return; 402701e04c3fSmrg 402801e04c3fSmrg framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget, 402901e04c3fSmrg renderbuffer, 403001e04c3fSmrg "glNamedFramebufferRenderbuffer"); 403101e04c3fSmrg} 403201e04c3fSmrg 403301e04c3fSmrg 403401e04c3fSmrgstatic void 403501e04c3fSmrgget_framebuffer_attachment_parameter(struct gl_context *ctx, 403601e04c3fSmrg struct gl_framebuffer *buffer, 403701e04c3fSmrg GLenum attachment, GLenum pname, 403801e04c3fSmrg GLint *params, const char *caller) 403901e04c3fSmrg{ 404001e04c3fSmrg const struct gl_renderbuffer_attachment *att; 404101e04c3fSmrg bool is_color_attachment = false; 404201e04c3fSmrg GLenum err; 404301e04c3fSmrg 404401e04c3fSmrg /* The error code for an attachment type of GL_NONE differs between APIs. 404501e04c3fSmrg * 404601e04c3fSmrg * From the ES 2.0.25 specification, page 127: 404701e04c3fSmrg * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then 404801e04c3fSmrg * querying any other pname will generate INVALID_ENUM." 404901e04c3fSmrg * 405001e04c3fSmrg * From the OpenGL 3.0 specification, page 337, or identically, 405101e04c3fSmrg * the OpenGL ES 3.0.4 specification, page 240: 405201e04c3fSmrg * 405301e04c3fSmrg * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, no 405401e04c3fSmrg * framebuffer is bound to target. In this case querying pname 405501e04c3fSmrg * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero, and all other 405601e04c3fSmrg * queries will generate an INVALID_OPERATION error." 405701e04c3fSmrg */ 405801e04c3fSmrg err = ctx->API == API_OPENGLES2 && ctx->Version < 30 ? 405901e04c3fSmrg GL_INVALID_ENUM : GL_INVALID_OPERATION; 406001e04c3fSmrg 4061af69d88dSmrg if (_mesa_is_winsys_fbo(buffer)) { 4062af69d88dSmrg /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec 4063af69d88dSmrg * says: 4064af69d88dSmrg * 4065af69d88dSmrg * "If the framebuffer currently bound to target is zero, then 4066af69d88dSmrg * INVALID_OPERATION is generated." 4067af69d88dSmrg * 4068af69d88dSmrg * The EXT_framebuffer_object spec has the same wording, and the 4069af69d88dSmrg * OES_framebuffer_object spec refers to the EXT_framebuffer_object 4070af69d88dSmrg * spec. 4071af69d88dSmrg */ 4072af69d88dSmrg if ((!_mesa_is_desktop_gl(ctx) || 4073af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 4074af69d88dSmrg && !_mesa_is_gles3(ctx)) { 407501e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 407601e04c3fSmrg "%s(window-system framebuffer)", caller); 407701e04c3fSmrg return; 4078af69d88dSmrg } 4079af69d88dSmrg 4080af69d88dSmrg if (_mesa_is_gles3(ctx) && attachment != GL_BACK && 4081af69d88dSmrg attachment != GL_DEPTH && attachment != GL_STENCIL) { 408201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 408301e04c3fSmrg "%s(invalid attachment %s)", caller, 408401e04c3fSmrg _mesa_enum_to_string(attachment)); 408501e04c3fSmrg return; 408601e04c3fSmrg } 408701e04c3fSmrg 408801e04c3fSmrg /* The specs are not clear about how to handle 408901e04c3fSmrg * GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME with the default framebuffer, 409001e04c3fSmrg * but dEQP-GLES3 expects an INVALID_ENUM error. This has also been 409101e04c3fSmrg * discussed in: 409201e04c3fSmrg * 409301e04c3fSmrg * https://cvs.khronos.org/bugzilla/show_bug.cgi?id=12928#c1 409401e04c3fSmrg * and https://bugs.freedesktop.org/show_bug.cgi?id=31947 409501e04c3fSmrg */ 409601e04c3fSmrg if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) { 409701e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 409801e04c3fSmrg "%s(requesting GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME " 409901e04c3fSmrg "when GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is " 410001e04c3fSmrg "GL_FRAMEBUFFER_DEFAULT is not allowed)", caller); 4101af69d88dSmrg return; 4102af69d88dSmrg } 410301e04c3fSmrg 41043464ebd5Sriastradh /* the default / window-system FBO */ 410501e04c3fSmrg att = get_fb0_attachment(ctx, buffer, attachment); 41063464ebd5Sriastradh } 41073464ebd5Sriastradh else { 41083464ebd5Sriastradh /* user-created framebuffer FBO */ 410901e04c3fSmrg att = get_attachment(ctx, buffer, attachment, &is_color_attachment); 41107117f1b4Smrg } 41117117f1b4Smrg 41127117f1b4Smrg if (att == NULL) { 411301e04c3fSmrg /* 411401e04c3fSmrg * From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries": 411501e04c3fSmrg * 411601e04c3fSmrg * "An INVALID_OPERATION error is generated if a framebuffer object 411701e04c3fSmrg * is bound to target and attachment is COLOR_ATTACHMENTm where m is 411801e04c3fSmrg * greater than or equal to the value of MAX_COLOR_ATTACHMENTS." 411901e04c3fSmrg * 412001e04c3fSmrg * If we are at this point, is because the attachment is not valid, so 412101e04c3fSmrg * if is_color_attachment is true, is because of the previous reason. 412201e04c3fSmrg */ 412301e04c3fSmrg if (is_color_attachment) { 412401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid color attachment %s)", 412501e04c3fSmrg caller, _mesa_enum_to_string(attachment)); 412601e04c3fSmrg } else { 412701e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller, 412801e04c3fSmrg _mesa_enum_to_string(attachment)); 412901e04c3fSmrg } 41307117f1b4Smrg return; 41317117f1b4Smrg } 41327117f1b4Smrg 41334a49301eSmrg if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 41344a49301eSmrg const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; 4135af69d88dSmrg if (pname == GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) { 4136af69d88dSmrg /* This behavior is first specified in OpenGL 4.4 specification. 4137af69d88dSmrg * 4138af69d88dSmrg * From the OpenGL 4.4 spec page 275: 4139af69d88dSmrg * "This query cannot be performed for a combined depth+stencil 4140af69d88dSmrg * attachment, since it does not have a single format." 4141af69d88dSmrg */ 4142af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 414301e04c3fSmrg "%s(GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE" 414401e04c3fSmrg " is invalid for depth+stencil attachment)", caller); 4145af69d88dSmrg return; 4146af69d88dSmrg } 4147af69d88dSmrg /* the depth and stencil attachments must point to the same buffer */ 414801e04c3fSmrg depthAtt = get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT, NULL); 414901e04c3fSmrg stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT, NULL); 41504a49301eSmrg if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { 41514a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 415201e04c3fSmrg "%s(DEPTH/STENCIL attachments differ)", caller); 41534a49301eSmrg return; 41544a49301eSmrg } 41554a49301eSmrg } 41564a49301eSmrg 41574a49301eSmrg /* No need to flush here */ 41587117f1b4Smrg 41597117f1b4Smrg switch (pname) { 41607117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 416101e04c3fSmrg /* From the OpenGL spec, 9.2. Binding and Managing Framebuffer Objects: 416201e04c3fSmrg * 416301e04c3fSmrg * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then 416401e04c3fSmrg * either no framebuffer is bound to target; or the default framebuffer 416501e04c3fSmrg * is bound, attachment is DEPTH or STENCIL, and the number of depth or 416601e04c3fSmrg * stencil bits, respectively, is zero." 416701e04c3fSmrg * 416801e04c3fSmrg * Note that we don't need explicit checks on DEPTH and STENCIL, because 416901e04c3fSmrg * on the case the spec is pointing, att->Type is already NONE, so we 417001e04c3fSmrg * just need to check att->Type. 417101e04c3fSmrg */ 417201e04c3fSmrg *params = (_mesa_is_winsys_fbo(buffer) && att->Type != GL_NONE) ? 417301e04c3fSmrg GL_FRAMEBUFFER_DEFAULT : att->Type; 41747117f1b4Smrg return; 41757117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 41767117f1b4Smrg if (att->Type == GL_RENDERBUFFER_EXT) { 417701e04c3fSmrg *params = att->Renderbuffer->Name; 41787117f1b4Smrg } 41797117f1b4Smrg else if (att->Type == GL_TEXTURE) { 418001e04c3fSmrg *params = att->Texture->Name; 41817117f1b4Smrg } 41827117f1b4Smrg else { 41833464ebd5Sriastradh assert(att->Type == GL_NONE); 4184af69d88dSmrg if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { 41853464ebd5Sriastradh *params = 0; 41863464ebd5Sriastradh } else { 4187af69d88dSmrg goto invalid_pname_enum; 41883464ebd5Sriastradh } 41897117f1b4Smrg } 41907117f1b4Smrg return; 41917117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 41927117f1b4Smrg if (att->Type == GL_TEXTURE) { 419301e04c3fSmrg *params = att->TextureLevel; 41947117f1b4Smrg } 41953464ebd5Sriastradh else if (att->Type == GL_NONE) { 419601e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 419701e04c3fSmrg _mesa_enum_to_string(pname)); 41983464ebd5Sriastradh } 41997117f1b4Smrg else { 4200af69d88dSmrg goto invalid_pname_enum; 42017117f1b4Smrg } 42027117f1b4Smrg return; 42037117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 42047117f1b4Smrg if (att->Type == GL_TEXTURE) { 4205c1f859d4Smrg if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { 4206c1f859d4Smrg *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 4207c1f859d4Smrg } 4208c1f859d4Smrg else { 4209c1f859d4Smrg *params = 0; 4210c1f859d4Smrg } 42117117f1b4Smrg } 42123464ebd5Sriastradh else if (att->Type == GL_NONE) { 421301e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 421401e04c3fSmrg _mesa_enum_to_string(pname)); 42153464ebd5Sriastradh } 42167117f1b4Smrg else { 4217af69d88dSmrg goto invalid_pname_enum; 42187117f1b4Smrg } 42197117f1b4Smrg return; 42207117f1b4Smrg case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 4221af69d88dSmrg if (ctx->API == API_OPENGLES) { 4222af69d88dSmrg goto invalid_pname_enum; 4223af69d88dSmrg } else if (att->Type == GL_NONE) { 422401e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 422501e04c3fSmrg _mesa_enum_to_string(pname)); 4226af69d88dSmrg } else if (att->Type == GL_TEXTURE) { 422701e04c3fSmrg if (att->Texture && (att->Texture->Target == GL_TEXTURE_3D || 422801e04c3fSmrg att->Texture->Target == GL_TEXTURE_2D_ARRAY)) { 4229c1f859d4Smrg *params = att->Zoffset; 4230c1f859d4Smrg } 4231c1f859d4Smrg else { 4232c1f859d4Smrg *params = 0; 4233c1f859d4Smrg } 42347117f1b4Smrg } 42357117f1b4Smrg else { 4236af69d88dSmrg goto invalid_pname_enum; 42377117f1b4Smrg } 42387117f1b4Smrg return; 42394a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: 4240af69d88dSmrg if ((!_mesa_is_desktop_gl(ctx) || 4241af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 4242af69d88dSmrg && !_mesa_is_gles3(ctx)) { 4243af69d88dSmrg goto invalid_pname_enum; 42444a49301eSmrg } 42453464ebd5Sriastradh else if (att->Type == GL_NONE) { 424601e04c3fSmrg if (_mesa_is_winsys_fbo(buffer) && 424701e04c3fSmrg (attachment == GL_DEPTH || attachment == GL_STENCIL)) { 424801e04c3fSmrg *params = GL_LINEAR; 424901e04c3fSmrg } else { 425001e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 425101e04c3fSmrg _mesa_enum_to_string(pname)); 425201e04c3fSmrg } 42533464ebd5Sriastradh } 42544a49301eSmrg else { 4255af69d88dSmrg if (ctx->Extensions.EXT_framebuffer_sRGB) { 4256af69d88dSmrg *params = 4257af69d88dSmrg _mesa_get_format_color_encoding(att->Renderbuffer->Format); 42583464ebd5Sriastradh } 42593464ebd5Sriastradh else { 42603464ebd5Sriastradh /* According to ARB_framebuffer_sRGB, we should return LINEAR 42613464ebd5Sriastradh * if the sRGB conversion is unsupported. */ 42623464ebd5Sriastradh *params = GL_LINEAR; 42633464ebd5Sriastradh } 42644a49301eSmrg } 42654a49301eSmrg return; 42664a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: 4267af69d88dSmrg if ((ctx->API != API_OPENGL_COMPAT || 4268af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 4269af69d88dSmrg && ctx->API != API_OPENGL_CORE 4270af69d88dSmrg && !_mesa_is_gles3(ctx)) { 4271af69d88dSmrg goto invalid_pname_enum; 42724a49301eSmrg } 42733464ebd5Sriastradh else if (att->Type == GL_NONE) { 427401e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 427501e04c3fSmrg _mesa_enum_to_string(pname)); 42763464ebd5Sriastradh } 42774a49301eSmrg else { 4278af69d88dSmrg mesa_format format = att->Renderbuffer->Format; 4279af69d88dSmrg 4280af69d88dSmrg /* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES 4281af69d88dSmrg * 3.0.1 spec says: 4282af69d88dSmrg * 4283af69d88dSmrg * "If pname is FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE.... If 4284af69d88dSmrg * attachment is DEPTH_STENCIL_ATTACHMENT the query will fail and 4285af69d88dSmrg * generate an INVALID_OPERATION error. 4286af69d88dSmrg */ 4287af69d88dSmrg if (_mesa_is_gles3(ctx) && 4288af69d88dSmrg attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 4289af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 429001e04c3fSmrg "%s(cannot query " 4291af69d88dSmrg "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of " 429201e04c3fSmrg "GL_DEPTH_STENCIL_ATTACHMENT)", caller); 4293af69d88dSmrg return; 4294af69d88dSmrg } 4295af69d88dSmrg 4296af69d88dSmrg if (format == MESA_FORMAT_S_UINT8) { 42974a49301eSmrg /* special cases */ 42984a49301eSmrg *params = GL_INDEX; 42994a49301eSmrg } 4300af69d88dSmrg else if (format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) { 4301af69d88dSmrg /* depends on the attachment parameter */ 4302af69d88dSmrg if (attachment == GL_STENCIL_ATTACHMENT) { 4303af69d88dSmrg *params = GL_INDEX; 4304af69d88dSmrg } 4305af69d88dSmrg else { 4306af69d88dSmrg *params = GL_FLOAT; 4307af69d88dSmrg } 4308af69d88dSmrg } 43094a49301eSmrg else { 43104a49301eSmrg *params = _mesa_get_format_datatype(format); 43114a49301eSmrg } 43124a49301eSmrg } 43134a49301eSmrg return; 43144a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: 43154a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 43164a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 43174a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 43184a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 43194a49301eSmrg case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 4320af69d88dSmrg if ((!_mesa_is_desktop_gl(ctx) || 4321af69d88dSmrg !ctx->Extensions.ARB_framebuffer_object) 4322af69d88dSmrg && !_mesa_is_gles3(ctx)) { 4323af69d88dSmrg goto invalid_pname_enum; 43244a49301eSmrg } 43254a49301eSmrg else if (att->Texture) { 43264a49301eSmrg const struct gl_texture_image *texImage = 432701e04c3fSmrg _mesa_select_tex_image(att->Texture, att->Texture->Target, 43284a49301eSmrg att->TextureLevel); 43294a49301eSmrg if (texImage) { 43304a49301eSmrg *params = get_component_bits(pname, texImage->_BaseFormat, 43314a49301eSmrg texImage->TexFormat); 43324a49301eSmrg } 43334a49301eSmrg else { 43344a49301eSmrg *params = 0; 43354a49301eSmrg } 43364a49301eSmrg } 43374a49301eSmrg else if (att->Renderbuffer) { 43384a49301eSmrg *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, 43394a49301eSmrg att->Renderbuffer->Format); 43404a49301eSmrg } 43414a49301eSmrg else { 434201e04c3fSmrg assert(att->Type == GL_NONE); 434301e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 434401e04c3fSmrg _mesa_enum_to_string(pname)); 43454a49301eSmrg } 43464a49301eSmrg return; 4347af69d88dSmrg case GL_FRAMEBUFFER_ATTACHMENT_LAYERED: 4348af69d88dSmrg if (!_mesa_has_geometry_shaders(ctx)) { 4349af69d88dSmrg goto invalid_pname_enum; 4350af69d88dSmrg } else if (att->Type == GL_TEXTURE) { 4351af69d88dSmrg *params = att->Layered; 4352af69d88dSmrg } else if (att->Type == GL_NONE) { 435301e04c3fSmrg _mesa_error(ctx, err, "%s(invalid pname %s)", caller, 435401e04c3fSmrg _mesa_enum_to_string(pname)); 4355af69d88dSmrg } else { 4356af69d88dSmrg goto invalid_pname_enum; 4357af69d88dSmrg } 43587117f1b4Smrg return; 4359af69d88dSmrg default: 4360af69d88dSmrg goto invalid_pname_enum; 43617117f1b4Smrg } 4362af69d88dSmrg 4363af69d88dSmrg return; 4364af69d88dSmrg 4365af69d88dSmrginvalid_pname_enum: 436601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname %s)", caller, 436701e04c3fSmrg _mesa_enum_to_string(pname)); 4368af69d88dSmrg return; 43697117f1b4Smrg} 43707117f1b4Smrg 43717117f1b4Smrg 437201e04c3fSmrgvoid GLAPIENTRY 437301e04c3fSmrg_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, 437401e04c3fSmrg GLenum pname, GLint *params) 437501e04c3fSmrg{ 437601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 437701e04c3fSmrg struct gl_framebuffer *buffer; 437801e04c3fSmrg 437901e04c3fSmrg buffer = get_framebuffer_target(ctx, target); 438001e04c3fSmrg if (!buffer) { 438101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 438201e04c3fSmrg "glGetFramebufferAttachmentParameteriv(invalid target %s)", 438301e04c3fSmrg _mesa_enum_to_string(target)); 438401e04c3fSmrg return; 438501e04c3fSmrg } 438601e04c3fSmrg 438701e04c3fSmrg get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, 438801e04c3fSmrg params, 438901e04c3fSmrg "glGetFramebufferAttachmentParameteriv"); 439001e04c3fSmrg} 439101e04c3fSmrg 439201e04c3fSmrg 439301e04c3fSmrgvoid GLAPIENTRY 439401e04c3fSmrg_mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, 439501e04c3fSmrg GLenum attachment, 439601e04c3fSmrg GLenum pname, GLint *params) 439701e04c3fSmrg{ 439801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 439901e04c3fSmrg struct gl_framebuffer *buffer; 440001e04c3fSmrg 440101e04c3fSmrg if (framebuffer) { 440201e04c3fSmrg buffer = _mesa_lookup_framebuffer_err(ctx, framebuffer, 440301e04c3fSmrg "glGetNamedFramebufferAttachmentParameteriv"); 440401e04c3fSmrg if (!buffer) 440501e04c3fSmrg return; 440601e04c3fSmrg } 440701e04c3fSmrg else { 440801e04c3fSmrg /* 440901e04c3fSmrg * Section 9.2 Binding and Managing Framebuffer Objects of the OpenGL 441001e04c3fSmrg * 4.5 core spec (30.10.2014, PDF page 314): 441101e04c3fSmrg * "If framebuffer is zero, then the default draw framebuffer is 441201e04c3fSmrg * queried." 441301e04c3fSmrg */ 441401e04c3fSmrg buffer = ctx->WinSysDrawBuffer; 441501e04c3fSmrg } 441601e04c3fSmrg 441701e04c3fSmrg get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, 441801e04c3fSmrg params, 441901e04c3fSmrg "glGetNamedFramebufferAttachmentParameteriv"); 442001e04c3fSmrg} 442101e04c3fSmrg 442201e04c3fSmrg 442301e04c3fSmrgvoid GLAPIENTRY 442401e04c3fSmrg_mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, 442501e04c3fSmrg GLint param) 442601e04c3fSmrg{ 442701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 442801e04c3fSmrg struct gl_framebuffer *fb = NULL; 442901e04c3fSmrg 443001e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments && 443101e04c3fSmrg !ctx->Extensions.ARB_sample_locations) { 443201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 443301e04c3fSmrg "glNamedFramebufferParameteri(" 443401e04c3fSmrg "neither ARB_framebuffer_no_attachments nor " 443501e04c3fSmrg "ARB_sample_locations is available)"); 443601e04c3fSmrg return; 443701e04c3fSmrg } 443801e04c3fSmrg 443901e04c3fSmrg if (framebuffer) { 444001e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 444101e04c3fSmrg "glNamedFramebufferParameteri"); 444201e04c3fSmrg } else { 444301e04c3fSmrg fb = ctx->WinSysDrawBuffer; 444401e04c3fSmrg } 444501e04c3fSmrg 444601e04c3fSmrg if (fb) { 444701e04c3fSmrg framebuffer_parameteri(ctx, fb, pname, param, 444801e04c3fSmrg "glNamedFramebufferParameteriv"); 444901e04c3fSmrg } 445001e04c3fSmrg} 445101e04c3fSmrg 445201e04c3fSmrg 445301e04c3fSmrgvoid GLAPIENTRY 445401e04c3fSmrg_mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, 445501e04c3fSmrg GLint *param) 445601e04c3fSmrg{ 445701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 445801e04c3fSmrg struct gl_framebuffer *fb; 445901e04c3fSmrg 446001e04c3fSmrg if (!ctx->Extensions.ARB_framebuffer_no_attachments) { 446101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 446201e04c3fSmrg "glNamedFramebufferParameteriv(" 446301e04c3fSmrg "neither ARB_framebuffer_no_attachments nor ARB_sample_locations" 446401e04c3fSmrg " is available)"); 446501e04c3fSmrg return; 446601e04c3fSmrg } 446701e04c3fSmrg 446801e04c3fSmrg if (framebuffer) 446901e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 447001e04c3fSmrg "glGetNamedFramebufferParameteriv"); 447101e04c3fSmrg else 447201e04c3fSmrg fb = ctx->WinSysDrawBuffer; 447301e04c3fSmrg 447401e04c3fSmrg if (fb) { 447501e04c3fSmrg get_framebuffer_parameteriv(ctx, fb, pname, param, 447601e04c3fSmrg "glGetNamedFramebufferParameteriv"); 447701e04c3fSmrg } 447801e04c3fSmrg} 447901e04c3fSmrg 448001e04c3fSmrg 4481af69d88dSmrgstatic void 448201e04c3fSmrginvalidate_framebuffer_storage(struct gl_context *ctx, 448301e04c3fSmrg struct gl_framebuffer *fb, 448401e04c3fSmrg GLsizei numAttachments, 4485af69d88dSmrg const GLenum *attachments, GLint x, GLint y, 4486af69d88dSmrg GLsizei width, GLsizei height, const char *name) 44877117f1b4Smrg{ 4488af69d88dSmrg int i; 44897117f1b4Smrg 449001e04c3fSmrg /* Section 17.4 Whole Framebuffer Operations of the OpenGL 4.5 Core 449101e04c3fSmrg * Spec (2.2.2015, PDF page 522) says: 449201e04c3fSmrg * "An INVALID_VALUE error is generated if numAttachments, width, or 449301e04c3fSmrg * height is negative." 449401e04c3fSmrg */ 449501e04c3fSmrg if (numAttachments < 0) { 449601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 449701e04c3fSmrg "%s(numAttachments < 0)", name); 44987117f1b4Smrg return; 44997117f1b4Smrg } 45007117f1b4Smrg 450101e04c3fSmrg if (width < 0) { 4502af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 450301e04c3fSmrg "%s(width < 0)", name); 450401e04c3fSmrg return; 450501e04c3fSmrg } 450601e04c3fSmrg 450701e04c3fSmrg if (height < 0) { 450801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 450901e04c3fSmrg "%s(height < 0)", name); 45104a49301eSmrg return; 45114a49301eSmrg } 45127117f1b4Smrg 4513af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 4514af69d88dSmrg * 4515af69d88dSmrg * "If an attachment is specified that does not exist in the 4516af69d88dSmrg * framebuffer bound to <target>, it is ignored." 4517af69d88dSmrg * 4518af69d88dSmrg * It also says: 4519af69d88dSmrg * 4520af69d88dSmrg * "If <attachments> contains COLOR_ATTACHMENTm and m is greater than 4521af69d88dSmrg * or equal to the value of MAX_COLOR_ATTACHMENTS, then the error 4522af69d88dSmrg * INVALID_OPERATION is generated." 4523af69d88dSmrg * 4524af69d88dSmrg * No mention is made of GL_AUXi being out of range. Therefore, we allow 4525af69d88dSmrg * any enum that can be allowed by the API (OpenGL ES 3.0 has a different 4526af69d88dSmrg * set of retrictions). 4527af69d88dSmrg */ 4528af69d88dSmrg for (i = 0; i < numAttachments; i++) { 4529af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) { 4530af69d88dSmrg switch (attachments[i]) { 4531af69d88dSmrg case GL_ACCUM: 4532af69d88dSmrg case GL_AUX0: 4533af69d88dSmrg case GL_AUX1: 4534af69d88dSmrg case GL_AUX2: 4535af69d88dSmrg case GL_AUX3: 4536af69d88dSmrg /* Accumulation buffers and auxilary buffers were removed in 4537af69d88dSmrg * OpenGL 3.1, and they never existed in OpenGL ES. 4538af69d88dSmrg */ 4539af69d88dSmrg if (ctx->API != API_OPENGL_COMPAT) 4540af69d88dSmrg goto invalid_enum; 4541af69d88dSmrg break; 4542af69d88dSmrg case GL_COLOR: 4543af69d88dSmrg case GL_DEPTH: 4544af69d88dSmrg case GL_STENCIL: 4545af69d88dSmrg break; 4546af69d88dSmrg case GL_BACK_LEFT: 4547af69d88dSmrg case GL_BACK_RIGHT: 4548af69d88dSmrg case GL_FRONT_LEFT: 4549af69d88dSmrg case GL_FRONT_RIGHT: 4550af69d88dSmrg if (!_mesa_is_desktop_gl(ctx)) 4551af69d88dSmrg goto invalid_enum; 4552af69d88dSmrg break; 4553af69d88dSmrg default: 4554af69d88dSmrg goto invalid_enum; 4555af69d88dSmrg } 4556af69d88dSmrg } else { 4557af69d88dSmrg switch (attachments[i]) { 4558af69d88dSmrg case GL_DEPTH_ATTACHMENT: 4559af69d88dSmrg case GL_STENCIL_ATTACHMENT: 4560af69d88dSmrg break; 456101e04c3fSmrg case GL_DEPTH_STENCIL_ATTACHMENT: 456201e04c3fSmrg /* GL_DEPTH_STENCIL_ATTACHMENT is a valid attachment point only 456301e04c3fSmrg * in desktop and ES 3.0 profiles. Note that OES_packed_depth_stencil 456401e04c3fSmrg * extension does not make this attachment point valid on ES 2.0. 456501e04c3fSmrg */ 456601e04c3fSmrg if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) 456701e04c3fSmrg break; 456801e04c3fSmrg /* fallthrough */ 4569af69d88dSmrg case GL_COLOR_ATTACHMENT0: 4570af69d88dSmrg case GL_COLOR_ATTACHMENT1: 4571af69d88dSmrg case GL_COLOR_ATTACHMENT2: 4572af69d88dSmrg case GL_COLOR_ATTACHMENT3: 4573af69d88dSmrg case GL_COLOR_ATTACHMENT4: 4574af69d88dSmrg case GL_COLOR_ATTACHMENT5: 4575af69d88dSmrg case GL_COLOR_ATTACHMENT6: 4576af69d88dSmrg case GL_COLOR_ATTACHMENT7: 4577af69d88dSmrg case GL_COLOR_ATTACHMENT8: 4578af69d88dSmrg case GL_COLOR_ATTACHMENT9: 4579af69d88dSmrg case GL_COLOR_ATTACHMENT10: 4580af69d88dSmrg case GL_COLOR_ATTACHMENT11: 4581af69d88dSmrg case GL_COLOR_ATTACHMENT12: 4582af69d88dSmrg case GL_COLOR_ATTACHMENT13: 4583af69d88dSmrg case GL_COLOR_ATTACHMENT14: 4584af69d88dSmrg case GL_COLOR_ATTACHMENT15: { 4585af69d88dSmrg unsigned k = attachments[i] - GL_COLOR_ATTACHMENT0; 4586af69d88dSmrg if (k >= ctx->Const.MaxColorAttachments) { 4587af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 4588af69d88dSmrg "%s(attachment >= max. color attachments)", name); 4589af69d88dSmrg return; 4590af69d88dSmrg } 4591af69d88dSmrg break; 4592af69d88dSmrg } 4593af69d88dSmrg default: 4594af69d88dSmrg goto invalid_enum; 4595af69d88dSmrg } 4596af69d88dSmrg } 45973464ebd5Sriastradh } 45983464ebd5Sriastradh 4599af69d88dSmrg /* We don't actually do anything for this yet. Just return after 4600af69d88dSmrg * validating the parameters and generating the required errors. 4601af69d88dSmrg */ 4602af69d88dSmrg return; 46037117f1b4Smrg 4604af69d88dSmrginvalid_enum: 460501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", name, 460601e04c3fSmrg _mesa_enum_to_string(attachments[i])); 4607af69d88dSmrg return; 4608af69d88dSmrg} 46097117f1b4Smrg 46104a49301eSmrg 461101e04c3fSmrgvoid GLAPIENTRY 461201e04c3fSmrg_mesa_InvalidateSubFramebuffer_no_error(GLenum target, GLsizei numAttachments, 461301e04c3fSmrg const GLenum *attachments, GLint x, 461401e04c3fSmrg GLint y, GLsizei width, GLsizei height) 461501e04c3fSmrg{ 461601e04c3fSmrg /* no-op */ 461701e04c3fSmrg} 461801e04c3fSmrg 461901e04c3fSmrg 4620af69d88dSmrgvoid GLAPIENTRY 4621af69d88dSmrg_mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, 4622af69d88dSmrg const GLenum *attachments, GLint x, GLint y, 4623af69d88dSmrg GLsizei width, GLsizei height) 46244a49301eSmrg{ 462501e04c3fSmrg struct gl_framebuffer *fb; 462601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 462701e04c3fSmrg 462801e04c3fSmrg fb = get_framebuffer_target(ctx, target); 462901e04c3fSmrg if (!fb) { 463001e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 463101e04c3fSmrg "glInvalidateSubFramebuffer(invalid target %s)", 463201e04c3fSmrg _mesa_enum_to_string(target)); 463301e04c3fSmrg return; 463401e04c3fSmrg } 463501e04c3fSmrg 463601e04c3fSmrg invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 4637af69d88dSmrg x, y, width, height, 4638af69d88dSmrg "glInvalidateSubFramebuffer"); 46394a49301eSmrg} 46404a49301eSmrg 46414a49301eSmrg 464201e04c3fSmrgvoid GLAPIENTRY 464301e04c3fSmrg_mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer, 464401e04c3fSmrg GLsizei numAttachments, 464501e04c3fSmrg const GLenum *attachments, 464601e04c3fSmrg GLint x, GLint y, 464701e04c3fSmrg GLsizei width, GLsizei height) 464801e04c3fSmrg{ 464901e04c3fSmrg struct gl_framebuffer *fb; 465001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 465101e04c3fSmrg 465201e04c3fSmrg /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole 465301e04c3fSmrg * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the 465401e04c3fSmrg * default draw framebuffer is affected." 465501e04c3fSmrg */ 465601e04c3fSmrg if (framebuffer) { 465701e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 465801e04c3fSmrg "glInvalidateNamedFramebufferSubData"); 465901e04c3fSmrg if (!fb) 466001e04c3fSmrg return; 466101e04c3fSmrg } 466201e04c3fSmrg else 466301e04c3fSmrg fb = ctx->WinSysDrawBuffer; 466401e04c3fSmrg 466501e04c3fSmrg invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 466601e04c3fSmrg x, y, width, height, 466701e04c3fSmrg "glInvalidateNamedFramebufferSubData"); 466801e04c3fSmrg} 466901e04c3fSmrg 467001e04c3fSmrg 467101e04c3fSmrgvoid GLAPIENTRY 467201e04c3fSmrg_mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments, 467301e04c3fSmrg const GLenum *attachments) 467401e04c3fSmrg{ 467501e04c3fSmrg /* no-op */ 467601e04c3fSmrg} 467701e04c3fSmrg 467801e04c3fSmrg 46797117f1b4Smrgvoid GLAPIENTRY 4680af69d88dSmrg_mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, 4681af69d88dSmrg const GLenum *attachments) 46827117f1b4Smrg{ 468301e04c3fSmrg struct gl_framebuffer *fb; 468401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 468501e04c3fSmrg 468601e04c3fSmrg fb = get_framebuffer_target(ctx, target); 468701e04c3fSmrg if (!fb) { 468801e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 468901e04c3fSmrg "glInvalidateFramebuffer(invalid target %s)", 469001e04c3fSmrg _mesa_enum_to_string(target)); 469101e04c3fSmrg return; 469201e04c3fSmrg } 469301e04c3fSmrg 4694af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 4695af69d88dSmrg * 4696af69d88dSmrg * "The command 4697af69d88dSmrg * 4698af69d88dSmrg * void InvalidateFramebuffer(enum target, 4699af69d88dSmrg * sizei numAttachments, 4700af69d88dSmrg * const enum *attachments); 4701af69d88dSmrg * 4702af69d88dSmrg * is equivalent to the command InvalidateSubFramebuffer with <x>, <y>, 4703af69d88dSmrg * <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>, 4704af69d88dSmrg * <MAX_VIEWPORT_DIMS[1]> respectively." 4705af69d88dSmrg */ 470601e04c3fSmrg invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 4707af69d88dSmrg 0, 0, 470801e04c3fSmrg ctx->Const.MaxViewportWidth, 470901e04c3fSmrg ctx->Const.MaxViewportHeight, 4710af69d88dSmrg "glInvalidateFramebuffer"); 4711af69d88dSmrg} 47124a49301eSmrg 47133464ebd5Sriastradh 471401e04c3fSmrgvoid GLAPIENTRY 471501e04c3fSmrg_mesa_InvalidateNamedFramebufferData(GLuint framebuffer, 471601e04c3fSmrg GLsizei numAttachments, 471701e04c3fSmrg const GLenum *attachments) 471801e04c3fSmrg{ 471901e04c3fSmrg struct gl_framebuffer *fb; 472001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 472101e04c3fSmrg 472201e04c3fSmrg /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole 472301e04c3fSmrg * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the 472401e04c3fSmrg * default draw framebuffer is affected." 472501e04c3fSmrg */ 472601e04c3fSmrg if (framebuffer) { 472701e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 472801e04c3fSmrg "glInvalidateNamedFramebufferData"); 472901e04c3fSmrg if (!fb) 473001e04c3fSmrg return; 473101e04c3fSmrg } 473201e04c3fSmrg else 473301e04c3fSmrg fb = ctx->WinSysDrawBuffer; 473401e04c3fSmrg 473501e04c3fSmrg /* The GL_ARB_invalidate_subdata spec says: 473601e04c3fSmrg * 473701e04c3fSmrg * "The command 473801e04c3fSmrg * 473901e04c3fSmrg * void InvalidateFramebuffer(enum target, 474001e04c3fSmrg * sizei numAttachments, 474101e04c3fSmrg * const enum *attachments); 474201e04c3fSmrg * 474301e04c3fSmrg * is equivalent to the command InvalidateSubFramebuffer with <x>, <y>, 474401e04c3fSmrg * <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>, 474501e04c3fSmrg * <MAX_VIEWPORT_DIMS[1]> respectively." 474601e04c3fSmrg */ 474701e04c3fSmrg invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 474801e04c3fSmrg 0, 0, 474901e04c3fSmrg ctx->Const.MaxViewportWidth, 475001e04c3fSmrg ctx->Const.MaxViewportHeight, 475101e04c3fSmrg "glInvalidateNamedFramebufferData"); 475201e04c3fSmrg} 475301e04c3fSmrg 475401e04c3fSmrg 4755af69d88dSmrgvoid GLAPIENTRY 4756af69d88dSmrg_mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, 4757af69d88dSmrg const GLenum *attachments) 4758af69d88dSmrg{ 4759af69d88dSmrg struct gl_framebuffer *fb; 4760af69d88dSmrg GLint i; 47613464ebd5Sriastradh 4762af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 47637117f1b4Smrg 4764af69d88dSmrg fb = get_framebuffer_target(ctx, target); 4765af69d88dSmrg if (!fb) { 4766af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 4767af69d88dSmrg "glDiscardFramebufferEXT(target %s)", 476801e04c3fSmrg _mesa_enum_to_string(target)); 47694a49301eSmrg return; 47704a49301eSmrg } 47714a49301eSmrg 4772af69d88dSmrg if (numAttachments < 0) { 4773af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 4774af69d88dSmrg "glDiscardFramebufferEXT(numAttachments < 0)"); 47757117f1b4Smrg return; 47767117f1b4Smrg } 47777117f1b4Smrg 4778af69d88dSmrg for (i = 0; i < numAttachments; i++) { 4779af69d88dSmrg switch (attachments[i]) { 4780af69d88dSmrg case GL_COLOR: 4781af69d88dSmrg case GL_DEPTH: 4782af69d88dSmrg case GL_STENCIL: 4783af69d88dSmrg if (_mesa_is_user_fbo(fb)) 4784af69d88dSmrg goto invalid_enum; 4785af69d88dSmrg break; 4786af69d88dSmrg case GL_COLOR_ATTACHMENT0: 4787af69d88dSmrg case GL_DEPTH_ATTACHMENT: 4788af69d88dSmrg case GL_STENCIL_ATTACHMENT: 4789af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) 4790af69d88dSmrg goto invalid_enum; 4791af69d88dSmrg break; 4792af69d88dSmrg default: 4793af69d88dSmrg goto invalid_enum; 47944a49301eSmrg } 47954a49301eSmrg } 47964a49301eSmrg 4797af69d88dSmrg if (ctx->Driver.DiscardFramebuffer) 4798af69d88dSmrg ctx->Driver.DiscardFramebuffer(ctx, target, numAttachments, attachments); 47993464ebd5Sriastradh 4800af69d88dSmrg return; 48013464ebd5Sriastradh 4802af69d88dSmrginvalid_enum: 4803af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 4804af69d88dSmrg "glDiscardFramebufferEXT(attachment %s)", 480501e04c3fSmrg _mesa_enum_to_string(attachments[i])); 480601e04c3fSmrg} 480701e04c3fSmrg 480801e04c3fSmrgstatic void 480901e04c3fSmrgsample_locations(struct gl_context *ctx, struct gl_framebuffer *fb, 481001e04c3fSmrg GLuint start, GLsizei count, const GLfloat *v, bool no_error, 481101e04c3fSmrg const char *name) 481201e04c3fSmrg{ 481301e04c3fSmrg GLsizei i; 481401e04c3fSmrg 481501e04c3fSmrg if (!no_error) { 481601e04c3fSmrg if (!ctx->Extensions.ARB_sample_locations) { 481701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 481801e04c3fSmrg "%s not supported " 481901e04c3fSmrg "(ARB_sample_locations not available)", name); 482001e04c3fSmrg return; 482101e04c3fSmrg } 482201e04c3fSmrg 482301e04c3fSmrg if (start + count > MAX_SAMPLE_LOCATION_TABLE_SIZE) { 482401e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 482501e04c3fSmrg "%s(start+size > sample location table size)", name); 482601e04c3fSmrg return; 482701e04c3fSmrg } 482801e04c3fSmrg } 482901e04c3fSmrg 483001e04c3fSmrg if (!fb->SampleLocationTable) { 483101e04c3fSmrg size_t size = MAX_SAMPLE_LOCATION_TABLE_SIZE * 2 * sizeof(GLfloat); 483201e04c3fSmrg fb->SampleLocationTable = malloc(size); 483301e04c3fSmrg if (!fb->SampleLocationTable) { 483401e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 483501e04c3fSmrg "Cannot allocate sample location table"); 483601e04c3fSmrg return; 483701e04c3fSmrg } 483801e04c3fSmrg for (i = 0; i < MAX_SAMPLE_LOCATION_TABLE_SIZE * 2; i++) 483901e04c3fSmrg fb->SampleLocationTable[i] = 0.5f; 484001e04c3fSmrg } 484101e04c3fSmrg 484201e04c3fSmrg for (i = 0; i < count * 2; i++) { 484301e04c3fSmrg /* The ARB_sample_locations spec says: 484401e04c3fSmrg * 484501e04c3fSmrg * Sample locations outside of [0,1] result in undefined 484601e04c3fSmrg * behavior. 484701e04c3fSmrg * 484801e04c3fSmrg * To simplify driver implementations, we choose to clamp to 484901e04c3fSmrg * [0,1] and change NaN into 0.5. 485001e04c3fSmrg */ 485101e04c3fSmrg if (isnan(v[i]) || v[i] < 0.0f || v[i] > 1.0f) { 485201e04c3fSmrg static GLuint msg_id = 0; 485301e04c3fSmrg static const char* msg = "Invalid sample location specified"; 485401e04c3fSmrg _mesa_debug_get_id(&msg_id); 485501e04c3fSmrg 485601e04c3fSmrg _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_UNDEFINED, 485701e04c3fSmrg msg_id, MESA_DEBUG_SEVERITY_HIGH, strlen(msg), msg); 485801e04c3fSmrg } 485901e04c3fSmrg 486001e04c3fSmrg if (isnan(v[i])) 486101e04c3fSmrg fb->SampleLocationTable[start * 2 + i] = 0.5f; 486201e04c3fSmrg else 486301e04c3fSmrg fb->SampleLocationTable[start * 2 + i] = CLAMP(v[i], 0.0f, 1.0f); 486401e04c3fSmrg } 486501e04c3fSmrg 486601e04c3fSmrg if (fb == ctx->DrawBuffer) 486701e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations; 486801e04c3fSmrg} 486901e04c3fSmrg 487001e04c3fSmrgvoid GLAPIENTRY 487101e04c3fSmrg_mesa_FramebufferSampleLocationsfvARB(GLenum target, GLuint start, 487201e04c3fSmrg GLsizei count, const GLfloat *v) 487301e04c3fSmrg{ 487401e04c3fSmrg struct gl_framebuffer *fb; 487501e04c3fSmrg 487601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 487701e04c3fSmrg 487801e04c3fSmrg fb = get_framebuffer_target(ctx, target); 487901e04c3fSmrg if (!fb) { 488001e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 488101e04c3fSmrg "glFramebufferSampleLocationsfvARB(target %s)", 488201e04c3fSmrg _mesa_enum_to_string(target)); 488301e04c3fSmrg return; 488401e04c3fSmrg } 488501e04c3fSmrg 488601e04c3fSmrg sample_locations(ctx, fb, start, count, v, false, 488701e04c3fSmrg "glFramebufferSampleLocationsfvARB"); 488801e04c3fSmrg} 488901e04c3fSmrg 489001e04c3fSmrgvoid GLAPIENTRY 489101e04c3fSmrg_mesa_NamedFramebufferSampleLocationsfvARB(GLuint framebuffer, GLuint start, 489201e04c3fSmrg GLsizei count, const GLfloat *v) 489301e04c3fSmrg{ 489401e04c3fSmrg struct gl_framebuffer *fb; 489501e04c3fSmrg 489601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 489701e04c3fSmrg 489801e04c3fSmrg if (framebuffer) { 489901e04c3fSmrg fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, 490001e04c3fSmrg "glNamedFramebufferSampleLocationsfvARB"); 490101e04c3fSmrg if (!fb) 490201e04c3fSmrg return; 490301e04c3fSmrg } 490401e04c3fSmrg else 490501e04c3fSmrg fb = ctx->WinSysDrawBuffer; 490601e04c3fSmrg 490701e04c3fSmrg sample_locations(ctx, fb, start, count, v, false, 490801e04c3fSmrg "glNamedFramebufferSampleLocationsfvARB"); 490901e04c3fSmrg} 491001e04c3fSmrg 491101e04c3fSmrgvoid GLAPIENTRY 491201e04c3fSmrg_mesa_FramebufferSampleLocationsfvARB_no_error(GLenum target, GLuint start, 491301e04c3fSmrg GLsizei count, const GLfloat *v) 491401e04c3fSmrg{ 491501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 491601e04c3fSmrg sample_locations(ctx, get_framebuffer_target(ctx, target), start, 491701e04c3fSmrg count, v, true, "glFramebufferSampleLocationsfvARB"); 491801e04c3fSmrg} 491901e04c3fSmrg 492001e04c3fSmrgvoid GLAPIENTRY 492101e04c3fSmrg_mesa_NamedFramebufferSampleLocationsfvARB_no_error(GLuint framebuffer, 492201e04c3fSmrg GLuint start, GLsizei count, 492301e04c3fSmrg const GLfloat *v) 492401e04c3fSmrg{ 492501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 492601e04c3fSmrg sample_locations(ctx, _mesa_lookup_framebuffer(ctx, framebuffer), start, 492701e04c3fSmrg count, v, true, "glNamedFramebufferSampleLocationsfvARB"); 492801e04c3fSmrg} 492901e04c3fSmrg 493001e04c3fSmrgvoid GLAPIENTRY 493101e04c3fSmrg_mesa_EvaluateDepthValuesARB(void) 493201e04c3fSmrg{ 493301e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 493401e04c3fSmrg 493501e04c3fSmrg if (!ctx->Extensions.ARB_sample_locations) { 493601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 493701e04c3fSmrg "EvaluateDepthValuesARB not supported (neither " 493801e04c3fSmrg "ARB_sample_locations nor NV_sample_locations is available)"); 493901e04c3fSmrg return; 494001e04c3fSmrg } 494101e04c3fSmrg 494201e04c3fSmrg if (ctx->Driver.EvaluateDepthValues) 494301e04c3fSmrg ctx->Driver.EvaluateDepthValues(ctx); 49443464ebd5Sriastradh} 4945