fbobject.c revision af69d88d
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
4c1f859d4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
54a49301eSmrg * Copyright (C) 1999-2009  VMware, Inc.  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
20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
267117f1b4Smrg
277117f1b4Smrg/*
284a49301eSmrg * GL_EXT/ARB_framebuffer_object extensions
294a49301eSmrg *
307117f1b4Smrg * Authors:
317117f1b4Smrg *   Brian Paul
327117f1b4Smrg */
337117f1b4Smrg
34af69d88dSmrg#include <stdbool.h>
357117f1b4Smrg
36c1f859d4Smrg#include "buffers.h"
377117f1b4Smrg#include "context.h"
384a49301eSmrg#include "enums.h"
397117f1b4Smrg#include "fbobject.h"
404a49301eSmrg#include "formats.h"
417117f1b4Smrg#include "framebuffer.h"
42af69d88dSmrg#include "glformats.h"
437117f1b4Smrg#include "hash.h"
444a49301eSmrg#include "macros.h"
45af69d88dSmrg#include "multisample.h"
463464ebd5Sriastradh#include "mtypes.h"
477117f1b4Smrg#include "renderbuffer.h"
487117f1b4Smrg#include "state.h"
497117f1b4Smrg#include "teximage.h"
507117f1b4Smrg#include "texobj.h"
514a49301eSmrg
524a49301eSmrg
537117f1b4Smrg/**
547117f1b4Smrg * Notes:
557117f1b4Smrg *
567117f1b4Smrg * None of the GL_EXT_framebuffer_object functions are compiled into
577117f1b4Smrg * display lists.
587117f1b4Smrg */
597117f1b4Smrg
607117f1b4Smrg
617117f1b4Smrg
627117f1b4Smrg/*
637117f1b4Smrg * When glGenRender/FramebuffersEXT() is called we insert pointers to
647117f1b4Smrg * these placeholder objects into the hash table.
657117f1b4Smrg * Later, when the object ID is first bound, we replace the placeholder
667117f1b4Smrg * with the real frame/renderbuffer.
677117f1b4Smrg */
687117f1b4Smrgstatic struct gl_framebuffer DummyFramebuffer;
697117f1b4Smrgstatic struct gl_renderbuffer DummyRenderbuffer;
707117f1b4Smrg
713464ebd5Sriastradh/* We bind this framebuffer when applications pass a NULL
723464ebd5Sriastradh * drawable/surface in make current. */
733464ebd5Sriastradhstatic struct gl_framebuffer IncompleteFramebuffer;
747117f1b4Smrg
753464ebd5Sriastradh
76c1f859d4Smrgstatic void
77af69d88dSmrgdelete_dummy_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
78c1f859d4Smrg{
79c1f859d4Smrg   /* no op */
80c1f859d4Smrg}
81c1f859d4Smrg
82c1f859d4Smrgstatic void
83c1f859d4Smrgdelete_dummy_framebuffer(struct gl_framebuffer *fb)
84c1f859d4Smrg{
85c1f859d4Smrg   /* no op */
86c1f859d4Smrg}
87c1f859d4Smrg
88c1f859d4Smrg
89c1f859d4Smrgvoid
903464ebd5Sriastradh_mesa_init_fbobjects(struct gl_context *ctx)
91c1f859d4Smrg{
92af69d88dSmrg   mtx_init(&DummyFramebuffer.Mutex, mtx_plain);
93af69d88dSmrg   mtx_init(&DummyRenderbuffer.Mutex, mtx_plain);
94af69d88dSmrg   mtx_init(&IncompleteFramebuffer.Mutex, mtx_plain);
95c1f859d4Smrg   DummyFramebuffer.Delete = delete_dummy_framebuffer;
96c1f859d4Smrg   DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
973464ebd5Sriastradh   IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
98c1f859d4Smrg}
99c1f859d4Smrg
1003464ebd5Sriastradhstruct gl_framebuffer *
1013464ebd5Sriastradh_mesa_get_incomplete_framebuffer(void)
1023464ebd5Sriastradh{
1033464ebd5Sriastradh   return &IncompleteFramebuffer;
1043464ebd5Sriastradh}
105c1f859d4Smrg
1067117f1b4Smrg/**
1077117f1b4Smrg * Helper routine for getting a gl_renderbuffer.
1087117f1b4Smrg */
1097117f1b4Smrgstruct gl_renderbuffer *
1103464ebd5Sriastradh_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
1117117f1b4Smrg{
1127117f1b4Smrg   struct gl_renderbuffer *rb;
1137117f1b4Smrg
1147117f1b4Smrg   if (id == 0)
1157117f1b4Smrg      return NULL;
1167117f1b4Smrg
1177117f1b4Smrg   rb = (struct gl_renderbuffer *)
1187117f1b4Smrg      _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
1197117f1b4Smrg   return rb;
1207117f1b4Smrg}
1217117f1b4Smrg
1227117f1b4Smrg
1237117f1b4Smrg/**
1247117f1b4Smrg * Helper routine for getting a gl_framebuffer.
1257117f1b4Smrg */
1267117f1b4Smrgstruct gl_framebuffer *
1273464ebd5Sriastradh_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
1287117f1b4Smrg{
1297117f1b4Smrg   struct gl_framebuffer *fb;
1307117f1b4Smrg
1317117f1b4Smrg   if (id == 0)
1327117f1b4Smrg      return NULL;
1337117f1b4Smrg
1347117f1b4Smrg   fb = (struct gl_framebuffer *)
1357117f1b4Smrg      _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
1367117f1b4Smrg   return fb;
1377117f1b4Smrg}
1387117f1b4Smrg
1397117f1b4Smrg
1404a49301eSmrg/**
1414a49301eSmrg * Mark the given framebuffer as invalid.  This will force the
1424a49301eSmrg * test for framebuffer completeness to be done before the framebuffer
1434a49301eSmrg * is used.
1444a49301eSmrg */
1454a49301eSmrgstatic void
1464a49301eSmrginvalidate_framebuffer(struct gl_framebuffer *fb)
1474a49301eSmrg{
1484a49301eSmrg   fb->_Status = 0; /* "indeterminate" */
1494a49301eSmrg}
1504a49301eSmrg
1514a49301eSmrg
1523464ebd5Sriastradh/**
1533464ebd5Sriastradh * Return the gl_framebuffer object which corresponds to the given
1543464ebd5Sriastradh * framebuffer target, such as GL_DRAW_FRAMEBUFFER.
1553464ebd5Sriastradh * Check support for GL_EXT_framebuffer_blit to determine if certain
1563464ebd5Sriastradh * targets are legal.
1573464ebd5Sriastradh * \return gl_framebuffer pointer or NULL if target is illegal
1583464ebd5Sriastradh */
1593464ebd5Sriastradhstatic struct gl_framebuffer *
1603464ebd5Sriastradhget_framebuffer_target(struct gl_context *ctx, GLenum target)
1613464ebd5Sriastradh{
162af69d88dSmrg   bool have_fb_blit = _mesa_is_gles3(ctx) || _mesa_is_desktop_gl(ctx);
1633464ebd5Sriastradh   switch (target) {
1643464ebd5Sriastradh   case GL_DRAW_FRAMEBUFFER:
165af69d88dSmrg      return have_fb_blit ? ctx->DrawBuffer : NULL;
1663464ebd5Sriastradh   case GL_READ_FRAMEBUFFER:
167af69d88dSmrg      return have_fb_blit ? ctx->ReadBuffer : NULL;
1683464ebd5Sriastradh   case GL_FRAMEBUFFER_EXT:
1693464ebd5Sriastradh      return ctx->DrawBuffer;
1703464ebd5Sriastradh   default:
1713464ebd5Sriastradh      return NULL;
1723464ebd5Sriastradh   }
1733464ebd5Sriastradh}
1743464ebd5Sriastradh
1753464ebd5Sriastradh
1767117f1b4Smrg/**
1777117f1b4Smrg * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
1787117f1b4Smrg * gl_renderbuffer_attachment object.
1793464ebd5Sriastradh * This function is only used for user-created FB objects, not the
1803464ebd5Sriastradh * default / window-system FB object.
1814a49301eSmrg * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
1824a49301eSmrg * the depth buffer attachment point.
1837117f1b4Smrg */
184af69d88dSmrgstatic struct gl_renderbuffer_attachment *
185af69d88dSmrgget_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
186af69d88dSmrg               GLenum attachment)
1877117f1b4Smrg{
1887117f1b4Smrg   GLuint i;
1897117f1b4Smrg
190af69d88dSmrg   assert(_mesa_is_user_fbo(fb));
1913464ebd5Sriastradh
1927117f1b4Smrg   switch (attachment) {
1937117f1b4Smrg   case GL_COLOR_ATTACHMENT0_EXT:
1947117f1b4Smrg   case GL_COLOR_ATTACHMENT1_EXT:
1957117f1b4Smrg   case GL_COLOR_ATTACHMENT2_EXT:
1967117f1b4Smrg   case GL_COLOR_ATTACHMENT3_EXT:
1977117f1b4Smrg   case GL_COLOR_ATTACHMENT4_EXT:
1987117f1b4Smrg   case GL_COLOR_ATTACHMENT5_EXT:
1997117f1b4Smrg   case GL_COLOR_ATTACHMENT6_EXT:
2007117f1b4Smrg   case GL_COLOR_ATTACHMENT7_EXT:
2017117f1b4Smrg   case GL_COLOR_ATTACHMENT8_EXT:
2027117f1b4Smrg   case GL_COLOR_ATTACHMENT9_EXT:
2037117f1b4Smrg   case GL_COLOR_ATTACHMENT10_EXT:
2047117f1b4Smrg   case GL_COLOR_ATTACHMENT11_EXT:
2057117f1b4Smrg   case GL_COLOR_ATTACHMENT12_EXT:
2067117f1b4Smrg   case GL_COLOR_ATTACHMENT13_EXT:
2077117f1b4Smrg   case GL_COLOR_ATTACHMENT14_EXT:
2087117f1b4Smrg   case GL_COLOR_ATTACHMENT15_EXT:
209af69d88dSmrg      /* Only OpenGL ES 1.x forbids color attachments other than
210af69d88dSmrg       * GL_COLOR_ATTACHMENT0.  For all other APIs the limit set by the
211af69d88dSmrg       * hardware is used.
212af69d88dSmrg       */
2137117f1b4Smrg      i = attachment - GL_COLOR_ATTACHMENT0_EXT;
214af69d88dSmrg      if (i >= ctx->Const.MaxColorAttachments
215af69d88dSmrg	  || (i > 0 && ctx->API == API_OPENGLES)) {
2167117f1b4Smrg	 return NULL;
2177117f1b4Smrg      }
2187117f1b4Smrg      return &fb->Attachment[BUFFER_COLOR0 + i];
2194a49301eSmrg   case GL_DEPTH_STENCIL_ATTACHMENT:
220af69d88dSmrg      if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
221af69d88dSmrg	 return NULL;
2224a49301eSmrg      /* fall-through */
2237117f1b4Smrg   case GL_DEPTH_ATTACHMENT_EXT:
2247117f1b4Smrg      return &fb->Attachment[BUFFER_DEPTH];
2257117f1b4Smrg   case GL_STENCIL_ATTACHMENT_EXT:
2267117f1b4Smrg      return &fb->Attachment[BUFFER_STENCIL];
2277117f1b4Smrg   default:
2287117f1b4Smrg      return NULL;
2297117f1b4Smrg   }
2307117f1b4Smrg}
2317117f1b4Smrg
2327117f1b4Smrg
2333464ebd5Sriastradh/**
2343464ebd5Sriastradh * As above, but only used for getting attachments of the default /
2353464ebd5Sriastradh * window-system framebuffer (not user-created framebuffer objects).
2363464ebd5Sriastradh */
2373464ebd5Sriastradhstatic struct gl_renderbuffer_attachment *
2383464ebd5Sriastradh_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
2393464ebd5Sriastradh                         GLenum attachment)
2403464ebd5Sriastradh{
241af69d88dSmrg   assert(_mesa_is_winsys_fbo(fb));
242af69d88dSmrg
243af69d88dSmrg   if (_mesa_is_gles3(ctx)) {
244af69d88dSmrg      assert(attachment == GL_BACK ||
245af69d88dSmrg             attachment == GL_DEPTH ||
246af69d88dSmrg             attachment == GL_STENCIL);
247af69d88dSmrg      switch (attachment) {
248af69d88dSmrg      case GL_BACK:
249af69d88dSmrg         /* Since there is no stereo rendering in ES 3.0, only return the
250af69d88dSmrg          * LEFT bits.
251af69d88dSmrg          */
252af69d88dSmrg         if (ctx->DrawBuffer->Visual.doubleBufferMode)
253af69d88dSmrg            return &fb->Attachment[BUFFER_BACK_LEFT];
254af69d88dSmrg         return &fb->Attachment[BUFFER_FRONT_LEFT];
255af69d88dSmrg      case GL_DEPTH:
256af69d88dSmrg      return &fb->Attachment[BUFFER_DEPTH];
257af69d88dSmrg      case GL_STENCIL:
258af69d88dSmrg         return &fb->Attachment[BUFFER_STENCIL];
259af69d88dSmrg      }
260af69d88dSmrg   }
2613464ebd5Sriastradh
2623464ebd5Sriastradh   switch (attachment) {
2633464ebd5Sriastradh   case GL_FRONT_LEFT:
2643464ebd5Sriastradh      return &fb->Attachment[BUFFER_FRONT_LEFT];
2653464ebd5Sriastradh   case GL_FRONT_RIGHT:
2663464ebd5Sriastradh      return &fb->Attachment[BUFFER_FRONT_RIGHT];
2673464ebd5Sriastradh   case GL_BACK_LEFT:
2683464ebd5Sriastradh      return &fb->Attachment[BUFFER_BACK_LEFT];
2693464ebd5Sriastradh   case GL_BACK_RIGHT:
2703464ebd5Sriastradh      return &fb->Attachment[BUFFER_BACK_RIGHT];
2713464ebd5Sriastradh   case GL_AUX0:
2723464ebd5Sriastradh      if (fb->Visual.numAuxBuffers == 1) {
2733464ebd5Sriastradh         return &fb->Attachment[BUFFER_AUX0];
2743464ebd5Sriastradh      }
2753464ebd5Sriastradh      return NULL;
276af69d88dSmrg
277af69d88dSmrg   /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says:
278af69d88dSmrg    *
279af69d88dSmrg    *     "If the default framebuffer is bound to target, then attachment must
280af69d88dSmrg    *     be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi,
281af69d88dSmrg    *     identifying a color buffer; DEPTH, identifying the depth buffer; or
282af69d88dSmrg    *     STENCIL, identifying the stencil buffer."
283af69d88dSmrg    *
284af69d88dSmrg    * Revision #34 of the ARB_framebuffer_object spec has essentially the same
285af69d88dSmrg    * language.  However, revision #33 of the ARB_framebuffer_object spec
286af69d88dSmrg    * says:
287af69d88dSmrg    *
288af69d88dSmrg    *     "If the default framebuffer is bound to <target>, then <attachment>
289af69d88dSmrg    *     must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi,
290af69d88dSmrg    *     DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the
291af69d88dSmrg    *     depth buffer, or the stencil buffer, and <pname> may be
292af69d88dSmrg    *     FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or
293af69d88dSmrg    *     FRAMEBUFFER_ATTACHMENT_OBJECT_NAME."
294af69d88dSmrg    *
295af69d88dSmrg    * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed
296af69d88dSmrg    * from glext.h, so shipping apps should not use those values.
297af69d88dSmrg    *
298af69d88dSmrg    * Note that neither EXT_framebuffer_object nor OES_framebuffer_object
299af69d88dSmrg    * support queries of the window system FBO.
300af69d88dSmrg    */
301af69d88dSmrg   case GL_DEPTH:
3023464ebd5Sriastradh      return &fb->Attachment[BUFFER_DEPTH];
303af69d88dSmrg   case GL_STENCIL:
3043464ebd5Sriastradh      return &fb->Attachment[BUFFER_STENCIL];
3053464ebd5Sriastradh   default:
3063464ebd5Sriastradh      return NULL;
3073464ebd5Sriastradh   }
3083464ebd5Sriastradh}
3093464ebd5Sriastradh
3103464ebd5Sriastradh
3113464ebd5Sriastradh
3127117f1b4Smrg/**
3137117f1b4Smrg * Remove any texture or renderbuffer attached to the given attachment
3147117f1b4Smrg * point.  Update reference counts, etc.
3157117f1b4Smrg */
316af69d88dSmrgstatic void
317af69d88dSmrgremove_attachment(struct gl_context *ctx,
318af69d88dSmrg                  struct gl_renderbuffer_attachment *att)
3197117f1b4Smrg{
320af69d88dSmrg   struct gl_renderbuffer *rb = att->Renderbuffer;
321af69d88dSmrg
322af69d88dSmrg   /* tell driver that we're done rendering to this texture. */
323af69d88dSmrg   if (rb && rb->NeedsFinishRenderTexture)
324af69d88dSmrg      ctx->Driver.FinishRenderTexture(ctx, rb);
325af69d88dSmrg
3267117f1b4Smrg   if (att->Type == GL_TEXTURE) {
3277117f1b4Smrg      ASSERT(att->Texture);
3287117f1b4Smrg      _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
3297117f1b4Smrg      ASSERT(!att->Texture);
3307117f1b4Smrg   }
3317117f1b4Smrg   if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
3327117f1b4Smrg      ASSERT(!att->Texture);
3337117f1b4Smrg      _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
3347117f1b4Smrg      ASSERT(!att->Renderbuffer);
3357117f1b4Smrg   }
3367117f1b4Smrg   att->Type = GL_NONE;
3377117f1b4Smrg   att->Complete = GL_TRUE;
3387117f1b4Smrg}
3397117f1b4Smrg
340af69d88dSmrg/**
341af69d88dSmrg * Verify a couple error conditions that will lead to an incomplete FBO and
342af69d88dSmrg * may cause problems for the driver's RenderTexture path.
343af69d88dSmrg */
344af69d88dSmrgstatic bool
345af69d88dSmrgdriver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att)
346af69d88dSmrg{
347af69d88dSmrg   const struct gl_texture_image *const texImage =
348af69d88dSmrg      att->Texture->Image[att->CubeMapFace][att->TextureLevel];
349af69d88dSmrg
350af69d88dSmrg   if (texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0)
351af69d88dSmrg      return false;
352af69d88dSmrg
353af69d88dSmrg   if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY
354af69d88dSmrg        && att->Zoffset >= texImage->Height)
355af69d88dSmrg       || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY
356af69d88dSmrg           && att->Zoffset >= texImage->Depth))
357af69d88dSmrg      return false;
358af69d88dSmrg
359af69d88dSmrg   return true;
360af69d88dSmrg}
361af69d88dSmrg
362af69d88dSmrg/**
363af69d88dSmrg * Create a renderbuffer which will be set up by the driver to wrap the
364af69d88dSmrg * texture image slice.
365af69d88dSmrg *
366af69d88dSmrg * By using a gl_renderbuffer (like user-allocated renderbuffers), drivers get
367af69d88dSmrg * to share most of their framebuffer rendering code between winsys,
368af69d88dSmrg * renderbuffer, and texture attachments.
369af69d88dSmrg *
370af69d88dSmrg * The allocated renderbuffer uses a non-zero Name so that drivers can check
371af69d88dSmrg * it for determining vertical orientation, but we use ~0 to make it fairly
372af69d88dSmrg * unambiguous with actual user (non-texture) renderbuffers.
373af69d88dSmrg */
374af69d88dSmrgvoid
375af69d88dSmrg_mesa_update_texture_renderbuffer(struct gl_context *ctx,
376af69d88dSmrg                                  struct gl_framebuffer *fb,
377af69d88dSmrg                                  struct gl_renderbuffer_attachment *att)
378af69d88dSmrg{
379af69d88dSmrg   struct gl_texture_image *texImage;
380af69d88dSmrg   struct gl_renderbuffer *rb;
381af69d88dSmrg
382af69d88dSmrg   texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
383af69d88dSmrg
384af69d88dSmrg   rb = att->Renderbuffer;
385af69d88dSmrg   if (!rb) {
386af69d88dSmrg      rb = ctx->Driver.NewRenderbuffer(ctx, ~0);
387af69d88dSmrg      if (!rb) {
388af69d88dSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()");
389af69d88dSmrg         return;
390af69d88dSmrg      }
391af69d88dSmrg      _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
392af69d88dSmrg
393af69d88dSmrg      /* This can't get called on a texture renderbuffer, so set it to NULL
394af69d88dSmrg       * for clarity compared to user renderbuffers.
395af69d88dSmrg       */
396af69d88dSmrg      rb->AllocStorage = NULL;
397af69d88dSmrg
398af69d88dSmrg      rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL;
399af69d88dSmrg   }
400af69d88dSmrg
401af69d88dSmrg   if (!texImage)
402af69d88dSmrg      return;
403af69d88dSmrg
404af69d88dSmrg   rb->_BaseFormat = texImage->_BaseFormat;
405af69d88dSmrg   rb->Format = texImage->TexFormat;
406af69d88dSmrg   rb->InternalFormat = texImage->InternalFormat;
407af69d88dSmrg   rb->Width = texImage->Width2;
408af69d88dSmrg   rb->Height = texImage->Height2;
409af69d88dSmrg   rb->Depth = texImage->Depth2;
410af69d88dSmrg   rb->NumSamples = texImage->NumSamples;
411af69d88dSmrg   rb->TexImage = texImage;
412af69d88dSmrg
413af69d88dSmrg   if (driver_RenderTexture_is_safe(att))
414af69d88dSmrg      ctx->Driver.RenderTexture(ctx, fb, att);
415af69d88dSmrg}
4167117f1b4Smrg
4177117f1b4Smrg/**
4187117f1b4Smrg * Bind a texture object to an attachment point.
4197117f1b4Smrg * The previous binding, if any, will be removed first.
4207117f1b4Smrg */
421af69d88dSmrgstatic void
422af69d88dSmrgset_texture_attachment(struct gl_context *ctx,
423af69d88dSmrg                       struct gl_framebuffer *fb,
424af69d88dSmrg                       struct gl_renderbuffer_attachment *att,
425af69d88dSmrg                       struct gl_texture_object *texObj,
426af69d88dSmrg                       GLenum texTarget, GLuint level, GLuint zoffset,
427af69d88dSmrg                       GLboolean layered)
4287117f1b4Smrg{
429af69d88dSmrg   struct gl_renderbuffer *rb = att->Renderbuffer;
430af69d88dSmrg
431af69d88dSmrg   if (rb && rb->NeedsFinishRenderTexture)
432af69d88dSmrg      ctx->Driver.FinishRenderTexture(ctx, rb);
433af69d88dSmrg
4347117f1b4Smrg   if (att->Texture == texObj) {
4357117f1b4Smrg      /* re-attaching same texture */
4367117f1b4Smrg      ASSERT(att->Type == GL_TEXTURE);
4377117f1b4Smrg   }
4387117f1b4Smrg   else {
4397117f1b4Smrg      /* new attachment */
440af69d88dSmrg      remove_attachment(ctx, att);
4417117f1b4Smrg      att->Type = GL_TEXTURE;
4427117f1b4Smrg      assert(!att->Texture);
4437117f1b4Smrg      _mesa_reference_texobj(&att->Texture, texObj);
4447117f1b4Smrg   }
445af69d88dSmrg   invalidate_framebuffer(fb);
4467117f1b4Smrg
4477117f1b4Smrg   /* always update these fields */
4487117f1b4Smrg   att->TextureLevel = level;
4494a49301eSmrg   att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
4507117f1b4Smrg   att->Zoffset = zoffset;
451af69d88dSmrg   att->Layered = layered;
4527117f1b4Smrg   att->Complete = GL_FALSE;
4537117f1b4Smrg
454af69d88dSmrg   _mesa_update_texture_renderbuffer(ctx, fb, att);
4557117f1b4Smrg}
4567117f1b4Smrg
4577117f1b4Smrg
4587117f1b4Smrg/**
4597117f1b4Smrg * Bind a renderbuffer to an attachment point.
4607117f1b4Smrg * The previous binding, if any, will be removed first.
4617117f1b4Smrg */
462af69d88dSmrgstatic void
463af69d88dSmrgset_renderbuffer_attachment(struct gl_context *ctx,
464af69d88dSmrg                            struct gl_renderbuffer_attachment *att,
465af69d88dSmrg                            struct gl_renderbuffer *rb)
4667117f1b4Smrg{
4677117f1b4Smrg   /* XXX check if re-doing same attachment, exit early */
468af69d88dSmrg   remove_attachment(ctx, att);
4697117f1b4Smrg   att->Type = GL_RENDERBUFFER_EXT;
4707117f1b4Smrg   att->Texture = NULL; /* just to be safe */
4717117f1b4Smrg   att->Complete = GL_FALSE;
4727117f1b4Smrg   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
4737117f1b4Smrg}
4747117f1b4Smrg
4757117f1b4Smrg
4767117f1b4Smrg/**
4777117f1b4Smrg * Fallback for ctx->Driver.FramebufferRenderbuffer()
4787117f1b4Smrg * Attach a renderbuffer object to a framebuffer object.
4797117f1b4Smrg */
4807117f1b4Smrgvoid
4813464ebd5Sriastradh_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
4823464ebd5Sriastradh                               struct gl_framebuffer *fb,
4837117f1b4Smrg                               GLenum attachment, struct gl_renderbuffer *rb)
4847117f1b4Smrg{
4857117f1b4Smrg   struct gl_renderbuffer_attachment *att;
4867117f1b4Smrg
487af69d88dSmrg   mtx_lock(&fb->Mutex);
4887117f1b4Smrg
489af69d88dSmrg   att = get_attachment(ctx, fb, attachment);
4907117f1b4Smrg   ASSERT(att);
4917117f1b4Smrg   if (rb) {
492af69d88dSmrg      set_renderbuffer_attachment(ctx, att, rb);
4934a49301eSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
4944a49301eSmrg         /* do stencil attachment here (depth already done above) */
495af69d88dSmrg         att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
4964a49301eSmrg         assert(att);
497af69d88dSmrg         set_renderbuffer_attachment(ctx, att, rb);
4984a49301eSmrg      }
4993464ebd5Sriastradh      rb->AttachedAnytime = GL_TRUE;
5007117f1b4Smrg   }
5017117f1b4Smrg   else {
502af69d88dSmrg      remove_attachment(ctx, att);
503af69d88dSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
504af69d88dSmrg         /* detach stencil (depth was detached above) */
505af69d88dSmrg         att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
506af69d88dSmrg         assert(att);
507af69d88dSmrg         remove_attachment(ctx, att);
508af69d88dSmrg      }
5097117f1b4Smrg   }
5107117f1b4Smrg
5114a49301eSmrg   invalidate_framebuffer(fb);
5124a49301eSmrg
513af69d88dSmrg   mtx_unlock(&fb->Mutex);
5147117f1b4Smrg}
5157117f1b4Smrg
5167117f1b4Smrg
5173464ebd5Sriastradh/**
5183464ebd5Sriastradh * Fallback for ctx->Driver.ValidateFramebuffer()
5193464ebd5Sriastradh * Check if the renderbuffer's formats are supported by the software
5203464ebd5Sriastradh * renderer.
5213464ebd5Sriastradh * Drivers should probably override this.
5223464ebd5Sriastradh */
5233464ebd5Sriastradhvoid
5243464ebd5Sriastradh_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
5253464ebd5Sriastradh{
5263464ebd5Sriastradh   gl_buffer_index buf;
5273464ebd5Sriastradh   for (buf = 0; buf < BUFFER_COUNT; buf++) {
5283464ebd5Sriastradh      const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer;
5293464ebd5Sriastradh      if (rb) {
5303464ebd5Sriastradh         switch (rb->_BaseFormat) {
5313464ebd5Sriastradh         case GL_ALPHA:
5323464ebd5Sriastradh         case GL_LUMINANCE_ALPHA:
5333464ebd5Sriastradh         case GL_LUMINANCE:
5343464ebd5Sriastradh         case GL_INTENSITY:
5353464ebd5Sriastradh         case GL_RED:
5363464ebd5Sriastradh         case GL_RG:
5373464ebd5Sriastradh            fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
5383464ebd5Sriastradh            return;
5393464ebd5Sriastradh
5403464ebd5Sriastradh         default:
5413464ebd5Sriastradh            switch (rb->Format) {
5423464ebd5Sriastradh            /* XXX This list is likely incomplete. */
543af69d88dSmrg            case MESA_FORMAT_R9G9B9E5_FLOAT:
5443464ebd5Sriastradh               fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
5453464ebd5Sriastradh               return;
5463464ebd5Sriastradh            default:;
5473464ebd5Sriastradh               /* render buffer format is supported by software rendering */
5483464ebd5Sriastradh            }
5493464ebd5Sriastradh         }
5503464ebd5Sriastradh      }
5513464ebd5Sriastradh   }
5523464ebd5Sriastradh}
5533464ebd5Sriastradh
5543464ebd5Sriastradh
555af69d88dSmrg/**
556af69d88dSmrg * Return true if the framebuffer has a combined depth/stencil
557af69d88dSmrg * renderbuffer attached.
558af69d88dSmrg */
559af69d88dSmrgGLboolean
560af69d88dSmrg_mesa_has_depthstencil_combined(const struct gl_framebuffer *fb)
561af69d88dSmrg{
562af69d88dSmrg   const struct gl_renderbuffer_attachment *depth =
563af69d88dSmrg         &fb->Attachment[BUFFER_DEPTH];
564af69d88dSmrg   const struct gl_renderbuffer_attachment *stencil =
565af69d88dSmrg         &fb->Attachment[BUFFER_STENCIL];
566af69d88dSmrg
567af69d88dSmrg   if (depth->Type == stencil->Type) {
568af69d88dSmrg      if (depth->Type == GL_RENDERBUFFER_EXT &&
569af69d88dSmrg          depth->Renderbuffer == stencil->Renderbuffer)
570af69d88dSmrg         return GL_TRUE;
571af69d88dSmrg
572af69d88dSmrg      if (depth->Type == GL_TEXTURE &&
573af69d88dSmrg          depth->Texture == stencil->Texture)
574af69d88dSmrg         return GL_TRUE;
575af69d88dSmrg   }
576af69d88dSmrg
577af69d88dSmrg   return GL_FALSE;
578af69d88dSmrg}
579af69d88dSmrg
580af69d88dSmrg
5814a49301eSmrg/**
5824a49301eSmrg * For debug only.
5834a49301eSmrg */
5844a49301eSmrgstatic void
5854a49301eSmrgatt_incomplete(const char *msg)
5864a49301eSmrg{
587af69d88dSmrg   if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
588af69d88dSmrg      _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
589af69d88dSmrg   }
5904a49301eSmrg}
5914a49301eSmrg
5924a49301eSmrg
5934a49301eSmrg/**
5944a49301eSmrg * For debug only.
5954a49301eSmrg */
5964a49301eSmrgstatic void
597af69d88dSmrgfbo_incomplete(struct gl_context *ctx, const char *msg, int index)
5984a49301eSmrg{
599af69d88dSmrg   static GLuint msg_id;
600af69d88dSmrg
601af69d88dSmrg   _mesa_gl_debug(ctx, &msg_id,
602af69d88dSmrg                  MESA_DEBUG_TYPE_OTHER,
603af69d88dSmrg                  MESA_DEBUG_SEVERITY_MEDIUM,
604af69d88dSmrg                  "FBO incomplete: %s [%d]\n", msg, index);
605af69d88dSmrg
606af69d88dSmrg   if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
607af69d88dSmrg      _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
608af69d88dSmrg   }
6094a49301eSmrg}
6104a49301eSmrg
6114a49301eSmrg
6123464ebd5Sriastradh/**
6133464ebd5Sriastradh * Is the given base format a legal format for a color renderbuffer?
6143464ebd5Sriastradh */
6153464ebd5SriastradhGLboolean
6163464ebd5Sriastradh_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
6173464ebd5Sriastradh{
6183464ebd5Sriastradh   switch (baseFormat) {
6193464ebd5Sriastradh   case GL_RGB:
6203464ebd5Sriastradh   case GL_RGBA:
6213464ebd5Sriastradh      return GL_TRUE;
6223464ebd5Sriastradh   case GL_LUMINANCE:
6233464ebd5Sriastradh   case GL_LUMINANCE_ALPHA:
6243464ebd5Sriastradh   case GL_INTENSITY:
6253464ebd5Sriastradh   case GL_ALPHA:
626af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
627af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object;
6283464ebd5Sriastradh   case GL_RED:
6293464ebd5Sriastradh   case GL_RG:
6303464ebd5Sriastradh      return ctx->Extensions.ARB_texture_rg;
6313464ebd5Sriastradh   default:
6323464ebd5Sriastradh      return GL_FALSE;
6333464ebd5Sriastradh   }
6343464ebd5Sriastradh}
6353464ebd5Sriastradh
6363464ebd5Sriastradh
637af69d88dSmrg/**
638af69d88dSmrg * Is the given base format a legal format for a color renderbuffer?
639af69d88dSmrg */
640af69d88dSmrgstatic GLboolean
641af69d88dSmrgis_format_color_renderable(const struct gl_context *ctx, mesa_format format,
642af69d88dSmrg                           GLenum internalFormat)
643af69d88dSmrg{
644af69d88dSmrg   const GLenum baseFormat =
645af69d88dSmrg      _mesa_get_format_base_format(format);
646af69d88dSmrg   GLboolean valid;
647af69d88dSmrg
648af69d88dSmrg   valid = _mesa_is_legal_color_format(ctx, baseFormat);
649af69d88dSmrg   if (!valid || _mesa_is_desktop_gl(ctx)) {
650af69d88dSmrg      return valid;
651af69d88dSmrg   }
652af69d88dSmrg
653af69d88dSmrg   /* Reject additional cases for GLES */
654af69d88dSmrg   switch (internalFormat) {
655af69d88dSmrg   case GL_RGBA8_SNORM:
656af69d88dSmrg   case GL_RGB32F:
657af69d88dSmrg   case GL_RGB32I:
658af69d88dSmrg   case GL_RGB32UI:
659af69d88dSmrg   case GL_RGB16F:
660af69d88dSmrg   case GL_RGB16I:
661af69d88dSmrg   case GL_RGB16UI:
662af69d88dSmrg   case GL_RGB8_SNORM:
663af69d88dSmrg   case GL_RGB8I:
664af69d88dSmrg   case GL_RGB8UI:
665af69d88dSmrg   case GL_SRGB8:
666af69d88dSmrg   case GL_RGB9_E5:
667af69d88dSmrg   case GL_RG8_SNORM:
668af69d88dSmrg   case GL_R8_SNORM:
669af69d88dSmrg      return GL_FALSE;
670af69d88dSmrg   default:
671af69d88dSmrg      break;
672af69d88dSmrg   }
673af69d88dSmrg
674af69d88dSmrg   if (format == MESA_FORMAT_B10G10R10A2_UNORM &&
675af69d88dSmrg       internalFormat != GL_RGB10_A2) {
676af69d88dSmrg      return GL_FALSE;
677af69d88dSmrg   }
678af69d88dSmrg
679af69d88dSmrg   return GL_TRUE;
680af69d88dSmrg}
681af69d88dSmrg
682af69d88dSmrg
6833464ebd5Sriastradh/**
6843464ebd5Sriastradh * Is the given base format a legal format for a depth/stencil renderbuffer?
6853464ebd5Sriastradh */
6863464ebd5Sriastradhstatic GLboolean
6873464ebd5Sriastradhis_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
6883464ebd5Sriastradh{
6893464ebd5Sriastradh   switch (baseFormat) {
6903464ebd5Sriastradh   case GL_DEPTH_COMPONENT:
6913464ebd5Sriastradh   case GL_DEPTH_STENCIL_EXT:
6923464ebd5Sriastradh      return GL_TRUE;
6933464ebd5Sriastradh   default:
6943464ebd5Sriastradh      return GL_FALSE;
6953464ebd5Sriastradh   }
6963464ebd5Sriastradh}
6974a49301eSmrg
6984a49301eSmrg
6997117f1b4Smrg/**
7007117f1b4Smrg * Test if an attachment point is complete and update its Complete field.
7017117f1b4Smrg * \param format if GL_COLOR, this is a color attachment point,
7027117f1b4Smrg *               if GL_DEPTH, this is a depth component attachment point,
7037117f1b4Smrg *               if GL_STENCIL, this is a stencil component attachment point.
7047117f1b4Smrg */
7057117f1b4Smrgstatic void
7063464ebd5Sriastradhtest_attachment_completeness(const struct gl_context *ctx, GLenum format,
7077117f1b4Smrg                             struct gl_renderbuffer_attachment *att)
7087117f1b4Smrg{
7097117f1b4Smrg   assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
7107117f1b4Smrg
7117117f1b4Smrg   /* assume complete */
7127117f1b4Smrg   att->Complete = GL_TRUE;
7137117f1b4Smrg
7147117f1b4Smrg   /* Look for reasons why the attachment might be incomplete */
7157117f1b4Smrg   if (att->Type == GL_TEXTURE) {
7167117f1b4Smrg      const struct gl_texture_object *texObj = att->Texture;
7177117f1b4Smrg      struct gl_texture_image *texImage;
7184a49301eSmrg      GLenum baseFormat;
7197117f1b4Smrg
7207117f1b4Smrg      if (!texObj) {
7214a49301eSmrg         att_incomplete("no texobj");
7227117f1b4Smrg         att->Complete = GL_FALSE;
7237117f1b4Smrg         return;
7247117f1b4Smrg      }
7257117f1b4Smrg
7267117f1b4Smrg      texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
7277117f1b4Smrg      if (!texImage) {
7284a49301eSmrg         att_incomplete("no teximage");
7297117f1b4Smrg         att->Complete = GL_FALSE;
7307117f1b4Smrg         return;
7317117f1b4Smrg      }
7327117f1b4Smrg      if (texImage->Width < 1 || texImage->Height < 1) {
7334a49301eSmrg         att_incomplete("teximage width/height=0");
7347117f1b4Smrg         att->Complete = GL_FALSE;
7357117f1b4Smrg         return;
7367117f1b4Smrg      }
737af69d88dSmrg
738af69d88dSmrg      switch (texObj->Target) {
739af69d88dSmrg      case GL_TEXTURE_3D:
740af69d88dSmrg         if (att->Zoffset >= texImage->Depth) {
741af69d88dSmrg            att_incomplete("bad z offset");
742af69d88dSmrg            att->Complete = GL_FALSE;
743af69d88dSmrg            return;
744af69d88dSmrg         }
745af69d88dSmrg         break;
746af69d88dSmrg      case GL_TEXTURE_1D_ARRAY:
747af69d88dSmrg         if (att->Zoffset >= texImage->Height) {
748af69d88dSmrg            att_incomplete("bad 1D-array layer");
749af69d88dSmrg            att->Complete = GL_FALSE;
750af69d88dSmrg            return;
751af69d88dSmrg         }
752af69d88dSmrg         break;
753af69d88dSmrg      case GL_TEXTURE_2D_ARRAY:
754af69d88dSmrg         if (att->Zoffset >= texImage->Depth) {
755af69d88dSmrg            att_incomplete("bad 2D-array layer");
756af69d88dSmrg            att->Complete = GL_FALSE;
757af69d88dSmrg            return;
758af69d88dSmrg         }
759af69d88dSmrg         break;
760af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_ARRAY:
761af69d88dSmrg         if (att->Zoffset >= texImage->Depth) {
762af69d88dSmrg            att_incomplete("bad cube-array layer");
763af69d88dSmrg            att->Complete = GL_FALSE;
764af69d88dSmrg            return;
765af69d88dSmrg         }
766af69d88dSmrg         break;
7677117f1b4Smrg      }
7687117f1b4Smrg
7694a49301eSmrg      baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
7704a49301eSmrg
7717117f1b4Smrg      if (format == GL_COLOR) {
7723464ebd5Sriastradh         if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
7734a49301eSmrg            att_incomplete("bad format");
7744a49301eSmrg            att->Complete = GL_FALSE;
7754a49301eSmrg            return;
7764a49301eSmrg         }
7774a49301eSmrg         if (_mesa_is_format_compressed(texImage->TexFormat)) {
7784a49301eSmrg            att_incomplete("compressed internalformat");
7797117f1b4Smrg            att->Complete = GL_FALSE;
7807117f1b4Smrg            return;
7817117f1b4Smrg         }
7827117f1b4Smrg      }
7837117f1b4Smrg      else if (format == GL_DEPTH) {
7844a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
7857117f1b4Smrg            /* OK */
7867117f1b4Smrg         }
787af69d88dSmrg         else if (ctx->Extensions.ARB_depth_texture &&
788af69d88dSmrg                  baseFormat == GL_DEPTH_STENCIL) {
7897117f1b4Smrg            /* OK */
7907117f1b4Smrg         }
7917117f1b4Smrg         else {
7927117f1b4Smrg            att->Complete = GL_FALSE;
7934a49301eSmrg            att_incomplete("bad depth format");
7947117f1b4Smrg            return;
7957117f1b4Smrg         }
7967117f1b4Smrg      }
7977117f1b4Smrg      else {
798c7037ccdSmrg         ASSERT(format == GL_STENCIL);
799af69d88dSmrg         if (ctx->Extensions.ARB_depth_texture &&
800af69d88dSmrg             baseFormat == GL_DEPTH_STENCIL) {
801c7037ccdSmrg            /* OK */
802c7037ccdSmrg         }
803c7037ccdSmrg         else {
804c7037ccdSmrg            /* no such thing as stencil-only textures */
8054a49301eSmrg            att_incomplete("illegal stencil texture");
806c7037ccdSmrg            att->Complete = GL_FALSE;
807c7037ccdSmrg            return;
808c7037ccdSmrg         }
8097117f1b4Smrg      }
8107117f1b4Smrg   }
8117117f1b4Smrg   else if (att->Type == GL_RENDERBUFFER_EXT) {
8124a49301eSmrg      const GLenum baseFormat =
8134a49301eSmrg         _mesa_get_format_base_format(att->Renderbuffer->Format);
8144a49301eSmrg
8157117f1b4Smrg      ASSERT(att->Renderbuffer);
8167117f1b4Smrg      if (!att->Renderbuffer->InternalFormat ||
8177117f1b4Smrg          att->Renderbuffer->Width < 1 ||
8187117f1b4Smrg          att->Renderbuffer->Height < 1) {
8194a49301eSmrg         att_incomplete("0x0 renderbuffer");
8207117f1b4Smrg         att->Complete = GL_FALSE;
8217117f1b4Smrg         return;
8227117f1b4Smrg      }
8237117f1b4Smrg      if (format == GL_COLOR) {
8243464ebd5Sriastradh         if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
8254a49301eSmrg            att_incomplete("bad renderbuffer color format");
8267117f1b4Smrg            att->Complete = GL_FALSE;
8277117f1b4Smrg            return;
8287117f1b4Smrg         }
8297117f1b4Smrg      }
8307117f1b4Smrg      else if (format == GL_DEPTH) {
8314a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
8327117f1b4Smrg            /* OK */
8337117f1b4Smrg         }
834af69d88dSmrg         else if (baseFormat == GL_DEPTH_STENCIL) {
8357117f1b4Smrg            /* OK */
8367117f1b4Smrg         }
8377117f1b4Smrg         else {
8384a49301eSmrg            att_incomplete("bad renderbuffer depth format");
8397117f1b4Smrg            att->Complete = GL_FALSE;
8407117f1b4Smrg            return;
8417117f1b4Smrg         }
8427117f1b4Smrg      }
8437117f1b4Smrg      else {
8447117f1b4Smrg         assert(format == GL_STENCIL);
845af69d88dSmrg         if (baseFormat == GL_STENCIL_INDEX ||
846af69d88dSmrg             baseFormat == GL_DEPTH_STENCIL) {
8477117f1b4Smrg            /* OK */
8487117f1b4Smrg         }
8497117f1b4Smrg         else {
8507117f1b4Smrg            att->Complete = GL_FALSE;
8514a49301eSmrg            att_incomplete("bad renderbuffer stencil format");
8527117f1b4Smrg            return;
8537117f1b4Smrg         }
8547117f1b4Smrg      }
8557117f1b4Smrg   }
8567117f1b4Smrg   else {
8577117f1b4Smrg      ASSERT(att->Type == GL_NONE);
8587117f1b4Smrg      /* complete */
8597117f1b4Smrg      return;
8607117f1b4Smrg   }
8617117f1b4Smrg}
8627117f1b4Smrg
8637117f1b4Smrg
8647117f1b4Smrg/**
8657117f1b4Smrg * Test if the given framebuffer object is complete and update its
8667117f1b4Smrg * Status field with the results.
8674a49301eSmrg * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
8684a49301eSmrg * driver to make hardware-specific validation/completeness checks.
8697117f1b4Smrg * Also update the framebuffer's Width and Height fields if the
8707117f1b4Smrg * framebuffer is complete.
8717117f1b4Smrg */
8727117f1b4Smrgvoid
8733464ebd5Sriastradh_mesa_test_framebuffer_completeness(struct gl_context *ctx,
8743464ebd5Sriastradh                                    struct gl_framebuffer *fb)
8757117f1b4Smrg{
8764a49301eSmrg   GLuint numImages;
8774a49301eSmrg   GLenum intFormat = GL_NONE; /* color buffers' internal format */
8784a49301eSmrg   GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
8794a49301eSmrg   GLint numSamples = -1;
880af69d88dSmrg   GLint fixedSampleLocations = -1;
8817117f1b4Smrg   GLint i;
8827117f1b4Smrg   GLuint j;
883af69d88dSmrg   /* Covers max_layer_count, is_layered, and layer_tex_target */
884af69d88dSmrg   bool layer_info_valid = false;
885af69d88dSmrg   GLuint max_layer_count = 0, att_layer_count;
886af69d88dSmrg   bool is_layered = false;
887af69d88dSmrg   GLenum layer_tex_target = 0;
888af69d88dSmrg
889af69d88dSmrg   assert(_mesa_is_user_fbo(fb));
8907117f1b4Smrg
891af69d88dSmrg   /* we're changing framebuffer fields here */
892af69d88dSmrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
8937117f1b4Smrg
8947117f1b4Smrg   numImages = 0;
8957117f1b4Smrg   fb->Width = 0;
8967117f1b4Smrg   fb->Height = 0;
897af69d88dSmrg   fb->_AllColorBuffersFixedPoint = GL_TRUE;
898af69d88dSmrg   fb->_HasSNormOrFloatColorBuffer = GL_FALSE;
8997117f1b4Smrg
9004a49301eSmrg   /* Start at -2 to more easily loop over all attachment points.
9014a49301eSmrg    *  -2: depth buffer
9024a49301eSmrg    *  -1: stencil buffer
9034a49301eSmrg    * >=0: color buffer
9044a49301eSmrg    */
9057117f1b4Smrg   for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
9067117f1b4Smrg      struct gl_renderbuffer_attachment *att;
9077117f1b4Smrg      GLenum f;
908af69d88dSmrg      mesa_format attFormat;
909af69d88dSmrg      GLenum att_tex_target = GL_NONE;
9107117f1b4Smrg
9114a49301eSmrg      /*
9124a49301eSmrg       * XXX for ARB_fbo, only check color buffers that are named by
9134a49301eSmrg       * GL_READ_BUFFER and GL_DRAW_BUFFERi.
9144a49301eSmrg       */
9154a49301eSmrg
9164a49301eSmrg      /* check for attachment completeness
9174a49301eSmrg       */
9187117f1b4Smrg      if (i == -2) {
9197117f1b4Smrg         att = &fb->Attachment[BUFFER_DEPTH];
9207117f1b4Smrg         test_attachment_completeness(ctx, GL_DEPTH, att);
9217117f1b4Smrg         if (!att->Complete) {
9227117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
923af69d88dSmrg            fbo_incomplete(ctx, "depth attachment incomplete", -1);
9247117f1b4Smrg            return;
9257117f1b4Smrg         }
9267117f1b4Smrg      }
9277117f1b4Smrg      else if (i == -1) {
9287117f1b4Smrg         att = &fb->Attachment[BUFFER_STENCIL];
9297117f1b4Smrg         test_attachment_completeness(ctx, GL_STENCIL, att);
9307117f1b4Smrg         if (!att->Complete) {
9317117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
932af69d88dSmrg            fbo_incomplete(ctx, "stencil attachment incomplete", -1);
9337117f1b4Smrg            return;
9347117f1b4Smrg         }
9357117f1b4Smrg      }
9367117f1b4Smrg      else {
9377117f1b4Smrg         att = &fb->Attachment[BUFFER_COLOR0 + i];
9387117f1b4Smrg         test_attachment_completeness(ctx, GL_COLOR, att);
9397117f1b4Smrg         if (!att->Complete) {
9407117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
941af69d88dSmrg            fbo_incomplete(ctx, "color attachment incomplete", i);
9427117f1b4Smrg            return;
9437117f1b4Smrg         }
9447117f1b4Smrg      }
9457117f1b4Smrg
9464a49301eSmrg      /* get width, height, format of the renderbuffer/texture
9474a49301eSmrg       */
9487117f1b4Smrg      if (att->Type == GL_TEXTURE) {
949af69d88dSmrg         const struct gl_texture_image *texImg = att->Renderbuffer->TexImage;
950af69d88dSmrg         att_tex_target = att->Texture->Target;
9514a49301eSmrg         minWidth = MIN2(minWidth, texImg->Width);
9524a49301eSmrg         maxWidth = MAX2(maxWidth, texImg->Width);
9534a49301eSmrg         minHeight = MIN2(minHeight, texImg->Height);
9544a49301eSmrg         maxHeight = MAX2(maxHeight, texImg->Height);
9557117f1b4Smrg         f = texImg->_BaseFormat;
9563464ebd5Sriastradh         attFormat = texImg->TexFormat;
9577117f1b4Smrg         numImages++;
958af69d88dSmrg
959af69d88dSmrg         if (!is_format_color_renderable(ctx, attFormat,
960af69d88dSmrg                                         texImg->InternalFormat) &&
9613464ebd5Sriastradh             !is_legal_depth_format(ctx, f)) {
9627117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
963af69d88dSmrg            fbo_incomplete(ctx, "texture attachment incomplete", -1);
964af69d88dSmrg            return;
965af69d88dSmrg         }
966af69d88dSmrg
967af69d88dSmrg         if (numSamples < 0)
968af69d88dSmrg            numSamples = texImg->NumSamples;
969af69d88dSmrg         else if (numSamples != texImg->NumSamples) {
970af69d88dSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
971af69d88dSmrg            fbo_incomplete(ctx, "inconsistent sample count", -1);
972af69d88dSmrg            return;
973af69d88dSmrg         }
974af69d88dSmrg
975af69d88dSmrg         if (fixedSampleLocations < 0)
976af69d88dSmrg            fixedSampleLocations = texImg->FixedSampleLocations;
977af69d88dSmrg         else if (fixedSampleLocations != texImg->FixedSampleLocations) {
978af69d88dSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
979af69d88dSmrg            fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
9807117f1b4Smrg            return;
9817117f1b4Smrg         }
9827117f1b4Smrg      }
9837117f1b4Smrg      else if (att->Type == GL_RENDERBUFFER_EXT) {
9844a49301eSmrg         minWidth = MIN2(minWidth, att->Renderbuffer->Width);
9854a49301eSmrg         maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
9864a49301eSmrg         minHeight = MIN2(minHeight, att->Renderbuffer->Height);
9874a49301eSmrg         maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
9887117f1b4Smrg         f = att->Renderbuffer->InternalFormat;
9893464ebd5Sriastradh         attFormat = att->Renderbuffer->Format;
9907117f1b4Smrg         numImages++;
991af69d88dSmrg
992af69d88dSmrg         if (numSamples < 0)
993af69d88dSmrg            numSamples = att->Renderbuffer->NumSamples;
994af69d88dSmrg         else if (numSamples != att->Renderbuffer->NumSamples) {
995af69d88dSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
996af69d88dSmrg            fbo_incomplete(ctx, "inconsistent sample count", -1);
997af69d88dSmrg            return;
998af69d88dSmrg         }
999af69d88dSmrg
1000af69d88dSmrg         /* RENDERBUFFER has fixedSampleLocations implicitly true */
1001af69d88dSmrg         if (fixedSampleLocations < 0)
1002af69d88dSmrg            fixedSampleLocations = GL_TRUE;
1003af69d88dSmrg         else if (fixedSampleLocations != GL_TRUE) {
1004af69d88dSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1005af69d88dSmrg            fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
1006af69d88dSmrg            return;
1007af69d88dSmrg         }
10087117f1b4Smrg      }
10097117f1b4Smrg      else {
10107117f1b4Smrg         assert(att->Type == GL_NONE);
10117117f1b4Smrg         continue;
10127117f1b4Smrg      }
10137117f1b4Smrg
10143464ebd5Sriastradh      /* check if integer color */
10153464ebd5Sriastradh      fb->_IntegerColor = _mesa_is_format_integer_color(attFormat);
10163464ebd5Sriastradh
1017af69d88dSmrg      /* Update _AllColorBuffersFixedPoint and _HasSNormOrFloatColorBuffer. */
1018af69d88dSmrg      if (i >= 0) {
1019af69d88dSmrg         GLenum type = _mesa_get_format_datatype(attFormat);
1020af69d88dSmrg
1021af69d88dSmrg         fb->_AllColorBuffersFixedPoint =
1022af69d88dSmrg            fb->_AllColorBuffersFixedPoint &&
1023af69d88dSmrg            (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED);
1024af69d88dSmrg
1025af69d88dSmrg         fb->_HasSNormOrFloatColorBuffer =
1026af69d88dSmrg            fb->_HasSNormOrFloatColorBuffer ||
1027af69d88dSmrg            type == GL_SIGNED_NORMALIZED || type == GL_FLOAT;
1028af69d88dSmrg      }
1029af69d88dSmrg
1030af69d88dSmrg      /* Error-check width, height, format */
10317117f1b4Smrg      if (numImages == 1) {
1032af69d88dSmrg         /* save format */
10334a49301eSmrg         if (i >= 0) {
10347117f1b4Smrg            intFormat = f;
10354a49301eSmrg         }
10367117f1b4Smrg      }
10377117f1b4Smrg      else {
10384a49301eSmrg         if (!ctx->Extensions.ARB_framebuffer_object) {
10394a49301eSmrg            /* check that width, height, format are same */
10404a49301eSmrg            if (minWidth != maxWidth || minHeight != maxHeight) {
10414a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
1042af69d88dSmrg               fbo_incomplete(ctx, "width or height mismatch", -1);
10434a49301eSmrg               return;
10444a49301eSmrg            }
1045af69d88dSmrg            /* check that all color buffers are the same format */
10464a49301eSmrg            if (intFormat != GL_NONE && f != intFormat) {
10474a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
1048af69d88dSmrg               fbo_incomplete(ctx, "format mismatch", -1);
10494a49301eSmrg               return;
10504a49301eSmrg            }
10517117f1b4Smrg         }
1052af69d88dSmrg      }
1053af69d88dSmrg
1054af69d88dSmrg      /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported)
1055af69d88dSmrg       */
1056af69d88dSmrg      if (att->Type == GL_RENDERBUFFER &&
1057af69d88dSmrg          att->Renderbuffer->Format == MESA_FORMAT_NONE) {
1058af69d88dSmrg         fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
1059af69d88dSmrg         fbo_incomplete(ctx, "unsupported renderbuffer format", i);
1060af69d88dSmrg         return;
1061af69d88dSmrg      }
10624a49301eSmrg
1063af69d88dSmrg      /* Check that layered rendering is consistent. */
1064af69d88dSmrg      if (att->Layered) {
1065af69d88dSmrg         if (att_tex_target == GL_TEXTURE_CUBE_MAP)
1066af69d88dSmrg            att_layer_count = 6;
1067af69d88dSmrg         else if (att_tex_target == GL_TEXTURE_1D_ARRAY)
1068af69d88dSmrg            att_layer_count = att->Renderbuffer->Height;
1069af69d88dSmrg         else
1070af69d88dSmrg            att_layer_count = att->Renderbuffer->Depth;
1071af69d88dSmrg      } else {
1072af69d88dSmrg         att_layer_count = 0;
1073af69d88dSmrg      }
1074af69d88dSmrg      if (!layer_info_valid) {
1075af69d88dSmrg         is_layered = att->Layered;
1076af69d88dSmrg         max_layer_count = att_layer_count;
1077af69d88dSmrg         layer_tex_target = att_tex_target;
1078af69d88dSmrg         layer_info_valid = true;
1079af69d88dSmrg      } else if (max_layer_count > 0 && layer_tex_target != att_tex_target) {
1080af69d88dSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
1081af69d88dSmrg         fbo_incomplete(ctx, "layered framebuffer has mismatched targets", i);
1082af69d88dSmrg         return;
1083af69d88dSmrg      } else if (is_layered != att->Layered) {
1084af69d88dSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
1085af69d88dSmrg         fbo_incomplete(ctx,
1086af69d88dSmrg                        "framebuffer attachment layer mode is inconsistent",
1087af69d88dSmrg                        i);
1088af69d88dSmrg         return;
1089af69d88dSmrg      } else if (att_layer_count > max_layer_count) {
1090af69d88dSmrg         max_layer_count = att_layer_count;
10917117f1b4Smrg      }
10927117f1b4Smrg   }
10937117f1b4Smrg
1094af69d88dSmrg   fb->MaxNumLayers = max_layer_count;
1095af69d88dSmrg
1096af69d88dSmrg   if (numImages == 0) {
1097af69d88dSmrg      fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
1098af69d88dSmrg      fbo_incomplete(ctx, "no attachments", -1);
1099af69d88dSmrg      return;
1100af69d88dSmrg   }
1101af69d88dSmrg
1102af69d88dSmrg   if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) {
11033464ebd5Sriastradh      /* Check that all DrawBuffers are present */
11043464ebd5Sriastradh      for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
11053464ebd5Sriastradh	 if (fb->ColorDrawBuffer[j] != GL_NONE) {
11063464ebd5Sriastradh	    const struct gl_renderbuffer_attachment *att
1107af69d88dSmrg	       = get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
11083464ebd5Sriastradh	    assert(att);
11093464ebd5Sriastradh	    if (att->Type == GL_NONE) {
11103464ebd5Sriastradh	       fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
1111af69d88dSmrg	       fbo_incomplete(ctx, "missing drawbuffer", j);
11123464ebd5Sriastradh	       return;
11133464ebd5Sriastradh	    }
11143464ebd5Sriastradh	 }
11157117f1b4Smrg      }
11167117f1b4Smrg
11173464ebd5Sriastradh      /* Check that the ReadBuffer is present */
11183464ebd5Sriastradh      if (fb->ColorReadBuffer != GL_NONE) {
11193464ebd5Sriastradh	 const struct gl_renderbuffer_attachment *att
1120af69d88dSmrg	    = get_attachment(ctx, fb, fb->ColorReadBuffer);
11213464ebd5Sriastradh	 assert(att);
11223464ebd5Sriastradh	 if (att->Type == GL_NONE) {
11233464ebd5Sriastradh	    fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
1124af69d88dSmrg            fbo_incomplete(ctx, "missing readbuffer", -1);
11253464ebd5Sriastradh	    return;
11263464ebd5Sriastradh	 }
11277117f1b4Smrg      }
11287117f1b4Smrg   }
11297117f1b4Smrg
11304a49301eSmrg   /* Provisionally set status = COMPLETE ... */
11317117f1b4Smrg   fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
11324a49301eSmrg
11334a49301eSmrg   /* ... but the driver may say the FB is incomplete.
11344a49301eSmrg    * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
11354a49301eSmrg    * if anything.
11364a49301eSmrg    */
11374a49301eSmrg   if (ctx->Driver.ValidateFramebuffer) {
11384a49301eSmrg      ctx->Driver.ValidateFramebuffer(ctx, fb);
11394a49301eSmrg      if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1140af69d88dSmrg         fbo_incomplete(ctx, "driver marked FBO as incomplete", -1);
11414a49301eSmrg      }
11424a49301eSmrg   }
11434a49301eSmrg
11444a49301eSmrg   if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
11454a49301eSmrg      /*
11464a49301eSmrg       * Note that if ARB_framebuffer_object is supported and the attached
11474a49301eSmrg       * renderbuffers/textures are different sizes, the framebuffer
11484a49301eSmrg       * width/height will be set to the smallest width/height.
11494a49301eSmrg       */
11504a49301eSmrg      fb->Width = minWidth;
11514a49301eSmrg      fb->Height = minHeight;
11524a49301eSmrg
11534a49301eSmrg      /* finally, update the visual info for the framebuffer */
11543464ebd5Sriastradh      _mesa_update_framebuffer_visual(ctx, fb);
11554a49301eSmrg   }
11567117f1b4Smrg}
11577117f1b4Smrg
11587117f1b4Smrg
11597117f1b4SmrgGLboolean GLAPIENTRY
1160af69d88dSmrg_mesa_IsRenderbuffer(GLuint renderbuffer)
11617117f1b4Smrg{
11627117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
11637117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
11647117f1b4Smrg   if (renderbuffer) {
1165af69d88dSmrg      struct gl_renderbuffer *rb =
1166af69d88dSmrg         _mesa_lookup_renderbuffer(ctx, renderbuffer);
11677117f1b4Smrg      if (rb != NULL && rb != &DummyRenderbuffer)
11687117f1b4Smrg         return GL_TRUE;
11697117f1b4Smrg   }
11707117f1b4Smrg   return GL_FALSE;
11717117f1b4Smrg}
11727117f1b4Smrg
11737117f1b4Smrg
1174af69d88dSmrgstatic void
1175af69d88dSmrgbind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names)
11767117f1b4Smrg{
11777117f1b4Smrg   struct gl_renderbuffer *newRb;
11787117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
11797117f1b4Smrg
11807117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
11814a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
11827117f1b4Smrg      return;
11837117f1b4Smrg   }
11847117f1b4Smrg
11854a49301eSmrg   /* No need to flush here since the render buffer binding has no
11864a49301eSmrg    * effect on rendering state.
11877117f1b4Smrg    */
11887117f1b4Smrg
11897117f1b4Smrg   if (renderbuffer) {
11907117f1b4Smrg      newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
11917117f1b4Smrg      if (newRb == &DummyRenderbuffer) {
11927117f1b4Smrg         /* ID was reserved, but no real renderbuffer object made yet */
11937117f1b4Smrg         newRb = NULL;
11947117f1b4Smrg      }
1195af69d88dSmrg      else if (!newRb && !allow_user_names) {
11964a49301eSmrg         /* All RB IDs must be Gen'd */
11974a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
11984a49301eSmrg         return;
11994a49301eSmrg      }
12004a49301eSmrg
12017117f1b4Smrg      if (!newRb) {
12027117f1b4Smrg	 /* create new renderbuffer object */
12037117f1b4Smrg	 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
12047117f1b4Smrg	 if (!newRb) {
12057117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
12067117f1b4Smrg	    return;
12077117f1b4Smrg	 }
12087117f1b4Smrg         ASSERT(newRb->AllocStorage);
12097117f1b4Smrg         _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
12107117f1b4Smrg         newRb->RefCount = 1; /* referenced by hash table */
12117117f1b4Smrg      }
12127117f1b4Smrg   }
12137117f1b4Smrg   else {
12147117f1b4Smrg      newRb = NULL;
12157117f1b4Smrg   }
12167117f1b4Smrg
12177117f1b4Smrg   ASSERT(newRb != &DummyRenderbuffer);
12187117f1b4Smrg
12197117f1b4Smrg   _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
12207117f1b4Smrg}
12217117f1b4Smrg
1222af69d88dSmrgvoid GLAPIENTRY
1223af69d88dSmrg_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
1224af69d88dSmrg{
1225af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
1226af69d88dSmrg
1227af69d88dSmrg   /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same
1228af69d88dSmrg    * entry point, but they allow the use of user-generated names.
1229af69d88dSmrg    */
1230af69d88dSmrg   bind_renderbuffer(target, renderbuffer, _mesa_is_gles(ctx));
1231af69d88dSmrg}
1232af69d88dSmrg
1233af69d88dSmrgvoid GLAPIENTRY
1234af69d88dSmrg_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
1235af69d88dSmrg{
1236af69d88dSmrg   /* This function should not be in the dispatch table for core profile /
1237af69d88dSmrg    * OpenGL 3.1, so execution should never get here in those cases -- no
1238af69d88dSmrg    * need for an explicit test.
1239af69d88dSmrg    */
1240af69d88dSmrg   bind_renderbuffer(target, renderbuffer, true);
1241af69d88dSmrg}
1242af69d88dSmrg
12437117f1b4Smrg
12444a49301eSmrg/**
1245af69d88dSmrg * Remove the specified renderbuffer or texture from any attachment point in
1246af69d88dSmrg * the framebuffer.
1247af69d88dSmrg *
1248af69d88dSmrg * \returns
1249af69d88dSmrg * \c true if the renderbuffer was detached from an attachment point.  \c
1250af69d88dSmrg * false otherwise.
12514a49301eSmrg */
1252af69d88dSmrgbool
1253af69d88dSmrg_mesa_detach_renderbuffer(struct gl_context *ctx,
1254af69d88dSmrg                          struct gl_framebuffer *fb,
1255af69d88dSmrg                          const void *att)
12564a49301eSmrg{
1257af69d88dSmrg   unsigned i;
1258af69d88dSmrg   bool progress = false;
1259af69d88dSmrg
12604a49301eSmrg   for (i = 0; i < BUFFER_COUNT; i++) {
1261af69d88dSmrg      if (fb->Attachment[i].Texture == att
1262af69d88dSmrg          || fb->Attachment[i].Renderbuffer == att) {
1263af69d88dSmrg         remove_attachment(ctx, &fb->Attachment[i]);
1264af69d88dSmrg         progress = true;
12654a49301eSmrg      }
12664a49301eSmrg   }
1267af69d88dSmrg
1268af69d88dSmrg   /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer
1269af69d88dSmrg    * Completeness," of the OpenGL 3.1 spec says:
1270af69d88dSmrg    *
1271af69d88dSmrg    *     "Performing any of the following actions may change whether the
1272af69d88dSmrg    *     framebuffer is considered complete or incomplete:
1273af69d88dSmrg    *
1274af69d88dSmrg    *     ...
1275af69d88dSmrg    *
1276af69d88dSmrg    *        - Deleting, with DeleteTextures or DeleteRenderbuffers, an object
1277af69d88dSmrg    *          containing an image that is attached to a framebuffer object
1278af69d88dSmrg    *          that is bound to the framebuffer."
1279af69d88dSmrg    */
1280af69d88dSmrg   if (progress)
1281af69d88dSmrg      invalidate_framebuffer(fb);
1282af69d88dSmrg
1283af69d88dSmrg   return progress;
12844a49301eSmrg}
12854a49301eSmrg
12864a49301eSmrg
12877117f1b4Smrgvoid GLAPIENTRY
1288af69d88dSmrg_mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers)
12897117f1b4Smrg{
12907117f1b4Smrg   GLint i;
12917117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
12927117f1b4Smrg
12937117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
12947117f1b4Smrg
12957117f1b4Smrg   for (i = 0; i < n; i++) {
12967117f1b4Smrg      if (renderbuffers[i] > 0) {
12977117f1b4Smrg	 struct gl_renderbuffer *rb;
12987117f1b4Smrg	 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
12997117f1b4Smrg	 if (rb) {
13007117f1b4Smrg            /* check if deleting currently bound renderbuffer object */
13017117f1b4Smrg            if (rb == ctx->CurrentRenderbuffer) {
13027117f1b4Smrg               /* bind default */
13037117f1b4Smrg               ASSERT(rb->RefCount >= 2);
1304af69d88dSmrg               _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
13057117f1b4Smrg            }
13067117f1b4Smrg
1307af69d88dSmrg            /* Section 4.4.2 (Attaching Images to Framebuffer Objects),
1308af69d88dSmrg             * subsection "Attaching Renderbuffer Images to a Framebuffer,"
1309af69d88dSmrg             * of the OpenGL 3.1 spec says:
1310af69d88dSmrg             *
1311af69d88dSmrg             *     "If a renderbuffer object is deleted while its image is
1312af69d88dSmrg             *     attached to one or more attachment points in the currently
1313af69d88dSmrg             *     bound framebuffer, then it is as if FramebufferRenderbuffer
1314af69d88dSmrg             *     had been called, with a renderbuffer of 0, for each
1315af69d88dSmrg             *     attachment point to which this image was attached in the
1316af69d88dSmrg             *     currently bound framebuffer. In other words, this
1317af69d88dSmrg             *     renderbuffer image is first detached from all attachment
1318af69d88dSmrg             *     points in the currently bound framebuffer. Note that the
1319af69d88dSmrg             *     renderbuffer image is specifically not detached from any
1320af69d88dSmrg             *     non-bound framebuffers. Detaching the image from any
1321af69d88dSmrg             *     non-bound framebuffers is the responsibility of the
1322af69d88dSmrg             *     application.
1323af69d88dSmrg             */
1324af69d88dSmrg            if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
1325af69d88dSmrg               _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
13264a49301eSmrg            }
1327af69d88dSmrg            if (_mesa_is_user_fbo(ctx->ReadBuffer)
13283464ebd5Sriastradh                && ctx->ReadBuffer != ctx->DrawBuffer) {
1329af69d88dSmrg               _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
13304a49301eSmrg            }
13314a49301eSmrg
13327117f1b4Smrg	    /* Remove from hash table immediately, to free the ID.
13337117f1b4Smrg             * But the object will not be freed until it's no longer
13347117f1b4Smrg             * referenced anywhere else.
13357117f1b4Smrg             */
13367117f1b4Smrg	    _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
13377117f1b4Smrg
13387117f1b4Smrg            if (rb != &DummyRenderbuffer) {
13397117f1b4Smrg               /* no longer referenced by hash table */
13407117f1b4Smrg               _mesa_reference_renderbuffer(&rb, NULL);
13417117f1b4Smrg	    }
13427117f1b4Smrg	 }
13437117f1b4Smrg      }
13447117f1b4Smrg   }
13457117f1b4Smrg}
13467117f1b4Smrg
13477117f1b4Smrg
13487117f1b4Smrgvoid GLAPIENTRY
1349af69d88dSmrg_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers)
13507117f1b4Smrg{
13517117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
13527117f1b4Smrg   GLuint first;
13537117f1b4Smrg   GLint i;
13547117f1b4Smrg
13557117f1b4Smrg   if (n < 0) {
13567117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
13577117f1b4Smrg      return;
13587117f1b4Smrg   }
13597117f1b4Smrg
13607117f1b4Smrg   if (!renderbuffers)
13617117f1b4Smrg      return;
13627117f1b4Smrg
13637117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
13647117f1b4Smrg
13657117f1b4Smrg   for (i = 0; i < n; i++) {
13667117f1b4Smrg      GLuint name = first + i;
13677117f1b4Smrg      renderbuffers[i] = name;
13687117f1b4Smrg      /* insert dummy placeholder into hash table */
1369af69d88dSmrg      mtx_lock(&ctx->Shared->Mutex);
13707117f1b4Smrg      _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
1371af69d88dSmrg      mtx_unlock(&ctx->Shared->Mutex);
13727117f1b4Smrg   }
13737117f1b4Smrg}
13747117f1b4Smrg
13757117f1b4Smrg
13767117f1b4Smrg/**
13777117f1b4Smrg * Given an internal format token for a render buffer, return the
13783464ebd5Sriastradh * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
13793464ebd5Sriastradh * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE,
13803464ebd5Sriastradh * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc).
13817117f1b4Smrg *
13823464ebd5Sriastradh * This is similar to _mesa_base_tex_format() but the set of valid
13833464ebd5Sriastradh * internal formats is different.
1384cdc920a0Smrg *
13853464ebd5Sriastradh * Note that even if a format is determined to be legal here, validation
13863464ebd5Sriastradh * of the FBO may fail if the format is not supported by the driver/GPU.
13873464ebd5Sriastradh *
13883464ebd5Sriastradh * \param internalFormat  as passed to glRenderbufferStorage()
13893464ebd5Sriastradh * \return the base internal format, or 0 if internalFormat is illegal
13907117f1b4Smrg */
13917117f1b4SmrgGLenum
13923464ebd5Sriastradh_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
13937117f1b4Smrg{
13943464ebd5Sriastradh   /*
13953464ebd5Sriastradh    * Notes: some formats such as alpha, luminance, etc. were added
13963464ebd5Sriastradh    * with GL_ARB_framebuffer_object.
13973464ebd5Sriastradh    */
13987117f1b4Smrg   switch (internalFormat) {
13993464ebd5Sriastradh   case GL_ALPHA:
14003464ebd5Sriastradh   case GL_ALPHA4:
14013464ebd5Sriastradh   case GL_ALPHA8:
14023464ebd5Sriastradh   case GL_ALPHA12:
14033464ebd5Sriastradh   case GL_ALPHA16:
1404af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
1405af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_ALPHA : 0;
14063464ebd5Sriastradh   case GL_LUMINANCE:
14073464ebd5Sriastradh   case GL_LUMINANCE4:
14083464ebd5Sriastradh   case GL_LUMINANCE8:
14093464ebd5Sriastradh   case GL_LUMINANCE12:
14103464ebd5Sriastradh   case GL_LUMINANCE16:
1411af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
1412af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE : 0;
14133464ebd5Sriastradh   case GL_LUMINANCE_ALPHA:
14143464ebd5Sriastradh   case GL_LUMINANCE4_ALPHA4:
14153464ebd5Sriastradh   case GL_LUMINANCE6_ALPHA2:
14163464ebd5Sriastradh   case GL_LUMINANCE8_ALPHA8:
14173464ebd5Sriastradh   case GL_LUMINANCE12_ALPHA4:
14183464ebd5Sriastradh   case GL_LUMINANCE12_ALPHA12:
14193464ebd5Sriastradh   case GL_LUMINANCE16_ALPHA16:
1420af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
1421af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE_ALPHA : 0;
14223464ebd5Sriastradh   case GL_INTENSITY:
14233464ebd5Sriastradh   case GL_INTENSITY4:
14243464ebd5Sriastradh   case GL_INTENSITY8:
14253464ebd5Sriastradh   case GL_INTENSITY12:
14263464ebd5Sriastradh   case GL_INTENSITY16:
1427af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
1428af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_INTENSITY : 0;
1429af69d88dSmrg   case GL_RGB8:
1430af69d88dSmrg      return GL_RGB;
14317117f1b4Smrg   case GL_RGB:
14327117f1b4Smrg   case GL_R3_G3_B2:
14337117f1b4Smrg   case GL_RGB4:
14347117f1b4Smrg   case GL_RGB5:
14357117f1b4Smrg   case GL_RGB10:
14367117f1b4Smrg   case GL_RGB12:
14377117f1b4Smrg   case GL_RGB16:
1438af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0;
14393464ebd5Sriastradh   case GL_SRGB8_EXT:
1440af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0;
14417117f1b4Smrg   case GL_RGBA4:
14427117f1b4Smrg   case GL_RGB5_A1:
14437117f1b4Smrg   case GL_RGBA8:
1444af69d88dSmrg      return GL_RGBA;
1445af69d88dSmrg   case GL_RGBA:
1446af69d88dSmrg   case GL_RGBA2:
14477117f1b4Smrg   case GL_RGBA12:
14487117f1b4Smrg   case GL_RGBA16:
1449af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0;
1450af69d88dSmrg   case GL_RGB10_A2:
14513464ebd5Sriastradh   case GL_SRGB8_ALPHA8_EXT:
1452af69d88dSmrg      return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0;
14537117f1b4Smrg   case GL_STENCIL_INDEX:
14547117f1b4Smrg   case GL_STENCIL_INDEX1_EXT:
14557117f1b4Smrg   case GL_STENCIL_INDEX4_EXT:
14567117f1b4Smrg   case GL_STENCIL_INDEX16_EXT:
1457af69d88dSmrg      /* There are extensions for GL_STENCIL_INDEX1 and GL_STENCIL_INDEX4 in
1458af69d88dSmrg       * OpenGL ES, but Mesa does not currently support them.
1459af69d88dSmrg       */
1460af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_STENCIL_INDEX : 0;
1461af69d88dSmrg   case GL_STENCIL_INDEX8_EXT:
14627117f1b4Smrg      return GL_STENCIL_INDEX;
14637117f1b4Smrg   case GL_DEPTH_COMPONENT:
1464af69d88dSmrg   case GL_DEPTH_COMPONENT32:
1465af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_COMPONENT : 0;
14667117f1b4Smrg   case GL_DEPTH_COMPONENT16:
14677117f1b4Smrg   case GL_DEPTH_COMPONENT24:
14687117f1b4Smrg      return GL_DEPTH_COMPONENT;
1469af69d88dSmrg   case GL_DEPTH_STENCIL:
1470af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_STENCIL : 0;
1471af69d88dSmrg   case GL_DEPTH24_STENCIL8:
1472af69d88dSmrg      return GL_DEPTH_STENCIL;
1473af69d88dSmrg   case GL_DEPTH_COMPONENT32F:
1474af69d88dSmrg      return ctx->Version >= 30
1475af69d88dSmrg         || (ctx->API == API_OPENGL_COMPAT &&
1476af69d88dSmrg             ctx->Extensions.ARB_depth_buffer_float)
1477af69d88dSmrg         ? GL_DEPTH_COMPONENT : 0;
1478af69d88dSmrg   case GL_DEPTH32F_STENCIL8:
1479af69d88dSmrg      return ctx->Version >= 30
1480af69d88dSmrg         || (ctx->API == API_OPENGL_COMPAT &&
1481af69d88dSmrg             ctx->Extensions.ARB_depth_buffer_float)
1482af69d88dSmrg         ? GL_DEPTH_STENCIL : 0;
14833464ebd5Sriastradh   case GL_RED:
14843464ebd5Sriastradh   case GL_R16:
1485af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg
1486af69d88dSmrg         ? GL_RED : 0;
1487af69d88dSmrg   case GL_R8:
1488af69d88dSmrg      return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
1489af69d88dSmrg         ? GL_RED : 0;
14903464ebd5Sriastradh   case GL_RG:
14913464ebd5Sriastradh   case GL_RG16:
1492af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg
1493af69d88dSmrg         ? GL_RG : 0;
1494af69d88dSmrg   case GL_RG8:
1495af69d88dSmrg      return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
1496af69d88dSmrg         ? GL_RG : 0;
14973464ebd5Sriastradh   /* signed normalized texture formats */
14983464ebd5Sriastradh   case GL_RED_SNORM:
14993464ebd5Sriastradh   case GL_R8_SNORM:
15003464ebd5Sriastradh   case GL_R16_SNORM:
1501af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1502af69d88dSmrg         ? GL_RED : 0;
15033464ebd5Sriastradh   case GL_RG_SNORM:
15043464ebd5Sriastradh   case GL_RG8_SNORM:
15053464ebd5Sriastradh   case GL_RG16_SNORM:
1506af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1507af69d88dSmrg         ? GL_RG : 0;
15083464ebd5Sriastradh   case GL_RGB_SNORM:
15093464ebd5Sriastradh   case GL_RGB8_SNORM:
15103464ebd5Sriastradh   case GL_RGB16_SNORM:
1511af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1512af69d88dSmrg         ? GL_RGB : 0;
15133464ebd5Sriastradh   case GL_RGBA_SNORM:
15143464ebd5Sriastradh   case GL_RGBA8_SNORM:
15153464ebd5Sriastradh   case GL_RGBA16_SNORM:
1516af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1517af69d88dSmrg         ? GL_RGBA : 0;
15183464ebd5Sriastradh   case GL_ALPHA_SNORM:
15193464ebd5Sriastradh   case GL_ALPHA8_SNORM:
15203464ebd5Sriastradh   case GL_ALPHA16_SNORM:
1521af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
1522af69d88dSmrg             ctx->Extensions.EXT_texture_snorm &&
15233464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
15243464ebd5Sriastradh   case GL_LUMINANCE_SNORM:
15253464ebd5Sriastradh   case GL_LUMINANCE8_SNORM:
15263464ebd5Sriastradh   case GL_LUMINANCE16_SNORM:
1527af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1528af69d88dSmrg         ? GL_LUMINANCE : 0;
15293464ebd5Sriastradh   case GL_LUMINANCE_ALPHA_SNORM:
15303464ebd5Sriastradh   case GL_LUMINANCE8_ALPHA8_SNORM:
15313464ebd5Sriastradh   case GL_LUMINANCE16_ALPHA16_SNORM:
1532af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1533af69d88dSmrg         ? GL_LUMINANCE_ALPHA : 0;
15343464ebd5Sriastradh   case GL_INTENSITY_SNORM:
15353464ebd5Sriastradh   case GL_INTENSITY8_SNORM:
15363464ebd5Sriastradh   case GL_INTENSITY16_SNORM:
1537af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1538af69d88dSmrg         ? GL_INTENSITY : 0;
1539af69d88dSmrg
15403464ebd5Sriastradh   case GL_R16F:
15413464ebd5Sriastradh   case GL_R32F:
1542af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) &&
1543af69d88dSmrg               ctx->Extensions.ARB_texture_rg &&
1544af69d88dSmrg               ctx->Extensions.ARB_texture_float) ||
1545af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
1546af69d88dSmrg         ? GL_RED : 0;
15473464ebd5Sriastradh   case GL_RG16F:
15483464ebd5Sriastradh   case GL_RG32F:
1549af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) &&
1550af69d88dSmrg               ctx->Extensions.ARB_texture_rg &&
1551af69d88dSmrg               ctx->Extensions.ARB_texture_float) ||
1552af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
1553af69d88dSmrg         ? GL_RG : 0;
15543464ebd5Sriastradh   case GL_RGB16F:
15553464ebd5Sriastradh   case GL_RGB32F:
1556af69d88dSmrg      return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float)
1557af69d88dSmrg         ? GL_RGB : 0;
15583464ebd5Sriastradh   case GL_RGBA16F:
15593464ebd5Sriastradh   case GL_RGBA32F:
1560af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) &&
1561af69d88dSmrg               ctx->Extensions.ARB_texture_float) ||
1562af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
1563af69d88dSmrg         ? GL_RGBA : 0;
15643464ebd5Sriastradh   case GL_ALPHA16F_ARB:
15653464ebd5Sriastradh   case GL_ALPHA32F_ARB:
1566af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
1567af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
15683464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
15693464ebd5Sriastradh   case GL_LUMINANCE16F_ARB:
15703464ebd5Sriastradh   case GL_LUMINANCE32F_ARB:
1571af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
1572af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
15733464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
15743464ebd5Sriastradh   case GL_LUMINANCE_ALPHA16F_ARB:
15753464ebd5Sriastradh   case GL_LUMINANCE_ALPHA32F_ARB:
1576af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
1577af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
15783464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
15793464ebd5Sriastradh   case GL_INTENSITY16F_ARB:
15803464ebd5Sriastradh   case GL_INTENSITY32F_ARB:
1581af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
1582af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
15833464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
15843464ebd5Sriastradh   case GL_R11F_G11F_B10F:
1585af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) ||
1586af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
1587af69d88dSmrg         ? GL_RGB : 0;
1588af69d88dSmrg
1589af69d88dSmrg   case GL_RGBA8UI_EXT:
1590af69d88dSmrg   case GL_RGBA16UI_EXT:
1591af69d88dSmrg   case GL_RGBA32UI_EXT:
1592af69d88dSmrg   case GL_RGBA8I_EXT:
1593af69d88dSmrg   case GL_RGBA16I_EXT:
1594af69d88dSmrg   case GL_RGBA32I_EXT:
1595af69d88dSmrg      return ctx->Version >= 30
1596af69d88dSmrg         || (_mesa_is_desktop_gl(ctx) &&
1597af69d88dSmrg             ctx->Extensions.EXT_texture_integer) ? GL_RGBA : 0;
1598af69d88dSmrg
1599af69d88dSmrg   case GL_RGB8UI_EXT:
1600af69d88dSmrg   case GL_RGB16UI_EXT:
1601af69d88dSmrg   case GL_RGB32UI_EXT:
1602af69d88dSmrg   case GL_RGB8I_EXT:
1603af69d88dSmrg   case GL_RGB16I_EXT:
1604af69d88dSmrg   case GL_RGB32I_EXT:
1605af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_integer
1606af69d88dSmrg         ? GL_RGB : 0;
1607af69d88dSmrg   case GL_R8UI:
1608af69d88dSmrg   case GL_R8I:
1609af69d88dSmrg   case GL_R16UI:
1610af69d88dSmrg   case GL_R16I:
1611af69d88dSmrg   case GL_R32UI:
1612af69d88dSmrg   case GL_R32I:
1613af69d88dSmrg      return ctx->Version >= 30
1614af69d88dSmrg         || (_mesa_is_desktop_gl(ctx) &&
1615af69d88dSmrg             ctx->Extensions.ARB_texture_rg &&
1616af69d88dSmrg             ctx->Extensions.EXT_texture_integer) ? GL_RED : 0;
1617af69d88dSmrg
1618af69d88dSmrg   case GL_RG8UI:
1619af69d88dSmrg   case GL_RG8I:
1620af69d88dSmrg   case GL_RG16UI:
1621af69d88dSmrg   case GL_RG16I:
1622af69d88dSmrg   case GL_RG32UI:
1623af69d88dSmrg   case GL_RG32I:
1624af69d88dSmrg      return ctx->Version >= 30
1625af69d88dSmrg         || (_mesa_is_desktop_gl(ctx) &&
1626af69d88dSmrg             ctx->Extensions.ARB_texture_rg &&
1627af69d88dSmrg             ctx->Extensions.EXT_texture_integer) ? GL_RG : 0;
1628af69d88dSmrg
1629af69d88dSmrg   case GL_INTENSITY8I_EXT:
1630af69d88dSmrg   case GL_INTENSITY8UI_EXT:
1631af69d88dSmrg   case GL_INTENSITY16I_EXT:
1632af69d88dSmrg   case GL_INTENSITY16UI_EXT:
1633af69d88dSmrg   case GL_INTENSITY32I_EXT:
1634af69d88dSmrg   case GL_INTENSITY32UI_EXT:
1635af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
1636af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
1637af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
1638af69d88dSmrg
1639af69d88dSmrg   case GL_LUMINANCE8I_EXT:
1640af69d88dSmrg   case GL_LUMINANCE8UI_EXT:
1641af69d88dSmrg   case GL_LUMINANCE16I_EXT:
1642af69d88dSmrg   case GL_LUMINANCE16UI_EXT:
1643af69d88dSmrg   case GL_LUMINANCE32I_EXT:
1644af69d88dSmrg   case GL_LUMINANCE32UI_EXT:
1645af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
1646af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
1647af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1648af69d88dSmrg
1649af69d88dSmrg   case GL_LUMINANCE_ALPHA8I_EXT:
1650af69d88dSmrg   case GL_LUMINANCE_ALPHA8UI_EXT:
1651af69d88dSmrg   case GL_LUMINANCE_ALPHA16I_EXT:
1652af69d88dSmrg   case GL_LUMINANCE_ALPHA16UI_EXT:
1653af69d88dSmrg   case GL_LUMINANCE_ALPHA32I_EXT:
1654af69d88dSmrg   case GL_LUMINANCE_ALPHA32UI_EXT:
1655af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
1656af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
1657af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
1658af69d88dSmrg
1659af69d88dSmrg   case GL_ALPHA8I_EXT:
1660af69d88dSmrg   case GL_ALPHA8UI_EXT:
1661af69d88dSmrg   case GL_ALPHA16I_EXT:
1662af69d88dSmrg   case GL_ALPHA16UI_EXT:
1663af69d88dSmrg   case GL_ALPHA32I_EXT:
1664af69d88dSmrg   case GL_ALPHA32UI_EXT:
1665af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
1666af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
1667af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1668af69d88dSmrg
1669af69d88dSmrg   case GL_RGB10_A2UI:
1670af69d88dSmrg      return (_mesa_is_desktop_gl(ctx) &&
1671af69d88dSmrg              ctx->Extensions.ARB_texture_rgb10_a2ui)
1672af69d88dSmrg         || _mesa_is_gles3(ctx) ? GL_RGBA : 0;
1673af69d88dSmrg
1674af69d88dSmrg   case GL_RGB565:
1675af69d88dSmrg      return _mesa_is_gles(ctx) || ctx->Extensions.ARB_ES2_compatibility
1676af69d88dSmrg         ? GL_RGB : 0;
1677af69d88dSmrg   default:
1678af69d88dSmrg      return 0;
1679af69d88dSmrg   }
16807117f1b4Smrg}
16817117f1b4Smrg
16827117f1b4Smrg
16833464ebd5Sriastradh/**
16843464ebd5Sriastradh * Invalidate a renderbuffer attachment.  Called from _mesa_HashWalk().
16853464ebd5Sriastradh */
16863464ebd5Sriastradhstatic void
16873464ebd5Sriastradhinvalidate_rb(GLuint key, void *data, void *userData)
16883464ebd5Sriastradh{
16893464ebd5Sriastradh   struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
16903464ebd5Sriastradh   struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData;
16913464ebd5Sriastradh
16923464ebd5Sriastradh   /* If this is a user-created FBO */
1693af69d88dSmrg   if (_mesa_is_user_fbo(fb)) {
16943464ebd5Sriastradh      GLuint i;
16953464ebd5Sriastradh      for (i = 0; i < BUFFER_COUNT; i++) {
16963464ebd5Sriastradh         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
16973464ebd5Sriastradh         if (att->Type == GL_RENDERBUFFER &&
16983464ebd5Sriastradh             att->Renderbuffer == rb) {
16993464ebd5Sriastradh            /* Mark fb status as indeterminate to force re-validation */
17003464ebd5Sriastradh            fb->_Status = 0;
17013464ebd5Sriastradh            return;
17023464ebd5Sriastradh         }
17033464ebd5Sriastradh      }
17043464ebd5Sriastradh   }
17053464ebd5Sriastradh}
17063464ebd5Sriastradh
17073464ebd5Sriastradh
17084a49301eSmrg/** sentinal value, see below */
17094a49301eSmrg#define NO_SAMPLES 1000
17104a49301eSmrg
17114a49301eSmrg
17124a49301eSmrg/**
1713af69d88dSmrg * Helper function used by _mesa_RenderbufferStorage() and
17144a49301eSmrg * _mesa_RenderbufferStorageMultisample().
1715af69d88dSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorage().
17164a49301eSmrg */
17174a49301eSmrgstatic void
17184a49301eSmrgrenderbuffer_storage(GLenum target, GLenum internalFormat,
17194a49301eSmrg                     GLsizei width, GLsizei height, GLsizei samples)
17207117f1b4Smrg{
17214a49301eSmrg   const char *func = samples == NO_SAMPLES ?
1722af69d88dSmrg      "glRenderbufferStorage" : "glRenderbufferStorageMultisample";
17237117f1b4Smrg   struct gl_renderbuffer *rb;
17247117f1b4Smrg   GLenum baseFormat;
1725af69d88dSmrg   GLenum sample_count_error;
17267117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
17277117f1b4Smrg
1728af69d88dSmrg   if (MESA_VERBOSE & VERBOSE_API) {
1729af69d88dSmrg      if (samples == NO_SAMPLES)
1730af69d88dSmrg         _mesa_debug(ctx, "%s(%s, %s, %d, %d)\n",
1731af69d88dSmrg                     func,
1732af69d88dSmrg                     _mesa_lookup_enum_by_nr(target),
1733af69d88dSmrg                     _mesa_lookup_enum_by_nr(internalFormat),
1734af69d88dSmrg                     width, height);
1735af69d88dSmrg      else
1736af69d88dSmrg         _mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n",
1737af69d88dSmrg                     func,
1738af69d88dSmrg                     _mesa_lookup_enum_by_nr(target),
1739af69d88dSmrg                     _mesa_lookup_enum_by_nr(internalFormat),
1740af69d88dSmrg                     width, height, samples);
1741af69d88dSmrg   }
17427117f1b4Smrg
17437117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
17444a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
17457117f1b4Smrg      return;
17467117f1b4Smrg   }
17477117f1b4Smrg
17487117f1b4Smrg   baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
17497117f1b4Smrg   if (baseFormat == 0) {
1750af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)",
1751af69d88dSmrg                  func, _mesa_lookup_enum_by_nr(internalFormat));
17527117f1b4Smrg      return;
17537117f1b4Smrg   }
17547117f1b4Smrg
1755af69d88dSmrg   if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
17564a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
17577117f1b4Smrg      return;
17587117f1b4Smrg   }
17597117f1b4Smrg
1760af69d88dSmrg   if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
17614a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
17627117f1b4Smrg      return;
17637117f1b4Smrg   }
17647117f1b4Smrg
17654a49301eSmrg   if (samples == NO_SAMPLES) {
17664a49301eSmrg      /* NumSamples == 0 indicates non-multisampling */
17674a49301eSmrg      samples = 0;
17684a49301eSmrg   }
1769af69d88dSmrg   else {
1770af69d88dSmrg      /* check the sample count;
1771af69d88dSmrg       * note: driver may choose to use more samples than what's requested
1772af69d88dSmrg       */
1773af69d88dSmrg      sample_count_error = _mesa_check_sample_count(ctx, target,
1774af69d88dSmrg            internalFormat, samples);
1775af69d88dSmrg      if (sample_count_error != GL_NO_ERROR) {
1776af69d88dSmrg         _mesa_error(ctx, sample_count_error, "%s(samples)", func);
1777af69d88dSmrg         return;
1778af69d88dSmrg      }
17794a49301eSmrg   }
17807117f1b4Smrg
17814a49301eSmrg   rb = ctx->CurrentRenderbuffer;
17827117f1b4Smrg   if (!rb) {
17833464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
17847117f1b4Smrg      return;
17857117f1b4Smrg   }
17867117f1b4Smrg
17877117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
17887117f1b4Smrg
17897117f1b4Smrg   if (rb->InternalFormat == internalFormat &&
17907117f1b4Smrg       rb->Width == (GLuint) width &&
1791af69d88dSmrg       rb->Height == (GLuint) height &&
1792af69d88dSmrg       rb->NumSamples == samples) {
17937117f1b4Smrg      /* no change in allocation needed */
17947117f1b4Smrg      return;
17957117f1b4Smrg   }
17967117f1b4Smrg
17977117f1b4Smrg   /* These MUST get set by the AllocStorage func */
17984a49301eSmrg   rb->Format = MESA_FORMAT_NONE;
17994a49301eSmrg   rb->NumSamples = samples;
18007117f1b4Smrg
18017117f1b4Smrg   /* Now allocate the storage */
18027117f1b4Smrg   ASSERT(rb->AllocStorage);
18037117f1b4Smrg   if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
18047117f1b4Smrg      /* No error - check/set fields now */
1805af69d88dSmrg      /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */
18067117f1b4Smrg      assert(rb->Width == (GLuint) width);
18077117f1b4Smrg      assert(rb->Height == (GLuint) height);
18087117f1b4Smrg      rb->InternalFormat = internalFormat;
1809cdc920a0Smrg      rb->_BaseFormat = baseFormat;
18104a49301eSmrg      assert(rb->_BaseFormat != 0);
18117117f1b4Smrg   }
18127117f1b4Smrg   else {
18137117f1b4Smrg      /* Probably ran out of memory - clear the fields */
18147117f1b4Smrg      rb->Width = 0;
18157117f1b4Smrg      rb->Height = 0;
18164a49301eSmrg      rb->Format = MESA_FORMAT_NONE;
18177117f1b4Smrg      rb->InternalFormat = GL_NONE;
18187117f1b4Smrg      rb->_BaseFormat = GL_NONE;
18194a49301eSmrg      rb->NumSamples = 0;
18207117f1b4Smrg   }
18217117f1b4Smrg
18223464ebd5Sriastradh   /* Invalidate the framebuffers the renderbuffer is attached in. */
18233464ebd5Sriastradh   if (rb->AttachedAnytime) {
18243464ebd5Sriastradh      _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb);
18253464ebd5Sriastradh   }
18267117f1b4Smrg}
18277117f1b4Smrg
18283464ebd5Sriastradh
1829cdc920a0Smrgvoid GLAPIENTRY
18303464ebd5Sriastradh_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1831cdc920a0Smrg{
1832cdc920a0Smrg   struct gl_renderbuffer *rb;
1833cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
1834cdc920a0Smrg
18353464ebd5Sriastradh   if (!ctx->Extensions.OES_EGL_image) {
18363464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
18373464ebd5Sriastradh                  "glEGLImageTargetRenderbufferStorageOES(unsupported)");
18383464ebd5Sriastradh      return;
18393464ebd5Sriastradh   }
18403464ebd5Sriastradh
1841cdc920a0Smrg   if (target != GL_RENDERBUFFER) {
18423464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_ENUM,
18433464ebd5Sriastradh                  "EGLImageTargetRenderbufferStorageOES");
1844cdc920a0Smrg      return;
1845cdc920a0Smrg   }
1846cdc920a0Smrg
1847cdc920a0Smrg   rb = ctx->CurrentRenderbuffer;
1848cdc920a0Smrg   if (!rb) {
18493464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
18503464ebd5Sriastradh                  "EGLImageTargetRenderbufferStorageOES");
1851cdc920a0Smrg      return;
1852cdc920a0Smrg   }
1853cdc920a0Smrg
1854cdc920a0Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1855cdc920a0Smrg
1856cdc920a0Smrg   ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1857cdc920a0Smrg}
18587117f1b4Smrg
18593464ebd5Sriastradh
18604a49301eSmrg/**
1861af69d88dSmrg * Helper function for _mesa_GetRenderbufferParameteriv() and
1862af69d88dSmrg * _mesa_GetFramebufferAttachmentParameteriv()
18634a49301eSmrg * We have to be careful to respect the base format.  For example, if a
18644a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the
18654a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
18664a49301eSmrg * we need to return zero.
18674a49301eSmrg */
18684a49301eSmrgstatic GLint
1869af69d88dSmrgget_component_bits(GLenum pname, GLenum baseFormat, mesa_format format)
18704a49301eSmrg{
1871af69d88dSmrg   if (_mesa_base_format_has_channel(baseFormat, pname))
1872af69d88dSmrg      return _mesa_get_format_bits(format, pname);
1873af69d88dSmrg   else
18744a49301eSmrg      return 0;
18754a49301eSmrg}
18764a49301eSmrg
18774a49301eSmrg
18784a49301eSmrg
18794a49301eSmrgvoid GLAPIENTRY
1880af69d88dSmrg_mesa_RenderbufferStorage(GLenum target, GLenum internalFormat,
18814a49301eSmrg                             GLsizei width, GLsizei height)
18824a49301eSmrg{
18834a49301eSmrg   /* GL_ARB_fbo says calling this function is equivalent to calling
18844a49301eSmrg    * glRenderbufferStorageMultisample() with samples=0.  We pass in
18854a49301eSmrg    * a token value here just for error reporting purposes.
18864a49301eSmrg    */
18874a49301eSmrg   renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
18884a49301eSmrg}
18894a49301eSmrg
18904a49301eSmrg
18914a49301eSmrgvoid GLAPIENTRY
18924a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
18934a49301eSmrg                                     GLenum internalFormat,
18944a49301eSmrg                                     GLsizei width, GLsizei height)
18954a49301eSmrg{
18964a49301eSmrg   renderbuffer_storage(target, internalFormat, width, height, samples);
18974a49301eSmrg}
18984a49301eSmrg
18994a49301eSmrg
19003464ebd5Sriastradh/**
19013464ebd5Sriastradh * OpenGL ES version of glRenderBufferStorage.
19023464ebd5Sriastradh */
19033464ebd5Sriastradhvoid GLAPIENTRY
19043464ebd5Sriastradh_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
19053464ebd5Sriastradh			   GLsizei width, GLsizei height)
19063464ebd5Sriastradh{
19073464ebd5Sriastradh   switch (internalFormat) {
19083464ebd5Sriastradh   case GL_RGB565:
19093464ebd5Sriastradh      /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
19103464ebd5Sriastradh      /* choose a closest format */
19113464ebd5Sriastradh      internalFormat = GL_RGB5;
19123464ebd5Sriastradh      break;
19133464ebd5Sriastradh   default:
19143464ebd5Sriastradh      break;
19153464ebd5Sriastradh   }
19163464ebd5Sriastradh
19173464ebd5Sriastradh   renderbuffer_storage(target, internalFormat, width, height, 0);
19183464ebd5Sriastradh}
19193464ebd5Sriastradh
19204a49301eSmrg
19217117f1b4Smrgvoid GLAPIENTRY
1922af69d88dSmrg_mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params)
19237117f1b4Smrg{
19244a49301eSmrg   struct gl_renderbuffer *rb;
19257117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
19267117f1b4Smrg
19277117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
19287117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
19297117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
19307117f1b4Smrg      return;
19317117f1b4Smrg   }
19327117f1b4Smrg
19334a49301eSmrg   rb = ctx->CurrentRenderbuffer;
19344a49301eSmrg   if (!rb) {
19357117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
19367117f1b4Smrg                  "glGetRenderbufferParameterivEXT");
19377117f1b4Smrg      return;
19387117f1b4Smrg   }
19397117f1b4Smrg
19404a49301eSmrg   /* No need to flush here since we're just quering state which is
19414a49301eSmrg    * not effected by rendering.
19424a49301eSmrg    */
19437117f1b4Smrg
19447117f1b4Smrg   switch (pname) {
19457117f1b4Smrg   case GL_RENDERBUFFER_WIDTH_EXT:
19464a49301eSmrg      *params = rb->Width;
19477117f1b4Smrg      return;
19487117f1b4Smrg   case GL_RENDERBUFFER_HEIGHT_EXT:
19494a49301eSmrg      *params = rb->Height;
19507117f1b4Smrg      return;
19517117f1b4Smrg   case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
19524a49301eSmrg      *params = rb->InternalFormat;
19537117f1b4Smrg      return;
19547117f1b4Smrg   case GL_RENDERBUFFER_RED_SIZE_EXT:
19557117f1b4Smrg   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
19567117f1b4Smrg   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
19577117f1b4Smrg   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
19587117f1b4Smrg   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
19597117f1b4Smrg   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
19604a49301eSmrg      *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
19617117f1b4Smrg      break;
19624a49301eSmrg   case GL_RENDERBUFFER_SAMPLES:
1963af69d88dSmrg      if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object)
1964af69d88dSmrg          || _mesa_is_gles3(ctx)) {
19654a49301eSmrg         *params = rb->NumSamples;
19664a49301eSmrg         break;
19674a49301eSmrg      }
19684a49301eSmrg      /* fallthrough */
19697117f1b4Smrg   default:
19707117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
19717117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
19727117f1b4Smrg      return;
19737117f1b4Smrg   }
19747117f1b4Smrg}
19757117f1b4Smrg
19767117f1b4Smrg
19777117f1b4SmrgGLboolean GLAPIENTRY
1978af69d88dSmrg_mesa_IsFramebuffer(GLuint framebuffer)
19797117f1b4Smrg{
19807117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
19817117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
19827117f1b4Smrg   if (framebuffer) {
19837117f1b4Smrg      struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
19847117f1b4Smrg      if (rb != NULL && rb != &DummyFramebuffer)
19857117f1b4Smrg         return GL_TRUE;
19867117f1b4Smrg   }
19877117f1b4Smrg   return GL_FALSE;
19887117f1b4Smrg}
19897117f1b4Smrg
19907117f1b4Smrg
19914a49301eSmrg/**
19924a49301eSmrg * Check if any of the attachments of the given framebuffer are textures
19934a49301eSmrg * (render to texture).  Call ctx->Driver.RenderTexture() for such
19944a49301eSmrg * attachments.
19954a49301eSmrg */
19967117f1b4Smrgstatic void
19973464ebd5Sriastradhcheck_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
19987117f1b4Smrg{
19997117f1b4Smrg   GLuint i;
20007117f1b4Smrg   ASSERT(ctx->Driver.RenderTexture);
20014a49301eSmrg
2002af69d88dSmrg   if (_mesa_is_winsys_fbo(fb))
20034a49301eSmrg      return; /* can't render to texture with winsys framebuffers */
20044a49301eSmrg
20057117f1b4Smrg   for (i = 0; i < BUFFER_COUNT; i++) {
20067117f1b4Smrg      struct gl_renderbuffer_attachment *att = fb->Attachment + i;
2007af69d88dSmrg      if (att->Texture && att->Renderbuffer->TexImage
2008af69d88dSmrg          && driver_RenderTexture_is_safe(att)) {
20097117f1b4Smrg         ctx->Driver.RenderTexture(ctx, fb, att);
20107117f1b4Smrg      }
20117117f1b4Smrg   }
20127117f1b4Smrg}
20137117f1b4Smrg
20147117f1b4Smrg
20157117f1b4Smrg/**
20167117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures.
20177117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to
20187117f1b4Smrg * notify the device driver that the texture image may have changed.
20197117f1b4Smrg */
20207117f1b4Smrgstatic void
20213464ebd5Sriastradhcheck_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
20227117f1b4Smrg{
2023af69d88dSmrg   /* Skip if we know NeedsFinishRenderTexture won't be set. */
2024af69d88dSmrg   if (_mesa_is_winsys_fbo(fb) && !ctx->Driver.BindRenderbufferTexImage)
2025af69d88dSmrg      return;
20264a49301eSmrg
20277117f1b4Smrg   if (ctx->Driver.FinishRenderTexture) {
20287117f1b4Smrg      GLuint i;
20297117f1b4Smrg      for (i = 0; i < BUFFER_COUNT; i++) {
20307117f1b4Smrg         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
2031af69d88dSmrg         struct gl_renderbuffer *rb = att->Renderbuffer;
2032af69d88dSmrg         if (rb && rb->NeedsFinishRenderTexture) {
2033af69d88dSmrg            ctx->Driver.FinishRenderTexture(ctx, rb);
20347117f1b4Smrg         }
20357117f1b4Smrg      }
20367117f1b4Smrg   }
20377117f1b4Smrg}
20387117f1b4Smrg
20397117f1b4Smrg
2040af69d88dSmrgstatic void
2041af69d88dSmrgbind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names)
20427117f1b4Smrg{
20434a49301eSmrg   struct gl_framebuffer *newDrawFb, *newReadFb;
20444a49301eSmrg   struct gl_framebuffer *oldDrawFb, *oldReadFb;
20457117f1b4Smrg   GLboolean bindReadBuf, bindDrawBuf;
20467117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
20477117f1b4Smrg
20487117f1b4Smrg   switch (target) {
20497117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
20507117f1b4Smrg      bindDrawBuf = GL_TRUE;
20517117f1b4Smrg      bindReadBuf = GL_FALSE;
20527117f1b4Smrg      break;
20537117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
20547117f1b4Smrg      bindDrawBuf = GL_FALSE;
20557117f1b4Smrg      bindReadBuf = GL_TRUE;
20567117f1b4Smrg      break;
20577117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
20587117f1b4Smrg      bindDrawBuf = GL_TRUE;
20597117f1b4Smrg      bindReadBuf = GL_TRUE;
20607117f1b4Smrg      break;
20617117f1b4Smrg   default:
20627117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
20637117f1b4Smrg      return;
20647117f1b4Smrg   }
20657117f1b4Smrg
20667117f1b4Smrg   if (framebuffer) {
20677117f1b4Smrg      /* Binding a user-created framebuffer object */
20684a49301eSmrg      newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
20694a49301eSmrg      if (newDrawFb == &DummyFramebuffer) {
20707117f1b4Smrg         /* ID was reserved, but no real framebuffer object made yet */
20714a49301eSmrg         newDrawFb = NULL;
20727117f1b4Smrg      }
2073af69d88dSmrg      else if (!newDrawFb && !allow_user_names) {
20744a49301eSmrg         /* All FBO IDs must be Gen'd */
20754a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
20764a49301eSmrg         return;
20774a49301eSmrg      }
20784a49301eSmrg
20794a49301eSmrg      if (!newDrawFb) {
20807117f1b4Smrg	 /* create new framebuffer object */
20814a49301eSmrg	 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
20824a49301eSmrg	 if (!newDrawFb) {
20837117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
20847117f1b4Smrg	    return;
20857117f1b4Smrg	 }
20864a49301eSmrg         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
20877117f1b4Smrg      }
20884a49301eSmrg      newReadFb = newDrawFb;
20897117f1b4Smrg   }
20907117f1b4Smrg   else {
20917117f1b4Smrg      /* Binding the window system framebuffer (which was originally set
20927117f1b4Smrg       * with MakeCurrent).
20937117f1b4Smrg       */
20944a49301eSmrg      newDrawFb = ctx->WinSysDrawBuffer;
20954a49301eSmrg      newReadFb = ctx->WinSysReadBuffer;
20967117f1b4Smrg   }
20977117f1b4Smrg
20984a49301eSmrg   ASSERT(newDrawFb);
20994a49301eSmrg   ASSERT(newDrawFb != &DummyFramebuffer);
21004a49301eSmrg
21014a49301eSmrg   /* save pointers to current/old framebuffers */
21024a49301eSmrg   oldDrawFb = ctx->DrawBuffer;
21034a49301eSmrg   oldReadFb = ctx->ReadBuffer;
21044a49301eSmrg
21054a49301eSmrg   /* check if really changing bindings */
21064a49301eSmrg   if (oldDrawFb == newDrawFb)
21074a49301eSmrg      bindDrawBuf = GL_FALSE;
21084a49301eSmrg   if (oldReadFb == newReadFb)
21094a49301eSmrg      bindReadBuf = GL_FALSE;
21107117f1b4Smrg
21117117f1b4Smrg   /*
21124a49301eSmrg    * OK, now bind the new Draw/Read framebuffers, if they're changing.
21134a49301eSmrg    *
21144a49301eSmrg    * We also check if we're beginning and/or ending render-to-texture.
21154a49301eSmrg    * When a framebuffer with texture attachments is unbound, call
21164a49301eSmrg    * ctx->Driver.FinishRenderTexture().
21174a49301eSmrg    * When a framebuffer with texture attachments is bound, call
21184a49301eSmrg    * ctx->Driver.RenderTexture().
21194a49301eSmrg    *
21204a49301eSmrg    * Note that if the ReadBuffer has texture attachments we don't consider
21214a49301eSmrg    * that a render-to-texture case.
21227117f1b4Smrg    */
21237117f1b4Smrg   if (bindReadBuf) {
21244a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
21254a49301eSmrg
21264a49301eSmrg      /* check if old readbuffer was render-to-texture */
21274a49301eSmrg      check_end_texture_render(ctx, oldReadFb);
21284a49301eSmrg
21294a49301eSmrg      _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
21307117f1b4Smrg   }
21317117f1b4Smrg
21327117f1b4Smrg   if (bindDrawBuf) {
21334a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
21347117f1b4Smrg
2135af69d88dSmrg      /* check if old framebuffer had any texture attachments */
2136af69d88dSmrg      if (oldDrawFb)
21374a49301eSmrg         check_end_texture_render(ctx, oldDrawFb);
21384a49301eSmrg
21394a49301eSmrg      /* check if newly bound framebuffer has any texture attachments */
21404a49301eSmrg      check_begin_texture_render(ctx, newDrawFb);
21414a49301eSmrg
21424a49301eSmrg      _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
21437117f1b4Smrg   }
21447117f1b4Smrg
21454a49301eSmrg   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
21464a49301eSmrg      ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
21477117f1b4Smrg   }
21487117f1b4Smrg}
21497117f1b4Smrg
2150af69d88dSmrgvoid GLAPIENTRY
2151af69d88dSmrg_mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
2152af69d88dSmrg{
2153af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
2154af69d88dSmrg
2155af69d88dSmrg   /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry
2156af69d88dSmrg    * point, but they allow the use of user-generated names.
2157af69d88dSmrg    */
2158af69d88dSmrg   bind_framebuffer(target, framebuffer, _mesa_is_gles(ctx));
2159af69d88dSmrg}
2160af69d88dSmrg
21617117f1b4Smrg
21627117f1b4Smrgvoid GLAPIENTRY
2163af69d88dSmrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
2164af69d88dSmrg{
2165af69d88dSmrg   /* This function should not be in the dispatch table for core profile /
2166af69d88dSmrg    * OpenGL 3.1, so execution should never get here in those cases -- no
2167af69d88dSmrg    * need for an explicit test.
2168af69d88dSmrg    */
2169af69d88dSmrg   bind_framebuffer(target, framebuffer, true);
2170af69d88dSmrg}
2171af69d88dSmrg
2172af69d88dSmrg
2173af69d88dSmrgvoid GLAPIENTRY
2174af69d88dSmrg_mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
21757117f1b4Smrg{
21767117f1b4Smrg   GLint i;
21777117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
21787117f1b4Smrg
21797117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
21807117f1b4Smrg
21817117f1b4Smrg   for (i = 0; i < n; i++) {
21827117f1b4Smrg      if (framebuffers[i] > 0) {
21837117f1b4Smrg	 struct gl_framebuffer *fb;
21847117f1b4Smrg	 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
21857117f1b4Smrg	 if (fb) {
21867117f1b4Smrg            ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
21877117f1b4Smrg
21887117f1b4Smrg            /* check if deleting currently bound framebuffer object */
2189af69d88dSmrg            if (fb == ctx->DrawBuffer) {
2190af69d88dSmrg               /* bind default */
2191af69d88dSmrg               ASSERT(fb->RefCount >= 2);
2192af69d88dSmrg               _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
21934a49301eSmrg            }
2194af69d88dSmrg            if (fb == ctx->ReadBuffer) {
2195af69d88dSmrg               /* bind default */
2196af69d88dSmrg               ASSERT(fb->RefCount >= 2);
2197af69d88dSmrg               _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, 0);
21987117f1b4Smrg            }
21997117f1b4Smrg
22007117f1b4Smrg	    /* remove from hash table immediately, to free the ID */
22017117f1b4Smrg	    _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
22027117f1b4Smrg
22037117f1b4Smrg            if (fb != &DummyFramebuffer) {
22047117f1b4Smrg               /* But the object will not be freed until it's no longer
22057117f1b4Smrg                * bound in any context.
22067117f1b4Smrg                */
22074a49301eSmrg               _mesa_reference_framebuffer(&fb, NULL);
22087117f1b4Smrg	    }
22097117f1b4Smrg	 }
22107117f1b4Smrg      }
22117117f1b4Smrg   }
22127117f1b4Smrg}
22137117f1b4Smrg
22147117f1b4Smrg
22157117f1b4Smrgvoid GLAPIENTRY
2216af69d88dSmrg_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers)
22177117f1b4Smrg{
22187117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
22197117f1b4Smrg   GLuint first;
22207117f1b4Smrg   GLint i;
22217117f1b4Smrg
22227117f1b4Smrg   if (n < 0) {
22237117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
22247117f1b4Smrg      return;
22257117f1b4Smrg   }
22267117f1b4Smrg
22277117f1b4Smrg   if (!framebuffers)
22287117f1b4Smrg      return;
22297117f1b4Smrg
22307117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
22317117f1b4Smrg
22327117f1b4Smrg   for (i = 0; i < n; i++) {
22337117f1b4Smrg      GLuint name = first + i;
22347117f1b4Smrg      framebuffers[i] = name;
22357117f1b4Smrg      /* insert dummy placeholder into hash table */
2236af69d88dSmrg      mtx_lock(&ctx->Shared->Mutex);
22377117f1b4Smrg      _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
2238af69d88dSmrg      mtx_unlock(&ctx->Shared->Mutex);
22397117f1b4Smrg   }
22407117f1b4Smrg}
22417117f1b4Smrg
22427117f1b4Smrg
22437117f1b4SmrgGLenum GLAPIENTRY
2244af69d88dSmrg_mesa_CheckFramebufferStatus(GLenum target)
22457117f1b4Smrg{
22467117f1b4Smrg   struct gl_framebuffer *buffer;
22477117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
22487117f1b4Smrg
22497117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
22507117f1b4Smrg
2251af69d88dSmrg   if (MESA_VERBOSE & VERBOSE_API)
2252af69d88dSmrg      _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n",
2253af69d88dSmrg                  _mesa_lookup_enum_by_nr(target));
2254af69d88dSmrg
22553464ebd5Sriastradh   buffer = get_framebuffer_target(ctx, target);
22563464ebd5Sriastradh   if (!buffer) {
22577117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
22583464ebd5Sriastradh      return 0;
22597117f1b4Smrg   }
22607117f1b4Smrg
2261af69d88dSmrg   if (_mesa_is_winsys_fbo(buffer)) {
2262af69d88dSmrg      /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */
2263af69d88dSmrg      if (buffer != &IncompleteFramebuffer) {
2264af69d88dSmrg         return GL_FRAMEBUFFER_COMPLETE_EXT;
2265af69d88dSmrg      } else {
2266af69d88dSmrg         return GL_FRAMEBUFFER_UNDEFINED;
2267af69d88dSmrg      }
22687117f1b4Smrg   }
22697117f1b4Smrg
22704a49301eSmrg   /* No need to flush here */
22714a49301eSmrg
22724a49301eSmrg   if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
22734a49301eSmrg      _mesa_test_framebuffer_completeness(ctx, buffer);
22744a49301eSmrg   }
22757117f1b4Smrg
22767117f1b4Smrg   return buffer->_Status;
22777117f1b4Smrg}
22787117f1b4Smrg
22797117f1b4Smrg
2280af69d88dSmrg/**
2281af69d88dSmrg * Replicate the src attachment point. Used by framebuffer_texture() when
2282af69d88dSmrg * the same texture is attached at GL_DEPTH_ATTACHMENT and
2283af69d88dSmrg * GL_STENCIL_ATTACHMENT.
2284af69d88dSmrg */
2285af69d88dSmrgstatic void
2286af69d88dSmrgreuse_framebuffer_texture_attachment(struct gl_framebuffer *fb,
2287af69d88dSmrg                                     gl_buffer_index dst,
2288af69d88dSmrg                                     gl_buffer_index src)
2289af69d88dSmrg{
2290af69d88dSmrg   struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst];
2291af69d88dSmrg   struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src];
2292af69d88dSmrg
2293af69d88dSmrg   assert(src_att->Texture != NULL);
2294af69d88dSmrg   assert(src_att->Renderbuffer != NULL);
2295af69d88dSmrg
2296af69d88dSmrg   _mesa_reference_texobj(&dst_att->Texture, src_att->Texture);
2297af69d88dSmrg   _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer);
2298af69d88dSmrg   dst_att->Type = src_att->Type;
2299af69d88dSmrg   dst_att->Complete = src_att->Complete;
2300af69d88dSmrg   dst_att->TextureLevel = src_att->TextureLevel;
2301af69d88dSmrg   dst_att->Zoffset = src_att->Zoffset;
2302af69d88dSmrg}
2303af69d88dSmrg
23047117f1b4Smrg
23057117f1b4Smrg/**
2306af69d88dSmrg * Common code called by glFramebufferTexture1D/2D/3DEXT() and
2307af69d88dSmrg * glFramebufferTextureLayerEXT().
2308af69d88dSmrg *
2309af69d88dSmrg * \param textarget is the textarget that was passed to the
2310af69d88dSmrg * glFramebufferTexture...() function, or 0 if the corresponding function
2311af69d88dSmrg * doesn't have a textarget parameter.
2312af69d88dSmrg *
2313af69d88dSmrg * \param layered is true if this function was called from
2314af69d88dSmrg * glFramebufferTexture(), false otherwise.
23157117f1b4Smrg */
23167117f1b4Smrgstatic void
2317af69d88dSmrgframebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
23187117f1b4Smrg                    GLenum attachment, GLenum textarget, GLuint texture,
2319af69d88dSmrg                    GLint level, GLint zoffset, GLboolean layered)
23207117f1b4Smrg{
23217117f1b4Smrg   struct gl_renderbuffer_attachment *att;
23227117f1b4Smrg   struct gl_texture_object *texObj = NULL;
23237117f1b4Smrg   struct gl_framebuffer *fb;
2324af69d88dSmrg   GLenum maxLevelsTarget;
23257117f1b4Smrg
23263464ebd5Sriastradh   fb = get_framebuffer_target(ctx, target);
23273464ebd5Sriastradh   if (!fb) {
23287117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
23294a49301eSmrg                  "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
23307117f1b4Smrg      return;
23317117f1b4Smrg   }
23327117f1b4Smrg
23337117f1b4Smrg   /* check framebuffer binding */
2334af69d88dSmrg   if (_mesa_is_winsys_fbo(fb)) {
23357117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
23367117f1b4Smrg                  "glFramebufferTexture%sEXT", caller);
23377117f1b4Smrg      return;
23387117f1b4Smrg   }
23397117f1b4Smrg
23407117f1b4Smrg   /* The textarget, level, and zoffset parameters are only validated if
23417117f1b4Smrg    * texture is non-zero.
23427117f1b4Smrg    */
23437117f1b4Smrg   if (texture) {
23447117f1b4Smrg      GLboolean err = GL_TRUE;
23457117f1b4Smrg
23467117f1b4Smrg      texObj = _mesa_lookup_texture(ctx, texture);
23477117f1b4Smrg      if (texObj != NULL) {
2348c1f859d4Smrg         if (textarget == 0) {
2349af69d88dSmrg            if (layered) {
2350af69d88dSmrg               /* We're being called by glFramebufferTexture() and textarget
2351af69d88dSmrg                * is not used.
2352af69d88dSmrg                */
2353af69d88dSmrg               switch (texObj->Target) {
2354af69d88dSmrg               case GL_TEXTURE_3D:
2355af69d88dSmrg               case GL_TEXTURE_1D_ARRAY_EXT:
2356af69d88dSmrg               case GL_TEXTURE_2D_ARRAY_EXT:
2357af69d88dSmrg               case GL_TEXTURE_CUBE_MAP:
2358af69d88dSmrg               case GL_TEXTURE_CUBE_MAP_ARRAY:
2359af69d88dSmrg               case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
2360af69d88dSmrg                  err = false;
2361af69d88dSmrg                  break;
2362af69d88dSmrg               case GL_TEXTURE_1D:
2363af69d88dSmrg               case GL_TEXTURE_2D:
2364af69d88dSmrg               case GL_TEXTURE_RECTANGLE:
2365af69d88dSmrg               case GL_TEXTURE_2D_MULTISAMPLE:
2366af69d88dSmrg                  /* These texture types are valid to pass to
2367af69d88dSmrg                   * glFramebufferTexture(), but since they aren't layered, it
2368af69d88dSmrg                   * is equivalent to calling glFramebufferTexture{1D,2D}().
2369af69d88dSmrg                   */
2370af69d88dSmrg                  err = false;
2371af69d88dSmrg                  layered = false;
2372af69d88dSmrg                  textarget = texObj->Target;
2373af69d88dSmrg                  break;
2374af69d88dSmrg               default:
2375af69d88dSmrg                  err = true;
2376af69d88dSmrg                  break;
2377af69d88dSmrg               }
2378af69d88dSmrg            } else {
2379af69d88dSmrg               /* We're being called by glFramebufferTextureLayer() and
2380af69d88dSmrg                * textarget is not used.  The only legal texture types for
2381af69d88dSmrg                * that function are 3D and 1D/2D arrays textures.
2382af69d88dSmrg                */
2383af69d88dSmrg               err = (texObj->Target != GL_TEXTURE_3D) &&
2384af69d88dSmrg                  (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
2385af69d88dSmrg                  (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT) &&
2386af69d88dSmrg                  (texObj->Target != GL_TEXTURE_CUBE_MAP_ARRAY) &&
2387af69d88dSmrg                  (texObj->Target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
2388af69d88dSmrg            }
2389c1f859d4Smrg         }
2390c1f859d4Smrg         else {
2391af69d88dSmrg            /* Make sure textarget is consistent with the texture's type */
2392c1f859d4Smrg            err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
2393af69d88dSmrg                ? !_mesa_is_cube_face(textarget)
2394c1f859d4Smrg                : (texObj->Target != textarget);
2395c1f859d4Smrg         }
23967117f1b4Smrg      }
23973464ebd5Sriastradh      else {
23983464ebd5Sriastradh         /* can't render to a non-existant texture */
23993464ebd5Sriastradh         _mesa_error(ctx, GL_INVALID_OPERATION,
24003464ebd5Sriastradh                     "glFramebufferTexture%sEXT(non existant texture)",
24013464ebd5Sriastradh                     caller);
24023464ebd5Sriastradh         return;
24033464ebd5Sriastradh      }
24047117f1b4Smrg
24057117f1b4Smrg      if (err) {
24067117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
24077117f1b4Smrg                     "glFramebufferTexture%sEXT(texture target mismatch)",
24087117f1b4Smrg                     caller);
24097117f1b4Smrg         return;
24107117f1b4Smrg      }
24117117f1b4Smrg
24127117f1b4Smrg      if (texObj->Target == GL_TEXTURE_3D) {
24137117f1b4Smrg         const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
24147117f1b4Smrg         if (zoffset < 0 || zoffset >= maxSize) {
24157117f1b4Smrg            _mesa_error(ctx, GL_INVALID_VALUE,
2416c1f859d4Smrg                        "glFramebufferTexture%sEXT(zoffset)", caller);
24177117f1b4Smrg            return;
24187117f1b4Smrg         }
24197117f1b4Smrg      }
2420c1f859d4Smrg      else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
2421af69d88dSmrg               (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT) ||
2422af69d88dSmrg               (texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) ||
2423af69d88dSmrg               (texObj->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) {
2424af69d88dSmrg         if (zoffset < 0 ||
2425af69d88dSmrg             zoffset >= (GLint) ctx->Const.MaxArrayTextureLayers) {
2426c1f859d4Smrg            _mesa_error(ctx, GL_INVALID_VALUE,
2427c1f859d4Smrg                        "glFramebufferTexture%sEXT(layer)", caller);
2428c1f859d4Smrg            return;
2429c1f859d4Smrg         }
2430c1f859d4Smrg      }
2431c1f859d4Smrg
2432af69d88dSmrg      maxLevelsTarget = textarget ? textarget : texObj->Target;
2433af69d88dSmrg      if ((level < 0) ||
2434af69d88dSmrg          (level >= _mesa_max_texture_levels(ctx, maxLevelsTarget))) {
24357117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
24367117f1b4Smrg                     "glFramebufferTexture%sEXT(level)", caller);
24377117f1b4Smrg         return;
24387117f1b4Smrg      }
24397117f1b4Smrg   }
24407117f1b4Smrg
2441af69d88dSmrg   att = get_attachment(ctx, fb, attachment);
24427117f1b4Smrg   if (att == NULL) {
24437117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
24447117f1b4Smrg                  "glFramebufferTexture%sEXT(attachment)", caller);
24457117f1b4Smrg      return;
24467117f1b4Smrg   }
24477117f1b4Smrg
24487117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
24497117f1b4Smrg
2450af69d88dSmrg   mtx_lock(&fb->Mutex);
24517117f1b4Smrg   if (texObj) {
2452af69d88dSmrg      if (attachment == GL_DEPTH_ATTACHMENT &&
2453af69d88dSmrg          texObj == fb->Attachment[BUFFER_STENCIL].Texture &&
2454af69d88dSmrg          level == fb->Attachment[BUFFER_STENCIL].TextureLevel &&
2455af69d88dSmrg          _mesa_tex_target_to_face(textarget) ==
2456af69d88dSmrg          fb->Attachment[BUFFER_STENCIL].CubeMapFace &&
2457af69d88dSmrg          zoffset == fb->Attachment[BUFFER_STENCIL].Zoffset) {
2458af69d88dSmrg	 /* The texture object is already attached to the stencil attachment
2459af69d88dSmrg	  * point. Don't create a new renderbuffer; just reuse the stencil
2460af69d88dSmrg	  * attachment's. This is required to prevent a GL error in
2461af69d88dSmrg	  * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL).
2462af69d88dSmrg	  */
2463af69d88dSmrg	 reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH,
2464af69d88dSmrg	                                      BUFFER_STENCIL);
2465af69d88dSmrg      } else if (attachment == GL_STENCIL_ATTACHMENT &&
2466af69d88dSmrg	         texObj == fb->Attachment[BUFFER_DEPTH].Texture &&
2467af69d88dSmrg                 level == fb->Attachment[BUFFER_DEPTH].TextureLevel &&
2468af69d88dSmrg                 _mesa_tex_target_to_face(textarget) ==
2469af69d88dSmrg                 fb->Attachment[BUFFER_DEPTH].CubeMapFace &&
2470af69d88dSmrg                 zoffset == fb->Attachment[BUFFER_DEPTH].Zoffset) {
2471af69d88dSmrg	 /* As above, but with depth and stencil transposed. */
2472af69d88dSmrg	 reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL,
2473af69d88dSmrg	                                      BUFFER_DEPTH);
2474af69d88dSmrg      } else {
2475af69d88dSmrg	 set_texture_attachment(ctx, fb, att, texObj, textarget,
2476af69d88dSmrg	                              level, zoffset, layered);
2477af69d88dSmrg	 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2478af69d88dSmrg	    /* Above we created a new renderbuffer and attached it to the
2479af69d88dSmrg	     * depth attachment point. Now attach it to the stencil attachment
2480af69d88dSmrg	     * point too.
2481af69d88dSmrg	     */
2482af69d88dSmrg	    assert(att == &fb->Attachment[BUFFER_DEPTH]);
2483af69d88dSmrg	    reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL,
2484af69d88dSmrg	                                         BUFFER_DEPTH);
2485af69d88dSmrg	 }
2486af69d88dSmrg      }
2487af69d88dSmrg
24884a49301eSmrg      /* Set the render-to-texture flag.  We'll check this flag in
24894a49301eSmrg       * glTexImage() and friends to determine if we need to revalidate
24904a49301eSmrg       * any FBOs that might be rendering into this texture.
24914a49301eSmrg       * This flag never gets cleared since it's non-trivial to determine
24924a49301eSmrg       * when all FBOs might be done rendering to this texture.  That's OK
24934a49301eSmrg       * though since it's uncommon to render to a texture then repeatedly
24944a49301eSmrg       * call glTexImage() to change images in the texture.
24954a49301eSmrg       */
24964a49301eSmrg      texObj->_RenderToTexture = GL_TRUE;
24977117f1b4Smrg   }
24987117f1b4Smrg   else {
2499af69d88dSmrg      remove_attachment(ctx, att);
2500af69d88dSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2501af69d88dSmrg	 assert(att == &fb->Attachment[BUFFER_DEPTH]);
2502af69d88dSmrg	 remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]);
2503af69d88dSmrg      }
25047117f1b4Smrg   }
25054a49301eSmrg
25064a49301eSmrg   invalidate_framebuffer(fb);
25074a49301eSmrg
2508af69d88dSmrg   mtx_unlock(&fb->Mutex);
25097117f1b4Smrg}
25107117f1b4Smrg
25117117f1b4Smrg
25127117f1b4Smrgvoid GLAPIENTRY
2513af69d88dSmrg_mesa_FramebufferTexture1D(GLenum target, GLenum attachment,
2514af69d88dSmrg                           GLenum textarget, GLuint texture, GLint level)
25157117f1b4Smrg{
25167117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
25177117f1b4Smrg
2518af69d88dSmrg   if (texture != 0) {
2519af69d88dSmrg      GLboolean error;
2520af69d88dSmrg
2521af69d88dSmrg      switch (textarget) {
2522af69d88dSmrg      case GL_TEXTURE_1D:
2523af69d88dSmrg         error = GL_FALSE;
2524af69d88dSmrg         break;
2525af69d88dSmrg      case GL_TEXTURE_1D_ARRAY:
2526af69d88dSmrg         error = !ctx->Extensions.EXT_texture_array;
2527af69d88dSmrg         break;
2528af69d88dSmrg      default:
2529af69d88dSmrg         error = GL_TRUE;
2530af69d88dSmrg      }
2531af69d88dSmrg
2532af69d88dSmrg      if (error) {
2533af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2534af69d88dSmrg                     "glFramebufferTexture1DEXT(textarget=%s)",
2535af69d88dSmrg                     _mesa_lookup_enum_by_nr(textarget));
2536af69d88dSmrg         return;
2537af69d88dSmrg      }
25387117f1b4Smrg   }
25397117f1b4Smrg
25407117f1b4Smrg   framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
2541af69d88dSmrg                       level, 0, GL_FALSE);
25427117f1b4Smrg}
25437117f1b4Smrg
25447117f1b4Smrg
25457117f1b4Smrgvoid GLAPIENTRY
2546af69d88dSmrg_mesa_FramebufferTexture2D(GLenum target, GLenum attachment,
2547af69d88dSmrg                           GLenum textarget, GLuint texture, GLint level)
25487117f1b4Smrg{
25497117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
25507117f1b4Smrg
2551af69d88dSmrg   if (texture != 0) {
2552af69d88dSmrg      GLboolean error;
2553af69d88dSmrg
2554af69d88dSmrg      switch (textarget) {
2555af69d88dSmrg      case GL_TEXTURE_2D:
2556af69d88dSmrg         error = GL_FALSE;
2557af69d88dSmrg         break;
2558af69d88dSmrg      case GL_TEXTURE_RECTANGLE:
2559af69d88dSmrg         error = _mesa_is_gles(ctx)
2560af69d88dSmrg            || !ctx->Extensions.NV_texture_rectangle;
2561af69d88dSmrg         break;
2562af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2563af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2564af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2565af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2566af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2567af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2568af69d88dSmrg         error = !ctx->Extensions.ARB_texture_cube_map;
2569af69d88dSmrg         break;
2570af69d88dSmrg      case GL_TEXTURE_2D_ARRAY:
2571af69d88dSmrg         error = (_mesa_is_gles(ctx) && ctx->Version < 30)
2572af69d88dSmrg            || !ctx->Extensions.EXT_texture_array;
2573af69d88dSmrg         break;
2574af69d88dSmrg      case GL_TEXTURE_2D_MULTISAMPLE:
2575af69d88dSmrg      case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
2576af69d88dSmrg         error = _mesa_is_gles(ctx)
2577af69d88dSmrg            || !ctx->Extensions.ARB_texture_multisample;
2578af69d88dSmrg         break;
2579af69d88dSmrg      default:
2580af69d88dSmrg         error = GL_TRUE;
2581af69d88dSmrg      }
2582af69d88dSmrg
2583af69d88dSmrg      if (error) {
2584af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2585af69d88dSmrg                     "glFramebufferTexture2DEXT(textarget=%s)",
2586af69d88dSmrg                     _mesa_lookup_enum_by_nr(textarget));
2587af69d88dSmrg         return;
2588af69d88dSmrg      }
25897117f1b4Smrg   }
25907117f1b4Smrg
25917117f1b4Smrg   framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
2592af69d88dSmrg                       level, 0, GL_FALSE);
25937117f1b4Smrg}
25947117f1b4Smrg
25957117f1b4Smrg
25967117f1b4Smrgvoid GLAPIENTRY
2597af69d88dSmrg_mesa_FramebufferTexture3D(GLenum target, GLenum attachment,
2598af69d88dSmrg                           GLenum textarget, GLuint texture,
2599af69d88dSmrg                           GLint level, GLint zoffset)
26007117f1b4Smrg{
26017117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
26027117f1b4Smrg
26037117f1b4Smrg   if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
26043464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
26057117f1b4Smrg                  "glFramebufferTexture3DEXT(textarget)");
26067117f1b4Smrg      return;
26077117f1b4Smrg   }
26087117f1b4Smrg
26097117f1b4Smrg   framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
2610af69d88dSmrg                       level, zoffset, GL_FALSE);
26117117f1b4Smrg}
26127117f1b4Smrg
26137117f1b4Smrg
2614c1f859d4Smrgvoid GLAPIENTRY
2615af69d88dSmrg_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment,
2616af69d88dSmrg                              GLuint texture, GLint level, GLint layer)
2617c1f859d4Smrg{
2618c1f859d4Smrg   GET_CURRENT_CONTEXT(ctx);
2619c1f859d4Smrg
2620c1f859d4Smrg   framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
2621af69d88dSmrg                       level, layer, GL_FALSE);
2622af69d88dSmrg}
2623af69d88dSmrg
2624af69d88dSmrg
2625af69d88dSmrgvoid GLAPIENTRY
2626af69d88dSmrg_mesa_FramebufferTexture(GLenum target, GLenum attachment,
2627af69d88dSmrg                         GLuint texture, GLint level)
2628af69d88dSmrg{
2629af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
2630af69d88dSmrg
2631af69d88dSmrg   if (_mesa_has_geometry_shaders(ctx)) {
2632af69d88dSmrg      framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
2633af69d88dSmrg                          level, 0, GL_TRUE);
2634af69d88dSmrg   } else {
2635af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
2636af69d88dSmrg                  "unsupported function (glFramebufferTexture) called");
2637af69d88dSmrg   }
2638c1f859d4Smrg}
2639c1f859d4Smrg
2640c1f859d4Smrg
26417117f1b4Smrgvoid GLAPIENTRY
2642af69d88dSmrg_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment,
2643af69d88dSmrg                              GLenum renderbufferTarget,
2644af69d88dSmrg                              GLuint renderbuffer)
26457117f1b4Smrg{
26467117f1b4Smrg   struct gl_renderbuffer_attachment *att;
26477117f1b4Smrg   struct gl_framebuffer *fb;
26487117f1b4Smrg   struct gl_renderbuffer *rb;
26497117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
26507117f1b4Smrg
26513464ebd5Sriastradh   fb = get_framebuffer_target(ctx, target);
26523464ebd5Sriastradh   if (!fb) {
2653af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
2654af69d88dSmrg                  "glFramebufferRenderbufferEXT(target)");
26557117f1b4Smrg      return;
26567117f1b4Smrg   }
26577117f1b4Smrg
26587117f1b4Smrg   if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
26597117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
26607117f1b4Smrg                  "glFramebufferRenderbufferEXT(renderbufferTarget)");
26617117f1b4Smrg      return;
26627117f1b4Smrg   }
26637117f1b4Smrg
2664af69d88dSmrg   if (_mesa_is_winsys_fbo(fb)) {
26657117f1b4Smrg      /* Can't attach new renderbuffers to a window system framebuffer */
26667117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
26677117f1b4Smrg      return;
26687117f1b4Smrg   }
26697117f1b4Smrg
2670af69d88dSmrg   att = get_attachment(ctx, fb, attachment);
26717117f1b4Smrg   if (att == NULL) {
26727117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
26734a49301eSmrg                  "glFramebufferRenderbufferEXT(invalid attachment %s)",
26744a49301eSmrg                  _mesa_lookup_enum_by_nr(attachment));
26757117f1b4Smrg      return;
26767117f1b4Smrg   }
26777117f1b4Smrg
26787117f1b4Smrg   if (renderbuffer) {
26797117f1b4Smrg      rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
26807117f1b4Smrg      if (!rb) {
26817117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION,
26824a49301eSmrg		     "glFramebufferRenderbufferEXT(non-existant"
26834a49301eSmrg                     " renderbuffer %u)", renderbuffer);
26847117f1b4Smrg	 return;
26857117f1b4Smrg      }
26863464ebd5Sriastradh      else if (rb == &DummyRenderbuffer) {
2687af69d88dSmrg	 _mesa_error(ctx, GL_INVALID_OPERATION,
26883464ebd5Sriastradh		     "glFramebufferRenderbufferEXT(renderbuffer %u)",
26893464ebd5Sriastradh                     renderbuffer);
26903464ebd5Sriastradh	 return;
26913464ebd5Sriastradh      }
26927117f1b4Smrg   }
26937117f1b4Smrg   else {
26947117f1b4Smrg      /* remove renderbuffer attachment */
26957117f1b4Smrg      rb = NULL;
26967117f1b4Smrg   }
26977117f1b4Smrg
2698cdc920a0Smrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
2699cdc920a0Smrg       rb && rb->Format != MESA_FORMAT_NONE) {
27004a49301eSmrg      /* make sure the renderbuffer is a depth/stencil format */
2701cdc920a0Smrg      const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
27024a49301eSmrg      if (baseFormat != GL_DEPTH_STENCIL) {
27034a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
27044a49301eSmrg                     "glFramebufferRenderbufferEXT(renderbuffer"
27054a49301eSmrg                     " is not DEPTH_STENCIL format)");
27064a49301eSmrg         return;
27074a49301eSmrg      }
27084a49301eSmrg   }
27094a49301eSmrg
27107117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
27117117f1b4Smrg
27127117f1b4Smrg   assert(ctx->Driver.FramebufferRenderbuffer);
27137117f1b4Smrg   ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
27147117f1b4Smrg
27157117f1b4Smrg   /* Some subsequent GL commands may depend on the framebuffer's visual
27167117f1b4Smrg    * after the binding is updated.  Update visual info now.
27177117f1b4Smrg    */
27183464ebd5Sriastradh   _mesa_update_framebuffer_visual(ctx, fb);
27197117f1b4Smrg}
27207117f1b4Smrg
27217117f1b4Smrg
27227117f1b4Smrgvoid GLAPIENTRY
2723af69d88dSmrg_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment,
2724af69d88dSmrg                                          GLenum pname, GLint *params)
27257117f1b4Smrg{
27267117f1b4Smrg   const struct gl_renderbuffer_attachment *att;
27277117f1b4Smrg   struct gl_framebuffer *buffer;
27283464ebd5Sriastradh   GLenum err;
27297117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
27307117f1b4Smrg
2731af69d88dSmrg   /* The error differs in GL and GLES. */
2732af69d88dSmrg   err = _mesa_is_desktop_gl(ctx) ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
27333464ebd5Sriastradh
27343464ebd5Sriastradh   buffer = get_framebuffer_target(ctx, target);
27353464ebd5Sriastradh   if (!buffer) {
27367117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
27377117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(target)");
27387117f1b4Smrg      return;
27397117f1b4Smrg   }
27407117f1b4Smrg
2741af69d88dSmrg   if (_mesa_is_winsys_fbo(buffer)) {
2742af69d88dSmrg      /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec
2743af69d88dSmrg       * says:
2744af69d88dSmrg       *
2745af69d88dSmrg       *     "If the framebuffer currently bound to target is zero, then
2746af69d88dSmrg       *     INVALID_OPERATION is generated."
2747af69d88dSmrg       *
2748af69d88dSmrg       * The EXT_framebuffer_object spec has the same wording, and the
2749af69d88dSmrg       * OES_framebuffer_object spec refers to the EXT_framebuffer_object
2750af69d88dSmrg       * spec.
2751af69d88dSmrg       */
2752af69d88dSmrg      if ((!_mesa_is_desktop_gl(ctx) ||
2753af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
2754af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
2755af69d88dSmrg	 _mesa_error(ctx, GL_INVALID_OPERATION,
2756af69d88dSmrg		     "glGetFramebufferAttachmentParameteriv(bound FBO = 0)");
2757af69d88dSmrg	 return;
2758af69d88dSmrg      }
2759af69d88dSmrg
2760af69d88dSmrg      if (_mesa_is_gles3(ctx) && attachment != GL_BACK &&
2761af69d88dSmrg          attachment != GL_DEPTH && attachment != GL_STENCIL) {
2762af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2763af69d88dSmrg                     "glGetFramebufferAttachmentParameteriv(attachment)");
2764af69d88dSmrg         return;
2765af69d88dSmrg      }
27663464ebd5Sriastradh      /* the default / window-system FBO */
27673464ebd5Sriastradh      att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
27683464ebd5Sriastradh   }
27693464ebd5Sriastradh   else {
27703464ebd5Sriastradh      /* user-created framebuffer FBO */
2771af69d88dSmrg      att = get_attachment(ctx, buffer, attachment);
27727117f1b4Smrg   }
27737117f1b4Smrg
27747117f1b4Smrg   if (att == NULL) {
27757117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
27767117f1b4Smrg                  "glGetFramebufferAttachmentParameterivEXT(attachment)");
27777117f1b4Smrg      return;
27787117f1b4Smrg   }
27797117f1b4Smrg
27804a49301eSmrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
27814a49301eSmrg      const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
2782af69d88dSmrg      if (pname == GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) {
2783af69d88dSmrg         /* This behavior is first specified in OpenGL 4.4 specification.
2784af69d88dSmrg          *
2785af69d88dSmrg          * From the OpenGL 4.4 spec page 275:
2786af69d88dSmrg          *   "This query cannot be performed for a combined depth+stencil
2787af69d88dSmrg          *    attachment, since it does not have a single format."
2788af69d88dSmrg          */
2789af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2790af69d88dSmrg                     "glGetFramebufferAttachmentParameteriv("
2791af69d88dSmrg                     "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE"
2792af69d88dSmrg                     " is invalid for depth+stencil attachment)");
2793af69d88dSmrg         return;
2794af69d88dSmrg      }
2795af69d88dSmrg      /* the depth and stencil attachments must point to the same buffer */
2796af69d88dSmrg      depthAtt = get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
2797af69d88dSmrg      stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
27984a49301eSmrg      if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
27994a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
28004a49301eSmrg                     "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
28014a49301eSmrg                     " attachments differ)");
28024a49301eSmrg         return;
28034a49301eSmrg      }
28044a49301eSmrg   }
28054a49301eSmrg
28064a49301eSmrg   /* No need to flush here */
28077117f1b4Smrg
28087117f1b4Smrg   switch (pname) {
28097117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
2810af69d88dSmrg      *params = _mesa_is_winsys_fbo(buffer)
2811af69d88dSmrg         ? GL_FRAMEBUFFER_DEFAULT : att->Type;
28127117f1b4Smrg      return;
28137117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
28147117f1b4Smrg      if (att->Type == GL_RENDERBUFFER_EXT) {
28157117f1b4Smrg	 *params = att->Renderbuffer->Name;
28167117f1b4Smrg      }
28177117f1b4Smrg      else if (att->Type == GL_TEXTURE) {
28187117f1b4Smrg	 *params = att->Texture->Name;
28197117f1b4Smrg      }
28207117f1b4Smrg      else {
28213464ebd5Sriastradh         assert(att->Type == GL_NONE);
2822af69d88dSmrg         if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
28233464ebd5Sriastradh            *params = 0;
28243464ebd5Sriastradh         } else {
2825af69d88dSmrg            goto invalid_pname_enum;
28263464ebd5Sriastradh         }
28277117f1b4Smrg      }
28287117f1b4Smrg      return;
28297117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
28307117f1b4Smrg      if (att->Type == GL_TEXTURE) {
28317117f1b4Smrg	 *params = att->TextureLevel;
28327117f1b4Smrg      }
28333464ebd5Sriastradh      else if (att->Type == GL_NONE) {
28343464ebd5Sriastradh         _mesa_error(ctx, err,
28353464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
28363464ebd5Sriastradh      }
28377117f1b4Smrg      else {
2838af69d88dSmrg         goto invalid_pname_enum;
28397117f1b4Smrg      }
28407117f1b4Smrg      return;
28417117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
28427117f1b4Smrg      if (att->Type == GL_TEXTURE) {
2843c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
2844c1f859d4Smrg            *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
2845c1f859d4Smrg         }
2846c1f859d4Smrg         else {
2847c1f859d4Smrg            *params = 0;
2848c1f859d4Smrg         }
28497117f1b4Smrg      }
28503464ebd5Sriastradh      else if (att->Type == GL_NONE) {
28513464ebd5Sriastradh         _mesa_error(ctx, err,
28523464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
28533464ebd5Sriastradh      }
28547117f1b4Smrg      else {
2855af69d88dSmrg         goto invalid_pname_enum;
28567117f1b4Smrg      }
28577117f1b4Smrg      return;
28587117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
2859af69d88dSmrg      if (ctx->API == API_OPENGLES) {
2860af69d88dSmrg         goto invalid_pname_enum;
2861af69d88dSmrg      } else if (att->Type == GL_NONE) {
2862af69d88dSmrg         _mesa_error(ctx, err,
2863af69d88dSmrg                     "glGetFramebufferAttachmentParameterivEXT(pname)");
2864af69d88dSmrg      } else if (att->Type == GL_TEXTURE) {
2865c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2866c1f859d4Smrg            *params = att->Zoffset;
2867c1f859d4Smrg         }
2868c1f859d4Smrg         else {
2869c1f859d4Smrg            *params = 0;
2870c1f859d4Smrg         }
28717117f1b4Smrg      }
28727117f1b4Smrg      else {
2873af69d88dSmrg         goto invalid_pname_enum;
28747117f1b4Smrg      }
28757117f1b4Smrg      return;
28764a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2877af69d88dSmrg      if ((!_mesa_is_desktop_gl(ctx) ||
2878af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
2879af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
2880af69d88dSmrg         goto invalid_pname_enum;
28814a49301eSmrg      }
28823464ebd5Sriastradh      else if (att->Type == GL_NONE) {
28833464ebd5Sriastradh         _mesa_error(ctx, err,
28843464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
28853464ebd5Sriastradh      }
28864a49301eSmrg      else {
2887af69d88dSmrg         if (ctx->Extensions.EXT_framebuffer_sRGB) {
2888af69d88dSmrg            *params =
2889af69d88dSmrg               _mesa_get_format_color_encoding(att->Renderbuffer->Format);
28903464ebd5Sriastradh         }
28913464ebd5Sriastradh         else {
28923464ebd5Sriastradh            /* According to ARB_framebuffer_sRGB, we should return LINEAR
28933464ebd5Sriastradh             * if the sRGB conversion is unsupported. */
28943464ebd5Sriastradh            *params = GL_LINEAR;
28953464ebd5Sriastradh         }
28964a49301eSmrg      }
28974a49301eSmrg      return;
28984a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2899af69d88dSmrg      if ((ctx->API != API_OPENGL_COMPAT ||
2900af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
2901af69d88dSmrg          && ctx->API != API_OPENGL_CORE
2902af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
2903af69d88dSmrg         goto invalid_pname_enum;
29044a49301eSmrg      }
29053464ebd5Sriastradh      else if (att->Type == GL_NONE) {
29063464ebd5Sriastradh         _mesa_error(ctx, err,
29073464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
29083464ebd5Sriastradh      }
29094a49301eSmrg      else {
2910af69d88dSmrg         mesa_format format = att->Renderbuffer->Format;
2911af69d88dSmrg
2912af69d88dSmrg         /* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES
2913af69d88dSmrg          * 3.0.1 spec says:
2914af69d88dSmrg          *
2915af69d88dSmrg          *     "If pname is FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE.... If
2916af69d88dSmrg          *     attachment is DEPTH_STENCIL_ATTACHMENT the query will fail and
2917af69d88dSmrg          *     generate an INVALID_OPERATION error.
2918af69d88dSmrg          */
2919af69d88dSmrg         if (_mesa_is_gles3(ctx) &&
2920af69d88dSmrg             attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2921af69d88dSmrg            _mesa_error(ctx, GL_INVALID_OPERATION,
2922af69d88dSmrg                        "glGetFramebufferAttachmentParameteriv(cannot query "
2923af69d88dSmrg                        "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of "
2924af69d88dSmrg                        "GL_DEPTH_STENCIL_ATTACHMENT");
2925af69d88dSmrg            return;
2926af69d88dSmrg         }
2927af69d88dSmrg
2928af69d88dSmrg         if (format == MESA_FORMAT_S_UINT8) {
29294a49301eSmrg            /* special cases */
29304a49301eSmrg            *params = GL_INDEX;
29314a49301eSmrg         }
2932af69d88dSmrg         else if (format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) {
2933af69d88dSmrg            /* depends on the attachment parameter */
2934af69d88dSmrg            if (attachment == GL_STENCIL_ATTACHMENT) {
2935af69d88dSmrg               *params = GL_INDEX;
2936af69d88dSmrg            }
2937af69d88dSmrg            else {
2938af69d88dSmrg               *params = GL_FLOAT;
2939af69d88dSmrg            }
2940af69d88dSmrg         }
29414a49301eSmrg         else {
29424a49301eSmrg            *params = _mesa_get_format_datatype(format);
29434a49301eSmrg         }
29444a49301eSmrg      }
29454a49301eSmrg      return;
29464a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
29474a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
29484a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
29494a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
29504a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
29514a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2952af69d88dSmrg      if ((!_mesa_is_desktop_gl(ctx) ||
2953af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
2954af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
2955af69d88dSmrg         goto invalid_pname_enum;
29564a49301eSmrg      }
29573464ebd5Sriastradh      else if (att->Type == GL_NONE) {
29583464ebd5Sriastradh         _mesa_error(ctx, err,
29593464ebd5Sriastradh                     "glGetFramebufferAttachmentParameterivEXT(pname)");
29603464ebd5Sriastradh      }
29614a49301eSmrg      else if (att->Texture) {
29624a49301eSmrg         const struct gl_texture_image *texImage =
29634a49301eSmrg            _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
29644a49301eSmrg                                   att->TextureLevel);
29654a49301eSmrg         if (texImage) {
29664a49301eSmrg            *params = get_component_bits(pname, texImage->_BaseFormat,
29674a49301eSmrg                                         texImage->TexFormat);
29684a49301eSmrg         }
29694a49301eSmrg         else {
29704a49301eSmrg            *params = 0;
29714a49301eSmrg         }
29724a49301eSmrg      }
29734a49301eSmrg      else if (att->Renderbuffer) {
29744a49301eSmrg         *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
29754a49301eSmrg                                      att->Renderbuffer->Format);
29764a49301eSmrg      }
29774a49301eSmrg      else {
29783464ebd5Sriastradh         _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:"
29793464ebd5Sriastradh                       " invalid FBO attachment structure");
29804a49301eSmrg      }
29814a49301eSmrg      return;
2982af69d88dSmrg   case GL_FRAMEBUFFER_ATTACHMENT_LAYERED:
2983af69d88dSmrg      if (!_mesa_has_geometry_shaders(ctx)) {
2984af69d88dSmrg         goto invalid_pname_enum;
2985af69d88dSmrg      } else if (att->Type == GL_TEXTURE) {
2986af69d88dSmrg         *params = att->Layered;
2987af69d88dSmrg      } else if (att->Type == GL_NONE) {
2988af69d88dSmrg         _mesa_error(ctx, err,
2989af69d88dSmrg                     "glGetFramebufferAttachmentParameteriv(pname)");
2990af69d88dSmrg      } else {
2991af69d88dSmrg         goto invalid_pname_enum;
2992af69d88dSmrg      }
29937117f1b4Smrg      return;
2994af69d88dSmrg   default:
2995af69d88dSmrg      goto invalid_pname_enum;
29967117f1b4Smrg   }
2997af69d88dSmrg
2998af69d88dSmrg   return;
2999af69d88dSmrg
3000af69d88dSmrginvalid_pname_enum:
3001af69d88dSmrg   _mesa_error(ctx, GL_INVALID_ENUM,
3002af69d88dSmrg               "glGetFramebufferAttachmentParameteriv(pname)");
3003af69d88dSmrg   return;
30047117f1b4Smrg}
30057117f1b4Smrg
30067117f1b4Smrg
3007af69d88dSmrgstatic void
3008af69d88dSmrginvalidate_framebuffer_storage(GLenum target, GLsizei numAttachments,
3009af69d88dSmrg                               const GLenum *attachments, GLint x, GLint y,
3010af69d88dSmrg                               GLsizei width, GLsizei height, const char *name)
30117117f1b4Smrg{
3012af69d88dSmrg   int i;
3013af69d88dSmrg   struct gl_framebuffer *fb;
30147117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
30157117f1b4Smrg
3016af69d88dSmrg   fb = get_framebuffer_target(ctx, target);
3017af69d88dSmrg   if (!fb) {
3018af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", name);
30197117f1b4Smrg      return;
30207117f1b4Smrg   }
30217117f1b4Smrg
3022af69d88dSmrg   if (numAttachments < 0) {
3023af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
3024af69d88dSmrg                  "%s(numAttachments < 0)", name);
30254a49301eSmrg      return;
30264a49301eSmrg   }
30277117f1b4Smrg
3028af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
3029af69d88dSmrg    *
3030af69d88dSmrg    *     "If an attachment is specified that does not exist in the
3031af69d88dSmrg    *     framebuffer bound to <target>, it is ignored."
3032af69d88dSmrg    *
3033af69d88dSmrg    * It also says:
3034af69d88dSmrg    *
3035af69d88dSmrg    *     "If <attachments> contains COLOR_ATTACHMENTm and m is greater than
3036af69d88dSmrg    *     or equal to the value of MAX_COLOR_ATTACHMENTS, then the error
3037af69d88dSmrg    *     INVALID_OPERATION is generated."
3038af69d88dSmrg    *
3039af69d88dSmrg    * No mention is made of GL_AUXi being out of range.  Therefore, we allow
3040af69d88dSmrg    * any enum that can be allowed by the API (OpenGL ES 3.0 has a different
3041af69d88dSmrg    * set of retrictions).
3042af69d88dSmrg    */
3043af69d88dSmrg   for (i = 0; i < numAttachments; i++) {
3044af69d88dSmrg      if (_mesa_is_winsys_fbo(fb)) {
3045af69d88dSmrg         switch (attachments[i]) {
3046af69d88dSmrg         case GL_ACCUM:
3047af69d88dSmrg         case GL_AUX0:
3048af69d88dSmrg         case GL_AUX1:
3049af69d88dSmrg         case GL_AUX2:
3050af69d88dSmrg         case GL_AUX3:
3051af69d88dSmrg            /* Accumulation buffers and auxilary buffers were removed in
3052af69d88dSmrg             * OpenGL 3.1, and they never existed in OpenGL ES.
3053af69d88dSmrg             */
3054af69d88dSmrg            if (ctx->API != API_OPENGL_COMPAT)
3055af69d88dSmrg               goto invalid_enum;
3056af69d88dSmrg            break;
3057af69d88dSmrg         case GL_COLOR:
3058af69d88dSmrg         case GL_DEPTH:
3059af69d88dSmrg         case GL_STENCIL:
3060af69d88dSmrg            break;
3061af69d88dSmrg         case GL_BACK_LEFT:
3062af69d88dSmrg         case GL_BACK_RIGHT:
3063af69d88dSmrg         case GL_FRONT_LEFT:
3064af69d88dSmrg         case GL_FRONT_RIGHT:
3065af69d88dSmrg            if (!_mesa_is_desktop_gl(ctx))
3066af69d88dSmrg               goto invalid_enum;
3067af69d88dSmrg            break;
3068af69d88dSmrg         default:
3069af69d88dSmrg            goto invalid_enum;
3070af69d88dSmrg         }
3071af69d88dSmrg      } else {
3072af69d88dSmrg         switch (attachments[i]) {
3073af69d88dSmrg         case GL_DEPTH_ATTACHMENT:
3074af69d88dSmrg         case GL_STENCIL_ATTACHMENT:
3075af69d88dSmrg            break;
3076af69d88dSmrg         case GL_COLOR_ATTACHMENT0:
3077af69d88dSmrg         case GL_COLOR_ATTACHMENT1:
3078af69d88dSmrg         case GL_COLOR_ATTACHMENT2:
3079af69d88dSmrg         case GL_COLOR_ATTACHMENT3:
3080af69d88dSmrg         case GL_COLOR_ATTACHMENT4:
3081af69d88dSmrg         case GL_COLOR_ATTACHMENT5:
3082af69d88dSmrg         case GL_COLOR_ATTACHMENT6:
3083af69d88dSmrg         case GL_COLOR_ATTACHMENT7:
3084af69d88dSmrg         case GL_COLOR_ATTACHMENT8:
3085af69d88dSmrg         case GL_COLOR_ATTACHMENT9:
3086af69d88dSmrg         case GL_COLOR_ATTACHMENT10:
3087af69d88dSmrg         case GL_COLOR_ATTACHMENT11:
3088af69d88dSmrg         case GL_COLOR_ATTACHMENT12:
3089af69d88dSmrg         case GL_COLOR_ATTACHMENT13:
3090af69d88dSmrg         case GL_COLOR_ATTACHMENT14:
3091af69d88dSmrg         case GL_COLOR_ATTACHMENT15: {
3092af69d88dSmrg            unsigned k = attachments[i] - GL_COLOR_ATTACHMENT0;
3093af69d88dSmrg            if (k >= ctx->Const.MaxColorAttachments) {
3094af69d88dSmrg               _mesa_error(ctx, GL_INVALID_OPERATION,
3095af69d88dSmrg                           "%s(attachment >= max. color attachments)", name);
3096af69d88dSmrg               return;
3097af69d88dSmrg            }
3098af69d88dSmrg            break;
3099af69d88dSmrg         }
3100af69d88dSmrg         default:
3101af69d88dSmrg            goto invalid_enum;
3102af69d88dSmrg         }
3103af69d88dSmrg      }
31043464ebd5Sriastradh   }
31053464ebd5Sriastradh
3106af69d88dSmrg   /* We don't actually do anything for this yet.  Just return after
3107af69d88dSmrg    * validating the parameters and generating the required errors.
3108af69d88dSmrg    */
3109af69d88dSmrg   return;
31107117f1b4Smrg
3111af69d88dSmrginvalid_enum:
3112af69d88dSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(attachment)", name);
3113af69d88dSmrg   return;
3114af69d88dSmrg}
31157117f1b4Smrg
31164a49301eSmrg
3117af69d88dSmrgvoid GLAPIENTRY
3118af69d88dSmrg_mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
3119af69d88dSmrg                               const GLenum *attachments, GLint x, GLint y,
3120af69d88dSmrg                               GLsizei width, GLsizei height)
31214a49301eSmrg{
3122af69d88dSmrg   invalidate_framebuffer_storage(target, numAttachments, attachments,
3123af69d88dSmrg                                  x, y, width, height,
3124af69d88dSmrg                                  "glInvalidateSubFramebuffer");
31254a49301eSmrg}
31264a49301eSmrg
31274a49301eSmrg
31287117f1b4Smrgvoid GLAPIENTRY
3129af69d88dSmrg_mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments,
3130af69d88dSmrg                            const GLenum *attachments)
31317117f1b4Smrg{
3132af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
3133af69d88dSmrg    *
3134af69d88dSmrg    *     "The command
3135af69d88dSmrg    *
3136af69d88dSmrg    *        void InvalidateFramebuffer(enum target,
3137af69d88dSmrg    *                                   sizei numAttachments,
3138af69d88dSmrg    *                                   const enum *attachments);
3139af69d88dSmrg    *
3140af69d88dSmrg    *     is equivalent to the command InvalidateSubFramebuffer with <x>, <y>,
3141af69d88dSmrg    *     <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>,
3142af69d88dSmrg    *     <MAX_VIEWPORT_DIMS[1]> respectively."
3143af69d88dSmrg    */
3144af69d88dSmrg   invalidate_framebuffer_storage(target, numAttachments, attachments,
3145af69d88dSmrg                                  0, 0,
3146af69d88dSmrg                                  MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT,
3147af69d88dSmrg                                  "glInvalidateFramebuffer");
3148af69d88dSmrg}
31494a49301eSmrg
31503464ebd5Sriastradh
3151af69d88dSmrgvoid GLAPIENTRY
3152af69d88dSmrg_mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments,
3153af69d88dSmrg                            const GLenum *attachments)
3154af69d88dSmrg{
3155af69d88dSmrg   struct gl_framebuffer *fb;
3156af69d88dSmrg   GLint i;
31573464ebd5Sriastradh
3158af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
31597117f1b4Smrg
3160af69d88dSmrg   fb = get_framebuffer_target(ctx, target);
3161af69d88dSmrg   if (!fb) {
3162af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
3163af69d88dSmrg         "glDiscardFramebufferEXT(target %s)",
3164af69d88dSmrg         _mesa_lookup_enum_by_nr(target));
31654a49301eSmrg      return;
31664a49301eSmrg   }
31674a49301eSmrg
3168af69d88dSmrg   if (numAttachments < 0) {
3169af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
3170af69d88dSmrg                  "glDiscardFramebufferEXT(numAttachments < 0)");
31717117f1b4Smrg      return;
31727117f1b4Smrg   }
31737117f1b4Smrg
3174af69d88dSmrg   for (i = 0; i < numAttachments; i++) {
3175af69d88dSmrg      switch (attachments[i]) {
3176af69d88dSmrg      case GL_COLOR:
3177af69d88dSmrg      case GL_DEPTH:
3178af69d88dSmrg      case GL_STENCIL:
3179af69d88dSmrg         if (_mesa_is_user_fbo(fb))
3180af69d88dSmrg            goto invalid_enum;
3181af69d88dSmrg         break;
3182af69d88dSmrg      case GL_COLOR_ATTACHMENT0:
3183af69d88dSmrg      case GL_DEPTH_ATTACHMENT:
3184af69d88dSmrg      case GL_STENCIL_ATTACHMENT:
3185af69d88dSmrg         if (_mesa_is_winsys_fbo(fb))
3186af69d88dSmrg            goto invalid_enum;
3187af69d88dSmrg         break;
3188af69d88dSmrg      default:
3189af69d88dSmrg         goto invalid_enum;
31904a49301eSmrg      }
31914a49301eSmrg   }
31924a49301eSmrg
3193af69d88dSmrg   if (ctx->Driver.DiscardFramebuffer)
3194af69d88dSmrg      ctx->Driver.DiscardFramebuffer(ctx, target, numAttachments, attachments);
31953464ebd5Sriastradh
3196af69d88dSmrg   return;
31973464ebd5Sriastradh
3198af69d88dSmrginvalid_enum:
3199af69d88dSmrg   _mesa_error(ctx, GL_INVALID_ENUM,
3200af69d88dSmrg               "glDiscardFramebufferEXT(attachment %s)",
3201af69d88dSmrg              _mesa_lookup_enum_by_nr(attachments[i]));
32023464ebd5Sriastradh}
3203