17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 4c1f859d4Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 57117f1b4Smrg * 67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 87117f1b4Smrg * to deal in the Software without restriction, including without limitation 97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 117117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 127117f1b4Smrg * 137117f1b4Smrg * The above copyright notice and this permission notice shall be included 147117f1b4Smrg * in all copies or substantial portions of the Software. 157117f1b4Smrg * 167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 237117f1b4Smrg */ 247117f1b4Smrg 257117f1b4Smrg 267117f1b4Smrg/** 277117f1b4Smrg * Functions for allocating/managing framebuffers and renderbuffers. 287117f1b4Smrg * Also, routines for reading/writing renderbuffer data as ubytes, 297117f1b4Smrg * ushorts, uints, etc. 307117f1b4Smrg */ 317117f1b4Smrg 3201e04c3fSmrg#include <stdio.h> 337117f1b4Smrg#include "glheader.h" 347ec681f3Smrg 35af69d88dSmrg#include "blend.h" 36c1f859d4Smrg#include "buffers.h" 377117f1b4Smrg#include "context.h" 387ec681f3Smrg#include "draw_validate.h" 393464ebd5Sriastradh#include "enums.h" 404a49301eSmrg#include "formats.h" 414a49301eSmrg#include "macros.h" 427117f1b4Smrg#include "mtypes.h" 437117f1b4Smrg#include "fbobject.h" 447117f1b4Smrg#include "framebuffer.h" 457117f1b4Smrg#include "renderbuffer.h" 467117f1b4Smrg#include "texobj.h" 47af69d88dSmrg#include "glformats.h" 4801e04c3fSmrg#include "state.h" 497ec681f3Smrg#include "util/u_memory.h" 507117f1b4Smrg 517117f1b4Smrg 527117f1b4Smrg 537117f1b4Smrg/** 547117f1b4Smrg * Compute/set the _DepthMax field for the given framebuffer. 557117f1b4Smrg * This value depends on the Z buffer resolution. 567117f1b4Smrg */ 577117f1b4Smrgstatic void 587117f1b4Smrgcompute_depth_max(struct gl_framebuffer *fb) 597117f1b4Smrg{ 607117f1b4Smrg if (fb->Visual.depthBits == 0) { 617117f1b4Smrg /* Special case. Even if we don't have a depth buffer we need 627117f1b4Smrg * good values for DepthMax for Z vertex transformation purposes 637117f1b4Smrg * and for per-fragment fog computation. 647117f1b4Smrg */ 657117f1b4Smrg fb->_DepthMax = (1 << 16) - 1; 667117f1b4Smrg } 677117f1b4Smrg else if (fb->Visual.depthBits < 32) { 687117f1b4Smrg fb->_DepthMax = (1 << fb->Visual.depthBits) - 1; 697117f1b4Smrg } 707117f1b4Smrg else { 717117f1b4Smrg /* Special case since shift values greater than or equal to the 727117f1b4Smrg * number of bits in the left hand expression's type are undefined. 737117f1b4Smrg */ 747117f1b4Smrg fb->_DepthMax = 0xffffffff; 757117f1b4Smrg } 767117f1b4Smrg fb->_DepthMaxF = (GLfloat) fb->_DepthMax; 77c1f859d4Smrg 78c1f859d4Smrg /* Minimum resolvable depth value, for polygon offset */ 79c1f859d4Smrg fb->_MRD = (GLfloat)1.0 / fb->_DepthMaxF; 807117f1b4Smrg} 817117f1b4Smrg 827117f1b4Smrg/** 837117f1b4Smrg * Allocate a new gl_framebuffer object. 847117f1b4Smrg * This is the default function for ctx->Driver.NewFramebuffer(). 857117f1b4Smrg * This is for allocating user-created framebuffers, not window-system 867117f1b4Smrg * framebuffers! 877117f1b4Smrg */ 887117f1b4Smrgstruct gl_framebuffer * 893464ebd5Sriastradh_mesa_new_framebuffer(struct gl_context *ctx, GLuint name) 907117f1b4Smrg{ 917117f1b4Smrg struct gl_framebuffer *fb; 927117f1b4Smrg (void) ctx; 937117f1b4Smrg assert(name != 0); 947117f1b4Smrg fb = CALLOC_STRUCT(gl_framebuffer); 957117f1b4Smrg if (fb) { 96cdc920a0Smrg _mesa_initialize_user_framebuffer(fb, name); 977117f1b4Smrg } 987117f1b4Smrg return fb; 997117f1b4Smrg} 1007117f1b4Smrg 1017117f1b4Smrg 1027117f1b4Smrg/** 1037117f1b4Smrg * Initialize a gl_framebuffer object. Typically used to initialize 1047117f1b4Smrg * window system-created framebuffers, not user-created framebuffers. 105cdc920a0Smrg * \sa _mesa_initialize_user_framebuffer 1067117f1b4Smrg */ 1077117f1b4Smrgvoid 108cdc920a0Smrg_mesa_initialize_window_framebuffer(struct gl_framebuffer *fb, 1093464ebd5Sriastradh const struct gl_config *visual) 1107117f1b4Smrg{ 1117117f1b4Smrg assert(fb); 1127117f1b4Smrg assert(visual); 1137117f1b4Smrg 114cdc920a0Smrg memset(fb, 0, sizeof(struct gl_framebuffer)); 1157117f1b4Smrg 11601e04c3fSmrg simple_mtx_init(&fb->Mutex, mtx_plain); 1177117f1b4Smrg 1187117f1b4Smrg fb->RefCount = 1; 1197117f1b4Smrg 1207117f1b4Smrg /* save the visual */ 1217117f1b4Smrg fb->Visual = *visual; 1227117f1b4Smrg 123c1f859d4Smrg /* Init read/draw renderbuffer state */ 1247117f1b4Smrg if (visual->doubleBufferMode) { 125c1f859d4Smrg fb->_NumColorDrawBuffers = 1; 1267117f1b4Smrg fb->ColorDrawBuffer[0] = GL_BACK; 127c1f859d4Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_BACK_LEFT; 1287117f1b4Smrg fb->ColorReadBuffer = GL_BACK; 1297117f1b4Smrg fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT; 1307117f1b4Smrg } 1317117f1b4Smrg else { 132c1f859d4Smrg fb->_NumColorDrawBuffers = 1; 1337117f1b4Smrg fb->ColorDrawBuffer[0] = GL_FRONT; 134c1f859d4Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_FRONT_LEFT; 1357117f1b4Smrg fb->ColorReadBuffer = GL_FRONT; 1367117f1b4Smrg fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT; 1377117f1b4Smrg } 1387117f1b4Smrg 1397117f1b4Smrg fb->Delete = _mesa_destroy_framebuffer; 1407117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 141af69d88dSmrg fb->_AllColorBuffersFixedPoint = !visual->floatMode; 142af69d88dSmrg fb->_HasSNormOrFloatColorBuffer = visual->floatMode; 14301e04c3fSmrg fb->_HasAttachments = true; 14401e04c3fSmrg fb->FlipY = true; 14501e04c3fSmrg 14601e04c3fSmrg fb->SampleLocationTable = NULL; 14701e04c3fSmrg fb->ProgrammableSampleLocations = 0; 14801e04c3fSmrg fb->SampleLocationPixelGrid = 0; 1497117f1b4Smrg 1507117f1b4Smrg compute_depth_max(fb); 1517117f1b4Smrg} 1527117f1b4Smrg 1537117f1b4Smrg 154cdc920a0Smrg/** 155cdc920a0Smrg * Initialize a user-created gl_framebuffer object. 156cdc920a0Smrg * \sa _mesa_initialize_window_framebuffer 157cdc920a0Smrg */ 158cdc920a0Smrgvoid 159cdc920a0Smrg_mesa_initialize_user_framebuffer(struct gl_framebuffer *fb, GLuint name) 160cdc920a0Smrg{ 161cdc920a0Smrg assert(fb); 162cdc920a0Smrg assert(name); 163cdc920a0Smrg 164cdc920a0Smrg memset(fb, 0, sizeof(struct gl_framebuffer)); 165cdc920a0Smrg 166cdc920a0Smrg fb->Name = name; 167cdc920a0Smrg fb->RefCount = 1; 168cdc920a0Smrg fb->_NumColorDrawBuffers = 1; 169cdc920a0Smrg fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT; 170cdc920a0Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_COLOR0; 171cdc920a0Smrg fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT; 172cdc920a0Smrg fb->_ColorReadBufferIndex = BUFFER_COLOR0; 17301e04c3fSmrg fb->SampleLocationTable = NULL; 17401e04c3fSmrg fb->ProgrammableSampleLocations = 0; 17501e04c3fSmrg fb->SampleLocationPixelGrid = 0; 176cdc920a0Smrg fb->Delete = _mesa_destroy_framebuffer; 17701e04c3fSmrg simple_mtx_init(&fb->Mutex, mtx_plain); 178cdc920a0Smrg} 179cdc920a0Smrg 180cdc920a0Smrg 1817117f1b4Smrg/** 1827117f1b4Smrg * Deallocate buffer and everything attached to it. 1837117f1b4Smrg * Typically called via the gl_framebuffer->Delete() method. 1847117f1b4Smrg */ 1857117f1b4Smrgvoid 1867117f1b4Smrg_mesa_destroy_framebuffer(struct gl_framebuffer *fb) 1877117f1b4Smrg{ 1887117f1b4Smrg if (fb) { 1897117f1b4Smrg _mesa_free_framebuffer_data(fb); 190af69d88dSmrg free(fb->Label); 191cdc920a0Smrg free(fb); 1927117f1b4Smrg } 1937117f1b4Smrg} 1947117f1b4Smrg 1957117f1b4Smrg 1967117f1b4Smrg/** 1977117f1b4Smrg * Free all the data hanging off the given gl_framebuffer, but don't free 1987117f1b4Smrg * the gl_framebuffer object itself. 1997117f1b4Smrg */ 2007117f1b4Smrgvoid 2017117f1b4Smrg_mesa_free_framebuffer_data(struct gl_framebuffer *fb) 2027117f1b4Smrg{ 2037117f1b4Smrg assert(fb); 2047117f1b4Smrg assert(fb->RefCount == 0); 2057117f1b4Smrg 20601e04c3fSmrg simple_mtx_destroy(&fb->Mutex); 2077117f1b4Smrg 20801e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 2097117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 2107117f1b4Smrg if (att->Renderbuffer) { 2117117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 2127117f1b4Smrg } 2137117f1b4Smrg if (att->Texture) { 2147117f1b4Smrg _mesa_reference_texobj(&att->Texture, NULL); 2157117f1b4Smrg } 21601e04c3fSmrg assert(!att->Renderbuffer); 21701e04c3fSmrg assert(!att->Texture); 2187117f1b4Smrg att->Type = GL_NONE; 2197117f1b4Smrg } 22001e04c3fSmrg 22101e04c3fSmrg free(fb->SampleLocationTable); 22201e04c3fSmrg fb->SampleLocationTable = NULL; 2237117f1b4Smrg} 2247117f1b4Smrg 2257117f1b4Smrg 2267117f1b4Smrg/** 2277117f1b4Smrg * Set *ptr to point to fb, with refcounting and locking. 228af69d88dSmrg * This is normally only called from the _mesa_reference_framebuffer() macro 229af69d88dSmrg * when there's a real pointer change. 2307117f1b4Smrg */ 2317117f1b4Smrgvoid 232af69d88dSmrg_mesa_reference_framebuffer_(struct gl_framebuffer **ptr, 233af69d88dSmrg struct gl_framebuffer *fb) 2347117f1b4Smrg{ 2354a49301eSmrg if (*ptr) { 2364a49301eSmrg /* unreference old renderbuffer */ 2377117f1b4Smrg GLboolean deleteFlag = GL_FALSE; 2384a49301eSmrg struct gl_framebuffer *oldFb = *ptr; 2397117f1b4Smrg 24001e04c3fSmrg simple_mtx_lock(&oldFb->Mutex); 24101e04c3fSmrg assert(oldFb->RefCount > 0); 2424a49301eSmrg oldFb->RefCount--; 2434a49301eSmrg deleteFlag = (oldFb->RefCount == 0); 24401e04c3fSmrg simple_mtx_unlock(&oldFb->Mutex); 24501e04c3fSmrg 2467117f1b4Smrg if (deleteFlag) 2474a49301eSmrg oldFb->Delete(oldFb); 2487117f1b4Smrg 2494a49301eSmrg *ptr = NULL; 2507117f1b4Smrg } 2517117f1b4Smrg 2524a49301eSmrg if (fb) { 25301e04c3fSmrg simple_mtx_lock(&fb->Mutex); 2544a49301eSmrg fb->RefCount++; 25501e04c3fSmrg simple_mtx_unlock(&fb->Mutex); 2564a49301eSmrg *ptr = fb; 2574a49301eSmrg } 2584a49301eSmrg} 2597117f1b4Smrg 2607117f1b4Smrg 2617117f1b4Smrg/** 2627117f1b4Smrg * Resize the given framebuffer's renderbuffers to the new width and height. 2637117f1b4Smrg * This should only be used for window-system framebuffers, not 2647117f1b4Smrg * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). 26501e04c3fSmrg * This will typically be called directly from a device driver. 2667117f1b4Smrg * 2677117f1b4Smrg * \note it's possible for ctx to be null since a window can be resized 2687117f1b4Smrg * without a currently bound rendering context. 2697117f1b4Smrg */ 2707117f1b4Smrgvoid 2713464ebd5Sriastradh_mesa_resize_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 2727117f1b4Smrg GLuint width, GLuint height) 2737117f1b4Smrg{ 2747117f1b4Smrg /* XXX I think we could check if the size is not changing 2757117f1b4Smrg * and return early. 2767117f1b4Smrg */ 2777117f1b4Smrg 278af69d88dSmrg /* Can only resize win-sys framebuffer objects */ 279af69d88dSmrg assert(_mesa_is_winsys_fbo(fb)); 2807117f1b4Smrg 28101e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 2827117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 2837117f1b4Smrg if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 2847117f1b4Smrg struct gl_renderbuffer *rb = att->Renderbuffer; 2857117f1b4Smrg /* only resize if size is changing */ 2867117f1b4Smrg if (rb->Width != width || rb->Height != height) { 2877117f1b4Smrg if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 28801e04c3fSmrg assert(rb->Width == width); 28901e04c3fSmrg assert(rb->Height == height); 2907117f1b4Smrg } 2917117f1b4Smrg else { 2927117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 2937117f1b4Smrg /* no return */ 2947117f1b4Smrg } 2957117f1b4Smrg } 2967117f1b4Smrg } 2977117f1b4Smrg } 2987117f1b4Smrg 2997117f1b4Smrg fb->Width = width; 3007117f1b4Smrg fb->Height = height; 3017117f1b4Smrg 3027117f1b4Smrg if (ctx) { 3037117f1b4Smrg /* update scissor / window bounds */ 30401e04c3fSmrg _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); 3057117f1b4Smrg /* Signal new buffer state so that swrast will update its clipping 3067117f1b4Smrg * info (the CLIP_BIT flag). 3077117f1b4Smrg */ 3087117f1b4Smrg ctx->NewState |= _NEW_BUFFERS; 3097117f1b4Smrg } 3107117f1b4Smrg} 3117117f1b4Smrg 3127117f1b4Smrg/** 31301e04c3fSmrg * Given a bounding box, intersect the bounding box with the scissor of 31401e04c3fSmrg * a specified vieport. 315af69d88dSmrg * 316af69d88dSmrg * \param ctx GL context. 317af69d88dSmrg * \param idx Index of the desired viewport 318af69d88dSmrg * \param bbox Bounding box for the scissored viewport. Stored as xmin, 319af69d88dSmrg * xmax, ymin, ymax. 320af69d88dSmrg */ 321af69d88dSmrgvoid 32201e04c3fSmrg_mesa_intersect_scissor_bounding_box(const struct gl_context *ctx, 32301e04c3fSmrg unsigned idx, int *bbox) 324af69d88dSmrg{ 325af69d88dSmrg if (ctx->Scissor.EnableFlags & (1u << idx)) { 326af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].X > bbox[0]) { 327af69d88dSmrg bbox[0] = ctx->Scissor.ScissorArray[idx].X; 328af69d88dSmrg } 329af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].Y > bbox[2]) { 330af69d88dSmrg bbox[2] = ctx->Scissor.ScissorArray[idx].Y; 331af69d88dSmrg } 332af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].X + ctx->Scissor.ScissorArray[idx].Width < bbox[1]) { 333af69d88dSmrg bbox[1] = ctx->Scissor.ScissorArray[idx].X + ctx->Scissor.ScissorArray[idx].Width; 334af69d88dSmrg } 335af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].Y + ctx->Scissor.ScissorArray[idx].Height < bbox[3]) { 336af69d88dSmrg bbox[3] = ctx->Scissor.ScissorArray[idx].Y + ctx->Scissor.ScissorArray[idx].Height; 337af69d88dSmrg } 338af69d88dSmrg /* finally, check for empty region */ 339af69d88dSmrg if (bbox[0] > bbox[1]) { 340af69d88dSmrg bbox[0] = bbox[1]; 341af69d88dSmrg } 342af69d88dSmrg if (bbox[2] > bbox[3]) { 343af69d88dSmrg bbox[2] = bbox[3]; 344af69d88dSmrg } 345af69d88dSmrg } 34601e04c3fSmrg} 347af69d88dSmrg 34801e04c3fSmrg/** 34901e04c3fSmrg * Calculate the inclusive bounding box for the scissor of a specific viewport 35001e04c3fSmrg * 35101e04c3fSmrg * \param ctx GL context. 35201e04c3fSmrg * \param buffer Framebuffer to be checked against 35301e04c3fSmrg * \param idx Index of the desired viewport 35401e04c3fSmrg * \param bbox Bounding box for the scissored viewport. Stored as xmin, 35501e04c3fSmrg * xmax, ymin, ymax. 35601e04c3fSmrg * 35701e04c3fSmrg * \warning This function assumes that the framebuffer dimensions are up to 35801e04c3fSmrg * date. 35901e04c3fSmrg * 36001e04c3fSmrg * \sa _mesa_clip_to_region 36101e04c3fSmrg */ 36201e04c3fSmrgstatic void 36301e04c3fSmrgscissor_bounding_box(const struct gl_context *ctx, 36401e04c3fSmrg const struct gl_framebuffer *buffer, 36501e04c3fSmrg unsigned idx, int *bbox) 36601e04c3fSmrg{ 36701e04c3fSmrg bbox[0] = 0; 36801e04c3fSmrg bbox[2] = 0; 36901e04c3fSmrg bbox[1] = buffer->Width; 37001e04c3fSmrg bbox[3] = buffer->Height; 37101e04c3fSmrg 37201e04c3fSmrg _mesa_intersect_scissor_bounding_box(ctx, idx, bbox); 37301e04c3fSmrg 37401e04c3fSmrg assert(bbox[0] <= bbox[1]); 37501e04c3fSmrg assert(bbox[2] <= bbox[3]); 376af69d88dSmrg} 377af69d88dSmrg 3787117f1b4Smrg/** 3797117f1b4Smrg * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields. 3807117f1b4Smrg * These values are computed from the buffer's width and height and 3817117f1b4Smrg * the scissor box, if it's enabled. 3827117f1b4Smrg * \param ctx the GL context. 3837117f1b4Smrg */ 3847117f1b4Smrgvoid 38501e04c3fSmrg_mesa_update_draw_buffer_bounds(struct gl_context *ctx, 38601e04c3fSmrg struct gl_framebuffer *buffer) 3877117f1b4Smrg{ 388af69d88dSmrg int bbox[4]; 3897117f1b4Smrg 3907117f1b4Smrg if (!buffer) 3917117f1b4Smrg return; 3927117f1b4Smrg 393af69d88dSmrg /* Default to the first scissor as that's always valid */ 39401e04c3fSmrg scissor_bounding_box(ctx, buffer, 0, bbox); 395af69d88dSmrg buffer->_Xmin = bbox[0]; 396af69d88dSmrg buffer->_Ymin = bbox[2]; 397af69d88dSmrg buffer->_Xmax = bbox[1]; 398af69d88dSmrg buffer->_Ymax = bbox[3]; 3997117f1b4Smrg} 4007117f1b4Smrg 4017117f1b4Smrg 4027117f1b4Smrg/** 4037117f1b4Smrg * The glGet queries of the framebuffer red/green/blue size, stencil size, 4047117f1b4Smrg * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can 4057117f1b4Smrg * change depending on the renderbuffer bindings. This function updates 4067117f1b4Smrg * the given framebuffer's Visual from the current renderbuffer bindings. 4077117f1b4Smrg * 4087117f1b4Smrg * This may apply to user-created framebuffers or window system framebuffers. 4097117f1b4Smrg * 4107117f1b4Smrg * Also note: ctx->DrawBuffer->Visual.depthBits might not equal 4117117f1b4Smrg * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. 4127117f1b4Smrg * The former one is used to convert floating point depth values into 4137117f1b4Smrg * integer Z values. 4147117f1b4Smrg */ 4157117f1b4Smrgvoid 4163464ebd5Sriastradh_mesa_update_framebuffer_visual(struct gl_context *ctx, 4173464ebd5Sriastradh struct gl_framebuffer *fb) 4187117f1b4Smrg{ 419cdc920a0Smrg memset(&fb->Visual, 0, sizeof(fb->Visual)); 4207117f1b4Smrg 421cdc920a0Smrg /* find first RGB renderbuffer */ 42201e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 4237117f1b4Smrg if (fb->Attachment[i].Renderbuffer) { 4247117f1b4Smrg const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 4254a49301eSmrg const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); 426af69d88dSmrg const mesa_format fmt = rb->Format; 427af69d88dSmrg 428af69d88dSmrg /* Grab samples and sampleBuffers from any attachment point (assuming 429af69d88dSmrg * the framebuffer is complete, we'll get the same answer from all 430af69d88dSmrg * attachments). 431af69d88dSmrg */ 432af69d88dSmrg fb->Visual.samples = rb->NumSamples; 4333464ebd5Sriastradh 4343464ebd5Sriastradh if (_mesa_is_legal_color_format(ctx, baseFormat)) { 4354a49301eSmrg fb->Visual.redBits = _mesa_get_format_bits(fmt, GL_RED_BITS); 4364a49301eSmrg fb->Visual.greenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); 4374a49301eSmrg fb->Visual.blueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); 4384a49301eSmrg fb->Visual.alphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); 4397ec681f3Smrg fb->Visual.rgbBits = fb->Visual.redBits + fb->Visual.greenBits + 4407ec681f3Smrg fb->Visual.blueBits + fb->Visual.alphaBits; 4417ec681f3Smrg if (_mesa_is_format_srgb(fmt)) 442b9abf16eSmaya fb->Visual.sRGBCapable = ctx->Extensions.EXT_sRGB; 4433464ebd5Sriastradh break; 4443464ebd5Sriastradh } 4453464ebd5Sriastradh } 4463464ebd5Sriastradh } 4473464ebd5Sriastradh 4483464ebd5Sriastradh fb->Visual.floatMode = GL_FALSE; 44901e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 4507ec681f3Smrg if (i == BUFFER_DEPTH) 4517ec681f3Smrg continue; 4523464ebd5Sriastradh if (fb->Attachment[i].Renderbuffer) { 4533464ebd5Sriastradh const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 454af69d88dSmrg const mesa_format fmt = rb->Format; 4553464ebd5Sriastradh 4563464ebd5Sriastradh if (_mesa_get_format_datatype(fmt) == GL_FLOAT) { 4573464ebd5Sriastradh fb->Visual.floatMode = GL_TRUE; 4587117f1b4Smrg break; 4597117f1b4Smrg } 4607117f1b4Smrg } 4617117f1b4Smrg } 4627117f1b4Smrg 4637117f1b4Smrg if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { 4644a49301eSmrg const struct gl_renderbuffer *rb = 4654a49301eSmrg fb->Attachment[BUFFER_DEPTH].Renderbuffer; 466af69d88dSmrg const mesa_format fmt = rb->Format; 4674a49301eSmrg fb->Visual.depthBits = _mesa_get_format_bits(fmt, GL_DEPTH_BITS); 4687117f1b4Smrg } 4697117f1b4Smrg 4707117f1b4Smrg if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { 4714a49301eSmrg const struct gl_renderbuffer *rb = 4724a49301eSmrg fb->Attachment[BUFFER_STENCIL].Renderbuffer; 473af69d88dSmrg const mesa_format fmt = rb->Format; 4744a49301eSmrg fb->Visual.stencilBits = _mesa_get_format_bits(fmt, GL_STENCIL_BITS); 4757117f1b4Smrg } 4767117f1b4Smrg 4777117f1b4Smrg if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) { 4784a49301eSmrg const struct gl_renderbuffer *rb = 4794a49301eSmrg fb->Attachment[BUFFER_ACCUM].Renderbuffer; 480af69d88dSmrg const mesa_format fmt = rb->Format; 4814a49301eSmrg fb->Visual.accumRedBits = _mesa_get_format_bits(fmt, GL_RED_BITS); 4824a49301eSmrg fb->Visual.accumGreenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); 4834a49301eSmrg fb->Visual.accumBlueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); 4844a49301eSmrg fb->Visual.accumAlphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); 4857117f1b4Smrg } 4867117f1b4Smrg 4877117f1b4Smrg compute_depth_max(fb); 4887ec681f3Smrg _mesa_update_allow_draw_out_of_order(ctx); 4897ec681f3Smrg _mesa_update_valid_to_render_state(ctx); 4907117f1b4Smrg} 4917117f1b4Smrg 4927117f1b4Smrg 493c1f859d4Smrg/* 494c1f859d4Smrg * Example DrawBuffers scenarios: 495c1f859d4Smrg * 496c1f859d4Smrg * 1. glDrawBuffer(GL_FRONT_AND_BACK), fixed-func or shader writes to 497c1f859d4Smrg * "gl_FragColor" or program writes to the "result.color" register: 498c1f859d4Smrg * 499c1f859d4Smrg * fragment color output renderbuffer 500c1f859d4Smrg * --------------------- --------------- 501c1f859d4Smrg * color[0] Front, Back 502c1f859d4Smrg * 503c1f859d4Smrg * 504c1f859d4Smrg * 2. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]), shader writes to 505c1f859d4Smrg * gl_FragData[i] or program writes to result.color[i] registers: 506c1f859d4Smrg * 507c1f859d4Smrg * fragment color output renderbuffer 508c1f859d4Smrg * --------------------- --------------- 509c1f859d4Smrg * color[0] Front 510c1f859d4Smrg * color[1] Aux0 511c1f859d4Smrg * color[3] Aux1 512c1f859d4Smrg * 513c1f859d4Smrg * 514c1f859d4Smrg * 3. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]) and shader writes to 515c1f859d4Smrg * gl_FragColor, or fixed function: 516c1f859d4Smrg * 517c1f859d4Smrg * fragment color output renderbuffer 518c1f859d4Smrg * --------------------- --------------- 519c1f859d4Smrg * color[0] Front, Aux0, Aux1 520c1f859d4Smrg * 521c1f859d4Smrg * 522c1f859d4Smrg * In either case, the list of renderbuffers is stored in the 523c1f859d4Smrg * framebuffer->_ColorDrawBuffers[] array and 524c1f859d4Smrg * framebuffer->_NumColorDrawBuffers indicates the number of buffers. 525c1f859d4Smrg * The renderer (like swrast) has to look at the current fragment shader 526c1f859d4Smrg * to see if it writes to gl_FragColor vs. gl_FragData[i] to determine 527c1f859d4Smrg * how to map color outputs to renderbuffers. 528c1f859d4Smrg * 529c1f859d4Smrg * Note that these two calls are equivalent (for fixed function fragment 530c1f859d4Smrg * shading anyway): 531c1f859d4Smrg * a) glDrawBuffer(GL_FRONT_AND_BACK); (assuming non-stereo framebuffer) 532c1f859d4Smrg * b) glDrawBuffers(2, [GL_FRONT_LEFT, GL_BACK_LEFT]); 533c1f859d4Smrg */ 534c1f859d4Smrg 535c1f859d4Smrg 536c1f859d4Smrg 537c1f859d4Smrg 5387117f1b4Smrg/** 539c1f859d4Smrg * Update the (derived) list of color drawing renderbuffer pointers. 5407117f1b4Smrg * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers 5417117f1b4Smrg * writing colors. 5427117f1b4Smrg */ 5437117f1b4Smrgstatic void 54401e04c3fSmrgupdate_color_draw_buffers(struct gl_framebuffer *fb) 5457117f1b4Smrg{ 5467117f1b4Smrg GLuint output; 5477117f1b4Smrg 548c1f859d4Smrg /* set 0th buffer to NULL now in case _NumColorDrawBuffers is zero */ 549c1f859d4Smrg fb->_ColorDrawBuffers[0] = NULL; 550c1f859d4Smrg 551c1f859d4Smrg for (output = 0; output < fb->_NumColorDrawBuffers; output++) { 55201e04c3fSmrg gl_buffer_index buf = fb->_ColorDrawBufferIndexes[output]; 55301e04c3fSmrg if (buf != BUFFER_NONE) { 554c1f859d4Smrg fb->_ColorDrawBuffers[output] = fb->Attachment[buf].Renderbuffer; 555c1f859d4Smrg } 556c1f859d4Smrg else { 557c1f859d4Smrg fb->_ColorDrawBuffers[output] = NULL; 5587117f1b4Smrg } 5597117f1b4Smrg } 5607117f1b4Smrg} 5617117f1b4Smrg 5627117f1b4Smrg 5637117f1b4Smrg/** 564c1f859d4Smrg * Update the (derived) color read renderbuffer pointer. 5657117f1b4Smrg * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. 5667117f1b4Smrg */ 5677117f1b4Smrgstatic void 56801e04c3fSmrgupdate_color_read_buffer(struct gl_framebuffer *fb) 5697117f1b4Smrg{ 57001e04c3fSmrg if (fb->_ColorReadBufferIndex == BUFFER_NONE || 5717117f1b4Smrg fb->DeletePending || 5727117f1b4Smrg fb->Width == 0 || 5737117f1b4Smrg fb->Height == 0) { 5747117f1b4Smrg fb->_ColorReadBuffer = NULL; /* legal! */ 5757117f1b4Smrg } 5767117f1b4Smrg else { 57701e04c3fSmrg assert(fb->_ColorReadBufferIndex >= 0); 57801e04c3fSmrg assert(fb->_ColorReadBufferIndex < BUFFER_COUNT); 5797117f1b4Smrg fb->_ColorReadBuffer 5807117f1b4Smrg = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; 5817117f1b4Smrg } 5827117f1b4Smrg} 5837117f1b4Smrg 5847117f1b4Smrg 5857117f1b4Smrg/** 586c1f859d4Smrg * Update a gl_framebuffer's derived state. 587c1f859d4Smrg * 5887117f1b4Smrg * Specifically, update these framebuffer fields: 5897117f1b4Smrg * _ColorDrawBuffers 5907117f1b4Smrg * _NumColorDrawBuffers 5917117f1b4Smrg * _ColorReadBuffer 592c1f859d4Smrg * 593c1f859d4Smrg * If the framebuffer is user-created, make sure it's complete. 594c1f859d4Smrg * 595c1f859d4Smrg * The following functions (at least) can effect framebuffer state: 596c1f859d4Smrg * glReadBuffer, glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT, 5977117f1b4Smrg * glRenderbufferStorageEXT. 5987117f1b4Smrg */ 599c1f859d4Smrgstatic void 6003464ebd5Sriastradhupdate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) 6017117f1b4Smrg{ 602af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) { 603c1f859d4Smrg /* This is a window-system framebuffer */ 604c1f859d4Smrg /* Need to update the FB's GL_DRAW_BUFFER state to match the 605c1f859d4Smrg * context state (GL_READ_BUFFER too). 606c1f859d4Smrg */ 607c1f859d4Smrg if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) { 60801e04c3fSmrg _mesa_drawbuffers(ctx, fb, ctx->Const.MaxDrawBuffers, 609c1f859d4Smrg ctx->Color.DrawBuffer, NULL); 610c1f859d4Smrg } 61101e04c3fSmrg 61201e04c3fSmrg /* Call device driver function if fb is the bound draw buffer. */ 61301e04c3fSmrg if (fb == ctx->DrawBuffer) { 61401e04c3fSmrg if (ctx->Driver.DrawBufferAllocate) 61501e04c3fSmrg ctx->Driver.DrawBufferAllocate(ctx); 61601e04c3fSmrg } 617c1f859d4Smrg } 618c1f859d4Smrg else { 619c1f859d4Smrg /* This is a user-created framebuffer. 620c1f859d4Smrg * Completeness only matters for user-created framebuffers. 621c1f859d4Smrg */ 6224a49301eSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE) { 6234a49301eSmrg _mesa_test_framebuffer_completeness(ctx, fb); 6244a49301eSmrg } 6257117f1b4Smrg } 6267117f1b4Smrg 627c1f859d4Smrg /* Strictly speaking, we don't need to update the draw-state 628c1f859d4Smrg * if this FB is bound as ctx->ReadBuffer (and conversely, the 629c1f859d4Smrg * read-state if this FB is bound as ctx->DrawBuffer), but no 630c1f859d4Smrg * harm. 631c1f859d4Smrg */ 63201e04c3fSmrg update_color_draw_buffers(fb); 63301e04c3fSmrg update_color_read_buffer(fb); 6347117f1b4Smrg 6357117f1b4Smrg compute_depth_max(fb); 6367117f1b4Smrg} 6377117f1b4Smrg 6387117f1b4Smrg 639c1f859d4Smrg/** 64001e04c3fSmrg * Update state related to the draw/read framebuffers. 641c1f859d4Smrg */ 642c1f859d4Smrgvoid 64301e04c3fSmrg_mesa_update_framebuffer(struct gl_context *ctx, 64401e04c3fSmrg struct gl_framebuffer *readFb, 64501e04c3fSmrg struct gl_framebuffer *drawFb) 646c1f859d4Smrg{ 647cdc920a0Smrg assert(ctx); 648c1f859d4Smrg 649c1f859d4Smrg update_framebuffer(ctx, drawFb); 650c1f859d4Smrg if (readFb != drawFb) 651c1f859d4Smrg update_framebuffer(ctx, readFb); 652af69d88dSmrg 65301e04c3fSmrg _mesa_update_clamp_vertex_color(ctx, drawFb); 65401e04c3fSmrg _mesa_update_clamp_fragment_color(ctx, drawFb); 655c1f859d4Smrg} 656c1f859d4Smrg 657c1f859d4Smrg 6587117f1b4Smrg/** 659af69d88dSmrg * Check if the renderbuffer for a read/draw operation exists. 6607117f1b4Smrg * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, 6617117f1b4Smrg * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. 662af69d88dSmrg * \param reading if TRUE, we're going to read from the buffer, 663af69d88dSmrg if FALSE, we're going to write to the buffer. 6647117f1b4Smrg * \return GL_TRUE if buffer exists, GL_FALSE otherwise 6657117f1b4Smrg */ 666af69d88dSmrgstatic GLboolean 667af69d88dSmrgrenderbuffer_exists(struct gl_context *ctx, 668af69d88dSmrg struct gl_framebuffer *fb, 669af69d88dSmrg GLenum format, 670af69d88dSmrg GLboolean reading) 6717117f1b4Smrg{ 672af69d88dSmrg const struct gl_renderbuffer_attachment *att = fb->Attachment; 6734a49301eSmrg 6744a49301eSmrg /* If we don't know the framebuffer status, update it now */ 675af69d88dSmrg if (fb->_Status == 0) { 676af69d88dSmrg _mesa_test_framebuffer_completeness(ctx, fb); 6774a49301eSmrg } 6787117f1b4Smrg 679af69d88dSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 6807117f1b4Smrg return GL_FALSE; 6817117f1b4Smrg } 6827117f1b4Smrg 6837117f1b4Smrg switch (format) { 6847117f1b4Smrg case GL_COLOR: 6857117f1b4Smrg case GL_RED: 6867117f1b4Smrg case GL_GREEN: 6877117f1b4Smrg case GL_BLUE: 6887117f1b4Smrg case GL_ALPHA: 6897117f1b4Smrg case GL_LUMINANCE: 6907117f1b4Smrg case GL_LUMINANCE_ALPHA: 6917117f1b4Smrg case GL_INTENSITY: 6923464ebd5Sriastradh case GL_RG: 6937117f1b4Smrg case GL_RGB: 6947117f1b4Smrg case GL_BGR: 6957117f1b4Smrg case GL_RGBA: 6967117f1b4Smrg case GL_BGRA: 6977117f1b4Smrg case GL_ABGR_EXT: 6983464ebd5Sriastradh case GL_RED_INTEGER_EXT: 699af69d88dSmrg case GL_RG_INTEGER: 7003464ebd5Sriastradh case GL_GREEN_INTEGER_EXT: 7013464ebd5Sriastradh case GL_BLUE_INTEGER_EXT: 7023464ebd5Sriastradh case GL_ALPHA_INTEGER_EXT: 7033464ebd5Sriastradh case GL_RGB_INTEGER_EXT: 7043464ebd5Sriastradh case GL_RGBA_INTEGER_EXT: 7053464ebd5Sriastradh case GL_BGR_INTEGER_EXT: 7063464ebd5Sriastradh case GL_BGRA_INTEGER_EXT: 7073464ebd5Sriastradh case GL_LUMINANCE_INTEGER_EXT: 7083464ebd5Sriastradh case GL_LUMINANCE_ALPHA_INTEGER_EXT: 709af69d88dSmrg if (reading) { 710af69d88dSmrg /* about to read from a color buffer */ 711af69d88dSmrg const struct gl_renderbuffer *readBuf = fb->_ColorReadBuffer; 712af69d88dSmrg if (!readBuf) { 713af69d88dSmrg return GL_FALSE; 714af69d88dSmrg } 71501e04c3fSmrg assert(_mesa_get_format_bits(readBuf->Format, GL_RED_BITS) > 0 || 716af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_ALPHA_BITS) > 0 || 717af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_TEXTURE_LUMINANCE_SIZE) > 0 || 718af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_TEXTURE_INTENSITY_SIZE) > 0 || 719af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_INDEX_BITS) > 0); 720af69d88dSmrg } 721af69d88dSmrg else { 722af69d88dSmrg /* about to draw to zero or more color buffers (none is OK) */ 723af69d88dSmrg return GL_TRUE; 7247117f1b4Smrg } 7257117f1b4Smrg break; 7267117f1b4Smrg case GL_DEPTH: 7277117f1b4Smrg case GL_DEPTH_COMPONENT: 728af69d88dSmrg if (att[BUFFER_DEPTH].Type == GL_NONE) { 7297117f1b4Smrg return GL_FALSE; 7307117f1b4Smrg } 7317117f1b4Smrg break; 7327117f1b4Smrg case GL_STENCIL: 7337117f1b4Smrg case GL_STENCIL_INDEX: 734af69d88dSmrg if (att[BUFFER_STENCIL].Type == GL_NONE) { 7357117f1b4Smrg return GL_FALSE; 7367117f1b4Smrg } 7377117f1b4Smrg break; 7387117f1b4Smrg case GL_DEPTH_STENCIL_EXT: 739af69d88dSmrg if (att[BUFFER_DEPTH].Type == GL_NONE || 740af69d88dSmrg att[BUFFER_STENCIL].Type == GL_NONE) { 7417117f1b4Smrg return GL_FALSE; 7427117f1b4Smrg } 7437117f1b4Smrg break; 7447ec681f3Smrg case GL_DEPTH_STENCIL_TO_RGBA_NV: 7457ec681f3Smrg case GL_DEPTH_STENCIL_TO_BGRA_NV: 7467ec681f3Smrg if (att[BUFFER_DEPTH].Type == GL_NONE || 7477ec681f3Smrg att[BUFFER_STENCIL].Type == GL_NONE) { 7487ec681f3Smrg return GL_FALSE; 7497ec681f3Smrg } 7507ec681f3Smrg break; 7517117f1b4Smrg default: 7527117f1b4Smrg _mesa_problem(ctx, 753af69d88dSmrg "Unexpected format 0x%x in renderbuffer_exists", 7547117f1b4Smrg format); 7557117f1b4Smrg return GL_FALSE; 7567117f1b4Smrg } 7577117f1b4Smrg 7587117f1b4Smrg /* OK */ 7597117f1b4Smrg return GL_TRUE; 7607117f1b4Smrg} 7617117f1b4Smrg 7627117f1b4Smrg 763af69d88dSmrg/** 764af69d88dSmrg * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels, 765af69d88dSmrg * glCopyTex[Sub]Image, etc) exists. 766af69d88dSmrg * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, 767af69d88dSmrg * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. 768af69d88dSmrg * \return GL_TRUE if buffer exists, GL_FALSE otherwise 769af69d88dSmrg */ 770af69d88dSmrgGLboolean 771af69d88dSmrg_mesa_source_buffer_exists(struct gl_context *ctx, GLenum format) 772af69d88dSmrg{ 773af69d88dSmrg return renderbuffer_exists(ctx, ctx->ReadBuffer, format, GL_TRUE); 774af69d88dSmrg} 775af69d88dSmrg 776af69d88dSmrg 7777117f1b4Smrg/** 7787117f1b4Smrg * As above, but for drawing operations. 7797117f1b4Smrg */ 7807117f1b4SmrgGLboolean 7813464ebd5Sriastradh_mesa_dest_buffer_exists(struct gl_context *ctx, GLenum format) 7827117f1b4Smrg{ 783af69d88dSmrg return renderbuffer_exists(ctx, ctx->DrawBuffer, format, GL_FALSE); 784af69d88dSmrg} 7854a49301eSmrg 7867117f1b4Smrg 787af69d88dSmrg/** 78801e04c3fSmrg * Used to answer the GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES queries (using 78901e04c3fSmrg * GetIntegerv, GetFramebufferParameteriv, etc) 79001e04c3fSmrg * 79101e04c3fSmrg * If @fb is NULL, the method returns the value for the current bound 79201e04c3fSmrg * framebuffer. 793af69d88dSmrg */ 794af69d88dSmrgGLenum 79501e04c3fSmrg_mesa_get_color_read_format(struct gl_context *ctx, 79601e04c3fSmrg struct gl_framebuffer *fb, 79701e04c3fSmrg const char *caller) 798af69d88dSmrg{ 79901e04c3fSmrg if (ctx->NewState) 80001e04c3fSmrg _mesa_update_state(ctx); 80101e04c3fSmrg 80201e04c3fSmrg if (fb == NULL) 80301e04c3fSmrg fb = ctx->ReadBuffer; 80401e04c3fSmrg 80501e04c3fSmrg if (!fb || !fb->_ColorReadBuffer) { 80601e04c3fSmrg /* 80701e04c3fSmrg * From OpenGL 4.5 spec, section 18.2.2 "ReadPixels": 80801e04c3fSmrg * 80901e04c3fSmrg * "An INVALID_OPERATION error is generated by GetIntegerv if pname 81001e04c3fSmrg * is IMPLEMENTATION_COLOR_READ_FORMAT or IMPLEMENTATION_COLOR_- 81101e04c3fSmrg * READ_TYPE and any of: 81201e04c3fSmrg * * the read framebuffer is not framebuffer complete. 81301e04c3fSmrg * * the read framebuffer is a framebuffer object, and the selected 81401e04c3fSmrg * read buffer (see section 18.2.1) has no image attached. 81501e04c3fSmrg * * the selected read buffer is NONE." 81601e04c3fSmrg * 81701e04c3fSmrg * There is not equivalent quote for GetFramebufferParameteriv or 81801e04c3fSmrg * GetNamedFramebufferParameteriv, but from section 9.2.3 "Framebuffer 81901e04c3fSmrg * Object Queries": 82001e04c3fSmrg * 82101e04c3fSmrg * "Values of framebuffer-dependent state are identical to those that 82201e04c3fSmrg * would be obtained were the framebuffer object bound and queried 82301e04c3fSmrg * using the simple state queries in that table." 82401e04c3fSmrg * 82501e04c3fSmrg * Where "using the simple state queries" refer to use GetIntegerv. So 82601e04c3fSmrg * we will assume that on that situation the same error should be 82701e04c3fSmrg * triggered too. 828af69d88dSmrg */ 829af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 83001e04c3fSmrg "%s(GL_IMPLEMENTATION_COLOR_READ_FORMAT: no GL_READ_BUFFER)", 83101e04c3fSmrg caller); 832af69d88dSmrg return GL_NONE; 8337117f1b4Smrg } 834af69d88dSmrg else { 83501e04c3fSmrg const mesa_format format = fb->_ColorReadBuffer->Format; 8367117f1b4Smrg 83701e04c3fSmrg switch (format) { 83801e04c3fSmrg case MESA_FORMAT_RGBA_UINT8: 83901e04c3fSmrg return GL_RGBA_INTEGER; 84001e04c3fSmrg case MESA_FORMAT_B8G8R8A8_UNORM: 841af69d88dSmrg return GL_BGRA; 84201e04c3fSmrg case MESA_FORMAT_B5G6R5_UNORM: 84301e04c3fSmrg case MESA_FORMAT_R11G11B10_FLOAT: 84401e04c3fSmrg return GL_RGB; 84501e04c3fSmrg case MESA_FORMAT_RG_FLOAT32: 84601e04c3fSmrg case MESA_FORMAT_RG_FLOAT16: 8477ec681f3Smrg case MESA_FORMAT_RG_UNORM8: 84801e04c3fSmrg return GL_RG; 84901e04c3fSmrg case MESA_FORMAT_RG_SINT32: 85001e04c3fSmrg case MESA_FORMAT_RG_UINT32: 85101e04c3fSmrg case MESA_FORMAT_RG_SINT16: 85201e04c3fSmrg case MESA_FORMAT_RG_UINT16: 85301e04c3fSmrg case MESA_FORMAT_RG_SINT8: 85401e04c3fSmrg case MESA_FORMAT_RG_UINT8: 85501e04c3fSmrg return GL_RG_INTEGER; 85601e04c3fSmrg case MESA_FORMAT_R_FLOAT32: 85701e04c3fSmrg case MESA_FORMAT_R_FLOAT16: 85801e04c3fSmrg case MESA_FORMAT_R_UNORM16: 85901e04c3fSmrg case MESA_FORMAT_R_UNORM8: 86001e04c3fSmrg case MESA_FORMAT_R_SNORM16: 86101e04c3fSmrg case MESA_FORMAT_R_SNORM8: 86201e04c3fSmrg return GL_RED; 86301e04c3fSmrg case MESA_FORMAT_R_SINT32: 86401e04c3fSmrg case MESA_FORMAT_R_UINT32: 86501e04c3fSmrg case MESA_FORMAT_R_SINT16: 86601e04c3fSmrg case MESA_FORMAT_R_UINT16: 86701e04c3fSmrg case MESA_FORMAT_R_SINT8: 86801e04c3fSmrg case MESA_FORMAT_R_UINT8: 86901e04c3fSmrg return GL_RED_INTEGER; 87001e04c3fSmrg default: 87101e04c3fSmrg break; 87201e04c3fSmrg } 873af69d88dSmrg 87401e04c3fSmrg if (_mesa_is_format_integer(format)) 875af69d88dSmrg return GL_RGBA_INTEGER; 87601e04c3fSmrg else 877af69d88dSmrg return GL_RGBA; 8787117f1b4Smrg } 8797117f1b4Smrg} 8804a49301eSmrg 8813464ebd5Sriastradh 8823464ebd5Sriastradh/** 88301e04c3fSmrg * Used to answer the GL_IMPLEMENTATION_COLOR_READ_TYPE_OES queries (using 88401e04c3fSmrg * GetIntegerv, GetFramebufferParameteriv, etc) 88501e04c3fSmrg * 88601e04c3fSmrg * If @fb is NULL, the method returns the value for the current bound 88701e04c3fSmrg * framebuffer. 8883464ebd5Sriastradh */ 8894a49301eSmrgGLenum 89001e04c3fSmrg_mesa_get_color_read_type(struct gl_context *ctx, 89101e04c3fSmrg struct gl_framebuffer *fb, 89201e04c3fSmrg const char *caller) 8934a49301eSmrg{ 89401e04c3fSmrg if (ctx->NewState) 89501e04c3fSmrg _mesa_update_state(ctx); 89601e04c3fSmrg 89701e04c3fSmrg if (fb == NULL) 89801e04c3fSmrg fb = ctx->ReadBuffer; 89901e04c3fSmrg 90001e04c3fSmrg if (!fb || !fb->_ColorReadBuffer) { 90101e04c3fSmrg /* 90201e04c3fSmrg * See comment on _mesa_get_color_read_format 903af69d88dSmrg */ 904af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 90501e04c3fSmrg "%s(GL_IMPLEMENTATION_COLOR_READ_TYPE: no GL_READ_BUFFER)", 90601e04c3fSmrg caller); 907af69d88dSmrg return GL_NONE; 908af69d88dSmrg } 909af69d88dSmrg else { 91001e04c3fSmrg const mesa_format format = fb->_ColorReadBuffer->Format; 91101e04c3fSmrg GLenum data_type; 91201e04c3fSmrg GLuint comps; 91301e04c3fSmrg 91401e04c3fSmrg _mesa_uncompressed_format_to_type_and_comps(format, &data_type, &comps); 91501e04c3fSmrg 91601e04c3fSmrg return data_type; 9174a49301eSmrg } 9184a49301eSmrg} 9194a49301eSmrg 9203464ebd5Sriastradh 9213464ebd5Sriastradh/** 922af69d88dSmrg * Returns the read renderbuffer for the specified format. 9233464ebd5Sriastradh */ 924af69d88dSmrgstruct gl_renderbuffer * 925af69d88dSmrg_mesa_get_read_renderbuffer_for_format(const struct gl_context *ctx, 926af69d88dSmrg GLenum format) 9274a49301eSmrg{ 928af69d88dSmrg const struct gl_framebuffer *rfb = ctx->ReadBuffer; 929af69d88dSmrg 930af69d88dSmrg if (_mesa_is_color_format(format)) { 931af69d88dSmrg return rfb->Attachment[rfb->_ColorReadBufferIndex].Renderbuffer; 932af69d88dSmrg } else if (_mesa_is_depth_format(format) || 933af69d88dSmrg _mesa_is_depthstencil_format(format)) { 934af69d88dSmrg return rfb->Attachment[BUFFER_DEPTH].Renderbuffer; 935af69d88dSmrg } else { 936af69d88dSmrg return rfb->Attachment[BUFFER_STENCIL].Renderbuffer; 9374a49301eSmrg } 9384a49301eSmrg} 9393464ebd5Sriastradh 9403464ebd5Sriastradh 9413464ebd5Sriastradh/** 9423464ebd5Sriastradh * Print framebuffer info to stderr, for debugging. 9433464ebd5Sriastradh */ 9443464ebd5Sriastradhvoid 9453464ebd5Sriastradh_mesa_print_framebuffer(const struct gl_framebuffer *fb) 9463464ebd5Sriastradh{ 9473464ebd5Sriastradh fprintf(stderr, "Mesa Framebuffer %u at %p\n", fb->Name, (void *) fb); 9483464ebd5Sriastradh fprintf(stderr, " Size: %u x %u Status: %s\n", fb->Width, fb->Height, 94901e04c3fSmrg _mesa_enum_to_string(fb->_Status)); 9503464ebd5Sriastradh fprintf(stderr, " Attachments:\n"); 9513464ebd5Sriastradh 95201e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 9533464ebd5Sriastradh const struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 9543464ebd5Sriastradh if (att->Type == GL_TEXTURE) { 955af69d88dSmrg const struct gl_texture_image *texImage = att->Renderbuffer->TexImage; 9563464ebd5Sriastradh fprintf(stderr, 9573464ebd5Sriastradh " %2d: Texture %u, level %u, face %u, slice %u, complete %d\n", 9583464ebd5Sriastradh i, att->Texture->Name, att->TextureLevel, att->CubeMapFace, 9593464ebd5Sriastradh att->Zoffset, att->Complete); 9603464ebd5Sriastradh fprintf(stderr, " Size: %u x %u x %u Format %s\n", 9613464ebd5Sriastradh texImage->Width, texImage->Height, texImage->Depth, 9623464ebd5Sriastradh _mesa_get_format_name(texImage->TexFormat)); 9633464ebd5Sriastradh } 9643464ebd5Sriastradh else if (att->Type == GL_RENDERBUFFER) { 9653464ebd5Sriastradh fprintf(stderr, " %2d: Renderbuffer %u, complete %d\n", 9663464ebd5Sriastradh i, att->Renderbuffer->Name, att->Complete); 9673464ebd5Sriastradh fprintf(stderr, " Size: %u x %u Format %s\n", 9683464ebd5Sriastradh att->Renderbuffer->Width, att->Renderbuffer->Height, 9693464ebd5Sriastradh _mesa_get_format_name(att->Renderbuffer->Format)); 9703464ebd5Sriastradh } 9713464ebd5Sriastradh else { 9723464ebd5Sriastradh fprintf(stderr, " %2d: none\n", i); 9733464ebd5Sriastradh } 9743464ebd5Sriastradh } 9753464ebd5Sriastradh} 97601e04c3fSmrg 97701e04c3fSmrgbool 97801e04c3fSmrg_mesa_is_front_buffer_reading(const struct gl_framebuffer *fb) 97901e04c3fSmrg{ 98001e04c3fSmrg if (!fb || _mesa_is_user_fbo(fb)) 98101e04c3fSmrg return false; 98201e04c3fSmrg 98301e04c3fSmrg return fb->_ColorReadBufferIndex == BUFFER_FRONT_LEFT; 98401e04c3fSmrg} 98501e04c3fSmrg 98601e04c3fSmrgbool 98701e04c3fSmrg_mesa_is_front_buffer_drawing(const struct gl_framebuffer *fb) 98801e04c3fSmrg{ 98901e04c3fSmrg if (!fb || _mesa_is_user_fbo(fb)) 99001e04c3fSmrg return false; 99101e04c3fSmrg 99201e04c3fSmrg return (fb->_NumColorDrawBuffers >= 1 && 99301e04c3fSmrg fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT); 99401e04c3fSmrg} 99501e04c3fSmrg 99601e04c3fSmrgstatic inline GLuint 99701e04c3fSmrg_mesa_geometric_nonvalidated_samples(const struct gl_framebuffer *buffer) 99801e04c3fSmrg{ 99901e04c3fSmrg return buffer->_HasAttachments ? 100001e04c3fSmrg buffer->Visual.samples : 100101e04c3fSmrg buffer->DefaultGeometry.NumSamples; 100201e04c3fSmrg} 100301e04c3fSmrg 100401e04c3fSmrgbool 100501e04c3fSmrg_mesa_is_multisample_enabled(const struct gl_context *ctx) 100601e04c3fSmrg{ 100701e04c3fSmrg /* The sample count may not be validated by the driver, but when it is set, 100801e04c3fSmrg * we know that is in a valid range and no driver should ever validate a 100901e04c3fSmrg * multisampled framebuffer to non-multisampled and vice-versa. 101001e04c3fSmrg */ 101101e04c3fSmrg return ctx->Multisample.Enabled && 101201e04c3fSmrg ctx->DrawBuffer && 101301e04c3fSmrg _mesa_geometric_nonvalidated_samples(ctx->DrawBuffer) >= 1; 101401e04c3fSmrg} 101501e04c3fSmrg 101601e04c3fSmrg/** 101701e04c3fSmrg * Is alpha testing enabled and applicable to the currently bound 101801e04c3fSmrg * framebuffer? 101901e04c3fSmrg */ 102001e04c3fSmrgbool 102101e04c3fSmrg_mesa_is_alpha_test_enabled(const struct gl_context *ctx) 102201e04c3fSmrg{ 102301e04c3fSmrg bool buffer0_is_integer = ctx->DrawBuffer->_IntegerBuffers & 0x1; 102401e04c3fSmrg return (ctx->Color.AlphaEnabled && !buffer0_is_integer); 102501e04c3fSmrg} 102601e04c3fSmrg 102701e04c3fSmrg/** 102801e04c3fSmrg * Is alpha to coverage enabled and applicable to the currently bound 102901e04c3fSmrg * framebuffer? 103001e04c3fSmrg */ 103101e04c3fSmrgbool 103201e04c3fSmrg_mesa_is_alpha_to_coverage_enabled(const struct gl_context *ctx) 103301e04c3fSmrg{ 103401e04c3fSmrg bool buffer0_is_integer = ctx->DrawBuffer->_IntegerBuffers & 0x1; 103501e04c3fSmrg return (ctx->Multisample.SampleAlphaToCoverage && 103601e04c3fSmrg _mesa_is_multisample_enabled(ctx) && 103701e04c3fSmrg !buffer0_is_integer); 103801e04c3fSmrg} 1039