framebuffer.c revision af69d88d
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 327117f1b4Smrg 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" 477117f1b4Smrg 487117f1b4Smrg 497117f1b4Smrg 507117f1b4Smrg/** 517117f1b4Smrg * Compute/set the _DepthMax field for the given framebuffer. 527117f1b4Smrg * This value depends on the Z buffer resolution. 537117f1b4Smrg */ 547117f1b4Smrgstatic void 557117f1b4Smrgcompute_depth_max(struct gl_framebuffer *fb) 567117f1b4Smrg{ 577117f1b4Smrg if (fb->Visual.depthBits == 0) { 587117f1b4Smrg /* Special case. Even if we don't have a depth buffer we need 597117f1b4Smrg * good values for DepthMax for Z vertex transformation purposes 607117f1b4Smrg * and for per-fragment fog computation. 617117f1b4Smrg */ 627117f1b4Smrg fb->_DepthMax = (1 << 16) - 1; 637117f1b4Smrg } 647117f1b4Smrg else if (fb->Visual.depthBits < 32) { 657117f1b4Smrg fb->_DepthMax = (1 << fb->Visual.depthBits) - 1; 667117f1b4Smrg } 677117f1b4Smrg else { 687117f1b4Smrg /* Special case since shift values greater than or equal to the 697117f1b4Smrg * number of bits in the left hand expression's type are undefined. 707117f1b4Smrg */ 717117f1b4Smrg fb->_DepthMax = 0xffffffff; 727117f1b4Smrg } 737117f1b4Smrg fb->_DepthMaxF = (GLfloat) fb->_DepthMax; 74c1f859d4Smrg 75c1f859d4Smrg /* Minimum resolvable depth value, for polygon offset */ 76c1f859d4Smrg fb->_MRD = (GLfloat)1.0 / fb->_DepthMaxF; 777117f1b4Smrg} 787117f1b4Smrg 797117f1b4Smrg/** 807117f1b4Smrg * Create and initialize a gl_framebuffer object. 817117f1b4Smrg * This is intended for creating _window_system_ framebuffers, not generic 827117f1b4Smrg * framebuffer objects ala GL_EXT_framebuffer_object. 837117f1b4Smrg * 847117f1b4Smrg * \sa _mesa_new_framebuffer 857117f1b4Smrg */ 867117f1b4Smrgstruct gl_framebuffer * 873464ebd5Sriastradh_mesa_create_framebuffer(const struct gl_config *visual) 887117f1b4Smrg{ 897117f1b4Smrg struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer); 907117f1b4Smrg assert(visual); 917117f1b4Smrg if (fb) { 92cdc920a0Smrg _mesa_initialize_window_framebuffer(fb, visual); 937117f1b4Smrg } 947117f1b4Smrg return fb; 957117f1b4Smrg} 967117f1b4Smrg 977117f1b4Smrg 987117f1b4Smrg/** 997117f1b4Smrg * Allocate a new gl_framebuffer object. 1007117f1b4Smrg * This is the default function for ctx->Driver.NewFramebuffer(). 1017117f1b4Smrg * This is for allocating user-created framebuffers, not window-system 1027117f1b4Smrg * framebuffers! 1037117f1b4Smrg * \sa _mesa_create_framebuffer 1047117f1b4Smrg */ 1057117f1b4Smrgstruct gl_framebuffer * 1063464ebd5Sriastradh_mesa_new_framebuffer(struct gl_context *ctx, GLuint name) 1077117f1b4Smrg{ 1087117f1b4Smrg struct gl_framebuffer *fb; 1097117f1b4Smrg (void) ctx; 1107117f1b4Smrg assert(name != 0); 1117117f1b4Smrg fb = CALLOC_STRUCT(gl_framebuffer); 1127117f1b4Smrg if (fb) { 113cdc920a0Smrg _mesa_initialize_user_framebuffer(fb, name); 1147117f1b4Smrg } 1157117f1b4Smrg return fb; 1167117f1b4Smrg} 1177117f1b4Smrg 1187117f1b4Smrg 1197117f1b4Smrg/** 1207117f1b4Smrg * Initialize a gl_framebuffer object. Typically used to initialize 1217117f1b4Smrg * window system-created framebuffers, not user-created framebuffers. 122cdc920a0Smrg * \sa _mesa_initialize_user_framebuffer 1237117f1b4Smrg */ 1247117f1b4Smrgvoid 125cdc920a0Smrg_mesa_initialize_window_framebuffer(struct gl_framebuffer *fb, 1263464ebd5Sriastradh const struct gl_config *visual) 1277117f1b4Smrg{ 1287117f1b4Smrg assert(fb); 1297117f1b4Smrg assert(visual); 1307117f1b4Smrg 131cdc920a0Smrg memset(fb, 0, sizeof(struct gl_framebuffer)); 1327117f1b4Smrg 133af69d88dSmrg mtx_init(&fb->Mutex, mtx_plain); 1347117f1b4Smrg 1357117f1b4Smrg fb->RefCount = 1; 1367117f1b4Smrg 1377117f1b4Smrg /* save the visual */ 1387117f1b4Smrg fb->Visual = *visual; 1397117f1b4Smrg 140c1f859d4Smrg /* Init read/draw renderbuffer state */ 1417117f1b4Smrg if (visual->doubleBufferMode) { 142c1f859d4Smrg fb->_NumColorDrawBuffers = 1; 1437117f1b4Smrg fb->ColorDrawBuffer[0] = GL_BACK; 144c1f859d4Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_BACK_LEFT; 1457117f1b4Smrg fb->ColorReadBuffer = GL_BACK; 1467117f1b4Smrg fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT; 1477117f1b4Smrg } 1487117f1b4Smrg else { 149c1f859d4Smrg fb->_NumColorDrawBuffers = 1; 1507117f1b4Smrg fb->ColorDrawBuffer[0] = GL_FRONT; 151c1f859d4Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_FRONT_LEFT; 1527117f1b4Smrg fb->ColorReadBuffer = GL_FRONT; 1537117f1b4Smrg fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT; 1547117f1b4Smrg } 1557117f1b4Smrg 1567117f1b4Smrg fb->Delete = _mesa_destroy_framebuffer; 1577117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 158af69d88dSmrg fb->_AllColorBuffersFixedPoint = !visual->floatMode; 159af69d88dSmrg fb->_HasSNormOrFloatColorBuffer = visual->floatMode; 1607117f1b4Smrg 1617117f1b4Smrg compute_depth_max(fb); 1627117f1b4Smrg} 1637117f1b4Smrg 1647117f1b4Smrg 165cdc920a0Smrg/** 166cdc920a0Smrg * Initialize a user-created gl_framebuffer object. 167cdc920a0Smrg * \sa _mesa_initialize_window_framebuffer 168cdc920a0Smrg */ 169cdc920a0Smrgvoid 170cdc920a0Smrg_mesa_initialize_user_framebuffer(struct gl_framebuffer *fb, GLuint name) 171cdc920a0Smrg{ 172cdc920a0Smrg assert(fb); 173cdc920a0Smrg assert(name); 174cdc920a0Smrg 175cdc920a0Smrg memset(fb, 0, sizeof(struct gl_framebuffer)); 176cdc920a0Smrg 177cdc920a0Smrg fb->Name = name; 178cdc920a0Smrg fb->RefCount = 1; 179cdc920a0Smrg fb->_NumColorDrawBuffers = 1; 180cdc920a0Smrg fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT; 181cdc920a0Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_COLOR0; 182cdc920a0Smrg fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT; 183cdc920a0Smrg fb->_ColorReadBufferIndex = BUFFER_COLOR0; 184cdc920a0Smrg fb->Delete = _mesa_destroy_framebuffer; 185af69d88dSmrg mtx_init(&fb->Mutex, mtx_plain); 186cdc920a0Smrg} 187cdc920a0Smrg 188cdc920a0Smrg 1897117f1b4Smrg/** 1907117f1b4Smrg * Deallocate buffer and everything attached to it. 1917117f1b4Smrg * Typically called via the gl_framebuffer->Delete() method. 1927117f1b4Smrg */ 1937117f1b4Smrgvoid 1947117f1b4Smrg_mesa_destroy_framebuffer(struct gl_framebuffer *fb) 1957117f1b4Smrg{ 1967117f1b4Smrg if (fb) { 1977117f1b4Smrg _mesa_free_framebuffer_data(fb); 198af69d88dSmrg free(fb->Label); 199cdc920a0Smrg free(fb); 2007117f1b4Smrg } 2017117f1b4Smrg} 2027117f1b4Smrg 2037117f1b4Smrg 2047117f1b4Smrg/** 2057117f1b4Smrg * Free all the data hanging off the given gl_framebuffer, but don't free 2067117f1b4Smrg * the gl_framebuffer object itself. 2077117f1b4Smrg */ 2087117f1b4Smrgvoid 2097117f1b4Smrg_mesa_free_framebuffer_data(struct gl_framebuffer *fb) 2107117f1b4Smrg{ 2117117f1b4Smrg GLuint i; 2127117f1b4Smrg 2137117f1b4Smrg assert(fb); 2147117f1b4Smrg assert(fb->RefCount == 0); 2157117f1b4Smrg 216af69d88dSmrg mtx_destroy(&fb->Mutex); 2177117f1b4Smrg 2187117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 2197117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 2207117f1b4Smrg if (att->Renderbuffer) { 2217117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 2227117f1b4Smrg } 2237117f1b4Smrg if (att->Texture) { 2247117f1b4Smrg _mesa_reference_texobj(&att->Texture, NULL); 2257117f1b4Smrg } 2267117f1b4Smrg ASSERT(!att->Renderbuffer); 2277117f1b4Smrg ASSERT(!att->Texture); 2287117f1b4Smrg att->Type = GL_NONE; 2297117f1b4Smrg } 2307117f1b4Smrg} 2317117f1b4Smrg 2327117f1b4Smrg 2337117f1b4Smrg/** 2347117f1b4Smrg * Set *ptr to point to fb, with refcounting and locking. 235af69d88dSmrg * This is normally only called from the _mesa_reference_framebuffer() macro 236af69d88dSmrg * when there's a real pointer change. 2377117f1b4Smrg */ 2387117f1b4Smrgvoid 239af69d88dSmrg_mesa_reference_framebuffer_(struct gl_framebuffer **ptr, 240af69d88dSmrg struct gl_framebuffer *fb) 2417117f1b4Smrg{ 2424a49301eSmrg if (*ptr) { 2434a49301eSmrg /* unreference old renderbuffer */ 2447117f1b4Smrg GLboolean deleteFlag = GL_FALSE; 2454a49301eSmrg struct gl_framebuffer *oldFb = *ptr; 2467117f1b4Smrg 247af69d88dSmrg mtx_lock(&oldFb->Mutex); 2484a49301eSmrg ASSERT(oldFb->RefCount > 0); 2494a49301eSmrg oldFb->RefCount--; 2504a49301eSmrg deleteFlag = (oldFb->RefCount == 0); 251af69d88dSmrg mtx_unlock(&oldFb->Mutex); 2527117f1b4Smrg 2537117f1b4Smrg if (deleteFlag) 2544a49301eSmrg oldFb->Delete(oldFb); 2557117f1b4Smrg 2564a49301eSmrg *ptr = NULL; 2577117f1b4Smrg } 2584a49301eSmrg assert(!*ptr); 2597117f1b4Smrg 2604a49301eSmrg if (fb) { 261af69d88dSmrg mtx_lock(&fb->Mutex); 2624a49301eSmrg fb->RefCount++; 263af69d88dSmrg mtx_unlock(&fb->Mutex); 2644a49301eSmrg *ptr = fb; 2654a49301eSmrg } 2664a49301eSmrg} 2677117f1b4Smrg 2687117f1b4Smrg 2697117f1b4Smrg/** 2707117f1b4Smrg * Resize the given framebuffer's renderbuffers to the new width and height. 2717117f1b4Smrg * This should only be used for window-system framebuffers, not 2727117f1b4Smrg * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). 2737117f1b4Smrg * This will typically be called via ctx->Driver.ResizeBuffers() or directly 2747117f1b4Smrg * from a device driver. 2757117f1b4Smrg * 2767117f1b4Smrg * \note it's possible for ctx to be null since a window can be resized 2777117f1b4Smrg * without a currently bound rendering context. 2787117f1b4Smrg */ 2797117f1b4Smrgvoid 2803464ebd5Sriastradh_mesa_resize_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 2817117f1b4Smrg GLuint width, GLuint height) 2827117f1b4Smrg{ 2837117f1b4Smrg GLuint i; 2847117f1b4Smrg 2857117f1b4Smrg /* XXX I think we could check if the size is not changing 2867117f1b4Smrg * and return early. 2877117f1b4Smrg */ 2887117f1b4Smrg 289af69d88dSmrg /* Can only resize win-sys framebuffer objects */ 290af69d88dSmrg assert(_mesa_is_winsys_fbo(fb)); 2917117f1b4Smrg 2927117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 2937117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 2947117f1b4Smrg if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 2957117f1b4Smrg struct gl_renderbuffer *rb = att->Renderbuffer; 2967117f1b4Smrg /* only resize if size is changing */ 2977117f1b4Smrg if (rb->Width != width || rb->Height != height) { 2987117f1b4Smrg if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 2997117f1b4Smrg ASSERT(rb->Width == width); 3007117f1b4Smrg ASSERT(rb->Height == height); 3017117f1b4Smrg } 3027117f1b4Smrg else { 3037117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 3047117f1b4Smrg /* no return */ 3057117f1b4Smrg } 3067117f1b4Smrg } 3077117f1b4Smrg } 3087117f1b4Smrg } 3097117f1b4Smrg 3107117f1b4Smrg fb->Width = width; 3117117f1b4Smrg fb->Height = height; 3127117f1b4Smrg 3137117f1b4Smrg if (ctx) { 3147117f1b4Smrg /* update scissor / window bounds */ 3157117f1b4Smrg _mesa_update_draw_buffer_bounds(ctx); 3167117f1b4Smrg /* Signal new buffer state so that swrast will update its clipping 3177117f1b4Smrg * info (the CLIP_BIT flag). 3187117f1b4Smrg */ 3197117f1b4Smrg ctx->NewState |= _NEW_BUFFERS; 3207117f1b4Smrg } 3217117f1b4Smrg} 3227117f1b4Smrg 3237117f1b4Smrg/** 3247117f1b4Smrg * Examine all the framebuffer's renderbuffers to update the Width/Height 3257117f1b4Smrg * fields of the framebuffer. If we have renderbuffers with different 3264a49301eSmrg * sizes, set the framebuffer's width and height to the min size. 3277117f1b4Smrg * Note: this is only intended for user-created framebuffers, not 3287117f1b4Smrg * window-system framebuffes. 3297117f1b4Smrg */ 3307117f1b4Smrgstatic void 3313464ebd5Sriastradhupdate_framebuffer_size(struct gl_context *ctx, struct gl_framebuffer *fb) 3327117f1b4Smrg{ 3334a49301eSmrg GLuint minWidth = ~0, minHeight = ~0; 3347117f1b4Smrg GLuint i; 3357117f1b4Smrg 3367117f1b4Smrg /* user-created framebuffers only */ 337af69d88dSmrg assert(_mesa_is_user_fbo(fb)); 3387117f1b4Smrg 3397117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 3407117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 3417117f1b4Smrg const struct gl_renderbuffer *rb = att->Renderbuffer; 3427117f1b4Smrg if (rb) { 3434a49301eSmrg minWidth = MIN2(minWidth, rb->Width); 3444a49301eSmrg minHeight = MIN2(minHeight, rb->Height); 3457117f1b4Smrg } 3467117f1b4Smrg } 3474a49301eSmrg 3484a49301eSmrg if (minWidth != ~0) { 3494a49301eSmrg fb->Width = minWidth; 3504a49301eSmrg fb->Height = minHeight; 3514a49301eSmrg } 3524a49301eSmrg else { 3534a49301eSmrg fb->Width = 0; 3544a49301eSmrg fb->Height = 0; 3554a49301eSmrg } 3567117f1b4Smrg} 3577117f1b4Smrg 3587117f1b4Smrg 359af69d88dSmrg/** 360af69d88dSmrg * Calculate the inclusive bounding box for the scissor of a specific viewport 361af69d88dSmrg * 362af69d88dSmrg * \param ctx GL context. 363af69d88dSmrg * \param buffer Framebuffer to be checked against 364af69d88dSmrg * \param idx Index of the desired viewport 365af69d88dSmrg * \param bbox Bounding box for the scissored viewport. Stored as xmin, 366af69d88dSmrg * xmax, ymin, ymax. 367af69d88dSmrg * 368af69d88dSmrg * \warning This function assumes that the framebuffer dimensions are up to 369af69d88dSmrg * date (e.g., update_framebuffer_size has been recently called on \c buffer). 370af69d88dSmrg * 371af69d88dSmrg * \sa _mesa_clip_to_region 372af69d88dSmrg */ 373af69d88dSmrgvoid 374af69d88dSmrg_mesa_scissor_bounding_box(const struct gl_context *ctx, 375af69d88dSmrg const struct gl_framebuffer *buffer, 376af69d88dSmrg unsigned idx, int *bbox) 377af69d88dSmrg{ 378af69d88dSmrg bbox[0] = 0; 379af69d88dSmrg bbox[2] = 0; 380af69d88dSmrg bbox[1] = buffer->Width; 381af69d88dSmrg bbox[3] = buffer->Height; 382af69d88dSmrg 383af69d88dSmrg if (ctx->Scissor.EnableFlags & (1u << idx)) { 384af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].X > bbox[0]) { 385af69d88dSmrg bbox[0] = ctx->Scissor.ScissorArray[idx].X; 386af69d88dSmrg } 387af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].Y > bbox[2]) { 388af69d88dSmrg bbox[2] = ctx->Scissor.ScissorArray[idx].Y; 389af69d88dSmrg } 390af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].X + ctx->Scissor.ScissorArray[idx].Width < bbox[1]) { 391af69d88dSmrg bbox[1] = ctx->Scissor.ScissorArray[idx].X + ctx->Scissor.ScissorArray[idx].Width; 392af69d88dSmrg } 393af69d88dSmrg if (ctx->Scissor.ScissorArray[idx].Y + ctx->Scissor.ScissorArray[idx].Height < bbox[3]) { 394af69d88dSmrg bbox[3] = ctx->Scissor.ScissorArray[idx].Y + ctx->Scissor.ScissorArray[idx].Height; 395af69d88dSmrg } 396af69d88dSmrg /* finally, check for empty region */ 397af69d88dSmrg if (bbox[0] > bbox[1]) { 398af69d88dSmrg bbox[0] = bbox[1]; 399af69d88dSmrg } 400af69d88dSmrg if (bbox[2] > bbox[3]) { 401af69d88dSmrg bbox[2] = bbox[3]; 402af69d88dSmrg } 403af69d88dSmrg } 404af69d88dSmrg 405af69d88dSmrg ASSERT(bbox[0] <= bbox[1]); 406af69d88dSmrg ASSERT(bbox[2] <= bbox[3]); 407af69d88dSmrg} 408af69d88dSmrg 4097117f1b4Smrg/** 4107117f1b4Smrg * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields. 4117117f1b4Smrg * These values are computed from the buffer's width and height and 4127117f1b4Smrg * the scissor box, if it's enabled. 4137117f1b4Smrg * \param ctx the GL context. 4147117f1b4Smrg */ 4157117f1b4Smrgvoid 4163464ebd5Sriastradh_mesa_update_draw_buffer_bounds(struct gl_context *ctx) 4177117f1b4Smrg{ 4187117f1b4Smrg struct gl_framebuffer *buffer = ctx->DrawBuffer; 419af69d88dSmrg int bbox[4]; 4207117f1b4Smrg 4217117f1b4Smrg if (!buffer) 4227117f1b4Smrg return; 4237117f1b4Smrg 424af69d88dSmrg if (_mesa_is_user_fbo(buffer)) { 4257117f1b4Smrg /* user-created framebuffer size depends on the renderbuffers */ 4264a49301eSmrg update_framebuffer_size(ctx, buffer); 4277117f1b4Smrg } 4287117f1b4Smrg 429af69d88dSmrg /* Default to the first scissor as that's always valid */ 430af69d88dSmrg _mesa_scissor_bounding_box(ctx, buffer, 0, bbox); 431af69d88dSmrg buffer->_Xmin = bbox[0]; 432af69d88dSmrg buffer->_Ymin = bbox[2]; 433af69d88dSmrg buffer->_Xmax = bbox[1]; 434af69d88dSmrg buffer->_Ymax = bbox[3]; 4357117f1b4Smrg} 4367117f1b4Smrg 4377117f1b4Smrg 4387117f1b4Smrg/** 4397117f1b4Smrg * The glGet queries of the framebuffer red/green/blue size, stencil size, 4407117f1b4Smrg * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can 4417117f1b4Smrg * change depending on the renderbuffer bindings. This function updates 4427117f1b4Smrg * the given framebuffer's Visual from the current renderbuffer bindings. 4437117f1b4Smrg * 4447117f1b4Smrg * This may apply to user-created framebuffers or window system framebuffers. 4457117f1b4Smrg * 4467117f1b4Smrg * Also note: ctx->DrawBuffer->Visual.depthBits might not equal 4477117f1b4Smrg * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. 4487117f1b4Smrg * The former one is used to convert floating point depth values into 4497117f1b4Smrg * integer Z values. 4507117f1b4Smrg */ 4517117f1b4Smrgvoid 4523464ebd5Sriastradh_mesa_update_framebuffer_visual(struct gl_context *ctx, 4533464ebd5Sriastradh struct gl_framebuffer *fb) 4547117f1b4Smrg{ 4557117f1b4Smrg GLuint i; 4567117f1b4Smrg 457cdc920a0Smrg memset(&fb->Visual, 0, sizeof(fb->Visual)); 4587117f1b4Smrg fb->Visual.rgbMode = GL_TRUE; /* assume this */ 4597117f1b4Smrg 4607117f1b4Smrg#if 0 /* this _might_ be needed */ 4617117f1b4Smrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 4627117f1b4Smrg /* leave visual fields zero'd */ 4637117f1b4Smrg return; 4647117f1b4Smrg } 4657117f1b4Smrg#endif 4667117f1b4Smrg 467cdc920a0Smrg /* find first RGB renderbuffer */ 4687117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 4697117f1b4Smrg if (fb->Attachment[i].Renderbuffer) { 4707117f1b4Smrg const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 4714a49301eSmrg const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); 472af69d88dSmrg const mesa_format fmt = rb->Format; 473af69d88dSmrg 474af69d88dSmrg /* Grab samples and sampleBuffers from any attachment point (assuming 475af69d88dSmrg * the framebuffer is complete, we'll get the same answer from all 476af69d88dSmrg * attachments). 477af69d88dSmrg */ 478af69d88dSmrg fb->Visual.samples = rb->NumSamples; 479af69d88dSmrg fb->Visual.sampleBuffers = rb->NumSamples > 0 ? 1 : 0; 4803464ebd5Sriastradh 4813464ebd5Sriastradh if (_mesa_is_legal_color_format(ctx, baseFormat)) { 4824a49301eSmrg fb->Visual.redBits = _mesa_get_format_bits(fmt, GL_RED_BITS); 4834a49301eSmrg fb->Visual.greenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); 4844a49301eSmrg fb->Visual.blueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); 4854a49301eSmrg fb->Visual.alphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); 4867117f1b4Smrg fb->Visual.rgbBits = fb->Visual.redBits 4877117f1b4Smrg + fb->Visual.greenBits + fb->Visual.blueBits; 4883464ebd5Sriastradh if (_mesa_get_format_color_encoding(fmt) == GL_SRGB) 489af69d88dSmrg fb->Visual.sRGBCapable = ctx->Extensions.EXT_framebuffer_sRGB; 4903464ebd5Sriastradh break; 4913464ebd5Sriastradh } 4923464ebd5Sriastradh } 4933464ebd5Sriastradh } 4943464ebd5Sriastradh 4953464ebd5Sriastradh fb->Visual.floatMode = GL_FALSE; 4963464ebd5Sriastradh for (i = 0; i < BUFFER_COUNT; i++) { 4973464ebd5Sriastradh if (fb->Attachment[i].Renderbuffer) { 4983464ebd5Sriastradh const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 499af69d88dSmrg const mesa_format fmt = rb->Format; 5003464ebd5Sriastradh 5013464ebd5Sriastradh if (_mesa_get_format_datatype(fmt) == GL_FLOAT) { 5023464ebd5Sriastradh fb->Visual.floatMode = GL_TRUE; 5037117f1b4Smrg break; 5047117f1b4Smrg } 5057117f1b4Smrg } 5067117f1b4Smrg } 5077117f1b4Smrg 5087117f1b4Smrg if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { 5094a49301eSmrg const struct gl_renderbuffer *rb = 5104a49301eSmrg fb->Attachment[BUFFER_DEPTH].Renderbuffer; 511af69d88dSmrg const mesa_format fmt = rb->Format; 5127117f1b4Smrg fb->Visual.haveDepthBuffer = GL_TRUE; 5134a49301eSmrg fb->Visual.depthBits = _mesa_get_format_bits(fmt, GL_DEPTH_BITS); 5147117f1b4Smrg } 5157117f1b4Smrg 5167117f1b4Smrg if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { 5174a49301eSmrg const struct gl_renderbuffer *rb = 5184a49301eSmrg fb->Attachment[BUFFER_STENCIL].Renderbuffer; 519af69d88dSmrg const mesa_format fmt = rb->Format; 5207117f1b4Smrg fb->Visual.haveStencilBuffer = GL_TRUE; 5214a49301eSmrg fb->Visual.stencilBits = _mesa_get_format_bits(fmt, GL_STENCIL_BITS); 5227117f1b4Smrg } 5237117f1b4Smrg 5247117f1b4Smrg if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) { 5254a49301eSmrg const struct gl_renderbuffer *rb = 5264a49301eSmrg fb->Attachment[BUFFER_ACCUM].Renderbuffer; 527af69d88dSmrg const mesa_format fmt = rb->Format; 5287117f1b4Smrg fb->Visual.haveAccumBuffer = GL_TRUE; 5294a49301eSmrg fb->Visual.accumRedBits = _mesa_get_format_bits(fmt, GL_RED_BITS); 5304a49301eSmrg fb->Visual.accumGreenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); 5314a49301eSmrg fb->Visual.accumBlueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); 5324a49301eSmrg fb->Visual.accumAlphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); 5337117f1b4Smrg } 5347117f1b4Smrg 5357117f1b4Smrg compute_depth_max(fb); 5367117f1b4Smrg} 5377117f1b4Smrg 5387117f1b4Smrg 539c1f859d4Smrg/* 540c1f859d4Smrg * Example DrawBuffers scenarios: 541c1f859d4Smrg * 542c1f859d4Smrg * 1. glDrawBuffer(GL_FRONT_AND_BACK), fixed-func or shader writes to 543c1f859d4Smrg * "gl_FragColor" or program writes to the "result.color" register: 544c1f859d4Smrg * 545c1f859d4Smrg * fragment color output renderbuffer 546c1f859d4Smrg * --------------------- --------------- 547c1f859d4Smrg * color[0] Front, Back 548c1f859d4Smrg * 549c1f859d4Smrg * 550c1f859d4Smrg * 2. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]), shader writes to 551c1f859d4Smrg * gl_FragData[i] or program writes to result.color[i] registers: 552c1f859d4Smrg * 553c1f859d4Smrg * fragment color output renderbuffer 554c1f859d4Smrg * --------------------- --------------- 555c1f859d4Smrg * color[0] Front 556c1f859d4Smrg * color[1] Aux0 557c1f859d4Smrg * color[3] Aux1 558c1f859d4Smrg * 559c1f859d4Smrg * 560c1f859d4Smrg * 3. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]) and shader writes to 561c1f859d4Smrg * gl_FragColor, or fixed function: 562c1f859d4Smrg * 563c1f859d4Smrg * fragment color output renderbuffer 564c1f859d4Smrg * --------------------- --------------- 565c1f859d4Smrg * color[0] Front, Aux0, Aux1 566c1f859d4Smrg * 567c1f859d4Smrg * 568c1f859d4Smrg * In either case, the list of renderbuffers is stored in the 569c1f859d4Smrg * framebuffer->_ColorDrawBuffers[] array and 570c1f859d4Smrg * framebuffer->_NumColorDrawBuffers indicates the number of buffers. 571c1f859d4Smrg * The renderer (like swrast) has to look at the current fragment shader 572c1f859d4Smrg * to see if it writes to gl_FragColor vs. gl_FragData[i] to determine 573c1f859d4Smrg * how to map color outputs to renderbuffers. 574c1f859d4Smrg * 575c1f859d4Smrg * Note that these two calls are equivalent (for fixed function fragment 576c1f859d4Smrg * shading anyway): 577c1f859d4Smrg * a) glDrawBuffer(GL_FRONT_AND_BACK); (assuming non-stereo framebuffer) 578c1f859d4Smrg * b) glDrawBuffers(2, [GL_FRONT_LEFT, GL_BACK_LEFT]); 579c1f859d4Smrg */ 580c1f859d4Smrg 581c1f859d4Smrg 582c1f859d4Smrg 583c1f859d4Smrg 5847117f1b4Smrg/** 585c1f859d4Smrg * Update the (derived) list of color drawing renderbuffer pointers. 5867117f1b4Smrg * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers 5877117f1b4Smrg * writing colors. 5887117f1b4Smrg */ 5897117f1b4Smrgstatic void 5903464ebd5Sriastradhupdate_color_draw_buffers(struct gl_context *ctx, struct gl_framebuffer *fb) 5917117f1b4Smrg{ 5927117f1b4Smrg GLuint output; 5937117f1b4Smrg 594c1f859d4Smrg /* set 0th buffer to NULL now in case _NumColorDrawBuffers is zero */ 595c1f859d4Smrg fb->_ColorDrawBuffers[0] = NULL; 596c1f859d4Smrg 597c1f859d4Smrg for (output = 0; output < fb->_NumColorDrawBuffers; output++) { 598c1f859d4Smrg GLint buf = fb->_ColorDrawBufferIndexes[output]; 599c1f859d4Smrg if (buf >= 0) { 600c1f859d4Smrg fb->_ColorDrawBuffers[output] = fb->Attachment[buf].Renderbuffer; 601c1f859d4Smrg } 602c1f859d4Smrg else { 603c1f859d4Smrg fb->_ColorDrawBuffers[output] = NULL; 6047117f1b4Smrg } 6057117f1b4Smrg } 6067117f1b4Smrg} 6077117f1b4Smrg 6087117f1b4Smrg 6097117f1b4Smrg/** 610c1f859d4Smrg * Update the (derived) color read renderbuffer pointer. 6117117f1b4Smrg * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. 6127117f1b4Smrg */ 6137117f1b4Smrgstatic void 6143464ebd5Sriastradhupdate_color_read_buffer(struct gl_context *ctx, struct gl_framebuffer *fb) 6157117f1b4Smrg{ 6167117f1b4Smrg (void) ctx; 6177117f1b4Smrg if (fb->_ColorReadBufferIndex == -1 || 6187117f1b4Smrg fb->DeletePending || 6197117f1b4Smrg fb->Width == 0 || 6207117f1b4Smrg fb->Height == 0) { 6217117f1b4Smrg fb->_ColorReadBuffer = NULL; /* legal! */ 6227117f1b4Smrg } 6237117f1b4Smrg else { 6247117f1b4Smrg ASSERT(fb->_ColorReadBufferIndex >= 0); 6257117f1b4Smrg ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT); 6267117f1b4Smrg fb->_ColorReadBuffer 6277117f1b4Smrg = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; 6287117f1b4Smrg } 6297117f1b4Smrg} 6307117f1b4Smrg 6317117f1b4Smrg 6327117f1b4Smrg/** 633c1f859d4Smrg * Update a gl_framebuffer's derived state. 634c1f859d4Smrg * 6357117f1b4Smrg * Specifically, update these framebuffer fields: 6367117f1b4Smrg * _ColorDrawBuffers 6377117f1b4Smrg * _NumColorDrawBuffers 6387117f1b4Smrg * _ColorReadBuffer 639c1f859d4Smrg * 640c1f859d4Smrg * If the framebuffer is user-created, make sure it's complete. 641c1f859d4Smrg * 642c1f859d4Smrg * The following functions (at least) can effect framebuffer state: 643c1f859d4Smrg * glReadBuffer, glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT, 6447117f1b4Smrg * glRenderbufferStorageEXT. 6457117f1b4Smrg */ 646c1f859d4Smrgstatic void 6473464ebd5Sriastradhupdate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) 6487117f1b4Smrg{ 649af69d88dSmrg if (_mesa_is_winsys_fbo(fb)) { 650c1f859d4Smrg /* This is a window-system framebuffer */ 651c1f859d4Smrg /* Need to update the FB's GL_DRAW_BUFFER state to match the 652c1f859d4Smrg * context state (GL_READ_BUFFER too). 653c1f859d4Smrg */ 654c1f859d4Smrg if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) { 655c1f859d4Smrg _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, 656c1f859d4Smrg ctx->Color.DrawBuffer, NULL); 657c1f859d4Smrg } 658c1f859d4Smrg } 659c1f859d4Smrg else { 660c1f859d4Smrg /* This is a user-created framebuffer. 661c1f859d4Smrg * Completeness only matters for user-created framebuffers. 662c1f859d4Smrg */ 6634a49301eSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE) { 6644a49301eSmrg _mesa_test_framebuffer_completeness(ctx, fb); 6654a49301eSmrg } 6667117f1b4Smrg } 6677117f1b4Smrg 668c1f859d4Smrg /* Strictly speaking, we don't need to update the draw-state 669c1f859d4Smrg * if this FB is bound as ctx->ReadBuffer (and conversely, the 670c1f859d4Smrg * read-state if this FB is bound as ctx->DrawBuffer), but no 671c1f859d4Smrg * harm. 672c1f859d4Smrg */ 6737117f1b4Smrg update_color_draw_buffers(ctx, fb); 6747117f1b4Smrg update_color_read_buffer(ctx, fb); 6757117f1b4Smrg 6767117f1b4Smrg compute_depth_max(fb); 6777117f1b4Smrg} 6787117f1b4Smrg 6797117f1b4Smrg 680c1f859d4Smrg/** 681c1f859d4Smrg * Update state related to the current draw/read framebuffers. 682c1f859d4Smrg */ 683c1f859d4Smrgvoid 6843464ebd5Sriastradh_mesa_update_framebuffer(struct gl_context *ctx) 685c1f859d4Smrg{ 686cdc920a0Smrg struct gl_framebuffer *drawFb; 687cdc920a0Smrg struct gl_framebuffer *readFb; 688cdc920a0Smrg 689cdc920a0Smrg assert(ctx); 690cdc920a0Smrg drawFb = ctx->DrawBuffer; 691cdc920a0Smrg readFb = ctx->ReadBuffer; 692c1f859d4Smrg 693c1f859d4Smrg update_framebuffer(ctx, drawFb); 694c1f859d4Smrg if (readFb != drawFb) 695c1f859d4Smrg update_framebuffer(ctx, readFb); 696af69d88dSmrg 697af69d88dSmrg _mesa_update_clamp_vertex_color(ctx); 698af69d88dSmrg _mesa_update_clamp_fragment_color(ctx); 699c1f859d4Smrg} 700c1f859d4Smrg 701c1f859d4Smrg 7027117f1b4Smrg/** 703af69d88dSmrg * Check if the renderbuffer for a read/draw operation exists. 7047117f1b4Smrg * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, 7057117f1b4Smrg * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. 706af69d88dSmrg * \param reading if TRUE, we're going to read from the buffer, 707af69d88dSmrg if FALSE, we're going to write to the buffer. 7087117f1b4Smrg * \return GL_TRUE if buffer exists, GL_FALSE otherwise 7097117f1b4Smrg */ 710af69d88dSmrgstatic GLboolean 711af69d88dSmrgrenderbuffer_exists(struct gl_context *ctx, 712af69d88dSmrg struct gl_framebuffer *fb, 713af69d88dSmrg GLenum format, 714af69d88dSmrg GLboolean reading) 7157117f1b4Smrg{ 716af69d88dSmrg const struct gl_renderbuffer_attachment *att = fb->Attachment; 7174a49301eSmrg 7184a49301eSmrg /* If we don't know the framebuffer status, update it now */ 719af69d88dSmrg if (fb->_Status == 0) { 720af69d88dSmrg _mesa_test_framebuffer_completeness(ctx, fb); 7214a49301eSmrg } 7227117f1b4Smrg 723af69d88dSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 7247117f1b4Smrg return GL_FALSE; 7257117f1b4Smrg } 7267117f1b4Smrg 7277117f1b4Smrg switch (format) { 7287117f1b4Smrg case GL_COLOR: 7297117f1b4Smrg case GL_RED: 7307117f1b4Smrg case GL_GREEN: 7317117f1b4Smrg case GL_BLUE: 7327117f1b4Smrg case GL_ALPHA: 7337117f1b4Smrg case GL_LUMINANCE: 7347117f1b4Smrg case GL_LUMINANCE_ALPHA: 7357117f1b4Smrg case GL_INTENSITY: 7363464ebd5Sriastradh case GL_RG: 7377117f1b4Smrg case GL_RGB: 7387117f1b4Smrg case GL_BGR: 7397117f1b4Smrg case GL_RGBA: 7407117f1b4Smrg case GL_BGRA: 7417117f1b4Smrg case GL_ABGR_EXT: 7423464ebd5Sriastradh case GL_RED_INTEGER_EXT: 743af69d88dSmrg case GL_RG_INTEGER: 7443464ebd5Sriastradh case GL_GREEN_INTEGER_EXT: 7453464ebd5Sriastradh case GL_BLUE_INTEGER_EXT: 7463464ebd5Sriastradh case GL_ALPHA_INTEGER_EXT: 7473464ebd5Sriastradh case GL_RGB_INTEGER_EXT: 7483464ebd5Sriastradh case GL_RGBA_INTEGER_EXT: 7493464ebd5Sriastradh case GL_BGR_INTEGER_EXT: 7503464ebd5Sriastradh case GL_BGRA_INTEGER_EXT: 7513464ebd5Sriastradh case GL_LUMINANCE_INTEGER_EXT: 7523464ebd5Sriastradh case GL_LUMINANCE_ALPHA_INTEGER_EXT: 753af69d88dSmrg if (reading) { 754af69d88dSmrg /* about to read from a color buffer */ 755af69d88dSmrg const struct gl_renderbuffer *readBuf = fb->_ColorReadBuffer; 756af69d88dSmrg if (!readBuf) { 757af69d88dSmrg return GL_FALSE; 758af69d88dSmrg } 759af69d88dSmrg ASSERT(_mesa_get_format_bits(readBuf->Format, GL_RED_BITS) > 0 || 760af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_ALPHA_BITS) > 0 || 761af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_TEXTURE_LUMINANCE_SIZE) > 0 || 762af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_TEXTURE_INTENSITY_SIZE) > 0 || 763af69d88dSmrg _mesa_get_format_bits(readBuf->Format, GL_INDEX_BITS) > 0); 764af69d88dSmrg } 765af69d88dSmrg else { 766af69d88dSmrg /* about to draw to zero or more color buffers (none is OK) */ 767af69d88dSmrg return GL_TRUE; 7687117f1b4Smrg } 7697117f1b4Smrg break; 7707117f1b4Smrg case GL_DEPTH: 7717117f1b4Smrg case GL_DEPTH_COMPONENT: 772af69d88dSmrg if (att[BUFFER_DEPTH].Type == GL_NONE) { 7737117f1b4Smrg return GL_FALSE; 7747117f1b4Smrg } 7757117f1b4Smrg break; 7767117f1b4Smrg case GL_STENCIL: 7777117f1b4Smrg case GL_STENCIL_INDEX: 778af69d88dSmrg if (att[BUFFER_STENCIL].Type == GL_NONE) { 7797117f1b4Smrg return GL_FALSE; 7807117f1b4Smrg } 7817117f1b4Smrg break; 7827117f1b4Smrg case GL_DEPTH_STENCIL_EXT: 783af69d88dSmrg if (att[BUFFER_DEPTH].Type == GL_NONE || 784af69d88dSmrg att[BUFFER_STENCIL].Type == GL_NONE) { 7857117f1b4Smrg return GL_FALSE; 7867117f1b4Smrg } 7877117f1b4Smrg break; 7887117f1b4Smrg default: 7897117f1b4Smrg _mesa_problem(ctx, 790af69d88dSmrg "Unexpected format 0x%x in renderbuffer_exists", 7917117f1b4Smrg format); 7927117f1b4Smrg return GL_FALSE; 7937117f1b4Smrg } 7947117f1b4Smrg 7957117f1b4Smrg /* OK */ 7967117f1b4Smrg return GL_TRUE; 7977117f1b4Smrg} 7987117f1b4Smrg 7997117f1b4Smrg 800af69d88dSmrg/** 801af69d88dSmrg * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels, 802af69d88dSmrg * glCopyTex[Sub]Image, etc) exists. 803af69d88dSmrg * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, 804af69d88dSmrg * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. 805af69d88dSmrg * \return GL_TRUE if buffer exists, GL_FALSE otherwise 806af69d88dSmrg */ 807af69d88dSmrgGLboolean 808af69d88dSmrg_mesa_source_buffer_exists(struct gl_context *ctx, GLenum format) 809af69d88dSmrg{ 810af69d88dSmrg return renderbuffer_exists(ctx, ctx->ReadBuffer, format, GL_TRUE); 811af69d88dSmrg} 812af69d88dSmrg 813af69d88dSmrg 8147117f1b4Smrg/** 8157117f1b4Smrg * As above, but for drawing operations. 8167117f1b4Smrg */ 8177117f1b4SmrgGLboolean 8183464ebd5Sriastradh_mesa_dest_buffer_exists(struct gl_context *ctx, GLenum format) 8197117f1b4Smrg{ 820af69d88dSmrg return renderbuffer_exists(ctx, ctx->DrawBuffer, format, GL_FALSE); 821af69d88dSmrg} 8224a49301eSmrg 8237117f1b4Smrg 824af69d88dSmrg/** 825af69d88dSmrg * Used to answer the GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES query. 826af69d88dSmrg */ 827af69d88dSmrgGLenum 828af69d88dSmrg_mesa_get_color_read_format(struct gl_context *ctx) 829af69d88dSmrg{ 830af69d88dSmrg if (!ctx->ReadBuffer || !ctx->ReadBuffer->_ColorReadBuffer) { 831af69d88dSmrg /* The spec is unclear how to handle this case, but NVIDIA's 832af69d88dSmrg * driver generates GL_INVALID_OPERATION. 833af69d88dSmrg */ 834af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 835af69d88dSmrg "glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT: " 836af69d88dSmrg "no GL_READ_BUFFER)"); 837af69d88dSmrg return GL_NONE; 8387117f1b4Smrg } 839af69d88dSmrg else { 840af69d88dSmrg const GLenum format = ctx->ReadBuffer->_ColorReadBuffer->Format; 841af69d88dSmrg const GLenum data_type = _mesa_get_format_datatype(format); 8427117f1b4Smrg 843af69d88dSmrg if (format == MESA_FORMAT_B8G8R8A8_UNORM) 844af69d88dSmrg return GL_BGRA; 845af69d88dSmrg else if (format == MESA_FORMAT_B5G6R5_UNORM) 846af69d88dSmrg return GL_BGR; 847af69d88dSmrg 848af69d88dSmrg switch (data_type) { 849af69d88dSmrg case GL_UNSIGNED_INT: 850af69d88dSmrg case GL_INT: 851af69d88dSmrg return GL_RGBA_INTEGER; 852af69d88dSmrg default: 853af69d88dSmrg return GL_RGBA; 8547117f1b4Smrg } 8557117f1b4Smrg } 8567117f1b4Smrg} 8574a49301eSmrg 8583464ebd5Sriastradh 8593464ebd5Sriastradh/** 860af69d88dSmrg * Used to answer the GL_IMPLEMENTATION_COLOR_READ_TYPE_OES query. 8613464ebd5Sriastradh */ 8624a49301eSmrgGLenum 863af69d88dSmrg_mesa_get_color_read_type(struct gl_context *ctx) 8644a49301eSmrg{ 865af69d88dSmrg if (!ctx->ReadBuffer || !ctx->ReadBuffer->_ColorReadBuffer) { 866af69d88dSmrg /* The spec is unclear how to handle this case, but NVIDIA's 867af69d88dSmrg * driver generates GL_INVALID_OPERATION. 868af69d88dSmrg */ 869af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 870af69d88dSmrg "glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE: " 871af69d88dSmrg "no GL_READ_BUFFER)"); 872af69d88dSmrg return GL_NONE; 873af69d88dSmrg } 874af69d88dSmrg else { 875af69d88dSmrg const GLenum format = ctx->ReadBuffer->_ColorReadBuffer->Format; 876af69d88dSmrg const GLenum data_type = _mesa_get_format_datatype(format); 877af69d88dSmrg 878af69d88dSmrg if (format == MESA_FORMAT_B5G6R5_UNORM) 879af69d88dSmrg return GL_UNSIGNED_SHORT_5_6_5_REV; 880af69d88dSmrg 881af69d88dSmrg switch (data_type) { 882af69d88dSmrg case GL_SIGNED_NORMALIZED: 883af69d88dSmrg return GL_BYTE; 884af69d88dSmrg case GL_UNSIGNED_INT: 885af69d88dSmrg case GL_INT: 886af69d88dSmrg case GL_FLOAT: 887af69d88dSmrg return data_type; 888af69d88dSmrg case GL_UNSIGNED_NORMALIZED: 889af69d88dSmrg default: 890af69d88dSmrg return GL_UNSIGNED_BYTE; 891af69d88dSmrg } 8924a49301eSmrg } 8934a49301eSmrg} 8944a49301eSmrg 8953464ebd5Sriastradh 8963464ebd5Sriastradh/** 897af69d88dSmrg * Returns the read renderbuffer for the specified format. 8983464ebd5Sriastradh */ 899af69d88dSmrgstruct gl_renderbuffer * 900af69d88dSmrg_mesa_get_read_renderbuffer_for_format(const struct gl_context *ctx, 901af69d88dSmrg GLenum format) 9024a49301eSmrg{ 903af69d88dSmrg const struct gl_framebuffer *rfb = ctx->ReadBuffer; 904af69d88dSmrg 905af69d88dSmrg if (_mesa_is_color_format(format)) { 906af69d88dSmrg return rfb->Attachment[rfb->_ColorReadBufferIndex].Renderbuffer; 907af69d88dSmrg } else if (_mesa_is_depth_format(format) || 908af69d88dSmrg _mesa_is_depthstencil_format(format)) { 909af69d88dSmrg return rfb->Attachment[BUFFER_DEPTH].Renderbuffer; 910af69d88dSmrg } else { 911af69d88dSmrg return rfb->Attachment[BUFFER_STENCIL].Renderbuffer; 9124a49301eSmrg } 9134a49301eSmrg} 9143464ebd5Sriastradh 9153464ebd5Sriastradh 9163464ebd5Sriastradh/** 9173464ebd5Sriastradh * Print framebuffer info to stderr, for debugging. 9183464ebd5Sriastradh */ 9193464ebd5Sriastradhvoid 9203464ebd5Sriastradh_mesa_print_framebuffer(const struct gl_framebuffer *fb) 9213464ebd5Sriastradh{ 9223464ebd5Sriastradh GLuint i; 9233464ebd5Sriastradh 9243464ebd5Sriastradh fprintf(stderr, "Mesa Framebuffer %u at %p\n", fb->Name, (void *) fb); 9253464ebd5Sriastradh fprintf(stderr, " Size: %u x %u Status: %s\n", fb->Width, fb->Height, 9263464ebd5Sriastradh _mesa_lookup_enum_by_nr(fb->_Status)); 9273464ebd5Sriastradh fprintf(stderr, " Attachments:\n"); 9283464ebd5Sriastradh 9293464ebd5Sriastradh for (i = 0; i < BUFFER_COUNT; i++) { 9303464ebd5Sriastradh const struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 9313464ebd5Sriastradh if (att->Type == GL_TEXTURE) { 932af69d88dSmrg const struct gl_texture_image *texImage = att->Renderbuffer->TexImage; 9333464ebd5Sriastradh fprintf(stderr, 9343464ebd5Sriastradh " %2d: Texture %u, level %u, face %u, slice %u, complete %d\n", 9353464ebd5Sriastradh i, att->Texture->Name, att->TextureLevel, att->CubeMapFace, 9363464ebd5Sriastradh att->Zoffset, att->Complete); 9373464ebd5Sriastradh fprintf(stderr, " Size: %u x %u x %u Format %s\n", 9383464ebd5Sriastradh texImage->Width, texImage->Height, texImage->Depth, 9393464ebd5Sriastradh _mesa_get_format_name(texImage->TexFormat)); 9403464ebd5Sriastradh } 9413464ebd5Sriastradh else if (att->Type == GL_RENDERBUFFER) { 9423464ebd5Sriastradh fprintf(stderr, " %2d: Renderbuffer %u, complete %d\n", 9433464ebd5Sriastradh i, att->Renderbuffer->Name, att->Complete); 9443464ebd5Sriastradh fprintf(stderr, " Size: %u x %u Format %s\n", 9453464ebd5Sriastradh att->Renderbuffer->Width, att->Renderbuffer->Height, 9463464ebd5Sriastradh _mesa_get_format_name(att->Renderbuffer->Format)); 9473464ebd5Sriastradh } 9483464ebd5Sriastradh else { 9493464ebd5Sriastradh fprintf(stderr, " %2d: none\n", i); 9503464ebd5Sriastradh } 9513464ebd5Sriastradh } 9523464ebd5Sriastradh} 953