fbobject.c revision 01e04c3f
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"
3801e04c3fSmrg#include "debug_output.h"
394a49301eSmrg#include "enums.h"
407117f1b4Smrg#include "fbobject.h"
414a49301eSmrg#include "formats.h"
427117f1b4Smrg#include "framebuffer.h"
43af69d88dSmrg#include "glformats.h"
447117f1b4Smrg#include "hash.h"
454a49301eSmrg#include "macros.h"
46af69d88dSmrg#include "multisample.h"
473464ebd5Sriastradh#include "mtypes.h"
487117f1b4Smrg#include "renderbuffer.h"
497117f1b4Smrg#include "state.h"
507117f1b4Smrg#include "teximage.h"
517117f1b4Smrg#include "texobj.h"
524a49301eSmrg
534a49301eSmrg
547117f1b4Smrg/**
557117f1b4Smrg * Notes:
567117f1b4Smrg *
577117f1b4Smrg * None of the GL_EXT_framebuffer_object functions are compiled into
587117f1b4Smrg * display lists.
597117f1b4Smrg */
607117f1b4Smrg
617117f1b4Smrg
627117f1b4Smrg
637117f1b4Smrg/*
647117f1b4Smrg * When glGenRender/FramebuffersEXT() is called we insert pointers to
657117f1b4Smrg * these placeholder objects into the hash table.
667117f1b4Smrg * Later, when the object ID is first bound, we replace the placeholder
677117f1b4Smrg * with the real frame/renderbuffer.
687117f1b4Smrg */
697117f1b4Smrgstatic struct gl_framebuffer DummyFramebuffer;
707117f1b4Smrgstatic struct gl_renderbuffer DummyRenderbuffer;
717117f1b4Smrg
723464ebd5Sriastradh/* We bind this framebuffer when applications pass a NULL
733464ebd5Sriastradh * drawable/surface in make current. */
743464ebd5Sriastradhstatic struct gl_framebuffer IncompleteFramebuffer;
757117f1b4Smrg
763464ebd5Sriastradh
77c1f859d4Smrgstatic void
78af69d88dSmrgdelete_dummy_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
79c1f859d4Smrg{
80c1f859d4Smrg   /* no op */
81c1f859d4Smrg}
82c1f859d4Smrg
83c1f859d4Smrgstatic void
84c1f859d4Smrgdelete_dummy_framebuffer(struct gl_framebuffer *fb)
85c1f859d4Smrg{
86c1f859d4Smrg   /* no op */
87c1f859d4Smrg}
88c1f859d4Smrg
89c1f859d4Smrg
90c1f859d4Smrgvoid
913464ebd5Sriastradh_mesa_init_fbobjects(struct gl_context *ctx)
92c1f859d4Smrg{
9301e04c3fSmrg   simple_mtx_init(&DummyFramebuffer.Mutex, mtx_plain);
9401e04c3fSmrg   simple_mtx_init(&DummyRenderbuffer.Mutex, mtx_plain);
9501e04c3fSmrg   simple_mtx_init(&IncompleteFramebuffer.Mutex, mtx_plain);
96c1f859d4Smrg   DummyFramebuffer.Delete = delete_dummy_framebuffer;
97c1f859d4Smrg   DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
983464ebd5Sriastradh   IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
99c1f859d4Smrg}
100c1f859d4Smrg
1013464ebd5Sriastradhstruct gl_framebuffer *
1023464ebd5Sriastradh_mesa_get_incomplete_framebuffer(void)
1033464ebd5Sriastradh{
1043464ebd5Sriastradh   return &IncompleteFramebuffer;
1053464ebd5Sriastradh}
106c1f859d4Smrg
1077117f1b4Smrg/**
1087117f1b4Smrg * Helper routine for getting a gl_renderbuffer.
1097117f1b4Smrg */
1107117f1b4Smrgstruct gl_renderbuffer *
1113464ebd5Sriastradh_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
1127117f1b4Smrg{
1137117f1b4Smrg   struct gl_renderbuffer *rb;
1147117f1b4Smrg
1157117f1b4Smrg   if (id == 0)
1167117f1b4Smrg      return NULL;
1177117f1b4Smrg
1187117f1b4Smrg   rb = (struct gl_renderbuffer *)
1197117f1b4Smrg      _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
1207117f1b4Smrg   return rb;
1217117f1b4Smrg}
1227117f1b4Smrg
1237117f1b4Smrg
12401e04c3fSmrg/**
12501e04c3fSmrg * A convenience function for direct state access that throws
12601e04c3fSmrg * GL_INVALID_OPERATION if the renderbuffer doesn't exist.
12701e04c3fSmrg */
12801e04c3fSmrgstruct gl_renderbuffer *
12901e04c3fSmrg_mesa_lookup_renderbuffer_err(struct gl_context *ctx, GLuint id,
13001e04c3fSmrg                              const char *func)
13101e04c3fSmrg{
13201e04c3fSmrg   struct gl_renderbuffer *rb;
13301e04c3fSmrg
13401e04c3fSmrg   rb = _mesa_lookup_renderbuffer(ctx, id);
13501e04c3fSmrg   if (!rb || rb == &DummyRenderbuffer) {
13601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
13701e04c3fSmrg                  "%s(non-existent renderbuffer %u)", func, id);
13801e04c3fSmrg      return NULL;
13901e04c3fSmrg   }
14001e04c3fSmrg
14101e04c3fSmrg   return rb;
14201e04c3fSmrg}
14301e04c3fSmrg
14401e04c3fSmrg
1457117f1b4Smrg/**
1467117f1b4Smrg * Helper routine for getting a gl_framebuffer.
1477117f1b4Smrg */
1487117f1b4Smrgstruct gl_framebuffer *
1493464ebd5Sriastradh_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
1507117f1b4Smrg{
1517117f1b4Smrg   struct gl_framebuffer *fb;
1527117f1b4Smrg
1537117f1b4Smrg   if (id == 0)
1547117f1b4Smrg      return NULL;
1557117f1b4Smrg
1567117f1b4Smrg   fb = (struct gl_framebuffer *)
1577117f1b4Smrg      _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
1587117f1b4Smrg   return fb;
1597117f1b4Smrg}
1607117f1b4Smrg
1617117f1b4Smrg
16201e04c3fSmrg/**
16301e04c3fSmrg * A convenience function for direct state access that throws
16401e04c3fSmrg * GL_INVALID_OPERATION if the framebuffer doesn't exist.
16501e04c3fSmrg */
16601e04c3fSmrgstruct gl_framebuffer *
16701e04c3fSmrg_mesa_lookup_framebuffer_err(struct gl_context *ctx, GLuint id,
16801e04c3fSmrg                             const char *func)
16901e04c3fSmrg{
17001e04c3fSmrg   struct gl_framebuffer *fb;
17101e04c3fSmrg
17201e04c3fSmrg   fb = _mesa_lookup_framebuffer(ctx, id);
17301e04c3fSmrg   if (!fb || fb == &DummyFramebuffer) {
17401e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
17501e04c3fSmrg                  "%s(non-existent framebuffer %u)", func, id);
17601e04c3fSmrg      return NULL;
17701e04c3fSmrg   }
17801e04c3fSmrg
17901e04c3fSmrg   return fb;
18001e04c3fSmrg}
18101e04c3fSmrg
18201e04c3fSmrg
1834a49301eSmrg/**
1844a49301eSmrg * Mark the given framebuffer as invalid.  This will force the
1854a49301eSmrg * test for framebuffer completeness to be done before the framebuffer
1864a49301eSmrg * is used.
1874a49301eSmrg */
1884a49301eSmrgstatic void
1894a49301eSmrginvalidate_framebuffer(struct gl_framebuffer *fb)
1904a49301eSmrg{
1914a49301eSmrg   fb->_Status = 0; /* "indeterminate" */
1924a49301eSmrg}
1934a49301eSmrg
1944a49301eSmrg
1953464ebd5Sriastradh/**
1963464ebd5Sriastradh * Return the gl_framebuffer object which corresponds to the given
1973464ebd5Sriastradh * framebuffer target, such as GL_DRAW_FRAMEBUFFER.
1983464ebd5Sriastradh * Check support for GL_EXT_framebuffer_blit to determine if certain
1993464ebd5Sriastradh * targets are legal.
2003464ebd5Sriastradh * \return gl_framebuffer pointer or NULL if target is illegal
2013464ebd5Sriastradh */
2023464ebd5Sriastradhstatic struct gl_framebuffer *
2033464ebd5Sriastradhget_framebuffer_target(struct gl_context *ctx, GLenum target)
2043464ebd5Sriastradh{
205af69d88dSmrg   bool have_fb_blit = _mesa_is_gles3(ctx) || _mesa_is_desktop_gl(ctx);
2063464ebd5Sriastradh   switch (target) {
2073464ebd5Sriastradh   case GL_DRAW_FRAMEBUFFER:
208af69d88dSmrg      return have_fb_blit ? ctx->DrawBuffer : NULL;
2093464ebd5Sriastradh   case GL_READ_FRAMEBUFFER:
210af69d88dSmrg      return have_fb_blit ? ctx->ReadBuffer : NULL;
2113464ebd5Sriastradh   case GL_FRAMEBUFFER_EXT:
2123464ebd5Sriastradh      return ctx->DrawBuffer;
2133464ebd5Sriastradh   default:
2143464ebd5Sriastradh      return NULL;
2153464ebd5Sriastradh   }
2163464ebd5Sriastradh}
2173464ebd5Sriastradh
2183464ebd5Sriastradh
2197117f1b4Smrg/**
2207117f1b4Smrg * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
2217117f1b4Smrg * gl_renderbuffer_attachment object.
2223464ebd5Sriastradh * This function is only used for user-created FB objects, not the
2233464ebd5Sriastradh * default / window-system FB object.
2244a49301eSmrg * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
2254a49301eSmrg * the depth buffer attachment point.
22601e04c3fSmrg * Returns if the attachment is a GL_COLOR_ATTACHMENTm_EXT on
22701e04c3fSmrg * is_color_attachment, because several callers would return different errors
22801e04c3fSmrg * if they don't find the attachment.
2297117f1b4Smrg */
230af69d88dSmrgstatic struct gl_renderbuffer_attachment *
231af69d88dSmrgget_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
23201e04c3fSmrg               GLenum attachment, bool *is_color_attachment)
2337117f1b4Smrg{
2347117f1b4Smrg   GLuint i;
2357117f1b4Smrg
236af69d88dSmrg   assert(_mesa_is_user_fbo(fb));
2373464ebd5Sriastradh
23801e04c3fSmrg   if (is_color_attachment)
23901e04c3fSmrg      *is_color_attachment = false;
24001e04c3fSmrg
2417117f1b4Smrg   switch (attachment) {
2427117f1b4Smrg   case GL_COLOR_ATTACHMENT0_EXT:
2437117f1b4Smrg   case GL_COLOR_ATTACHMENT1_EXT:
2447117f1b4Smrg   case GL_COLOR_ATTACHMENT2_EXT:
2457117f1b4Smrg   case GL_COLOR_ATTACHMENT3_EXT:
2467117f1b4Smrg   case GL_COLOR_ATTACHMENT4_EXT:
2477117f1b4Smrg   case GL_COLOR_ATTACHMENT5_EXT:
2487117f1b4Smrg   case GL_COLOR_ATTACHMENT6_EXT:
2497117f1b4Smrg   case GL_COLOR_ATTACHMENT7_EXT:
2507117f1b4Smrg   case GL_COLOR_ATTACHMENT8_EXT:
2517117f1b4Smrg   case GL_COLOR_ATTACHMENT9_EXT:
2527117f1b4Smrg   case GL_COLOR_ATTACHMENT10_EXT:
2537117f1b4Smrg   case GL_COLOR_ATTACHMENT11_EXT:
2547117f1b4Smrg   case GL_COLOR_ATTACHMENT12_EXT:
2557117f1b4Smrg   case GL_COLOR_ATTACHMENT13_EXT:
2567117f1b4Smrg   case GL_COLOR_ATTACHMENT14_EXT:
2577117f1b4Smrg   case GL_COLOR_ATTACHMENT15_EXT:
25801e04c3fSmrg      if (is_color_attachment)
25901e04c3fSmrg         *is_color_attachment = true;
260af69d88dSmrg      /* Only OpenGL ES 1.x forbids color attachments other than
261af69d88dSmrg       * GL_COLOR_ATTACHMENT0.  For all other APIs the limit set by the
262af69d88dSmrg       * hardware is used.
263af69d88dSmrg       */
2647117f1b4Smrg      i = attachment - GL_COLOR_ATTACHMENT0_EXT;
265af69d88dSmrg      if (i >= ctx->Const.MaxColorAttachments
26601e04c3fSmrg          || (i > 0 && ctx->API == API_OPENGLES)) {
26701e04c3fSmrg         return NULL;
2687117f1b4Smrg      }
2697117f1b4Smrg      return &fb->Attachment[BUFFER_COLOR0 + i];
2704a49301eSmrg   case GL_DEPTH_STENCIL_ATTACHMENT:
271af69d88dSmrg      if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
27201e04c3fSmrg         return NULL;
2734a49301eSmrg      /* fall-through */
2747117f1b4Smrg   case GL_DEPTH_ATTACHMENT_EXT:
2757117f1b4Smrg      return &fb->Attachment[BUFFER_DEPTH];
2767117f1b4Smrg   case GL_STENCIL_ATTACHMENT_EXT:
2777117f1b4Smrg      return &fb->Attachment[BUFFER_STENCIL];
2787117f1b4Smrg   default:
2797117f1b4Smrg      return NULL;
2807117f1b4Smrg   }
2817117f1b4Smrg}
2827117f1b4Smrg
2837117f1b4Smrg
2843464ebd5Sriastradh/**
2853464ebd5Sriastradh * As above, but only used for getting attachments of the default /
2863464ebd5Sriastradh * window-system framebuffer (not user-created framebuffer objects).
2873464ebd5Sriastradh */
2883464ebd5Sriastradhstatic struct gl_renderbuffer_attachment *
28901e04c3fSmrgget_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
29001e04c3fSmrg                   GLenum attachment)
2913464ebd5Sriastradh{
292af69d88dSmrg   assert(_mesa_is_winsys_fbo(fb));
293af69d88dSmrg
294af69d88dSmrg   if (_mesa_is_gles3(ctx)) {
295af69d88dSmrg      assert(attachment == GL_BACK ||
296af69d88dSmrg             attachment == GL_DEPTH ||
297af69d88dSmrg             attachment == GL_STENCIL);
298af69d88dSmrg      switch (attachment) {
299af69d88dSmrg      case GL_BACK:
300af69d88dSmrg         /* Since there is no stereo rendering in ES 3.0, only return the
301af69d88dSmrg          * LEFT bits.
302af69d88dSmrg          */
303af69d88dSmrg         if (ctx->DrawBuffer->Visual.doubleBufferMode)
304af69d88dSmrg            return &fb->Attachment[BUFFER_BACK_LEFT];
305af69d88dSmrg         return &fb->Attachment[BUFFER_FRONT_LEFT];
306af69d88dSmrg      case GL_DEPTH:
30701e04c3fSmrg         return &fb->Attachment[BUFFER_DEPTH];
308af69d88dSmrg      case GL_STENCIL:
309af69d88dSmrg         return &fb->Attachment[BUFFER_STENCIL];
310af69d88dSmrg      }
311af69d88dSmrg   }
3123464ebd5Sriastradh
3133464ebd5Sriastradh   switch (attachment) {
3143464ebd5Sriastradh   case GL_FRONT_LEFT:
31501e04c3fSmrg      /* Front buffers can be allocated on the first use, but
31601e04c3fSmrg       * glGetFramebufferAttachmentParameteriv must work even if that
31701e04c3fSmrg       * allocation hasn't happened yet. In such case, use the back buffer,
31801e04c3fSmrg       * which should be the same.
31901e04c3fSmrg       */
32001e04c3fSmrg      if (fb->Attachment[BUFFER_FRONT_LEFT].Type == GL_NONE)
32101e04c3fSmrg         return &fb->Attachment[BUFFER_BACK_LEFT];
32201e04c3fSmrg      else
32301e04c3fSmrg         return &fb->Attachment[BUFFER_FRONT_LEFT];
3243464ebd5Sriastradh   case GL_FRONT_RIGHT:
32501e04c3fSmrg      /* Same as above. */
32601e04c3fSmrg      if (fb->Attachment[BUFFER_FRONT_RIGHT].Type == GL_NONE)
32701e04c3fSmrg         return &fb->Attachment[BUFFER_BACK_RIGHT];
32801e04c3fSmrg      else
32901e04c3fSmrg         return &fb->Attachment[BUFFER_FRONT_RIGHT];
3303464ebd5Sriastradh   case GL_BACK_LEFT:
3313464ebd5Sriastradh      return &fb->Attachment[BUFFER_BACK_LEFT];
3323464ebd5Sriastradh   case GL_BACK_RIGHT:
3333464ebd5Sriastradh      return &fb->Attachment[BUFFER_BACK_RIGHT];
33401e04c3fSmrg   case GL_BACK:
33501e04c3fSmrg      /* The ARB_ES3_1_compatibility spec says:
33601e04c3fSmrg       *
33701e04c3fSmrg       *    "Since this command can only query a single framebuffer
33801e04c3fSmrg       *     attachment, BACK is equivalent to BACK_LEFT."
33901e04c3fSmrg       */
34001e04c3fSmrg      if (ctx->Extensions.ARB_ES3_1_compatibility)
34101e04c3fSmrg         return &fb->Attachment[BUFFER_BACK_LEFT];
34201e04c3fSmrg      return NULL;
3433464ebd5Sriastradh   case GL_AUX0:
3443464ebd5Sriastradh      if (fb->Visual.numAuxBuffers == 1) {
3453464ebd5Sriastradh         return &fb->Attachment[BUFFER_AUX0];
3463464ebd5Sriastradh      }
3473464ebd5Sriastradh      return NULL;
348af69d88dSmrg
349af69d88dSmrg   /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says:
350af69d88dSmrg    *
351af69d88dSmrg    *     "If the default framebuffer is bound to target, then attachment must
352af69d88dSmrg    *     be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi,
353af69d88dSmrg    *     identifying a color buffer; DEPTH, identifying the depth buffer; or
354af69d88dSmrg    *     STENCIL, identifying the stencil buffer."
355af69d88dSmrg    *
356af69d88dSmrg    * Revision #34 of the ARB_framebuffer_object spec has essentially the same
357af69d88dSmrg    * language.  However, revision #33 of the ARB_framebuffer_object spec
358af69d88dSmrg    * says:
359af69d88dSmrg    *
360af69d88dSmrg    *     "If the default framebuffer is bound to <target>, then <attachment>
361af69d88dSmrg    *     must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi,
362af69d88dSmrg    *     DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the
363af69d88dSmrg    *     depth buffer, or the stencil buffer, and <pname> may be
364af69d88dSmrg    *     FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or
365af69d88dSmrg    *     FRAMEBUFFER_ATTACHMENT_OBJECT_NAME."
366af69d88dSmrg    *
367af69d88dSmrg    * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed
368af69d88dSmrg    * from glext.h, so shipping apps should not use those values.
369af69d88dSmrg    *
370af69d88dSmrg    * Note that neither EXT_framebuffer_object nor OES_framebuffer_object
371af69d88dSmrg    * support queries of the window system FBO.
372af69d88dSmrg    */
373af69d88dSmrg   case GL_DEPTH:
3743464ebd5Sriastradh      return &fb->Attachment[BUFFER_DEPTH];
375af69d88dSmrg   case GL_STENCIL:
3763464ebd5Sriastradh      return &fb->Attachment[BUFFER_STENCIL];
3773464ebd5Sriastradh   default:
3783464ebd5Sriastradh      return NULL;
3793464ebd5Sriastradh   }
3803464ebd5Sriastradh}
3813464ebd5Sriastradh
3823464ebd5Sriastradh
3833464ebd5Sriastradh
3847117f1b4Smrg/**
3857117f1b4Smrg * Remove any texture or renderbuffer attached to the given attachment
3867117f1b4Smrg * point.  Update reference counts, etc.
3877117f1b4Smrg */
388af69d88dSmrgstatic void
389af69d88dSmrgremove_attachment(struct gl_context *ctx,
390af69d88dSmrg                  struct gl_renderbuffer_attachment *att)
3917117f1b4Smrg{
392af69d88dSmrg   struct gl_renderbuffer *rb = att->Renderbuffer;
393af69d88dSmrg
394af69d88dSmrg   /* tell driver that we're done rendering to this texture. */
395af69d88dSmrg   if (rb && rb->NeedsFinishRenderTexture)
396af69d88dSmrg      ctx->Driver.FinishRenderTexture(ctx, rb);
397af69d88dSmrg
3987117f1b4Smrg   if (att->Type == GL_TEXTURE) {
39901e04c3fSmrg      assert(att->Texture);
4007117f1b4Smrg      _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
40101e04c3fSmrg      assert(!att->Texture);
4027117f1b4Smrg   }
4037117f1b4Smrg   if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
40401e04c3fSmrg      assert(!att->Texture);
4057117f1b4Smrg      _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
40601e04c3fSmrg      assert(!att->Renderbuffer);
4077117f1b4Smrg   }
4087117f1b4Smrg   att->Type = GL_NONE;
4097117f1b4Smrg   att->Complete = GL_TRUE;
4107117f1b4Smrg}
4117117f1b4Smrg
412af69d88dSmrg/**
413af69d88dSmrg * Verify a couple error conditions that will lead to an incomplete FBO and
414af69d88dSmrg * may cause problems for the driver's RenderTexture path.
415af69d88dSmrg */
416af69d88dSmrgstatic bool
417af69d88dSmrgdriver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att)
418af69d88dSmrg{
419af69d88dSmrg   const struct gl_texture_image *const texImage =
420af69d88dSmrg      att->Texture->Image[att->CubeMapFace][att->TextureLevel];
421af69d88dSmrg
42201e04c3fSmrg   if (!texImage ||
42301e04c3fSmrg       texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0)
424af69d88dSmrg      return false;
425af69d88dSmrg
426af69d88dSmrg   if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY
427af69d88dSmrg        && att->Zoffset >= texImage->Height)
428af69d88dSmrg       || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY
429af69d88dSmrg           && att->Zoffset >= texImage->Depth))
430af69d88dSmrg      return false;
431af69d88dSmrg
432af69d88dSmrg   return true;
433af69d88dSmrg}
434af69d88dSmrg
435af69d88dSmrg/**
436af69d88dSmrg * Create a renderbuffer which will be set up by the driver to wrap the
437af69d88dSmrg * texture image slice.
438af69d88dSmrg *
439af69d88dSmrg * By using a gl_renderbuffer (like user-allocated renderbuffers), drivers get
440af69d88dSmrg * to share most of their framebuffer rendering code between winsys,
441af69d88dSmrg * renderbuffer, and texture attachments.
442af69d88dSmrg *
443af69d88dSmrg * The allocated renderbuffer uses a non-zero Name so that drivers can check
444af69d88dSmrg * it for determining vertical orientation, but we use ~0 to make it fairly
445af69d88dSmrg * unambiguous with actual user (non-texture) renderbuffers.
446af69d88dSmrg */
447af69d88dSmrgvoid
448af69d88dSmrg_mesa_update_texture_renderbuffer(struct gl_context *ctx,
449af69d88dSmrg                                  struct gl_framebuffer *fb,
450af69d88dSmrg                                  struct gl_renderbuffer_attachment *att)
451af69d88dSmrg{
452af69d88dSmrg   struct gl_texture_image *texImage;
453af69d88dSmrg   struct gl_renderbuffer *rb;
454af69d88dSmrg
455af69d88dSmrg   texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
456af69d88dSmrg
457af69d88dSmrg   rb = att->Renderbuffer;
458af69d88dSmrg   if (!rb) {
459af69d88dSmrg      rb = ctx->Driver.NewRenderbuffer(ctx, ~0);
460af69d88dSmrg      if (!rb) {
461af69d88dSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()");
462af69d88dSmrg         return;
463af69d88dSmrg      }
46401e04c3fSmrg      att->Renderbuffer = rb;
465af69d88dSmrg
466af69d88dSmrg      /* This can't get called on a texture renderbuffer, so set it to NULL
467af69d88dSmrg       * for clarity compared to user renderbuffers.
468af69d88dSmrg       */
469af69d88dSmrg      rb->AllocStorage = NULL;
470af69d88dSmrg
471af69d88dSmrg      rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL;
472af69d88dSmrg   }
473af69d88dSmrg
474af69d88dSmrg   if (!texImage)
475af69d88dSmrg      return;
476af69d88dSmrg
477af69d88dSmrg   rb->_BaseFormat = texImage->_BaseFormat;
478af69d88dSmrg   rb->Format = texImage->TexFormat;
479af69d88dSmrg   rb->InternalFormat = texImage->InternalFormat;
480af69d88dSmrg   rb->Width = texImage->Width2;
481af69d88dSmrg   rb->Height = texImage->Height2;
482af69d88dSmrg   rb->Depth = texImage->Depth2;
483af69d88dSmrg   rb->NumSamples = texImage->NumSamples;
48401e04c3fSmrg   rb->NumStorageSamples = texImage->NumSamples;
485af69d88dSmrg   rb->TexImage = texImage;
486af69d88dSmrg
487af69d88dSmrg   if (driver_RenderTexture_is_safe(att))
488af69d88dSmrg      ctx->Driver.RenderTexture(ctx, fb, att);
489af69d88dSmrg}
4907117f1b4Smrg
4917117f1b4Smrg/**
4927117f1b4Smrg * Bind a texture object to an attachment point.
4937117f1b4Smrg * The previous binding, if any, will be removed first.
4947117f1b4Smrg */
495af69d88dSmrgstatic void
496af69d88dSmrgset_texture_attachment(struct gl_context *ctx,
497af69d88dSmrg                       struct gl_framebuffer *fb,
498af69d88dSmrg                       struct gl_renderbuffer_attachment *att,
499af69d88dSmrg                       struct gl_texture_object *texObj,
50001e04c3fSmrg                       GLenum texTarget, GLuint level, GLuint layer,
501af69d88dSmrg                       GLboolean layered)
5027117f1b4Smrg{
503af69d88dSmrg   struct gl_renderbuffer *rb = att->Renderbuffer;
504af69d88dSmrg
505af69d88dSmrg   if (rb && rb->NeedsFinishRenderTexture)
506af69d88dSmrg      ctx->Driver.FinishRenderTexture(ctx, rb);
507af69d88dSmrg
5087117f1b4Smrg   if (att->Texture == texObj) {
5097117f1b4Smrg      /* re-attaching same texture */
51001e04c3fSmrg      assert(att->Type == GL_TEXTURE);
5117117f1b4Smrg   }
5127117f1b4Smrg   else {
5137117f1b4Smrg      /* new attachment */
514af69d88dSmrg      remove_attachment(ctx, att);
5157117f1b4Smrg      att->Type = GL_TEXTURE;
5167117f1b4Smrg      assert(!att->Texture);
5177117f1b4Smrg      _mesa_reference_texobj(&att->Texture, texObj);
5187117f1b4Smrg   }
519af69d88dSmrg   invalidate_framebuffer(fb);
5207117f1b4Smrg
5217117f1b4Smrg   /* always update these fields */
5227117f1b4Smrg   att->TextureLevel = level;
5234a49301eSmrg   att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
52401e04c3fSmrg   att->Zoffset = layer;
525af69d88dSmrg   att->Layered = layered;
5267117f1b4Smrg   att->Complete = GL_FALSE;
5277117f1b4Smrg
528af69d88dSmrg   _mesa_update_texture_renderbuffer(ctx, fb, att);
5297117f1b4Smrg}
5307117f1b4Smrg
5317117f1b4Smrg
5327117f1b4Smrg/**
5337117f1b4Smrg * Bind a renderbuffer to an attachment point.
5347117f1b4Smrg * The previous binding, if any, will be removed first.
5357117f1b4Smrg */
536af69d88dSmrgstatic void
537af69d88dSmrgset_renderbuffer_attachment(struct gl_context *ctx,
538af69d88dSmrg                            struct gl_renderbuffer_attachment *att,
539af69d88dSmrg                            struct gl_renderbuffer *rb)
5407117f1b4Smrg{
5417117f1b4Smrg   /* XXX check if re-doing same attachment, exit early */
542af69d88dSmrg   remove_attachment(ctx, att);
5437117f1b4Smrg   att->Type = GL_RENDERBUFFER_EXT;
5447117f1b4Smrg   att->Texture = NULL; /* just to be safe */
54501e04c3fSmrg   att->Layered = GL_FALSE;
5467117f1b4Smrg   att->Complete = GL_FALSE;
5477117f1b4Smrg   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
5487117f1b4Smrg}
5497117f1b4Smrg
5507117f1b4Smrg
5517117f1b4Smrg/**
5527117f1b4Smrg * Fallback for ctx->Driver.FramebufferRenderbuffer()
5537117f1b4Smrg * Attach a renderbuffer object to a framebuffer object.
5547117f1b4Smrg */
5557117f1b4Smrgvoid
55601e04c3fSmrg_mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx,
55701e04c3fSmrg                                 struct gl_framebuffer *fb,
55801e04c3fSmrg                                 GLenum attachment,
55901e04c3fSmrg                                 struct gl_renderbuffer *rb)
5607117f1b4Smrg{
5617117f1b4Smrg   struct gl_renderbuffer_attachment *att;
5627117f1b4Smrg
56301e04c3fSmrg   simple_mtx_lock(&fb->Mutex);
5647117f1b4Smrg
56501e04c3fSmrg   att = get_attachment(ctx, fb, attachment, NULL);
56601e04c3fSmrg   assert(att);
5677117f1b4Smrg   if (rb) {
568af69d88dSmrg      set_renderbuffer_attachment(ctx, att, rb);
5694a49301eSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
5704a49301eSmrg         /* do stencil attachment here (depth already done above) */
57101e04c3fSmrg         att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL);
5724a49301eSmrg         assert(att);
573af69d88dSmrg         set_renderbuffer_attachment(ctx, att, rb);
5744a49301eSmrg      }
5753464ebd5Sriastradh      rb->AttachedAnytime = GL_TRUE;
5767117f1b4Smrg   }
5777117f1b4Smrg   else {
578af69d88dSmrg      remove_attachment(ctx, att);
579af69d88dSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
580af69d88dSmrg         /* detach stencil (depth was detached above) */
58101e04c3fSmrg         att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL);
582af69d88dSmrg         assert(att);
583af69d88dSmrg         remove_attachment(ctx, att);
584af69d88dSmrg      }
5857117f1b4Smrg   }
5867117f1b4Smrg
5874a49301eSmrg   invalidate_framebuffer(fb);
5884a49301eSmrg
58901e04c3fSmrg   simple_mtx_unlock(&fb->Mutex);
5907117f1b4Smrg}
5917117f1b4Smrg
5927117f1b4Smrg
5933464ebd5Sriastradh/**
5943464ebd5Sriastradh * Fallback for ctx->Driver.ValidateFramebuffer()
5953464ebd5Sriastradh * Check if the renderbuffer's formats are supported by the software
5963464ebd5Sriastradh * renderer.
5973464ebd5Sriastradh * Drivers should probably override this.
5983464ebd5Sriastradh */
5993464ebd5Sriastradhvoid
6003464ebd5Sriastradh_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
6013464ebd5Sriastradh{
6023464ebd5Sriastradh   gl_buffer_index buf;
6033464ebd5Sriastradh   for (buf = 0; buf < BUFFER_COUNT; buf++) {
6043464ebd5Sriastradh      const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer;
6053464ebd5Sriastradh      if (rb) {
6063464ebd5Sriastradh         switch (rb->_BaseFormat) {
6073464ebd5Sriastradh         case GL_ALPHA:
6083464ebd5Sriastradh         case GL_LUMINANCE_ALPHA:
6093464ebd5Sriastradh         case GL_LUMINANCE:
6103464ebd5Sriastradh         case GL_INTENSITY:
6113464ebd5Sriastradh         case GL_RED:
6123464ebd5Sriastradh         case GL_RG:
6133464ebd5Sriastradh            fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
6143464ebd5Sriastradh            return;
6153464ebd5Sriastradh
6163464ebd5Sriastradh         default:
6173464ebd5Sriastradh            switch (rb->Format) {
6183464ebd5Sriastradh            /* XXX This list is likely incomplete. */
619af69d88dSmrg            case MESA_FORMAT_R9G9B9E5_FLOAT:
6203464ebd5Sriastradh               fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
6213464ebd5Sriastradh               return;
6223464ebd5Sriastradh            default:;
6233464ebd5Sriastradh               /* render buffer format is supported by software rendering */
6243464ebd5Sriastradh            }
6253464ebd5Sriastradh         }
6263464ebd5Sriastradh      }
6273464ebd5Sriastradh   }
6283464ebd5Sriastradh}
6293464ebd5Sriastradh
6303464ebd5Sriastradh
631af69d88dSmrg/**
632af69d88dSmrg * Return true if the framebuffer has a combined depth/stencil
633af69d88dSmrg * renderbuffer attached.
634af69d88dSmrg */
635af69d88dSmrgGLboolean
636af69d88dSmrg_mesa_has_depthstencil_combined(const struct gl_framebuffer *fb)
637af69d88dSmrg{
638af69d88dSmrg   const struct gl_renderbuffer_attachment *depth =
639af69d88dSmrg         &fb->Attachment[BUFFER_DEPTH];
640af69d88dSmrg   const struct gl_renderbuffer_attachment *stencil =
641af69d88dSmrg         &fb->Attachment[BUFFER_STENCIL];
642af69d88dSmrg
643af69d88dSmrg   if (depth->Type == stencil->Type) {
644af69d88dSmrg      if (depth->Type == GL_RENDERBUFFER_EXT &&
645af69d88dSmrg          depth->Renderbuffer == stencil->Renderbuffer)
646af69d88dSmrg         return GL_TRUE;
647af69d88dSmrg
648af69d88dSmrg      if (depth->Type == GL_TEXTURE &&
649af69d88dSmrg          depth->Texture == stencil->Texture)
650af69d88dSmrg         return GL_TRUE;
651af69d88dSmrg   }
652af69d88dSmrg
653af69d88dSmrg   return GL_FALSE;
654af69d88dSmrg}
655af69d88dSmrg
656af69d88dSmrg
6574a49301eSmrg/**
6584a49301eSmrg * For debug only.
6594a49301eSmrg */
6604a49301eSmrgstatic void
6614a49301eSmrgatt_incomplete(const char *msg)
6624a49301eSmrg{
663af69d88dSmrg   if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
664af69d88dSmrg      _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
665af69d88dSmrg   }
6664a49301eSmrg}
6674a49301eSmrg
6684a49301eSmrg
6694a49301eSmrg/**
6704a49301eSmrg * For debug only.
6714a49301eSmrg */
6724a49301eSmrgstatic void
673af69d88dSmrgfbo_incomplete(struct gl_context *ctx, const char *msg, int index)
6744a49301eSmrg{
675af69d88dSmrg   static GLuint msg_id;
676af69d88dSmrg
677af69d88dSmrg   _mesa_gl_debug(ctx, &msg_id,
67801e04c3fSmrg                  MESA_DEBUG_SOURCE_API,
679af69d88dSmrg                  MESA_DEBUG_TYPE_OTHER,
680af69d88dSmrg                  MESA_DEBUG_SEVERITY_MEDIUM,
681af69d88dSmrg                  "FBO incomplete: %s [%d]\n", msg, index);
682af69d88dSmrg
683af69d88dSmrg   if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
684af69d88dSmrg      _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
685af69d88dSmrg   }
6864a49301eSmrg}
6874a49301eSmrg
6884a49301eSmrg
6893464ebd5Sriastradh/**
6903464ebd5Sriastradh * Is the given base format a legal format for a color renderbuffer?
6913464ebd5Sriastradh */
6923464ebd5SriastradhGLboolean
6933464ebd5Sriastradh_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
6943464ebd5Sriastradh{
6953464ebd5Sriastradh   switch (baseFormat) {
6963464ebd5Sriastradh   case GL_RGB:
6973464ebd5Sriastradh   case GL_RGBA:
6983464ebd5Sriastradh      return GL_TRUE;
6993464ebd5Sriastradh   case GL_LUMINANCE:
7003464ebd5Sriastradh   case GL_LUMINANCE_ALPHA:
7013464ebd5Sriastradh   case GL_INTENSITY:
7023464ebd5Sriastradh   case GL_ALPHA:
703af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
704af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object;
7053464ebd5Sriastradh   case GL_RED:
7063464ebd5Sriastradh   case GL_RG:
7073464ebd5Sriastradh      return ctx->Extensions.ARB_texture_rg;
7083464ebd5Sriastradh   default:
7093464ebd5Sriastradh      return GL_FALSE;
7103464ebd5Sriastradh   }
7113464ebd5Sriastradh}
7123464ebd5Sriastradh
7133464ebd5Sriastradh
714af69d88dSmrg/**
715af69d88dSmrg * Is the given base format a legal format for a color renderbuffer?
716af69d88dSmrg */
717af69d88dSmrgstatic GLboolean
718af69d88dSmrgis_format_color_renderable(const struct gl_context *ctx, mesa_format format,
719af69d88dSmrg                           GLenum internalFormat)
720af69d88dSmrg{
721af69d88dSmrg   const GLenum baseFormat =
722af69d88dSmrg      _mesa_get_format_base_format(format);
723af69d88dSmrg   GLboolean valid;
724af69d88dSmrg
725af69d88dSmrg   valid = _mesa_is_legal_color_format(ctx, baseFormat);
726af69d88dSmrg   if (!valid || _mesa_is_desktop_gl(ctx)) {
727af69d88dSmrg      return valid;
728af69d88dSmrg   }
729af69d88dSmrg
730af69d88dSmrg   /* Reject additional cases for GLES */
731af69d88dSmrg   switch (internalFormat) {
73201e04c3fSmrg   case GL_R8_SNORM:
73301e04c3fSmrg   case GL_RG8_SNORM:
734af69d88dSmrg   case GL_RGBA8_SNORM:
73501e04c3fSmrg      return _mesa_has_EXT_render_snorm(ctx);
73601e04c3fSmrg   case GL_R16_SNORM:
73701e04c3fSmrg   case GL_RG16_SNORM:
73801e04c3fSmrg   case GL_RGBA16_SNORM:
73901e04c3fSmrg      return _mesa_has_EXT_texture_norm16(ctx) &&
74001e04c3fSmrg             _mesa_has_EXT_render_snorm(ctx);
741af69d88dSmrg   case GL_RGB32F:
742af69d88dSmrg   case GL_RGB32I:
743af69d88dSmrg   case GL_RGB32UI:
744af69d88dSmrg   case GL_RGB16F:
745af69d88dSmrg   case GL_RGB16I:
746af69d88dSmrg   case GL_RGB16UI:
747af69d88dSmrg   case GL_RGB8_SNORM:
748af69d88dSmrg   case GL_RGB8I:
749af69d88dSmrg   case GL_RGB8UI:
750af69d88dSmrg   case GL_SRGB8:
75101e04c3fSmrg   case GL_RGB10:
752af69d88dSmrg   case GL_RGB9_E5:
753af69d88dSmrg      return GL_FALSE;
754af69d88dSmrg   default:
755af69d88dSmrg      break;
756af69d88dSmrg   }
757af69d88dSmrg
75801e04c3fSmrg   if (internalFormat != GL_RGB10_A2 &&
75901e04c3fSmrg       (format == MESA_FORMAT_B10G10R10A2_UNORM ||
76001e04c3fSmrg        format == MESA_FORMAT_B10G10R10X2_UNORM ||
76101e04c3fSmrg        format == MESA_FORMAT_R10G10B10A2_UNORM ||
76201e04c3fSmrg        format == MESA_FORMAT_R10G10B10X2_UNORM)) {
763af69d88dSmrg      return GL_FALSE;
764af69d88dSmrg   }
765af69d88dSmrg
766af69d88dSmrg   return GL_TRUE;
767af69d88dSmrg}
768af69d88dSmrg
769af69d88dSmrg
7703464ebd5Sriastradh/**
7713464ebd5Sriastradh * Is the given base format a legal format for a depth/stencil renderbuffer?
7723464ebd5Sriastradh */
7733464ebd5Sriastradhstatic GLboolean
7743464ebd5Sriastradhis_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
7753464ebd5Sriastradh{
7763464ebd5Sriastradh   switch (baseFormat) {
7773464ebd5Sriastradh   case GL_DEPTH_COMPONENT:
7783464ebd5Sriastradh   case GL_DEPTH_STENCIL_EXT:
7793464ebd5Sriastradh      return GL_TRUE;
7803464ebd5Sriastradh   default:
7813464ebd5Sriastradh      return GL_FALSE;
7823464ebd5Sriastradh   }
7833464ebd5Sriastradh}
7844a49301eSmrg
7854a49301eSmrg
7867117f1b4Smrg/**
7877117f1b4Smrg * Test if an attachment point is complete and update its Complete field.
7887117f1b4Smrg * \param format if GL_COLOR, this is a color attachment point,
7897117f1b4Smrg *               if GL_DEPTH, this is a depth component attachment point,
7907117f1b4Smrg *               if GL_STENCIL, this is a stencil component attachment point.
7917117f1b4Smrg */
7927117f1b4Smrgstatic void
7933464ebd5Sriastradhtest_attachment_completeness(const struct gl_context *ctx, GLenum format,
7947117f1b4Smrg                             struct gl_renderbuffer_attachment *att)
7957117f1b4Smrg{
7967117f1b4Smrg   assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
7977117f1b4Smrg
7987117f1b4Smrg   /* assume complete */
7997117f1b4Smrg   att->Complete = GL_TRUE;
8007117f1b4Smrg
8017117f1b4Smrg   /* Look for reasons why the attachment might be incomplete */
8027117f1b4Smrg   if (att->Type == GL_TEXTURE) {
8037117f1b4Smrg      const struct gl_texture_object *texObj = att->Texture;
80401e04c3fSmrg      const struct gl_texture_image *texImage;
8054a49301eSmrg      GLenum baseFormat;
8067117f1b4Smrg
8077117f1b4Smrg      if (!texObj) {
8084a49301eSmrg         att_incomplete("no texobj");
8097117f1b4Smrg         att->Complete = GL_FALSE;
8107117f1b4Smrg         return;
8117117f1b4Smrg      }
8127117f1b4Smrg
8137117f1b4Smrg      texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
8147117f1b4Smrg      if (!texImage) {
8154a49301eSmrg         att_incomplete("no teximage");
8167117f1b4Smrg         att->Complete = GL_FALSE;
8177117f1b4Smrg         return;
8187117f1b4Smrg      }
8197117f1b4Smrg      if (texImage->Width < 1 || texImage->Height < 1) {
8204a49301eSmrg         att_incomplete("teximage width/height=0");
8217117f1b4Smrg         att->Complete = GL_FALSE;
8227117f1b4Smrg         return;
8237117f1b4Smrg      }
824af69d88dSmrg
825af69d88dSmrg      switch (texObj->Target) {
826af69d88dSmrg      case GL_TEXTURE_3D:
827af69d88dSmrg         if (att->Zoffset >= texImage->Depth) {
828af69d88dSmrg            att_incomplete("bad z offset");
829af69d88dSmrg            att->Complete = GL_FALSE;
830af69d88dSmrg            return;
831af69d88dSmrg         }
832af69d88dSmrg         break;
833af69d88dSmrg      case GL_TEXTURE_1D_ARRAY:
834af69d88dSmrg         if (att->Zoffset >= texImage->Height) {
835af69d88dSmrg            att_incomplete("bad 1D-array layer");
836af69d88dSmrg            att->Complete = GL_FALSE;
837af69d88dSmrg            return;
838af69d88dSmrg         }
839af69d88dSmrg         break;
840af69d88dSmrg      case GL_TEXTURE_2D_ARRAY:
841af69d88dSmrg         if (att->Zoffset >= texImage->Depth) {
842af69d88dSmrg            att_incomplete("bad 2D-array layer");
843af69d88dSmrg            att->Complete = GL_FALSE;
844af69d88dSmrg            return;
845af69d88dSmrg         }
846af69d88dSmrg         break;
847af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_ARRAY:
848af69d88dSmrg         if (att->Zoffset >= texImage->Depth) {
849af69d88dSmrg            att_incomplete("bad cube-array layer");
850af69d88dSmrg            att->Complete = GL_FALSE;
851af69d88dSmrg            return;
852af69d88dSmrg         }
853af69d88dSmrg         break;
8547117f1b4Smrg      }
8557117f1b4Smrg
85601e04c3fSmrg      baseFormat = texImage->_BaseFormat;
8574a49301eSmrg
8587117f1b4Smrg      if (format == GL_COLOR) {
8593464ebd5Sriastradh         if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
8604a49301eSmrg            att_incomplete("bad format");
8614a49301eSmrg            att->Complete = GL_FALSE;
8624a49301eSmrg            return;
8634a49301eSmrg         }
8644a49301eSmrg         if (_mesa_is_format_compressed(texImage->TexFormat)) {
8654a49301eSmrg            att_incomplete("compressed internalformat");
8667117f1b4Smrg            att->Complete = GL_FALSE;
8677117f1b4Smrg            return;
8687117f1b4Smrg         }
86901e04c3fSmrg
87001e04c3fSmrg         /* OES_texture_float allows creation and use of floating point
87101e04c3fSmrg          * textures with GL_FLOAT, GL_HALF_FLOAT but it does not allow
87201e04c3fSmrg          * these textures to be used as a render target, this is done via
87301e04c3fSmrg          * GL_EXT_color_buffer(_half)_float with set of new sized types.
87401e04c3fSmrg          */
87501e04c3fSmrg         if (_mesa_is_gles(ctx) && (texObj->_IsFloat || texObj->_IsHalfFloat)) {
87601e04c3fSmrg            att_incomplete("bad internal format");
87701e04c3fSmrg            att->Complete = GL_FALSE;
87801e04c3fSmrg            return;
87901e04c3fSmrg         }
8807117f1b4Smrg      }
8817117f1b4Smrg      else if (format == GL_DEPTH) {
8824a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
8837117f1b4Smrg            /* OK */
8847117f1b4Smrg         }
885af69d88dSmrg         else if (ctx->Extensions.ARB_depth_texture &&
886af69d88dSmrg                  baseFormat == GL_DEPTH_STENCIL) {
8877117f1b4Smrg            /* OK */
8887117f1b4Smrg         }
8897117f1b4Smrg         else {
8907117f1b4Smrg            att->Complete = GL_FALSE;
8914a49301eSmrg            att_incomplete("bad depth format");
8927117f1b4Smrg            return;
8937117f1b4Smrg         }
8947117f1b4Smrg      }
8957117f1b4Smrg      else {
89601e04c3fSmrg         assert(format == GL_STENCIL);
897af69d88dSmrg         if (ctx->Extensions.ARB_depth_texture &&
898af69d88dSmrg             baseFormat == GL_DEPTH_STENCIL) {
899c7037ccdSmrg            /* OK */
90001e04c3fSmrg         } else if (ctx->Extensions.ARB_texture_stencil8 &&
90101e04c3fSmrg                    baseFormat == GL_STENCIL_INDEX) {
90201e04c3fSmrg            /* OK */
90301e04c3fSmrg         } else {
904c7037ccdSmrg            /* no such thing as stencil-only textures */
9054a49301eSmrg            att_incomplete("illegal stencil texture");
906c7037ccdSmrg            att->Complete = GL_FALSE;
907c7037ccdSmrg            return;
908c7037ccdSmrg         }
9097117f1b4Smrg      }
9107117f1b4Smrg   }
9117117f1b4Smrg   else if (att->Type == GL_RENDERBUFFER_EXT) {
91201e04c3fSmrg      const GLenum baseFormat = att->Renderbuffer->_BaseFormat;
9134a49301eSmrg
91401e04c3fSmrg      assert(att->Renderbuffer);
9157117f1b4Smrg      if (!att->Renderbuffer->InternalFormat ||
9167117f1b4Smrg          att->Renderbuffer->Width < 1 ||
9177117f1b4Smrg          att->Renderbuffer->Height < 1) {
9184a49301eSmrg         att_incomplete("0x0 renderbuffer");
9197117f1b4Smrg         att->Complete = GL_FALSE;
9207117f1b4Smrg         return;
9217117f1b4Smrg      }
9227117f1b4Smrg      if (format == GL_COLOR) {
9233464ebd5Sriastradh         if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
9244a49301eSmrg            att_incomplete("bad renderbuffer color format");
9257117f1b4Smrg            att->Complete = GL_FALSE;
9267117f1b4Smrg            return;
9277117f1b4Smrg         }
9287117f1b4Smrg      }
9297117f1b4Smrg      else if (format == GL_DEPTH) {
9304a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
9317117f1b4Smrg            /* OK */
9327117f1b4Smrg         }
933af69d88dSmrg         else if (baseFormat == GL_DEPTH_STENCIL) {
9347117f1b4Smrg            /* OK */
9357117f1b4Smrg         }
9367117f1b4Smrg         else {
9374a49301eSmrg            att_incomplete("bad renderbuffer depth format");
9387117f1b4Smrg            att->Complete = GL_FALSE;
9397117f1b4Smrg            return;
9407117f1b4Smrg         }
9417117f1b4Smrg      }
9427117f1b4Smrg      else {
9437117f1b4Smrg         assert(format == GL_STENCIL);
944af69d88dSmrg         if (baseFormat == GL_STENCIL_INDEX ||
945af69d88dSmrg             baseFormat == GL_DEPTH_STENCIL) {
9467117f1b4Smrg            /* OK */
9477117f1b4Smrg         }
9487117f1b4Smrg         else {
9497117f1b4Smrg            att->Complete = GL_FALSE;
9504a49301eSmrg            att_incomplete("bad renderbuffer stencil format");
9517117f1b4Smrg            return;
9527117f1b4Smrg         }
9537117f1b4Smrg      }
9547117f1b4Smrg   }
9557117f1b4Smrg   else {
95601e04c3fSmrg      assert(att->Type == GL_NONE);
9577117f1b4Smrg      /* complete */
9587117f1b4Smrg      return;
9597117f1b4Smrg   }
9607117f1b4Smrg}
9617117f1b4Smrg
9627117f1b4Smrg
9637117f1b4Smrg/**
9647117f1b4Smrg * Test if the given framebuffer object is complete and update its
9657117f1b4Smrg * Status field with the results.
9664a49301eSmrg * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
9674a49301eSmrg * driver to make hardware-specific validation/completeness checks.
9687117f1b4Smrg * Also update the framebuffer's Width and Height fields if the
9697117f1b4Smrg * framebuffer is complete.
9707117f1b4Smrg */
9717117f1b4Smrgvoid
9723464ebd5Sriastradh_mesa_test_framebuffer_completeness(struct gl_context *ctx,
9733464ebd5Sriastradh                                    struct gl_framebuffer *fb)
9747117f1b4Smrg{
9754a49301eSmrg   GLuint numImages;
9764a49301eSmrg   GLenum intFormat = GL_NONE; /* color buffers' internal format */
9774a49301eSmrg   GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
97801e04c3fSmrg   GLint numColorSamples = -1;
97901e04c3fSmrg   GLint numColorStorageSamples = -1;
98001e04c3fSmrg   GLint numDepthSamples = -1;
981af69d88dSmrg   GLint fixedSampleLocations = -1;
9827117f1b4Smrg   GLint i;
9837117f1b4Smrg   GLuint j;
984af69d88dSmrg   /* Covers max_layer_count, is_layered, and layer_tex_target */
985af69d88dSmrg   bool layer_info_valid = false;
986af69d88dSmrg   GLuint max_layer_count = 0, att_layer_count;
987af69d88dSmrg   bool is_layered = false;
988af69d88dSmrg   GLenum layer_tex_target = 0;
98901e04c3fSmrg   bool has_depth_attachment = false;
99001e04c3fSmrg   bool has_stencil_attachment = false;
991af69d88dSmrg
992af69d88dSmrg   assert(_mesa_is_user_fbo(fb));
9937117f1b4Smrg
994af69d88dSmrg   /* we're changing framebuffer fields here */
995af69d88dSmrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
9967117f1b4Smrg
9977117f1b4Smrg   numImages = 0;
9987117f1b4Smrg   fb->Width = 0;
9997117f1b4Smrg   fb->Height = 0;
1000af69d88dSmrg   fb->_AllColorBuffersFixedPoint = GL_TRUE;
1001af69d88dSmrg   fb->_HasSNormOrFloatColorBuffer = GL_FALSE;
100201e04c3fSmrg   fb->_HasAttachments = true;
100301e04c3fSmrg   fb->_IntegerBuffers = 0;
10047117f1b4Smrg
10054a49301eSmrg   /* Start at -2 to more easily loop over all attachment points.
10064a49301eSmrg    *  -2: depth buffer
10074a49301eSmrg    *  -1: stencil buffer
10084a49301eSmrg    * >=0: color buffer
10094a49301eSmrg    */
10107117f1b4Smrg   for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
10117117f1b4Smrg      struct gl_renderbuffer_attachment *att;
10127117f1b4Smrg      GLenum f;
1013af69d88dSmrg      mesa_format attFormat;
1014af69d88dSmrg      GLenum att_tex_target = GL_NONE;
10157117f1b4Smrg
10164a49301eSmrg      /*
10174a49301eSmrg       * XXX for ARB_fbo, only check color buffers that are named by
10184a49301eSmrg       * GL_READ_BUFFER and GL_DRAW_BUFFERi.
10194a49301eSmrg       */
10204a49301eSmrg
10214a49301eSmrg      /* check for attachment completeness
10224a49301eSmrg       */
10237117f1b4Smrg      if (i == -2) {
10247117f1b4Smrg         att = &fb->Attachment[BUFFER_DEPTH];
10257117f1b4Smrg         test_attachment_completeness(ctx, GL_DEPTH, att);
10267117f1b4Smrg         if (!att->Complete) {
10277117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
1028af69d88dSmrg            fbo_incomplete(ctx, "depth attachment incomplete", -1);
10297117f1b4Smrg            return;
103001e04c3fSmrg         } else if (att->Type != GL_NONE) {
103101e04c3fSmrg            has_depth_attachment = true;
10327117f1b4Smrg         }
10337117f1b4Smrg      }
10347117f1b4Smrg      else if (i == -1) {
10357117f1b4Smrg         att = &fb->Attachment[BUFFER_STENCIL];
10367117f1b4Smrg         test_attachment_completeness(ctx, GL_STENCIL, att);
10377117f1b4Smrg         if (!att->Complete) {
10387117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
1039af69d88dSmrg            fbo_incomplete(ctx, "stencil attachment incomplete", -1);
10407117f1b4Smrg            return;
104101e04c3fSmrg         } else if (att->Type != GL_NONE) {
104201e04c3fSmrg            has_stencil_attachment = true;
10437117f1b4Smrg         }
10447117f1b4Smrg      }
10457117f1b4Smrg      else {
10467117f1b4Smrg         att = &fb->Attachment[BUFFER_COLOR0 + i];
10477117f1b4Smrg         test_attachment_completeness(ctx, GL_COLOR, att);
10487117f1b4Smrg         if (!att->Complete) {
10497117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
1050af69d88dSmrg            fbo_incomplete(ctx, "color attachment incomplete", i);
10517117f1b4Smrg            return;
10527117f1b4Smrg         }
10537117f1b4Smrg      }
10547117f1b4Smrg
10554a49301eSmrg      /* get width, height, format of the renderbuffer/texture
10564a49301eSmrg       */
105701e04c3fSmrg      unsigned attNumSamples, attNumStorageSamples;
105801e04c3fSmrg
10597117f1b4Smrg      if (att->Type == GL_TEXTURE) {
1060af69d88dSmrg         const struct gl_texture_image *texImg = att->Renderbuffer->TexImage;
1061af69d88dSmrg         att_tex_target = att->Texture->Target;
10624a49301eSmrg         minWidth = MIN2(minWidth, texImg->Width);
10634a49301eSmrg         maxWidth = MAX2(maxWidth, texImg->Width);
10644a49301eSmrg         minHeight = MIN2(minHeight, texImg->Height);
10654a49301eSmrg         maxHeight = MAX2(maxHeight, texImg->Height);
10667117f1b4Smrg         f = texImg->_BaseFormat;
10673464ebd5Sriastradh         attFormat = texImg->TexFormat;
10687117f1b4Smrg         numImages++;
1069af69d88dSmrg
1070af69d88dSmrg         if (!is_format_color_renderable(ctx, attFormat,
1071af69d88dSmrg                                         texImg->InternalFormat) &&
107201e04c3fSmrg             !is_legal_depth_format(ctx, f) &&
107301e04c3fSmrg             f != GL_STENCIL_INDEX) {
107401e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1075af69d88dSmrg            fbo_incomplete(ctx, "texture attachment incomplete", -1);
1076af69d88dSmrg            return;
1077af69d88dSmrg         }
1078af69d88dSmrg
1079af69d88dSmrg         if (fixedSampleLocations < 0)
1080af69d88dSmrg            fixedSampleLocations = texImg->FixedSampleLocations;
1081af69d88dSmrg         else if (fixedSampleLocations != texImg->FixedSampleLocations) {
1082af69d88dSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1083af69d88dSmrg            fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
10847117f1b4Smrg            return;
10857117f1b4Smrg         }
108601e04c3fSmrg
108701e04c3fSmrg         attNumSamples = texImg->NumSamples;
108801e04c3fSmrg         attNumStorageSamples = texImg->NumSamples;
10897117f1b4Smrg      }
10907117f1b4Smrg      else if (att->Type == GL_RENDERBUFFER_EXT) {
10914a49301eSmrg         minWidth = MIN2(minWidth, att->Renderbuffer->Width);
10924a49301eSmrg         maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
10934a49301eSmrg         minHeight = MIN2(minHeight, att->Renderbuffer->Height);
10944a49301eSmrg         maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
10957117f1b4Smrg         f = att->Renderbuffer->InternalFormat;
10963464ebd5Sriastradh         attFormat = att->Renderbuffer->Format;
10977117f1b4Smrg         numImages++;
1098af69d88dSmrg
1099af69d88dSmrg         /* RENDERBUFFER has fixedSampleLocations implicitly true */
1100af69d88dSmrg         if (fixedSampleLocations < 0)
1101af69d88dSmrg            fixedSampleLocations = GL_TRUE;
1102af69d88dSmrg         else if (fixedSampleLocations != GL_TRUE) {
1103af69d88dSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1104af69d88dSmrg            fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
1105af69d88dSmrg            return;
1106af69d88dSmrg         }
110701e04c3fSmrg
110801e04c3fSmrg         attNumSamples = att->Renderbuffer->NumSamples;
110901e04c3fSmrg         attNumStorageSamples = att->Renderbuffer->NumStorageSamples;
11107117f1b4Smrg      }
11117117f1b4Smrg      else {
11127117f1b4Smrg         assert(att->Type == GL_NONE);
11137117f1b4Smrg         continue;
11147117f1b4Smrg      }
11157117f1b4Smrg
111601e04c3fSmrg      if (i >= 0) {
111701e04c3fSmrg         /* Color buffers. */
111801e04c3fSmrg         if (numColorSamples < 0) {
111901e04c3fSmrg            assert(numColorStorageSamples < 0);
112001e04c3fSmrg            numColorSamples = attNumSamples;
112101e04c3fSmrg            numColorStorageSamples = attNumStorageSamples;
112201e04c3fSmrg         } else if (numColorSamples != attNumSamples ||
112301e04c3fSmrg                    numColorStorageSamples != attNumStorageSamples) {
112401e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
112501e04c3fSmrg            fbo_incomplete(ctx, "inconsistent sample counts", -1);
112601e04c3fSmrg            return;
112701e04c3fSmrg         }
112801e04c3fSmrg      } else {
112901e04c3fSmrg         /* Depth/stencil buffers. */
113001e04c3fSmrg         if (numDepthSamples < 0) {
113101e04c3fSmrg            numDepthSamples = attNumSamples;
113201e04c3fSmrg         } else if (numDepthSamples != attNumSamples) {
113301e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
113401e04c3fSmrg            fbo_incomplete(ctx, "inconsistent sample counts", -1);
113501e04c3fSmrg            return;
113601e04c3fSmrg         }
113701e04c3fSmrg      }
11383464ebd5Sriastradh
113901e04c3fSmrg      /* Update flags describing color buffer datatypes */
1140af69d88dSmrg      if (i >= 0) {
1141af69d88dSmrg         GLenum type = _mesa_get_format_datatype(attFormat);
1142af69d88dSmrg
114301e04c3fSmrg         /* check if integer color */
114401e04c3fSmrg         if (_mesa_is_format_integer_color(attFormat))
114501e04c3fSmrg            fb->_IntegerBuffers |= (1 << i);
114601e04c3fSmrg
1147af69d88dSmrg         fb->_AllColorBuffersFixedPoint =
1148af69d88dSmrg            fb->_AllColorBuffersFixedPoint &&
1149af69d88dSmrg            (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED);
1150af69d88dSmrg
1151af69d88dSmrg         fb->_HasSNormOrFloatColorBuffer =
1152af69d88dSmrg            fb->_HasSNormOrFloatColorBuffer ||
1153af69d88dSmrg            type == GL_SIGNED_NORMALIZED || type == GL_FLOAT;
1154af69d88dSmrg      }
1155af69d88dSmrg
1156af69d88dSmrg      /* Error-check width, height, format */
11577117f1b4Smrg      if (numImages == 1) {
1158af69d88dSmrg         /* save format */
11594a49301eSmrg         if (i >= 0) {
11607117f1b4Smrg            intFormat = f;
11614a49301eSmrg         }
11627117f1b4Smrg      }
11637117f1b4Smrg      else {
11644a49301eSmrg         if (!ctx->Extensions.ARB_framebuffer_object) {
11654a49301eSmrg            /* check that width, height, format are same */
11664a49301eSmrg            if (minWidth != maxWidth || minHeight != maxHeight) {
11674a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
1168af69d88dSmrg               fbo_incomplete(ctx, "width or height mismatch", -1);
11694a49301eSmrg               return;
11704a49301eSmrg            }
1171af69d88dSmrg            /* check that all color buffers are the same format */
11724a49301eSmrg            if (intFormat != GL_NONE && f != intFormat) {
11734a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
1174af69d88dSmrg               fbo_incomplete(ctx, "format mismatch", -1);
11754a49301eSmrg               return;
11764a49301eSmrg            }
11777117f1b4Smrg         }
1178af69d88dSmrg      }
1179af69d88dSmrg
1180af69d88dSmrg      /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported)
1181af69d88dSmrg       */
1182af69d88dSmrg      if (att->Type == GL_RENDERBUFFER &&
1183af69d88dSmrg          att->Renderbuffer->Format == MESA_FORMAT_NONE) {
1184af69d88dSmrg         fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
1185af69d88dSmrg         fbo_incomplete(ctx, "unsupported renderbuffer format", i);
1186af69d88dSmrg         return;
1187af69d88dSmrg      }
11884a49301eSmrg
1189af69d88dSmrg      /* Check that layered rendering is consistent. */
1190af69d88dSmrg      if (att->Layered) {
1191af69d88dSmrg         if (att_tex_target == GL_TEXTURE_CUBE_MAP)
1192af69d88dSmrg            att_layer_count = 6;
1193af69d88dSmrg         else if (att_tex_target == GL_TEXTURE_1D_ARRAY)
1194af69d88dSmrg            att_layer_count = att->Renderbuffer->Height;
1195af69d88dSmrg         else
1196af69d88dSmrg            att_layer_count = att->Renderbuffer->Depth;
1197af69d88dSmrg      } else {
1198af69d88dSmrg         att_layer_count = 0;
1199af69d88dSmrg      }
1200af69d88dSmrg      if (!layer_info_valid) {
1201af69d88dSmrg         is_layered = att->Layered;
1202af69d88dSmrg         max_layer_count = att_layer_count;
1203af69d88dSmrg         layer_tex_target = att_tex_target;
1204af69d88dSmrg         layer_info_valid = true;
1205af69d88dSmrg      } else if (max_layer_count > 0 && layer_tex_target != att_tex_target) {
1206af69d88dSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
1207af69d88dSmrg         fbo_incomplete(ctx, "layered framebuffer has mismatched targets", i);
1208af69d88dSmrg         return;
1209af69d88dSmrg      } else if (is_layered != att->Layered) {
1210af69d88dSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
1211af69d88dSmrg         fbo_incomplete(ctx,
1212af69d88dSmrg                        "framebuffer attachment layer mode is inconsistent",
1213af69d88dSmrg                        i);
1214af69d88dSmrg         return;
1215af69d88dSmrg      } else if (att_layer_count > max_layer_count) {
1216af69d88dSmrg         max_layer_count = att_layer_count;
12177117f1b4Smrg      }
121801e04c3fSmrg
121901e04c3fSmrg      /*
122001e04c3fSmrg       * The extension GL_ARB_framebuffer_no_attachments places additional
122101e04c3fSmrg       * requirement on each attachment. Those additional requirements are
122201e04c3fSmrg       * tighter that those of previous versions of GL. In interest of better
122301e04c3fSmrg       * compatibility, we will not enforce these restrictions. For the record
122401e04c3fSmrg       * those additional restrictions are quoted below:
122501e04c3fSmrg       *
122601e04c3fSmrg       * "The width and height of image are greater than zero and less than or
122701e04c3fSmrg       *  equal to the values of the implementation-dependent limits
122801e04c3fSmrg       *  MAX_FRAMEBUFFER_WIDTH and MAX_FRAMEBUFFER_HEIGHT, respectively."
122901e04c3fSmrg       *
123001e04c3fSmrg       * "If <image> is a three-dimensional texture or a one- or two-dimensional
123101e04c3fSmrg       *  array texture and the attachment is layered, the depth or layer count
123201e04c3fSmrg       *  of the texture is less than or equal to the implementation-dependent
123301e04c3fSmrg       *  limit MAX_FRAMEBUFFER_LAYERS."
123401e04c3fSmrg       *
123501e04c3fSmrg       * "If image has multiple samples, its sample count is less than or equal
123601e04c3fSmrg       *  to the value of the implementation-dependent limit
123701e04c3fSmrg       *  MAX_FRAMEBUFFER_SAMPLES."
123801e04c3fSmrg       *
123901e04c3fSmrg       * The same requirements are also in place for GL 4.5,
124001e04c3fSmrg       * Section 9.4.1 "Framebuffer Attachment Completeness", pg 310-311
124101e04c3fSmrg       */
124201e04c3fSmrg   }
124301e04c3fSmrg
124401e04c3fSmrg   if (ctx->Extensions.AMD_framebuffer_multisample_advanced) {
124501e04c3fSmrg      /* See if non-matching sample counts are supported. */
124601e04c3fSmrg      if (numColorSamples >= 0 && numDepthSamples >= 0) {
124701e04c3fSmrg         bool found = false;
124801e04c3fSmrg
124901e04c3fSmrg         assert(numColorStorageSamples != -1);
125001e04c3fSmrg
125101e04c3fSmrg         numColorSamples = MAX2(numColorSamples, 1);
125201e04c3fSmrg         numColorStorageSamples = MAX2(numColorStorageSamples, 1);
125301e04c3fSmrg         numDepthSamples = MAX2(numDepthSamples, 1);
125401e04c3fSmrg
125501e04c3fSmrg         if (numColorSamples == 1 && numColorStorageSamples == 1 &&
125601e04c3fSmrg             numDepthSamples == 1) {
125701e04c3fSmrg            found = true;
125801e04c3fSmrg         } else {
125901e04c3fSmrg            for (i = 0; i < ctx->Const.NumSupportedMultisampleModes; i++) {
126001e04c3fSmrg               GLint *counts =
126101e04c3fSmrg                  &ctx->Const.SupportedMultisampleModes[i].NumColorSamples;
126201e04c3fSmrg
126301e04c3fSmrg               if (counts[0] == numColorSamples &&
126401e04c3fSmrg                   counts[1] == numColorStorageSamples &&
126501e04c3fSmrg                   counts[2] == numDepthSamples) {
126601e04c3fSmrg                  found = true;
126701e04c3fSmrg                  break;
126801e04c3fSmrg               }
126901e04c3fSmrg            }
127001e04c3fSmrg         }
127101e04c3fSmrg
127201e04c3fSmrg         if (!found) {
127301e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
127401e04c3fSmrg            fbo_incomplete(ctx, "unsupported sample counts", -1);
127501e04c3fSmrg            return;
127601e04c3fSmrg         }
127701e04c3fSmrg      }
127801e04c3fSmrg   } else {
127901e04c3fSmrg      /* If the extension is unsupported, all sample counts must be equal. */
128001e04c3fSmrg      if (numColorSamples >= 0 &&
128101e04c3fSmrg          (numColorSamples != numColorStorageSamples ||
128201e04c3fSmrg           (numDepthSamples >= 0 && numColorSamples != numDepthSamples))) {
128301e04c3fSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
128401e04c3fSmrg         fbo_incomplete(ctx, "inconsistent sample counts", -1);
128501e04c3fSmrg         return;
128601e04c3fSmrg      }
12877117f1b4Smrg   }
12887117f1b4Smrg
1289af69d88dSmrg   fb->MaxNumLayers = max_layer_count;
1290af69d88dSmrg
1291af69d88dSmrg   if (numImages == 0) {
129201e04c3fSmrg      fb->_HasAttachments = false;
129301e04c3fSmrg
129401e04c3fSmrg      if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
129501e04c3fSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
129601e04c3fSmrg         fbo_incomplete(ctx, "no attachments", -1);
129701e04c3fSmrg         return;
129801e04c3fSmrg      }
129901e04c3fSmrg
130001e04c3fSmrg      if (fb->DefaultGeometry.Width == 0 || fb->DefaultGeometry.Height == 0) {
130101e04c3fSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
130201e04c3fSmrg         fbo_incomplete(ctx, "no attachments and default width or height is 0", -1);
130301e04c3fSmrg         return;
130401e04c3fSmrg      }
1305af69d88dSmrg   }
1306af69d88dSmrg
1307af69d88dSmrg   if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) {
13083464ebd5Sriastradh      /* Check that all DrawBuffers are present */
13093464ebd5Sriastradh      for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
131001e04c3fSmrg         if (fb->ColorDrawBuffer[j] != GL_NONE) {
131101e04c3fSmrg            const struct gl_renderbuffer_attachment *att
131201e04c3fSmrg               = get_attachment(ctx, fb, fb->ColorDrawBuffer[j], NULL);
131301e04c3fSmrg            assert(att);
131401e04c3fSmrg            if (att->Type == GL_NONE) {
131501e04c3fSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
131601e04c3fSmrg               fbo_incomplete(ctx, "missing drawbuffer", j);
131701e04c3fSmrg               return;
131801e04c3fSmrg            }
131901e04c3fSmrg         }
13207117f1b4Smrg      }
13217117f1b4Smrg
13223464ebd5Sriastradh      /* Check that the ReadBuffer is present */
13233464ebd5Sriastradh      if (fb->ColorReadBuffer != GL_NONE) {
132401e04c3fSmrg         const struct gl_renderbuffer_attachment *att
132501e04c3fSmrg            = get_attachment(ctx, fb, fb->ColorReadBuffer, NULL);
132601e04c3fSmrg         assert(att);
132701e04c3fSmrg         if (att->Type == GL_NONE) {
132801e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
1329af69d88dSmrg            fbo_incomplete(ctx, "missing readbuffer", -1);
133001e04c3fSmrg            return;
133101e04c3fSmrg         }
13327117f1b4Smrg      }
13337117f1b4Smrg   }
13347117f1b4Smrg
133501e04c3fSmrg   /* The OpenGL ES3 spec, in chapter 9.4. FRAMEBUFFER COMPLETENESS, says:
133601e04c3fSmrg    *
133701e04c3fSmrg    *    "Depth and stencil attachments, if present, are the same image."
133801e04c3fSmrg    *
133901e04c3fSmrg    * This restriction is not present in the OpenGL ES2 spec.
134001e04c3fSmrg    */
134101e04c3fSmrg   if (_mesa_is_gles3(ctx) &&
134201e04c3fSmrg       has_stencil_attachment && has_depth_attachment &&
134301e04c3fSmrg       !_mesa_has_depthstencil_combined(fb)) {
134401e04c3fSmrg      fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
134501e04c3fSmrg      fbo_incomplete(ctx, "Depth and stencil attachments must be the same image", -1);
134601e04c3fSmrg      return;
134701e04c3fSmrg   }
134801e04c3fSmrg
13494a49301eSmrg   /* Provisionally set status = COMPLETE ... */
13507117f1b4Smrg   fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
13514a49301eSmrg
13524a49301eSmrg   /* ... but the driver may say the FB is incomplete.
13534a49301eSmrg    * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
13544a49301eSmrg    * if anything.
13554a49301eSmrg    */
13564a49301eSmrg   if (ctx->Driver.ValidateFramebuffer) {
13574a49301eSmrg      ctx->Driver.ValidateFramebuffer(ctx, fb);
13584a49301eSmrg      if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1359af69d88dSmrg         fbo_incomplete(ctx, "driver marked FBO as incomplete", -1);
136001e04c3fSmrg         return;
13614a49301eSmrg      }
13624a49301eSmrg   }
13634a49301eSmrg
136401e04c3fSmrg   /*
136501e04c3fSmrg    * Note that if ARB_framebuffer_object is supported and the attached
136601e04c3fSmrg    * renderbuffers/textures are different sizes, the framebuffer
136701e04c3fSmrg    * width/height will be set to the smallest width/height.
136801e04c3fSmrg    */
136901e04c3fSmrg   if (numImages != 0) {
13704a49301eSmrg      fb->Width = minWidth;
13714a49301eSmrg      fb->Height = minHeight;
13724a49301eSmrg   }
137301e04c3fSmrg
137401e04c3fSmrg   /* finally, update the visual info for the framebuffer */
137501e04c3fSmrg   _mesa_update_framebuffer_visual(ctx, fb);
13767117f1b4Smrg}
13777117f1b4Smrg
13787117f1b4Smrg
13797117f1b4SmrgGLboolean GLAPIENTRY
1380af69d88dSmrg_mesa_IsRenderbuffer(GLuint renderbuffer)
13817117f1b4Smrg{
138201e04c3fSmrg   struct gl_renderbuffer *rb;
138301e04c3fSmrg
13847117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
138501e04c3fSmrg
13867117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
138701e04c3fSmrg
138801e04c3fSmrg   rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
138901e04c3fSmrg   return rb != NULL && rb != &DummyRenderbuffer;
139001e04c3fSmrg}
139101e04c3fSmrg
139201e04c3fSmrg
139301e04c3fSmrgstatic struct gl_renderbuffer *
139401e04c3fSmrgallocate_renderbuffer_locked(struct gl_context *ctx, GLuint renderbuffer,
139501e04c3fSmrg                             const char *func)
139601e04c3fSmrg{
139701e04c3fSmrg   struct gl_renderbuffer *newRb;
139801e04c3fSmrg
139901e04c3fSmrg   /* create new renderbuffer object */
140001e04c3fSmrg   newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
140101e04c3fSmrg   if (!newRb) {
140201e04c3fSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
140301e04c3fSmrg      return NULL;
14047117f1b4Smrg   }
140501e04c3fSmrg   assert(newRb->AllocStorage);
140601e04c3fSmrg   _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, renderbuffer, newRb);
140701e04c3fSmrg
140801e04c3fSmrg   return newRb;
14097117f1b4Smrg}
14107117f1b4Smrg
14117117f1b4Smrg
1412af69d88dSmrgstatic void
141301e04c3fSmrgbind_renderbuffer(GLenum target, GLuint renderbuffer)
14147117f1b4Smrg{
14157117f1b4Smrg   struct gl_renderbuffer *newRb;
14167117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
14177117f1b4Smrg
14187117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
14194a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
14207117f1b4Smrg      return;
14217117f1b4Smrg   }
14227117f1b4Smrg
14234a49301eSmrg   /* No need to flush here since the render buffer binding has no
14244a49301eSmrg    * effect on rendering state.
14257117f1b4Smrg    */
14267117f1b4Smrg
14277117f1b4Smrg   if (renderbuffer) {
14287117f1b4Smrg      newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
14297117f1b4Smrg      if (newRb == &DummyRenderbuffer) {
14307117f1b4Smrg         /* ID was reserved, but no real renderbuffer object made yet */
14317117f1b4Smrg         newRb = NULL;
14327117f1b4Smrg      }
143301e04c3fSmrg      else if (!newRb && ctx->API == API_OPENGL_CORE) {
14344a49301eSmrg         /* All RB IDs must be Gen'd */
143501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
143601e04c3fSmrg                     "glBindRenderbuffer(non-gen name)");
14374a49301eSmrg         return;
14384a49301eSmrg      }
14394a49301eSmrg
14407117f1b4Smrg      if (!newRb) {
144101e04c3fSmrg         _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
144201e04c3fSmrg         newRb = allocate_renderbuffer_locked(ctx, renderbuffer,
144301e04c3fSmrg                                              "glBindRenderbufferEXT");
144401e04c3fSmrg         _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
14457117f1b4Smrg      }
14467117f1b4Smrg   }
14477117f1b4Smrg   else {
14487117f1b4Smrg      newRb = NULL;
14497117f1b4Smrg   }
14507117f1b4Smrg
145101e04c3fSmrg   assert(newRb != &DummyRenderbuffer);
14527117f1b4Smrg
14537117f1b4Smrg   _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
14547117f1b4Smrg}
14557117f1b4Smrg
1456af69d88dSmrgvoid GLAPIENTRY
1457af69d88dSmrg_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
1458af69d88dSmrg{
1459af69d88dSmrg   /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same
1460af69d88dSmrg    * entry point, but they allow the use of user-generated names.
1461af69d88dSmrg    */
146201e04c3fSmrg   bind_renderbuffer(target, renderbuffer);
1463af69d88dSmrg}
1464af69d88dSmrg
1465af69d88dSmrgvoid GLAPIENTRY
1466af69d88dSmrg_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
1467af69d88dSmrg{
146801e04c3fSmrg   bind_renderbuffer(target, renderbuffer);
1469af69d88dSmrg}
1470af69d88dSmrg
14714a49301eSmrg/**
147201e04c3fSmrg * ARB_framebuffer_no_attachment and ARB_sample_locations - Application passes
147301e04c3fSmrg * requested param's here. NOTE: NumSamples requested need not be _NumSamples
147401e04c3fSmrg * which is what the hw supports.
14754a49301eSmrg */
147601e04c3fSmrgstatic void
147701e04c3fSmrgframebuffer_parameteri(struct gl_context *ctx, struct gl_framebuffer *fb,
147801e04c3fSmrg                       GLenum pname, GLint param, const char *func)
14794a49301eSmrg{
148001e04c3fSmrg   bool cannot_be_winsys_fbo = false;
1481af69d88dSmrg
148201e04c3fSmrg   switch (pname) {
148301e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_WIDTH:
148401e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
148501e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_LAYERS:
148601e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
148701e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
148801e04c3fSmrg      if (!ctx->Extensions.ARB_framebuffer_no_attachments)
148901e04c3fSmrg         goto invalid_pname_enum;
149001e04c3fSmrg      cannot_be_winsys_fbo = true;
149101e04c3fSmrg      break;
149201e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
149301e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
149401e04c3fSmrg      if (!ctx->Extensions.ARB_sample_locations)
149501e04c3fSmrg         goto invalid_pname_enum;
149601e04c3fSmrg      break;
149701e04c3fSmrg   case GL_FRAMEBUFFER_FLIP_Y_MESA:
149801e04c3fSmrg      if (!ctx->Extensions.MESA_framebuffer_flip_y)
149901e04c3fSmrg         goto invalid_pname_enum;
150001e04c3fSmrg      cannot_be_winsys_fbo = true;
150101e04c3fSmrg      break;
150201e04c3fSmrg   default:
150301e04c3fSmrg      goto invalid_pname_enum;
150401e04c3fSmrg   }
150501e04c3fSmrg
150601e04c3fSmrg   if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) {
150701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
150801e04c3fSmrg                  "%s(invalid pname=0x%x for default framebuffer)", func, pname);
150901e04c3fSmrg      return;
151001e04c3fSmrg   }
151101e04c3fSmrg
151201e04c3fSmrg   switch (pname) {
151301e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_WIDTH:
151401e04c3fSmrg      if (param < 0 || param > ctx->Const.MaxFramebufferWidth)
151501e04c3fSmrg        _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
151601e04c3fSmrg      else
151701e04c3fSmrg         fb->DefaultGeometry.Width = param;
151801e04c3fSmrg      break;
151901e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
152001e04c3fSmrg      if (param < 0 || param > ctx->Const.MaxFramebufferHeight)
152101e04c3fSmrg        _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
152201e04c3fSmrg      else
152301e04c3fSmrg         fb->DefaultGeometry.Height = param;
152401e04c3fSmrg      break;
152501e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_LAYERS:
152601e04c3fSmrg     /*
152701e04c3fSmrg      * According to the OpenGL ES 3.1 specification section 9.2.1, the
152801e04c3fSmrg      * GL_FRAMEBUFFER_DEFAULT_LAYERS parameter name is not supported.
152901e04c3fSmrg      */
153001e04c3fSmrg      if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) {
153101e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
153201e04c3fSmrg         break;
15334a49301eSmrg      }
153401e04c3fSmrg      if (param < 0 || param > ctx->Const.MaxFramebufferLayers)
153501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
153601e04c3fSmrg      else
153701e04c3fSmrg         fb->DefaultGeometry.Layers = param;
153801e04c3fSmrg      break;
153901e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
154001e04c3fSmrg      if (param < 0 || param > ctx->Const.MaxFramebufferSamples)
154101e04c3fSmrg        _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
154201e04c3fSmrg      else
154301e04c3fSmrg        fb->DefaultGeometry.NumSamples = param;
154401e04c3fSmrg      break;
154501e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
154601e04c3fSmrg      fb->DefaultGeometry.FixedSampleLocations = param;
154701e04c3fSmrg      break;
154801e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
154901e04c3fSmrg      fb->ProgrammableSampleLocations = !!param;
155001e04c3fSmrg      break;
155101e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
155201e04c3fSmrg      fb->SampleLocationPixelGrid = !!param;
155301e04c3fSmrg      break;
155401e04c3fSmrg   case GL_FRAMEBUFFER_FLIP_Y_MESA:
155501e04c3fSmrg      fb->FlipY = param;
155601e04c3fSmrg      break;
15574a49301eSmrg   }
1558af69d88dSmrg
155901e04c3fSmrg   switch (pname) {
156001e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
156101e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
156201e04c3fSmrg      if (fb == ctx->DrawBuffer)
156301e04c3fSmrg         ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
156401e04c3fSmrg      break;
156501e04c3fSmrg   default:
1566af69d88dSmrg      invalidate_framebuffer(fb);
156701e04c3fSmrg      ctx->NewState |= _NEW_BUFFERS;
156801e04c3fSmrg      break;
156901e04c3fSmrg   }
1570af69d88dSmrg
157101e04c3fSmrg   return;
15724a49301eSmrg
157301e04c3fSmrginvalid_pname_enum:
157401e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
157501e04c3fSmrg}
15764a49301eSmrg
15777117f1b4Smrgvoid GLAPIENTRY
157801e04c3fSmrg_mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param)
15797117f1b4Smrg{
15807117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
158101e04c3fSmrg   struct gl_framebuffer *fb;
15827117f1b4Smrg
158301e04c3fSmrg   if (!ctx->Extensions.ARB_framebuffer_no_attachments &&
158401e04c3fSmrg       !ctx->Extensions.ARB_sample_locations) {
158501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
158601e04c3fSmrg                  "glFramebufferParameteriv not supported "
158701e04c3fSmrg                  "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations"
158801e04c3fSmrg                  " is available)");
158901e04c3fSmrg      return;
159001e04c3fSmrg   }
15917117f1b4Smrg
159201e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
159301e04c3fSmrg   if (!fb) {
159401e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
159501e04c3fSmrg                  "glFramebufferParameteri(target=0x%x)", target);
159601e04c3fSmrg      return;
159701e04c3fSmrg   }
15987117f1b4Smrg
159901e04c3fSmrg   framebuffer_parameteri(ctx, fb, pname, param, "glFramebufferParameteri");
160001e04c3fSmrg}
160101e04c3fSmrg
160201e04c3fSmrgstatic bool
160301e04c3fSmrgvalidate_get_framebuffer_parameteriv_pname(struct gl_context *ctx,
160401e04c3fSmrg                                           struct gl_framebuffer *fb,
160501e04c3fSmrg                                           GLuint pname, const char *func)
160601e04c3fSmrg{
160701e04c3fSmrg   bool cannot_be_winsys_fbo = true;
160801e04c3fSmrg
160901e04c3fSmrg   switch (pname) {
161001e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_LAYERS:
161101e04c3fSmrg      /*
161201e04c3fSmrg       * According to the OpenGL ES 3.1 specification section 9.2.3, the
161301e04c3fSmrg       * GL_FRAMEBUFFER_LAYERS parameter name is not supported.
161401e04c3fSmrg       */
161501e04c3fSmrg      if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) {
161601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
161701e04c3fSmrg         return false;
161801e04c3fSmrg      }
161901e04c3fSmrg      break;
162001e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_WIDTH:
162101e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
162201e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
162301e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
162401e04c3fSmrg      break;
162501e04c3fSmrg   case GL_DOUBLEBUFFER:
162601e04c3fSmrg   case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
162701e04c3fSmrg   case GL_IMPLEMENTATION_COLOR_READ_TYPE:
162801e04c3fSmrg   case GL_SAMPLES:
162901e04c3fSmrg   case GL_SAMPLE_BUFFERS:
163001e04c3fSmrg   case GL_STEREO:
163101e04c3fSmrg      /* From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries:
163201e04c3fSmrg       *
163301e04c3fSmrg       *    "An INVALID_OPERATION error is generated by GetFramebufferParameteriv
163401e04c3fSmrg       *     if the default framebuffer is bound to target and pname is not one
163501e04c3fSmrg       *     of the accepted values from table 23.73, other than
163601e04c3fSmrg       *     SAMPLE_POSITION."
163701e04c3fSmrg       *
163801e04c3fSmrg       * For OpenGL ES, using default framebuffer raises INVALID_OPERATION
163901e04c3fSmrg       * for any pname.
164001e04c3fSmrg       */
164101e04c3fSmrg      cannot_be_winsys_fbo = !_mesa_is_desktop_gl(ctx);
164201e04c3fSmrg      break;
164301e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
164401e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
164501e04c3fSmrg      if (!ctx->Extensions.ARB_sample_locations)
164601e04c3fSmrg         goto invalid_pname_enum;
164701e04c3fSmrg      cannot_be_winsys_fbo = false;
164801e04c3fSmrg      break;
164901e04c3fSmrg   case GL_FRAMEBUFFER_FLIP_Y_MESA:
165001e04c3fSmrg      if (!ctx->Extensions.MESA_framebuffer_flip_y) {
165101e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
165201e04c3fSmrg         return false;
165301e04c3fSmrg      }
165401e04c3fSmrg      break;
165501e04c3fSmrg   default:
165601e04c3fSmrg      goto invalid_pname_enum;
165701e04c3fSmrg   }
165801e04c3fSmrg
165901e04c3fSmrg   if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) {
166001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
166101e04c3fSmrg                  "%s(invalid pname=0x%x for default framebuffer)", func, pname);
166201e04c3fSmrg      return false;
166301e04c3fSmrg   }
166401e04c3fSmrg
166501e04c3fSmrg   return true;
166601e04c3fSmrg
166701e04c3fSmrginvalid_pname_enum:
166801e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
166901e04c3fSmrg   return false;
167001e04c3fSmrg}
167101e04c3fSmrg
167201e04c3fSmrgstatic void
167301e04c3fSmrgget_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb,
167401e04c3fSmrg                            GLenum pname, GLint *params, const char *func)
167501e04c3fSmrg{
167601e04c3fSmrg   if (!validate_get_framebuffer_parameteriv_pname(ctx, fb, pname, func))
167701e04c3fSmrg      return;
167801e04c3fSmrg
167901e04c3fSmrg   switch (pname) {
168001e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_WIDTH:
168101e04c3fSmrg      *params = fb->DefaultGeometry.Width;
168201e04c3fSmrg      break;
168301e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
168401e04c3fSmrg      *params = fb->DefaultGeometry.Height;
168501e04c3fSmrg      break;
168601e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_LAYERS:
168701e04c3fSmrg      *params = fb->DefaultGeometry.Layers;
168801e04c3fSmrg      break;
168901e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
169001e04c3fSmrg      *params = fb->DefaultGeometry.NumSamples;
169101e04c3fSmrg      break;
169201e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
169301e04c3fSmrg      *params = fb->DefaultGeometry.FixedSampleLocations;
169401e04c3fSmrg      break;
169501e04c3fSmrg   case GL_DOUBLEBUFFER:
169601e04c3fSmrg      *params = fb->Visual.doubleBufferMode;
169701e04c3fSmrg      break;
169801e04c3fSmrg   case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
169901e04c3fSmrg      *params = _mesa_get_color_read_format(ctx, fb, func);
170001e04c3fSmrg      break;
170101e04c3fSmrg   case GL_IMPLEMENTATION_COLOR_READ_TYPE:
170201e04c3fSmrg      *params = _mesa_get_color_read_type(ctx, fb, func);
170301e04c3fSmrg      break;
170401e04c3fSmrg   case GL_SAMPLES:
170501e04c3fSmrg      *params = _mesa_geometric_samples(fb);
170601e04c3fSmrg      break;
170701e04c3fSmrg   case GL_SAMPLE_BUFFERS:
170801e04c3fSmrg      *params = _mesa_geometric_samples(fb) > 0;
170901e04c3fSmrg      break;
171001e04c3fSmrg   case GL_STEREO:
171101e04c3fSmrg      *params = fb->Visual.stereoMode;
171201e04c3fSmrg      break;
171301e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
171401e04c3fSmrg      *params = fb->ProgrammableSampleLocations;
171501e04c3fSmrg      break;
171601e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
171701e04c3fSmrg      *params = fb->SampleLocationPixelGrid;
171801e04c3fSmrg      break;
171901e04c3fSmrg   case GL_FRAMEBUFFER_FLIP_Y_MESA:
172001e04c3fSmrg      *params = fb->FlipY;
172101e04c3fSmrg      break;
172201e04c3fSmrg   }
172301e04c3fSmrg}
172401e04c3fSmrg
172501e04c3fSmrgvoid GLAPIENTRY
172601e04c3fSmrg_mesa_GetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params)
172701e04c3fSmrg{
172801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
172901e04c3fSmrg   struct gl_framebuffer *fb;
173001e04c3fSmrg
173101e04c3fSmrg   if (!ctx->Extensions.ARB_framebuffer_no_attachments &&
173201e04c3fSmrg       !ctx->Extensions.ARB_sample_locations) {
173301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
173401e04c3fSmrg                  "glGetFramebufferParameteriv not supported "
173501e04c3fSmrg                  "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations"
173601e04c3fSmrg                  " is available)");
173701e04c3fSmrg      return;
173801e04c3fSmrg   }
173901e04c3fSmrg
174001e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
174101e04c3fSmrg   if (!fb) {
174201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
174301e04c3fSmrg                  "glGetFramebufferParameteriv(target=0x%x)", target);
174401e04c3fSmrg      return;
174501e04c3fSmrg   }
174601e04c3fSmrg
174701e04c3fSmrg   get_framebuffer_parameteriv(ctx, fb, pname, params,
174801e04c3fSmrg                               "glGetFramebufferParameteriv");
174901e04c3fSmrg}
175001e04c3fSmrg
175101e04c3fSmrg
175201e04c3fSmrg/**
175301e04c3fSmrg * Remove the specified renderbuffer or texture from any attachment point in
175401e04c3fSmrg * the framebuffer.
175501e04c3fSmrg *
175601e04c3fSmrg * \returns
175701e04c3fSmrg * \c true if the renderbuffer was detached from an attachment point.  \c
175801e04c3fSmrg * false otherwise.
175901e04c3fSmrg */
176001e04c3fSmrgbool
176101e04c3fSmrg_mesa_detach_renderbuffer(struct gl_context *ctx,
176201e04c3fSmrg                          struct gl_framebuffer *fb,
176301e04c3fSmrg                          const void *att)
176401e04c3fSmrg{
176501e04c3fSmrg   unsigned i;
176601e04c3fSmrg   bool progress = false;
176701e04c3fSmrg
176801e04c3fSmrg   for (i = 0; i < BUFFER_COUNT; i++) {
176901e04c3fSmrg      if (fb->Attachment[i].Texture == att
177001e04c3fSmrg          || fb->Attachment[i].Renderbuffer == att) {
177101e04c3fSmrg         remove_attachment(ctx, &fb->Attachment[i]);
177201e04c3fSmrg         progress = true;
177301e04c3fSmrg      }
177401e04c3fSmrg   }
177501e04c3fSmrg
177601e04c3fSmrg   /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer
177701e04c3fSmrg    * Completeness," of the OpenGL 3.1 spec says:
177801e04c3fSmrg    *
177901e04c3fSmrg    *     "Performing any of the following actions may change whether the
178001e04c3fSmrg    *     framebuffer is considered complete or incomplete:
178101e04c3fSmrg    *
178201e04c3fSmrg    *     ...
178301e04c3fSmrg    *
178401e04c3fSmrg    *        - Deleting, with DeleteTextures or DeleteRenderbuffers, an object
178501e04c3fSmrg    *          containing an image that is attached to a framebuffer object
178601e04c3fSmrg    *          that is bound to the framebuffer."
178701e04c3fSmrg    */
178801e04c3fSmrg   if (progress)
178901e04c3fSmrg      invalidate_framebuffer(fb);
179001e04c3fSmrg
179101e04c3fSmrg   return progress;
179201e04c3fSmrg}
179301e04c3fSmrg
179401e04c3fSmrg
179501e04c3fSmrgvoid GLAPIENTRY
179601e04c3fSmrg_mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers)
179701e04c3fSmrg{
179801e04c3fSmrg   GLint i;
179901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
180001e04c3fSmrg
180101e04c3fSmrg   if (n < 0) {
180201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteRenderbuffers(n < 0)");
180301e04c3fSmrg      return;
180401e04c3fSmrg   }
180501e04c3fSmrg
180601e04c3fSmrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
180701e04c3fSmrg
180801e04c3fSmrg   for (i = 0; i < n; i++) {
180901e04c3fSmrg      if (renderbuffers[i] > 0) {
181001e04c3fSmrg         struct gl_renderbuffer *rb;
181101e04c3fSmrg         rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
181201e04c3fSmrg         if (rb) {
181301e04c3fSmrg            /* check if deleting currently bound renderbuffer object */
181401e04c3fSmrg            if (rb == ctx->CurrentRenderbuffer) {
181501e04c3fSmrg               /* bind default */
181601e04c3fSmrg               assert(rb->RefCount >= 2);
181701e04c3fSmrg               _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
181801e04c3fSmrg            }
181901e04c3fSmrg
182001e04c3fSmrg            /* Section 4.4.2 (Attaching Images to Framebuffer Objects),
182101e04c3fSmrg             * subsection "Attaching Renderbuffer Images to a Framebuffer,"
182201e04c3fSmrg             * of the OpenGL 3.1 spec says:
182301e04c3fSmrg             *
182401e04c3fSmrg             *     "If a renderbuffer object is deleted while its image is
182501e04c3fSmrg             *     attached to one or more attachment points in the currently
182601e04c3fSmrg             *     bound framebuffer, then it is as if FramebufferRenderbuffer
182701e04c3fSmrg             *     had been called, with a renderbuffer of 0, for each
182801e04c3fSmrg             *     attachment point to which this image was attached in the
182901e04c3fSmrg             *     currently bound framebuffer. In other words, this
183001e04c3fSmrg             *     renderbuffer image is first detached from all attachment
183101e04c3fSmrg             *     points in the currently bound framebuffer. Note that the
183201e04c3fSmrg             *     renderbuffer image is specifically not detached from any
183301e04c3fSmrg             *     non-bound framebuffers. Detaching the image from any
183401e04c3fSmrg             *     non-bound framebuffers is the responsibility of the
1835af69d88dSmrg             *     application.
1836af69d88dSmrg             */
1837af69d88dSmrg            if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
1838af69d88dSmrg               _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
18394a49301eSmrg            }
1840af69d88dSmrg            if (_mesa_is_user_fbo(ctx->ReadBuffer)
18413464ebd5Sriastradh                && ctx->ReadBuffer != ctx->DrawBuffer) {
1842af69d88dSmrg               _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
18434a49301eSmrg            }
18444a49301eSmrg
184501e04c3fSmrg            /* Remove from hash table immediately, to free the ID.
18467117f1b4Smrg             * But the object will not be freed until it's no longer
18477117f1b4Smrg             * referenced anywhere else.
18487117f1b4Smrg             */
184901e04c3fSmrg            _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
18507117f1b4Smrg
18517117f1b4Smrg            if (rb != &DummyRenderbuffer) {
18527117f1b4Smrg               /* no longer referenced by hash table */
18537117f1b4Smrg               _mesa_reference_renderbuffer(&rb, NULL);
185401e04c3fSmrg            }
185501e04c3fSmrg         }
18567117f1b4Smrg      }
18577117f1b4Smrg   }
18587117f1b4Smrg}
18597117f1b4Smrg
186001e04c3fSmrgstatic void
186101e04c3fSmrgcreate_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers,
186201e04c3fSmrg                      bool dsa)
18637117f1b4Smrg{
186401e04c3fSmrg   const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers";
18657117f1b4Smrg   GLuint first;
18667117f1b4Smrg   GLint i;
18677117f1b4Smrg
18687117f1b4Smrg   if (!renderbuffers)
18697117f1b4Smrg      return;
18707117f1b4Smrg
187101e04c3fSmrg   _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
187201e04c3fSmrg
18737117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
18747117f1b4Smrg
18757117f1b4Smrg   for (i = 0; i < n; i++) {
18767117f1b4Smrg      GLuint name = first + i;
18777117f1b4Smrg      renderbuffers[i] = name;
187801e04c3fSmrg
187901e04c3fSmrg      if (dsa) {
188001e04c3fSmrg         allocate_renderbuffer_locked(ctx, name, func);
188101e04c3fSmrg      } else {
188201e04c3fSmrg         /* insert a dummy renderbuffer into the hash table */
188301e04c3fSmrg         _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, name,
188401e04c3fSmrg                                &DummyRenderbuffer);
188501e04c3fSmrg      }
188601e04c3fSmrg   }
188701e04c3fSmrg
188801e04c3fSmrg   _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
188901e04c3fSmrg}
189001e04c3fSmrg
189101e04c3fSmrg
189201e04c3fSmrgstatic void
189301e04c3fSmrgcreate_render_buffers_err(struct gl_context *ctx, GLsizei n,
189401e04c3fSmrg                          GLuint *renderbuffers, bool dsa)
189501e04c3fSmrg{
189601e04c3fSmrg   const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers";
189701e04c3fSmrg
189801e04c3fSmrg   if (n < 0) {
189901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", func);
190001e04c3fSmrg      return;
19017117f1b4Smrg   }
190201e04c3fSmrg
190301e04c3fSmrg   create_render_buffers(ctx, n, renderbuffers, dsa);
190401e04c3fSmrg}
190501e04c3fSmrg
190601e04c3fSmrg
190701e04c3fSmrgvoid GLAPIENTRY
190801e04c3fSmrg_mesa_GenRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers)
190901e04c3fSmrg{
191001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
191101e04c3fSmrg   create_render_buffers(ctx, n, renderbuffers, false);
191201e04c3fSmrg}
191301e04c3fSmrg
191401e04c3fSmrg
191501e04c3fSmrgvoid GLAPIENTRY
191601e04c3fSmrg_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers)
191701e04c3fSmrg{
191801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
191901e04c3fSmrg   create_render_buffers_err(ctx, n, renderbuffers, false);
192001e04c3fSmrg}
192101e04c3fSmrg
192201e04c3fSmrg
192301e04c3fSmrgvoid GLAPIENTRY
192401e04c3fSmrg_mesa_CreateRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers)
192501e04c3fSmrg{
192601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
192701e04c3fSmrg   create_render_buffers(ctx, n, renderbuffers, true);
192801e04c3fSmrg}
192901e04c3fSmrg
193001e04c3fSmrg
193101e04c3fSmrgvoid GLAPIENTRY
193201e04c3fSmrg_mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers)
193301e04c3fSmrg{
193401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
193501e04c3fSmrg   create_render_buffers_err(ctx, n, renderbuffers, true);
19367117f1b4Smrg}
19377117f1b4Smrg
19387117f1b4Smrg
19397117f1b4Smrg/**
19407117f1b4Smrg * Given an internal format token for a render buffer, return the
19413464ebd5Sriastradh * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
19423464ebd5Sriastradh * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE,
19433464ebd5Sriastradh * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc).
19447117f1b4Smrg *
19453464ebd5Sriastradh * This is similar to _mesa_base_tex_format() but the set of valid
19463464ebd5Sriastradh * internal formats is different.
1947cdc920a0Smrg *
19483464ebd5Sriastradh * Note that even if a format is determined to be legal here, validation
19493464ebd5Sriastradh * of the FBO may fail if the format is not supported by the driver/GPU.
19503464ebd5Sriastradh *
19513464ebd5Sriastradh * \param internalFormat  as passed to glRenderbufferStorage()
19523464ebd5Sriastradh * \return the base internal format, or 0 if internalFormat is illegal
19537117f1b4Smrg */
19547117f1b4SmrgGLenum
195501e04c3fSmrg_mesa_base_fbo_format(const struct gl_context *ctx, GLenum internalFormat)
19567117f1b4Smrg{
19573464ebd5Sriastradh   /*
19583464ebd5Sriastradh    * Notes: some formats such as alpha, luminance, etc. were added
19593464ebd5Sriastradh    * with GL_ARB_framebuffer_object.
19603464ebd5Sriastradh    */
19617117f1b4Smrg   switch (internalFormat) {
19623464ebd5Sriastradh   case GL_ALPHA:
19633464ebd5Sriastradh   case GL_ALPHA4:
19643464ebd5Sriastradh   case GL_ALPHA8:
19653464ebd5Sriastradh   case GL_ALPHA12:
19663464ebd5Sriastradh   case GL_ALPHA16:
1967af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
1968af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_ALPHA : 0;
19693464ebd5Sriastradh   case GL_LUMINANCE:
19703464ebd5Sriastradh   case GL_LUMINANCE4:
19713464ebd5Sriastradh   case GL_LUMINANCE8:
19723464ebd5Sriastradh   case GL_LUMINANCE12:
19733464ebd5Sriastradh   case GL_LUMINANCE16:
1974af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
1975af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE : 0;
19763464ebd5Sriastradh   case GL_LUMINANCE_ALPHA:
19773464ebd5Sriastradh   case GL_LUMINANCE4_ALPHA4:
19783464ebd5Sriastradh   case GL_LUMINANCE6_ALPHA2:
19793464ebd5Sriastradh   case GL_LUMINANCE8_ALPHA8:
19803464ebd5Sriastradh   case GL_LUMINANCE12_ALPHA4:
19813464ebd5Sriastradh   case GL_LUMINANCE12_ALPHA12:
19823464ebd5Sriastradh   case GL_LUMINANCE16_ALPHA16:
1983af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
1984af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE_ALPHA : 0;
19853464ebd5Sriastradh   case GL_INTENSITY:
19863464ebd5Sriastradh   case GL_INTENSITY4:
19873464ebd5Sriastradh   case GL_INTENSITY8:
19883464ebd5Sriastradh   case GL_INTENSITY12:
19893464ebd5Sriastradh   case GL_INTENSITY16:
1990af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
1991af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_INTENSITY : 0;
1992af69d88dSmrg   case GL_RGB8:
1993af69d88dSmrg      return GL_RGB;
19947117f1b4Smrg   case GL_RGB:
19957117f1b4Smrg   case GL_R3_G3_B2:
19967117f1b4Smrg   case GL_RGB4:
19977117f1b4Smrg   case GL_RGB5:
19987117f1b4Smrg   case GL_RGB10:
19997117f1b4Smrg   case GL_RGB12:
20007117f1b4Smrg   case GL_RGB16:
2001af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0;
20023464ebd5Sriastradh   case GL_SRGB8_EXT:
2003af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0;
20047117f1b4Smrg   case GL_RGBA4:
20057117f1b4Smrg   case GL_RGB5_A1:
20067117f1b4Smrg   case GL_RGBA8:
2007af69d88dSmrg      return GL_RGBA;
2008af69d88dSmrg   case GL_RGBA:
2009af69d88dSmrg   case GL_RGBA2:
20107117f1b4Smrg   case GL_RGBA12:
2011af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0;
201201e04c3fSmrg   case GL_RGBA16:
201301e04c3fSmrg      return _mesa_is_desktop_gl(ctx) || _mesa_has_EXT_texture_norm16(ctx)
201401e04c3fSmrg         ? GL_RGBA : 0;
2015af69d88dSmrg   case GL_RGB10_A2:
20163464ebd5Sriastradh   case GL_SRGB8_ALPHA8_EXT:
2017af69d88dSmrg      return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0;
20187117f1b4Smrg   case GL_STENCIL_INDEX:
20197117f1b4Smrg   case GL_STENCIL_INDEX1_EXT:
20207117f1b4Smrg   case GL_STENCIL_INDEX4_EXT:
20217117f1b4Smrg   case GL_STENCIL_INDEX16_EXT:
2022af69d88dSmrg      /* There are extensions for GL_STENCIL_INDEX1 and GL_STENCIL_INDEX4 in
2023af69d88dSmrg       * OpenGL ES, but Mesa does not currently support them.
2024af69d88dSmrg       */
2025af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_STENCIL_INDEX : 0;
2026af69d88dSmrg   case GL_STENCIL_INDEX8_EXT:
20277117f1b4Smrg      return GL_STENCIL_INDEX;
20287117f1b4Smrg   case GL_DEPTH_COMPONENT:
2029af69d88dSmrg   case GL_DEPTH_COMPONENT32:
2030af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_COMPONENT : 0;
20317117f1b4Smrg   case GL_DEPTH_COMPONENT16:
20327117f1b4Smrg   case GL_DEPTH_COMPONENT24:
20337117f1b4Smrg      return GL_DEPTH_COMPONENT;
2034af69d88dSmrg   case GL_DEPTH_STENCIL:
2035af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_STENCIL : 0;
2036af69d88dSmrg   case GL_DEPTH24_STENCIL8:
2037af69d88dSmrg      return GL_DEPTH_STENCIL;
2038af69d88dSmrg   case GL_DEPTH_COMPONENT32F:
2039af69d88dSmrg      return ctx->Version >= 30
2040af69d88dSmrg         || (ctx->API == API_OPENGL_COMPAT &&
2041af69d88dSmrg             ctx->Extensions.ARB_depth_buffer_float)
2042af69d88dSmrg         ? GL_DEPTH_COMPONENT : 0;
2043af69d88dSmrg   case GL_DEPTH32F_STENCIL8:
2044af69d88dSmrg      return ctx->Version >= 30
2045af69d88dSmrg         || (ctx->API == API_OPENGL_COMPAT &&
2046af69d88dSmrg             ctx->Extensions.ARB_depth_buffer_float)
2047af69d88dSmrg         ? GL_DEPTH_STENCIL : 0;
20483464ebd5Sriastradh   case GL_RED:
204901e04c3fSmrg      return _mesa_has_ARB_texture_rg(ctx) ? GL_RED : 0;
20503464ebd5Sriastradh   case GL_R16:
205101e04c3fSmrg      return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx)
2052af69d88dSmrg         ? GL_RED : 0;
2053af69d88dSmrg   case GL_R8:
2054af69d88dSmrg      return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
2055af69d88dSmrg         ? GL_RED : 0;
20563464ebd5Sriastradh   case GL_RG:
205701e04c3fSmrg      return _mesa_has_ARB_texture_rg(ctx) ? GL_RG : 0;
20583464ebd5Sriastradh   case GL_RG16:
205901e04c3fSmrg      return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx)
2060af69d88dSmrg         ? GL_RG : 0;
2061af69d88dSmrg   case GL_RG8:
2062af69d88dSmrg      return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
2063af69d88dSmrg         ? GL_RG : 0;
20643464ebd5Sriastradh   /* signed normalized texture formats */
20653464ebd5Sriastradh   case GL_R8_SNORM:
206601e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx)
206701e04c3fSmrg         ? GL_RED : 0;
206801e04c3fSmrg   case GL_RED_SNORM:
206901e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ? GL_RED : 0;
20703464ebd5Sriastradh   case GL_R16_SNORM:
207101e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ||
207201e04c3fSmrg             (_mesa_has_EXT_render_snorm(ctx) &&
207301e04c3fSmrg              _mesa_has_EXT_texture_norm16(ctx))
2074af69d88dSmrg         ? GL_RED : 0;
20753464ebd5Sriastradh   case GL_RG8_SNORM:
207601e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx)
207701e04c3fSmrg         ? GL_RG : 0;
207801e04c3fSmrg   case GL_RG_SNORM:
207901e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ? GL_RG : 0;
20803464ebd5Sriastradh   case GL_RG16_SNORM:
208101e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ||
208201e04c3fSmrg             (_mesa_has_EXT_render_snorm(ctx) &&
208301e04c3fSmrg              _mesa_has_EXT_texture_norm16(ctx))
2084af69d88dSmrg         ? GL_RG : 0;
20853464ebd5Sriastradh   case GL_RGB_SNORM:
20863464ebd5Sriastradh   case GL_RGB8_SNORM:
20873464ebd5Sriastradh   case GL_RGB16_SNORM:
2088af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
2089af69d88dSmrg         ? GL_RGB : 0;
20903464ebd5Sriastradh   case GL_RGBA8_SNORM:
209101e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx)
209201e04c3fSmrg         ? GL_RGBA : 0;
209301e04c3fSmrg   case GL_RGBA_SNORM:
209401e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ? GL_RGBA : 0;
20953464ebd5Sriastradh   case GL_RGBA16_SNORM:
209601e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ||
209701e04c3fSmrg             (_mesa_has_EXT_render_snorm(ctx) &&
209801e04c3fSmrg              _mesa_has_EXT_texture_norm16(ctx))
2099af69d88dSmrg         ? GL_RGBA : 0;
21003464ebd5Sriastradh   case GL_ALPHA_SNORM:
21013464ebd5Sriastradh   case GL_ALPHA8_SNORM:
21023464ebd5Sriastradh   case GL_ALPHA16_SNORM:
2103af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2104af69d88dSmrg             ctx->Extensions.EXT_texture_snorm &&
21053464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
21063464ebd5Sriastradh   case GL_LUMINANCE_SNORM:
21073464ebd5Sriastradh   case GL_LUMINANCE8_SNORM:
21083464ebd5Sriastradh   case GL_LUMINANCE16_SNORM:
2109af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
2110af69d88dSmrg         ? GL_LUMINANCE : 0;
21113464ebd5Sriastradh   case GL_LUMINANCE_ALPHA_SNORM:
21123464ebd5Sriastradh   case GL_LUMINANCE8_ALPHA8_SNORM:
21133464ebd5Sriastradh   case GL_LUMINANCE16_ALPHA16_SNORM:
2114af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
2115af69d88dSmrg         ? GL_LUMINANCE_ALPHA : 0;
21163464ebd5Sriastradh   case GL_INTENSITY_SNORM:
21173464ebd5Sriastradh   case GL_INTENSITY8_SNORM:
21183464ebd5Sriastradh   case GL_INTENSITY16_SNORM:
2119af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
2120af69d88dSmrg         ? GL_INTENSITY : 0;
2121af69d88dSmrg
21223464ebd5Sriastradh   case GL_R16F:
21233464ebd5Sriastradh   case GL_R32F:
2124af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) &&
2125af69d88dSmrg               ctx->Extensions.ARB_texture_rg &&
2126af69d88dSmrg               ctx->Extensions.ARB_texture_float) ||
2127af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
2128af69d88dSmrg         ? GL_RED : 0;
21293464ebd5Sriastradh   case GL_RG16F:
21303464ebd5Sriastradh   case GL_RG32F:
2131af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) &&
2132af69d88dSmrg               ctx->Extensions.ARB_texture_rg &&
2133af69d88dSmrg               ctx->Extensions.ARB_texture_float) ||
2134af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
2135af69d88dSmrg         ? GL_RG : 0;
21363464ebd5Sriastradh   case GL_RGB16F:
21373464ebd5Sriastradh   case GL_RGB32F:
2138af69d88dSmrg      return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float)
2139af69d88dSmrg         ? GL_RGB : 0;
21403464ebd5Sriastradh   case GL_RGBA16F:
21413464ebd5Sriastradh   case GL_RGBA32F:
2142af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) &&
2143af69d88dSmrg               ctx->Extensions.ARB_texture_float) ||
2144af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
2145af69d88dSmrg         ? GL_RGBA : 0;
214601e04c3fSmrg   case GL_RGB9_E5:
214701e04c3fSmrg      return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_shared_exponent)
214801e04c3fSmrg         ? GL_RGB: 0;
21493464ebd5Sriastradh   case GL_ALPHA16F_ARB:
21503464ebd5Sriastradh   case GL_ALPHA32F_ARB:
2151af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2152af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
21533464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
21543464ebd5Sriastradh   case GL_LUMINANCE16F_ARB:
21553464ebd5Sriastradh   case GL_LUMINANCE32F_ARB:
2156af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2157af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
21583464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
21593464ebd5Sriastradh   case GL_LUMINANCE_ALPHA16F_ARB:
21603464ebd5Sriastradh   case GL_LUMINANCE_ALPHA32F_ARB:
2161af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2162af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
21633464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
21643464ebd5Sriastradh   case GL_INTENSITY16F_ARB:
21653464ebd5Sriastradh   case GL_INTENSITY32F_ARB:
2166af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2167af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
21683464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
21693464ebd5Sriastradh   case GL_R11F_G11F_B10F:
2170af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) ||
2171af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
2172af69d88dSmrg         ? GL_RGB : 0;
2173af69d88dSmrg
2174af69d88dSmrg   case GL_RGBA8UI_EXT:
2175af69d88dSmrg   case GL_RGBA16UI_EXT:
2176af69d88dSmrg   case GL_RGBA32UI_EXT:
2177af69d88dSmrg   case GL_RGBA8I_EXT:
2178af69d88dSmrg   case GL_RGBA16I_EXT:
2179af69d88dSmrg   case GL_RGBA32I_EXT:
2180af69d88dSmrg      return ctx->Version >= 30
2181af69d88dSmrg         || (_mesa_is_desktop_gl(ctx) &&
2182af69d88dSmrg             ctx->Extensions.EXT_texture_integer) ? GL_RGBA : 0;
2183af69d88dSmrg
2184af69d88dSmrg   case GL_RGB8UI_EXT:
2185af69d88dSmrg   case GL_RGB16UI_EXT:
2186af69d88dSmrg   case GL_RGB32UI_EXT:
2187af69d88dSmrg   case GL_RGB8I_EXT:
2188af69d88dSmrg   case GL_RGB16I_EXT:
2189af69d88dSmrg   case GL_RGB32I_EXT:
2190af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_integer
2191af69d88dSmrg         ? GL_RGB : 0;
2192af69d88dSmrg   case GL_R8UI:
2193af69d88dSmrg   case GL_R8I:
2194af69d88dSmrg   case GL_R16UI:
2195af69d88dSmrg   case GL_R16I:
2196af69d88dSmrg   case GL_R32UI:
2197af69d88dSmrg   case GL_R32I:
2198af69d88dSmrg      return ctx->Version >= 30
2199af69d88dSmrg         || (_mesa_is_desktop_gl(ctx) &&
2200af69d88dSmrg             ctx->Extensions.ARB_texture_rg &&
2201af69d88dSmrg             ctx->Extensions.EXT_texture_integer) ? GL_RED : 0;
2202af69d88dSmrg
2203af69d88dSmrg   case GL_RG8UI:
2204af69d88dSmrg   case GL_RG8I:
2205af69d88dSmrg   case GL_RG16UI:
2206af69d88dSmrg   case GL_RG16I:
2207af69d88dSmrg   case GL_RG32UI:
2208af69d88dSmrg   case GL_RG32I:
2209af69d88dSmrg      return ctx->Version >= 30
2210af69d88dSmrg         || (_mesa_is_desktop_gl(ctx) &&
2211af69d88dSmrg             ctx->Extensions.ARB_texture_rg &&
2212af69d88dSmrg             ctx->Extensions.EXT_texture_integer) ? GL_RG : 0;
2213af69d88dSmrg
2214af69d88dSmrg   case GL_INTENSITY8I_EXT:
2215af69d88dSmrg   case GL_INTENSITY8UI_EXT:
2216af69d88dSmrg   case GL_INTENSITY16I_EXT:
2217af69d88dSmrg   case GL_INTENSITY16UI_EXT:
2218af69d88dSmrg   case GL_INTENSITY32I_EXT:
2219af69d88dSmrg   case GL_INTENSITY32UI_EXT:
2220af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2221af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
2222af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
2223af69d88dSmrg
2224af69d88dSmrg   case GL_LUMINANCE8I_EXT:
2225af69d88dSmrg   case GL_LUMINANCE8UI_EXT:
2226af69d88dSmrg   case GL_LUMINANCE16I_EXT:
2227af69d88dSmrg   case GL_LUMINANCE16UI_EXT:
2228af69d88dSmrg   case GL_LUMINANCE32I_EXT:
2229af69d88dSmrg   case GL_LUMINANCE32UI_EXT:
2230af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2231af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
2232af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
2233af69d88dSmrg
2234af69d88dSmrg   case GL_LUMINANCE_ALPHA8I_EXT:
2235af69d88dSmrg   case GL_LUMINANCE_ALPHA8UI_EXT:
2236af69d88dSmrg   case GL_LUMINANCE_ALPHA16I_EXT:
2237af69d88dSmrg   case GL_LUMINANCE_ALPHA16UI_EXT:
2238af69d88dSmrg   case GL_LUMINANCE_ALPHA32I_EXT:
2239af69d88dSmrg   case GL_LUMINANCE_ALPHA32UI_EXT:
2240af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2241af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
2242af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
2243af69d88dSmrg
2244af69d88dSmrg   case GL_ALPHA8I_EXT:
2245af69d88dSmrg   case GL_ALPHA8UI_EXT:
2246af69d88dSmrg   case GL_ALPHA16I_EXT:
2247af69d88dSmrg   case GL_ALPHA16UI_EXT:
2248af69d88dSmrg   case GL_ALPHA32I_EXT:
2249af69d88dSmrg   case GL_ALPHA32UI_EXT:
2250af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2251af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
2252af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
2253af69d88dSmrg
2254af69d88dSmrg   case GL_RGB10_A2UI:
2255af69d88dSmrg      return (_mesa_is_desktop_gl(ctx) &&
2256af69d88dSmrg              ctx->Extensions.ARB_texture_rgb10_a2ui)
2257af69d88dSmrg         || _mesa_is_gles3(ctx) ? GL_RGBA : 0;
2258af69d88dSmrg
2259af69d88dSmrg   case GL_RGB565:
2260af69d88dSmrg      return _mesa_is_gles(ctx) || ctx->Extensions.ARB_ES2_compatibility
2261af69d88dSmrg         ? GL_RGB : 0;
2262af69d88dSmrg   default:
2263af69d88dSmrg      return 0;
2264af69d88dSmrg   }
22657117f1b4Smrg}
22667117f1b4Smrg
22677117f1b4Smrg
22683464ebd5Sriastradh/**
22693464ebd5Sriastradh * Invalidate a renderbuffer attachment.  Called from _mesa_HashWalk().
22703464ebd5Sriastradh */
22713464ebd5Sriastradhstatic void
22723464ebd5Sriastradhinvalidate_rb(GLuint key, void *data, void *userData)
22733464ebd5Sriastradh{
22743464ebd5Sriastradh   struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
22753464ebd5Sriastradh   struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData;
22763464ebd5Sriastradh
22773464ebd5Sriastradh   /* If this is a user-created FBO */
2278af69d88dSmrg   if (_mesa_is_user_fbo(fb)) {
22793464ebd5Sriastradh      GLuint i;
22803464ebd5Sriastradh      for (i = 0; i < BUFFER_COUNT; i++) {
22813464ebd5Sriastradh         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
22823464ebd5Sriastradh         if (att->Type == GL_RENDERBUFFER &&
22833464ebd5Sriastradh             att->Renderbuffer == rb) {
22843464ebd5Sriastradh            /* Mark fb status as indeterminate to force re-validation */
22853464ebd5Sriastradh            fb->_Status = 0;
22863464ebd5Sriastradh            return;
22873464ebd5Sriastradh         }
22883464ebd5Sriastradh      }
22893464ebd5Sriastradh   }
22903464ebd5Sriastradh}
22913464ebd5Sriastradh
22923464ebd5Sriastradh
22934a49301eSmrg/** sentinal value, see below */
22944a49301eSmrg#define NO_SAMPLES 1000
22954a49301eSmrg
229601e04c3fSmrgvoid
229701e04c3fSmrg_mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
229801e04c3fSmrg                           GLenum internalFormat, GLsizei width,
229901e04c3fSmrg                           GLsizei height, GLsizei samples,
230001e04c3fSmrg                           GLsizei storageSamples)
23017117f1b4Smrg{
230201e04c3fSmrg   const GLenum baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
230301e04c3fSmrg
230401e04c3fSmrg   assert(baseFormat != 0);
230501e04c3fSmrg   assert(width >= 0 && width <= (GLsizei) ctx->Const.MaxRenderbufferSize);
230601e04c3fSmrg   assert(height >= 0 && height <= (GLsizei) ctx->Const.MaxRenderbufferSize);
230701e04c3fSmrg   assert(samples != NO_SAMPLES);
230801e04c3fSmrg   if (samples != 0) {
230901e04c3fSmrg      assert(samples > 0);
231001e04c3fSmrg      assert(_mesa_check_sample_count(ctx, GL_RENDERBUFFER,
231101e04c3fSmrg                                      internalFormat, samples,
231201e04c3fSmrg                                      storageSamples) == GL_NO_ERROR);
23137117f1b4Smrg   }
23147117f1b4Smrg
231501e04c3fSmrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
23167117f1b4Smrg
231701e04c3fSmrg   if (rb->InternalFormat == internalFormat &&
231801e04c3fSmrg       rb->Width == (GLuint) width &&
231901e04c3fSmrg       rb->Height == (GLuint) height &&
232001e04c3fSmrg       rb->NumSamples == samples &&
232101e04c3fSmrg       rb->NumStorageSamples == storageSamples) {
232201e04c3fSmrg      /* no change in allocation needed */
23237117f1b4Smrg      return;
23247117f1b4Smrg   }
23257117f1b4Smrg
23267117f1b4Smrg   /* These MUST get set by the AllocStorage func */
23274a49301eSmrg   rb->Format = MESA_FORMAT_NONE;
23284a49301eSmrg   rb->NumSamples = samples;
232901e04c3fSmrg   rb->NumStorageSamples = storageSamples;
23307117f1b4Smrg
23317117f1b4Smrg   /* Now allocate the storage */
233201e04c3fSmrg   assert(rb->AllocStorage);
23337117f1b4Smrg   if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
23347117f1b4Smrg      /* No error - check/set fields now */
2335af69d88dSmrg      /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */
23367117f1b4Smrg      assert(rb->Width == (GLuint) width);
23377117f1b4Smrg      assert(rb->Height == (GLuint) height);
23387117f1b4Smrg      rb->InternalFormat = internalFormat;
2339cdc920a0Smrg      rb->_BaseFormat = baseFormat;
23404a49301eSmrg      assert(rb->_BaseFormat != 0);
23417117f1b4Smrg   }
23427117f1b4Smrg   else {
23437117f1b4Smrg      /* Probably ran out of memory - clear the fields */
23447117f1b4Smrg      rb->Width = 0;
23457117f1b4Smrg      rb->Height = 0;
23464a49301eSmrg      rb->Format = MESA_FORMAT_NONE;
23477117f1b4Smrg      rb->InternalFormat = GL_NONE;
23487117f1b4Smrg      rb->_BaseFormat = GL_NONE;
23494a49301eSmrg      rb->NumSamples = 0;
235001e04c3fSmrg      rb->NumStorageSamples = 0;
23517117f1b4Smrg   }
23527117f1b4Smrg
23533464ebd5Sriastradh   /* Invalidate the framebuffers the renderbuffer is attached in. */
23543464ebd5Sriastradh   if (rb->AttachedAnytime) {
23553464ebd5Sriastradh      _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb);
23563464ebd5Sriastradh   }
23577117f1b4Smrg}
23587117f1b4Smrg
235901e04c3fSmrg/**
236001e04c3fSmrg * Helper function used by renderbuffer_storage_direct() and
236101e04c3fSmrg * renderbuffer_storage_target().
236201e04c3fSmrg * samples will be NO_SAMPLES if called by a non-multisample function.
236301e04c3fSmrg */
236401e04c3fSmrgstatic void
236501e04c3fSmrgrenderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
236601e04c3fSmrg                     GLenum internalFormat, GLsizei width,
236701e04c3fSmrg                     GLsizei height, GLsizei samples, GLsizei storageSamples,
236801e04c3fSmrg                     const char *func)
236901e04c3fSmrg{
237001e04c3fSmrg   GLenum baseFormat;
237101e04c3fSmrg   GLenum sample_count_error;
237201e04c3fSmrg
237301e04c3fSmrg   baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
237401e04c3fSmrg   if (baseFormat == 0) {
237501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)",
237601e04c3fSmrg                  func, _mesa_enum_to_string(internalFormat));
237701e04c3fSmrg      return;
237801e04c3fSmrg   }
237901e04c3fSmrg
238001e04c3fSmrg   if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
238101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid width %d)", func,
238201e04c3fSmrg                  width);
238301e04c3fSmrg      return;
238401e04c3fSmrg   }
238501e04c3fSmrg
238601e04c3fSmrg   if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
238701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid height %d)", func,
238801e04c3fSmrg                  height);
238901e04c3fSmrg      return;
239001e04c3fSmrg   }
239101e04c3fSmrg
239201e04c3fSmrg   if (samples == NO_SAMPLES) {
239301e04c3fSmrg      /* NumSamples == 0 indicates non-multisampling */
239401e04c3fSmrg      samples = 0;
239501e04c3fSmrg      storageSamples = 0;
239601e04c3fSmrg   }
239701e04c3fSmrg   else {
239801e04c3fSmrg      /* check the sample count;
239901e04c3fSmrg       * note: driver may choose to use more samples than what's requested
240001e04c3fSmrg       */
240101e04c3fSmrg      sample_count_error = _mesa_check_sample_count(ctx, GL_RENDERBUFFER,
240201e04c3fSmrg            internalFormat, samples, storageSamples);
240301e04c3fSmrg
240401e04c3fSmrg      /* Section 2.5 (GL Errors) of OpenGL 3.0 specification, page 16:
240501e04c3fSmrg       *
240601e04c3fSmrg       * "If a negative number is provided where an argument of type sizei or
240701e04c3fSmrg       * sizeiptr is specified, the error INVALID VALUE is generated."
240801e04c3fSmrg       */
240901e04c3fSmrg      if (samples < 0 || storageSamples < 0) {
241001e04c3fSmrg         sample_count_error = GL_INVALID_VALUE;
241101e04c3fSmrg      }
241201e04c3fSmrg
241301e04c3fSmrg      if (sample_count_error != GL_NO_ERROR) {
241401e04c3fSmrg         _mesa_error(ctx, sample_count_error,
241501e04c3fSmrg                     "%s(samples=%d, storageSamples=%d)", func, samples,
241601e04c3fSmrg                     storageSamples);
241701e04c3fSmrg         return;
241801e04c3fSmrg      }
241901e04c3fSmrg   }
242001e04c3fSmrg
242101e04c3fSmrg   _mesa_renderbuffer_storage(ctx, rb, internalFormat, width, height, samples,
242201e04c3fSmrg                              storageSamples);
242301e04c3fSmrg}
242401e04c3fSmrg
242501e04c3fSmrg/**
242601e04c3fSmrg * Helper function used by _mesa_NamedRenderbufferStorage*().
242701e04c3fSmrg * samples will be NO_SAMPLES if called by a non-multisample function.
242801e04c3fSmrg */
242901e04c3fSmrgstatic void
243001e04c3fSmrgrenderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat,
243101e04c3fSmrg                           GLsizei width, GLsizei height, GLsizei samples,
243201e04c3fSmrg                           GLsizei storageSamples, const char *func)
243301e04c3fSmrg{
243401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
243501e04c3fSmrg
243601e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
243701e04c3fSmrg      if (samples == NO_SAMPLES)
243801e04c3fSmrg         _mesa_debug(ctx, "%s(%u, %s, %d, %d)\n",
243901e04c3fSmrg                     func, renderbuffer,
244001e04c3fSmrg                     _mesa_enum_to_string(internalFormat),
244101e04c3fSmrg                     width, height);
244201e04c3fSmrg      else
244301e04c3fSmrg         _mesa_debug(ctx, "%s(%u, %s, %d, %d, %d)\n",
244401e04c3fSmrg                     func, renderbuffer,
244501e04c3fSmrg                     _mesa_enum_to_string(internalFormat),
244601e04c3fSmrg                     width, height, samples);
244701e04c3fSmrg   }
244801e04c3fSmrg
244901e04c3fSmrg   struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
245001e04c3fSmrg   if (!rb || rb == &DummyRenderbuffer) {
245101e04c3fSmrg      /* ID was reserved, but no real renderbuffer object made yet */
245201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid renderbuffer %u)",
245301e04c3fSmrg                  func, renderbuffer);
245401e04c3fSmrg      return;
245501e04c3fSmrg   }
245601e04c3fSmrg
245701e04c3fSmrg   renderbuffer_storage(ctx, rb, internalFormat, width, height, samples,
245801e04c3fSmrg                        storageSamples, func);
245901e04c3fSmrg}
246001e04c3fSmrg
246101e04c3fSmrg/**
246201e04c3fSmrg * Helper function used by _mesa_RenderbufferStorage() and
246301e04c3fSmrg * _mesa_RenderbufferStorageMultisample().
246401e04c3fSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorage().
246501e04c3fSmrg */
246601e04c3fSmrgstatic void
246701e04c3fSmrgrenderbuffer_storage_target(GLenum target, GLenum internalFormat,
246801e04c3fSmrg                            GLsizei width, GLsizei height, GLsizei samples,
246901e04c3fSmrg                            GLsizei storageSamples, const char *func)
247001e04c3fSmrg{
247101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
247201e04c3fSmrg
247301e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
247401e04c3fSmrg      if (samples == NO_SAMPLES)
247501e04c3fSmrg         _mesa_debug(ctx, "%s(%s, %s, %d, %d)\n",
247601e04c3fSmrg                     func,
247701e04c3fSmrg                     _mesa_enum_to_string(target),
247801e04c3fSmrg                     _mesa_enum_to_string(internalFormat),
247901e04c3fSmrg                     width, height);
248001e04c3fSmrg      else
248101e04c3fSmrg         _mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n",
248201e04c3fSmrg                     func,
248301e04c3fSmrg                     _mesa_enum_to_string(target),
248401e04c3fSmrg                     _mesa_enum_to_string(internalFormat),
248501e04c3fSmrg                     width, height, samples);
248601e04c3fSmrg   }
248701e04c3fSmrg
248801e04c3fSmrg   if (target != GL_RENDERBUFFER_EXT) {
248901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
249001e04c3fSmrg      return;
249101e04c3fSmrg   }
249201e04c3fSmrg
249301e04c3fSmrg   if (!ctx->CurrentRenderbuffer) {
249401e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no renderbuffer bound)",
249501e04c3fSmrg                  func);
249601e04c3fSmrg      return;
249701e04c3fSmrg   }
249801e04c3fSmrg
249901e04c3fSmrg   renderbuffer_storage(ctx, ctx->CurrentRenderbuffer, internalFormat, width,
250001e04c3fSmrg                        height, samples, storageSamples, func);
250101e04c3fSmrg}
250201e04c3fSmrg
25033464ebd5Sriastradh
2504cdc920a0Smrgvoid GLAPIENTRY
25053464ebd5Sriastradh_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
2506cdc920a0Smrg{
2507cdc920a0Smrg   struct gl_renderbuffer *rb;
2508cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
2509cdc920a0Smrg
25103464ebd5Sriastradh   if (!ctx->Extensions.OES_EGL_image) {
25113464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
25123464ebd5Sriastradh                  "glEGLImageTargetRenderbufferStorageOES(unsupported)");
25133464ebd5Sriastradh      return;
25143464ebd5Sriastradh   }
25153464ebd5Sriastradh
2516cdc920a0Smrg   if (target != GL_RENDERBUFFER) {
25173464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_ENUM,
25183464ebd5Sriastradh                  "EGLImageTargetRenderbufferStorageOES");
2519cdc920a0Smrg      return;
2520cdc920a0Smrg   }
2521cdc920a0Smrg
2522cdc920a0Smrg   rb = ctx->CurrentRenderbuffer;
2523cdc920a0Smrg   if (!rb) {
25243464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
25253464ebd5Sriastradh                  "EGLImageTargetRenderbufferStorageOES");
2526cdc920a0Smrg      return;
2527cdc920a0Smrg   }
2528cdc920a0Smrg
2529cdc920a0Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2530cdc920a0Smrg
2531cdc920a0Smrg   ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
2532cdc920a0Smrg}
25337117f1b4Smrg
25343464ebd5Sriastradh
25354a49301eSmrg/**
2536af69d88dSmrg * Helper function for _mesa_GetRenderbufferParameteriv() and
2537af69d88dSmrg * _mesa_GetFramebufferAttachmentParameteriv()
25384a49301eSmrg * We have to be careful to respect the base format.  For example, if a
25394a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the
25404a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
25414a49301eSmrg * we need to return zero.
25424a49301eSmrg */
25434a49301eSmrgstatic GLint
2544af69d88dSmrgget_component_bits(GLenum pname, GLenum baseFormat, mesa_format format)
25454a49301eSmrg{
2546af69d88dSmrg   if (_mesa_base_format_has_channel(baseFormat, pname))
2547af69d88dSmrg      return _mesa_get_format_bits(format, pname);
2548af69d88dSmrg   else
25494a49301eSmrg      return 0;
25504a49301eSmrg}
25514a49301eSmrg
25524a49301eSmrg
25534a49301eSmrg
25544a49301eSmrgvoid GLAPIENTRY
2555af69d88dSmrg_mesa_RenderbufferStorage(GLenum target, GLenum internalFormat,
25564a49301eSmrg                             GLsizei width, GLsizei height)
25574a49301eSmrg{
25584a49301eSmrg   /* GL_ARB_fbo says calling this function is equivalent to calling
25594a49301eSmrg    * glRenderbufferStorageMultisample() with samples=0.  We pass in
25604a49301eSmrg    * a token value here just for error reporting purposes.
25614a49301eSmrg    */
256201e04c3fSmrg   renderbuffer_storage_target(target, internalFormat, width, height,
256301e04c3fSmrg                               NO_SAMPLES, 0, "glRenderbufferStorage");
25644a49301eSmrg}
25654a49301eSmrg
25664a49301eSmrg
25674a49301eSmrgvoid GLAPIENTRY
25684a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
25694a49301eSmrg                                     GLenum internalFormat,
25704a49301eSmrg                                     GLsizei width, GLsizei height)
25714a49301eSmrg{
257201e04c3fSmrg   renderbuffer_storage_target(target, internalFormat, width, height,
257301e04c3fSmrg                               samples, samples,
257401e04c3fSmrg                               "glRenderbufferStorageMultisample");
257501e04c3fSmrg}
257601e04c3fSmrg
257701e04c3fSmrg
257801e04c3fSmrgvoid GLAPIENTRY
257901e04c3fSmrg_mesa_RenderbufferStorageMultisampleAdvancedAMD(
258001e04c3fSmrg      GLenum target, GLsizei samples, GLsizei storageSamples,
258101e04c3fSmrg      GLenum internalFormat, GLsizei width, GLsizei height)
258201e04c3fSmrg{
258301e04c3fSmrg   renderbuffer_storage_target(target, internalFormat, width, height,
258401e04c3fSmrg                               samples, storageSamples,
258501e04c3fSmrg                               "glRenderbufferStorageMultisampleAdvancedAMD");
25864a49301eSmrg}
25874a49301eSmrg
25884a49301eSmrg
25893464ebd5Sriastradh/**
25903464ebd5Sriastradh * OpenGL ES version of glRenderBufferStorage.
25913464ebd5Sriastradh */
25923464ebd5Sriastradhvoid GLAPIENTRY
25933464ebd5Sriastradh_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
259401e04c3fSmrg                           GLsizei width, GLsizei height)
25953464ebd5Sriastradh{
25963464ebd5Sriastradh   switch (internalFormat) {
25973464ebd5Sriastradh   case GL_RGB565:
25983464ebd5Sriastradh      /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
25993464ebd5Sriastradh      /* choose a closest format */
26003464ebd5Sriastradh      internalFormat = GL_RGB5;
26013464ebd5Sriastradh      break;
26023464ebd5Sriastradh   default:
26033464ebd5Sriastradh      break;
26043464ebd5Sriastradh   }
26053464ebd5Sriastradh
260601e04c3fSmrg   renderbuffer_storage_target(target, internalFormat, width, height, 0, 0,
260701e04c3fSmrg                               "glRenderbufferStorageEXT");
26083464ebd5Sriastradh}
26093464ebd5Sriastradh
261001e04c3fSmrgvoid GLAPIENTRY
261101e04c3fSmrg_mesa_NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat,
261201e04c3fSmrg                               GLsizei width, GLsizei height)
261301e04c3fSmrg{
261401e04c3fSmrg   /* GL_ARB_fbo says calling this function is equivalent to calling
261501e04c3fSmrg    * glRenderbufferStorageMultisample() with samples=0.  We pass in
261601e04c3fSmrg    * a token value here just for error reporting purposes.
261701e04c3fSmrg    */
261801e04c3fSmrg   renderbuffer_storage_named(renderbuffer, internalformat, width, height,
261901e04c3fSmrg                              NO_SAMPLES, 0, "glNamedRenderbufferStorage");
262001e04c3fSmrg}
26214a49301eSmrg
26227117f1b4Smrgvoid GLAPIENTRY
262301e04c3fSmrg_mesa_NamedRenderbufferStorageMultisample(GLuint renderbuffer, GLsizei samples,
262401e04c3fSmrg                                          GLenum internalformat,
262501e04c3fSmrg                                          GLsizei width, GLsizei height)
26267117f1b4Smrg{
262701e04c3fSmrg   renderbuffer_storage_named(renderbuffer, internalformat, width, height,
262801e04c3fSmrg                              samples, samples,
262901e04c3fSmrg                              "glNamedRenderbufferStorageMultisample");
263001e04c3fSmrg}
26317117f1b4Smrg
26327117f1b4Smrg
263301e04c3fSmrgvoid GLAPIENTRY
263401e04c3fSmrg_mesa_NamedRenderbufferStorageMultisampleAdvancedAMD(
263501e04c3fSmrg      GLuint renderbuffer, GLsizei samples, GLsizei storageSamples,
263601e04c3fSmrg      GLenum internalformat, GLsizei width, GLsizei height)
263701e04c3fSmrg{
263801e04c3fSmrg   renderbuffer_storage_named(renderbuffer, internalformat, width, height,
263901e04c3fSmrg                              samples, storageSamples,
264001e04c3fSmrg                              "glNamedRenderbufferStorageMultisampleAdvancedAMD");
264101e04c3fSmrg}
264201e04c3fSmrg
26437117f1b4Smrg
264401e04c3fSmrgstatic void
264501e04c3fSmrgget_render_buffer_parameteriv(struct gl_context *ctx,
264601e04c3fSmrg                              struct gl_renderbuffer *rb, GLenum pname,
264701e04c3fSmrg                              GLint *params, const char *func)
264801e04c3fSmrg{
26494a49301eSmrg   /* No need to flush here since we're just quering state which is
26504a49301eSmrg    * not effected by rendering.
26514a49301eSmrg    */
26527117f1b4Smrg
26537117f1b4Smrg   switch (pname) {
26547117f1b4Smrg   case GL_RENDERBUFFER_WIDTH_EXT:
26554a49301eSmrg      *params = rb->Width;
26567117f1b4Smrg      return;
26577117f1b4Smrg   case GL_RENDERBUFFER_HEIGHT_EXT:
26584a49301eSmrg      *params = rb->Height;
26597117f1b4Smrg      return;
26607117f1b4Smrg   case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
26614a49301eSmrg      *params = rb->InternalFormat;
26627117f1b4Smrg      return;
26637117f1b4Smrg   case GL_RENDERBUFFER_RED_SIZE_EXT:
26647117f1b4Smrg   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
26657117f1b4Smrg   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
26667117f1b4Smrg   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
26677117f1b4Smrg   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
26687117f1b4Smrg   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
26694a49301eSmrg      *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
267001e04c3fSmrg      return;
26714a49301eSmrg   case GL_RENDERBUFFER_SAMPLES:
2672af69d88dSmrg      if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object)
2673af69d88dSmrg          || _mesa_is_gles3(ctx)) {
26744a49301eSmrg         *params = rb->NumSamples;
267501e04c3fSmrg         return;
26764a49301eSmrg      }
267701e04c3fSmrg      break;
267801e04c3fSmrg   case GL_RENDERBUFFER_STORAGE_SAMPLES_AMD:
267901e04c3fSmrg      if (ctx->Extensions.AMD_framebuffer_multisample_advanced) {
268001e04c3fSmrg         *params = rb->NumStorageSamples;
268101e04c3fSmrg         return;
268201e04c3fSmrg      }
268301e04c3fSmrg      break;
268401e04c3fSmrg   }
268501e04c3fSmrg
268601e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname=%s)", func,
268701e04c3fSmrg               _mesa_enum_to_string(pname));
268801e04c3fSmrg}
268901e04c3fSmrg
269001e04c3fSmrg
269101e04c3fSmrgvoid GLAPIENTRY
269201e04c3fSmrg_mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params)
269301e04c3fSmrg{
269401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
269501e04c3fSmrg
269601e04c3fSmrg   if (target != GL_RENDERBUFFER_EXT) {
26977117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
26987117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
26997117f1b4Smrg      return;
27007117f1b4Smrg   }
270101e04c3fSmrg
270201e04c3fSmrg   if (!ctx->CurrentRenderbuffer) {
270301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetRenderbufferParameterivEXT"
270401e04c3fSmrg                  "(no renderbuffer bound)");
270501e04c3fSmrg      return;
270601e04c3fSmrg   }
270701e04c3fSmrg
270801e04c3fSmrg   get_render_buffer_parameteriv(ctx, ctx->CurrentRenderbuffer, pname,
270901e04c3fSmrg                                 params, "glGetRenderbufferParameteriv");
271001e04c3fSmrg}
271101e04c3fSmrg
271201e04c3fSmrg
271301e04c3fSmrgvoid GLAPIENTRY
271401e04c3fSmrg_mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname,
271501e04c3fSmrg                                      GLint *params)
271601e04c3fSmrg{
271701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
271801e04c3fSmrg
271901e04c3fSmrg   struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
272001e04c3fSmrg   if (!rb || rb == &DummyRenderbuffer) {
272101e04c3fSmrg      /* ID was reserved, but no real renderbuffer object made yet */
272201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetNamedRenderbufferParameteriv"
272301e04c3fSmrg                  "(invalid renderbuffer %i)", renderbuffer);
272401e04c3fSmrg      return;
272501e04c3fSmrg   }
272601e04c3fSmrg
272701e04c3fSmrg   get_render_buffer_parameteriv(ctx, rb, pname, params,
272801e04c3fSmrg                                 "glGetNamedRenderbufferParameteriv");
27297117f1b4Smrg}
27307117f1b4Smrg
27317117f1b4Smrg
27327117f1b4SmrgGLboolean GLAPIENTRY
2733af69d88dSmrg_mesa_IsFramebuffer(GLuint framebuffer)
27347117f1b4Smrg{
27357117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
27367117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
27377117f1b4Smrg   if (framebuffer) {
27387117f1b4Smrg      struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
27397117f1b4Smrg      if (rb != NULL && rb != &DummyFramebuffer)
27407117f1b4Smrg         return GL_TRUE;
27417117f1b4Smrg   }
27427117f1b4Smrg   return GL_FALSE;
27437117f1b4Smrg}
27447117f1b4Smrg
27457117f1b4Smrg
27464a49301eSmrg/**
27474a49301eSmrg * Check if any of the attachments of the given framebuffer are textures
27484a49301eSmrg * (render to texture).  Call ctx->Driver.RenderTexture() for such
27494a49301eSmrg * attachments.
27504a49301eSmrg */
27517117f1b4Smrgstatic void
27523464ebd5Sriastradhcheck_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
27537117f1b4Smrg{
27547117f1b4Smrg   GLuint i;
275501e04c3fSmrg   assert(ctx->Driver.RenderTexture);
27564a49301eSmrg
2757af69d88dSmrg   if (_mesa_is_winsys_fbo(fb))
27584a49301eSmrg      return; /* can't render to texture with winsys framebuffers */
27594a49301eSmrg
27607117f1b4Smrg   for (i = 0; i < BUFFER_COUNT; i++) {
27617117f1b4Smrg      struct gl_renderbuffer_attachment *att = fb->Attachment + i;
2762af69d88dSmrg      if (att->Texture && att->Renderbuffer->TexImage
2763af69d88dSmrg          && driver_RenderTexture_is_safe(att)) {
27647117f1b4Smrg         ctx->Driver.RenderTexture(ctx, fb, att);
27657117f1b4Smrg      }
27667117f1b4Smrg   }
27677117f1b4Smrg}
27687117f1b4Smrg
27697117f1b4Smrg
27707117f1b4Smrg/**
27717117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures.
27727117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to
27737117f1b4Smrg * notify the device driver that the texture image may have changed.
27747117f1b4Smrg */
27757117f1b4Smrgstatic void
27763464ebd5Sriastradhcheck_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
27777117f1b4Smrg{
2778af69d88dSmrg   /* Skip if we know NeedsFinishRenderTexture won't be set. */
2779af69d88dSmrg   if (_mesa_is_winsys_fbo(fb) && !ctx->Driver.BindRenderbufferTexImage)
2780af69d88dSmrg      return;
27814a49301eSmrg
27827117f1b4Smrg   if (ctx->Driver.FinishRenderTexture) {
27837117f1b4Smrg      GLuint i;
27847117f1b4Smrg      for (i = 0; i < BUFFER_COUNT; i++) {
27857117f1b4Smrg         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
2786af69d88dSmrg         struct gl_renderbuffer *rb = att->Renderbuffer;
2787af69d88dSmrg         if (rb && rb->NeedsFinishRenderTexture) {
2788af69d88dSmrg            ctx->Driver.FinishRenderTexture(ctx, rb);
27897117f1b4Smrg         }
27907117f1b4Smrg      }
27917117f1b4Smrg   }
27927117f1b4Smrg}
27937117f1b4Smrg
27947117f1b4Smrg
2795af69d88dSmrgstatic void
279601e04c3fSmrgbind_framebuffer(GLenum target, GLuint framebuffer)
27977117f1b4Smrg{
27984a49301eSmrg   struct gl_framebuffer *newDrawFb, *newReadFb;
27997117f1b4Smrg   GLboolean bindReadBuf, bindDrawBuf;
28007117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
28017117f1b4Smrg
28027117f1b4Smrg   switch (target) {
28037117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
28047117f1b4Smrg      bindDrawBuf = GL_TRUE;
28057117f1b4Smrg      bindReadBuf = GL_FALSE;
28067117f1b4Smrg      break;
28077117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
28087117f1b4Smrg      bindDrawBuf = GL_FALSE;
28097117f1b4Smrg      bindReadBuf = GL_TRUE;
28107117f1b4Smrg      break;
28117117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
28127117f1b4Smrg      bindDrawBuf = GL_TRUE;
28137117f1b4Smrg      bindReadBuf = GL_TRUE;
28147117f1b4Smrg      break;
28157117f1b4Smrg   default:
28167117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
28177117f1b4Smrg      return;
28187117f1b4Smrg   }
28197117f1b4Smrg
28207117f1b4Smrg   if (framebuffer) {
28217117f1b4Smrg      /* Binding a user-created framebuffer object */
28224a49301eSmrg      newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
28234a49301eSmrg      if (newDrawFb == &DummyFramebuffer) {
28247117f1b4Smrg         /* ID was reserved, but no real framebuffer object made yet */
28254a49301eSmrg         newDrawFb = NULL;
28267117f1b4Smrg      }
282701e04c3fSmrg      else if (!newDrawFb && ctx->API == API_OPENGL_CORE) {
28284a49301eSmrg         /* All FBO IDs must be Gen'd */
282901e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
283001e04c3fSmrg                     "glBindFramebuffer(non-gen name)");
28314a49301eSmrg         return;
28324a49301eSmrg      }
28334a49301eSmrg
28344a49301eSmrg      if (!newDrawFb) {
283501e04c3fSmrg         /* create new framebuffer object */
283601e04c3fSmrg         newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
283701e04c3fSmrg         if (!newDrawFb) {
283801e04c3fSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
283901e04c3fSmrg            return;
284001e04c3fSmrg         }
28414a49301eSmrg         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
28427117f1b4Smrg      }
28434a49301eSmrg      newReadFb = newDrawFb;
28447117f1b4Smrg   }
28457117f1b4Smrg   else {
28467117f1b4Smrg      /* Binding the window system framebuffer (which was originally set
28477117f1b4Smrg       * with MakeCurrent).
28487117f1b4Smrg       */
28494a49301eSmrg      newDrawFb = ctx->WinSysDrawBuffer;
28504a49301eSmrg      newReadFb = ctx->WinSysReadBuffer;
28517117f1b4Smrg   }
28527117f1b4Smrg
285301e04c3fSmrg   _mesa_bind_framebuffers(ctx,
285401e04c3fSmrg                           bindDrawBuf ? newDrawFb : ctx->DrawBuffer,
285501e04c3fSmrg                           bindReadBuf ? newReadFb : ctx->ReadBuffer);
285601e04c3fSmrg}
28574a49301eSmrg
285801e04c3fSmrgvoid
285901e04c3fSmrg_mesa_bind_framebuffers(struct gl_context *ctx,
286001e04c3fSmrg                        struct gl_framebuffer *newDrawFb,
286101e04c3fSmrg                        struct gl_framebuffer *newReadFb)
286201e04c3fSmrg{
286301e04c3fSmrg   struct gl_framebuffer *const oldDrawFb = ctx->DrawBuffer;
286401e04c3fSmrg   struct gl_framebuffer *const oldReadFb = ctx->ReadBuffer;
286501e04c3fSmrg   const bool bindDrawBuf = oldDrawFb != newDrawFb;
286601e04c3fSmrg   const bool bindReadBuf = oldReadFb != newReadFb;
28674a49301eSmrg
286801e04c3fSmrg   assert(newDrawFb);
286901e04c3fSmrg   assert(newDrawFb != &DummyFramebuffer);
28707117f1b4Smrg
28717117f1b4Smrg   /*
28724a49301eSmrg    * OK, now bind the new Draw/Read framebuffers, if they're changing.
28734a49301eSmrg    *
28744a49301eSmrg    * We also check if we're beginning and/or ending render-to-texture.
28754a49301eSmrg    * When a framebuffer with texture attachments is unbound, call
28764a49301eSmrg    * ctx->Driver.FinishRenderTexture().
28774a49301eSmrg    * When a framebuffer with texture attachments is bound, call
28784a49301eSmrg    * ctx->Driver.RenderTexture().
28794a49301eSmrg    *
28804a49301eSmrg    * Note that if the ReadBuffer has texture attachments we don't consider
28814a49301eSmrg    * that a render-to-texture case.
28827117f1b4Smrg    */
28837117f1b4Smrg   if (bindReadBuf) {
28844a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
28854a49301eSmrg
28864a49301eSmrg      /* check if old readbuffer was render-to-texture */
28874a49301eSmrg      check_end_texture_render(ctx, oldReadFb);
28884a49301eSmrg
28894a49301eSmrg      _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
28907117f1b4Smrg   }
28917117f1b4Smrg
28927117f1b4Smrg   if (bindDrawBuf) {
28934a49301eSmrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
289401e04c3fSmrg      ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
28957117f1b4Smrg
2896af69d88dSmrg      /* check if old framebuffer had any texture attachments */
2897af69d88dSmrg      if (oldDrawFb)
28984a49301eSmrg         check_end_texture_render(ctx, oldDrawFb);
28994a49301eSmrg
29004a49301eSmrg      /* check if newly bound framebuffer has any texture attachments */
29014a49301eSmrg      check_begin_texture_render(ctx, newDrawFb);
29024a49301eSmrg
29034a49301eSmrg      _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
29047117f1b4Smrg   }
29057117f1b4Smrg
29064a49301eSmrg   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
290701e04c3fSmrg      /* The few classic drivers that actually hook this function really only
290801e04c3fSmrg       * want to know if the draw framebuffer changed.
290901e04c3fSmrg       */
291001e04c3fSmrg      ctx->Driver.BindFramebuffer(ctx,
291101e04c3fSmrg                                  bindDrawBuf ? GL_FRAMEBUFFER : GL_READ_FRAMEBUFFER,
291201e04c3fSmrg                                  newDrawFb, newReadFb);
29137117f1b4Smrg   }
29147117f1b4Smrg}
29157117f1b4Smrg
2916af69d88dSmrgvoid GLAPIENTRY
2917af69d88dSmrg_mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
2918af69d88dSmrg{
2919af69d88dSmrg   /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry
2920af69d88dSmrg    * point, but they allow the use of user-generated names.
2921af69d88dSmrg    */
292201e04c3fSmrg   bind_framebuffer(target, framebuffer);
2923af69d88dSmrg}
2924af69d88dSmrg
29257117f1b4Smrg
29267117f1b4Smrgvoid GLAPIENTRY
2927af69d88dSmrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
2928af69d88dSmrg{
292901e04c3fSmrg   bind_framebuffer(target, framebuffer);
2930af69d88dSmrg}
2931af69d88dSmrg
2932af69d88dSmrg
2933af69d88dSmrgvoid GLAPIENTRY
2934af69d88dSmrg_mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
29357117f1b4Smrg{
29367117f1b4Smrg   GLint i;
29377117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
29387117f1b4Smrg
293901e04c3fSmrg   if (n < 0) {
294001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteFramebuffers(n < 0)");
294101e04c3fSmrg      return;
294201e04c3fSmrg   }
294301e04c3fSmrg
29447117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
29457117f1b4Smrg
29467117f1b4Smrg   for (i = 0; i < n; i++) {
29477117f1b4Smrg      if (framebuffers[i] > 0) {
294801e04c3fSmrg         struct gl_framebuffer *fb;
294901e04c3fSmrg         fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
295001e04c3fSmrg         if (fb) {
295101e04c3fSmrg            assert(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
29527117f1b4Smrg
29537117f1b4Smrg            /* check if deleting currently bound framebuffer object */
2954af69d88dSmrg            if (fb == ctx->DrawBuffer) {
2955af69d88dSmrg               /* bind default */
295601e04c3fSmrg               assert(fb->RefCount >= 2);
2957af69d88dSmrg               _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
29584a49301eSmrg            }
2959af69d88dSmrg            if (fb == ctx->ReadBuffer) {
2960af69d88dSmrg               /* bind default */
296101e04c3fSmrg               assert(fb->RefCount >= 2);
2962af69d88dSmrg               _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, 0);
29637117f1b4Smrg            }
29647117f1b4Smrg
296501e04c3fSmrg            /* remove from hash table immediately, to free the ID */
296601e04c3fSmrg            _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
29677117f1b4Smrg
29687117f1b4Smrg            if (fb != &DummyFramebuffer) {
29697117f1b4Smrg               /* But the object will not be freed until it's no longer
29707117f1b4Smrg                * bound in any context.
29717117f1b4Smrg                */
29724a49301eSmrg               _mesa_reference_framebuffer(&fb, NULL);
297301e04c3fSmrg            }
297401e04c3fSmrg         }
29757117f1b4Smrg      }
29767117f1b4Smrg   }
29777117f1b4Smrg}
29787117f1b4Smrg
29797117f1b4Smrg
298001e04c3fSmrg/**
298101e04c3fSmrg * This is the implementation for glGenFramebuffers and glCreateFramebuffers.
298201e04c3fSmrg * It is not exposed to the rest of Mesa to encourage the use of
298301e04c3fSmrg * nameless buffers in driver internals.
298401e04c3fSmrg */
298501e04c3fSmrgstatic void
298601e04c3fSmrgcreate_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa)
29877117f1b4Smrg{
29887117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
29897117f1b4Smrg   GLuint first;
29907117f1b4Smrg   GLint i;
299101e04c3fSmrg   struct gl_framebuffer *fb;
299201e04c3fSmrg
299301e04c3fSmrg   const char *func = dsa ? "glCreateFramebuffers" : "glGenFramebuffers";
29947117f1b4Smrg
29957117f1b4Smrg   if (n < 0) {
299601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
29977117f1b4Smrg      return;
29987117f1b4Smrg   }
29997117f1b4Smrg
30007117f1b4Smrg   if (!framebuffers)
30017117f1b4Smrg      return;
30027117f1b4Smrg
300301e04c3fSmrg   _mesa_HashLockMutex(ctx->Shared->FrameBuffers);
300401e04c3fSmrg
30057117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
30067117f1b4Smrg
30077117f1b4Smrg   for (i = 0; i < n; i++) {
30087117f1b4Smrg      GLuint name = first + i;
30097117f1b4Smrg      framebuffers[i] = name;
301001e04c3fSmrg
301101e04c3fSmrg      if (dsa) {
301201e04c3fSmrg         fb = ctx->Driver.NewFramebuffer(ctx, framebuffers[i]);
301301e04c3fSmrg         if (!fb) {
301401e04c3fSmrg            _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers);
301501e04c3fSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
301601e04c3fSmrg            return;
301701e04c3fSmrg         }
301801e04c3fSmrg      }
301901e04c3fSmrg      else
302001e04c3fSmrg         fb = &DummyFramebuffer;
302101e04c3fSmrg
302201e04c3fSmrg      _mesa_HashInsertLocked(ctx->Shared->FrameBuffers, name, fb);
30237117f1b4Smrg   }
302401e04c3fSmrg
302501e04c3fSmrg   _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers);
30267117f1b4Smrg}
30277117f1b4Smrg
30287117f1b4Smrg
302901e04c3fSmrgvoid GLAPIENTRY
303001e04c3fSmrg_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers)
30317117f1b4Smrg{
303201e04c3fSmrg   create_framebuffers(n, framebuffers, false);
303301e04c3fSmrg}
30347117f1b4Smrg
30357117f1b4Smrg
303601e04c3fSmrgvoid GLAPIENTRY
303701e04c3fSmrg_mesa_CreateFramebuffers(GLsizei n, GLuint *framebuffers)
303801e04c3fSmrg{
303901e04c3fSmrg   create_framebuffers(n, framebuffers, true);
304001e04c3fSmrg}
3041af69d88dSmrg
304201e04c3fSmrg
304301e04c3fSmrgGLenum
304401e04c3fSmrg_mesa_check_framebuffer_status(struct gl_context *ctx,
304501e04c3fSmrg                               struct gl_framebuffer *buffer)
304601e04c3fSmrg{
304701e04c3fSmrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
30487117f1b4Smrg
3049af69d88dSmrg   if (_mesa_is_winsys_fbo(buffer)) {
3050af69d88dSmrg      /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */
3051af69d88dSmrg      if (buffer != &IncompleteFramebuffer) {
3052af69d88dSmrg         return GL_FRAMEBUFFER_COMPLETE_EXT;
3053af69d88dSmrg      } else {
3054af69d88dSmrg         return GL_FRAMEBUFFER_UNDEFINED;
3055af69d88dSmrg      }
30567117f1b4Smrg   }
30577117f1b4Smrg
30584a49301eSmrg   /* No need to flush here */
30594a49301eSmrg
30604a49301eSmrg   if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
30614a49301eSmrg      _mesa_test_framebuffer_completeness(ctx, buffer);
30624a49301eSmrg   }
30637117f1b4Smrg
30647117f1b4Smrg   return buffer->_Status;
30657117f1b4Smrg}
30667117f1b4Smrg
30677117f1b4Smrg
306801e04c3fSmrgGLenum GLAPIENTRY
306901e04c3fSmrg_mesa_CheckFramebufferStatus_no_error(GLenum target)
3070af69d88dSmrg{
307101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
3072af69d88dSmrg
307301e04c3fSmrg   struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
307401e04c3fSmrg   return _mesa_check_framebuffer_status(ctx, fb);
307501e04c3fSmrg}
307601e04c3fSmrg
307701e04c3fSmrg
307801e04c3fSmrgGLenum GLAPIENTRY
307901e04c3fSmrg_mesa_CheckFramebufferStatus(GLenum target)
308001e04c3fSmrg{
308101e04c3fSmrg   struct gl_framebuffer *fb;
308201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
308301e04c3fSmrg
308401e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API)
308501e04c3fSmrg      _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n",
308601e04c3fSmrg                  _mesa_enum_to_string(target));
308701e04c3fSmrg
308801e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
308901e04c3fSmrg   if (!fb) {
309001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
309101e04c3fSmrg                  "glCheckFramebufferStatus(invalid target %s)",
309201e04c3fSmrg                  _mesa_enum_to_string(target));
309301e04c3fSmrg      return 0;
309401e04c3fSmrg   }
309501e04c3fSmrg
309601e04c3fSmrg   return _mesa_check_framebuffer_status(ctx, fb);
309701e04c3fSmrg}
309801e04c3fSmrg
309901e04c3fSmrg
310001e04c3fSmrgGLenum GLAPIENTRY
310101e04c3fSmrg_mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target)
310201e04c3fSmrg{
310301e04c3fSmrg   struct gl_framebuffer *fb;
310401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
310501e04c3fSmrg
310601e04c3fSmrg   /* Validate the target (for conformance's sake) and grab a reference to the
310701e04c3fSmrg    * default framebuffer in case framebuffer = 0.
310801e04c3fSmrg    * Section 9.4 Framebuffer Completeness of the OpenGL 4.5 core spec
310901e04c3fSmrg    * (30.10.2014, PDF page 336) says:
311001e04c3fSmrg    *    "If framebuffer is zero, then the status of the default read or
311101e04c3fSmrg    *    draw framebuffer (as determined by target) is returned."
311201e04c3fSmrg    */
311301e04c3fSmrg   switch (target) {
311401e04c3fSmrg      case GL_DRAW_FRAMEBUFFER:
311501e04c3fSmrg      case GL_FRAMEBUFFER:
311601e04c3fSmrg         fb = ctx->WinSysDrawBuffer;
311701e04c3fSmrg         break;
311801e04c3fSmrg      case GL_READ_FRAMEBUFFER:
311901e04c3fSmrg         fb = ctx->WinSysReadBuffer;
312001e04c3fSmrg         break;
312101e04c3fSmrg      default:
312201e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
312301e04c3fSmrg                     "glCheckNamedFramebufferStatus(invalid target %s)",
312401e04c3fSmrg                     _mesa_enum_to_string(target));
312501e04c3fSmrg         return 0;
312601e04c3fSmrg   }
312701e04c3fSmrg
312801e04c3fSmrg   if (framebuffer) {
312901e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
313001e04c3fSmrg                                        "glCheckNamedFramebufferStatus");
313101e04c3fSmrg      if (!fb)
313201e04c3fSmrg         return 0;
313301e04c3fSmrg   }
313401e04c3fSmrg
313501e04c3fSmrg   return _mesa_check_framebuffer_status(ctx, fb);
313601e04c3fSmrg}
313701e04c3fSmrg
313801e04c3fSmrg
313901e04c3fSmrg/**
314001e04c3fSmrg * Replicate the src attachment point. Used by framebuffer_texture() when
314101e04c3fSmrg * the same texture is attached at GL_DEPTH_ATTACHMENT and
314201e04c3fSmrg * GL_STENCIL_ATTACHMENT.
314301e04c3fSmrg */
314401e04c3fSmrgstatic void
314501e04c3fSmrgreuse_framebuffer_texture_attachment(struct gl_framebuffer *fb,
314601e04c3fSmrg                                     gl_buffer_index dst,
314701e04c3fSmrg                                     gl_buffer_index src)
314801e04c3fSmrg{
314901e04c3fSmrg   struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst];
315001e04c3fSmrg   struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src];
315101e04c3fSmrg
315201e04c3fSmrg   assert(src_att->Texture != NULL);
315301e04c3fSmrg   assert(src_att->Renderbuffer != NULL);
3154af69d88dSmrg
3155af69d88dSmrg   _mesa_reference_texobj(&dst_att->Texture, src_att->Texture);
3156af69d88dSmrg   _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer);
3157af69d88dSmrg   dst_att->Type = src_att->Type;
3158af69d88dSmrg   dst_att->Complete = src_att->Complete;
3159af69d88dSmrg   dst_att->TextureLevel = src_att->TextureLevel;
316001e04c3fSmrg   dst_att->CubeMapFace = src_att->CubeMapFace;
3161af69d88dSmrg   dst_att->Zoffset = src_att->Zoffset;
316201e04c3fSmrg   dst_att->Layered = src_att->Layered;
316301e04c3fSmrg}
316401e04c3fSmrg
316501e04c3fSmrg
316601e04c3fSmrgstatic struct gl_texture_object *
316701e04c3fSmrgget_texture_for_framebuffer(struct gl_context *ctx, GLuint texture)
316801e04c3fSmrg{
316901e04c3fSmrg   if (!texture)
317001e04c3fSmrg      return NULL;
317101e04c3fSmrg
317201e04c3fSmrg   return _mesa_lookup_texture(ctx, texture);
3173af69d88dSmrg}
3174af69d88dSmrg
31757117f1b4Smrg
31767117f1b4Smrg/**
317701e04c3fSmrg * Common code called by gl*FramebufferTexture*() to retrieve the correct
317801e04c3fSmrg * texture object pointer.
3179af69d88dSmrg *
318001e04c3fSmrg * \param texObj where the pointer to the texture object is returned.  Note
318101e04c3fSmrg * that a successful call may return texObj = NULL.
3182af69d88dSmrg *
318301e04c3fSmrg * \return true if no errors, false if errors
31847117f1b4Smrg */
318501e04c3fSmrgstatic bool
318601e04c3fSmrgget_texture_for_framebuffer_err(struct gl_context *ctx, GLuint texture,
318701e04c3fSmrg                                bool layered, const char *caller,
318801e04c3fSmrg                                struct gl_texture_object **texObj)
31897117f1b4Smrg{
319001e04c3fSmrg   *texObj = NULL; /* This will get returned if texture = 0. */
31917117f1b4Smrg
319201e04c3fSmrg   if (!texture)
319301e04c3fSmrg      return true;
319401e04c3fSmrg
319501e04c3fSmrg   *texObj = _mesa_lookup_texture(ctx, texture);
319601e04c3fSmrg   if (*texObj == NULL || (*texObj)->Target == 0) {
319701e04c3fSmrg      /* Can't render to a non-existent texture object.
319801e04c3fSmrg       *
319901e04c3fSmrg       * The OpenGL 4.5 core spec (02.02.2015) in Section 9.2 Binding and
320001e04c3fSmrg       * Managing Framebuffer Objects specifies a different error
320101e04c3fSmrg       * depending upon the calling function (PDF pages 325-328).
320201e04c3fSmrg       * *FramebufferTexture (where layered = GL_TRUE) throws invalid
320301e04c3fSmrg       * value, while the other commands throw invalid operation (where
320401e04c3fSmrg       * layered = GL_FALSE).
320501e04c3fSmrg       */
320601e04c3fSmrg      const GLenum error = layered ? GL_INVALID_VALUE :
320701e04c3fSmrg                           GL_INVALID_OPERATION;
320801e04c3fSmrg      _mesa_error(ctx, error,
320901e04c3fSmrg                  "%s(non-existent texture %u)", caller, texture);
321001e04c3fSmrg      return false;
321101e04c3fSmrg   }
321201e04c3fSmrg
321301e04c3fSmrg   return true;
321401e04c3fSmrg}
321501e04c3fSmrg
321601e04c3fSmrg
321701e04c3fSmrg/**
321801e04c3fSmrg * Common code called by gl*FramebufferTexture() to verify the texture target
321901e04c3fSmrg * and decide whether or not the attachment should truly be considered
322001e04c3fSmrg * layered.
322101e04c3fSmrg *
322201e04c3fSmrg * \param layered true if attachment should be considered layered, false if
322301e04c3fSmrg * not
322401e04c3fSmrg *
322501e04c3fSmrg * \return true if no errors, false if errors
322601e04c3fSmrg */
322701e04c3fSmrgstatic bool
322801e04c3fSmrgcheck_layered_texture_target(struct gl_context *ctx, GLenum target,
322901e04c3fSmrg                             const char *caller, GLboolean *layered)
323001e04c3fSmrg{
323101e04c3fSmrg   *layered = GL_TRUE;
323201e04c3fSmrg
323301e04c3fSmrg   switch (target) {
323401e04c3fSmrg   case GL_TEXTURE_3D:
323501e04c3fSmrg   case GL_TEXTURE_1D_ARRAY_EXT:
323601e04c3fSmrg   case GL_TEXTURE_2D_ARRAY_EXT:
323701e04c3fSmrg   case GL_TEXTURE_CUBE_MAP:
323801e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_ARRAY:
323901e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
324001e04c3fSmrg      return true;
324101e04c3fSmrg   case GL_TEXTURE_1D:
324201e04c3fSmrg   case GL_TEXTURE_2D:
324301e04c3fSmrg   case GL_TEXTURE_RECTANGLE:
324401e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE:
324501e04c3fSmrg      /* These texture types are valid to pass to
324601e04c3fSmrg       * glFramebufferTexture(), but since they aren't layered, it
324701e04c3fSmrg       * is equivalent to calling glFramebufferTexture{1D,2D}().
324801e04c3fSmrg       */
324901e04c3fSmrg      *layered = GL_FALSE;
325001e04c3fSmrg      return true;
325101e04c3fSmrg   }
325201e04c3fSmrg
325301e04c3fSmrg   _mesa_error(ctx, GL_INVALID_OPERATION,
325401e04c3fSmrg               "%s(invalid texture target %s)", caller,
325501e04c3fSmrg               _mesa_enum_to_string(target));
325601e04c3fSmrg   return false;
325701e04c3fSmrg}
325801e04c3fSmrg
325901e04c3fSmrg
326001e04c3fSmrg/**
326101e04c3fSmrg * Common code called by gl*FramebufferTextureLayer() to verify the texture
326201e04c3fSmrg * target.
326301e04c3fSmrg *
326401e04c3fSmrg * \return true if no errors, false if errors
326501e04c3fSmrg */
326601e04c3fSmrgstatic bool
326701e04c3fSmrgcheck_texture_target(struct gl_context *ctx, GLenum target,
326801e04c3fSmrg                     const char *caller)
326901e04c3fSmrg{
327001e04c3fSmrg   /* We're being called by glFramebufferTextureLayer().
327101e04c3fSmrg    * The only legal texture types for that function are 3D,
327201e04c3fSmrg    * cube-map, and 1D/2D/cube-map array textures.
327301e04c3fSmrg    *
327401e04c3fSmrg    * We don't need to check for GL_ARB_texture_cube_map_array because the
327501e04c3fSmrg    * application wouldn't have been able to create a texture with a
327601e04c3fSmrg    * GL_TEXTURE_CUBE_MAP_ARRAY target if the extension were not enabled.
327701e04c3fSmrg    */
327801e04c3fSmrg   switch (target) {
327901e04c3fSmrg   case GL_TEXTURE_3D:
328001e04c3fSmrg   case GL_TEXTURE_1D_ARRAY:
328101e04c3fSmrg   case GL_TEXTURE_2D_ARRAY:
328201e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_ARRAY:
328301e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
328401e04c3fSmrg      return true;
328501e04c3fSmrg   case GL_TEXTURE_CUBE_MAP:
328601e04c3fSmrg      /* GL_TEXTURE_CUBE_MAP is only allowed by OpenGL 4.5 here, which
328701e04c3fSmrg       * includes the DSA API.
328801e04c3fSmrg       *
328901e04c3fSmrg       * Because DSA is only enabled for GL 3.1+ and this can be called
329001e04c3fSmrg       * from _mesa_FramebufferTextureLayer in compatibility profile,
329101e04c3fSmrg       * we need to check the version.
329201e04c3fSmrg       */
329301e04c3fSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Version >= 31;
329401e04c3fSmrg   }
329501e04c3fSmrg
329601e04c3fSmrg   _mesa_error(ctx, GL_INVALID_OPERATION,
329701e04c3fSmrg               "%s(invalid texture target %s)", caller,
329801e04c3fSmrg               _mesa_enum_to_string(target));
329901e04c3fSmrg   return false;
330001e04c3fSmrg}
330101e04c3fSmrg
330201e04c3fSmrg
330301e04c3fSmrg/**
330401e04c3fSmrg * Common code called by glFramebufferTexture*D() to verify the texture
330501e04c3fSmrg * target.
330601e04c3fSmrg *
330701e04c3fSmrg * \return true if no errors, false if errors
330801e04c3fSmrg */
330901e04c3fSmrgstatic bool
331001e04c3fSmrgcheck_textarget(struct gl_context *ctx, int dims, GLenum target,
331101e04c3fSmrg                GLenum textarget, const char *caller)
331201e04c3fSmrg{
331301e04c3fSmrg   bool err = false;
331401e04c3fSmrg
331501e04c3fSmrg   switch (textarget) {
331601e04c3fSmrg   case GL_TEXTURE_1D:
331701e04c3fSmrg      err = dims != 1;
331801e04c3fSmrg      break;
331901e04c3fSmrg   case GL_TEXTURE_1D_ARRAY:
332001e04c3fSmrg      err = dims != 1 || !ctx->Extensions.EXT_texture_array;
332101e04c3fSmrg      break;
332201e04c3fSmrg   case GL_TEXTURE_2D:
332301e04c3fSmrg      err = dims != 2;
332401e04c3fSmrg      break;
332501e04c3fSmrg   case GL_TEXTURE_2D_ARRAY:
332601e04c3fSmrg      err = dims != 2 || !ctx->Extensions.EXT_texture_array ||
332701e04c3fSmrg            (_mesa_is_gles(ctx) && ctx->Version < 30);
332801e04c3fSmrg      break;
332901e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE:
333001e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
333101e04c3fSmrg      err = dims != 2 ||
333201e04c3fSmrg            !ctx->Extensions.ARB_texture_multisample ||
333301e04c3fSmrg            (_mesa_is_gles(ctx) && ctx->Version < 31);
333401e04c3fSmrg      break;
333501e04c3fSmrg   case GL_TEXTURE_RECTANGLE:
333601e04c3fSmrg      err = dims != 2 || _mesa_is_gles(ctx) ||
333701e04c3fSmrg            !ctx->Extensions.NV_texture_rectangle;
333801e04c3fSmrg      break;
333901e04c3fSmrg   case GL_TEXTURE_CUBE_MAP:
334001e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_ARRAY:
334101e04c3fSmrg      err = true;
334201e04c3fSmrg      break;
334301e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
334401e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
334501e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
334601e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
334701e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
334801e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
334901e04c3fSmrg      err = dims != 2 || !ctx->Extensions.ARB_texture_cube_map;
335001e04c3fSmrg      break;
335101e04c3fSmrg   case GL_TEXTURE_3D:
335201e04c3fSmrg      err = dims != 3;
335301e04c3fSmrg      break;
335401e04c3fSmrg   default:
33557117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
335601e04c3fSmrg                  "%s(unknown textarget 0x%x)", caller, textarget);
335701e04c3fSmrg      return false;
33587117f1b4Smrg   }
33597117f1b4Smrg
336001e04c3fSmrg   if (err) {
33617117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
336201e04c3fSmrg                  "%s(invalid textarget %s)",
336301e04c3fSmrg                  caller, _mesa_enum_to_string(textarget));
336401e04c3fSmrg      return false;
33657117f1b4Smrg   }
33667117f1b4Smrg
336701e04c3fSmrg   /* Make sure textarget is consistent with the texture's type */
336801e04c3fSmrg   err = (target == GL_TEXTURE_CUBE_MAP) ?
336901e04c3fSmrg          !_mesa_is_cube_face(textarget): (target != textarget);
33707117f1b4Smrg
337101e04c3fSmrg   if (err) {
337201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
337301e04c3fSmrg                  "%s(mismatched texture target)", caller);
337401e04c3fSmrg      return false;
337501e04c3fSmrg   }
33767117f1b4Smrg
337701e04c3fSmrg   return true;
337801e04c3fSmrg}
337901e04c3fSmrg
338001e04c3fSmrg
338101e04c3fSmrg/**
338201e04c3fSmrg * Common code called by gl*FramebufferTextureLayer() and
338301e04c3fSmrg * glFramebufferTexture3D() to validate the layer.
338401e04c3fSmrg *
338501e04c3fSmrg * \return true if no errors, false if errors
338601e04c3fSmrg */
338701e04c3fSmrgstatic bool
338801e04c3fSmrgcheck_layer(struct gl_context *ctx, GLenum target, GLint layer,
338901e04c3fSmrg            const char *caller)
339001e04c3fSmrg{
339101e04c3fSmrg   /* Page 306 (page 328 of the PDF) of the OpenGL 4.5 (Core Profile)
339201e04c3fSmrg    * spec says:
339301e04c3fSmrg    *
339401e04c3fSmrg    *    "An INVALID_VALUE error is generated if texture is non-zero
339501e04c3fSmrg    *     and layer is negative."
339601e04c3fSmrg    */
339701e04c3fSmrg   if (layer < 0) {
339801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(layer %d < 0)", caller, layer);
339901e04c3fSmrg      return false;
340001e04c3fSmrg   }
340101e04c3fSmrg
340201e04c3fSmrg   if (target == GL_TEXTURE_3D) {
340301e04c3fSmrg      const GLuint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
340401e04c3fSmrg      if (layer >= maxSize) {
340501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
340601e04c3fSmrg                     "%s(invalid layer %u)", caller, layer);
340701e04c3fSmrg         return false;
34087117f1b4Smrg      }
340901e04c3fSmrg   }
341001e04c3fSmrg   else if ((target == GL_TEXTURE_1D_ARRAY) ||
341101e04c3fSmrg            (target == GL_TEXTURE_2D_ARRAY) ||
341201e04c3fSmrg            (target == GL_TEXTURE_CUBE_MAP_ARRAY) ||
341301e04c3fSmrg            (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) {
341401e04c3fSmrg      if (layer >= ctx->Const.MaxArrayTextureLayers) {
341501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
341601e04c3fSmrg                     "%s(layer %u >= GL_MAX_ARRAY_TEXTURE_LAYERS)",
341701e04c3fSmrg                     caller, layer);
341801e04c3fSmrg         return false;
3419c1f859d4Smrg      }
342001e04c3fSmrg   }
342101e04c3fSmrg   else if (target == GL_TEXTURE_CUBE_MAP) {
342201e04c3fSmrg      if (layer >= 6) {
34237117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
342401e04c3fSmrg                     "%s(layer %u >= 6)", caller, layer);
342501e04c3fSmrg         return false;
34267117f1b4Smrg      }
34277117f1b4Smrg   }
34287117f1b4Smrg
342901e04c3fSmrg   return true;
343001e04c3fSmrg}
343101e04c3fSmrg
343201e04c3fSmrg
343301e04c3fSmrg/**
343401e04c3fSmrg * Common code called by all gl*FramebufferTexture*() entry points to verify
343501e04c3fSmrg * the level.
343601e04c3fSmrg *
343701e04c3fSmrg * \return true if no errors, false if errors
343801e04c3fSmrg */
343901e04c3fSmrgstatic bool
344001e04c3fSmrgcheck_level(struct gl_context *ctx, struct gl_texture_object *texObj,
344101e04c3fSmrg            GLenum target, GLint level, const char *caller)
344201e04c3fSmrg{
344301e04c3fSmrg   /* Section 9.2.8 of the OpenGL 4.6 specification says:
344401e04c3fSmrg    *
344501e04c3fSmrg    *    "If texture refers to an immutable-format texture, level must be
344601e04c3fSmrg    *     greater than or equal to zero and smaller than the value of
344701e04c3fSmrg    *     TEXTURE_VIEW_NUM_LEVELS for texture."
344801e04c3fSmrg    */
344901e04c3fSmrg   const int max_levels = texObj->Immutable ? texObj->ImmutableLevels :
345001e04c3fSmrg                          _mesa_max_texture_levels(ctx, target);
345101e04c3fSmrg
345201e04c3fSmrg   if (level < 0 || level >= max_levels) {
345301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
345401e04c3fSmrg                  "%s(invalid level %d)", caller, level);
345501e04c3fSmrg      return false;
345601e04c3fSmrg   }
345701e04c3fSmrg
345801e04c3fSmrg   return true;
345901e04c3fSmrg}
346001e04c3fSmrg
346101e04c3fSmrg
346201e04c3fSmrgstruct gl_renderbuffer_attachment *
346301e04c3fSmrg_mesa_get_and_validate_attachment(struct gl_context *ctx,
346401e04c3fSmrg                                  struct gl_framebuffer *fb,
346501e04c3fSmrg                                  GLenum attachment, const char *caller)
346601e04c3fSmrg{
346701e04c3fSmrg   /* The window-system framebuffer object is immutable */
346801e04c3fSmrg   if (_mesa_is_winsys_fbo(fb)) {
346901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(window-system framebuffer)",
347001e04c3fSmrg                  caller);
347101e04c3fSmrg      return NULL;
347201e04c3fSmrg   }
347301e04c3fSmrg
347401e04c3fSmrg   /* Not a hash lookup, so we can afford to get the attachment here. */
347501e04c3fSmrg   bool is_color_attachment;
347601e04c3fSmrg   struct gl_renderbuffer_attachment *att =
347701e04c3fSmrg      get_attachment(ctx, fb, attachment, &is_color_attachment);
34787117f1b4Smrg   if (att == NULL) {
347901e04c3fSmrg      if (is_color_attachment) {
348001e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
348101e04c3fSmrg                     "%s(invalid color attachment %s)", caller,
348201e04c3fSmrg                     _mesa_enum_to_string(attachment));
348301e04c3fSmrg      } else {
348401e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
348501e04c3fSmrg                     "%s(invalid attachment %s)", caller,
348601e04c3fSmrg                     _mesa_enum_to_string(attachment));
348701e04c3fSmrg      }
348801e04c3fSmrg      return NULL;
34897117f1b4Smrg   }
34907117f1b4Smrg
349101e04c3fSmrg   return att;
349201e04c3fSmrg}
349301e04c3fSmrg
349401e04c3fSmrg
349501e04c3fSmrgvoid
349601e04c3fSmrg_mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
349701e04c3fSmrg                          GLenum attachment,
349801e04c3fSmrg                          struct gl_renderbuffer_attachment *att,
349901e04c3fSmrg                          struct gl_texture_object *texObj, GLenum textarget,
350001e04c3fSmrg                          GLint level, GLuint layer, GLboolean layered)
350101e04c3fSmrg{
35027117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
35037117f1b4Smrg
350401e04c3fSmrg   simple_mtx_lock(&fb->Mutex);
35057117f1b4Smrg   if (texObj) {
3506af69d88dSmrg      if (attachment == GL_DEPTH_ATTACHMENT &&
3507af69d88dSmrg          texObj == fb->Attachment[BUFFER_STENCIL].Texture &&
3508af69d88dSmrg          level == fb->Attachment[BUFFER_STENCIL].TextureLevel &&
3509af69d88dSmrg          _mesa_tex_target_to_face(textarget) ==
3510af69d88dSmrg          fb->Attachment[BUFFER_STENCIL].CubeMapFace &&
351101e04c3fSmrg          layer == fb->Attachment[BUFFER_STENCIL].Zoffset) {
351201e04c3fSmrg         /* The texture object is already attached to the stencil attachment
351301e04c3fSmrg          * point. Don't create a new renderbuffer; just reuse the stencil
351401e04c3fSmrg          * attachment's. This is required to prevent a GL error in
351501e04c3fSmrg          * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL).
351601e04c3fSmrg          */
351701e04c3fSmrg         reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH,
351801e04c3fSmrg                                              BUFFER_STENCIL);
3519af69d88dSmrg      } else if (attachment == GL_STENCIL_ATTACHMENT &&
352001e04c3fSmrg                 texObj == fb->Attachment[BUFFER_DEPTH].Texture &&
3521af69d88dSmrg                 level == fb->Attachment[BUFFER_DEPTH].TextureLevel &&
3522af69d88dSmrg                 _mesa_tex_target_to_face(textarget) ==
3523af69d88dSmrg                 fb->Attachment[BUFFER_DEPTH].CubeMapFace &&
352401e04c3fSmrg                 layer == fb->Attachment[BUFFER_DEPTH].Zoffset) {
352501e04c3fSmrg         /* As above, but with depth and stencil transposed. */
352601e04c3fSmrg         reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL,
352701e04c3fSmrg                                              BUFFER_DEPTH);
3528af69d88dSmrg      } else {
352901e04c3fSmrg         set_texture_attachment(ctx, fb, att, texObj, textarget,
353001e04c3fSmrg                                level, layer, layered);
353101e04c3fSmrg
353201e04c3fSmrg         if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
353301e04c3fSmrg            /* Above we created a new renderbuffer and attached it to the
353401e04c3fSmrg             * depth attachment point. Now attach it to the stencil attachment
353501e04c3fSmrg             * point too.
353601e04c3fSmrg             */
353701e04c3fSmrg            assert(att == &fb->Attachment[BUFFER_DEPTH]);
353801e04c3fSmrg            reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL,
353901e04c3fSmrg                                                 BUFFER_DEPTH);
354001e04c3fSmrg         }
3541af69d88dSmrg      }
3542af69d88dSmrg
35434a49301eSmrg      /* Set the render-to-texture flag.  We'll check this flag in
35444a49301eSmrg       * glTexImage() and friends to determine if we need to revalidate
35454a49301eSmrg       * any FBOs that might be rendering into this texture.
35464a49301eSmrg       * This flag never gets cleared since it's non-trivial to determine
35474a49301eSmrg       * when all FBOs might be done rendering to this texture.  That's OK
35484a49301eSmrg       * though since it's uncommon to render to a texture then repeatedly
35494a49301eSmrg       * call glTexImage() to change images in the texture.
35504a49301eSmrg       */
35514a49301eSmrg      texObj->_RenderToTexture = GL_TRUE;
35527117f1b4Smrg   }
35537117f1b4Smrg   else {
3554af69d88dSmrg      remove_attachment(ctx, att);
3555af69d88dSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
355601e04c3fSmrg         assert(att == &fb->Attachment[BUFFER_DEPTH]);
355701e04c3fSmrg         remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]);
3558af69d88dSmrg      }
35597117f1b4Smrg   }
35604a49301eSmrg
35614a49301eSmrg   invalidate_framebuffer(fb);
35624a49301eSmrg
356301e04c3fSmrg   simple_mtx_unlock(&fb->Mutex);
35647117f1b4Smrg}
35657117f1b4Smrg
35667117f1b4Smrg
356701e04c3fSmrgstatic void
356801e04c3fSmrgframebuffer_texture_with_dims_no_error(GLenum target, GLenum attachment,
356901e04c3fSmrg                                       GLenum textarget, GLuint texture,
357001e04c3fSmrg                                       GLint level, GLint layer)
35717117f1b4Smrg{
35727117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
35737117f1b4Smrg
357401e04c3fSmrg   /* Get the framebuffer object */
357501e04c3fSmrg   struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
3576af69d88dSmrg
357701e04c3fSmrg   /* Get the texture object */
357801e04c3fSmrg   struct gl_texture_object *texObj =
357901e04c3fSmrg      get_texture_for_framebuffer(ctx, texture);
3580af69d88dSmrg
358101e04c3fSmrg   struct gl_renderbuffer_attachment *att =
358201e04c3fSmrg      get_attachment(ctx, fb, attachment, NULL);
358301e04c3fSmrg
358401e04c3fSmrg   _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
358501e04c3fSmrg                             level, layer, GL_FALSE);
358601e04c3fSmrg}
358701e04c3fSmrg
358801e04c3fSmrg
358901e04c3fSmrgstatic void
359001e04c3fSmrgframebuffer_texture_with_dims(int dims, GLenum target,
359101e04c3fSmrg                              GLenum attachment, GLenum textarget,
359201e04c3fSmrg                              GLuint texture, GLint level, GLint layer,
359301e04c3fSmrg                              const char *caller)
359401e04c3fSmrg{
359501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
359601e04c3fSmrg   struct gl_framebuffer *fb;
359701e04c3fSmrg   struct gl_texture_object *texObj;
359801e04c3fSmrg
359901e04c3fSmrg   /* Get the framebuffer object */
360001e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
360101e04c3fSmrg   if (!fb) {
360201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller,
360301e04c3fSmrg                  _mesa_enum_to_string(target));
360401e04c3fSmrg      return;
360501e04c3fSmrg   }
360601e04c3fSmrg
360701e04c3fSmrg   /* Get the texture object */
360801e04c3fSmrg   if (!get_texture_for_framebuffer_err(ctx, texture, false, caller, &texObj))
360901e04c3fSmrg      return;
361001e04c3fSmrg
361101e04c3fSmrg   if (texObj) {
361201e04c3fSmrg      if (!check_textarget(ctx, dims, texObj->Target, textarget, caller))
361301e04c3fSmrg         return;
361401e04c3fSmrg
361501e04c3fSmrg      if ((dims == 3) && !check_layer(ctx, texObj->Target, layer, caller))
361601e04c3fSmrg         return;
361701e04c3fSmrg
361801e04c3fSmrg      if (!check_level(ctx, texObj, textarget, level, caller))
3619af69d88dSmrg         return;
36207117f1b4Smrg   }
36217117f1b4Smrg
362201e04c3fSmrg   struct gl_renderbuffer_attachment *att =
362301e04c3fSmrg      _mesa_get_and_validate_attachment(ctx, fb, attachment, caller);
362401e04c3fSmrg   if (!att)
362501e04c3fSmrg      return;
362601e04c3fSmrg
362701e04c3fSmrg   _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
362801e04c3fSmrg                             level, layer, GL_FALSE);
36297117f1b4Smrg}
36307117f1b4Smrg
36317117f1b4Smrg
36327117f1b4Smrgvoid GLAPIENTRY
363301e04c3fSmrg_mesa_FramebufferTexture1D_no_error(GLenum target, GLenum attachment,
363401e04c3fSmrg                                    GLenum textarget, GLuint texture,
363501e04c3fSmrg                                    GLint level)
363601e04c3fSmrg{
363701e04c3fSmrg   framebuffer_texture_with_dims_no_error(target, attachment, textarget,
363801e04c3fSmrg                                          texture, level, 0);
363901e04c3fSmrg}
364001e04c3fSmrg
364101e04c3fSmrg
364201e04c3fSmrgvoid GLAPIENTRY
364301e04c3fSmrg_mesa_FramebufferTexture1D(GLenum target, GLenum attachment,
3644af69d88dSmrg                           GLenum textarget, GLuint texture, GLint level)
36457117f1b4Smrg{
364601e04c3fSmrg   framebuffer_texture_with_dims(1, target, attachment, textarget, texture,
364701e04c3fSmrg                                 level, 0, "glFramebufferTexture1D");
364801e04c3fSmrg}
36497117f1b4Smrg
3650af69d88dSmrg
365101e04c3fSmrgvoid GLAPIENTRY
365201e04c3fSmrg_mesa_FramebufferTexture2D_no_error(GLenum target, GLenum attachment,
365301e04c3fSmrg                                    GLenum textarget, GLuint texture,
365401e04c3fSmrg                                    GLint level)
365501e04c3fSmrg{
365601e04c3fSmrg   framebuffer_texture_with_dims_no_error(target, attachment, textarget,
365701e04c3fSmrg                                          texture, level, 0);
365801e04c3fSmrg}
3659af69d88dSmrg
36607117f1b4Smrg
366101e04c3fSmrgvoid GLAPIENTRY
366201e04c3fSmrg_mesa_FramebufferTexture2D(GLenum target, GLenum attachment,
366301e04c3fSmrg                           GLenum textarget, GLuint texture, GLint level)
366401e04c3fSmrg{
366501e04c3fSmrg   framebuffer_texture_with_dims(2, target, attachment, textarget, texture,
366601e04c3fSmrg                                 level, 0, "glFramebufferTexture2D");
366701e04c3fSmrg}
366801e04c3fSmrg
366901e04c3fSmrg
367001e04c3fSmrgvoid GLAPIENTRY
367101e04c3fSmrg_mesa_FramebufferTexture3D_no_error(GLenum target, GLenum attachment,
367201e04c3fSmrg                                    GLenum textarget, GLuint texture,
367301e04c3fSmrg                                    GLint level, GLint layer)
367401e04c3fSmrg{
367501e04c3fSmrg   framebuffer_texture_with_dims_no_error(target, attachment, textarget,
367601e04c3fSmrg                                          texture, level, layer);
36777117f1b4Smrg}
36787117f1b4Smrg
36797117f1b4Smrg
36807117f1b4Smrgvoid GLAPIENTRY
3681af69d88dSmrg_mesa_FramebufferTexture3D(GLenum target, GLenum attachment,
3682af69d88dSmrg                           GLenum textarget, GLuint texture,
368301e04c3fSmrg                           GLint level, GLint layer)
368401e04c3fSmrg{
368501e04c3fSmrg   framebuffer_texture_with_dims(3, target, attachment, textarget, texture,
368601e04c3fSmrg                                 level, layer, "glFramebufferTexture3D");
368701e04c3fSmrg}
368801e04c3fSmrg
368901e04c3fSmrg
369001e04c3fSmrgstatic ALWAYS_INLINE void
369101e04c3fSmrgframe_buffer_texture(GLuint framebuffer, GLenum target,
369201e04c3fSmrg                     GLenum attachment, GLuint texture,
369301e04c3fSmrg                     GLint level, GLint layer, const char *func,
369401e04c3fSmrg                     bool dsa, bool no_error, bool check_layered)
36957117f1b4Smrg{
36967117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
369701e04c3fSmrg   GLboolean layered = GL_FALSE;
36987117f1b4Smrg
369901e04c3fSmrg   if (!no_error && check_layered) {
370001e04c3fSmrg      if (!_mesa_has_geometry_shaders(ctx)) {
370101e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
370201e04c3fSmrg                     "unsupported function (%s) called", func);
370301e04c3fSmrg         return;
370401e04c3fSmrg      }
37057117f1b4Smrg   }
37067117f1b4Smrg
370701e04c3fSmrg   /* Get the framebuffer object */
370801e04c3fSmrg   struct gl_framebuffer *fb;
370901e04c3fSmrg   if (no_error) {
371001e04c3fSmrg      if (dsa) {
371101e04c3fSmrg         fb = _mesa_lookup_framebuffer(ctx, framebuffer);
371201e04c3fSmrg      } else {
371301e04c3fSmrg         fb = get_framebuffer_target(ctx, target);
371401e04c3fSmrg      }
371501e04c3fSmrg   } else {
371601e04c3fSmrg      if (dsa) {
371701e04c3fSmrg         fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func);
371801e04c3fSmrg         if (!fb)
371901e04c3fSmrg            return;
372001e04c3fSmrg      } else {
372101e04c3fSmrg         fb = get_framebuffer_target(ctx, target);
372201e04c3fSmrg         if (!fb) {
372301e04c3fSmrg            _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)",
372401e04c3fSmrg                        func, _mesa_enum_to_string(target));
372501e04c3fSmrg            return;
372601e04c3fSmrg         }
372701e04c3fSmrg      }
372801e04c3fSmrg   }
372901e04c3fSmrg
373001e04c3fSmrg   /* Get the texture object and framebuffer attachment*/
373101e04c3fSmrg   struct gl_renderbuffer_attachment *att;
373201e04c3fSmrg   struct gl_texture_object *texObj;
373301e04c3fSmrg   if (no_error) {
373401e04c3fSmrg      texObj = get_texture_for_framebuffer(ctx, texture);
373501e04c3fSmrg      att = get_attachment(ctx, fb, attachment, NULL);
373601e04c3fSmrg   } else {
373701e04c3fSmrg      if (!get_texture_for_framebuffer_err(ctx, texture, check_layered, func,
373801e04c3fSmrg                                           &texObj))
373901e04c3fSmrg         return;
374001e04c3fSmrg
374101e04c3fSmrg      att = _mesa_get_and_validate_attachment(ctx, fb, attachment, func);
374201e04c3fSmrg      if (!att)
374301e04c3fSmrg         return;
374401e04c3fSmrg   }
374501e04c3fSmrg
374601e04c3fSmrg   GLenum textarget = 0;
374701e04c3fSmrg   if (texObj) {
374801e04c3fSmrg      if (check_layered) {
374901e04c3fSmrg         /* We do this regardless of no_error because this sets layered */
375001e04c3fSmrg         if (!check_layered_texture_target(ctx, texObj->Target, func,
375101e04c3fSmrg                                           &layered))
375201e04c3fSmrg            return;
375301e04c3fSmrg      }
375401e04c3fSmrg
375501e04c3fSmrg      if (!no_error) {
375601e04c3fSmrg         if (!check_layered) {
375701e04c3fSmrg            if (!check_texture_target(ctx, texObj->Target, func))
375801e04c3fSmrg               return;
375901e04c3fSmrg
376001e04c3fSmrg            if (!check_layer(ctx, texObj->Target, layer, func))
376101e04c3fSmrg               return;
376201e04c3fSmrg         }
376301e04c3fSmrg
376401e04c3fSmrg         if (!check_level(ctx, texObj, texObj->Target, level, func))
376501e04c3fSmrg            return;
376601e04c3fSmrg      }
376701e04c3fSmrg
376801e04c3fSmrg      if (!check_layered && texObj->Target == GL_TEXTURE_CUBE_MAP) {
376901e04c3fSmrg         assert(layer >= 0 && layer < 6);
377001e04c3fSmrg         textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
377101e04c3fSmrg         layer = 0;
377201e04c3fSmrg      }
377301e04c3fSmrg   }
377401e04c3fSmrg
377501e04c3fSmrg   _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
377601e04c3fSmrg                             level, layer, layered);
377701e04c3fSmrg}
377801e04c3fSmrg
377901e04c3fSmrgvoid GLAPIENTRY
378001e04c3fSmrg_mesa_FramebufferTextureLayer_no_error(GLenum target, GLenum attachment,
378101e04c3fSmrg                                       GLuint texture, GLint level,
378201e04c3fSmrg                                       GLint layer)
378301e04c3fSmrg{
378401e04c3fSmrg   frame_buffer_texture(0, target, attachment, texture, level, layer,
378501e04c3fSmrg                        "glFramebufferTextureLayer", false, true, false);
37867117f1b4Smrg}
37877117f1b4Smrg
37887117f1b4Smrg
3789c1f859d4Smrgvoid GLAPIENTRY
3790af69d88dSmrg_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment,
3791af69d88dSmrg                              GLuint texture, GLint level, GLint layer)
3792c1f859d4Smrg{
379301e04c3fSmrg   frame_buffer_texture(0, target, attachment, texture, level, layer,
379401e04c3fSmrg                        "glFramebufferTextureLayer", false, false, false);
379501e04c3fSmrg}
379601e04c3fSmrg
379701e04c3fSmrg
379801e04c3fSmrgvoid GLAPIENTRY
379901e04c3fSmrg_mesa_NamedFramebufferTextureLayer_no_error(GLuint framebuffer,
380001e04c3fSmrg                                            GLenum attachment,
380101e04c3fSmrg                                            GLuint texture, GLint level,
380201e04c3fSmrg                                            GLint layer)
380301e04c3fSmrg{
380401e04c3fSmrg   frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer,
380501e04c3fSmrg                        "glNamedFramebufferTextureLayer", true, true, false);
380601e04c3fSmrg}
380701e04c3fSmrg
380801e04c3fSmrg
380901e04c3fSmrgvoid GLAPIENTRY
381001e04c3fSmrg_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment,
381101e04c3fSmrg                                   GLuint texture, GLint level, GLint layer)
381201e04c3fSmrg{
381301e04c3fSmrg   frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer,
381401e04c3fSmrg                        "glNamedFramebufferTextureLayer", true, false, false);
381501e04c3fSmrg}
3816c1f859d4Smrg
381701e04c3fSmrg
381801e04c3fSmrgvoid GLAPIENTRY
381901e04c3fSmrg_mesa_FramebufferTexture_no_error(GLenum target, GLenum attachment,
382001e04c3fSmrg                                  GLuint texture, GLint level)
382101e04c3fSmrg{
382201e04c3fSmrg   frame_buffer_texture(0, target, attachment, texture, level, 0,
382301e04c3fSmrg                        "glFramebufferTexture", false, true, true);
3824af69d88dSmrg}
3825af69d88dSmrg
3826af69d88dSmrg
3827af69d88dSmrgvoid GLAPIENTRY
3828af69d88dSmrg_mesa_FramebufferTexture(GLenum target, GLenum attachment,
3829af69d88dSmrg                         GLuint texture, GLint level)
3830af69d88dSmrg{
383101e04c3fSmrg   frame_buffer_texture(0, target, attachment, texture, level, 0,
383201e04c3fSmrg                        "glFramebufferTexture", false, false, true);
383301e04c3fSmrg}
3834af69d88dSmrg
383501e04c3fSmrgvoid GLAPIENTRY
383601e04c3fSmrg_mesa_NamedFramebufferTexture_no_error(GLuint framebuffer, GLenum attachment,
383701e04c3fSmrg                                       GLuint texture, GLint level)
383801e04c3fSmrg{
383901e04c3fSmrg   frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0,
384001e04c3fSmrg                        "glNamedFramebufferTexture", true, true, true);
3841c1f859d4Smrg}
3842c1f859d4Smrg
3843c1f859d4Smrg
38447117f1b4Smrgvoid GLAPIENTRY
384501e04c3fSmrg_mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment,
384601e04c3fSmrg                              GLuint texture, GLint level)
38477117f1b4Smrg{
384801e04c3fSmrg   frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0,
384901e04c3fSmrg                        "glNamedFramebufferTexture", true, false, true);
385001e04c3fSmrg}
38517117f1b4Smrg
38527117f1b4Smrg
385301e04c3fSmrgvoid
385401e04c3fSmrg_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
385501e04c3fSmrg                               struct gl_framebuffer *fb,
385601e04c3fSmrg                               GLenum attachment,
385701e04c3fSmrg                               struct gl_renderbuffer *rb)
385801e04c3fSmrg{
385901e04c3fSmrg   assert(!_mesa_is_winsys_fbo(fb));
38607117f1b4Smrg
386101e04c3fSmrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
38627117f1b4Smrg
386301e04c3fSmrg   assert(ctx->Driver.FramebufferRenderbuffer);
386401e04c3fSmrg   ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
386501e04c3fSmrg
386601e04c3fSmrg   /* Some subsequent GL commands may depend on the framebuffer's visual
386701e04c3fSmrg    * after the binding is updated.  Update visual info now.
386801e04c3fSmrg    */
386901e04c3fSmrg   _mesa_update_framebuffer_visual(ctx, fb);
387001e04c3fSmrg}
387101e04c3fSmrg
387201e04c3fSmrgstatic ALWAYS_INLINE void
387301e04c3fSmrgframebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
387401e04c3fSmrg                         GLenum attachment, GLenum renderbuffertarget,
387501e04c3fSmrg                         GLuint renderbuffer, const char *func, bool no_error)
387601e04c3fSmrg{
387701e04c3fSmrg   struct gl_renderbuffer_attachment *att;
387801e04c3fSmrg   struct gl_renderbuffer *rb;
387901e04c3fSmrg   bool is_color_attachment;
388001e04c3fSmrg
388101e04c3fSmrg   if (!no_error && renderbuffertarget != GL_RENDERBUFFER) {
38827117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
388301e04c3fSmrg                  "%s(renderbuffertarget is not GL_RENDERBUFFER)", func);
38847117f1b4Smrg      return;
38857117f1b4Smrg   }
38867117f1b4Smrg
38877117f1b4Smrg   if (renderbuffer) {
388801e04c3fSmrg      if (!no_error) {
388901e04c3fSmrg         rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, func);
389001e04c3fSmrg         if (!rb)
389101e04c3fSmrg            return;
389201e04c3fSmrg      } else {
389301e04c3fSmrg         rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
38943464ebd5Sriastradh      }
389501e04c3fSmrg   } else {
38967117f1b4Smrg      /* remove renderbuffer attachment */
38977117f1b4Smrg      rb = NULL;
38987117f1b4Smrg   }
38997117f1b4Smrg
390001e04c3fSmrg   if (!no_error) {
390101e04c3fSmrg      if (_mesa_is_winsys_fbo(fb)) {
390201e04c3fSmrg         /* Can't attach new renderbuffers to a window system framebuffer */
39034a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
390401e04c3fSmrg                     "%s(window-system framebuffer)", func);
39054a49301eSmrg         return;
39064a49301eSmrg      }
39074a49301eSmrg
390801e04c3fSmrg      att = get_attachment(ctx, fb, attachment, &is_color_attachment);
390901e04c3fSmrg      if (att == NULL) {
391001e04c3fSmrg         /*
391101e04c3fSmrg          * From OpenGL 4.5 spec, section 9.2.7 "Attaching Renderbuffer Images
391201e04c3fSmrg          * to a Framebuffer":
391301e04c3fSmrg          *
391401e04c3fSmrg          *    "An INVALID_OPERATION error is generated if attachment is
391501e04c3fSmrg          *    COLOR_- ATTACHMENTm where m is greater than or equal to the
391601e04c3fSmrg          *    value of MAX_COLOR_- ATTACHMENTS ."
391701e04c3fSmrg          *
391801e04c3fSmrg          * If we are at this point, is because the attachment is not valid, so
391901e04c3fSmrg          * if is_color_attachment is true, is because of the previous reason.
392001e04c3fSmrg          */
392101e04c3fSmrg         if (is_color_attachment) {
392201e04c3fSmrg            _mesa_error(ctx, GL_INVALID_OPERATION,
392301e04c3fSmrg                        "%s(invalid color attachment %s)", func,
392401e04c3fSmrg                        _mesa_enum_to_string(attachment));
392501e04c3fSmrg         } else {
392601e04c3fSmrg            _mesa_error(ctx, GL_INVALID_ENUM,
392701e04c3fSmrg                        "%s(invalid attachment %s)", func,
392801e04c3fSmrg                        _mesa_enum_to_string(attachment));
392901e04c3fSmrg         }
39307117f1b4Smrg
393101e04c3fSmrg         return;
393201e04c3fSmrg      }
39337117f1b4Smrg
393401e04c3fSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
393501e04c3fSmrg          rb && rb->Format != MESA_FORMAT_NONE) {
393601e04c3fSmrg         /* make sure the renderbuffer is a depth/stencil format */
393701e04c3fSmrg         const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
393801e04c3fSmrg         if (baseFormat != GL_DEPTH_STENCIL) {
393901e04c3fSmrg            _mesa_error(ctx, GL_INVALID_OPERATION,
394001e04c3fSmrg                        "%s(renderbuffer is not DEPTH_STENCIL format)", func);
394101e04c3fSmrg            return;
394201e04c3fSmrg         }
394301e04c3fSmrg      }
394401e04c3fSmrg   }
394501e04c3fSmrg
394601e04c3fSmrg   _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
39477117f1b4Smrg}
39487117f1b4Smrg
394901e04c3fSmrgstatic void
395001e04c3fSmrgframebuffer_renderbuffer_error(struct gl_context *ctx,
395101e04c3fSmrg                               struct gl_framebuffer *fb, GLenum attachment,
395201e04c3fSmrg                               GLenum renderbuffertarget,
395301e04c3fSmrg                               GLuint renderbuffer, const char *func)
395401e04c3fSmrg{
395501e04c3fSmrg   framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget,
395601e04c3fSmrg                            renderbuffer, func, false);
395701e04c3fSmrg}
395801e04c3fSmrg
395901e04c3fSmrgstatic void
396001e04c3fSmrgframebuffer_renderbuffer_no_error(struct gl_context *ctx,
396101e04c3fSmrg                                  struct gl_framebuffer *fb, GLenum attachment,
396201e04c3fSmrg                                  GLenum renderbuffertarget,
396301e04c3fSmrg                                  GLuint renderbuffer, const char *func)
396401e04c3fSmrg{
396501e04c3fSmrg   framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget,
396601e04c3fSmrg                            renderbuffer, func, true);
396701e04c3fSmrg}
39687117f1b4Smrg
39697117f1b4Smrgvoid GLAPIENTRY
397001e04c3fSmrg_mesa_FramebufferRenderbuffer_no_error(GLenum target, GLenum attachment,
397101e04c3fSmrg                                       GLenum renderbuffertarget,
397201e04c3fSmrg                                       GLuint renderbuffer)
39737117f1b4Smrg{
39747117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
39757117f1b4Smrg
397601e04c3fSmrg   struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
397701e04c3fSmrg   framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget,
397801e04c3fSmrg                                     renderbuffer, "glFramebufferRenderbuffer");
397901e04c3fSmrg}
39803464ebd5Sriastradh
398101e04c3fSmrgvoid GLAPIENTRY
398201e04c3fSmrg_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment,
398301e04c3fSmrg                              GLenum renderbuffertarget,
398401e04c3fSmrg                              GLuint renderbuffer)
398501e04c3fSmrg{
398601e04c3fSmrg   struct gl_framebuffer *fb;
398701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
398801e04c3fSmrg
398901e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
399001e04c3fSmrg   if (!fb) {
39917117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
399201e04c3fSmrg                  "glFramebufferRenderbuffer(invalid target %s)",
399301e04c3fSmrg                  _mesa_enum_to_string(target));
39947117f1b4Smrg      return;
39957117f1b4Smrg   }
39967117f1b4Smrg
399701e04c3fSmrg   framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
399801e04c3fSmrg                                  renderbuffer, "glFramebufferRenderbuffer");
399901e04c3fSmrg}
400001e04c3fSmrg
400101e04c3fSmrgvoid GLAPIENTRY
400201e04c3fSmrg_mesa_NamedFramebufferRenderbuffer_no_error(GLuint framebuffer,
400301e04c3fSmrg                                            GLenum attachment,
400401e04c3fSmrg                                            GLenum renderbuffertarget,
400501e04c3fSmrg                                            GLuint renderbuffer)
400601e04c3fSmrg{
400701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
400801e04c3fSmrg
400901e04c3fSmrg   struct gl_framebuffer *fb = _mesa_lookup_framebuffer(ctx, framebuffer);
401001e04c3fSmrg   framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget,
401101e04c3fSmrg                                     renderbuffer,
401201e04c3fSmrg                                     "glNamedFramebufferRenderbuffer");
401301e04c3fSmrg}
401401e04c3fSmrg
401501e04c3fSmrgvoid GLAPIENTRY
401601e04c3fSmrg_mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment,
401701e04c3fSmrg                                   GLenum renderbuffertarget,
401801e04c3fSmrg                                   GLuint renderbuffer)
401901e04c3fSmrg{
402001e04c3fSmrg   struct gl_framebuffer *fb;
402101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
402201e04c3fSmrg
402301e04c3fSmrg   fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
402401e04c3fSmrg                                     "glNamedFramebufferRenderbuffer");
402501e04c3fSmrg   if (!fb)
402601e04c3fSmrg      return;
402701e04c3fSmrg
402801e04c3fSmrg   framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
402901e04c3fSmrg                                  renderbuffer,
403001e04c3fSmrg                                  "glNamedFramebufferRenderbuffer");
403101e04c3fSmrg}
403201e04c3fSmrg
403301e04c3fSmrg
403401e04c3fSmrgstatic void
403501e04c3fSmrgget_framebuffer_attachment_parameter(struct gl_context *ctx,
403601e04c3fSmrg                                     struct gl_framebuffer *buffer,
403701e04c3fSmrg                                     GLenum attachment, GLenum pname,
403801e04c3fSmrg                                     GLint *params, const char *caller)
403901e04c3fSmrg{
404001e04c3fSmrg   const struct gl_renderbuffer_attachment *att;
404101e04c3fSmrg   bool is_color_attachment = false;
404201e04c3fSmrg   GLenum err;
404301e04c3fSmrg
404401e04c3fSmrg   /* The error code for an attachment type of GL_NONE differs between APIs.
404501e04c3fSmrg    *
404601e04c3fSmrg    * From the ES 2.0.25 specification, page 127:
404701e04c3fSmrg    * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then
404801e04c3fSmrg    *  querying any other pname will generate INVALID_ENUM."
404901e04c3fSmrg    *
405001e04c3fSmrg    * From the OpenGL 3.0 specification, page 337, or identically,
405101e04c3fSmrg    * the OpenGL ES 3.0.4 specification, page 240:
405201e04c3fSmrg    *
405301e04c3fSmrg    * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, no
405401e04c3fSmrg    *  framebuffer is bound to target.  In this case querying pname
405501e04c3fSmrg    *  FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero, and all other
405601e04c3fSmrg    *  queries will generate an INVALID_OPERATION error."
405701e04c3fSmrg    */
405801e04c3fSmrg   err = ctx->API == API_OPENGLES2 && ctx->Version < 30 ?
405901e04c3fSmrg      GL_INVALID_ENUM : GL_INVALID_OPERATION;
406001e04c3fSmrg
4061af69d88dSmrg   if (_mesa_is_winsys_fbo(buffer)) {
4062af69d88dSmrg      /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec
4063af69d88dSmrg       * says:
4064af69d88dSmrg       *
4065af69d88dSmrg       *     "If the framebuffer currently bound to target is zero, then
4066af69d88dSmrg       *     INVALID_OPERATION is generated."
4067af69d88dSmrg       *
4068af69d88dSmrg       * The EXT_framebuffer_object spec has the same wording, and the
4069af69d88dSmrg       * OES_framebuffer_object spec refers to the EXT_framebuffer_object
4070af69d88dSmrg       * spec.
4071af69d88dSmrg       */
4072af69d88dSmrg      if ((!_mesa_is_desktop_gl(ctx) ||
4073af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
4074af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
407501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
407601e04c3fSmrg                     "%s(window-system framebuffer)", caller);
407701e04c3fSmrg         return;
4078af69d88dSmrg      }
4079af69d88dSmrg
4080af69d88dSmrg      if (_mesa_is_gles3(ctx) && attachment != GL_BACK &&
4081af69d88dSmrg          attachment != GL_DEPTH && attachment != GL_STENCIL) {
408201e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
408301e04c3fSmrg                     "%s(invalid attachment %s)", caller,
408401e04c3fSmrg                     _mesa_enum_to_string(attachment));
408501e04c3fSmrg         return;
408601e04c3fSmrg      }
408701e04c3fSmrg
408801e04c3fSmrg      /* The specs are not clear about how to handle
408901e04c3fSmrg       * GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME with the default framebuffer,
409001e04c3fSmrg       * but dEQP-GLES3 expects an INVALID_ENUM error. This has also been
409101e04c3fSmrg       * discussed in:
409201e04c3fSmrg       *
409301e04c3fSmrg       * https://cvs.khronos.org/bugzilla/show_bug.cgi?id=12928#c1
409401e04c3fSmrg       * and https://bugs.freedesktop.org/show_bug.cgi?id=31947
409501e04c3fSmrg       */
409601e04c3fSmrg      if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
409701e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
409801e04c3fSmrg                     "%s(requesting GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME "
409901e04c3fSmrg                     "when GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is "
410001e04c3fSmrg                     "GL_FRAMEBUFFER_DEFAULT is not allowed)", caller);
4101af69d88dSmrg         return;
4102af69d88dSmrg      }
410301e04c3fSmrg
41043464ebd5Sriastradh      /* the default / window-system FBO */
410501e04c3fSmrg      att = get_fb0_attachment(ctx, buffer, attachment);
41063464ebd5Sriastradh   }
41073464ebd5Sriastradh   else {
41083464ebd5Sriastradh      /* user-created framebuffer FBO */
410901e04c3fSmrg      att = get_attachment(ctx, buffer, attachment, &is_color_attachment);
41107117f1b4Smrg   }
41117117f1b4Smrg
41127117f1b4Smrg   if (att == NULL) {
411301e04c3fSmrg      /*
411401e04c3fSmrg       * From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries":
411501e04c3fSmrg       *
411601e04c3fSmrg       *    "An INVALID_OPERATION error is generated if a framebuffer object
411701e04c3fSmrg       *     is bound to target and attachment is COLOR_ATTACHMENTm where m is
411801e04c3fSmrg       *     greater than or equal to the value of MAX_COLOR_ATTACHMENTS."
411901e04c3fSmrg       *
412001e04c3fSmrg       * If we are at this point, is because the attachment is not valid, so
412101e04c3fSmrg       * if is_color_attachment is true, is because of the previous reason.
412201e04c3fSmrg       */
412301e04c3fSmrg      if (is_color_attachment) {
412401e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid color attachment %s)",
412501e04c3fSmrg                     caller, _mesa_enum_to_string(attachment));
412601e04c3fSmrg      } else {
412701e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller,
412801e04c3fSmrg                     _mesa_enum_to_string(attachment));
412901e04c3fSmrg      }
41307117f1b4Smrg      return;
41317117f1b4Smrg   }
41327117f1b4Smrg
41334a49301eSmrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
41344a49301eSmrg      const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
4135af69d88dSmrg      if (pname == GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) {
4136af69d88dSmrg         /* This behavior is first specified in OpenGL 4.4 specification.
4137af69d88dSmrg          *
4138af69d88dSmrg          * From the OpenGL 4.4 spec page 275:
4139af69d88dSmrg          *   "This query cannot be performed for a combined depth+stencil
4140af69d88dSmrg          *    attachment, since it does not have a single format."
4141af69d88dSmrg          */
4142af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
414301e04c3fSmrg                     "%s(GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE"
414401e04c3fSmrg                     " is invalid for depth+stencil attachment)", caller);
4145af69d88dSmrg         return;
4146af69d88dSmrg      }
4147af69d88dSmrg      /* the depth and stencil attachments must point to the same buffer */
414801e04c3fSmrg      depthAtt = get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT, NULL);
414901e04c3fSmrg      stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT, NULL);
41504a49301eSmrg      if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
41514a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
415201e04c3fSmrg                     "%s(DEPTH/STENCIL attachments differ)", caller);
41534a49301eSmrg         return;
41544a49301eSmrg      }
41554a49301eSmrg   }
41564a49301eSmrg
41574a49301eSmrg   /* No need to flush here */
41587117f1b4Smrg
41597117f1b4Smrg   switch (pname) {
41607117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
416101e04c3fSmrg      /* From the OpenGL spec, 9.2. Binding and Managing Framebuffer Objects:
416201e04c3fSmrg       *
416301e04c3fSmrg       * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then
416401e04c3fSmrg       *  either no framebuffer is bound to target; or the default framebuffer
416501e04c3fSmrg       *  is bound, attachment is DEPTH or STENCIL, and the number of depth or
416601e04c3fSmrg       *  stencil bits, respectively, is zero."
416701e04c3fSmrg       *
416801e04c3fSmrg       * Note that we don't need explicit checks on DEPTH and STENCIL, because
416901e04c3fSmrg       * on the case the spec is pointing, att->Type is already NONE, so we
417001e04c3fSmrg       * just need to check att->Type.
417101e04c3fSmrg       */
417201e04c3fSmrg      *params = (_mesa_is_winsys_fbo(buffer) && att->Type != GL_NONE) ?
417301e04c3fSmrg         GL_FRAMEBUFFER_DEFAULT : att->Type;
41747117f1b4Smrg      return;
41757117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
41767117f1b4Smrg      if (att->Type == GL_RENDERBUFFER_EXT) {
417701e04c3fSmrg         *params = att->Renderbuffer->Name;
41787117f1b4Smrg      }
41797117f1b4Smrg      else if (att->Type == GL_TEXTURE) {
418001e04c3fSmrg         *params = att->Texture->Name;
41817117f1b4Smrg      }
41827117f1b4Smrg      else {
41833464ebd5Sriastradh         assert(att->Type == GL_NONE);
4184af69d88dSmrg         if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
41853464ebd5Sriastradh            *params = 0;
41863464ebd5Sriastradh         } else {
4187af69d88dSmrg            goto invalid_pname_enum;
41883464ebd5Sriastradh         }
41897117f1b4Smrg      }
41907117f1b4Smrg      return;
41917117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
41927117f1b4Smrg      if (att->Type == GL_TEXTURE) {
419301e04c3fSmrg         *params = att->TextureLevel;
41947117f1b4Smrg      }
41953464ebd5Sriastradh      else if (att->Type == GL_NONE) {
419601e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
419701e04c3fSmrg                     _mesa_enum_to_string(pname));
41983464ebd5Sriastradh      }
41997117f1b4Smrg      else {
4200af69d88dSmrg         goto invalid_pname_enum;
42017117f1b4Smrg      }
42027117f1b4Smrg      return;
42037117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
42047117f1b4Smrg      if (att->Type == GL_TEXTURE) {
4205c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
4206c1f859d4Smrg            *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
4207c1f859d4Smrg         }
4208c1f859d4Smrg         else {
4209c1f859d4Smrg            *params = 0;
4210c1f859d4Smrg         }
42117117f1b4Smrg      }
42123464ebd5Sriastradh      else if (att->Type == GL_NONE) {
421301e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
421401e04c3fSmrg                     _mesa_enum_to_string(pname));
42153464ebd5Sriastradh      }
42167117f1b4Smrg      else {
4217af69d88dSmrg         goto invalid_pname_enum;
42187117f1b4Smrg      }
42197117f1b4Smrg      return;
42207117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
4221af69d88dSmrg      if (ctx->API == API_OPENGLES) {
4222af69d88dSmrg         goto invalid_pname_enum;
4223af69d88dSmrg      } else if (att->Type == GL_NONE) {
422401e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
422501e04c3fSmrg                     _mesa_enum_to_string(pname));
4226af69d88dSmrg      } else if (att->Type == GL_TEXTURE) {
422701e04c3fSmrg         if (att->Texture && (att->Texture->Target == GL_TEXTURE_3D ||
422801e04c3fSmrg             att->Texture->Target == GL_TEXTURE_2D_ARRAY)) {
4229c1f859d4Smrg            *params = att->Zoffset;
4230c1f859d4Smrg         }
4231c1f859d4Smrg         else {
4232c1f859d4Smrg            *params = 0;
4233c1f859d4Smrg         }
42347117f1b4Smrg      }
42357117f1b4Smrg      else {
4236af69d88dSmrg         goto invalid_pname_enum;
42377117f1b4Smrg      }
42387117f1b4Smrg      return;
42394a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
4240af69d88dSmrg      if ((!_mesa_is_desktop_gl(ctx) ||
4241af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
4242af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
4243af69d88dSmrg         goto invalid_pname_enum;
42444a49301eSmrg      }
42453464ebd5Sriastradh      else if (att->Type == GL_NONE) {
424601e04c3fSmrg         if (_mesa_is_winsys_fbo(buffer) &&
424701e04c3fSmrg             (attachment == GL_DEPTH || attachment == GL_STENCIL)) {
424801e04c3fSmrg            *params = GL_LINEAR;
424901e04c3fSmrg         } else {
425001e04c3fSmrg            _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
425101e04c3fSmrg                        _mesa_enum_to_string(pname));
425201e04c3fSmrg         }
42533464ebd5Sriastradh      }
42544a49301eSmrg      else {
4255af69d88dSmrg         if (ctx->Extensions.EXT_framebuffer_sRGB) {
4256af69d88dSmrg            *params =
4257af69d88dSmrg               _mesa_get_format_color_encoding(att->Renderbuffer->Format);
42583464ebd5Sriastradh         }
42593464ebd5Sriastradh         else {
42603464ebd5Sriastradh            /* According to ARB_framebuffer_sRGB, we should return LINEAR
42613464ebd5Sriastradh             * if the sRGB conversion is unsupported. */
42623464ebd5Sriastradh            *params = GL_LINEAR;
42633464ebd5Sriastradh         }
42644a49301eSmrg      }
42654a49301eSmrg      return;
42664a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
4267af69d88dSmrg      if ((ctx->API != API_OPENGL_COMPAT ||
4268af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
4269af69d88dSmrg          && ctx->API != API_OPENGL_CORE
4270af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
4271af69d88dSmrg         goto invalid_pname_enum;
42724a49301eSmrg      }
42733464ebd5Sriastradh      else if (att->Type == GL_NONE) {
427401e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
427501e04c3fSmrg                     _mesa_enum_to_string(pname));
42763464ebd5Sriastradh      }
42774a49301eSmrg      else {
4278af69d88dSmrg         mesa_format format = att->Renderbuffer->Format;
4279af69d88dSmrg
4280af69d88dSmrg         /* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES
4281af69d88dSmrg          * 3.0.1 spec says:
4282af69d88dSmrg          *
4283af69d88dSmrg          *     "If pname is FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE.... If
4284af69d88dSmrg          *     attachment is DEPTH_STENCIL_ATTACHMENT the query will fail and
4285af69d88dSmrg          *     generate an INVALID_OPERATION error.
4286af69d88dSmrg          */
4287af69d88dSmrg         if (_mesa_is_gles3(ctx) &&
4288af69d88dSmrg             attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
4289af69d88dSmrg            _mesa_error(ctx, GL_INVALID_OPERATION,
429001e04c3fSmrg                        "%s(cannot query "
4291af69d88dSmrg                        "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of "
429201e04c3fSmrg                        "GL_DEPTH_STENCIL_ATTACHMENT)", caller);
4293af69d88dSmrg            return;
4294af69d88dSmrg         }
4295af69d88dSmrg
4296af69d88dSmrg         if (format == MESA_FORMAT_S_UINT8) {
42974a49301eSmrg            /* special cases */
42984a49301eSmrg            *params = GL_INDEX;
42994a49301eSmrg         }
4300af69d88dSmrg         else if (format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) {
4301af69d88dSmrg            /* depends on the attachment parameter */
4302af69d88dSmrg            if (attachment == GL_STENCIL_ATTACHMENT) {
4303af69d88dSmrg               *params = GL_INDEX;
4304af69d88dSmrg            }
4305af69d88dSmrg            else {
4306af69d88dSmrg               *params = GL_FLOAT;
4307af69d88dSmrg            }
4308af69d88dSmrg         }
43094a49301eSmrg         else {
43104a49301eSmrg            *params = _mesa_get_format_datatype(format);
43114a49301eSmrg         }
43124a49301eSmrg      }
43134a49301eSmrg      return;
43144a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
43154a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
43164a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
43174a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
43184a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
43194a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
4320af69d88dSmrg      if ((!_mesa_is_desktop_gl(ctx) ||
4321af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
4322af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
4323af69d88dSmrg         goto invalid_pname_enum;
43244a49301eSmrg      }
43254a49301eSmrg      else if (att->Texture) {
43264a49301eSmrg         const struct gl_texture_image *texImage =
432701e04c3fSmrg            _mesa_select_tex_image(att->Texture, att->Texture->Target,
43284a49301eSmrg                                   att->TextureLevel);
43294a49301eSmrg         if (texImage) {
43304a49301eSmrg            *params = get_component_bits(pname, texImage->_BaseFormat,
43314a49301eSmrg                                         texImage->TexFormat);
43324a49301eSmrg         }
43334a49301eSmrg         else {
43344a49301eSmrg            *params = 0;
43354a49301eSmrg         }
43364a49301eSmrg      }
43374a49301eSmrg      else if (att->Renderbuffer) {
43384a49301eSmrg         *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
43394a49301eSmrg                                      att->Renderbuffer->Format);
43404a49301eSmrg      }
43414a49301eSmrg      else {
434201e04c3fSmrg         assert(att->Type == GL_NONE);
434301e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
434401e04c3fSmrg                     _mesa_enum_to_string(pname));
43454a49301eSmrg      }
43464a49301eSmrg      return;
4347af69d88dSmrg   case GL_FRAMEBUFFER_ATTACHMENT_LAYERED:
4348af69d88dSmrg      if (!_mesa_has_geometry_shaders(ctx)) {
4349af69d88dSmrg         goto invalid_pname_enum;
4350af69d88dSmrg      } else if (att->Type == GL_TEXTURE) {
4351af69d88dSmrg         *params = att->Layered;
4352af69d88dSmrg      } else if (att->Type == GL_NONE) {
435301e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
435401e04c3fSmrg                     _mesa_enum_to_string(pname));
4355af69d88dSmrg      } else {
4356af69d88dSmrg         goto invalid_pname_enum;
4357af69d88dSmrg      }
43587117f1b4Smrg      return;
4359af69d88dSmrg   default:
4360af69d88dSmrg      goto invalid_pname_enum;
43617117f1b4Smrg   }
4362af69d88dSmrg
4363af69d88dSmrg   return;
4364af69d88dSmrg
4365af69d88dSmrginvalid_pname_enum:
436601e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname %s)", caller,
436701e04c3fSmrg               _mesa_enum_to_string(pname));
4368af69d88dSmrg   return;
43697117f1b4Smrg}
43707117f1b4Smrg
43717117f1b4Smrg
437201e04c3fSmrgvoid GLAPIENTRY
437301e04c3fSmrg_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment,
437401e04c3fSmrg                                          GLenum pname, GLint *params)
437501e04c3fSmrg{
437601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
437701e04c3fSmrg   struct gl_framebuffer *buffer;
437801e04c3fSmrg
437901e04c3fSmrg   buffer = get_framebuffer_target(ctx, target);
438001e04c3fSmrg   if (!buffer) {
438101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
438201e04c3fSmrg                  "glGetFramebufferAttachmentParameteriv(invalid target %s)",
438301e04c3fSmrg                  _mesa_enum_to_string(target));
438401e04c3fSmrg      return;
438501e04c3fSmrg   }
438601e04c3fSmrg
438701e04c3fSmrg   get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
438801e04c3fSmrg                                        params,
438901e04c3fSmrg                                    "glGetFramebufferAttachmentParameteriv");
439001e04c3fSmrg}
439101e04c3fSmrg
439201e04c3fSmrg
439301e04c3fSmrgvoid GLAPIENTRY
439401e04c3fSmrg_mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer,
439501e04c3fSmrg                                               GLenum attachment,
439601e04c3fSmrg                                               GLenum pname, GLint *params)
439701e04c3fSmrg{
439801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
439901e04c3fSmrg   struct gl_framebuffer *buffer;
440001e04c3fSmrg
440101e04c3fSmrg   if (framebuffer) {
440201e04c3fSmrg      buffer = _mesa_lookup_framebuffer_err(ctx, framebuffer,
440301e04c3fSmrg                              "glGetNamedFramebufferAttachmentParameteriv");
440401e04c3fSmrg      if (!buffer)
440501e04c3fSmrg         return;
440601e04c3fSmrg   }
440701e04c3fSmrg   else {
440801e04c3fSmrg      /*
440901e04c3fSmrg       * Section 9.2 Binding and Managing Framebuffer Objects of the OpenGL
441001e04c3fSmrg       * 4.5 core spec (30.10.2014, PDF page 314):
441101e04c3fSmrg       *    "If framebuffer is zero, then the default draw framebuffer is
441201e04c3fSmrg       *    queried."
441301e04c3fSmrg       */
441401e04c3fSmrg      buffer = ctx->WinSysDrawBuffer;
441501e04c3fSmrg   }
441601e04c3fSmrg
441701e04c3fSmrg   get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
441801e04c3fSmrg                                        params,
441901e04c3fSmrg                              "glGetNamedFramebufferAttachmentParameteriv");
442001e04c3fSmrg}
442101e04c3fSmrg
442201e04c3fSmrg
442301e04c3fSmrgvoid GLAPIENTRY
442401e04c3fSmrg_mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname,
442501e04c3fSmrg                                 GLint param)
442601e04c3fSmrg{
442701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
442801e04c3fSmrg   struct gl_framebuffer *fb = NULL;
442901e04c3fSmrg
443001e04c3fSmrg   if (!ctx->Extensions.ARB_framebuffer_no_attachments &&
443101e04c3fSmrg       !ctx->Extensions.ARB_sample_locations) {
443201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
443301e04c3fSmrg                  "glNamedFramebufferParameteri("
443401e04c3fSmrg                  "neither ARB_framebuffer_no_attachments nor "
443501e04c3fSmrg                  "ARB_sample_locations is available)");
443601e04c3fSmrg      return;
443701e04c3fSmrg   }
443801e04c3fSmrg
443901e04c3fSmrg   if (framebuffer) {
444001e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
444101e04c3fSmrg                                        "glNamedFramebufferParameteri");
444201e04c3fSmrg   } else {
444301e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
444401e04c3fSmrg   }
444501e04c3fSmrg
444601e04c3fSmrg   if (fb) {
444701e04c3fSmrg      framebuffer_parameteri(ctx, fb, pname, param,
444801e04c3fSmrg                             "glNamedFramebufferParameteriv");
444901e04c3fSmrg   }
445001e04c3fSmrg}
445101e04c3fSmrg
445201e04c3fSmrg
445301e04c3fSmrgvoid GLAPIENTRY
445401e04c3fSmrg_mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname,
445501e04c3fSmrg                                     GLint *param)
445601e04c3fSmrg{
445701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
445801e04c3fSmrg   struct gl_framebuffer *fb;
445901e04c3fSmrg
446001e04c3fSmrg   if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
446101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
446201e04c3fSmrg                  "glNamedFramebufferParameteriv("
446301e04c3fSmrg                  "neither ARB_framebuffer_no_attachments nor ARB_sample_locations"
446401e04c3fSmrg                  " is available)");
446501e04c3fSmrg      return;
446601e04c3fSmrg   }
446701e04c3fSmrg
446801e04c3fSmrg   if (framebuffer)
446901e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
447001e04c3fSmrg                                        "glGetNamedFramebufferParameteriv");
447101e04c3fSmrg   else
447201e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
447301e04c3fSmrg
447401e04c3fSmrg   if (fb) {
447501e04c3fSmrg      get_framebuffer_parameteriv(ctx, fb, pname, param,
447601e04c3fSmrg                                  "glGetNamedFramebufferParameteriv");
447701e04c3fSmrg   }
447801e04c3fSmrg}
447901e04c3fSmrg
448001e04c3fSmrg
4481af69d88dSmrgstatic void
448201e04c3fSmrginvalidate_framebuffer_storage(struct gl_context *ctx,
448301e04c3fSmrg                               struct gl_framebuffer *fb,
448401e04c3fSmrg                               GLsizei numAttachments,
4485af69d88dSmrg                               const GLenum *attachments, GLint x, GLint y,
4486af69d88dSmrg                               GLsizei width, GLsizei height, const char *name)
44877117f1b4Smrg{
4488af69d88dSmrg   int i;
44897117f1b4Smrg
449001e04c3fSmrg   /* Section 17.4 Whole Framebuffer Operations of the OpenGL 4.5 Core
449101e04c3fSmrg    * Spec (2.2.2015, PDF page 522) says:
449201e04c3fSmrg    *    "An INVALID_VALUE error is generated if numAttachments, width, or
449301e04c3fSmrg    *    height is negative."
449401e04c3fSmrg    */
449501e04c3fSmrg   if (numAttachments < 0) {
449601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
449701e04c3fSmrg                  "%s(numAttachments < 0)", name);
44987117f1b4Smrg      return;
44997117f1b4Smrg   }
45007117f1b4Smrg
450101e04c3fSmrg   if (width < 0) {
4502af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
450301e04c3fSmrg                  "%s(width < 0)", name);
450401e04c3fSmrg      return;
450501e04c3fSmrg   }
450601e04c3fSmrg
450701e04c3fSmrg   if (height < 0) {
450801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
450901e04c3fSmrg                  "%s(height < 0)", name);
45104a49301eSmrg      return;
45114a49301eSmrg   }
45127117f1b4Smrg
4513af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
4514af69d88dSmrg    *
4515af69d88dSmrg    *     "If an attachment is specified that does not exist in the
4516af69d88dSmrg    *     framebuffer bound to <target>, it is ignored."
4517af69d88dSmrg    *
4518af69d88dSmrg    * It also says:
4519af69d88dSmrg    *
4520af69d88dSmrg    *     "If <attachments> contains COLOR_ATTACHMENTm and m is greater than
4521af69d88dSmrg    *     or equal to the value of MAX_COLOR_ATTACHMENTS, then the error
4522af69d88dSmrg    *     INVALID_OPERATION is generated."
4523af69d88dSmrg    *
4524af69d88dSmrg    * No mention is made of GL_AUXi being out of range.  Therefore, we allow
4525af69d88dSmrg    * any enum that can be allowed by the API (OpenGL ES 3.0 has a different
4526af69d88dSmrg    * set of retrictions).
4527af69d88dSmrg    */
4528af69d88dSmrg   for (i = 0; i < numAttachments; i++) {
4529af69d88dSmrg      if (_mesa_is_winsys_fbo(fb)) {
4530af69d88dSmrg         switch (attachments[i]) {
4531af69d88dSmrg         case GL_ACCUM:
4532af69d88dSmrg         case GL_AUX0:
4533af69d88dSmrg         case GL_AUX1:
4534af69d88dSmrg         case GL_AUX2:
4535af69d88dSmrg         case GL_AUX3:
4536af69d88dSmrg            /* Accumulation buffers and auxilary buffers were removed in
4537af69d88dSmrg             * OpenGL 3.1, and they never existed in OpenGL ES.
4538af69d88dSmrg             */
4539af69d88dSmrg            if (ctx->API != API_OPENGL_COMPAT)
4540af69d88dSmrg               goto invalid_enum;
4541af69d88dSmrg            break;
4542af69d88dSmrg         case GL_COLOR:
4543af69d88dSmrg         case GL_DEPTH:
4544af69d88dSmrg         case GL_STENCIL:
4545af69d88dSmrg            break;
4546af69d88dSmrg         case GL_BACK_LEFT:
4547af69d88dSmrg         case GL_BACK_RIGHT:
4548af69d88dSmrg         case GL_FRONT_LEFT:
4549af69d88dSmrg         case GL_FRONT_RIGHT:
4550af69d88dSmrg            if (!_mesa_is_desktop_gl(ctx))
4551af69d88dSmrg               goto invalid_enum;
4552af69d88dSmrg            break;
4553af69d88dSmrg         default:
4554af69d88dSmrg            goto invalid_enum;
4555af69d88dSmrg         }
4556af69d88dSmrg      } else {
4557af69d88dSmrg         switch (attachments[i]) {
4558af69d88dSmrg         case GL_DEPTH_ATTACHMENT:
4559af69d88dSmrg         case GL_STENCIL_ATTACHMENT:
4560af69d88dSmrg            break;
456101e04c3fSmrg         case GL_DEPTH_STENCIL_ATTACHMENT:
456201e04c3fSmrg            /* GL_DEPTH_STENCIL_ATTACHMENT is a valid attachment point only
456301e04c3fSmrg             * in desktop and ES 3.0 profiles. Note that OES_packed_depth_stencil
456401e04c3fSmrg             * extension does not make this attachment point valid on ES 2.0.
456501e04c3fSmrg             */
456601e04c3fSmrg            if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx))
456701e04c3fSmrg               break;
456801e04c3fSmrg            /* fallthrough */
4569af69d88dSmrg         case GL_COLOR_ATTACHMENT0:
4570af69d88dSmrg         case GL_COLOR_ATTACHMENT1:
4571af69d88dSmrg         case GL_COLOR_ATTACHMENT2:
4572af69d88dSmrg         case GL_COLOR_ATTACHMENT3:
4573af69d88dSmrg         case GL_COLOR_ATTACHMENT4:
4574af69d88dSmrg         case GL_COLOR_ATTACHMENT5:
4575af69d88dSmrg         case GL_COLOR_ATTACHMENT6:
4576af69d88dSmrg         case GL_COLOR_ATTACHMENT7:
4577af69d88dSmrg         case GL_COLOR_ATTACHMENT8:
4578af69d88dSmrg         case GL_COLOR_ATTACHMENT9:
4579af69d88dSmrg         case GL_COLOR_ATTACHMENT10:
4580af69d88dSmrg         case GL_COLOR_ATTACHMENT11:
4581af69d88dSmrg         case GL_COLOR_ATTACHMENT12:
4582af69d88dSmrg         case GL_COLOR_ATTACHMENT13:
4583af69d88dSmrg         case GL_COLOR_ATTACHMENT14:
4584af69d88dSmrg         case GL_COLOR_ATTACHMENT15: {
4585af69d88dSmrg            unsigned k = attachments[i] - GL_COLOR_ATTACHMENT0;
4586af69d88dSmrg            if (k >= ctx->Const.MaxColorAttachments) {
4587af69d88dSmrg               _mesa_error(ctx, GL_INVALID_OPERATION,
4588af69d88dSmrg                           "%s(attachment >= max. color attachments)", name);
4589af69d88dSmrg               return;
4590af69d88dSmrg            }
4591af69d88dSmrg            break;
4592af69d88dSmrg         }
4593af69d88dSmrg         default:
4594af69d88dSmrg            goto invalid_enum;
4595af69d88dSmrg         }
4596af69d88dSmrg      }
45973464ebd5Sriastradh   }
45983464ebd5Sriastradh
4599af69d88dSmrg   /* We don't actually do anything for this yet.  Just return after
4600af69d88dSmrg    * validating the parameters and generating the required errors.
4601af69d88dSmrg    */
4602af69d88dSmrg   return;
46037117f1b4Smrg
4604af69d88dSmrginvalid_enum:
460501e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", name,
460601e04c3fSmrg               _mesa_enum_to_string(attachments[i]));
4607af69d88dSmrg   return;
4608af69d88dSmrg}
46097117f1b4Smrg
46104a49301eSmrg
461101e04c3fSmrgvoid GLAPIENTRY
461201e04c3fSmrg_mesa_InvalidateSubFramebuffer_no_error(GLenum target, GLsizei numAttachments,
461301e04c3fSmrg                                        const GLenum *attachments, GLint x,
461401e04c3fSmrg                                        GLint y, GLsizei width, GLsizei height)
461501e04c3fSmrg{
461601e04c3fSmrg   /* no-op */
461701e04c3fSmrg}
461801e04c3fSmrg
461901e04c3fSmrg
4620af69d88dSmrgvoid GLAPIENTRY
4621af69d88dSmrg_mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
4622af69d88dSmrg                               const GLenum *attachments, GLint x, GLint y,
4623af69d88dSmrg                               GLsizei width, GLsizei height)
46244a49301eSmrg{
462501e04c3fSmrg   struct gl_framebuffer *fb;
462601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
462701e04c3fSmrg
462801e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
462901e04c3fSmrg   if (!fb) {
463001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
463101e04c3fSmrg                  "glInvalidateSubFramebuffer(invalid target %s)",
463201e04c3fSmrg                  _mesa_enum_to_string(target));
463301e04c3fSmrg      return;
463401e04c3fSmrg   }
463501e04c3fSmrg
463601e04c3fSmrg   invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
4637af69d88dSmrg                                  x, y, width, height,
4638af69d88dSmrg                                  "glInvalidateSubFramebuffer");
46394a49301eSmrg}
46404a49301eSmrg
46414a49301eSmrg
464201e04c3fSmrgvoid GLAPIENTRY
464301e04c3fSmrg_mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer,
464401e04c3fSmrg                                        GLsizei numAttachments,
464501e04c3fSmrg                                        const GLenum *attachments,
464601e04c3fSmrg                                        GLint x, GLint y,
464701e04c3fSmrg                                        GLsizei width, GLsizei height)
464801e04c3fSmrg{
464901e04c3fSmrg   struct gl_framebuffer *fb;
465001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
465101e04c3fSmrg
465201e04c3fSmrg   /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole
465301e04c3fSmrg    * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the
465401e04c3fSmrg    * default draw framebuffer is affected."
465501e04c3fSmrg    */
465601e04c3fSmrg   if (framebuffer) {
465701e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
465801e04c3fSmrg                                        "glInvalidateNamedFramebufferSubData");
465901e04c3fSmrg      if (!fb)
466001e04c3fSmrg         return;
466101e04c3fSmrg   }
466201e04c3fSmrg   else
466301e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
466401e04c3fSmrg
466501e04c3fSmrg   invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
466601e04c3fSmrg                                  x, y, width, height,
466701e04c3fSmrg                                  "glInvalidateNamedFramebufferSubData");
466801e04c3fSmrg}
466901e04c3fSmrg
467001e04c3fSmrg
467101e04c3fSmrgvoid GLAPIENTRY
467201e04c3fSmrg_mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments,
467301e04c3fSmrg                                     const GLenum *attachments)
467401e04c3fSmrg{
467501e04c3fSmrg   /* no-op */
467601e04c3fSmrg}
467701e04c3fSmrg
467801e04c3fSmrg
46797117f1b4Smrgvoid GLAPIENTRY
4680af69d88dSmrg_mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments,
4681af69d88dSmrg                            const GLenum *attachments)
46827117f1b4Smrg{
468301e04c3fSmrg   struct gl_framebuffer *fb;
468401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
468501e04c3fSmrg
468601e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
468701e04c3fSmrg   if (!fb) {
468801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
468901e04c3fSmrg                  "glInvalidateFramebuffer(invalid target %s)",
469001e04c3fSmrg                  _mesa_enum_to_string(target));
469101e04c3fSmrg      return;
469201e04c3fSmrg   }
469301e04c3fSmrg
4694af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
4695af69d88dSmrg    *
4696af69d88dSmrg    *     "The command
4697af69d88dSmrg    *
4698af69d88dSmrg    *        void InvalidateFramebuffer(enum target,
4699af69d88dSmrg    *                                   sizei numAttachments,
4700af69d88dSmrg    *                                   const enum *attachments);
4701af69d88dSmrg    *
4702af69d88dSmrg    *     is equivalent to the command InvalidateSubFramebuffer with <x>, <y>,
4703af69d88dSmrg    *     <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>,
4704af69d88dSmrg    *     <MAX_VIEWPORT_DIMS[1]> respectively."
4705af69d88dSmrg    */
470601e04c3fSmrg   invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
4707af69d88dSmrg                                  0, 0,
470801e04c3fSmrg                                  ctx->Const.MaxViewportWidth,
470901e04c3fSmrg                                  ctx->Const.MaxViewportHeight,
4710af69d88dSmrg                                  "glInvalidateFramebuffer");
4711af69d88dSmrg}
47124a49301eSmrg
47133464ebd5Sriastradh
471401e04c3fSmrgvoid GLAPIENTRY
471501e04c3fSmrg_mesa_InvalidateNamedFramebufferData(GLuint framebuffer,
471601e04c3fSmrg                                     GLsizei numAttachments,
471701e04c3fSmrg                                     const GLenum *attachments)
471801e04c3fSmrg{
471901e04c3fSmrg   struct gl_framebuffer *fb;
472001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
472101e04c3fSmrg
472201e04c3fSmrg   /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole
472301e04c3fSmrg    * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the
472401e04c3fSmrg    * default draw framebuffer is affected."
472501e04c3fSmrg    */
472601e04c3fSmrg   if (framebuffer) {
472701e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
472801e04c3fSmrg                                        "glInvalidateNamedFramebufferData");
472901e04c3fSmrg      if (!fb)
473001e04c3fSmrg         return;
473101e04c3fSmrg   }
473201e04c3fSmrg   else
473301e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
473401e04c3fSmrg
473501e04c3fSmrg   /* The GL_ARB_invalidate_subdata spec says:
473601e04c3fSmrg    *
473701e04c3fSmrg    *     "The command
473801e04c3fSmrg    *
473901e04c3fSmrg    *        void InvalidateFramebuffer(enum target,
474001e04c3fSmrg    *                                   sizei numAttachments,
474101e04c3fSmrg    *                                   const enum *attachments);
474201e04c3fSmrg    *
474301e04c3fSmrg    *     is equivalent to the command InvalidateSubFramebuffer with <x>, <y>,
474401e04c3fSmrg    *     <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>,
474501e04c3fSmrg    *     <MAX_VIEWPORT_DIMS[1]> respectively."
474601e04c3fSmrg    */
474701e04c3fSmrg   invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
474801e04c3fSmrg                                  0, 0,
474901e04c3fSmrg                                  ctx->Const.MaxViewportWidth,
475001e04c3fSmrg                                  ctx->Const.MaxViewportHeight,
475101e04c3fSmrg                                  "glInvalidateNamedFramebufferData");
475201e04c3fSmrg}
475301e04c3fSmrg
475401e04c3fSmrg
4755af69d88dSmrgvoid GLAPIENTRY
4756af69d88dSmrg_mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments,
4757af69d88dSmrg                            const GLenum *attachments)
4758af69d88dSmrg{
4759af69d88dSmrg   struct gl_framebuffer *fb;
4760af69d88dSmrg   GLint i;
47613464ebd5Sriastradh
4762af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
47637117f1b4Smrg
4764af69d88dSmrg   fb = get_framebuffer_target(ctx, target);
4765af69d88dSmrg   if (!fb) {
4766af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
4767af69d88dSmrg         "glDiscardFramebufferEXT(target %s)",
476801e04c3fSmrg         _mesa_enum_to_string(target));
47694a49301eSmrg      return;
47704a49301eSmrg   }
47714a49301eSmrg
4772af69d88dSmrg   if (numAttachments < 0) {
4773af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
4774af69d88dSmrg                  "glDiscardFramebufferEXT(numAttachments < 0)");
47757117f1b4Smrg      return;
47767117f1b4Smrg   }
47777117f1b4Smrg
4778af69d88dSmrg   for (i = 0; i < numAttachments; i++) {
4779af69d88dSmrg      switch (attachments[i]) {
4780af69d88dSmrg      case GL_COLOR:
4781af69d88dSmrg      case GL_DEPTH:
4782af69d88dSmrg      case GL_STENCIL:
4783af69d88dSmrg         if (_mesa_is_user_fbo(fb))
4784af69d88dSmrg            goto invalid_enum;
4785af69d88dSmrg         break;
4786af69d88dSmrg      case GL_COLOR_ATTACHMENT0:
4787af69d88dSmrg      case GL_DEPTH_ATTACHMENT:
4788af69d88dSmrg      case GL_STENCIL_ATTACHMENT:
4789af69d88dSmrg         if (_mesa_is_winsys_fbo(fb))
4790af69d88dSmrg            goto invalid_enum;
4791af69d88dSmrg         break;
4792af69d88dSmrg      default:
4793af69d88dSmrg         goto invalid_enum;
47944a49301eSmrg      }
47954a49301eSmrg   }
47964a49301eSmrg
4797af69d88dSmrg   if (ctx->Driver.DiscardFramebuffer)
4798af69d88dSmrg      ctx->Driver.DiscardFramebuffer(ctx, target, numAttachments, attachments);
47993464ebd5Sriastradh
4800af69d88dSmrg   return;
48013464ebd5Sriastradh
4802af69d88dSmrginvalid_enum:
4803af69d88dSmrg   _mesa_error(ctx, GL_INVALID_ENUM,
4804af69d88dSmrg               "glDiscardFramebufferEXT(attachment %s)",
480501e04c3fSmrg              _mesa_enum_to_string(attachments[i]));
480601e04c3fSmrg}
480701e04c3fSmrg
480801e04c3fSmrgstatic void
480901e04c3fSmrgsample_locations(struct gl_context *ctx, struct gl_framebuffer *fb,
481001e04c3fSmrg                 GLuint start, GLsizei count, const GLfloat *v, bool no_error,
481101e04c3fSmrg                 const char *name)
481201e04c3fSmrg{
481301e04c3fSmrg   GLsizei i;
481401e04c3fSmrg
481501e04c3fSmrg   if (!no_error) {
481601e04c3fSmrg      if (!ctx->Extensions.ARB_sample_locations) {
481701e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
481801e04c3fSmrg                     "%s not supported "
481901e04c3fSmrg                     "(ARB_sample_locations not available)", name);
482001e04c3fSmrg         return;
482101e04c3fSmrg      }
482201e04c3fSmrg
482301e04c3fSmrg      if (start + count > MAX_SAMPLE_LOCATION_TABLE_SIZE) {
482401e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
482501e04c3fSmrg                     "%s(start+size > sample location table size)", name);
482601e04c3fSmrg         return;
482701e04c3fSmrg      }
482801e04c3fSmrg   }
482901e04c3fSmrg
483001e04c3fSmrg   if (!fb->SampleLocationTable) {
483101e04c3fSmrg      size_t size = MAX_SAMPLE_LOCATION_TABLE_SIZE * 2 * sizeof(GLfloat);
483201e04c3fSmrg      fb->SampleLocationTable = malloc(size);
483301e04c3fSmrg      if (!fb->SampleLocationTable) {
483401e04c3fSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY,
483501e04c3fSmrg                     "Cannot allocate sample location table");
483601e04c3fSmrg         return;
483701e04c3fSmrg      }
483801e04c3fSmrg      for (i = 0; i < MAX_SAMPLE_LOCATION_TABLE_SIZE * 2; i++)
483901e04c3fSmrg         fb->SampleLocationTable[i] = 0.5f;
484001e04c3fSmrg   }
484101e04c3fSmrg
484201e04c3fSmrg   for (i = 0; i < count * 2; i++) {
484301e04c3fSmrg      /* The ARB_sample_locations spec says:
484401e04c3fSmrg       *
484501e04c3fSmrg       *    Sample locations outside of [0,1] result in undefined
484601e04c3fSmrg       *    behavior.
484701e04c3fSmrg       *
484801e04c3fSmrg       * To simplify driver implementations, we choose to clamp to
484901e04c3fSmrg       * [0,1] and change NaN into 0.5.
485001e04c3fSmrg       */
485101e04c3fSmrg      if (isnan(v[i]) || v[i] < 0.0f || v[i] > 1.0f) {
485201e04c3fSmrg         static GLuint msg_id = 0;
485301e04c3fSmrg         static const char* msg = "Invalid sample location specified";
485401e04c3fSmrg         _mesa_debug_get_id(&msg_id);
485501e04c3fSmrg
485601e04c3fSmrg         _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_UNDEFINED,
485701e04c3fSmrg                       msg_id, MESA_DEBUG_SEVERITY_HIGH, strlen(msg), msg);
485801e04c3fSmrg      }
485901e04c3fSmrg
486001e04c3fSmrg      if (isnan(v[i]))
486101e04c3fSmrg         fb->SampleLocationTable[start * 2 + i] = 0.5f;
486201e04c3fSmrg      else
486301e04c3fSmrg         fb->SampleLocationTable[start * 2 + i] = CLAMP(v[i], 0.0f, 1.0f);
486401e04c3fSmrg   }
486501e04c3fSmrg
486601e04c3fSmrg   if (fb == ctx->DrawBuffer)
486701e04c3fSmrg      ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
486801e04c3fSmrg}
486901e04c3fSmrg
487001e04c3fSmrgvoid GLAPIENTRY
487101e04c3fSmrg_mesa_FramebufferSampleLocationsfvARB(GLenum target, GLuint start,
487201e04c3fSmrg                                      GLsizei count, const GLfloat *v)
487301e04c3fSmrg{
487401e04c3fSmrg   struct gl_framebuffer *fb;
487501e04c3fSmrg
487601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
487701e04c3fSmrg
487801e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
487901e04c3fSmrg   if (!fb) {
488001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
488101e04c3fSmrg                  "glFramebufferSampleLocationsfvARB(target %s)",
488201e04c3fSmrg                  _mesa_enum_to_string(target));
488301e04c3fSmrg      return;
488401e04c3fSmrg   }
488501e04c3fSmrg
488601e04c3fSmrg   sample_locations(ctx, fb, start, count, v, false,
488701e04c3fSmrg                    "glFramebufferSampleLocationsfvARB");
488801e04c3fSmrg}
488901e04c3fSmrg
489001e04c3fSmrgvoid GLAPIENTRY
489101e04c3fSmrg_mesa_NamedFramebufferSampleLocationsfvARB(GLuint framebuffer, GLuint start,
489201e04c3fSmrg                                           GLsizei count, const GLfloat *v)
489301e04c3fSmrg{
489401e04c3fSmrg   struct gl_framebuffer *fb;
489501e04c3fSmrg
489601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
489701e04c3fSmrg
489801e04c3fSmrg   if (framebuffer) {
489901e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
490001e04c3fSmrg                                        "glNamedFramebufferSampleLocationsfvARB");
490101e04c3fSmrg      if (!fb)
490201e04c3fSmrg         return;
490301e04c3fSmrg   }
490401e04c3fSmrg   else
490501e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
490601e04c3fSmrg
490701e04c3fSmrg   sample_locations(ctx, fb, start, count, v, false,
490801e04c3fSmrg                    "glNamedFramebufferSampleLocationsfvARB");
490901e04c3fSmrg}
491001e04c3fSmrg
491101e04c3fSmrgvoid GLAPIENTRY
491201e04c3fSmrg_mesa_FramebufferSampleLocationsfvARB_no_error(GLenum target, GLuint start,
491301e04c3fSmrg                                               GLsizei count, const GLfloat *v)
491401e04c3fSmrg{
491501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
491601e04c3fSmrg   sample_locations(ctx, get_framebuffer_target(ctx, target), start,
491701e04c3fSmrg                    count, v, true, "glFramebufferSampleLocationsfvARB");
491801e04c3fSmrg}
491901e04c3fSmrg
492001e04c3fSmrgvoid GLAPIENTRY
492101e04c3fSmrg_mesa_NamedFramebufferSampleLocationsfvARB_no_error(GLuint framebuffer,
492201e04c3fSmrg                                                    GLuint start, GLsizei count,
492301e04c3fSmrg                                                    const GLfloat *v)
492401e04c3fSmrg{
492501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
492601e04c3fSmrg   sample_locations(ctx, _mesa_lookup_framebuffer(ctx, framebuffer), start,
492701e04c3fSmrg                    count, v, true, "glNamedFramebufferSampleLocationsfvARB");
492801e04c3fSmrg}
492901e04c3fSmrg
493001e04c3fSmrgvoid GLAPIENTRY
493101e04c3fSmrg_mesa_EvaluateDepthValuesARB(void)
493201e04c3fSmrg{
493301e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
493401e04c3fSmrg
493501e04c3fSmrg   if (!ctx->Extensions.ARB_sample_locations) {
493601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
493701e04c3fSmrg                  "EvaluateDepthValuesARB not supported (neither "
493801e04c3fSmrg                  "ARB_sample_locations nor NV_sample_locations is available)");
493901e04c3fSmrg      return;
494001e04c3fSmrg   }
494101e04c3fSmrg
494201e04c3fSmrg   if (ctx->Driver.EvaluateDepthValues)
494301e04c3fSmrg      ctx->Driver.EvaluateDepthValues(ctx);
49443464ebd5Sriastradh}
4945