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