framebuffer.c revision cdc920a0
17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 3c1f859d4Smrg * Version: 7.2 47117f1b4Smrg * 5c1f859d4Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 67117f1b4Smrg * 77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 87117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 97117f1b4Smrg * to deal in the Software without restriction, including without limitation 107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 127117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 137117f1b4Smrg * 147117f1b4Smrg * The above copyright notice and this permission notice shall be included 157117f1b4Smrg * in all copies or substantial portions of the Software. 167117f1b4Smrg * 177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 207117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 217117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 227117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR 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" 35c1f859d4Smrg#include "buffers.h" 367117f1b4Smrg#include "context.h" 377117f1b4Smrg#include "depthstencil.h" 384a49301eSmrg#include "formats.h" 394a49301eSmrg#include "macros.h" 407117f1b4Smrg#include "mtypes.h" 417117f1b4Smrg#include "fbobject.h" 427117f1b4Smrg#include "framebuffer.h" 437117f1b4Smrg#include "renderbuffer.h" 447117f1b4Smrg#include "texobj.h" 457117f1b4Smrg 467117f1b4Smrg 477117f1b4Smrg 487117f1b4Smrg/** 497117f1b4Smrg * Compute/set the _DepthMax field for the given framebuffer. 507117f1b4Smrg * This value depends on the Z buffer resolution. 517117f1b4Smrg */ 527117f1b4Smrgstatic void 537117f1b4Smrgcompute_depth_max(struct gl_framebuffer *fb) 547117f1b4Smrg{ 557117f1b4Smrg if (fb->Visual.depthBits == 0) { 567117f1b4Smrg /* Special case. Even if we don't have a depth buffer we need 577117f1b4Smrg * good values for DepthMax for Z vertex transformation purposes 587117f1b4Smrg * and for per-fragment fog computation. 597117f1b4Smrg */ 607117f1b4Smrg fb->_DepthMax = (1 << 16) - 1; 617117f1b4Smrg } 627117f1b4Smrg else if (fb->Visual.depthBits < 32) { 637117f1b4Smrg fb->_DepthMax = (1 << fb->Visual.depthBits) - 1; 647117f1b4Smrg } 657117f1b4Smrg else { 667117f1b4Smrg /* Special case since shift values greater than or equal to the 677117f1b4Smrg * number of bits in the left hand expression's type are undefined. 687117f1b4Smrg */ 697117f1b4Smrg fb->_DepthMax = 0xffffffff; 707117f1b4Smrg } 717117f1b4Smrg fb->_DepthMaxF = (GLfloat) fb->_DepthMax; 72c1f859d4Smrg 73c1f859d4Smrg /* Minimum resolvable depth value, for polygon offset */ 74c1f859d4Smrg fb->_MRD = (GLfloat)1.0 / fb->_DepthMaxF; 757117f1b4Smrg} 767117f1b4Smrg 777117f1b4Smrg 787117f1b4Smrg/** 797117f1b4Smrg * Create and initialize a gl_framebuffer object. 807117f1b4Smrg * This is intended for creating _window_system_ framebuffers, not generic 817117f1b4Smrg * framebuffer objects ala GL_EXT_framebuffer_object. 827117f1b4Smrg * 837117f1b4Smrg * \sa _mesa_new_framebuffer 847117f1b4Smrg */ 857117f1b4Smrgstruct gl_framebuffer * 867117f1b4Smrg_mesa_create_framebuffer(const GLvisual *visual) 877117f1b4Smrg{ 887117f1b4Smrg struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer); 897117f1b4Smrg assert(visual); 907117f1b4Smrg if (fb) { 91cdc920a0Smrg _mesa_initialize_window_framebuffer(fb, visual); 927117f1b4Smrg } 937117f1b4Smrg return fb; 947117f1b4Smrg} 957117f1b4Smrg 967117f1b4Smrg 977117f1b4Smrg/** 987117f1b4Smrg * Allocate a new gl_framebuffer object. 997117f1b4Smrg * This is the default function for ctx->Driver.NewFramebuffer(). 1007117f1b4Smrg * This is for allocating user-created framebuffers, not window-system 1017117f1b4Smrg * framebuffers! 1027117f1b4Smrg * \sa _mesa_create_framebuffer 1037117f1b4Smrg */ 1047117f1b4Smrgstruct gl_framebuffer * 1057117f1b4Smrg_mesa_new_framebuffer(GLcontext *ctx, GLuint name) 1067117f1b4Smrg{ 1077117f1b4Smrg struct gl_framebuffer *fb; 1087117f1b4Smrg (void) ctx; 1097117f1b4Smrg assert(name != 0); 1107117f1b4Smrg fb = CALLOC_STRUCT(gl_framebuffer); 1117117f1b4Smrg if (fb) { 112cdc920a0Smrg _mesa_initialize_user_framebuffer(fb, name); 1137117f1b4Smrg } 1147117f1b4Smrg return fb; 1157117f1b4Smrg} 1167117f1b4Smrg 1177117f1b4Smrg 1187117f1b4Smrg/** 1197117f1b4Smrg * Initialize a gl_framebuffer object. Typically used to initialize 1207117f1b4Smrg * window system-created framebuffers, not user-created framebuffers. 121cdc920a0Smrg * \sa _mesa_initialize_user_framebuffer 1227117f1b4Smrg */ 1237117f1b4Smrgvoid 124cdc920a0Smrg_mesa_initialize_window_framebuffer(struct gl_framebuffer *fb, 125cdc920a0Smrg const GLvisual *visual) 1267117f1b4Smrg{ 1277117f1b4Smrg assert(fb); 1287117f1b4Smrg assert(visual); 1297117f1b4Smrg 130cdc920a0Smrg memset(fb, 0, sizeof(struct gl_framebuffer)); 1317117f1b4Smrg 1327117f1b4Smrg _glthread_INIT_MUTEX(fb->Mutex); 1337117f1b4Smrg 1347117f1b4Smrg fb->RefCount = 1; 1357117f1b4Smrg 1367117f1b4Smrg /* save the visual */ 1377117f1b4Smrg fb->Visual = *visual; 1387117f1b4Smrg 139c1f859d4Smrg /* Init read/draw renderbuffer state */ 1407117f1b4Smrg if (visual->doubleBufferMode) { 141c1f859d4Smrg fb->_NumColorDrawBuffers = 1; 1427117f1b4Smrg fb->ColorDrawBuffer[0] = GL_BACK; 143c1f859d4Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_BACK_LEFT; 1447117f1b4Smrg fb->ColorReadBuffer = GL_BACK; 1457117f1b4Smrg fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT; 1467117f1b4Smrg } 1477117f1b4Smrg else { 148c1f859d4Smrg fb->_NumColorDrawBuffers = 1; 1497117f1b4Smrg fb->ColorDrawBuffer[0] = GL_FRONT; 150c1f859d4Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_FRONT_LEFT; 1517117f1b4Smrg fb->ColorReadBuffer = GL_FRONT; 1527117f1b4Smrg fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT; 1537117f1b4Smrg } 1547117f1b4Smrg 1557117f1b4Smrg fb->Delete = _mesa_destroy_framebuffer; 1567117f1b4Smrg fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 1577117f1b4Smrg 1587117f1b4Smrg compute_depth_max(fb); 1597117f1b4Smrg} 1607117f1b4Smrg 1617117f1b4Smrg 162cdc920a0Smrg/** 163cdc920a0Smrg * Initialize a user-created gl_framebuffer object. 164cdc920a0Smrg * \sa _mesa_initialize_window_framebuffer 165cdc920a0Smrg */ 166cdc920a0Smrgvoid 167cdc920a0Smrg_mesa_initialize_user_framebuffer(struct gl_framebuffer *fb, GLuint name) 168cdc920a0Smrg{ 169cdc920a0Smrg assert(fb); 170cdc920a0Smrg assert(name); 171cdc920a0Smrg 172cdc920a0Smrg memset(fb, 0, sizeof(struct gl_framebuffer)); 173cdc920a0Smrg 174cdc920a0Smrg fb->Name = name; 175cdc920a0Smrg fb->RefCount = 1; 176cdc920a0Smrg fb->_NumColorDrawBuffers = 1; 177cdc920a0Smrg fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT; 178cdc920a0Smrg fb->_ColorDrawBufferIndexes[0] = BUFFER_COLOR0; 179cdc920a0Smrg fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT; 180cdc920a0Smrg fb->_ColorReadBufferIndex = BUFFER_COLOR0; 181cdc920a0Smrg fb->Delete = _mesa_destroy_framebuffer; 182cdc920a0Smrg _glthread_INIT_MUTEX(fb->Mutex); 183cdc920a0Smrg} 184cdc920a0Smrg 185cdc920a0Smrg 1867117f1b4Smrg/** 1877117f1b4Smrg * Deallocate buffer and everything attached to it. 1887117f1b4Smrg * Typically called via the gl_framebuffer->Delete() method. 1897117f1b4Smrg */ 1907117f1b4Smrgvoid 1917117f1b4Smrg_mesa_destroy_framebuffer(struct gl_framebuffer *fb) 1927117f1b4Smrg{ 1937117f1b4Smrg if (fb) { 1947117f1b4Smrg _mesa_free_framebuffer_data(fb); 195cdc920a0Smrg free(fb); 1967117f1b4Smrg } 1977117f1b4Smrg} 1987117f1b4Smrg 1997117f1b4Smrg 2007117f1b4Smrg/** 2017117f1b4Smrg * Free all the data hanging off the given gl_framebuffer, but don't free 2027117f1b4Smrg * the gl_framebuffer object itself. 2037117f1b4Smrg */ 2047117f1b4Smrgvoid 2057117f1b4Smrg_mesa_free_framebuffer_data(struct gl_framebuffer *fb) 2067117f1b4Smrg{ 2077117f1b4Smrg GLuint i; 2087117f1b4Smrg 2097117f1b4Smrg assert(fb); 2107117f1b4Smrg assert(fb->RefCount == 0); 2117117f1b4Smrg 2127117f1b4Smrg _glthread_DESTROY_MUTEX(fb->Mutex); 2137117f1b4Smrg 2147117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 2157117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 2167117f1b4Smrg if (att->Renderbuffer) { 2177117f1b4Smrg _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 2187117f1b4Smrg } 2197117f1b4Smrg if (att->Texture) { 2207117f1b4Smrg _mesa_reference_texobj(&att->Texture, NULL); 2217117f1b4Smrg } 2227117f1b4Smrg ASSERT(!att->Renderbuffer); 2237117f1b4Smrg ASSERT(!att->Texture); 2247117f1b4Smrg att->Type = GL_NONE; 2257117f1b4Smrg } 2267117f1b4Smrg 2277117f1b4Smrg /* unbind _Depth/_StencilBuffer to decr ref counts */ 2287117f1b4Smrg _mesa_reference_renderbuffer(&fb->_DepthBuffer, NULL); 2297117f1b4Smrg _mesa_reference_renderbuffer(&fb->_StencilBuffer, NULL); 2307117f1b4Smrg} 2317117f1b4Smrg 2327117f1b4Smrg 2337117f1b4Smrg/** 2347117f1b4Smrg * Set *ptr to point to fb, with refcounting and locking. 2357117f1b4Smrg */ 2367117f1b4Smrgvoid 2377117f1b4Smrg_mesa_reference_framebuffer(struct gl_framebuffer **ptr, 2387117f1b4Smrg struct gl_framebuffer *fb) 2397117f1b4Smrg{ 2407117f1b4Smrg assert(ptr); 2417117f1b4Smrg if (*ptr == fb) { 2427117f1b4Smrg /* no change */ 2437117f1b4Smrg return; 2447117f1b4Smrg } 2457117f1b4Smrg 2464a49301eSmrg if (*ptr) { 2474a49301eSmrg /* unreference old renderbuffer */ 2487117f1b4Smrg GLboolean deleteFlag = GL_FALSE; 2494a49301eSmrg struct gl_framebuffer *oldFb = *ptr; 2507117f1b4Smrg 2514a49301eSmrg _glthread_LOCK_MUTEX(oldFb->Mutex); 2524a49301eSmrg ASSERT(oldFb->RefCount > 0); 2534a49301eSmrg oldFb->RefCount--; 2544a49301eSmrg deleteFlag = (oldFb->RefCount == 0); 2554a49301eSmrg _glthread_UNLOCK_MUTEX(oldFb->Mutex); 2567117f1b4Smrg 2577117f1b4Smrg if (deleteFlag) 2584a49301eSmrg oldFb->Delete(oldFb); 2597117f1b4Smrg 2604a49301eSmrg *ptr = NULL; 2617117f1b4Smrg } 2624a49301eSmrg assert(!*ptr); 2637117f1b4Smrg 2644a49301eSmrg if (fb) { 2654a49301eSmrg _glthread_LOCK_MUTEX(fb->Mutex); 2664a49301eSmrg fb->RefCount++; 2674a49301eSmrg _glthread_UNLOCK_MUTEX(fb->Mutex); 2684a49301eSmrg *ptr = fb; 2694a49301eSmrg } 2704a49301eSmrg} 2717117f1b4Smrg 2727117f1b4Smrg 2737117f1b4Smrg/** 2747117f1b4Smrg * Resize the given framebuffer's renderbuffers to the new width and height. 2757117f1b4Smrg * This should only be used for window-system framebuffers, not 2767117f1b4Smrg * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). 2777117f1b4Smrg * This will typically be called via ctx->Driver.ResizeBuffers() or directly 2787117f1b4Smrg * from a device driver. 2797117f1b4Smrg * 2807117f1b4Smrg * \note it's possible for ctx to be null since a window can be resized 2817117f1b4Smrg * without a currently bound rendering context. 2827117f1b4Smrg */ 2837117f1b4Smrgvoid 2847117f1b4Smrg_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb, 2857117f1b4Smrg GLuint width, GLuint height) 2867117f1b4Smrg{ 2877117f1b4Smrg GLuint i; 2887117f1b4Smrg 2897117f1b4Smrg /* XXX I think we could check if the size is not changing 2907117f1b4Smrg * and return early. 2917117f1b4Smrg */ 2927117f1b4Smrg 2937117f1b4Smrg /* For window system framebuffers, Name is zero */ 2947117f1b4Smrg assert(fb->Name == 0); 2957117f1b4Smrg 2967117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 2977117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 2987117f1b4Smrg if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 2997117f1b4Smrg struct gl_renderbuffer *rb = att->Renderbuffer; 3007117f1b4Smrg /* only resize if size is changing */ 3017117f1b4Smrg if (rb->Width != width || rb->Height != height) { 3027117f1b4Smrg if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 3037117f1b4Smrg ASSERT(rb->Width == width); 3047117f1b4Smrg ASSERT(rb->Height == height); 3057117f1b4Smrg } 3067117f1b4Smrg else { 3077117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 3087117f1b4Smrg /* no return */ 3097117f1b4Smrg } 3107117f1b4Smrg } 3117117f1b4Smrg } 3127117f1b4Smrg } 3137117f1b4Smrg 3147117f1b4Smrg if (fb->_DepthBuffer) { 3157117f1b4Smrg struct gl_renderbuffer *rb = fb->_DepthBuffer; 3167117f1b4Smrg if (rb->Width != width || rb->Height != height) { 3177117f1b4Smrg if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 3187117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 3197117f1b4Smrg } 3207117f1b4Smrg } 3217117f1b4Smrg } 3227117f1b4Smrg 3237117f1b4Smrg if (fb->_StencilBuffer) { 3247117f1b4Smrg struct gl_renderbuffer *rb = fb->_StencilBuffer; 3257117f1b4Smrg if (rb->Width != width || rb->Height != height) { 3267117f1b4Smrg if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 3277117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 3287117f1b4Smrg } 3297117f1b4Smrg } 3307117f1b4Smrg } 3317117f1b4Smrg 3327117f1b4Smrg fb->Width = width; 3337117f1b4Smrg fb->Height = height; 3347117f1b4Smrg 3357117f1b4Smrg if (ctx) { 3367117f1b4Smrg /* update scissor / window bounds */ 3377117f1b4Smrg _mesa_update_draw_buffer_bounds(ctx); 3387117f1b4Smrg /* Signal new buffer state so that swrast will update its clipping 3397117f1b4Smrg * info (the CLIP_BIT flag). 3407117f1b4Smrg */ 3417117f1b4Smrg ctx->NewState |= _NEW_BUFFERS; 3427117f1b4Smrg } 3437117f1b4Smrg} 3447117f1b4Smrg 3457117f1b4Smrg 346c1f859d4Smrg 347c1f859d4Smrg/** 348c1f859d4Smrg * XXX THIS IS OBSOLETE - drivers should take care of detecting window 349c1f859d4Smrg * size changes and act accordingly, likely calling _mesa_resize_framebuffer(). 350c1f859d4Smrg * 351c1f859d4Smrg * GL_MESA_resize_buffers extension. 352c1f859d4Smrg * 353c1f859d4Smrg * When this function is called, we'll ask the window system how large 354c1f859d4Smrg * the current window is. If it's a new size, we'll call the driver's 355c1f859d4Smrg * ResizeBuffers function. The driver will then resize its color buffers 356c1f859d4Smrg * as needed, and maybe call the swrast's routine for reallocating 357c1f859d4Smrg * swrast-managed depth/stencil/accum/etc buffers. 358c1f859d4Smrg * \note This function should only be called through the GL API, not 359c1f859d4Smrg * from device drivers (as was done in the past). 360c1f859d4Smrg */ 361c1f859d4Smrgvoid 362c1f859d4Smrg_mesa_resizebuffers( GLcontext *ctx ) 363c1f859d4Smrg{ 364c1f859d4Smrg ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx ); 365c1f859d4Smrg 366c1f859d4Smrg if (MESA_VERBOSE & VERBOSE_API) 367c1f859d4Smrg _mesa_debug(ctx, "glResizeBuffersMESA\n"); 368c1f859d4Smrg 369c1f859d4Smrg if (!ctx->Driver.GetBufferSize) { 370c1f859d4Smrg return; 371c1f859d4Smrg } 372c1f859d4Smrg 373c1f859d4Smrg if (ctx->WinSysDrawBuffer) { 374c1f859d4Smrg GLuint newWidth, newHeight; 375c1f859d4Smrg GLframebuffer *buffer = ctx->WinSysDrawBuffer; 376c1f859d4Smrg 377c1f859d4Smrg assert(buffer->Name == 0); 378c1f859d4Smrg 379c1f859d4Smrg /* ask device driver for size of output buffer */ 380c1f859d4Smrg ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight ); 381c1f859d4Smrg 382c1f859d4Smrg /* see if size of device driver's color buffer (window) has changed */ 383c1f859d4Smrg if (buffer->Width != newWidth || buffer->Height != newHeight) { 384c1f859d4Smrg if (ctx->Driver.ResizeBuffers) 385c1f859d4Smrg ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight ); 386c1f859d4Smrg } 387c1f859d4Smrg } 388c1f859d4Smrg 389c1f859d4Smrg if (ctx->WinSysReadBuffer 390c1f859d4Smrg && ctx->WinSysReadBuffer != ctx->WinSysDrawBuffer) { 391c1f859d4Smrg GLuint newWidth, newHeight; 392c1f859d4Smrg GLframebuffer *buffer = ctx->WinSysReadBuffer; 393c1f859d4Smrg 394c1f859d4Smrg assert(buffer->Name == 0); 395c1f859d4Smrg 396c1f859d4Smrg /* ask device driver for size of read buffer */ 397c1f859d4Smrg ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight ); 398c1f859d4Smrg 399c1f859d4Smrg /* see if size of device driver's color buffer (window) has changed */ 400c1f859d4Smrg if (buffer->Width != newWidth || buffer->Height != newHeight) { 401c1f859d4Smrg if (ctx->Driver.ResizeBuffers) 402c1f859d4Smrg ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight ); 403c1f859d4Smrg } 404c1f859d4Smrg } 405c1f859d4Smrg 406c1f859d4Smrg ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */ 407c1f859d4Smrg} 408c1f859d4Smrg 409c1f859d4Smrg 410c1f859d4Smrg/* 411c1f859d4Smrg * XXX THIS IS OBSOLETE 412c1f859d4Smrg */ 413c1f859d4Smrgvoid GLAPIENTRY 414c1f859d4Smrg_mesa_ResizeBuffersMESA( void ) 415c1f859d4Smrg{ 416c1f859d4Smrg GET_CURRENT_CONTEXT(ctx); 417c1f859d4Smrg 418c1f859d4Smrg if (ctx->Extensions.MESA_resize_buffers) 419c1f859d4Smrg _mesa_resizebuffers( ctx ); 420c1f859d4Smrg} 421c1f859d4Smrg 422c1f859d4Smrg 423c1f859d4Smrg 4247117f1b4Smrg/** 4257117f1b4Smrg * Examine all the framebuffer's renderbuffers to update the Width/Height 4267117f1b4Smrg * fields of the framebuffer. If we have renderbuffers with different 4274a49301eSmrg * sizes, set the framebuffer's width and height to the min size. 4287117f1b4Smrg * Note: this is only intended for user-created framebuffers, not 4297117f1b4Smrg * window-system framebuffes. 4307117f1b4Smrg */ 4317117f1b4Smrgstatic void 4324a49301eSmrgupdate_framebuffer_size(GLcontext *ctx, struct gl_framebuffer *fb) 4337117f1b4Smrg{ 4344a49301eSmrg GLuint minWidth = ~0, minHeight = ~0; 4357117f1b4Smrg GLuint i; 4367117f1b4Smrg 4377117f1b4Smrg /* user-created framebuffers only */ 4387117f1b4Smrg assert(fb->Name); 4397117f1b4Smrg 4407117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 4417117f1b4Smrg struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 4427117f1b4Smrg const struct gl_renderbuffer *rb = att->Renderbuffer; 4437117f1b4Smrg if (rb) { 4444a49301eSmrg minWidth = MIN2(minWidth, rb->Width); 4454a49301eSmrg minHeight = MIN2(minHeight, rb->Height); 4467117f1b4Smrg } 4477117f1b4Smrg } 4484a49301eSmrg 4494a49301eSmrg if (minWidth != ~0) { 4504a49301eSmrg fb->Width = minWidth; 4514a49301eSmrg fb->Height = minHeight; 4524a49301eSmrg } 4534a49301eSmrg else { 4544a49301eSmrg fb->Width = 0; 4554a49301eSmrg fb->Height = 0; 4564a49301eSmrg } 4577117f1b4Smrg} 4587117f1b4Smrg 4597117f1b4Smrg 4607117f1b4Smrg/** 4617117f1b4Smrg * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields. 4627117f1b4Smrg * These values are computed from the buffer's width and height and 4637117f1b4Smrg * the scissor box, if it's enabled. 4647117f1b4Smrg * \param ctx the GL context. 4657117f1b4Smrg */ 4667117f1b4Smrgvoid 4677117f1b4Smrg_mesa_update_draw_buffer_bounds(GLcontext *ctx) 4687117f1b4Smrg{ 4697117f1b4Smrg struct gl_framebuffer *buffer = ctx->DrawBuffer; 4707117f1b4Smrg 4717117f1b4Smrg if (!buffer) 4727117f1b4Smrg return; 4737117f1b4Smrg 4747117f1b4Smrg if (buffer->Name) { 4757117f1b4Smrg /* user-created framebuffer size depends on the renderbuffers */ 4764a49301eSmrg update_framebuffer_size(ctx, buffer); 4777117f1b4Smrg } 4787117f1b4Smrg 4797117f1b4Smrg buffer->_Xmin = 0; 4807117f1b4Smrg buffer->_Ymin = 0; 4817117f1b4Smrg buffer->_Xmax = buffer->Width; 4827117f1b4Smrg buffer->_Ymax = buffer->Height; 4837117f1b4Smrg 4847117f1b4Smrg if (ctx->Scissor.Enabled) { 4857117f1b4Smrg if (ctx->Scissor.X > buffer->_Xmin) { 4867117f1b4Smrg buffer->_Xmin = ctx->Scissor.X; 4877117f1b4Smrg } 4887117f1b4Smrg if (ctx->Scissor.Y > buffer->_Ymin) { 4897117f1b4Smrg buffer->_Ymin = ctx->Scissor.Y; 4907117f1b4Smrg } 4917117f1b4Smrg if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) { 4927117f1b4Smrg buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width; 4937117f1b4Smrg } 4947117f1b4Smrg if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) { 4957117f1b4Smrg buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height; 4967117f1b4Smrg } 4977117f1b4Smrg /* finally, check for empty region */ 4987117f1b4Smrg if (buffer->_Xmin > buffer->_Xmax) { 4997117f1b4Smrg buffer->_Xmin = buffer->_Xmax; 5007117f1b4Smrg } 5017117f1b4Smrg if (buffer->_Ymin > buffer->_Ymax) { 5027117f1b4Smrg buffer->_Ymin = buffer->_Ymax; 5037117f1b4Smrg } 5047117f1b4Smrg } 5057117f1b4Smrg 5067117f1b4Smrg ASSERT(buffer->_Xmin <= buffer->_Xmax); 5077117f1b4Smrg ASSERT(buffer->_Ymin <= buffer->_Ymax); 5087117f1b4Smrg} 5097117f1b4Smrg 5107117f1b4Smrg 5117117f1b4Smrg/** 5127117f1b4Smrg * The glGet queries of the framebuffer red/green/blue size, stencil size, 5137117f1b4Smrg * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can 5147117f1b4Smrg * change depending on the renderbuffer bindings. This function updates 5157117f1b4Smrg * the given framebuffer's Visual from the current renderbuffer bindings. 5167117f1b4Smrg * 5177117f1b4Smrg * This may apply to user-created framebuffers or window system framebuffers. 5187117f1b4Smrg * 5197117f1b4Smrg * Also note: ctx->DrawBuffer->Visual.depthBits might not equal 5207117f1b4Smrg * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. 5217117f1b4Smrg * The former one is used to convert floating point depth values into 5227117f1b4Smrg * integer Z values. 5237117f1b4Smrg */ 5247117f1b4Smrgvoid 5257117f1b4Smrg_mesa_update_framebuffer_visual(struct gl_framebuffer *fb) 5267117f1b4Smrg{ 5277117f1b4Smrg GLuint i; 5287117f1b4Smrg 529cdc920a0Smrg memset(&fb->Visual, 0, sizeof(fb->Visual)); 5307117f1b4Smrg fb->Visual.rgbMode = GL_TRUE; /* assume this */ 5317117f1b4Smrg 5327117f1b4Smrg#if 0 /* this _might_ be needed */ 5337117f1b4Smrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 5347117f1b4Smrg /* leave visual fields zero'd */ 5357117f1b4Smrg return; 5367117f1b4Smrg } 5377117f1b4Smrg#endif 5387117f1b4Smrg 539cdc920a0Smrg /* find first RGB renderbuffer */ 5407117f1b4Smrg for (i = 0; i < BUFFER_COUNT; i++) { 5417117f1b4Smrg if (fb->Attachment[i].Renderbuffer) { 5427117f1b4Smrg const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 5434a49301eSmrg const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); 5444a49301eSmrg const gl_format fmt = rb->Format; 5454a49301eSmrg 5464a49301eSmrg if (baseFormat == GL_RGBA || baseFormat == GL_RGB) { 5474a49301eSmrg fb->Visual.redBits = _mesa_get_format_bits(fmt, GL_RED_BITS); 5484a49301eSmrg fb->Visual.greenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); 5494a49301eSmrg fb->Visual.blueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); 5504a49301eSmrg fb->Visual.alphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); 5517117f1b4Smrg fb->Visual.rgbBits = fb->Visual.redBits 5527117f1b4Smrg + fb->Visual.greenBits + fb->Visual.blueBits; 5537117f1b4Smrg fb->Visual.floatMode = GL_FALSE; 5544a49301eSmrg fb->Visual.samples = rb->NumSamples; 5557117f1b4Smrg break; 5567117f1b4Smrg } 5577117f1b4Smrg } 5587117f1b4Smrg } 5597117f1b4Smrg 5607117f1b4Smrg if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { 5614a49301eSmrg const struct gl_renderbuffer *rb = 5624a49301eSmrg fb->Attachment[BUFFER_DEPTH].Renderbuffer; 5634a49301eSmrg const gl_format fmt = rb->Format; 5647117f1b4Smrg fb->Visual.haveDepthBuffer = GL_TRUE; 5654a49301eSmrg fb->Visual.depthBits = _mesa_get_format_bits(fmt, GL_DEPTH_BITS); 5667117f1b4Smrg } 5677117f1b4Smrg 5687117f1b4Smrg if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { 5694a49301eSmrg const struct gl_renderbuffer *rb = 5704a49301eSmrg fb->Attachment[BUFFER_STENCIL].Renderbuffer; 5714a49301eSmrg const gl_format fmt = rb->Format; 5727117f1b4Smrg fb->Visual.haveStencilBuffer = GL_TRUE; 5734a49301eSmrg fb->Visual.stencilBits = _mesa_get_format_bits(fmt, GL_STENCIL_BITS); 5747117f1b4Smrg } 5757117f1b4Smrg 5767117f1b4Smrg if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) { 5774a49301eSmrg const struct gl_renderbuffer *rb = 5784a49301eSmrg fb->Attachment[BUFFER_ACCUM].Renderbuffer; 5794a49301eSmrg const gl_format fmt = rb->Format; 5807117f1b4Smrg fb->Visual.haveAccumBuffer = GL_TRUE; 5814a49301eSmrg fb->Visual.accumRedBits = _mesa_get_format_bits(fmt, GL_RED_BITS); 5824a49301eSmrg fb->Visual.accumGreenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); 5834a49301eSmrg fb->Visual.accumBlueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); 5844a49301eSmrg fb->Visual.accumAlphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); 5857117f1b4Smrg } 5867117f1b4Smrg 5877117f1b4Smrg compute_depth_max(fb); 5887117f1b4Smrg} 5897117f1b4Smrg 5907117f1b4Smrg 5917117f1b4Smrg/** 5927117f1b4Smrg * Update the framebuffer's _DepthBuffer field using the renderbuffer 5937117f1b4Smrg * found at the given attachment index. 5947117f1b4Smrg * 5957117f1b4Smrg * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer, 5967117f1b4Smrg * create and install a depth wrapper/adaptor. 5977117f1b4Smrg * 5987117f1b4Smrg * \param fb the framebuffer whose _DepthBuffer field to update 5997117f1b4Smrg * \param attIndex indicates the renderbuffer to possibly wrap 6007117f1b4Smrg */ 6017117f1b4Smrgvoid 6027117f1b4Smrg_mesa_update_depth_buffer(GLcontext *ctx, 6037117f1b4Smrg struct gl_framebuffer *fb, 6047117f1b4Smrg GLuint attIndex) 6057117f1b4Smrg{ 6067117f1b4Smrg struct gl_renderbuffer *depthRb; 6077117f1b4Smrg 6087117f1b4Smrg /* only one possiblity for now */ 6097117f1b4Smrg ASSERT(attIndex == BUFFER_DEPTH); 6107117f1b4Smrg 6117117f1b4Smrg depthRb = fb->Attachment[attIndex].Renderbuffer; 6127117f1b4Smrg 6134a49301eSmrg if (depthRb && depthRb->_BaseFormat == GL_DEPTH_STENCIL) { 6147117f1b4Smrg /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */ 6157117f1b4Smrg if (!fb->_DepthBuffer 6167117f1b4Smrg || fb->_DepthBuffer->Wrapped != depthRb 6174a49301eSmrg || _mesa_get_format_base_format(fb->_DepthBuffer->Format) != GL_DEPTH_COMPONENT) { 6187117f1b4Smrg /* need to update wrapper */ 6197117f1b4Smrg struct gl_renderbuffer *wrapper 6207117f1b4Smrg = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb); 6217117f1b4Smrg _mesa_reference_renderbuffer(&fb->_DepthBuffer, wrapper); 6227117f1b4Smrg ASSERT(fb->_DepthBuffer->Wrapped == depthRb); 6237117f1b4Smrg } 6247117f1b4Smrg } 6257117f1b4Smrg else { 6267117f1b4Smrg /* depthRb may be null */ 6277117f1b4Smrg _mesa_reference_renderbuffer(&fb->_DepthBuffer, depthRb); 6287117f1b4Smrg } 6297117f1b4Smrg} 6307117f1b4Smrg 6317117f1b4Smrg 6327117f1b4Smrg/** 6337117f1b4Smrg * Update the framebuffer's _StencilBuffer field using the renderbuffer 6347117f1b4Smrg * found at the given attachment index. 6357117f1b4Smrg * 6367117f1b4Smrg * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer, 6377117f1b4Smrg * create and install a stencil wrapper/adaptor. 6387117f1b4Smrg * 6397117f1b4Smrg * \param fb the framebuffer whose _StencilBuffer field to update 6407117f1b4Smrg * \param attIndex indicates the renderbuffer to possibly wrap 6417117f1b4Smrg */ 6427117f1b4Smrgvoid 6437117f1b4Smrg_mesa_update_stencil_buffer(GLcontext *ctx, 6447117f1b4Smrg struct gl_framebuffer *fb, 6457117f1b4Smrg GLuint attIndex) 6467117f1b4Smrg{ 6477117f1b4Smrg struct gl_renderbuffer *stencilRb; 6487117f1b4Smrg 6497117f1b4Smrg ASSERT(attIndex == BUFFER_DEPTH || 6507117f1b4Smrg attIndex == BUFFER_STENCIL); 6517117f1b4Smrg 6527117f1b4Smrg stencilRb = fb->Attachment[attIndex].Renderbuffer; 6537117f1b4Smrg 6544a49301eSmrg if (stencilRb && stencilRb->_BaseFormat == GL_DEPTH_STENCIL) { 6557117f1b4Smrg /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */ 6567117f1b4Smrg if (!fb->_StencilBuffer 6577117f1b4Smrg || fb->_StencilBuffer->Wrapped != stencilRb 6584a49301eSmrg || _mesa_get_format_base_format(fb->_StencilBuffer->Format) != GL_STENCIL_INDEX) { 6597117f1b4Smrg /* need to update wrapper */ 6607117f1b4Smrg struct gl_renderbuffer *wrapper 6617117f1b4Smrg = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb); 6627117f1b4Smrg _mesa_reference_renderbuffer(&fb->_StencilBuffer, wrapper); 6637117f1b4Smrg ASSERT(fb->_StencilBuffer->Wrapped == stencilRb); 6647117f1b4Smrg } 6657117f1b4Smrg } 6667117f1b4Smrg else { 6677117f1b4Smrg /* stencilRb may be null */ 6687117f1b4Smrg _mesa_reference_renderbuffer(&fb->_StencilBuffer, stencilRb); 6697117f1b4Smrg } 6707117f1b4Smrg} 6717117f1b4Smrg 6727117f1b4Smrg 673c1f859d4Smrg/* 674c1f859d4Smrg * Example DrawBuffers scenarios: 675c1f859d4Smrg * 676c1f859d4Smrg * 1. glDrawBuffer(GL_FRONT_AND_BACK), fixed-func or shader writes to 677c1f859d4Smrg * "gl_FragColor" or program writes to the "result.color" register: 678c1f859d4Smrg * 679c1f859d4Smrg * fragment color output renderbuffer 680c1f859d4Smrg * --------------------- --------------- 681c1f859d4Smrg * color[0] Front, Back 682c1f859d4Smrg * 683c1f859d4Smrg * 684c1f859d4Smrg * 2. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]), shader writes to 685c1f859d4Smrg * gl_FragData[i] or program writes to result.color[i] registers: 686c1f859d4Smrg * 687c1f859d4Smrg * fragment color output renderbuffer 688c1f859d4Smrg * --------------------- --------------- 689c1f859d4Smrg * color[0] Front 690c1f859d4Smrg * color[1] Aux0 691c1f859d4Smrg * color[3] Aux1 692c1f859d4Smrg * 693c1f859d4Smrg * 694c1f859d4Smrg * 3. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]) and shader writes to 695c1f859d4Smrg * gl_FragColor, or fixed function: 696c1f859d4Smrg * 697c1f859d4Smrg * fragment color output renderbuffer 698c1f859d4Smrg * --------------------- --------------- 699c1f859d4Smrg * color[0] Front, Aux0, Aux1 700c1f859d4Smrg * 701c1f859d4Smrg * 702c1f859d4Smrg * In either case, the list of renderbuffers is stored in the 703c1f859d4Smrg * framebuffer->_ColorDrawBuffers[] array and 704c1f859d4Smrg * framebuffer->_NumColorDrawBuffers indicates the number of buffers. 705c1f859d4Smrg * The renderer (like swrast) has to look at the current fragment shader 706c1f859d4Smrg * to see if it writes to gl_FragColor vs. gl_FragData[i] to determine 707c1f859d4Smrg * how to map color outputs to renderbuffers. 708c1f859d4Smrg * 709c1f859d4Smrg * Note that these two calls are equivalent (for fixed function fragment 710c1f859d4Smrg * shading anyway): 711c1f859d4Smrg * a) glDrawBuffer(GL_FRONT_AND_BACK); (assuming non-stereo framebuffer) 712c1f859d4Smrg * b) glDrawBuffers(2, [GL_FRONT_LEFT, GL_BACK_LEFT]); 713c1f859d4Smrg */ 714c1f859d4Smrg 715c1f859d4Smrg 716c1f859d4Smrg 717c1f859d4Smrg 7187117f1b4Smrg/** 719c1f859d4Smrg * Update the (derived) list of color drawing renderbuffer pointers. 7207117f1b4Smrg * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers 7217117f1b4Smrg * writing colors. 7227117f1b4Smrg */ 7237117f1b4Smrgstatic void 7247117f1b4Smrgupdate_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb) 7257117f1b4Smrg{ 7267117f1b4Smrg GLuint output; 7277117f1b4Smrg 728c1f859d4Smrg /* set 0th buffer to NULL now in case _NumColorDrawBuffers is zero */ 729c1f859d4Smrg fb->_ColorDrawBuffers[0] = NULL; 730c1f859d4Smrg 731c1f859d4Smrg for (output = 0; output < fb->_NumColorDrawBuffers; output++) { 732c1f859d4Smrg GLint buf = fb->_ColorDrawBufferIndexes[output]; 733c1f859d4Smrg if (buf >= 0) { 734c1f859d4Smrg fb->_ColorDrawBuffers[output] = fb->Attachment[buf].Renderbuffer; 735c1f859d4Smrg } 736c1f859d4Smrg else { 737c1f859d4Smrg fb->_ColorDrawBuffers[output] = NULL; 7387117f1b4Smrg } 7397117f1b4Smrg } 7407117f1b4Smrg} 7417117f1b4Smrg 7427117f1b4Smrg 7437117f1b4Smrg/** 744c1f859d4Smrg * Update the (derived) color read renderbuffer pointer. 7457117f1b4Smrg * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. 7467117f1b4Smrg */ 7477117f1b4Smrgstatic void 7487117f1b4Smrgupdate_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb) 7497117f1b4Smrg{ 7507117f1b4Smrg (void) ctx; 7517117f1b4Smrg if (fb->_ColorReadBufferIndex == -1 || 7527117f1b4Smrg fb->DeletePending || 7537117f1b4Smrg fb->Width == 0 || 7547117f1b4Smrg fb->Height == 0) { 7557117f1b4Smrg fb->_ColorReadBuffer = NULL; /* legal! */ 7567117f1b4Smrg } 7577117f1b4Smrg else { 7587117f1b4Smrg ASSERT(fb->_ColorReadBufferIndex >= 0); 7597117f1b4Smrg ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT); 7607117f1b4Smrg fb->_ColorReadBuffer 7617117f1b4Smrg = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; 7627117f1b4Smrg } 7637117f1b4Smrg} 7647117f1b4Smrg 7657117f1b4Smrg 7667117f1b4Smrg/** 767c1f859d4Smrg * Update a gl_framebuffer's derived state. 768c1f859d4Smrg * 7697117f1b4Smrg * Specifically, update these framebuffer fields: 7707117f1b4Smrg * _ColorDrawBuffers 7717117f1b4Smrg * _NumColorDrawBuffers 7727117f1b4Smrg * _ColorReadBuffer 7737117f1b4Smrg * _DepthBuffer 7747117f1b4Smrg * _StencilBuffer 775c1f859d4Smrg * 776c1f859d4Smrg * If the framebuffer is user-created, make sure it's complete. 777c1f859d4Smrg * 778c1f859d4Smrg * The following functions (at least) can effect framebuffer state: 779c1f859d4Smrg * glReadBuffer, glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT, 7807117f1b4Smrg * glRenderbufferStorageEXT. 7817117f1b4Smrg */ 782c1f859d4Smrgstatic void 783c1f859d4Smrgupdate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) 7847117f1b4Smrg{ 785c1f859d4Smrg if (fb->Name == 0) { 786c1f859d4Smrg /* This is a window-system framebuffer */ 787c1f859d4Smrg /* Need to update the FB's GL_DRAW_BUFFER state to match the 788c1f859d4Smrg * context state (GL_READ_BUFFER too). 789c1f859d4Smrg */ 790c1f859d4Smrg if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) { 791c1f859d4Smrg _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, 792c1f859d4Smrg ctx->Color.DrawBuffer, NULL); 793c1f859d4Smrg } 794c1f859d4Smrg if (fb->ColorReadBuffer != ctx->Pixel.ReadBuffer) { 795c1f859d4Smrg 796c1f859d4Smrg } 797c1f859d4Smrg } 798c1f859d4Smrg else { 799c1f859d4Smrg /* This is a user-created framebuffer. 800c1f859d4Smrg * Completeness only matters for user-created framebuffers. 801c1f859d4Smrg */ 8024a49301eSmrg if (fb->_Status != GL_FRAMEBUFFER_COMPLETE) { 8034a49301eSmrg _mesa_test_framebuffer_completeness(ctx, fb); 8044a49301eSmrg } 8057117f1b4Smrg } 8067117f1b4Smrg 807c1f859d4Smrg /* Strictly speaking, we don't need to update the draw-state 808c1f859d4Smrg * if this FB is bound as ctx->ReadBuffer (and conversely, the 809c1f859d4Smrg * read-state if this FB is bound as ctx->DrawBuffer), but no 810c1f859d4Smrg * harm. 811c1f859d4Smrg */ 8127117f1b4Smrg update_color_draw_buffers(ctx, fb); 8137117f1b4Smrg update_color_read_buffer(ctx, fb); 8147117f1b4Smrg _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH); 8157117f1b4Smrg _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL); 8167117f1b4Smrg 8177117f1b4Smrg compute_depth_max(fb); 8187117f1b4Smrg} 8197117f1b4Smrg 8207117f1b4Smrg 821c1f859d4Smrg/** 822c1f859d4Smrg * Update state related to the current draw/read framebuffers. 823c1f859d4Smrg */ 824c1f859d4Smrgvoid 825c1f859d4Smrg_mesa_update_framebuffer(GLcontext *ctx) 826c1f859d4Smrg{ 827cdc920a0Smrg struct gl_framebuffer *drawFb; 828cdc920a0Smrg struct gl_framebuffer *readFb; 829cdc920a0Smrg 830cdc920a0Smrg assert(ctx); 831cdc920a0Smrg drawFb = ctx->DrawBuffer; 832cdc920a0Smrg readFb = ctx->ReadBuffer; 833c1f859d4Smrg 834c1f859d4Smrg update_framebuffer(ctx, drawFb); 835c1f859d4Smrg if (readFb != drawFb) 836c1f859d4Smrg update_framebuffer(ctx, readFb); 837c1f859d4Smrg} 838c1f859d4Smrg 839c1f859d4Smrg 8407117f1b4Smrg/** 8417117f1b4Smrg * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels, 8424a49301eSmrg * glCopyTex[Sub]Image, etc) exists. 8437117f1b4Smrg * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, 8447117f1b4Smrg * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. 8457117f1b4Smrg * \return GL_TRUE if buffer exists, GL_FALSE otherwise 8467117f1b4Smrg */ 8477117f1b4SmrgGLboolean 8487117f1b4Smrg_mesa_source_buffer_exists(GLcontext *ctx, GLenum format) 8497117f1b4Smrg{ 8504a49301eSmrg const struct gl_renderbuffer_attachment *att = ctx->ReadBuffer->Attachment; 8514a49301eSmrg 8524a49301eSmrg /* If we don't know the framebuffer status, update it now */ 8534a49301eSmrg if (ctx->ReadBuffer->_Status == 0) { 8544a49301eSmrg _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); 8554a49301eSmrg } 8567117f1b4Smrg 8577117f1b4Smrg if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 8587117f1b4Smrg return GL_FALSE; 8597117f1b4Smrg } 8607117f1b4Smrg 8617117f1b4Smrg switch (format) { 8627117f1b4Smrg case GL_COLOR: 8637117f1b4Smrg case GL_RED: 8647117f1b4Smrg case GL_GREEN: 8657117f1b4Smrg case GL_BLUE: 8667117f1b4Smrg case GL_ALPHA: 8677117f1b4Smrg case GL_LUMINANCE: 8687117f1b4Smrg case GL_LUMINANCE_ALPHA: 8697117f1b4Smrg case GL_INTENSITY: 8707117f1b4Smrg case GL_RGB: 8717117f1b4Smrg case GL_BGR: 8727117f1b4Smrg case GL_RGBA: 8737117f1b4Smrg case GL_BGRA: 8747117f1b4Smrg case GL_ABGR_EXT: 8757117f1b4Smrg case GL_COLOR_INDEX: 8767117f1b4Smrg if (ctx->ReadBuffer->_ColorReadBuffer == NULL) { 8777117f1b4Smrg return GL_FALSE; 8787117f1b4Smrg } 8794a49301eSmrg ASSERT(_mesa_get_format_bits(ctx->ReadBuffer->_ColorReadBuffer->Format, GL_RED_BITS) > 0 || 8804a49301eSmrg _mesa_get_format_bits(ctx->ReadBuffer->_ColorReadBuffer->Format, GL_INDEX_BITS) > 0); 8817117f1b4Smrg break; 8827117f1b4Smrg case GL_DEPTH: 8837117f1b4Smrg case GL_DEPTH_COMPONENT: 8847117f1b4Smrg if (!att[BUFFER_DEPTH].Renderbuffer) { 8857117f1b4Smrg return GL_FALSE; 8867117f1b4Smrg } 8874a49301eSmrg /*ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);*/ 8887117f1b4Smrg break; 8897117f1b4Smrg case GL_STENCIL: 8907117f1b4Smrg case GL_STENCIL_INDEX: 8917117f1b4Smrg if (!att[BUFFER_STENCIL].Renderbuffer) { 8927117f1b4Smrg return GL_FALSE; 8937117f1b4Smrg } 8944a49301eSmrg /*ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);*/ 8957117f1b4Smrg break; 8967117f1b4Smrg case GL_DEPTH_STENCIL_EXT: 8977117f1b4Smrg if (!att[BUFFER_DEPTH].Renderbuffer || 8987117f1b4Smrg !att[BUFFER_STENCIL].Renderbuffer) { 8997117f1b4Smrg return GL_FALSE; 9007117f1b4Smrg } 9014a49301eSmrg /* 9027117f1b4Smrg ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 9037117f1b4Smrg ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 9044a49301eSmrg */ 9057117f1b4Smrg break; 9067117f1b4Smrg default: 9077117f1b4Smrg _mesa_problem(ctx, 9087117f1b4Smrg "Unexpected format 0x%x in _mesa_source_buffer_exists", 9097117f1b4Smrg format); 9107117f1b4Smrg return GL_FALSE; 9117117f1b4Smrg } 9127117f1b4Smrg 9137117f1b4Smrg /* OK */ 9147117f1b4Smrg return GL_TRUE; 9157117f1b4Smrg} 9167117f1b4Smrg 9177117f1b4Smrg 9187117f1b4Smrg/** 9197117f1b4Smrg * As above, but for drawing operations. 9204a49301eSmrg * XXX could do some code merging w/ above function. 9217117f1b4Smrg */ 9227117f1b4SmrgGLboolean 9237117f1b4Smrg_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format) 9247117f1b4Smrg{ 9254a49301eSmrg const struct gl_renderbuffer_attachment *att = ctx->DrawBuffer->Attachment; 9264a49301eSmrg 9274a49301eSmrg /* If we don't know the framebuffer status, update it now */ 9284a49301eSmrg if (ctx->DrawBuffer->_Status == 0) { 9294a49301eSmrg _mesa_test_framebuffer_completeness(ctx, ctx->DrawBuffer); 9304a49301eSmrg } 9317117f1b4Smrg 9327117f1b4Smrg if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 9337117f1b4Smrg return GL_FALSE; 9347117f1b4Smrg } 9357117f1b4Smrg 9367117f1b4Smrg switch (format) { 9377117f1b4Smrg case GL_COLOR: 9387117f1b4Smrg case GL_RED: 9397117f1b4Smrg case GL_GREEN: 9407117f1b4Smrg case GL_BLUE: 9417117f1b4Smrg case GL_ALPHA: 9427117f1b4Smrg case GL_LUMINANCE: 9437117f1b4Smrg case GL_LUMINANCE_ALPHA: 9447117f1b4Smrg case GL_INTENSITY: 9457117f1b4Smrg case GL_RGB: 9467117f1b4Smrg case GL_BGR: 9477117f1b4Smrg case GL_RGBA: 9487117f1b4Smrg case GL_BGRA: 9497117f1b4Smrg case GL_ABGR_EXT: 9507117f1b4Smrg case GL_COLOR_INDEX: 9514a49301eSmrg /* Nothing special since GL_DRAW_BUFFER could be GL_NONE. */ 9527117f1b4Smrg /* Could assert that colorbuffer has RedBits > 0 */ 9537117f1b4Smrg break; 9547117f1b4Smrg case GL_DEPTH: 9557117f1b4Smrg case GL_DEPTH_COMPONENT: 9567117f1b4Smrg if (!att[BUFFER_DEPTH].Renderbuffer) { 9577117f1b4Smrg return GL_FALSE; 9587117f1b4Smrg } 9594a49301eSmrg /*ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0);*/ 9607117f1b4Smrg break; 9617117f1b4Smrg case GL_STENCIL: 9627117f1b4Smrg case GL_STENCIL_INDEX: 9637117f1b4Smrg if (!att[BUFFER_STENCIL].Renderbuffer) { 9647117f1b4Smrg return GL_FALSE; 9657117f1b4Smrg } 9664a49301eSmrg /*ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0);*/ 9677117f1b4Smrg break; 9687117f1b4Smrg case GL_DEPTH_STENCIL_EXT: 9697117f1b4Smrg if (!att[BUFFER_DEPTH].Renderbuffer || 9707117f1b4Smrg !att[BUFFER_STENCIL].Renderbuffer) { 9717117f1b4Smrg return GL_FALSE; 9727117f1b4Smrg } 9734a49301eSmrg /* 9747117f1b4Smrg ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 9757117f1b4Smrg ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 9764a49301eSmrg */ 9777117f1b4Smrg break; 9787117f1b4Smrg default: 9797117f1b4Smrg _mesa_problem(ctx, 9804a49301eSmrg "Unexpected format 0x%x in _mesa_dest_buffer_exists", 9817117f1b4Smrg format); 9827117f1b4Smrg return GL_FALSE; 9837117f1b4Smrg } 9847117f1b4Smrg 9857117f1b4Smrg /* OK */ 9867117f1b4Smrg return GL_TRUE; 9877117f1b4Smrg} 9884a49301eSmrg 9894a49301eSmrgGLenum 9904a49301eSmrg_mesa_get_color_read_format(GLcontext *ctx) 9914a49301eSmrg{ 9924a49301eSmrg switch (ctx->ReadBuffer->_ColorReadBuffer->Format) { 9934a49301eSmrg case MESA_FORMAT_ARGB8888: 9944a49301eSmrg return GL_BGRA; 9954a49301eSmrg case MESA_FORMAT_RGB565: 9964a49301eSmrg return GL_BGR; 9974a49301eSmrg default: 9984a49301eSmrg return GL_RGBA; 9994a49301eSmrg } 10004a49301eSmrg} 10014a49301eSmrg 10024a49301eSmrgGLenum 10034a49301eSmrg_mesa_get_color_read_type(GLcontext *ctx) 10044a49301eSmrg{ 10054a49301eSmrg switch (ctx->ReadBuffer->_ColorReadBuffer->Format) { 10064a49301eSmrg case MESA_FORMAT_ARGB8888: 10074a49301eSmrg return GL_UNSIGNED_BYTE; 10084a49301eSmrg case MESA_FORMAT_RGB565: 10094a49301eSmrg return GL_UNSIGNED_SHORT_5_6_5_REV; 10104a49301eSmrg default: 10114a49301eSmrg return GL_UNSIGNED_BYTE; 10124a49301eSmrg } 10134a49301eSmrg} 1014