framebuffer.c revision 01e04c3f
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" 347117f1b4Smrg#include "imports.h" 35af69d88dSmrg#include "blend.h" 36c1f859d4Smrg#include "buffers.h" 377117f1b4Smrg#include "context.h" 383464ebd5Sriastradh#include "enums.h" 394a49301eSmrg#include "formats.h" 404a49301eSmrg#include "macros.h" 417117f1b4Smrg#include "mtypes.h" 427117f1b4Smrg#include "fbobject.h" 437117f1b4Smrg#include "framebuffer.h" 447117f1b4Smrg#include "renderbuffer.h" 457117f1b4Smrg#include "texobj.h" 46af69d88dSmrg#include "glformats.h" 4701e04c3fSmrg#include "state.h" 487117f1b4Smrg 497117f1b4Smrg 507117f1b4Smrg 517117f1b4Smrg/** 527117f1b4Smrg * Compute/set the _DepthMax field for the given framebuffer. 537117f1b4Smrg * This value depends on the Z buffer resolution. 547117f1b4Smrg */ 557117f1b4Smrgstatic void 567117f1b4Smrgcompute_depth_max(struct gl_framebuffer *fb) 577117f1b4Smrg{ 587117f1b4Smrg if (fb->Visual.depthBits == 0) { 597117f1b4Smrg /* Special case. Even if we don't have a depth buffer we need 607117f1b4Smrg * good values for DepthMax for Z vertex transformation purposes 617117f1b4Smrg * and for per-fragment fog computation. 627117f1b4Smrg */ 637117f1b4Smrg fb->_DepthMax = (1 << 16) - 1; 647117f1b4Smrg } 657117f1b4Smrg else if (fb->Visual.depthBits < 32) { 667117f1b4Smrg fb->_DepthMax = (1 << fb->Visual.depthBits) - 1; 677117f1b4Smrg } 687117f1b4Smrg else { 697117f1b4Smrg /* Special case since shift values greater than or equal to the 707117f1b4Smrg * number of bits in the left hand expression's type are undefined. 717117f1b4Smrg */ 727117f1b4Smrg fb->_DepthMax = 0xffffffff; 737117f1b4Smrg } 747117f1b4Smrg fb->_DepthMaxF = (GLfloat) fb->_DepthMax; 75c1f859d4Smrg 76c1f859d4Smrg /* Minimum resolvable depth value, for polygon offset */ 77c1f859d4Smrg fb->_MRD = (GLfloat)1.0 / fb->_DepthMaxF; 787117f1b4Smrg} 797117f1b4Smrg 807117f1b4Smrg/** 817117f1b4Smrg * Create and initialize a gl_framebuffer object. 827117f1b4Smrg * This is intended for creating _window_system_ framebuffers, not generic 837117f1b4Smrg * framebuffer objects ala GL_EXT_framebuffer_object. 847117f1b4Smrg * 857117f1b4Smrg * \sa _mesa_new_framebuffer 867117f1b4Smrg */ 877117f1b4Smrgstruct gl_framebuffer * 883464ebd5Sriastradh_mesa_create_framebuffer(const struct gl_config *visual) 897117f1b4Smrg{ 907117f1b4Smrg struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer); 917117f1b4Smrg assert(visual); 927117f1b4Smrg if (fb) { 93cdc920a0Smrg _mesa_initialize_window_framebuffer(fb, visual); 947117f1b4Smrg } 957117f1b4Smrg return fb; 967117f1b4Smrg} 977117f1b4Smrg 987117f1b4Smrg 997117f1b4Smrg/** 1007117f1b4Smrg * Allocate a new gl_framebuffer object. 1017117f1b4Smrg * This is the default function for ctx->Driver.NewFramebuffer(). 1027117f1b4Smrg * This is for allocating user-created framebuffers, not window-system 1037117f1b4Smrg * framebuffers! 1047117f1b4Smrg * \sa _mesa_create_framebuffer 1057117f1b4Smrg */ 1067117f1b4Smrgstruct gl_framebuffer * 1073464ebd5Sriastradh_mesa_new_framebuffer(struct gl_context *ctx, GLuint name) 1087117f1b4Smrg{ 1097117f1b4Smrg struct gl_framebuffer *fb; 1107117f1b4Smrg (void) ctx; 1117117f1b4Smrg assert(name != 0); 1127117f1b4Smrg fb = CALLOC_STRUCT(gl_framebuffer); 1137117f1b4Smrg if (fb) { 114cdc920a0Smrg _mesa_initialize_user_framebuffer(fb, name); 1157117f1b4Smrg } 1167117f1b4Smrg return fb; 1177117f1b4Smrg} 1187117f1b4Smrg 1197117f1b4Smrg 1207117f1b4Smrg/** 1217117f1b4Smrg * Initialize a gl_framebuffer object. Typically used to initialize 1227117f1b4Smrg * window system-created framebuffers, not user-created framebuffers. 123cdc920a0Smrg * \sa _mesa_initialize_user_framebuffer 1247117f1b4Smrg */ 1257117f1b4Smrgvoid 126cdc920a0Smrg_mesa_initialize_window_framebuffer(struct gl_framebuffer *fb, 1273464ebd5Sriastradh const struct gl_config *visual) 1287117f1b4Smrg{ 1297117f1b4Smrg assert(fb); 1307117f1b4Smrg assert(visual); 1317117f1b4Smrg 132cdc920a0Smrg memset(fb, 0, sizeof(struct gl_framebuffer)); 1337117f1b4Smrg 13401e04c3fSmrg simple_mtx_init(&fb->Mutex, mtx_plain); 1357117f1b4Smrg 1367117f1b4Smrg fb->RefCount = 1; 1377117f1b4Smrg 1387117f1b4Smrg /* save the visual */ 1397117f1b4Smrg fb->Visual = *visual; 1407117f1b4Smrg 141c1f859d4Smrg /* Init read/draw renderbuffer state */ 1427117f1b4Smrg if (visual->doubleBufferMode) { 143c1f859d4Smrg fb->_NumColorDrawBuffers = 1; 1447117f1b4Smrg fb->ColorDrawBuffer[0] = GL_BACK; 145c1f859d4Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_BACK_LEFT; 1467117f1b4Smrg fb->ColorReadBuffer = GL_BACK; 1477117f1b4Smrg fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT; 1487117f1b4Smrg } 1497117f1b4Smrg else { 150c1f859d4Smrg fb->_NumColorDrawBuffers = 1; 1517117f1b4Smrg fb->ColorDrawBuffer[0] = GL_FRONT; 152c1f859d4Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_FRONT_LEFT; 1537117f1b4Smrg fb->ColorReadBuffer = GL_FRONT; 1547117f1b4Smrg fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT; 1557117f1b4Smrg } 1567117f1b4Smrg 1577117f1b4Smrg fb->Delete = _mesa_destroy_framebuffer; 1587117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 159af69d88dSmrg fb->_AllColorBuffersFixedPoint = !visual->floatMode; 160af69d88dSmrg fb->_HasSNormOrFloatColorBuffer = visual->floatMode; 16101e04c3fSmrg fb->_HasAttachments = true; 16201e04c3fSmrg fb->FlipY = true; 16301e04c3fSmrg 16401e04c3fSmrg fb->SampleLocationTable = NULL; 16501e04c3fSmrg fb->ProgrammableSampleLocations = 0; 16601e04c3fSmrg fb->SampleLocationPixelGrid = 0; 1677117f1b4Smrg 1687117f1b4Smrg compute_depth_max(fb); 1697117f1b4Smrg} 1707117f1b4Smrg 1717117f1b4Smrg 172cdc920a0Smrg/** 173cdc920a0Smrg * Initialize a user-created gl_framebuffer object. 174cdc920a0Smrg * \sa _mesa_initialize_window_framebuffer 175cdc920a0Smrg */ 176cdc920a0Smrgvoid 177cdc920a0Smrg_mesa_initialize_user_framebuffer(struct gl_framebuffer *fb, GLuint name) 178cdc920a0Smrg{ 179cdc920a0Smrg assert(fb); 180cdc920a0Smrg assert(name); 181cdc920a0Smrg 182cdc920a0Smrg memset(fb, 0, sizeof(struct gl_framebuffer)); 183cdc920a0Smrg 184cdc920a0Smrg fb->Name = name; 185cdc920a0Smrg fb->RefCount = 1; 186cdc920a0Smrg fb->_NumColorDrawBuffers = 1; 187cdc920a0Smrg fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT; 188cdc920a0Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_COLOR0; 189cdc920a0Smrg fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT; 190cdc920a0Smrg fb->_ColorReadBufferIndex = BUFFER_COLOR0; 19101e04c3fSmrg fb->SampleLocationTable = NULL; 19201e04c3fSmrg fb->ProgrammableSampleLocations = 0; 19301e04c3fSmrg fb->SampleLocationPixelGrid = 0; 194cdc920a0Smrg fb->Delete = _mesa_destroy_framebuffer; 19501e04c3fSmrg simple_mtx_init(&fb->Mutex, mtx_plain); 196cdc920a0Smrg} 197cdc920a0Smrg 198cdc920a0Smrg 1997117f1b4Smrg/** 2007117f1b4Smrg * Deallocate buffer and everything attached to it. 2017117f1b4Smrg * Typically called via the gl_framebuffer->Delete() method. 2027117f1b4Smrg */ 2037117f1b4Smrgvoid 2047117f1b4Smrg_mesa_destroy_framebuffer(struct gl_framebuffer *fb) 2057117f1b4Smrg{ 2067117f1b4Smrg if (fb) { 2077117f1b4Smrg _mesa_free_framebuffer_data(fb); 208af69d88dSmrg free(fb->Label); 209cdc920a0Smrg free(fb); 2107117f1b4Smrg } 2117117f1b4Smrg} 2127117f1b4Smrg 2137117f1b4Smrg 2147117f1b4Smrg/** 2157117f1b4Smrg * Free all the data hanging off the given gl_framebuffer, but don't free 2167117f1b4Smrg * the gl_framebuffer object itself. 2177117f1b4Smrg */ 2187117f1b4Smrgvoid 2197117f1b4Smrg_mesa_free_framebuffer_data(struct gl_framebuffer *fb) 2207117f1b4Smrg{ 2217117f1b4Smrg assert(fb); 2227117f1b4Smrg assert(fb->RefCount == 0); 2237117f1b4Smrg 22401e04c3fSmrg simple_mtx_destroy(&fb->Mutex); 2257117f1b4Smrg 22601e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 2277117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 2287117f1b4Smrg if (att->Renderbuffer) { 2297117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 2307117f1b4Smrg } 2317117f1b4Smrg if (att->Texture) { 2327117f1b4Smrg _mesa_reference_texobj(&att->Texture, NULL); 2337117f1b4Smrg } 23401e04c3fSmrg assert(!att->Renderbuffer); 23501e04c3fSmrg assert(!att->Texture); 2367117f1b4Smrg att->Type = GL_NONE; 2377117f1b4Smrg } 23801e04c3fSmrg 23901e04c3fSmrg free(fb->SampleLocationTable); 24001e04c3fSmrg fb->SampleLocationTable = NULL; 2417117f1b4Smrg} 2427117f1b4Smrg 2437117f1b4Smrg 2447117f1b4Smrg/** 2457117f1b4Smrg * Set *ptr to point to fb, with refcounting and locking. 246af69d88dSmrg * This is normally only called from the _mesa_reference_framebuffer() macro 247af69d88dSmrg * when there's a real pointer change. 2487117f1b4Smrg */ 2497117f1b4Smrgvoid 250af69d88dSmrg_mesa_reference_framebuffer_(struct gl_framebuffer **ptr, 251af69d88dSmrg struct gl_framebuffer *fb) 2527117f1b4Smrg{ 2534a49301eSmrg if (*ptr) { 2544a49301eSmrg /* unreference old renderbuffer */ 2557117f1b4Smrg GLboolean deleteFlag = GL_FALSE; 2564a49301eSmrg struct gl_framebuffer *oldFb = *ptr; 2577117f1b4Smrg 25801e04c3fSmrg simple_mtx_lock(&oldFb->Mutex); 25901e04c3fSmrg assert(oldFb->RefCount > 0); 2604a49301eSmrg oldFb->RefCount--; 2614a49301eSmrg deleteFlag = (oldFb->RefCount == 0); 26201e04c3fSmrg simple_mtx_unlock(&oldFb->Mutex); 26301e04c3fSmrg 2647117f1b4Smrg if (deleteFlag) 2654a49301eSmrg oldFb->Delete(oldFb); 2667117f1b4Smrg 2674a49301eSmrg *ptr = NULL; 2687117f1b4Smrg } 2697117f1b4Smrg 2704a49301eSmrg if (fb) { 27101e04c3fSmrg simple_mtx_lock(&fb->Mutex); 2724a49301eSmrg fb->RefCount++; 27301e04c3fSmrg simple_mtx_unlock(&fb->Mutex); 2744a49301eSmrg *ptr = fb; 2754a49301eSmrg } 2764a49301eSmrg} 2777117f1b4Smrg 2787117f1b4Smrg 2797117f1b4Smrg/** 2807117f1b4Smrg * Resize the given framebuffer's renderbuffers to the new width and height. 2817117f1b4Smrg * This should only be used for window-system framebuffers, not 2827117f1b4Smrg * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). 28301e04c3fSmrg * This will typically be called directly from a device driver. 2847117f1b4Smrg * 2857117f1b4Smrg * \note it's possible for ctx to be null since a window can be resized 2867117f1b4Smrg * without a currently bound rendering context. 2877117f1b4Smrg */ 2887117f1b4Smrgvoid 2893464ebd5Sriastradh_mesa_resize_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 2907117f1b4Smrg GLuint width, GLuint height) 2917117f1b4Smrg{ 2927117f1b4Smrg /* XXX I think we could check if the size is not changing 2937117f1b4Smrg * and return early. 2947117f1b4Smrg */ 2957117f1b4Smrg 296af69d88dSmrg /* Can only resize win-sys framebuffer objects */ 297af69d88dSmrg assert(_mesa_is_winsys_fbo(fb)); 2987117f1b4Smrg 29901e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 3007117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 3017117f1b4Smrg if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 3027117f1b4Smrg struct gl_renderbuffer *rb = att->Renderbuffer; 3037117f1b4Smrg /* only resize if size is changing */ 3047117f1b4Smrg if (rb->Width != width || rb->Height != height) { 3057117f1b4Smrg if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 30601e04c3fSmrg assert(rb->Width == width); 30701e04c3fSmrg assert(rb->Height == height); 3087117f1b4Smrg } 3097117f1b4Smrg else { 3107117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 3117117f1b4Smrg /* no return */ 3127117f1b4Smrg } 3137117f1b4Smrg } 3147117f1b4Smrg } 3157117f1b4Smrg } 3167117f1b4Smrg 3177117f1b4Smrg fb->Width = width; 3187117f1b4Smrg fb->Height = height; 3197117f1b4Smrg 3207117f1b4Smrg if (ctx) { 3217117f1b4Smrg /* update scissor / window bounds */ 32201e04c3fSmrg _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); 3237117f1b4Smrg /* Signal new buffer state so that swrast will update its clipping 3247117f1b4Smrg * info (the CLIP_BIT flag). 3257117f1b4Smrg */ 3267117f1b4Smrg ctx->NewState |= _NEW_BUFFERS; 3277117f1b4Smrg } 3287117f1b4Smrg} 3297117f1b4Smrg 3307117f1b4Smrg/** 33101e04c3fSmrg * Given a bounding box, intersect the bounding box with the scissor of 33201e04c3fSmrg * a specified vieport. 333af69d88dSmrg * 334af69d88dSmrg * \param ctx GL context. 335af69d88dSmrg * \param idx Index of the desired viewport 336af69d88dSmrg * \param bbox Bounding box for the scissored viewport. Stored as xmin, 337af69d88dSmrg * xmax, ymin, ymax. 338af69d88dSmrg */ 339af69d88dSmrgvoid 34001e04c3fSmrg_mesa_intersect_scissor_bounding_box(const struct gl_context *ctx, 34101e04c3fSmrg unsigned idx, int *bbox) 342af69d88dSmrg{ 343af69d88dSmrg if (ctx->Scissor.EnableFlags & (1u << idx)) { 344af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].X > bbox[0]) { 345af69d88dSmrg bbox[0] = ctx->Scissor.ScissorArray[idx].X; 346af69d88dSmrg } 347af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].Y > bbox[2]) { 348af69d88dSmrg bbox[2] = ctx->Scissor.ScissorArray[idx].Y; 349af69d88dSmrg } 350af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].X + ctx->Scissor.ScissorArray[idx].Width < bbox[1]) { 351af69d88dSmrg bbox[1] = ctx->Scissor.ScissorArray[idx].X + ctx->Scissor.ScissorArray[idx].Width; 352af69d88dSmrg } 353af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].Y + ctx->Scissor.ScissorArray[idx].Height < bbox[3]) { 354af69d88dSmrg bbox[3] = ctx->Scissor.ScissorArray[idx].Y + ctx->Scissor.ScissorArray[idx].Height; 355af69d88dSmrg } 356af69d88dSmrg /* finally, check for empty region */ 357af69d88dSmrg if (bbox[0] > bbox[1]) { 358af69d88dSmrg bbox[0] = bbox[1]; 359af69d88dSmrg } 360af69d88dSmrg if (bbox[2] > bbox[3]) { 361af69d88dSmrg bbox[2] = bbox[3]; 362af69d88dSmrg } 363af69d88dSmrg } 36401e04c3fSmrg} 365af69d88dSmrg 36601e04c3fSmrg/** 36701e04c3fSmrg * Calculate the inclusive bounding box for the scissor of a specific viewport 36801e04c3fSmrg * 36901e04c3fSmrg * \param ctx GL context. 37001e04c3fSmrg * \param buffer Framebuffer to be checked against 37101e04c3fSmrg * \param idx Index of the desired viewport 37201e04c3fSmrg * \param bbox Bounding box for the scissored viewport. Stored as xmin, 37301e04c3fSmrg * xmax, ymin, ymax. 37401e04c3fSmrg * 37501e04c3fSmrg * \warning This function assumes that the framebuffer dimensions are up to 37601e04c3fSmrg * date. 37701e04c3fSmrg * 37801e04c3fSmrg * \sa _mesa_clip_to_region 37901e04c3fSmrg */ 38001e04c3fSmrgstatic void 38101e04c3fSmrgscissor_bounding_box(const struct gl_context *ctx, 38201e04c3fSmrg const struct gl_framebuffer *buffer, 38301e04c3fSmrg unsigned idx, int *bbox) 38401e04c3fSmrg{ 38501e04c3fSmrg bbox[0] = 0; 38601e04c3fSmrg bbox[2] = 0; 38701e04c3fSmrg bbox[1] = buffer->Width; 38801e04c3fSmrg bbox[3] = buffer->Height; 38901e04c3fSmrg 39001e04c3fSmrg _mesa_intersect_scissor_bounding_box(ctx, idx, bbox); 39101e04c3fSmrg 39201e04c3fSmrg assert(bbox[0] <= bbox[1]); 39301e04c3fSmrg assert(bbox[2] <= bbox[3]); 394af69d88dSmrg} 395af69d88dSmrg 3967117f1b4Smrg/** 3977117f1b4Smrg * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields. 3987117f1b4Smrg * These values are computed from the buffer's width and height and 3997117f1b4Smrg * the scissor box, if it's enabled. 4007117f1b4Smrg * \param ctx the GL context. 4017117f1b4Smrg */ 4027117f1b4Smrgvoid 40301e04c3fSmrg_mesa_update_draw_buffer_bounds(struct gl_context *ctx, 40401e04c3fSmrg struct gl_framebuffer *buffer) 4057117f1b4Smrg{ 406af69d88dSmrg int bbox[4]; 4077117f1b4Smrg 4087117f1b4Smrg if (!buffer) 4097117f1b4Smrg return; 4107117f1b4Smrg 411af69d88dSmrg /* Default to the first scissor as that's always valid */ 41201e04c3fSmrg scissor_bounding_box(ctx, buffer, 0, bbox); 413af69d88dSmrg buffer->_Xmin = bbox[0]; 414af69d88dSmrg buffer->_Ymin = bbox[2]; 415af69d88dSmrg buffer->_Xmax = bbox[1]; 416af69d88dSmrg buffer->_Ymax = bbox[3]; 4177117f1b4Smrg} 4187117f1b4Smrg 4197117f1b4Smrg 4207117f1b4Smrg/** 4217117f1b4Smrg * The glGet queries of the framebuffer red/green/blue size, stencil size, 4227117f1b4Smrg * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can 4237117f1b4Smrg * change depending on the renderbuffer bindings. This function updates 4247117f1b4Smrg * the given framebuffer's Visual from the current renderbuffer bindings. 4257117f1b4Smrg * 4267117f1b4Smrg * This may apply to user-created framebuffers or window system framebuffers. 4277117f1b4Smrg * 4287117f1b4Smrg * Also note: ctx->DrawBuffer->Visual.depthBits might not equal 4297117f1b4Smrg * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. 4307117f1b4Smrg * The former one is used to convert floating point depth values into 4317117f1b4Smrg * integer Z values. 4327117f1b4Smrg */ 4337117f1b4Smrgvoid 4343464ebd5Sriastradh_mesa_update_framebuffer_visual(struct gl_context *ctx, 4353464ebd5Sriastradh struct gl_framebuffer *fb) 4367117f1b4Smrg{ 437cdc920a0Smrg memset(&fb->Visual, 0, sizeof(fb->Visual)); 4387117f1b4Smrg fb->Visual.rgbMode = GL_TRUE; /* assume this */ 4397117f1b4Smrg 440cdc920a0Smrg /* find first RGB renderbuffer */ 44101e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 4427117f1b4Smrg if (fb->Attachment[i].Renderbuffer) { 4437117f1b4Smrg const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 4444a49301eSmrg const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); 445af69d88dSmrg const mesa_format fmt = rb->Format; 446af69d88dSmrg 447af69d88dSmrg /* Grab samples and sampleBuffers from any attachment point (assuming 448af69d88dSmrg * the framebuffer is complete, we'll get the same answer from all 449af69d88dSmrg * attachments). 450af69d88dSmrg */ 451af69d88dSmrg fb->Visual.samples = rb->NumSamples; 452af69d88dSmrg fb->Visual.sampleBuffers = rb->NumSamples > 0 ? 1 : 0; 4533464ebd5Sriastradh 4543464ebd5Sriastradh if (_mesa_is_legal_color_format(ctx, baseFormat)) { 4554a49301eSmrg fb->Visual.redBits = _mesa_get_format_bits(fmt, GL_RED_BITS); 4564a49301eSmrg fb->Visual.greenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); 4574a49301eSmrg fb->Visual.blueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); 4584a49301eSmrg fb->Visual.alphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); 4597117f1b4Smrg fb->Visual.rgbBits = fb->Visual.redBits 4607117f1b4Smrg + fb->Visual.greenBits + fb->Visual.blueBits; 4613464ebd5Sriastradh if (_mesa_get_format_color_encoding(fmt) == GL_SRGB) 462af69d88dSmrg fb->Visual.sRGBCapable = ctx->Extensions.EXT_framebuffer_sRGB; 4633464ebd5Sriastradh break; 4643464ebd5Sriastradh } 4653464ebd5Sriastradh } 4663464ebd5Sriastradh } 4673464ebd5Sriastradh 4683464ebd5Sriastradh fb->Visual.floatMode = GL_FALSE; 46901e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 4703464ebd5Sriastradh if (fb->Attachment[i].Renderbuffer) { 4713464ebd5Sriastradh const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 472af69d88dSmrg const mesa_format fmt = rb->Format; 4733464ebd5Sriastradh 4743464ebd5Sriastradh if (_mesa_get_format_datatype(fmt) == GL_FLOAT) { 4753464ebd5Sriastradh fb->Visual.floatMode = GL_TRUE; 4767117f1b4Smrg break; 4777117f1b4Smrg } 4787117f1b4Smrg } 4797117f1b4Smrg } 4807117f1b4Smrg 4817117f1b4Smrg if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { 4824a49301eSmrg const struct gl_renderbuffer *rb = 4834a49301eSmrg fb->Attachment[BUFFER_DEPTH].Renderbuffer; 484af69d88dSmrg const mesa_format fmt = rb->Format; 4857117f1b4Smrg fb->Visual.haveDepthBuffer = GL_TRUE; 4864a49301eSmrg fb->Visual.depthBits = _mesa_get_format_bits(fmt, GL_DEPTH_BITS); 4877117f1b4Smrg } 4887117f1b4Smrg 4897117f1b4Smrg if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { 4904a49301eSmrg const struct gl_renderbuffer *rb = 4914a49301eSmrg fb->Attachment[BUFFER_STENCIL].Renderbuffer; 492af69d88dSmrg const mesa_format fmt = rb->Format; 4937117f1b4Smrg fb->Visual.haveStencilBuffer = GL_TRUE; 4944a49301eSmrg fb->Visual.stencilBits = _mesa_get_format_bits(fmt, GL_STENCIL_BITS); 4957117f1b4Smrg } 4967117f1b4Smrg 4977117f1b4Smrg if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) { 4984a49301eSmrg const struct gl_renderbuffer *rb = 4994a49301eSmrg fb->Attachment[BUFFER_ACCUM].Renderbuffer; 500af69d88dSmrg const mesa_format fmt = rb->Format; 5017117f1b4Smrg fb->Visual.haveAccumBuffer = GL_TRUE; 5024a49301eSmrg fb->Visual.accumRedBits = _mesa_get_format_bits(fmt, GL_RED_BITS); 5034a49301eSmrg fb->Visual.accumGreenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); 5044a49301eSmrg fb->Visual.accumBlueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); 5054a49301eSmrg fb->Visual.accumAlphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); 5067117f1b4Smrg } 5077117f1b4Smrg 5087117f1b4Smrg compute_depth_max(fb); 5097117f1b4Smrg} 5107117f1b4Smrg 5117117f1b4Smrg 512c1f859d4Smrg/* 513c1f859d4Smrg * Example DrawBuffers scenarios: 514c1f859d4Smrg * 515c1f859d4Smrg * 1. glDrawBuffer(GL_FRONT_AND_BACK), fixed-func or shader writes to 516c1f859d4Smrg * "gl_FragColor" or program writes to the "result.color" register: 517c1f859d4Smrg * 518c1f859d4Smrg * fragment color output renderbuffer 519c1f859d4Smrg * --------------------- --------------- 520c1f859d4Smrg * color[0] Front, Back 521c1f859d4Smrg * 522c1f859d4Smrg * 523c1f859d4Smrg * 2. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]), shader writes to 524c1f859d4Smrg * gl_FragData[i] or program writes to result.color[i] registers: 525c1f859d4Smrg * 526c1f859d4Smrg * fragment color output renderbuffer 527c1f859d4Smrg * --------------------- --------------- 528c1f859d4Smrg * color[0] Front 529c1f859d4Smrg * color[1] Aux0 530c1f859d4Smrg * color[3] Aux1 531c1f859d4Smrg * 532c1f859d4Smrg * 533c1f859d4Smrg * 3. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]) and shader writes to 534c1f859d4Smrg * gl_FragColor, or fixed function: 535c1f859d4Smrg * 536c1f859d4Smrg * fragment color output renderbuffer 537c1f859d4Smrg * --------------------- --------------- 538c1f859d4Smrg * color[0] Front, Aux0, Aux1 539c1f859d4Smrg * 540c1f859d4Smrg * 541c1f859d4Smrg * In either case, the list of renderbuffers is stored in the 542c1f859d4Smrg * framebuffer->_ColorDrawBuffers[] array and 543c1f859d4Smrg * framebuffer->_NumColorDrawBuffers indicates the number of buffers. 544c1f859d4Smrg * The renderer (like swrast) has to look at the current fragment shader 545c1f859d4Smrg * to see if it writes to gl_FragColor vs. gl_FragData[i] to determine 546c1f859d4Smrg * how to map color outputs to renderbuffers. 547c1f859d4Smrg * 548c1f859d4Smrg * Note that these two calls are equivalent (for fixed function fragment 549c1f859d4Smrg * shading anyway): 550c1f859d4Smrg * a) glDrawBuffer(GL_FRONT_AND_BACK); (assuming non-stereo framebuffer) 551c1f859d4Smrg * b) glDrawBuffers(2, [GL_FRONT_LEFT, GL_BACK_LEFT]); 552c1f859d4Smrg */ 553c1f859d4Smrg 554c1f859d4Smrg 555c1f859d4Smrg 556c1f859d4Smrg 5577117f1b4Smrg/** 558c1f859d4Smrg * Update the (derived) list of color drawing renderbuffer pointers. 5597117f1b4Smrg * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers 5607117f1b4Smrg * writing colors. 5617117f1b4Smrg */ 5627117f1b4Smrgstatic void 56301e04c3fSmrgupdate_color_draw_buffers(struct gl_framebuffer *fb) 5647117f1b4Smrg{ 5657117f1b4Smrg GLuint output; 5667117f1b4Smrg 567c1f859d4Smrg /* set 0th buffer to NULL now in case _NumColorDrawBuffers is zero */ 568c1f859d4Smrg fb->_ColorDrawBuffers[0] = NULL; 569c1f859d4Smrg 570c1f859d4Smrg for (output = 0; output < fb->_NumColorDrawBuffers; output++) { 57101e04c3fSmrg gl_buffer_index buf = fb->_ColorDrawBufferIndexes[output]; 57201e04c3fSmrg if (buf != BUFFER_NONE) { 573c1f859d4Smrg fb->_ColorDrawBuffers[output] = fb->Attachment[buf].Renderbuffer; 574c1f859d4Smrg } 575c1f859d4Smrg else { 576c1f859d4Smrg fb->_ColorDrawBuffers[output] = NULL; 5777117f1b4Smrg } 5787117f1b4Smrg } 5797117f1b4Smrg} 5807117f1b4Smrg 5817117f1b4Smrg 5827117f1b4Smrg/** 583c1f859d4Smrg * Update the (derived) color read renderbuffer pointer. 5847117f1b4Smrg * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. 5857117f1b4Smrg */ 5867117f1b4Smrgstatic void 58701e04c3fSmrgupdate_color_read_buffer(struct gl_framebuffer *fb) 5887117f1b4Smrg{ 58901e04c3fSmrg if (fb->_ColorReadBufferIndex == BUFFER_NONE || 5907117f1b4Smrg fb->DeletePending || 5917117f1b4Smrg fb->Width == 0 || 5927117f1b4Smrg fb->Height == 0) { 5937117f1b4Smrg fb->_ColorReadBuffer = NULL; /* legal! */ 5947117f1b4Smrg } 5957117f1b4Smrg else { 59601e04c3fSmrg assert(fb->_ColorReadBufferIndex >= 0); 59701e04c3fSmrg assert(fb->_ColorReadBufferIndex < BUFFER_COUNT); 5987117f1b4Smrg fb->_ColorReadBuffer 5997117f1b4Smrg = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; 6007117f1b4Smrg } 6017117f1b4Smrg} 6027117f1b4Smrg 6037117f1b4Smrg 6047117f1b4Smrg/** 605c1f859d4Smrg * Update a gl_framebuffer's derived state. 606c1f859d4Smrg * 6077117f1b4Smrg * Specifically, update these framebuffer fields: 6087117f1b4Smrg * _ColorDrawBuffers 6097117f1b4Smrg * _NumColorDrawBuffers 6107117f1b4Smrg * _ColorReadBuffer 611c1f859d4Smrg * 612c1f859d4Smrg * If the framebuffer is user-created, make sure it's complete. 613c1f859d4Smrg * 614c1f859d4Smrg * The following functions (at least) can effect framebuffer state: 615c1f859d4Smrg * glReadBuffer, glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT, 6167117f1b4Smrg * glRenderbufferStorageEXT. 6177117f1b4Smrg */ 618c1f859d4Smrgstatic void 6193464ebd5Sriastradhupdate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) 6207117f1b4Smrg{ 621af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) { 622c1f859d4Smrg /* This is a window-system framebuffer */ 623c1f859d4Smrg /* Need to update the FB's GL_DRAW_BUFFER state to match the 624c1f859d4Smrg * context state (GL_READ_BUFFER too). 625c1f859d4Smrg */ 626c1f859d4Smrg if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) { 62701e04c3fSmrg _mesa_drawbuffers(ctx, fb, ctx->Const.MaxDrawBuffers, 628c1f859d4Smrg ctx->Color.DrawBuffer, NULL); 629c1f859d4Smrg } 63001e04c3fSmrg 63101e04c3fSmrg /* Call device driver function if fb is the bound draw buffer. */ 63201e04c3fSmrg if (fb == ctx->DrawBuffer) { 63301e04c3fSmrg if (ctx->Driver.DrawBufferAllocate) 63401e04c3fSmrg ctx->Driver.DrawBufferAllocate(ctx); 63501e04c3fSmrg } 636c1f859d4Smrg } 637c1f859d4Smrg else { 638c1f859d4Smrg /* This is a user-created framebuffer. 639c1f859d4Smrg * Completeness only matters for user-created framebuffers. 640c1f859d4Smrg */ 6414a49301eSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE) { 6424a49301eSmrg _mesa_test_framebuffer_completeness(ctx, fb); 6434a49301eSmrg } 6447117f1b4Smrg } 6457117f1b4Smrg 646c1f859d4Smrg /* Strictly speaking, we don't need to update the draw-state 647c1f859d4Smrg * if this FB is bound as ctx->ReadBuffer (and conversely, the 648c1f859d4Smrg * read-state if this FB is bound as ctx->DrawBuffer), but no 649c1f859d4Smrg * harm. 650c1f859d4Smrg */ 65101e04c3fSmrg update_color_draw_buffers(fb); 65201e04c3fSmrg update_color_read_buffer(fb); 6537117f1b4Smrg 6547117f1b4Smrg compute_depth_max(fb); 6557117f1b4Smrg} 6567117f1b4Smrg 6577117f1b4Smrg 658c1f859d4Smrg/** 65901e04c3fSmrg * Update state related to the draw/read framebuffers. 660c1f859d4Smrg */ 661c1f859d4Smrgvoid 66201e04c3fSmrg_mesa_update_framebuffer(struct gl_context *ctx, 66301e04c3fSmrg struct gl_framebuffer *readFb, 66401e04c3fSmrg struct gl_framebuffer *drawFb) 665c1f859d4Smrg{ 666cdc920a0Smrg assert(ctx); 667c1f859d4Smrg 668c1f859d4Smrg update_framebuffer(ctx, drawFb); 669c1f859d4Smrg if (readFb != drawFb) 670c1f859d4Smrg update_framebuffer(ctx, readFb); 671af69d88dSmrg 67201e04c3fSmrg _mesa_update_clamp_vertex_color(ctx, drawFb); 67301e04c3fSmrg _mesa_update_clamp_fragment_color(ctx, drawFb); 674c1f859d4Smrg} 675c1f859d4Smrg 676c1f859d4Smrg 6777117f1b4Smrg/** 678af69d88dSmrg * Check if the renderbuffer for a read/draw operation exists. 6797117f1b4Smrg * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, 6807117f1b4Smrg * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. 681af69d88dSmrg * \param reading if TRUE, we're going to read from the buffer, 682af69d88dSmrg if FALSE, we're going to write to the buffer. 6837117f1b4Smrg * \return GL_TRUE if buffer exists, GL_FALSE otherwise 6847117f1b4Smrg */ 685af69d88dSmrgstatic GLboolean 686af69d88dSmrgrenderbuffer_exists(struct gl_context *ctx, 687af69d88dSmrg struct gl_framebuffer *fb, 688af69d88dSmrg GLenum format, 689af69d88dSmrg GLboolean reading) 6907117f1b4Smrg{ 691af69d88dSmrg const struct gl_renderbuffer_attachment *att = fb->Attachment; 6924a49301eSmrg 6934a49301eSmrg /* If we don't know the framebuffer status, update it now */ 694af69d88dSmrg if (fb->_Status == 0) { 695af69d88dSmrg _mesa_test_framebuffer_completeness(ctx, fb); 6964a49301eSmrg } 6977117f1b4Smrg 698af69d88dSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 6997117f1b4Smrg return GL_FALSE; 7007117f1b4Smrg } 7017117f1b4Smrg 7027117f1b4Smrg switch (format) { 7037117f1b4Smrg case GL_COLOR: 7047117f1b4Smrg case GL_RED: 7057117f1b4Smrg case GL_GREEN: 7067117f1b4Smrg case GL_BLUE: 7077117f1b4Smrg case GL_ALPHA: 7087117f1b4Smrg case GL_LUMINANCE: 7097117f1b4Smrg case GL_LUMINANCE_ALPHA: 7107117f1b4Smrg case GL_INTENSITY: 7113464ebd5Sriastradh case GL_RG: 7127117f1b4Smrg case GL_RGB: 7137117f1b4Smrg case GL_BGR: 7147117f1b4Smrg case GL_RGBA: 7157117f1b4Smrg case GL_BGRA: 7167117f1b4Smrg case GL_ABGR_EXT: 7173464ebd5Sriastradh case GL_RED_INTEGER_EXT: 718af69d88dSmrg case GL_RG_INTEGER: 7193464ebd5Sriastradh case GL_GREEN_INTEGER_EXT: 7203464ebd5Sriastradh case GL_BLUE_INTEGER_EXT: 7213464ebd5Sriastradh case GL_ALPHA_INTEGER_EXT: 7223464ebd5Sriastradh case GL_RGB_INTEGER_EXT: 7233464ebd5Sriastradh case GL_RGBA_INTEGER_EXT: 7243464ebd5Sriastradh case GL_BGR_INTEGER_EXT: 7253464ebd5Sriastradh case GL_BGRA_INTEGER_EXT: 7263464ebd5Sriastradh case GL_LUMINANCE_INTEGER_EXT: 7273464ebd5Sriastradh case GL_LUMINANCE_ALPHA_INTEGER_EXT: 728af69d88dSmrg if (reading) { 729af69d88dSmrg /* about to read from a color buffer */ 730af69d88dSmrg const struct gl_renderbuffer *readBuf = fb->_ColorReadBuffer; 731af69d88dSmrg if (!readBuf) { 732af69d88dSmrg return GL_FALSE; 733af69d88dSmrg } 73401e04c3fSmrg assert(_mesa_get_format_bits(readBuf->Format, GL_RED_BITS) > 0 || 735af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_ALPHA_BITS) > 0 || 736af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_TEXTURE_LUMINANCE_SIZE) > 0 || 737af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_TEXTURE_INTENSITY_SIZE) > 0 || 738af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_INDEX_BITS) > 0); 739af69d88dSmrg } 740af69d88dSmrg else { 741af69d88dSmrg /* about to draw to zero or more color buffers (none is OK) */ 742af69d88dSmrg return GL_TRUE; 7437117f1b4Smrg } 7447117f1b4Smrg break; 7457117f1b4Smrg case GL_DEPTH: 7467117f1b4Smrg case GL_DEPTH_COMPONENT: 747af69d88dSmrg if (att[BUFFER_DEPTH].Type == GL_NONE) { 7487117f1b4Smrg return GL_FALSE; 7497117f1b4Smrg } 7507117f1b4Smrg break; 7517117f1b4Smrg case GL_STENCIL: 7527117f1b4Smrg case GL_STENCIL_INDEX: 753af69d88dSmrg if (att[BUFFER_STENCIL].Type == GL_NONE) { 7547117f1b4Smrg return GL_FALSE; 7557117f1b4Smrg } 7567117f1b4Smrg break; 7577117f1b4Smrg case GL_DEPTH_STENCIL_EXT: 758af69d88dSmrg if (att[BUFFER_DEPTH].Type == GL_NONE || 759af69d88dSmrg att[BUFFER_STENCIL].Type == GL_NONE) { 7607117f1b4Smrg return GL_FALSE; 7617117f1b4Smrg } 7627117f1b4Smrg break; 7637117f1b4Smrg default: 7647117f1b4Smrg _mesa_problem(ctx, 765af69d88dSmrg "Unexpected format 0x%x in renderbuffer_exists", 7667117f1b4Smrg format); 7677117f1b4Smrg return GL_FALSE; 7687117f1b4Smrg } 7697117f1b4Smrg 7707117f1b4Smrg /* OK */ 7717117f1b4Smrg return GL_TRUE; 7727117f1b4Smrg} 7737117f1b4Smrg 7747117f1b4Smrg 775af69d88dSmrg/** 776af69d88dSmrg * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels, 777af69d88dSmrg * glCopyTex[Sub]Image, etc) exists. 778af69d88dSmrg * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, 779af69d88dSmrg * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. 780af69d88dSmrg * \return GL_TRUE if buffer exists, GL_FALSE otherwise 781af69d88dSmrg */ 782af69d88dSmrgGLboolean 783af69d88dSmrg_mesa_source_buffer_exists(struct gl_context *ctx, GLenum format) 784af69d88dSmrg{ 785af69d88dSmrg return renderbuffer_exists(ctx, ctx->ReadBuffer, format, GL_TRUE); 786af69d88dSmrg} 787af69d88dSmrg 788af69d88dSmrg 7897117f1b4Smrg/** 7907117f1b4Smrg * As above, but for drawing operations. 7917117f1b4Smrg */ 7927117f1b4SmrgGLboolean 7933464ebd5Sriastradh_mesa_dest_buffer_exists(struct gl_context *ctx, GLenum format) 7947117f1b4Smrg{ 795af69d88dSmrg return renderbuffer_exists(ctx, ctx->DrawBuffer, format, GL_FALSE); 796af69d88dSmrg} 7974a49301eSmrg 7987117f1b4Smrg 799af69d88dSmrg/** 80001e04c3fSmrg * Used to answer the GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES queries (using 80101e04c3fSmrg * GetIntegerv, GetFramebufferParameteriv, etc) 80201e04c3fSmrg * 80301e04c3fSmrg * If @fb is NULL, the method returns the value for the current bound 80401e04c3fSmrg * framebuffer. 805af69d88dSmrg */ 806af69d88dSmrgGLenum 80701e04c3fSmrg_mesa_get_color_read_format(struct gl_context *ctx, 80801e04c3fSmrg struct gl_framebuffer *fb, 80901e04c3fSmrg const char *caller) 810af69d88dSmrg{ 81101e04c3fSmrg if (ctx->NewState) 81201e04c3fSmrg _mesa_update_state(ctx); 81301e04c3fSmrg 81401e04c3fSmrg if (fb == NULL) 81501e04c3fSmrg fb = ctx->ReadBuffer; 81601e04c3fSmrg 81701e04c3fSmrg if (!fb || !fb->_ColorReadBuffer) { 81801e04c3fSmrg /* 81901e04c3fSmrg * From OpenGL 4.5 spec, section 18.2.2 "ReadPixels": 82001e04c3fSmrg * 82101e04c3fSmrg * "An INVALID_OPERATION error is generated by GetIntegerv if pname 82201e04c3fSmrg * is IMPLEMENTATION_COLOR_READ_FORMAT or IMPLEMENTATION_COLOR_- 82301e04c3fSmrg * READ_TYPE and any of: 82401e04c3fSmrg * * the read framebuffer is not framebuffer complete. 82501e04c3fSmrg * * the read framebuffer is a framebuffer object, and the selected 82601e04c3fSmrg * read buffer (see section 18.2.1) has no image attached. 82701e04c3fSmrg * * the selected read buffer is NONE." 82801e04c3fSmrg * 82901e04c3fSmrg * There is not equivalent quote for GetFramebufferParameteriv or 83001e04c3fSmrg * GetNamedFramebufferParameteriv, but from section 9.2.3 "Framebuffer 83101e04c3fSmrg * Object Queries": 83201e04c3fSmrg * 83301e04c3fSmrg * "Values of framebuffer-dependent state are identical to those that 83401e04c3fSmrg * would be obtained were the framebuffer object bound and queried 83501e04c3fSmrg * using the simple state queries in that table." 83601e04c3fSmrg * 83701e04c3fSmrg * Where "using the simple state queries" refer to use GetIntegerv. So 83801e04c3fSmrg * we will assume that on that situation the same error should be 83901e04c3fSmrg * triggered too. 840af69d88dSmrg */ 841af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 84201e04c3fSmrg "%s(GL_IMPLEMENTATION_COLOR_READ_FORMAT: no GL_READ_BUFFER)", 84301e04c3fSmrg caller); 844af69d88dSmrg return GL_NONE; 8457117f1b4Smrg } 846af69d88dSmrg else { 84701e04c3fSmrg const mesa_format format = fb->_ColorReadBuffer->Format; 8487117f1b4Smrg 84901e04c3fSmrg switch (format) { 85001e04c3fSmrg case MESA_FORMAT_RGBA_UINT8: 85101e04c3fSmrg return GL_RGBA_INTEGER; 85201e04c3fSmrg case MESA_FORMAT_B8G8R8A8_UNORM: 853af69d88dSmrg return GL_BGRA; 85401e04c3fSmrg case MESA_FORMAT_B5G6R5_UNORM: 85501e04c3fSmrg case MESA_FORMAT_R11G11B10_FLOAT: 85601e04c3fSmrg return GL_RGB; 85701e04c3fSmrg case MESA_FORMAT_RG_FLOAT32: 85801e04c3fSmrg case MESA_FORMAT_RG_FLOAT16: 85901e04c3fSmrg case MESA_FORMAT_R8G8_UNORM: 86001e04c3fSmrg case MESA_FORMAT_R8G8_SNORM: 86101e04c3fSmrg return GL_RG; 86201e04c3fSmrg case MESA_FORMAT_RG_SINT32: 86301e04c3fSmrg case MESA_FORMAT_RG_UINT32: 86401e04c3fSmrg case MESA_FORMAT_RG_SINT16: 86501e04c3fSmrg case MESA_FORMAT_RG_UINT16: 86601e04c3fSmrg case MESA_FORMAT_RG_SINT8: 86701e04c3fSmrg case MESA_FORMAT_RG_UINT8: 86801e04c3fSmrg return GL_RG_INTEGER; 86901e04c3fSmrg case MESA_FORMAT_R_FLOAT32: 87001e04c3fSmrg case MESA_FORMAT_R_FLOAT16: 87101e04c3fSmrg case MESA_FORMAT_R_UNORM16: 87201e04c3fSmrg case MESA_FORMAT_R_UNORM8: 87301e04c3fSmrg case MESA_FORMAT_R_SNORM16: 87401e04c3fSmrg case MESA_FORMAT_R_SNORM8: 87501e04c3fSmrg return GL_RED; 87601e04c3fSmrg case MESA_FORMAT_R_SINT32: 87701e04c3fSmrg case MESA_FORMAT_R_UINT32: 87801e04c3fSmrg case MESA_FORMAT_R_SINT16: 87901e04c3fSmrg case MESA_FORMAT_R_UINT16: 88001e04c3fSmrg case MESA_FORMAT_R_SINT8: 88101e04c3fSmrg case MESA_FORMAT_R_UINT8: 88201e04c3fSmrg return GL_RED_INTEGER; 88301e04c3fSmrg default: 88401e04c3fSmrg break; 88501e04c3fSmrg } 886af69d88dSmrg 88701e04c3fSmrg if (_mesa_is_format_integer(format)) 888af69d88dSmrg return GL_RGBA_INTEGER; 88901e04c3fSmrg else 890af69d88dSmrg return GL_RGBA; 8917117f1b4Smrg } 8927117f1b4Smrg} 8934a49301eSmrg 8943464ebd5Sriastradh 8953464ebd5Sriastradh/** 89601e04c3fSmrg * Used to answer the GL_IMPLEMENTATION_COLOR_READ_TYPE_OES queries (using 89701e04c3fSmrg * GetIntegerv, GetFramebufferParameteriv, etc) 89801e04c3fSmrg * 89901e04c3fSmrg * If @fb is NULL, the method returns the value for the current bound 90001e04c3fSmrg * framebuffer. 9013464ebd5Sriastradh */ 9024a49301eSmrgGLenum 90301e04c3fSmrg_mesa_get_color_read_type(struct gl_context *ctx, 90401e04c3fSmrg struct gl_framebuffer *fb, 90501e04c3fSmrg const char *caller) 9064a49301eSmrg{ 90701e04c3fSmrg if (ctx->NewState) 90801e04c3fSmrg _mesa_update_state(ctx); 90901e04c3fSmrg 91001e04c3fSmrg if (fb == NULL) 91101e04c3fSmrg fb = ctx->ReadBuffer; 91201e04c3fSmrg 91301e04c3fSmrg if (!fb || !fb->_ColorReadBuffer) { 91401e04c3fSmrg /* 91501e04c3fSmrg * See comment on _mesa_get_color_read_format 916af69d88dSmrg */ 917af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 91801e04c3fSmrg "%s(GL_IMPLEMENTATION_COLOR_READ_TYPE: no GL_READ_BUFFER)", 91901e04c3fSmrg caller); 920af69d88dSmrg return GL_NONE; 921af69d88dSmrg } 922af69d88dSmrg else { 92301e04c3fSmrg const mesa_format format = fb->_ColorReadBuffer->Format; 92401e04c3fSmrg GLenum data_type; 92501e04c3fSmrg GLuint comps; 92601e04c3fSmrg 92701e04c3fSmrg _mesa_uncompressed_format_to_type_and_comps(format, &data_type, &comps); 92801e04c3fSmrg 92901e04c3fSmrg return data_type; 9304a49301eSmrg } 9314a49301eSmrg} 9324a49301eSmrg 9333464ebd5Sriastradh 9343464ebd5Sriastradh/** 935af69d88dSmrg * Returns the read renderbuffer for the specified format. 9363464ebd5Sriastradh */ 937af69d88dSmrgstruct gl_renderbuffer * 938af69d88dSmrg_mesa_get_read_renderbuffer_for_format(const struct gl_context *ctx, 939af69d88dSmrg GLenum format) 9404a49301eSmrg{ 941af69d88dSmrg const struct gl_framebuffer *rfb = ctx->ReadBuffer; 942af69d88dSmrg 943af69d88dSmrg if (_mesa_is_color_format(format)) { 944af69d88dSmrg return rfb->Attachment[rfb->_ColorReadBufferIndex].Renderbuffer; 945af69d88dSmrg } else if (_mesa_is_depth_format(format) || 946af69d88dSmrg _mesa_is_depthstencil_format(format)) { 947af69d88dSmrg return rfb->Attachment[BUFFER_DEPTH].Renderbuffer; 948af69d88dSmrg } else { 949af69d88dSmrg return rfb->Attachment[BUFFER_STENCIL].Renderbuffer; 9504a49301eSmrg } 9514a49301eSmrg} 9523464ebd5Sriastradh 9533464ebd5Sriastradh 9543464ebd5Sriastradh/** 9553464ebd5Sriastradh * Print framebuffer info to stderr, for debugging. 9563464ebd5Sriastradh */ 9573464ebd5Sriastradhvoid 9583464ebd5Sriastradh_mesa_print_framebuffer(const struct gl_framebuffer *fb) 9593464ebd5Sriastradh{ 9603464ebd5Sriastradh fprintf(stderr, "Mesa Framebuffer %u at %p\n", fb->Name, (void *) fb); 9613464ebd5Sriastradh fprintf(stderr, " Size: %u x %u Status: %s\n", fb->Width, fb->Height, 96201e04c3fSmrg _mesa_enum_to_string(fb->_Status)); 9633464ebd5Sriastradh fprintf(stderr, " Attachments:\n"); 9643464ebd5Sriastradh 96501e04c3fSmrg for (unsigned i = 0; i < BUFFER_COUNT; i++) { 9663464ebd5Sriastradh const struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 9673464ebd5Sriastradh if (att->Type == GL_TEXTURE) { 968af69d88dSmrg const struct gl_texture_image *texImage = att->Renderbuffer->TexImage; 9693464ebd5Sriastradh fprintf(stderr, 9703464ebd5Sriastradh " %2d: Texture %u, level %u, face %u, slice %u, complete %d\n", 9713464ebd5Sriastradh i, att->Texture->Name, att->TextureLevel, att->CubeMapFace, 9723464ebd5Sriastradh att->Zoffset, att->Complete); 9733464ebd5Sriastradh fprintf(stderr, " Size: %u x %u x %u Format %s\n", 9743464ebd5Sriastradh texImage->Width, texImage->Height, texImage->Depth, 9753464ebd5Sriastradh _mesa_get_format_name(texImage->TexFormat)); 9763464ebd5Sriastradh } 9773464ebd5Sriastradh else if (att->Type == GL_RENDERBUFFER) { 9783464ebd5Sriastradh fprintf(stderr, " %2d: Renderbuffer %u, complete %d\n", 9793464ebd5Sriastradh i, att->Renderbuffer->Name, att->Complete); 9803464ebd5Sriastradh fprintf(stderr, " Size: %u x %u Format %s\n", 9813464ebd5Sriastradh att->Renderbuffer->Width, att->Renderbuffer->Height, 9823464ebd5Sriastradh _mesa_get_format_name(att->Renderbuffer->Format)); 9833464ebd5Sriastradh } 9843464ebd5Sriastradh else { 9853464ebd5Sriastradh fprintf(stderr, " %2d: none\n", i); 9863464ebd5Sriastradh } 9873464ebd5Sriastradh } 9883464ebd5Sriastradh} 98901e04c3fSmrg 99001e04c3fSmrgbool 99101e04c3fSmrg_mesa_is_front_buffer_reading(const struct gl_framebuffer *fb) 99201e04c3fSmrg{ 99301e04c3fSmrg if (!fb || _mesa_is_user_fbo(fb)) 99401e04c3fSmrg return false; 99501e04c3fSmrg 99601e04c3fSmrg return fb->_ColorReadBufferIndex == BUFFER_FRONT_LEFT; 99701e04c3fSmrg} 99801e04c3fSmrg 99901e04c3fSmrgbool 100001e04c3fSmrg_mesa_is_front_buffer_drawing(const struct gl_framebuffer *fb) 100101e04c3fSmrg{ 100201e04c3fSmrg if (!fb || _mesa_is_user_fbo(fb)) 100301e04c3fSmrg return false; 100401e04c3fSmrg 100501e04c3fSmrg return (fb->_NumColorDrawBuffers >= 1 && 100601e04c3fSmrg fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT); 100701e04c3fSmrg} 100801e04c3fSmrg 100901e04c3fSmrgstatic inline GLuint 101001e04c3fSmrg_mesa_geometric_nonvalidated_samples(const struct gl_framebuffer *buffer) 101101e04c3fSmrg{ 101201e04c3fSmrg return buffer->_HasAttachments ? 101301e04c3fSmrg buffer->Visual.samples : 101401e04c3fSmrg buffer->DefaultGeometry.NumSamples; 101501e04c3fSmrg} 101601e04c3fSmrg 101701e04c3fSmrgbool 101801e04c3fSmrg_mesa_is_multisample_enabled(const struct gl_context *ctx) 101901e04c3fSmrg{ 102001e04c3fSmrg /* The sample count may not be validated by the driver, but when it is set, 102101e04c3fSmrg * we know that is in a valid range and no driver should ever validate a 102201e04c3fSmrg * multisampled framebuffer to non-multisampled and vice-versa. 102301e04c3fSmrg */ 102401e04c3fSmrg return ctx->Multisample.Enabled && 102501e04c3fSmrg ctx->DrawBuffer && 102601e04c3fSmrg _mesa_geometric_nonvalidated_samples(ctx->DrawBuffer) >= 1; 102701e04c3fSmrg} 102801e04c3fSmrg 102901e04c3fSmrg/** 103001e04c3fSmrg * Is alpha testing enabled and applicable to the currently bound 103101e04c3fSmrg * framebuffer? 103201e04c3fSmrg */ 103301e04c3fSmrgbool 103401e04c3fSmrg_mesa_is_alpha_test_enabled(const struct gl_context *ctx) 103501e04c3fSmrg{ 103601e04c3fSmrg bool buffer0_is_integer = ctx->DrawBuffer->_IntegerBuffers & 0x1; 103701e04c3fSmrg return (ctx->Color.AlphaEnabled && !buffer0_is_integer); 103801e04c3fSmrg} 103901e04c3fSmrg 104001e04c3fSmrg/** 104101e04c3fSmrg * Is alpha to coverage enabled and applicable to the currently bound 104201e04c3fSmrg * framebuffer? 104301e04c3fSmrg */ 104401e04c3fSmrgbool 104501e04c3fSmrg_mesa_is_alpha_to_coverage_enabled(const struct gl_context *ctx) 104601e04c3fSmrg{ 104701e04c3fSmrg bool buffer0_is_integer = ctx->DrawBuffer->_IntegerBuffers & 0x1; 104801e04c3fSmrg return (ctx->Multisample.SampleAlphaToCoverage && 104901e04c3fSmrg _mesa_is_multisample_enabled(ctx) && 105001e04c3fSmrg !buffer0_is_integer); 105101e04c3fSmrg} 1052