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