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"
397ec681f3Smrg#include "draw_validate.h"
404a49301eSmrg#include "enums.h"
417117f1b4Smrg#include "fbobject.h"
424a49301eSmrg#include "formats.h"
437117f1b4Smrg#include "framebuffer.h"
44af69d88dSmrg#include "glformats.h"
457117f1b4Smrg#include "hash.h"
464a49301eSmrg#include "macros.h"
47af69d88dSmrg#include "multisample.h"
483464ebd5Sriastradh#include "mtypes.h"
497117f1b4Smrg#include "renderbuffer.h"
507117f1b4Smrg#include "state.h"
517117f1b4Smrg#include "teximage.h"
527117f1b4Smrg#include "texobj.h"
534a49301eSmrg
544a49301eSmrg
557117f1b4Smrg/**
567117f1b4Smrg * Notes:
577117f1b4Smrg *
587117f1b4Smrg * None of the GL_EXT_framebuffer_object functions are compiled into
597117f1b4Smrg * display lists.
607117f1b4Smrg */
617117f1b4Smrg
627117f1b4Smrg
637117f1b4Smrg
64c1f859d4Smrgstatic void
65af69d88dSmrgdelete_dummy_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
66c1f859d4Smrg{
67c1f859d4Smrg   /* no op */
68c1f859d4Smrg}
69c1f859d4Smrg
70c1f859d4Smrgstatic void
71c1f859d4Smrgdelete_dummy_framebuffer(struct gl_framebuffer *fb)
72c1f859d4Smrg{
73c1f859d4Smrg   /* no op */
74c1f859d4Smrg}
75c1f859d4Smrg
76c1f859d4Smrg
777ec681f3Smrg/*
787ec681f3Smrg * When glGenRender/FramebuffersEXT() is called we insert pointers to
797ec681f3Smrg * these placeholder objects into the hash table.
807ec681f3Smrg * Later, when the object ID is first bound, we replace the placeholder
817ec681f3Smrg * with the real frame/renderbuffer.
827ec681f3Smrg */
837ec681f3Smrgstatic struct gl_framebuffer DummyFramebuffer = {
847ec681f3Smrg   .Mutex = _SIMPLE_MTX_INITIALIZER_NP,
857ec681f3Smrg   .Delete = delete_dummy_framebuffer,
867ec681f3Smrg};
877ec681f3Smrgstatic struct gl_renderbuffer DummyRenderbuffer = {
887ec681f3Smrg   .Delete = delete_dummy_renderbuffer,
897ec681f3Smrg};
907ec681f3Smrg
917ec681f3Smrg/* We bind this framebuffer when applications pass a NULL
927ec681f3Smrg * drawable/surface in make current. */
937ec681f3Smrgstatic struct gl_framebuffer IncompleteFramebuffer = {
947ec681f3Smrg   .Mutex = _SIMPLE_MTX_INITIALIZER_NP,
957ec681f3Smrg   .Delete = delete_dummy_framebuffer,
967ec681f3Smrg};
977ec681f3Smrg
98c1f859d4Smrg
993464ebd5Sriastradhstruct gl_framebuffer *
1003464ebd5Sriastradh_mesa_get_incomplete_framebuffer(void)
1013464ebd5Sriastradh{
1023464ebd5Sriastradh   return &IncompleteFramebuffer;
1033464ebd5Sriastradh}
104c1f859d4Smrg
1057117f1b4Smrg/**
1067117f1b4Smrg * Helper routine for getting a gl_renderbuffer.
1077117f1b4Smrg */
1087117f1b4Smrgstruct gl_renderbuffer *
1093464ebd5Sriastradh_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
1107117f1b4Smrg{
1117117f1b4Smrg   struct gl_renderbuffer *rb;
1127117f1b4Smrg
1137117f1b4Smrg   if (id == 0)
1147117f1b4Smrg      return NULL;
1157117f1b4Smrg
1167117f1b4Smrg   rb = (struct gl_renderbuffer *)
1177117f1b4Smrg      _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
1187117f1b4Smrg   return rb;
1197117f1b4Smrg}
1207117f1b4Smrg
1217117f1b4Smrg
12201e04c3fSmrg/**
12301e04c3fSmrg * A convenience function for direct state access that throws
12401e04c3fSmrg * GL_INVALID_OPERATION if the renderbuffer doesn't exist.
12501e04c3fSmrg */
12601e04c3fSmrgstruct gl_renderbuffer *
12701e04c3fSmrg_mesa_lookup_renderbuffer_err(struct gl_context *ctx, GLuint id,
12801e04c3fSmrg                              const char *func)
12901e04c3fSmrg{
13001e04c3fSmrg   struct gl_renderbuffer *rb;
13101e04c3fSmrg
13201e04c3fSmrg   rb = _mesa_lookup_renderbuffer(ctx, id);
13301e04c3fSmrg   if (!rb || rb == &DummyRenderbuffer) {
13401e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
13501e04c3fSmrg                  "%s(non-existent renderbuffer %u)", func, id);
13601e04c3fSmrg      return NULL;
13701e04c3fSmrg   }
13801e04c3fSmrg
13901e04c3fSmrg   return rb;
14001e04c3fSmrg}
14101e04c3fSmrg
14201e04c3fSmrg
1437117f1b4Smrg/**
1447117f1b4Smrg * Helper routine for getting a gl_framebuffer.
1457117f1b4Smrg */
1467117f1b4Smrgstruct gl_framebuffer *
1473464ebd5Sriastradh_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
1487117f1b4Smrg{
1497117f1b4Smrg   struct gl_framebuffer *fb;
1507117f1b4Smrg
1517117f1b4Smrg   if (id == 0)
1527117f1b4Smrg      return NULL;
1537117f1b4Smrg
1547117f1b4Smrg   fb = (struct gl_framebuffer *)
1557117f1b4Smrg      _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
1567ec681f3Smrg
1577ec681f3Smrg   return fb;
1587ec681f3Smrg}
1597ec681f3Smrg
1607ec681f3Smrg
1617ec681f3Smrgstruct gl_framebuffer *
1627ec681f3Smrg_mesa_lookup_framebuffer_dsa(struct gl_context *ctx, GLuint id,
1637ec681f3Smrg                             const char* func)
1647ec681f3Smrg{
1657ec681f3Smrg   struct gl_framebuffer *fb;
1667ec681f3Smrg
1677ec681f3Smrg   if (id == 0)
1687ec681f3Smrg      return NULL;
1697ec681f3Smrg
1707ec681f3Smrg   fb = _mesa_lookup_framebuffer(ctx, id);
1717ec681f3Smrg
1727ec681f3Smrg   /* Name exists but buffer is not initialized */
1737ec681f3Smrg   if (fb == &DummyFramebuffer) {
1747ec681f3Smrg      fb = ctx->Driver.NewFramebuffer(ctx, id);
1757ec681f3Smrg      _mesa_HashInsert(ctx->Shared->FrameBuffers, id, fb, true);
1767ec681f3Smrg   }
1777ec681f3Smrg   /* Name doesn't exist */
1787ec681f3Smrg   else if (!fb) {
1797ec681f3Smrg      fb = ctx->Driver.NewFramebuffer(ctx, id);
1807ec681f3Smrg      if (!fb) {
1817ec681f3Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1827ec681f3Smrg         return NULL;
1837ec681f3Smrg      }
1847ec681f3Smrg      _mesa_HashInsert(ctx->Shared->FrameBuffers, id, fb, false);
1857ec681f3Smrg   }
1867117f1b4Smrg   return fb;
1877117f1b4Smrg}
1887117f1b4Smrg
1897117f1b4Smrg
19001e04c3fSmrg/**
19101e04c3fSmrg * A convenience function for direct state access that throws
19201e04c3fSmrg * GL_INVALID_OPERATION if the framebuffer doesn't exist.
19301e04c3fSmrg */
19401e04c3fSmrgstruct gl_framebuffer *
19501e04c3fSmrg_mesa_lookup_framebuffer_err(struct gl_context *ctx, GLuint id,
19601e04c3fSmrg                             const char *func)
19701e04c3fSmrg{
19801e04c3fSmrg   struct gl_framebuffer *fb;
19901e04c3fSmrg
20001e04c3fSmrg   fb = _mesa_lookup_framebuffer(ctx, id);
20101e04c3fSmrg   if (!fb || fb == &DummyFramebuffer) {
20201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
20301e04c3fSmrg                  "%s(non-existent framebuffer %u)", func, id);
20401e04c3fSmrg      return NULL;
20501e04c3fSmrg   }
20601e04c3fSmrg
20701e04c3fSmrg   return fb;
20801e04c3fSmrg}
20901e04c3fSmrg
21001e04c3fSmrg
2114a49301eSmrg/**
2124a49301eSmrg * Mark the given framebuffer as invalid.  This will force the
2134a49301eSmrg * test for framebuffer completeness to be done before the framebuffer
2144a49301eSmrg * is used.
2154a49301eSmrg */
2164a49301eSmrgstatic void
2174a49301eSmrginvalidate_framebuffer(struct gl_framebuffer *fb)
2184a49301eSmrg{
2194a49301eSmrg   fb->_Status = 0; /* "indeterminate" */
2204a49301eSmrg}
2214a49301eSmrg
2224a49301eSmrg
2233464ebd5Sriastradh/**
2243464ebd5Sriastradh * Return the gl_framebuffer object which corresponds to the given
2253464ebd5Sriastradh * framebuffer target, such as GL_DRAW_FRAMEBUFFER.
2263464ebd5Sriastradh * Check support for GL_EXT_framebuffer_blit to determine if certain
2273464ebd5Sriastradh * targets are legal.
2283464ebd5Sriastradh * \return gl_framebuffer pointer or NULL if target is illegal
2293464ebd5Sriastradh */
2303464ebd5Sriastradhstatic struct gl_framebuffer *
2313464ebd5Sriastradhget_framebuffer_target(struct gl_context *ctx, GLenum target)
2323464ebd5Sriastradh{
233af69d88dSmrg   bool have_fb_blit = _mesa_is_gles3(ctx) || _mesa_is_desktop_gl(ctx);
2343464ebd5Sriastradh   switch (target) {
2353464ebd5Sriastradh   case GL_DRAW_FRAMEBUFFER:
236af69d88dSmrg      return have_fb_blit ? ctx->DrawBuffer : NULL;
2373464ebd5Sriastradh   case GL_READ_FRAMEBUFFER:
238af69d88dSmrg      return have_fb_blit ? ctx->ReadBuffer : NULL;
2393464ebd5Sriastradh   case GL_FRAMEBUFFER_EXT:
2403464ebd5Sriastradh      return ctx->DrawBuffer;
2413464ebd5Sriastradh   default:
2423464ebd5Sriastradh      return NULL;
2433464ebd5Sriastradh   }
2443464ebd5Sriastradh}
2453464ebd5Sriastradh
2463464ebd5Sriastradh
2477117f1b4Smrg/**
2487117f1b4Smrg * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
2497117f1b4Smrg * gl_renderbuffer_attachment object.
2503464ebd5Sriastradh * This function is only used for user-created FB objects, not the
2513464ebd5Sriastradh * default / window-system FB object.
2524a49301eSmrg * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
2534a49301eSmrg * the depth buffer attachment point.
25401e04c3fSmrg * Returns if the attachment is a GL_COLOR_ATTACHMENTm_EXT on
25501e04c3fSmrg * is_color_attachment, because several callers would return different errors
25601e04c3fSmrg * if they don't find the attachment.
2577117f1b4Smrg */
258af69d88dSmrgstatic struct gl_renderbuffer_attachment *
259af69d88dSmrgget_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
26001e04c3fSmrg               GLenum attachment, bool *is_color_attachment)
2617117f1b4Smrg{
2627117f1b4Smrg   GLuint i;
2637117f1b4Smrg
264af69d88dSmrg   assert(_mesa_is_user_fbo(fb));
2653464ebd5Sriastradh
26601e04c3fSmrg   if (is_color_attachment)
26701e04c3fSmrg      *is_color_attachment = false;
26801e04c3fSmrg
2697117f1b4Smrg   switch (attachment) {
2707117f1b4Smrg   case GL_COLOR_ATTACHMENT0_EXT:
2717117f1b4Smrg   case GL_COLOR_ATTACHMENT1_EXT:
2727117f1b4Smrg   case GL_COLOR_ATTACHMENT2_EXT:
2737117f1b4Smrg   case GL_COLOR_ATTACHMENT3_EXT:
2747117f1b4Smrg   case GL_COLOR_ATTACHMENT4_EXT:
2757117f1b4Smrg   case GL_COLOR_ATTACHMENT5_EXT:
2767117f1b4Smrg   case GL_COLOR_ATTACHMENT6_EXT:
2777117f1b4Smrg   case GL_COLOR_ATTACHMENT7_EXT:
2787117f1b4Smrg   case GL_COLOR_ATTACHMENT8_EXT:
2797117f1b4Smrg   case GL_COLOR_ATTACHMENT9_EXT:
2807117f1b4Smrg   case GL_COLOR_ATTACHMENT10_EXT:
2817117f1b4Smrg   case GL_COLOR_ATTACHMENT11_EXT:
2827117f1b4Smrg   case GL_COLOR_ATTACHMENT12_EXT:
2837117f1b4Smrg   case GL_COLOR_ATTACHMENT13_EXT:
2847117f1b4Smrg   case GL_COLOR_ATTACHMENT14_EXT:
2857117f1b4Smrg   case GL_COLOR_ATTACHMENT15_EXT:
28601e04c3fSmrg      if (is_color_attachment)
28701e04c3fSmrg         *is_color_attachment = true;
288af69d88dSmrg      /* Only OpenGL ES 1.x forbids color attachments other than
289af69d88dSmrg       * GL_COLOR_ATTACHMENT0.  For all other APIs the limit set by the
290af69d88dSmrg       * hardware is used.
291af69d88dSmrg       */
2927117f1b4Smrg      i = attachment - GL_COLOR_ATTACHMENT0_EXT;
293af69d88dSmrg      if (i >= ctx->Const.MaxColorAttachments
29401e04c3fSmrg          || (i > 0 && ctx->API == API_OPENGLES)) {
29501e04c3fSmrg         return NULL;
2967117f1b4Smrg      }
2977ec681f3Smrg      assert(BUFFER_COLOR0 + i < ARRAY_SIZE(fb->Attachment));
2987117f1b4Smrg      return &fb->Attachment[BUFFER_COLOR0 + i];
2994a49301eSmrg   case GL_DEPTH_STENCIL_ATTACHMENT:
300af69d88dSmrg      if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
30101e04c3fSmrg         return NULL;
3027ec681f3Smrg      FALLTHROUGH;
3037117f1b4Smrg   case GL_DEPTH_ATTACHMENT_EXT:
3047117f1b4Smrg      return &fb->Attachment[BUFFER_DEPTH];
3057117f1b4Smrg   case GL_STENCIL_ATTACHMENT_EXT:
3067117f1b4Smrg      return &fb->Attachment[BUFFER_STENCIL];
3077117f1b4Smrg   default:
3087117f1b4Smrg      return NULL;
3097117f1b4Smrg   }
3107117f1b4Smrg}
3117117f1b4Smrg
3127117f1b4Smrg
3133464ebd5Sriastradh/**
3143464ebd5Sriastradh * As above, but only used for getting attachments of the default /
3153464ebd5Sriastradh * window-system framebuffer (not user-created framebuffer objects).
3163464ebd5Sriastradh */
3173464ebd5Sriastradhstatic struct gl_renderbuffer_attachment *
31801e04c3fSmrgget_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
31901e04c3fSmrg                   GLenum attachment)
3203464ebd5Sriastradh{
321af69d88dSmrg   assert(_mesa_is_winsys_fbo(fb));
322af69d88dSmrg
3237ec681f3Smrg   attachment = _mesa_back_to_front_if_single_buffered(fb, attachment);
3247ec681f3Smrg
325af69d88dSmrg   if (_mesa_is_gles3(ctx)) {
326af69d88dSmrg      switch (attachment) {
327af69d88dSmrg      case GL_BACK:
328af69d88dSmrg         /* Since there is no stereo rendering in ES 3.0, only return the
329af69d88dSmrg          * LEFT bits.
330af69d88dSmrg          */
3317ec681f3Smrg         return &fb->Attachment[BUFFER_BACK_LEFT];
3327ec681f3Smrg      case GL_FRONT:
3337ec681f3Smrg         /* We might get this if back_to_front triggers above */
334af69d88dSmrg         return &fb->Attachment[BUFFER_FRONT_LEFT];
335af69d88dSmrg      case GL_DEPTH:
33601e04c3fSmrg         return &fb->Attachment[BUFFER_DEPTH];
337af69d88dSmrg      case GL_STENCIL:
338af69d88dSmrg         return &fb->Attachment[BUFFER_STENCIL];
3397ec681f3Smrg      default:
3407ec681f3Smrg         unreachable("invalid attachment");
341af69d88dSmrg      }
342af69d88dSmrg   }
3433464ebd5Sriastradh
3443464ebd5Sriastradh   switch (attachment) {
3457ec681f3Smrg   case GL_FRONT:
3463464ebd5Sriastradh   case GL_FRONT_LEFT:
34701e04c3fSmrg      /* Front buffers can be allocated on the first use, but
34801e04c3fSmrg       * glGetFramebufferAttachmentParameteriv must work even if that
34901e04c3fSmrg       * allocation hasn't happened yet. In such case, use the back buffer,
35001e04c3fSmrg       * which should be the same.
35101e04c3fSmrg       */
35201e04c3fSmrg      if (fb->Attachment[BUFFER_FRONT_LEFT].Type == GL_NONE)
35301e04c3fSmrg         return &fb->Attachment[BUFFER_BACK_LEFT];
35401e04c3fSmrg      else
35501e04c3fSmrg         return &fb->Attachment[BUFFER_FRONT_LEFT];
3563464ebd5Sriastradh   case GL_FRONT_RIGHT:
35701e04c3fSmrg      /* Same as above. */
35801e04c3fSmrg      if (fb->Attachment[BUFFER_FRONT_RIGHT].Type == GL_NONE)
35901e04c3fSmrg         return &fb->Attachment[BUFFER_BACK_RIGHT];
36001e04c3fSmrg      else
36101e04c3fSmrg         return &fb->Attachment[BUFFER_FRONT_RIGHT];
3623464ebd5Sriastradh   case GL_BACK_LEFT:
3633464ebd5Sriastradh      return &fb->Attachment[BUFFER_BACK_LEFT];
3643464ebd5Sriastradh   case GL_BACK_RIGHT:
3653464ebd5Sriastradh      return &fb->Attachment[BUFFER_BACK_RIGHT];
36601e04c3fSmrg   case GL_BACK:
36701e04c3fSmrg      /* The ARB_ES3_1_compatibility spec says:
36801e04c3fSmrg       *
36901e04c3fSmrg       *    "Since this command can only query a single framebuffer
37001e04c3fSmrg       *     attachment, BACK is equivalent to BACK_LEFT."
37101e04c3fSmrg       */
37201e04c3fSmrg      if (ctx->Extensions.ARB_ES3_1_compatibility)
37301e04c3fSmrg         return &fb->Attachment[BUFFER_BACK_LEFT];
37401e04c3fSmrg      return NULL;
3753464ebd5Sriastradh   case GL_AUX0:
3763464ebd5Sriastradh      return NULL;
377af69d88dSmrg
378af69d88dSmrg   /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says:
379af69d88dSmrg    *
380af69d88dSmrg    *     "If the default framebuffer is bound to target, then attachment must
381af69d88dSmrg    *     be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi,
382af69d88dSmrg    *     identifying a color buffer; DEPTH, identifying the depth buffer; or
383af69d88dSmrg    *     STENCIL, identifying the stencil buffer."
384af69d88dSmrg    *
385af69d88dSmrg    * Revision #34 of the ARB_framebuffer_object spec has essentially the same
386af69d88dSmrg    * language.  However, revision #33 of the ARB_framebuffer_object spec
387af69d88dSmrg    * says:
388af69d88dSmrg    *
389af69d88dSmrg    *     "If the default framebuffer is bound to <target>, then <attachment>
390af69d88dSmrg    *     must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi,
391af69d88dSmrg    *     DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the
392af69d88dSmrg    *     depth buffer, or the stencil buffer, and <pname> may be
393af69d88dSmrg    *     FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or
394af69d88dSmrg    *     FRAMEBUFFER_ATTACHMENT_OBJECT_NAME."
395af69d88dSmrg    *
396af69d88dSmrg    * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed
397af69d88dSmrg    * from glext.h, so shipping apps should not use those values.
398af69d88dSmrg    *
399af69d88dSmrg    * Note that neither EXT_framebuffer_object nor OES_framebuffer_object
400af69d88dSmrg    * support queries of the window system FBO.
401af69d88dSmrg    */
402af69d88dSmrg   case GL_DEPTH:
4033464ebd5Sriastradh      return &fb->Attachment[BUFFER_DEPTH];
404af69d88dSmrg   case GL_STENCIL:
4053464ebd5Sriastradh      return &fb->Attachment[BUFFER_STENCIL];
4063464ebd5Sriastradh   default:
4073464ebd5Sriastradh      return NULL;
4083464ebd5Sriastradh   }
4093464ebd5Sriastradh}
4103464ebd5Sriastradh
4113464ebd5Sriastradh
4123464ebd5Sriastradh
4137117f1b4Smrg/**
4147117f1b4Smrg * Remove any texture or renderbuffer attached to the given attachment
4157117f1b4Smrg * point.  Update reference counts, etc.
4167117f1b4Smrg */
417af69d88dSmrgstatic void
418af69d88dSmrgremove_attachment(struct gl_context *ctx,
419af69d88dSmrg                  struct gl_renderbuffer_attachment *att)
4207117f1b4Smrg{
421af69d88dSmrg   struct gl_renderbuffer *rb = att->Renderbuffer;
422af69d88dSmrg
423af69d88dSmrg   /* tell driver that we're done rendering to this texture. */
424af69d88dSmrg   if (rb && rb->NeedsFinishRenderTexture)
425af69d88dSmrg      ctx->Driver.FinishRenderTexture(ctx, rb);
426af69d88dSmrg
4277117f1b4Smrg   if (att->Type == GL_TEXTURE) {
42801e04c3fSmrg      assert(att->Texture);
4297117f1b4Smrg      _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
43001e04c3fSmrg      assert(!att->Texture);
4317117f1b4Smrg   }
4327117f1b4Smrg   if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
43301e04c3fSmrg      assert(!att->Texture);
4347117f1b4Smrg      _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
43501e04c3fSmrg      assert(!att->Renderbuffer);
4367117f1b4Smrg   }
4377117f1b4Smrg   att->Type = GL_NONE;
4387117f1b4Smrg   att->Complete = GL_TRUE;
4397117f1b4Smrg}
4407117f1b4Smrg
441af69d88dSmrg/**
442af69d88dSmrg * Verify a couple error conditions that will lead to an incomplete FBO and
443af69d88dSmrg * may cause problems for the driver's RenderTexture path.
444af69d88dSmrg */
445af69d88dSmrgstatic bool
446af69d88dSmrgdriver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att)
447af69d88dSmrg{
448af69d88dSmrg   const struct gl_texture_image *const texImage =
449af69d88dSmrg      att->Texture->Image[att->CubeMapFace][att->TextureLevel];
450af69d88dSmrg
45101e04c3fSmrg   if (!texImage ||
45201e04c3fSmrg       texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0)
453af69d88dSmrg      return false;
454af69d88dSmrg
455af69d88dSmrg   if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY
456af69d88dSmrg        && att->Zoffset >= texImage->Height)
457af69d88dSmrg       || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY
458af69d88dSmrg           && att->Zoffset >= texImage->Depth))
459af69d88dSmrg      return false;
460af69d88dSmrg
461af69d88dSmrg   return true;
462af69d88dSmrg}
463af69d88dSmrg
464af69d88dSmrg/**
465af69d88dSmrg * Create a renderbuffer which will be set up by the driver to wrap the
466af69d88dSmrg * texture image slice.
467af69d88dSmrg *
468af69d88dSmrg * By using a gl_renderbuffer (like user-allocated renderbuffers), drivers get
469af69d88dSmrg * to share most of their framebuffer rendering code between winsys,
470af69d88dSmrg * renderbuffer, and texture attachments.
471af69d88dSmrg *
472af69d88dSmrg * The allocated renderbuffer uses a non-zero Name so that drivers can check
473af69d88dSmrg * it for determining vertical orientation, but we use ~0 to make it fairly
474af69d88dSmrg * unambiguous with actual user (non-texture) renderbuffers.
475af69d88dSmrg */
476af69d88dSmrgvoid
477af69d88dSmrg_mesa_update_texture_renderbuffer(struct gl_context *ctx,
478af69d88dSmrg                                  struct gl_framebuffer *fb,
479af69d88dSmrg                                  struct gl_renderbuffer_attachment *att)
480af69d88dSmrg{
481af69d88dSmrg   struct gl_texture_image *texImage;
482af69d88dSmrg   struct gl_renderbuffer *rb;
483af69d88dSmrg
484af69d88dSmrg   texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
485af69d88dSmrg
486af69d88dSmrg   rb = att->Renderbuffer;
487af69d88dSmrg   if (!rb) {
488af69d88dSmrg      rb = ctx->Driver.NewRenderbuffer(ctx, ~0);
489af69d88dSmrg      if (!rb) {
490af69d88dSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()");
491af69d88dSmrg         return;
492af69d88dSmrg      }
49301e04c3fSmrg      att->Renderbuffer = rb;
494af69d88dSmrg
495af69d88dSmrg      /* This can't get called on a texture renderbuffer, so set it to NULL
496af69d88dSmrg       * for clarity compared to user renderbuffers.
497af69d88dSmrg       */
498af69d88dSmrg      rb->AllocStorage = NULL;
499af69d88dSmrg
500af69d88dSmrg      rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL;
501af69d88dSmrg   }
502af69d88dSmrg
503af69d88dSmrg   if (!texImage)
504af69d88dSmrg      return;
505af69d88dSmrg
506af69d88dSmrg   rb->_BaseFormat = texImage->_BaseFormat;
507af69d88dSmrg   rb->Format = texImage->TexFormat;
508af69d88dSmrg   rb->InternalFormat = texImage->InternalFormat;
509af69d88dSmrg   rb->Width = texImage->Width2;
510af69d88dSmrg   rb->Height = texImage->Height2;
511af69d88dSmrg   rb->Depth = texImage->Depth2;
512af69d88dSmrg   rb->NumSamples = texImage->NumSamples;
51301e04c3fSmrg   rb->NumStorageSamples = texImage->NumSamples;
514af69d88dSmrg   rb->TexImage = texImage;
515af69d88dSmrg
516af69d88dSmrg   if (driver_RenderTexture_is_safe(att))
517af69d88dSmrg      ctx->Driver.RenderTexture(ctx, fb, att);
518af69d88dSmrg}
5197117f1b4Smrg
5207117f1b4Smrg/**
5217117f1b4Smrg * Bind a texture object to an attachment point.
5227117f1b4Smrg * The previous binding, if any, will be removed first.
5237117f1b4Smrg */
524af69d88dSmrgstatic void
525af69d88dSmrgset_texture_attachment(struct gl_context *ctx,
526af69d88dSmrg                       struct gl_framebuffer *fb,
527af69d88dSmrg                       struct gl_renderbuffer_attachment *att,
528af69d88dSmrg                       struct gl_texture_object *texObj,
529a8bb7a65Smaya                       GLenum texTarget, GLuint level, GLsizei samples,
530a8bb7a65Smaya                       GLuint layer, GLboolean layered)
5317117f1b4Smrg{
532af69d88dSmrg   struct gl_renderbuffer *rb = att->Renderbuffer;
533af69d88dSmrg
534af69d88dSmrg   if (rb && rb->NeedsFinishRenderTexture)
535af69d88dSmrg      ctx->Driver.FinishRenderTexture(ctx, rb);
536af69d88dSmrg
5377117f1b4Smrg   if (att->Texture == texObj) {
5387117f1b4Smrg      /* re-attaching same texture */
53901e04c3fSmrg      assert(att->Type == GL_TEXTURE);
5407117f1b4Smrg   }
5417117f1b4Smrg   else {
5427117f1b4Smrg      /* new attachment */
543af69d88dSmrg      remove_attachment(ctx, att);
5447117f1b4Smrg      att->Type = GL_TEXTURE;
5457117f1b4Smrg      assert(!att->Texture);
5467117f1b4Smrg      _mesa_reference_texobj(&att->Texture, texObj);
5477117f1b4Smrg   }
548af69d88dSmrg   invalidate_framebuffer(fb);
5497117f1b4Smrg
5507117f1b4Smrg   /* always update these fields */
5517117f1b4Smrg   att->TextureLevel = level;
552a8bb7a65Smaya   att->NumSamples = samples;
5534a49301eSmrg   att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
55401e04c3fSmrg   att->Zoffset = layer;
555af69d88dSmrg   att->Layered = layered;
5567117f1b4Smrg   att->Complete = GL_FALSE;
5577117f1b4Smrg
558af69d88dSmrg   _mesa_update_texture_renderbuffer(ctx, fb, att);
5597117f1b4Smrg}
5607117f1b4Smrg
5617117f1b4Smrg
5627117f1b4Smrg/**
5637117f1b4Smrg * Bind a renderbuffer to an attachment point.
5647117f1b4Smrg * The previous binding, if any, will be removed first.
5657117f1b4Smrg */
566af69d88dSmrgstatic void
567af69d88dSmrgset_renderbuffer_attachment(struct gl_context *ctx,
568af69d88dSmrg                            struct gl_renderbuffer_attachment *att,
569af69d88dSmrg                            struct gl_renderbuffer *rb)
5707117f1b4Smrg{
5717117f1b4Smrg   /* XXX check if re-doing same attachment, exit early */
572af69d88dSmrg   remove_attachment(ctx, att);
5737117f1b4Smrg   att->Type = GL_RENDERBUFFER_EXT;
5747117f1b4Smrg   att->Texture = NULL; /* just to be safe */
57501e04c3fSmrg   att->Layered = GL_FALSE;
5767117f1b4Smrg   att->Complete = GL_FALSE;
5777117f1b4Smrg   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
5787117f1b4Smrg}
5797117f1b4Smrg
5807117f1b4Smrg
5817117f1b4Smrg/**
5827117f1b4Smrg * Fallback for ctx->Driver.FramebufferRenderbuffer()
5837117f1b4Smrg * Attach a renderbuffer object to a framebuffer object.
5847117f1b4Smrg */
5857117f1b4Smrgvoid
58601e04c3fSmrg_mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx,
58701e04c3fSmrg                                 struct gl_framebuffer *fb,
58801e04c3fSmrg                                 GLenum attachment,
58901e04c3fSmrg                                 struct gl_renderbuffer *rb)
5907117f1b4Smrg{
5917117f1b4Smrg   struct gl_renderbuffer_attachment *att;
5927117f1b4Smrg
59301e04c3fSmrg   simple_mtx_lock(&fb->Mutex);
5947117f1b4Smrg
59501e04c3fSmrg   att = get_attachment(ctx, fb, attachment, NULL);
59601e04c3fSmrg   assert(att);
5977117f1b4Smrg   if (rb) {
598af69d88dSmrg      set_renderbuffer_attachment(ctx, att, rb);
5994a49301eSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
6004a49301eSmrg         /* do stencil attachment here (depth already done above) */
60101e04c3fSmrg         att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL);
6024a49301eSmrg         assert(att);
603af69d88dSmrg         set_renderbuffer_attachment(ctx, att, rb);
6044a49301eSmrg      }
6053464ebd5Sriastradh      rb->AttachedAnytime = GL_TRUE;
6067117f1b4Smrg   }
6077117f1b4Smrg   else {
608af69d88dSmrg      remove_attachment(ctx, att);
609af69d88dSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
610af69d88dSmrg         /* detach stencil (depth was detached above) */
61101e04c3fSmrg         att = get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT, NULL);
612af69d88dSmrg         assert(att);
613af69d88dSmrg         remove_attachment(ctx, att);
614af69d88dSmrg      }
6157117f1b4Smrg   }
6167117f1b4Smrg
6174a49301eSmrg   invalidate_framebuffer(fb);
6184a49301eSmrg
61901e04c3fSmrg   simple_mtx_unlock(&fb->Mutex);
6207117f1b4Smrg}
6217117f1b4Smrg
6227117f1b4Smrg
6233464ebd5Sriastradh/**
6243464ebd5Sriastradh * Fallback for ctx->Driver.ValidateFramebuffer()
6253464ebd5Sriastradh * Check if the renderbuffer's formats are supported by the software
6263464ebd5Sriastradh * renderer.
6273464ebd5Sriastradh * Drivers should probably override this.
6283464ebd5Sriastradh */
6293464ebd5Sriastradhvoid
6303464ebd5Sriastradh_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
6313464ebd5Sriastradh{
6323464ebd5Sriastradh   gl_buffer_index buf;
6333464ebd5Sriastradh   for (buf = 0; buf < BUFFER_COUNT; buf++) {
6343464ebd5Sriastradh      const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer;
6353464ebd5Sriastradh      if (rb) {
6363464ebd5Sriastradh         switch (rb->_BaseFormat) {
6373464ebd5Sriastradh         case GL_ALPHA:
6383464ebd5Sriastradh         case GL_LUMINANCE_ALPHA:
6393464ebd5Sriastradh         case GL_LUMINANCE:
6403464ebd5Sriastradh         case GL_INTENSITY:
6413464ebd5Sriastradh         case GL_RED:
6423464ebd5Sriastradh         case GL_RG:
6433464ebd5Sriastradh            fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
6443464ebd5Sriastradh            return;
6453464ebd5Sriastradh
6463464ebd5Sriastradh         default:
6473464ebd5Sriastradh            switch (rb->Format) {
6483464ebd5Sriastradh            /* XXX This list is likely incomplete. */
649af69d88dSmrg            case MESA_FORMAT_R9G9B9E5_FLOAT:
6503464ebd5Sriastradh               fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
6513464ebd5Sriastradh               return;
6523464ebd5Sriastradh            default:;
6533464ebd5Sriastradh               /* render buffer format is supported by software rendering */
6543464ebd5Sriastradh            }
6553464ebd5Sriastradh         }
6563464ebd5Sriastradh      }
6573464ebd5Sriastradh   }
6583464ebd5Sriastradh}
6593464ebd5Sriastradh
6603464ebd5Sriastradh
661af69d88dSmrg/**
662af69d88dSmrg * Return true if the framebuffer has a combined depth/stencil
663af69d88dSmrg * renderbuffer attached.
664af69d88dSmrg */
665af69d88dSmrgGLboolean
666af69d88dSmrg_mesa_has_depthstencil_combined(const struct gl_framebuffer *fb)
667af69d88dSmrg{
668af69d88dSmrg   const struct gl_renderbuffer_attachment *depth =
669af69d88dSmrg         &fb->Attachment[BUFFER_DEPTH];
670af69d88dSmrg   const struct gl_renderbuffer_attachment *stencil =
671af69d88dSmrg         &fb->Attachment[BUFFER_STENCIL];
672af69d88dSmrg
673af69d88dSmrg   if (depth->Type == stencil->Type) {
674af69d88dSmrg      if (depth->Type == GL_RENDERBUFFER_EXT &&
675af69d88dSmrg          depth->Renderbuffer == stencil->Renderbuffer)
676af69d88dSmrg         return GL_TRUE;
677af69d88dSmrg
678af69d88dSmrg      if (depth->Type == GL_TEXTURE &&
679af69d88dSmrg          depth->Texture == stencil->Texture)
680af69d88dSmrg         return GL_TRUE;
681af69d88dSmrg   }
682af69d88dSmrg
683af69d88dSmrg   return GL_FALSE;
684af69d88dSmrg}
685af69d88dSmrg
686af69d88dSmrg
6874a49301eSmrg/**
6884a49301eSmrg * For debug only.
6894a49301eSmrg */
6904a49301eSmrgstatic void
6914a49301eSmrgatt_incomplete(const char *msg)
6924a49301eSmrg{
693af69d88dSmrg   if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
694af69d88dSmrg      _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
695af69d88dSmrg   }
6964a49301eSmrg}
6974a49301eSmrg
6984a49301eSmrg
6994a49301eSmrg/**
7004a49301eSmrg * For debug only.
7014a49301eSmrg */
7024a49301eSmrgstatic void
703af69d88dSmrgfbo_incomplete(struct gl_context *ctx, const char *msg, int index)
7044a49301eSmrg{
705af69d88dSmrg   static GLuint msg_id;
706af69d88dSmrg
707a8bb7a65Smaya   _mesa_gl_debugf(ctx, &msg_id,
708a8bb7a65Smaya                   MESA_DEBUG_SOURCE_API,
709a8bb7a65Smaya                   MESA_DEBUG_TYPE_OTHER,
710a8bb7a65Smaya                   MESA_DEBUG_SEVERITY_MEDIUM,
711a8bb7a65Smaya                   "FBO incomplete: %s [%d]\n", msg, index);
712af69d88dSmrg
713af69d88dSmrg   if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
714af69d88dSmrg      _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
715af69d88dSmrg   }
7167ec681f3Smrg
7177ec681f3Smrg   _mesa_update_valid_to_render_state(ctx);
7184a49301eSmrg}
7194a49301eSmrg
7204a49301eSmrg
7213464ebd5Sriastradh/**
7223464ebd5Sriastradh * Is the given base format a legal format for a color renderbuffer?
7233464ebd5Sriastradh */
7243464ebd5SriastradhGLboolean
7253464ebd5Sriastradh_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
7263464ebd5Sriastradh{
7273464ebd5Sriastradh   switch (baseFormat) {
7283464ebd5Sriastradh   case GL_RGB:
7293464ebd5Sriastradh   case GL_RGBA:
7303464ebd5Sriastradh      return GL_TRUE;
7313464ebd5Sriastradh   case GL_LUMINANCE:
7323464ebd5Sriastradh   case GL_LUMINANCE_ALPHA:
7333464ebd5Sriastradh   case GL_INTENSITY:
7343464ebd5Sriastradh   case GL_ALPHA:
735af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
736af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object;
7373464ebd5Sriastradh   case GL_RED:
7383464ebd5Sriastradh   case GL_RG:
7393464ebd5Sriastradh      return ctx->Extensions.ARB_texture_rg;
7403464ebd5Sriastradh   default:
7413464ebd5Sriastradh      return GL_FALSE;
7423464ebd5Sriastradh   }
7433464ebd5Sriastradh}
7443464ebd5Sriastradh
7457ec681f3Smrgstatic GLboolean
7467ec681f3Smrgis_float_format(GLenum internalFormat)
7477ec681f3Smrg{
7487ec681f3Smrg   switch (internalFormat) {
7497ec681f3Smrg   case GL_R16F:
7507ec681f3Smrg   case GL_RG16F:
7517ec681f3Smrg   case GL_RGB16F:
7527ec681f3Smrg   case GL_RGBA16F:
7537ec681f3Smrg   case GL_R32F:
7547ec681f3Smrg   case GL_RG32F:
7557ec681f3Smrg   case GL_RGB32F:
7567ec681f3Smrg   case GL_RGBA32F:
7577ec681f3Smrg      return true;
7587ec681f3Smrg   default:
7597ec681f3Smrg      return false;
7607ec681f3Smrg   }
7617ec681f3Smrg}
7623464ebd5Sriastradh
763af69d88dSmrg/**
764af69d88dSmrg * Is the given base format a legal format for a color renderbuffer?
765af69d88dSmrg */
766af69d88dSmrgstatic GLboolean
767af69d88dSmrgis_format_color_renderable(const struct gl_context *ctx, mesa_format format,
768af69d88dSmrg                           GLenum internalFormat)
769af69d88dSmrg{
770af69d88dSmrg   const GLenum baseFormat =
771af69d88dSmrg      _mesa_get_format_base_format(format);
772af69d88dSmrg   GLboolean valid;
773af69d88dSmrg
774af69d88dSmrg   valid = _mesa_is_legal_color_format(ctx, baseFormat);
775af69d88dSmrg   if (!valid || _mesa_is_desktop_gl(ctx)) {
776af69d88dSmrg      return valid;
777af69d88dSmrg   }
778af69d88dSmrg
779af69d88dSmrg   /* Reject additional cases for GLES */
780af69d88dSmrg   switch (internalFormat) {
78101e04c3fSmrg   case GL_R8_SNORM:
78201e04c3fSmrg   case GL_RG8_SNORM:
783af69d88dSmrg   case GL_RGBA8_SNORM:
78401e04c3fSmrg      return _mesa_has_EXT_render_snorm(ctx);
78501e04c3fSmrg   case GL_R16_SNORM:
78601e04c3fSmrg   case GL_RG16_SNORM:
78701e04c3fSmrg   case GL_RGBA16_SNORM:
78801e04c3fSmrg      return _mesa_has_EXT_texture_norm16(ctx) &&
78901e04c3fSmrg             _mesa_has_EXT_render_snorm(ctx);
7907ec681f3Smrg   case GL_R:
7917ec681f3Smrg   case GL_RG:
7927ec681f3Smrg      return _mesa_has_EXT_texture_rg(ctx);
7937ec681f3Smrg   case GL_R16F:
7947ec681f3Smrg   case GL_RG16F:
7957ec681f3Smrg      return _mesa_is_gles3(ctx) ||
7967ec681f3Smrg             (_mesa_has_EXT_color_buffer_half_float(ctx) &&
7977ec681f3Smrg              _mesa_has_EXT_texture_rg(ctx));
7987ec681f3Smrg   case GL_RGBA16F:
7997ec681f3Smrg      return _mesa_is_gles3(ctx) ||
8007ec681f3Smrg             _mesa_has_EXT_color_buffer_half_float(ctx);
8017ec681f3Smrg   case GL_RGBA32F:
8027ec681f3Smrg      return _mesa_has_EXT_color_buffer_float(ctx);
8037ec681f3Smrg   case GL_RGB16F:
8047ec681f3Smrg      return _mesa_has_EXT_color_buffer_half_float(ctx);
8057ec681f3Smrg   case GL_RGB10_A2:
8067ec681f3Smrg      return _mesa_is_gles3(ctx);
807af69d88dSmrg   case GL_RGB32F:
808af69d88dSmrg   case GL_RGB32I:
809af69d88dSmrg   case GL_RGB32UI:
810af69d88dSmrg   case GL_RGB16I:
811af69d88dSmrg   case GL_RGB16UI:
812af69d88dSmrg   case GL_RGB8_SNORM:
813af69d88dSmrg   case GL_RGB8I:
814af69d88dSmrg   case GL_RGB8UI:
815af69d88dSmrg   case GL_SRGB8:
81601e04c3fSmrg   case GL_RGB10:
817af69d88dSmrg   case GL_RGB9_E5:
818a8bb7a65Smaya   case GL_SR8_EXT:
8197ec681f3Smrg   case GL_SRG8_EXT:
820af69d88dSmrg      return GL_FALSE;
821af69d88dSmrg   default:
822af69d88dSmrg      break;
823af69d88dSmrg   }
824af69d88dSmrg
82501e04c3fSmrg   if (internalFormat != GL_RGB10_A2 &&
82601e04c3fSmrg       (format == MESA_FORMAT_B10G10R10A2_UNORM ||
82701e04c3fSmrg        format == MESA_FORMAT_B10G10R10X2_UNORM ||
82801e04c3fSmrg        format == MESA_FORMAT_R10G10B10A2_UNORM ||
82901e04c3fSmrg        format == MESA_FORMAT_R10G10B10X2_UNORM)) {
830af69d88dSmrg      return GL_FALSE;
831af69d88dSmrg   }
832af69d88dSmrg
833af69d88dSmrg   return GL_TRUE;
834af69d88dSmrg}
835af69d88dSmrg
8367ec681f3Smrg/**
8377ec681f3Smrg * Check that implements various limitations of floating point
8387ec681f3Smrg * rendering extensions on OpenGL ES.
8397ec681f3Smrg *
8407ec681f3Smrg * Check passes if texture format is not floating point or
8417ec681f3Smrg * is floating point and is color renderable.
8427ec681f3Smrg *
8437ec681f3Smrg * Check fails if texture format is floating point and cannot
8447ec681f3Smrg * be rendered to with current context and set of supported
8457ec681f3Smrg * extensions.
8467ec681f3Smrg */
8477ec681f3Smrgstatic GLboolean
8487ec681f3Smrggles_check_float_renderable(const struct gl_context *ctx,
8497ec681f3Smrg                            struct gl_renderbuffer_attachment *att)
8507ec681f3Smrg{
8517ec681f3Smrg   /* Only check floating point texture cases. */
8527ec681f3Smrg   if (!att->Texture || !is_float_format(att->Renderbuffer->InternalFormat))
8537ec681f3Smrg      return true;
8547ec681f3Smrg
8557ec681f3Smrg   /* GL_RGBA with unsized GL_FLOAT type, no extension can make this
8567ec681f3Smrg    * color renderable.
8577ec681f3Smrg    */
8587ec681f3Smrg   if (att->Texture->_IsFloat && att->Renderbuffer->_BaseFormat == GL_RGBA)
8597ec681f3Smrg      return false;
8607ec681f3Smrg
8617ec681f3Smrg   /* Unsized GL_HALF_FLOAT supported only with EXT_color_buffer_half_float. */
8627ec681f3Smrg   if (att->Texture->_IsHalfFloat && !_mesa_has_EXT_color_buffer_half_float(ctx))
8637ec681f3Smrg      return false;
8647ec681f3Smrg
8657ec681f3Smrg   const struct gl_texture_object *texObj = att->Texture;
8667ec681f3Smrg   const struct gl_texture_image *texImage =
8677ec681f3Smrg      texObj->Image[att->CubeMapFace][att->TextureLevel];
8687ec681f3Smrg
8697ec681f3Smrg   return is_format_color_renderable(ctx, texImage->TexFormat,
8707ec681f3Smrg                                     att->Renderbuffer->InternalFormat);
8717ec681f3Smrg}
872af69d88dSmrg
8733464ebd5Sriastradh/**
8743464ebd5Sriastradh * Is the given base format a legal format for a depth/stencil renderbuffer?
8753464ebd5Sriastradh */
8763464ebd5Sriastradhstatic GLboolean
8773464ebd5Sriastradhis_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
8783464ebd5Sriastradh{
8793464ebd5Sriastradh   switch (baseFormat) {
8803464ebd5Sriastradh   case GL_DEPTH_COMPONENT:
8813464ebd5Sriastradh   case GL_DEPTH_STENCIL_EXT:
8823464ebd5Sriastradh      return GL_TRUE;
8833464ebd5Sriastradh   default:
8843464ebd5Sriastradh      return GL_FALSE;
8853464ebd5Sriastradh   }
8863464ebd5Sriastradh}
8874a49301eSmrg
8884a49301eSmrg
8897117f1b4Smrg/**
8907117f1b4Smrg * Test if an attachment point is complete and update its Complete field.
8917117f1b4Smrg * \param format if GL_COLOR, this is a color attachment point,
8927117f1b4Smrg *               if GL_DEPTH, this is a depth component attachment point,
8937117f1b4Smrg *               if GL_STENCIL, this is a stencil component attachment point.
8947117f1b4Smrg */
8957117f1b4Smrgstatic void
8963464ebd5Sriastradhtest_attachment_completeness(const struct gl_context *ctx, GLenum format,
8977117f1b4Smrg                             struct gl_renderbuffer_attachment *att)
8987117f1b4Smrg{
8997117f1b4Smrg   assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
9007117f1b4Smrg
9017117f1b4Smrg   /* assume complete */
9027117f1b4Smrg   att->Complete = GL_TRUE;
9037117f1b4Smrg
9047117f1b4Smrg   /* Look for reasons why the attachment might be incomplete */
9057117f1b4Smrg   if (att->Type == GL_TEXTURE) {
9067117f1b4Smrg      const struct gl_texture_object *texObj = att->Texture;
90701e04c3fSmrg      const struct gl_texture_image *texImage;
9084a49301eSmrg      GLenum baseFormat;
9097117f1b4Smrg
9107117f1b4Smrg      if (!texObj) {
9114a49301eSmrg         att_incomplete("no texobj");
9127117f1b4Smrg         att->Complete = GL_FALSE;
9137117f1b4Smrg         return;
9147117f1b4Smrg      }
9157117f1b4Smrg
9167117f1b4Smrg      texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
9177117f1b4Smrg      if (!texImage) {
9184a49301eSmrg         att_incomplete("no teximage");
9197117f1b4Smrg         att->Complete = GL_FALSE;
9207117f1b4Smrg         return;
9217117f1b4Smrg      }
9227ec681f3Smrg
9237ec681f3Smrg      /* Mutable non base level texture as framebuffer attachment
9247ec681f3Smrg       * must be mipmap complete.
9257ec681f3Smrg       */
9267ec681f3Smrg      if (texImage->Level > texObj->Attrib.BaseLevel &&
9277ec681f3Smrg          !texObj->_MipmapComplete) {
9287ec681f3Smrg         /* Test if texture has become mipmap complete meanwhile. */
9297ec681f3Smrg         _mesa_test_texobj_completeness(ctx, att->Texture);
9307ec681f3Smrg         if (!texObj->_MipmapComplete) {
9317ec681f3Smrg            att_incomplete("texture attachment not mipmap complete");
9327ec681f3Smrg            att->Complete = GL_FALSE;
9337ec681f3Smrg            return;
9347ec681f3Smrg         }
9357ec681f3Smrg      }
9367ec681f3Smrg
9377117f1b4Smrg      if (texImage->Width < 1 || texImage->Height < 1) {
9384a49301eSmrg         att_incomplete("teximage width/height=0");
9397117f1b4Smrg         att->Complete = GL_FALSE;
9407117f1b4Smrg         return;
9417117f1b4Smrg      }
942af69d88dSmrg
943af69d88dSmrg      switch (texObj->Target) {
944af69d88dSmrg      case GL_TEXTURE_3D:
945af69d88dSmrg         if (att->Zoffset >= texImage->Depth) {
946af69d88dSmrg            att_incomplete("bad z offset");
947af69d88dSmrg            att->Complete = GL_FALSE;
948af69d88dSmrg            return;
949af69d88dSmrg         }
950af69d88dSmrg         break;
951af69d88dSmrg      case GL_TEXTURE_1D_ARRAY:
952af69d88dSmrg         if (att->Zoffset >= texImage->Height) {
953af69d88dSmrg            att_incomplete("bad 1D-array layer");
954af69d88dSmrg            att->Complete = GL_FALSE;
955af69d88dSmrg            return;
956af69d88dSmrg         }
957af69d88dSmrg         break;
958af69d88dSmrg      case GL_TEXTURE_2D_ARRAY:
959af69d88dSmrg         if (att->Zoffset >= texImage->Depth) {
960af69d88dSmrg            att_incomplete("bad 2D-array layer");
961af69d88dSmrg            att->Complete = GL_FALSE;
962af69d88dSmrg            return;
963af69d88dSmrg         }
964af69d88dSmrg         break;
965af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_ARRAY:
966af69d88dSmrg         if (att->Zoffset >= texImage->Depth) {
967af69d88dSmrg            att_incomplete("bad cube-array layer");
968af69d88dSmrg            att->Complete = GL_FALSE;
969af69d88dSmrg            return;
970af69d88dSmrg         }
971af69d88dSmrg         break;
9727117f1b4Smrg      }
9737117f1b4Smrg
97401e04c3fSmrg      baseFormat = texImage->_BaseFormat;
9754a49301eSmrg
9767117f1b4Smrg      if (format == GL_COLOR) {
9773464ebd5Sriastradh         if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
9784a49301eSmrg            att_incomplete("bad format");
9794a49301eSmrg            att->Complete = GL_FALSE;
9804a49301eSmrg            return;
9814a49301eSmrg         }
9824a49301eSmrg         if (_mesa_is_format_compressed(texImage->TexFormat)) {
9834a49301eSmrg            att_incomplete("compressed internalformat");
9847117f1b4Smrg            att->Complete = GL_FALSE;
9857117f1b4Smrg            return;
9867117f1b4Smrg         }
98701e04c3fSmrg
98801e04c3fSmrg         /* OES_texture_float allows creation and use of floating point
98901e04c3fSmrg          * textures with GL_FLOAT, GL_HALF_FLOAT but it does not allow
99001e04c3fSmrg          * these textures to be used as a render target, this is done via
99101e04c3fSmrg          * GL_EXT_color_buffer(_half)_float with set of new sized types.
99201e04c3fSmrg          */
9937ec681f3Smrg         if (_mesa_is_gles(ctx) && !gles_check_float_renderable(ctx, att)) {
99401e04c3fSmrg            att_incomplete("bad internal format");
99501e04c3fSmrg            att->Complete = GL_FALSE;
99601e04c3fSmrg            return;
99701e04c3fSmrg         }
9987117f1b4Smrg      }
9997117f1b4Smrg      else if (format == GL_DEPTH) {
10004a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
10017117f1b4Smrg            /* OK */
10027117f1b4Smrg         }
1003af69d88dSmrg         else if (ctx->Extensions.ARB_depth_texture &&
1004af69d88dSmrg                  baseFormat == GL_DEPTH_STENCIL) {
10057117f1b4Smrg            /* OK */
10067117f1b4Smrg         }
10077117f1b4Smrg         else {
10087117f1b4Smrg            att->Complete = GL_FALSE;
10094a49301eSmrg            att_incomplete("bad depth format");
10107117f1b4Smrg            return;
10117117f1b4Smrg         }
10127117f1b4Smrg      }
10137117f1b4Smrg      else {
101401e04c3fSmrg         assert(format == GL_STENCIL);
1015af69d88dSmrg         if (ctx->Extensions.ARB_depth_texture &&
1016af69d88dSmrg             baseFormat == GL_DEPTH_STENCIL) {
1017c7037ccdSmrg            /* OK */
101801e04c3fSmrg         } else if (ctx->Extensions.ARB_texture_stencil8 &&
101901e04c3fSmrg                    baseFormat == GL_STENCIL_INDEX) {
102001e04c3fSmrg            /* OK */
102101e04c3fSmrg         } else {
1022c7037ccdSmrg            /* no such thing as stencil-only textures */
10234a49301eSmrg            att_incomplete("illegal stencil texture");
1024c7037ccdSmrg            att->Complete = GL_FALSE;
1025c7037ccdSmrg            return;
1026c7037ccdSmrg         }
10277117f1b4Smrg      }
10287117f1b4Smrg   }
10297117f1b4Smrg   else if (att->Type == GL_RENDERBUFFER_EXT) {
103001e04c3fSmrg      const GLenum baseFormat = att->Renderbuffer->_BaseFormat;
10314a49301eSmrg
103201e04c3fSmrg      assert(att->Renderbuffer);
10337117f1b4Smrg      if (!att->Renderbuffer->InternalFormat ||
10347117f1b4Smrg          att->Renderbuffer->Width < 1 ||
10357117f1b4Smrg          att->Renderbuffer->Height < 1) {
10364a49301eSmrg         att_incomplete("0x0 renderbuffer");
10377117f1b4Smrg         att->Complete = GL_FALSE;
10387117f1b4Smrg         return;
10397117f1b4Smrg      }
10407117f1b4Smrg      if (format == GL_COLOR) {
10413464ebd5Sriastradh         if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
10424a49301eSmrg            att_incomplete("bad renderbuffer color format");
10437117f1b4Smrg            att->Complete = GL_FALSE;
10447117f1b4Smrg            return;
10457117f1b4Smrg         }
10467117f1b4Smrg      }
10477117f1b4Smrg      else if (format == GL_DEPTH) {
10484a49301eSmrg         if (baseFormat == GL_DEPTH_COMPONENT) {
10497117f1b4Smrg            /* OK */
10507117f1b4Smrg         }
1051af69d88dSmrg         else if (baseFormat == GL_DEPTH_STENCIL) {
10527117f1b4Smrg            /* OK */
10537117f1b4Smrg         }
10547117f1b4Smrg         else {
10554a49301eSmrg            att_incomplete("bad renderbuffer depth format");
10567117f1b4Smrg            att->Complete = GL_FALSE;
10577117f1b4Smrg            return;
10587117f1b4Smrg         }
10597117f1b4Smrg      }
10607117f1b4Smrg      else {
10617117f1b4Smrg         assert(format == GL_STENCIL);
1062af69d88dSmrg         if (baseFormat == GL_STENCIL_INDEX ||
1063af69d88dSmrg             baseFormat == GL_DEPTH_STENCIL) {
10647117f1b4Smrg            /* OK */
10657117f1b4Smrg         }
10667117f1b4Smrg         else {
10677117f1b4Smrg            att->Complete = GL_FALSE;
10684a49301eSmrg            att_incomplete("bad renderbuffer stencil format");
10697117f1b4Smrg            return;
10707117f1b4Smrg         }
10717117f1b4Smrg      }
10727117f1b4Smrg   }
10737117f1b4Smrg   else {
107401e04c3fSmrg      assert(att->Type == GL_NONE);
10757117f1b4Smrg      /* complete */
10767117f1b4Smrg      return;
10777117f1b4Smrg   }
10787117f1b4Smrg}
10797117f1b4Smrg
10807117f1b4Smrg
10817117f1b4Smrg/**
10827117f1b4Smrg * Test if the given framebuffer object is complete and update its
10837117f1b4Smrg * Status field with the results.
10844a49301eSmrg * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
10854a49301eSmrg * driver to make hardware-specific validation/completeness checks.
10867117f1b4Smrg * Also update the framebuffer's Width and Height fields if the
10877117f1b4Smrg * framebuffer is complete.
10887117f1b4Smrg */
10897117f1b4Smrgvoid
10903464ebd5Sriastradh_mesa_test_framebuffer_completeness(struct gl_context *ctx,
10913464ebd5Sriastradh                                    struct gl_framebuffer *fb)
10927117f1b4Smrg{
10934a49301eSmrg   GLuint numImages;
10944a49301eSmrg   GLenum intFormat = GL_NONE; /* color buffers' internal format */
10954a49301eSmrg   GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
109601e04c3fSmrg   GLint numColorSamples = -1;
109701e04c3fSmrg   GLint numColorStorageSamples = -1;
109801e04c3fSmrg   GLint numDepthSamples = -1;
1099af69d88dSmrg   GLint fixedSampleLocations = -1;
11007117f1b4Smrg   GLint i;
11017117f1b4Smrg   GLuint j;
1102af69d88dSmrg   /* Covers max_layer_count, is_layered, and layer_tex_target */
1103af69d88dSmrg   bool layer_info_valid = false;
1104af69d88dSmrg   GLuint max_layer_count = 0, att_layer_count;
1105af69d88dSmrg   bool is_layered = false;
1106af69d88dSmrg   GLenum layer_tex_target = 0;
110701e04c3fSmrg   bool has_depth_attachment = false;
110801e04c3fSmrg   bool has_stencil_attachment = false;
1109af69d88dSmrg
1110af69d88dSmrg   assert(_mesa_is_user_fbo(fb));
11117117f1b4Smrg
1112af69d88dSmrg   /* we're changing framebuffer fields here */
11137ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
11147117f1b4Smrg
11157117f1b4Smrg   numImages = 0;
11167117f1b4Smrg   fb->Width = 0;
11177117f1b4Smrg   fb->Height = 0;
1118af69d88dSmrg   fb->_AllColorBuffersFixedPoint = GL_TRUE;
1119af69d88dSmrg   fb->_HasSNormOrFloatColorBuffer = GL_FALSE;
112001e04c3fSmrg   fb->_HasAttachments = true;
112101e04c3fSmrg   fb->_IntegerBuffers = 0;
1122a8bb7a65Smaya   fb->_RGBBuffers = 0;
1123a8bb7a65Smaya   fb->_FP32Buffers = 0;
11247117f1b4Smrg
11254a49301eSmrg   /* Start at -2 to more easily loop over all attachment points.
11264a49301eSmrg    *  -2: depth buffer
11274a49301eSmrg    *  -1: stencil buffer
11284a49301eSmrg    * >=0: color buffer
11294a49301eSmrg    */
11307117f1b4Smrg   for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
11317117f1b4Smrg      struct gl_renderbuffer_attachment *att;
11327117f1b4Smrg      GLenum f;
1133a8bb7a65Smaya      GLenum baseFormat;
1134af69d88dSmrg      mesa_format attFormat;
1135af69d88dSmrg      GLenum att_tex_target = GL_NONE;
11367117f1b4Smrg
11374a49301eSmrg      /*
11384a49301eSmrg       * XXX for ARB_fbo, only check color buffers that are named by
11394a49301eSmrg       * GL_READ_BUFFER and GL_DRAW_BUFFERi.
11404a49301eSmrg       */
11414a49301eSmrg
11424a49301eSmrg      /* check for attachment completeness
11434a49301eSmrg       */
11447117f1b4Smrg      if (i == -2) {
11457117f1b4Smrg         att = &fb->Attachment[BUFFER_DEPTH];
11467117f1b4Smrg         test_attachment_completeness(ctx, GL_DEPTH, att);
11477117f1b4Smrg         if (!att->Complete) {
11487117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
1149af69d88dSmrg            fbo_incomplete(ctx, "depth attachment incomplete", -1);
11507117f1b4Smrg            return;
115101e04c3fSmrg         } else if (att->Type != GL_NONE) {
115201e04c3fSmrg            has_depth_attachment = true;
11537117f1b4Smrg         }
11547117f1b4Smrg      }
11557117f1b4Smrg      else if (i == -1) {
11567117f1b4Smrg         att = &fb->Attachment[BUFFER_STENCIL];
11577117f1b4Smrg         test_attachment_completeness(ctx, GL_STENCIL, att);
11587117f1b4Smrg         if (!att->Complete) {
11597117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
1160af69d88dSmrg            fbo_incomplete(ctx, "stencil attachment incomplete", -1);
11617117f1b4Smrg            return;
116201e04c3fSmrg         } else if (att->Type != GL_NONE) {
116301e04c3fSmrg            has_stencil_attachment = true;
11647117f1b4Smrg         }
11657117f1b4Smrg      }
11667117f1b4Smrg      else {
11677117f1b4Smrg         att = &fb->Attachment[BUFFER_COLOR0 + i];
11687117f1b4Smrg         test_attachment_completeness(ctx, GL_COLOR, att);
11697117f1b4Smrg         if (!att->Complete) {
11707ec681f3Smrg            /* With EXT_color_buffer_half_float, check if attachment was incomplete
11717ec681f3Smrg             * due to invalid format. This is special case for the extension where
11727ec681f3Smrg             * CTS tests expect unsupported framebuffer status instead of incomplete.
11737ec681f3Smrg             */
11747ec681f3Smrg            if ((_mesa_is_gles(ctx) && _mesa_has_EXT_color_buffer_half_float(ctx)) &&
11757ec681f3Smrg                !gles_check_float_renderable(ctx, att)) {
11767ec681f3Smrg               fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
11777ec681f3Smrg               return;
11787ec681f3Smrg            }
11797ec681f3Smrg
11807117f1b4Smrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
1181af69d88dSmrg            fbo_incomplete(ctx, "color attachment incomplete", i);
11827117f1b4Smrg            return;
11837117f1b4Smrg         }
11847117f1b4Smrg      }
11857117f1b4Smrg
11864a49301eSmrg      /* get width, height, format of the renderbuffer/texture
11874a49301eSmrg       */
118801e04c3fSmrg      unsigned attNumSamples, attNumStorageSamples;
118901e04c3fSmrg
11907117f1b4Smrg      if (att->Type == GL_TEXTURE) {
1191af69d88dSmrg         const struct gl_texture_image *texImg = att->Renderbuffer->TexImage;
1192af69d88dSmrg         att_tex_target = att->Texture->Target;
11934a49301eSmrg         minWidth = MIN2(minWidth, texImg->Width);
11944a49301eSmrg         maxWidth = MAX2(maxWidth, texImg->Width);
11954a49301eSmrg         minHeight = MIN2(minHeight, texImg->Height);
11964a49301eSmrg         maxHeight = MAX2(maxHeight, texImg->Height);
11977117f1b4Smrg         f = texImg->_BaseFormat;
1198a8bb7a65Smaya         baseFormat = f;
11993464ebd5Sriastradh         attFormat = texImg->TexFormat;
12007117f1b4Smrg         numImages++;
1201af69d88dSmrg
1202af69d88dSmrg         if (!is_format_color_renderable(ctx, attFormat,
1203af69d88dSmrg                                         texImg->InternalFormat) &&
120401e04c3fSmrg             !is_legal_depth_format(ctx, f) &&
120501e04c3fSmrg             f != GL_STENCIL_INDEX) {
120601e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
1207af69d88dSmrg            fbo_incomplete(ctx, "texture attachment incomplete", -1);
1208af69d88dSmrg            return;
1209af69d88dSmrg         }
1210af69d88dSmrg
1211af69d88dSmrg         if (fixedSampleLocations < 0)
1212af69d88dSmrg            fixedSampleLocations = texImg->FixedSampleLocations;
1213af69d88dSmrg         else if (fixedSampleLocations != texImg->FixedSampleLocations) {
1214af69d88dSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1215af69d88dSmrg            fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
12167117f1b4Smrg            return;
12177117f1b4Smrg         }
121801e04c3fSmrg
1219a8bb7a65Smaya         if (att->NumSamples > 0)
1220a8bb7a65Smaya            attNumSamples = att->NumSamples;
1221a8bb7a65Smaya         else
1222a8bb7a65Smaya            attNumSamples = texImg->NumSamples;
1223a8bb7a65Smaya         attNumStorageSamples = attNumSamples;
12247117f1b4Smrg      }
12257117f1b4Smrg      else if (att->Type == GL_RENDERBUFFER_EXT) {
12264a49301eSmrg         minWidth = MIN2(minWidth, att->Renderbuffer->Width);
12277ec681f3Smrg         maxWidth = MAX2(maxWidth, att->Renderbuffer->Width);
12284a49301eSmrg         minHeight = MIN2(minHeight, att->Renderbuffer->Height);
12297ec681f3Smrg         maxHeight = MAX2(maxHeight, att->Renderbuffer->Height);
12307117f1b4Smrg         f = att->Renderbuffer->InternalFormat;
1231a8bb7a65Smaya         baseFormat = att->Renderbuffer->_BaseFormat;
12323464ebd5Sriastradh         attFormat = att->Renderbuffer->Format;
12337117f1b4Smrg         numImages++;
1234af69d88dSmrg
1235af69d88dSmrg         /* RENDERBUFFER has fixedSampleLocations implicitly true */
1236af69d88dSmrg         if (fixedSampleLocations < 0)
1237af69d88dSmrg            fixedSampleLocations = GL_TRUE;
1238af69d88dSmrg         else if (fixedSampleLocations != GL_TRUE) {
1239af69d88dSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1240af69d88dSmrg            fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
1241af69d88dSmrg            return;
1242af69d88dSmrg         }
124301e04c3fSmrg
124401e04c3fSmrg         attNumSamples = att->Renderbuffer->NumSamples;
124501e04c3fSmrg         attNumStorageSamples = att->Renderbuffer->NumStorageSamples;
12467117f1b4Smrg      }
12477117f1b4Smrg      else {
12487117f1b4Smrg         assert(att->Type == GL_NONE);
12497117f1b4Smrg         continue;
12507117f1b4Smrg      }
12517117f1b4Smrg
125201e04c3fSmrg      if (i >= 0) {
125301e04c3fSmrg         /* Color buffers. */
125401e04c3fSmrg         if (numColorSamples < 0) {
125501e04c3fSmrg            assert(numColorStorageSamples < 0);
125601e04c3fSmrg            numColorSamples = attNumSamples;
125701e04c3fSmrg            numColorStorageSamples = attNumStorageSamples;
125801e04c3fSmrg         } else if (numColorSamples != attNumSamples ||
125901e04c3fSmrg                    numColorStorageSamples != attNumStorageSamples) {
126001e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
126101e04c3fSmrg            fbo_incomplete(ctx, "inconsistent sample counts", -1);
126201e04c3fSmrg            return;
126301e04c3fSmrg         }
126401e04c3fSmrg      } else {
126501e04c3fSmrg         /* Depth/stencil buffers. */
126601e04c3fSmrg         if (numDepthSamples < 0) {
126701e04c3fSmrg            numDepthSamples = attNumSamples;
126801e04c3fSmrg         } else if (numDepthSamples != attNumSamples) {
126901e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
127001e04c3fSmrg            fbo_incomplete(ctx, "inconsistent sample counts", -1);
127101e04c3fSmrg            return;
127201e04c3fSmrg         }
127301e04c3fSmrg      }
12743464ebd5Sriastradh
127501e04c3fSmrg      /* Update flags describing color buffer datatypes */
1276af69d88dSmrg      if (i >= 0) {
1277af69d88dSmrg         GLenum type = _mesa_get_format_datatype(attFormat);
1278af69d88dSmrg
127901e04c3fSmrg         /* check if integer color */
128001e04c3fSmrg         if (_mesa_is_format_integer_color(attFormat))
128101e04c3fSmrg            fb->_IntegerBuffers |= (1 << i);
128201e04c3fSmrg
1283a8bb7a65Smaya         if (baseFormat == GL_RGB)
1284a8bb7a65Smaya            fb->_RGBBuffers |= (1 << i);
1285a8bb7a65Smaya
1286a8bb7a65Smaya         if (type == GL_FLOAT && _mesa_get_format_max_bits(attFormat) > 16)
1287a8bb7a65Smaya            fb->_FP32Buffers |= (1 << i);
1288a8bb7a65Smaya
1289af69d88dSmrg         fb->_AllColorBuffersFixedPoint =
1290af69d88dSmrg            fb->_AllColorBuffersFixedPoint &&
1291af69d88dSmrg            (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED);
1292af69d88dSmrg
1293af69d88dSmrg         fb->_HasSNormOrFloatColorBuffer =
1294af69d88dSmrg            fb->_HasSNormOrFloatColorBuffer ||
1295af69d88dSmrg            type == GL_SIGNED_NORMALIZED || type == GL_FLOAT;
1296af69d88dSmrg      }
1297af69d88dSmrg
1298af69d88dSmrg      /* Error-check width, height, format */
12997117f1b4Smrg      if (numImages == 1) {
1300af69d88dSmrg         /* save format */
13014a49301eSmrg         if (i >= 0) {
13027117f1b4Smrg            intFormat = f;
13034a49301eSmrg         }
13047117f1b4Smrg      }
13057117f1b4Smrg      else {
13067ec681f3Smrg         if (!_mesa_has_ARB_framebuffer_object(ctx) &&
13077ec681f3Smrg             !_mesa_is_gles3(ctx)) {
13084a49301eSmrg            /* check that width, height, format are same */
13094a49301eSmrg            if (minWidth != maxWidth || minHeight != maxHeight) {
13104a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
1311af69d88dSmrg               fbo_incomplete(ctx, "width or height mismatch", -1);
13124a49301eSmrg               return;
13134a49301eSmrg            }
1314af69d88dSmrg            /* check that all color buffers are the same format */
13157ec681f3Smrg            if (ctx->API != API_OPENGLES2 && intFormat != GL_NONE && f != intFormat) {
13164a49301eSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
1317af69d88dSmrg               fbo_incomplete(ctx, "format mismatch", -1);
13184a49301eSmrg               return;
13194a49301eSmrg            }
13207117f1b4Smrg         }
1321af69d88dSmrg      }
1322af69d88dSmrg
1323af69d88dSmrg      /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported)
1324af69d88dSmrg       */
1325af69d88dSmrg      if (att->Type == GL_RENDERBUFFER &&
1326af69d88dSmrg          att->Renderbuffer->Format == MESA_FORMAT_NONE) {
1327af69d88dSmrg         fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
1328af69d88dSmrg         fbo_incomplete(ctx, "unsupported renderbuffer format", i);
1329af69d88dSmrg         return;
1330af69d88dSmrg      }
13314a49301eSmrg
1332af69d88dSmrg      /* Check that layered rendering is consistent. */
1333af69d88dSmrg      if (att->Layered) {
13347ec681f3Smrg         if (att_tex_target == GL_TEXTURE_CUBE_MAP) {
13357ec681f3Smrg            /* Each layer's format and size must match to the base layer. */
13367ec681f3Smrg            if (!_mesa_cube_complete(att->Texture)) {
13377ec681f3Smrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
13387ec681f3Smrg               fbo_incomplete(ctx, "attachment not cube complete", i);
13397ec681f3Smrg               return;
13407ec681f3Smrg            }
1341af69d88dSmrg            att_layer_count = 6;
13427ec681f3Smrg         } else if (att_tex_target == GL_TEXTURE_1D_ARRAY)
1343af69d88dSmrg            att_layer_count = att->Renderbuffer->Height;
1344af69d88dSmrg         else
1345af69d88dSmrg            att_layer_count = att->Renderbuffer->Depth;
13467ec681f3Smrg
13477ec681f3Smrg         /* From OpenGL ES 3.2 spec, chapter 9.4. FRAMEBUFFER COMPLETENESS:
13487ec681f3Smrg          *
13497ec681f3Smrg          *    "If any framebuffer attachment is layered, all populated
13507ec681f3Smrg          *    attachments must be layered. Additionally, all populated color
13517ec681f3Smrg          *    attachments must be from textures of the same target
13527ec681f3Smrg          *    (three-dimensional, one- or two-dimensional array, cube map, or
13537ec681f3Smrg          *    cube map array textures)."
13547ec681f3Smrg          *
13557ec681f3Smrg          * Same text can be found from OpenGL 4.6 spec.
13567ec681f3Smrg          *
13577ec681f3Smrg          * Setup the checked layer target with first color attachment here
13587ec681f3Smrg          * so that mismatch check below will not trigger between depth,
13597ec681f3Smrg          * stencil, only between color attachments.
13607ec681f3Smrg          */
13617ec681f3Smrg         if (i == 0)
13627ec681f3Smrg            layer_tex_target = att_tex_target;
13637ec681f3Smrg
1364af69d88dSmrg      } else {
1365af69d88dSmrg         att_layer_count = 0;
1366af69d88dSmrg      }
1367af69d88dSmrg      if (!layer_info_valid) {
1368af69d88dSmrg         is_layered = att->Layered;
1369af69d88dSmrg         max_layer_count = att_layer_count;
1370af69d88dSmrg         layer_info_valid = true;
13717ec681f3Smrg      } else if (max_layer_count > 0 && layer_tex_target &&
13727ec681f3Smrg                 layer_tex_target != att_tex_target) {
1373af69d88dSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
1374af69d88dSmrg         fbo_incomplete(ctx, "layered framebuffer has mismatched targets", i);
1375af69d88dSmrg         return;
1376af69d88dSmrg      } else if (is_layered != att->Layered) {
1377af69d88dSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
1378af69d88dSmrg         fbo_incomplete(ctx,
1379af69d88dSmrg                        "framebuffer attachment layer mode is inconsistent",
1380af69d88dSmrg                        i);
1381af69d88dSmrg         return;
1382af69d88dSmrg      } else if (att_layer_count > max_layer_count) {
1383af69d88dSmrg         max_layer_count = att_layer_count;
13847117f1b4Smrg      }
138501e04c3fSmrg
138601e04c3fSmrg      /*
138701e04c3fSmrg       * The extension GL_ARB_framebuffer_no_attachments places additional
138801e04c3fSmrg       * requirement on each attachment. Those additional requirements are
138901e04c3fSmrg       * tighter that those of previous versions of GL. In interest of better
139001e04c3fSmrg       * compatibility, we will not enforce these restrictions. For the record
139101e04c3fSmrg       * those additional restrictions are quoted below:
139201e04c3fSmrg       *
139301e04c3fSmrg       * "The width and height of image are greater than zero and less than or
139401e04c3fSmrg       *  equal to the values of the implementation-dependent limits
139501e04c3fSmrg       *  MAX_FRAMEBUFFER_WIDTH and MAX_FRAMEBUFFER_HEIGHT, respectively."
139601e04c3fSmrg       *
139701e04c3fSmrg       * "If <image> is a three-dimensional texture or a one- or two-dimensional
139801e04c3fSmrg       *  array texture and the attachment is layered, the depth or layer count
139901e04c3fSmrg       *  of the texture is less than or equal to the implementation-dependent
140001e04c3fSmrg       *  limit MAX_FRAMEBUFFER_LAYERS."
140101e04c3fSmrg       *
140201e04c3fSmrg       * "If image has multiple samples, its sample count is less than or equal
140301e04c3fSmrg       *  to the value of the implementation-dependent limit
140401e04c3fSmrg       *  MAX_FRAMEBUFFER_SAMPLES."
140501e04c3fSmrg       *
140601e04c3fSmrg       * The same requirements are also in place for GL 4.5,
140701e04c3fSmrg       * Section 9.4.1 "Framebuffer Attachment Completeness", pg 310-311
140801e04c3fSmrg       */
140901e04c3fSmrg   }
141001e04c3fSmrg
141101e04c3fSmrg   if (ctx->Extensions.AMD_framebuffer_multisample_advanced) {
141201e04c3fSmrg      /* See if non-matching sample counts are supported. */
141301e04c3fSmrg      if (numColorSamples >= 0 && numDepthSamples >= 0) {
141401e04c3fSmrg         bool found = false;
141501e04c3fSmrg
141601e04c3fSmrg         assert(numColorStorageSamples != -1);
141701e04c3fSmrg
141801e04c3fSmrg         numColorSamples = MAX2(numColorSamples, 1);
141901e04c3fSmrg         numColorStorageSamples = MAX2(numColorStorageSamples, 1);
142001e04c3fSmrg         numDepthSamples = MAX2(numDepthSamples, 1);
142101e04c3fSmrg
142201e04c3fSmrg         if (numColorSamples == 1 && numColorStorageSamples == 1 &&
142301e04c3fSmrg             numDepthSamples == 1) {
142401e04c3fSmrg            found = true;
142501e04c3fSmrg         } else {
142601e04c3fSmrg            for (i = 0; i < ctx->Const.NumSupportedMultisampleModes; i++) {
142701e04c3fSmrg               GLint *counts =
142801e04c3fSmrg                  &ctx->Const.SupportedMultisampleModes[i].NumColorSamples;
142901e04c3fSmrg
143001e04c3fSmrg               if (counts[0] == numColorSamples &&
143101e04c3fSmrg                   counts[1] == numColorStorageSamples &&
143201e04c3fSmrg                   counts[2] == numDepthSamples) {
143301e04c3fSmrg                  found = true;
143401e04c3fSmrg                  break;
143501e04c3fSmrg               }
143601e04c3fSmrg            }
143701e04c3fSmrg         }
143801e04c3fSmrg
143901e04c3fSmrg         if (!found) {
144001e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
144101e04c3fSmrg            fbo_incomplete(ctx, "unsupported sample counts", -1);
144201e04c3fSmrg            return;
144301e04c3fSmrg         }
144401e04c3fSmrg      }
144501e04c3fSmrg   } else {
144601e04c3fSmrg      /* If the extension is unsupported, all sample counts must be equal. */
144701e04c3fSmrg      if (numColorSamples >= 0 &&
144801e04c3fSmrg          (numColorSamples != numColorStorageSamples ||
144901e04c3fSmrg           (numDepthSamples >= 0 && numColorSamples != numDepthSamples))) {
145001e04c3fSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
145101e04c3fSmrg         fbo_incomplete(ctx, "inconsistent sample counts", -1);
145201e04c3fSmrg         return;
145301e04c3fSmrg      }
14547117f1b4Smrg   }
14557117f1b4Smrg
1456af69d88dSmrg   fb->MaxNumLayers = max_layer_count;
1457af69d88dSmrg
1458af69d88dSmrg   if (numImages == 0) {
145901e04c3fSmrg      fb->_HasAttachments = false;
146001e04c3fSmrg
146101e04c3fSmrg      if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
146201e04c3fSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
146301e04c3fSmrg         fbo_incomplete(ctx, "no attachments", -1);
146401e04c3fSmrg         return;
146501e04c3fSmrg      }
146601e04c3fSmrg
146701e04c3fSmrg      if (fb->DefaultGeometry.Width == 0 || fb->DefaultGeometry.Height == 0) {
146801e04c3fSmrg         fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
146901e04c3fSmrg         fbo_incomplete(ctx, "no attachments and default width or height is 0", -1);
147001e04c3fSmrg         return;
147101e04c3fSmrg      }
1472af69d88dSmrg   }
1473af69d88dSmrg
1474af69d88dSmrg   if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) {
14753464ebd5Sriastradh      /* Check that all DrawBuffers are present */
14763464ebd5Sriastradh      for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
147701e04c3fSmrg         if (fb->ColorDrawBuffer[j] != GL_NONE) {
147801e04c3fSmrg            const struct gl_renderbuffer_attachment *att
147901e04c3fSmrg               = get_attachment(ctx, fb, fb->ColorDrawBuffer[j], NULL);
148001e04c3fSmrg            assert(att);
148101e04c3fSmrg            if (att->Type == GL_NONE) {
148201e04c3fSmrg               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
148301e04c3fSmrg               fbo_incomplete(ctx, "missing drawbuffer", j);
148401e04c3fSmrg               return;
148501e04c3fSmrg            }
148601e04c3fSmrg         }
14877117f1b4Smrg      }
14887117f1b4Smrg
14893464ebd5Sriastradh      /* Check that the ReadBuffer is present */
14903464ebd5Sriastradh      if (fb->ColorReadBuffer != GL_NONE) {
149101e04c3fSmrg         const struct gl_renderbuffer_attachment *att
149201e04c3fSmrg            = get_attachment(ctx, fb, fb->ColorReadBuffer, NULL);
149301e04c3fSmrg         assert(att);
149401e04c3fSmrg         if (att->Type == GL_NONE) {
149501e04c3fSmrg            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
1496af69d88dSmrg            fbo_incomplete(ctx, "missing readbuffer", -1);
149701e04c3fSmrg            return;
149801e04c3fSmrg         }
14997117f1b4Smrg      }
15007117f1b4Smrg   }
15017117f1b4Smrg
150201e04c3fSmrg   /* The OpenGL ES3 spec, in chapter 9.4. FRAMEBUFFER COMPLETENESS, says:
150301e04c3fSmrg    *
150401e04c3fSmrg    *    "Depth and stencil attachments, if present, are the same image."
150501e04c3fSmrg    *
150601e04c3fSmrg    * This restriction is not present in the OpenGL ES2 spec.
150701e04c3fSmrg    */
150801e04c3fSmrg   if (_mesa_is_gles3(ctx) &&
150901e04c3fSmrg       has_stencil_attachment && has_depth_attachment &&
151001e04c3fSmrg       !_mesa_has_depthstencil_combined(fb)) {
151101e04c3fSmrg      fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
151201e04c3fSmrg      fbo_incomplete(ctx, "Depth and stencil attachments must be the same image", -1);
151301e04c3fSmrg      return;
151401e04c3fSmrg   }
151501e04c3fSmrg
15164a49301eSmrg   /* Provisionally set status = COMPLETE ... */
15177117f1b4Smrg   fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
15184a49301eSmrg
15194a49301eSmrg   /* ... but the driver may say the FB is incomplete.
15204a49301eSmrg    * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
15214a49301eSmrg    * if anything.
15224a49301eSmrg    */
15234a49301eSmrg   if (ctx->Driver.ValidateFramebuffer) {
15244a49301eSmrg      ctx->Driver.ValidateFramebuffer(ctx, fb);
15254a49301eSmrg      if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1526af69d88dSmrg         fbo_incomplete(ctx, "driver marked FBO as incomplete", -1);
152701e04c3fSmrg         return;
15284a49301eSmrg      }
15294a49301eSmrg   }
15304a49301eSmrg
153101e04c3fSmrg   /*
153201e04c3fSmrg    * Note that if ARB_framebuffer_object is supported and the attached
153301e04c3fSmrg    * renderbuffers/textures are different sizes, the framebuffer
153401e04c3fSmrg    * width/height will be set to the smallest width/height.
153501e04c3fSmrg    */
153601e04c3fSmrg   if (numImages != 0) {
15374a49301eSmrg      fb->Width = minWidth;
15384a49301eSmrg      fb->Height = minHeight;
15394a49301eSmrg   }
154001e04c3fSmrg
154101e04c3fSmrg   /* finally, update the visual info for the framebuffer */
154201e04c3fSmrg   _mesa_update_framebuffer_visual(ctx, fb);
15437117f1b4Smrg}
15447117f1b4Smrg
15457117f1b4Smrg
15467117f1b4SmrgGLboolean GLAPIENTRY
1547af69d88dSmrg_mesa_IsRenderbuffer(GLuint renderbuffer)
15487117f1b4Smrg{
154901e04c3fSmrg   struct gl_renderbuffer *rb;
155001e04c3fSmrg
15517117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
155201e04c3fSmrg
15537117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
155401e04c3fSmrg
155501e04c3fSmrg   rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
155601e04c3fSmrg   return rb != NULL && rb != &DummyRenderbuffer;
155701e04c3fSmrg}
155801e04c3fSmrg
155901e04c3fSmrg
156001e04c3fSmrgstatic struct gl_renderbuffer *
156101e04c3fSmrgallocate_renderbuffer_locked(struct gl_context *ctx, GLuint renderbuffer,
15627ec681f3Smrg                             bool isGenName,
156301e04c3fSmrg                             const char *func)
156401e04c3fSmrg{
156501e04c3fSmrg   struct gl_renderbuffer *newRb;
156601e04c3fSmrg
156701e04c3fSmrg   /* create new renderbuffer object */
156801e04c3fSmrg   newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
156901e04c3fSmrg   if (!newRb) {
157001e04c3fSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
157101e04c3fSmrg      return NULL;
15727117f1b4Smrg   }
157301e04c3fSmrg   assert(newRb->AllocStorage);
15747ec681f3Smrg   _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, renderbuffer,
15757ec681f3Smrg                          newRb, isGenName);
157601e04c3fSmrg
157701e04c3fSmrg   return newRb;
15787117f1b4Smrg}
15797117f1b4Smrg
15807117f1b4Smrg
1581af69d88dSmrgstatic void
158201e04c3fSmrgbind_renderbuffer(GLenum target, GLuint renderbuffer)
15837117f1b4Smrg{
15847117f1b4Smrg   struct gl_renderbuffer *newRb;
15857117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
15867117f1b4Smrg
15877117f1b4Smrg   if (target != GL_RENDERBUFFER_EXT) {
15884a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
15897117f1b4Smrg      return;
15907117f1b4Smrg   }
15917117f1b4Smrg
15924a49301eSmrg   /* No need to flush here since the render buffer binding has no
15934a49301eSmrg    * effect on rendering state.
15947117f1b4Smrg    */
15957117f1b4Smrg
15967117f1b4Smrg   if (renderbuffer) {
15977ec681f3Smrg      bool isGenName = false;
15987117f1b4Smrg      newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
15997117f1b4Smrg      if (newRb == &DummyRenderbuffer) {
16007117f1b4Smrg         /* ID was reserved, but no real renderbuffer object made yet */
16017117f1b4Smrg         newRb = NULL;
16027ec681f3Smrg         isGenName = true;
16037117f1b4Smrg      }
160401e04c3fSmrg      else if (!newRb && ctx->API == API_OPENGL_CORE) {
16054a49301eSmrg         /* All RB IDs must be Gen'd */
160601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
160701e04c3fSmrg                     "glBindRenderbuffer(non-gen name)");
16084a49301eSmrg         return;
16094a49301eSmrg      }
16104a49301eSmrg
16117117f1b4Smrg      if (!newRb) {
161201e04c3fSmrg         _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
161301e04c3fSmrg         newRb = allocate_renderbuffer_locked(ctx, renderbuffer,
16147ec681f3Smrg                                              isGenName, "glBindRenderbufferEXT");
161501e04c3fSmrg         _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
16167117f1b4Smrg      }
16177117f1b4Smrg   }
16187117f1b4Smrg   else {
16197117f1b4Smrg      newRb = NULL;
16207117f1b4Smrg   }
16217117f1b4Smrg
162201e04c3fSmrg   assert(newRb != &DummyRenderbuffer);
16237117f1b4Smrg
16247117f1b4Smrg   _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
16257117f1b4Smrg}
16267117f1b4Smrg
1627af69d88dSmrgvoid GLAPIENTRY
1628af69d88dSmrg_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
1629af69d88dSmrg{
1630af69d88dSmrg   /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same
1631af69d88dSmrg    * entry point, but they allow the use of user-generated names.
1632af69d88dSmrg    */
163301e04c3fSmrg   bind_renderbuffer(target, renderbuffer);
1634af69d88dSmrg}
1635af69d88dSmrg
1636af69d88dSmrgvoid GLAPIENTRY
1637af69d88dSmrg_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
1638af69d88dSmrg{
163901e04c3fSmrg   bind_renderbuffer(target, renderbuffer);
1640af69d88dSmrg}
1641af69d88dSmrg
16424a49301eSmrg/**
164301e04c3fSmrg * ARB_framebuffer_no_attachment and ARB_sample_locations - Application passes
164401e04c3fSmrg * requested param's here. NOTE: NumSamples requested need not be _NumSamples
164501e04c3fSmrg * which is what the hw supports.
16464a49301eSmrg */
164701e04c3fSmrgstatic void
164801e04c3fSmrgframebuffer_parameteri(struct gl_context *ctx, struct gl_framebuffer *fb,
164901e04c3fSmrg                       GLenum pname, GLint param, const char *func)
16504a49301eSmrg{
165101e04c3fSmrg   bool cannot_be_winsys_fbo = false;
1652af69d88dSmrg
165301e04c3fSmrg   switch (pname) {
165401e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_WIDTH:
165501e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
165601e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_LAYERS:
165701e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
165801e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
165901e04c3fSmrg      if (!ctx->Extensions.ARB_framebuffer_no_attachments)
166001e04c3fSmrg         goto invalid_pname_enum;
166101e04c3fSmrg      cannot_be_winsys_fbo = true;
166201e04c3fSmrg      break;
166301e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
166401e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
166501e04c3fSmrg      if (!ctx->Extensions.ARB_sample_locations)
166601e04c3fSmrg         goto invalid_pname_enum;
166701e04c3fSmrg      break;
166801e04c3fSmrg   case GL_FRAMEBUFFER_FLIP_Y_MESA:
166901e04c3fSmrg      if (!ctx->Extensions.MESA_framebuffer_flip_y)
167001e04c3fSmrg         goto invalid_pname_enum;
167101e04c3fSmrg      cannot_be_winsys_fbo = true;
167201e04c3fSmrg      break;
167301e04c3fSmrg   default:
167401e04c3fSmrg      goto invalid_pname_enum;
167501e04c3fSmrg   }
167601e04c3fSmrg
167701e04c3fSmrg   if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) {
167801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
167901e04c3fSmrg                  "%s(invalid pname=0x%x for default framebuffer)", func, pname);
168001e04c3fSmrg      return;
168101e04c3fSmrg   }
168201e04c3fSmrg
168301e04c3fSmrg   switch (pname) {
168401e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_WIDTH:
168501e04c3fSmrg      if (param < 0 || param > ctx->Const.MaxFramebufferWidth)
168601e04c3fSmrg        _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
168701e04c3fSmrg      else
168801e04c3fSmrg         fb->DefaultGeometry.Width = param;
168901e04c3fSmrg      break;
169001e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
169101e04c3fSmrg      if (param < 0 || param > ctx->Const.MaxFramebufferHeight)
169201e04c3fSmrg        _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
169301e04c3fSmrg      else
169401e04c3fSmrg         fb->DefaultGeometry.Height = param;
169501e04c3fSmrg      break;
169601e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_LAYERS:
169701e04c3fSmrg     /*
169801e04c3fSmrg      * According to the OpenGL ES 3.1 specification section 9.2.1, the
169901e04c3fSmrg      * GL_FRAMEBUFFER_DEFAULT_LAYERS parameter name is not supported.
170001e04c3fSmrg      */
170101e04c3fSmrg      if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) {
170201e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
170301e04c3fSmrg         break;
17044a49301eSmrg      }
170501e04c3fSmrg      if (param < 0 || param > ctx->Const.MaxFramebufferLayers)
170601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
170701e04c3fSmrg      else
170801e04c3fSmrg         fb->DefaultGeometry.Layers = param;
170901e04c3fSmrg      break;
171001e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
171101e04c3fSmrg      if (param < 0 || param > ctx->Const.MaxFramebufferSamples)
171201e04c3fSmrg        _mesa_error(ctx, GL_INVALID_VALUE, "%s", func);
171301e04c3fSmrg      else
171401e04c3fSmrg        fb->DefaultGeometry.NumSamples = param;
171501e04c3fSmrg      break;
171601e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
171701e04c3fSmrg      fb->DefaultGeometry.FixedSampleLocations = param;
171801e04c3fSmrg      break;
171901e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
172001e04c3fSmrg      fb->ProgrammableSampleLocations = !!param;
172101e04c3fSmrg      break;
172201e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
172301e04c3fSmrg      fb->SampleLocationPixelGrid = !!param;
172401e04c3fSmrg      break;
172501e04c3fSmrg   case GL_FRAMEBUFFER_FLIP_Y_MESA:
172601e04c3fSmrg      fb->FlipY = param;
172701e04c3fSmrg      break;
17284a49301eSmrg   }
1729af69d88dSmrg
173001e04c3fSmrg   switch (pname) {
173101e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
173201e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
173301e04c3fSmrg      if (fb == ctx->DrawBuffer)
173401e04c3fSmrg         ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
173501e04c3fSmrg      break;
173601e04c3fSmrg   default:
1737af69d88dSmrg      invalidate_framebuffer(fb);
173801e04c3fSmrg      ctx->NewState |= _NEW_BUFFERS;
173901e04c3fSmrg      break;
174001e04c3fSmrg   }
1741af69d88dSmrg
174201e04c3fSmrg   return;
17434a49301eSmrg
174401e04c3fSmrginvalid_pname_enum:
174501e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
174601e04c3fSmrg}
17474a49301eSmrg
17487ec681f3Smrgstatic bool
17497ec681f3Smrgvalidate_framebuffer_parameter_extensions(GLenum pname, const char *func)
17507ec681f3Smrg{
17517ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
17527ec681f3Smrg
17537ec681f3Smrg   if (!ctx->Extensions.ARB_framebuffer_no_attachments &&
17547ec681f3Smrg       !ctx->Extensions.ARB_sample_locations &&
17557ec681f3Smrg       !ctx->Extensions.MESA_framebuffer_flip_y) {
17567ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
17577ec681f3Smrg                  "%s not supported "
17587ec681f3Smrg                  "(none of ARB_framebuffer_no_attachments,"
17597ec681f3Smrg                  " ARB_sample_locations, or"
17607ec681f3Smrg                  " MESA_framebuffer_flip_y extensions are available)",
17617ec681f3Smrg                  func);
17627ec681f3Smrg      return false;
17637ec681f3Smrg   }
17647ec681f3Smrg
17657ec681f3Smrg   /*
17667ec681f3Smrg    * If only the MESA_framebuffer_flip_y extension is enabled
17677ec681f3Smrg    * pname can only be GL_FRAMEBUFFER_FLIP_Y_MESA
17687ec681f3Smrg    */
17697ec681f3Smrg   if (ctx->Extensions.MESA_framebuffer_flip_y &&
17707ec681f3Smrg       pname != GL_FRAMEBUFFER_FLIP_Y_MESA &&
17717ec681f3Smrg       !(ctx->Extensions.ARB_framebuffer_no_attachments ||
17727ec681f3Smrg         ctx->Extensions.ARB_sample_locations)) {
17737ec681f3Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
17747ec681f3Smrg      return false;
17757ec681f3Smrg   }
17767ec681f3Smrg
17777ec681f3Smrg   return true;
17787ec681f3Smrg}
17797ec681f3Smrg
17807117f1b4Smrgvoid GLAPIENTRY
178101e04c3fSmrg_mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param)
17827117f1b4Smrg{
17837117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
178401e04c3fSmrg   struct gl_framebuffer *fb;
17857117f1b4Smrg
17867ec681f3Smrg   if (!validate_framebuffer_parameter_extensions(pname,
17877ec681f3Smrg       "glFramebufferParameteri")) {
178801e04c3fSmrg      return;
178901e04c3fSmrg   }
17907117f1b4Smrg
179101e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
179201e04c3fSmrg   if (!fb) {
179301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
179401e04c3fSmrg                  "glFramebufferParameteri(target=0x%x)", target);
179501e04c3fSmrg      return;
179601e04c3fSmrg   }
17977117f1b4Smrg
179801e04c3fSmrg   framebuffer_parameteri(ctx, fb, pname, param, "glFramebufferParameteri");
179901e04c3fSmrg}
180001e04c3fSmrg
18017ec681f3Smrgvoid GLAPIENTRY
18027ec681f3Smrg_mesa_FramebufferParameteriMESA(GLenum target, GLenum pname, GLint param)
18037ec681f3Smrg{
18047ec681f3Smrg   _mesa_FramebufferParameteri(target, pname, param);
18057ec681f3Smrg}
18067ec681f3Smrg
180701e04c3fSmrgstatic bool
180801e04c3fSmrgvalidate_get_framebuffer_parameteriv_pname(struct gl_context *ctx,
180901e04c3fSmrg                                           struct gl_framebuffer *fb,
181001e04c3fSmrg                                           GLuint pname, const char *func)
181101e04c3fSmrg{
181201e04c3fSmrg   bool cannot_be_winsys_fbo = true;
181301e04c3fSmrg
181401e04c3fSmrg   switch (pname) {
181501e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_LAYERS:
181601e04c3fSmrg      /*
181701e04c3fSmrg       * According to the OpenGL ES 3.1 specification section 9.2.3, the
181801e04c3fSmrg       * GL_FRAMEBUFFER_LAYERS parameter name is not supported.
181901e04c3fSmrg       */
182001e04c3fSmrg      if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) {
182101e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
182201e04c3fSmrg         return false;
182301e04c3fSmrg      }
182401e04c3fSmrg      break;
182501e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_WIDTH:
182601e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
182701e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
182801e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
182901e04c3fSmrg      break;
183001e04c3fSmrg   case GL_DOUBLEBUFFER:
183101e04c3fSmrg   case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
183201e04c3fSmrg   case GL_IMPLEMENTATION_COLOR_READ_TYPE:
183301e04c3fSmrg   case GL_SAMPLES:
183401e04c3fSmrg   case GL_SAMPLE_BUFFERS:
183501e04c3fSmrg   case GL_STEREO:
183601e04c3fSmrg      /* From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries:
183701e04c3fSmrg       *
183801e04c3fSmrg       *    "An INVALID_OPERATION error is generated by GetFramebufferParameteriv
183901e04c3fSmrg       *     if the default framebuffer is bound to target and pname is not one
184001e04c3fSmrg       *     of the accepted values from table 23.73, other than
184101e04c3fSmrg       *     SAMPLE_POSITION."
184201e04c3fSmrg       *
184301e04c3fSmrg       * For OpenGL ES, using default framebuffer raises INVALID_OPERATION
184401e04c3fSmrg       * for any pname.
184501e04c3fSmrg       */
184601e04c3fSmrg      cannot_be_winsys_fbo = !_mesa_is_desktop_gl(ctx);
184701e04c3fSmrg      break;
184801e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
184901e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
185001e04c3fSmrg      if (!ctx->Extensions.ARB_sample_locations)
185101e04c3fSmrg         goto invalid_pname_enum;
185201e04c3fSmrg      cannot_be_winsys_fbo = false;
185301e04c3fSmrg      break;
185401e04c3fSmrg   case GL_FRAMEBUFFER_FLIP_Y_MESA:
185501e04c3fSmrg      if (!ctx->Extensions.MESA_framebuffer_flip_y) {
185601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
185701e04c3fSmrg         return false;
185801e04c3fSmrg      }
185901e04c3fSmrg      break;
186001e04c3fSmrg   default:
186101e04c3fSmrg      goto invalid_pname_enum;
186201e04c3fSmrg   }
186301e04c3fSmrg
186401e04c3fSmrg   if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) {
186501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
186601e04c3fSmrg                  "%s(invalid pname=0x%x for default framebuffer)", func, pname);
186701e04c3fSmrg      return false;
186801e04c3fSmrg   }
186901e04c3fSmrg
187001e04c3fSmrg   return true;
187101e04c3fSmrg
187201e04c3fSmrginvalid_pname_enum:
187301e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
187401e04c3fSmrg   return false;
187501e04c3fSmrg}
187601e04c3fSmrg
187701e04c3fSmrgstatic void
187801e04c3fSmrgget_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb,
187901e04c3fSmrg                            GLenum pname, GLint *params, const char *func)
188001e04c3fSmrg{
188101e04c3fSmrg   if (!validate_get_framebuffer_parameteriv_pname(ctx, fb, pname, func))
188201e04c3fSmrg      return;
188301e04c3fSmrg
188401e04c3fSmrg   switch (pname) {
188501e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_WIDTH:
188601e04c3fSmrg      *params = fb->DefaultGeometry.Width;
188701e04c3fSmrg      break;
188801e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
188901e04c3fSmrg      *params = fb->DefaultGeometry.Height;
189001e04c3fSmrg      break;
189101e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_LAYERS:
189201e04c3fSmrg      *params = fb->DefaultGeometry.Layers;
189301e04c3fSmrg      break;
189401e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
189501e04c3fSmrg      *params = fb->DefaultGeometry.NumSamples;
189601e04c3fSmrg      break;
189701e04c3fSmrg   case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
189801e04c3fSmrg      *params = fb->DefaultGeometry.FixedSampleLocations;
189901e04c3fSmrg      break;
190001e04c3fSmrg   case GL_DOUBLEBUFFER:
190101e04c3fSmrg      *params = fb->Visual.doubleBufferMode;
190201e04c3fSmrg      break;
190301e04c3fSmrg   case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
190401e04c3fSmrg      *params = _mesa_get_color_read_format(ctx, fb, func);
190501e04c3fSmrg      break;
190601e04c3fSmrg   case GL_IMPLEMENTATION_COLOR_READ_TYPE:
190701e04c3fSmrg      *params = _mesa_get_color_read_type(ctx, fb, func);
190801e04c3fSmrg      break;
190901e04c3fSmrg   case GL_SAMPLES:
191001e04c3fSmrg      *params = _mesa_geometric_samples(fb);
191101e04c3fSmrg      break;
191201e04c3fSmrg   case GL_SAMPLE_BUFFERS:
191301e04c3fSmrg      *params = _mesa_geometric_samples(fb) > 0;
191401e04c3fSmrg      break;
191501e04c3fSmrg   case GL_STEREO:
191601e04c3fSmrg      *params = fb->Visual.stereoMode;
191701e04c3fSmrg      break;
191801e04c3fSmrg   case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
191901e04c3fSmrg      *params = fb->ProgrammableSampleLocations;
192001e04c3fSmrg      break;
192101e04c3fSmrg   case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
192201e04c3fSmrg      *params = fb->SampleLocationPixelGrid;
192301e04c3fSmrg      break;
192401e04c3fSmrg   case GL_FRAMEBUFFER_FLIP_Y_MESA:
192501e04c3fSmrg      *params = fb->FlipY;
192601e04c3fSmrg      break;
192701e04c3fSmrg   }
192801e04c3fSmrg}
192901e04c3fSmrg
193001e04c3fSmrgvoid GLAPIENTRY
193101e04c3fSmrg_mesa_GetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params)
193201e04c3fSmrg{
193301e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
193401e04c3fSmrg   struct gl_framebuffer *fb;
193501e04c3fSmrg
19367ec681f3Smrg   if (!validate_framebuffer_parameter_extensions(pname,
19377ec681f3Smrg       "glGetFramebufferParameteriv")) {
193801e04c3fSmrg      return;
193901e04c3fSmrg   }
194001e04c3fSmrg
194101e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
194201e04c3fSmrg   if (!fb) {
194301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
194401e04c3fSmrg                  "glGetFramebufferParameteriv(target=0x%x)", target);
194501e04c3fSmrg      return;
194601e04c3fSmrg   }
194701e04c3fSmrg
194801e04c3fSmrg   get_framebuffer_parameteriv(ctx, fb, pname, params,
194901e04c3fSmrg                               "glGetFramebufferParameteriv");
195001e04c3fSmrg}
195101e04c3fSmrg
19527ec681f3Smrgvoid GLAPIENTRY
19537ec681f3Smrg_mesa_GetFramebufferParameterivMESA(GLenum target, GLenum pname, GLint *params)
19547ec681f3Smrg{
19557ec681f3Smrg   _mesa_GetFramebufferParameteriv(target, pname, params);
19567ec681f3Smrg}
195701e04c3fSmrg
195801e04c3fSmrg/**
195901e04c3fSmrg * Remove the specified renderbuffer or texture from any attachment point in
196001e04c3fSmrg * the framebuffer.
196101e04c3fSmrg *
196201e04c3fSmrg * \returns
196301e04c3fSmrg * \c true if the renderbuffer was detached from an attachment point.  \c
196401e04c3fSmrg * false otherwise.
196501e04c3fSmrg */
196601e04c3fSmrgbool
196701e04c3fSmrg_mesa_detach_renderbuffer(struct gl_context *ctx,
196801e04c3fSmrg                          struct gl_framebuffer *fb,
196901e04c3fSmrg                          const void *att)
197001e04c3fSmrg{
197101e04c3fSmrg   unsigned i;
197201e04c3fSmrg   bool progress = false;
197301e04c3fSmrg
197401e04c3fSmrg   for (i = 0; i < BUFFER_COUNT; i++) {
197501e04c3fSmrg      if (fb->Attachment[i].Texture == att
197601e04c3fSmrg          || fb->Attachment[i].Renderbuffer == att) {
197701e04c3fSmrg         remove_attachment(ctx, &fb->Attachment[i]);
197801e04c3fSmrg         progress = true;
197901e04c3fSmrg      }
198001e04c3fSmrg   }
198101e04c3fSmrg
198201e04c3fSmrg   /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer
198301e04c3fSmrg    * Completeness," of the OpenGL 3.1 spec says:
198401e04c3fSmrg    *
198501e04c3fSmrg    *     "Performing any of the following actions may change whether the
198601e04c3fSmrg    *     framebuffer is considered complete or incomplete:
198701e04c3fSmrg    *
198801e04c3fSmrg    *     ...
198901e04c3fSmrg    *
199001e04c3fSmrg    *        - Deleting, with DeleteTextures or DeleteRenderbuffers, an object
199101e04c3fSmrg    *          containing an image that is attached to a framebuffer object
199201e04c3fSmrg    *          that is bound to the framebuffer."
199301e04c3fSmrg    */
199401e04c3fSmrg   if (progress)
199501e04c3fSmrg      invalidate_framebuffer(fb);
199601e04c3fSmrg
199701e04c3fSmrg   return progress;
199801e04c3fSmrg}
199901e04c3fSmrg
200001e04c3fSmrg
200101e04c3fSmrgvoid GLAPIENTRY
200201e04c3fSmrg_mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers)
200301e04c3fSmrg{
200401e04c3fSmrg   GLint i;
200501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
200601e04c3fSmrg
200701e04c3fSmrg   if (n < 0) {
200801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteRenderbuffers(n < 0)");
200901e04c3fSmrg      return;
201001e04c3fSmrg   }
201101e04c3fSmrg
20127ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
201301e04c3fSmrg
201401e04c3fSmrg   for (i = 0; i < n; i++) {
201501e04c3fSmrg      if (renderbuffers[i] > 0) {
201601e04c3fSmrg         struct gl_renderbuffer *rb;
201701e04c3fSmrg         rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
201801e04c3fSmrg         if (rb) {
201901e04c3fSmrg            /* check if deleting currently bound renderbuffer object */
202001e04c3fSmrg            if (rb == ctx->CurrentRenderbuffer) {
202101e04c3fSmrg               /* bind default */
202201e04c3fSmrg               assert(rb->RefCount >= 2);
202301e04c3fSmrg               _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
202401e04c3fSmrg            }
202501e04c3fSmrg
202601e04c3fSmrg            /* Section 4.4.2 (Attaching Images to Framebuffer Objects),
202701e04c3fSmrg             * subsection "Attaching Renderbuffer Images to a Framebuffer,"
202801e04c3fSmrg             * of the OpenGL 3.1 spec says:
202901e04c3fSmrg             *
203001e04c3fSmrg             *     "If a renderbuffer object is deleted while its image is
203101e04c3fSmrg             *     attached to one or more attachment points in the currently
203201e04c3fSmrg             *     bound framebuffer, then it is as if FramebufferRenderbuffer
203301e04c3fSmrg             *     had been called, with a renderbuffer of 0, for each
203401e04c3fSmrg             *     attachment point to which this image was attached in the
203501e04c3fSmrg             *     currently bound framebuffer. In other words, this
203601e04c3fSmrg             *     renderbuffer image is first detached from all attachment
203701e04c3fSmrg             *     points in the currently bound framebuffer. Note that the
203801e04c3fSmrg             *     renderbuffer image is specifically not detached from any
203901e04c3fSmrg             *     non-bound framebuffers. Detaching the image from any
204001e04c3fSmrg             *     non-bound framebuffers is the responsibility of the
2041af69d88dSmrg             *     application.
2042af69d88dSmrg             */
2043af69d88dSmrg            if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
2044af69d88dSmrg               _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
20454a49301eSmrg            }
2046af69d88dSmrg            if (_mesa_is_user_fbo(ctx->ReadBuffer)
20473464ebd5Sriastradh                && ctx->ReadBuffer != ctx->DrawBuffer) {
2048af69d88dSmrg               _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
20494a49301eSmrg            }
20504a49301eSmrg
205101e04c3fSmrg            /* Remove from hash table immediately, to free the ID.
20527117f1b4Smrg             * But the object will not be freed until it's no longer
20537117f1b4Smrg             * referenced anywhere else.
20547117f1b4Smrg             */
205501e04c3fSmrg            _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
20567117f1b4Smrg
20577117f1b4Smrg            if (rb != &DummyRenderbuffer) {
20587117f1b4Smrg               /* no longer referenced by hash table */
20597117f1b4Smrg               _mesa_reference_renderbuffer(&rb, NULL);
206001e04c3fSmrg            }
206101e04c3fSmrg         }
20627117f1b4Smrg      }
20637117f1b4Smrg   }
20647117f1b4Smrg}
20657117f1b4Smrg
206601e04c3fSmrgstatic void
206701e04c3fSmrgcreate_render_buffers(struct gl_context *ctx, GLsizei n, GLuint *renderbuffers,
206801e04c3fSmrg                      bool dsa)
20697117f1b4Smrg{
207001e04c3fSmrg   const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers";
20717117f1b4Smrg   GLint i;
20727117f1b4Smrg
20737117f1b4Smrg   if (!renderbuffers)
20747117f1b4Smrg      return;
20757117f1b4Smrg
207601e04c3fSmrg   _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
207701e04c3fSmrg
20787ec681f3Smrg   _mesa_HashFindFreeKeys(ctx->Shared->RenderBuffers, renderbuffers, n);
20797117f1b4Smrg
20807117f1b4Smrg   for (i = 0; i < n; i++) {
208101e04c3fSmrg      if (dsa) {
20827ec681f3Smrg         allocate_renderbuffer_locked(ctx, renderbuffers[i], true, func);
208301e04c3fSmrg      } else {
208401e04c3fSmrg         /* insert a dummy renderbuffer into the hash table */
20857ec681f3Smrg         _mesa_HashInsertLocked(ctx->Shared->RenderBuffers, renderbuffers[i],
20867ec681f3Smrg                                &DummyRenderbuffer, true);
208701e04c3fSmrg      }
208801e04c3fSmrg   }
208901e04c3fSmrg
209001e04c3fSmrg   _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
209101e04c3fSmrg}
209201e04c3fSmrg
209301e04c3fSmrg
209401e04c3fSmrgstatic void
209501e04c3fSmrgcreate_render_buffers_err(struct gl_context *ctx, GLsizei n,
209601e04c3fSmrg                          GLuint *renderbuffers, bool dsa)
209701e04c3fSmrg{
209801e04c3fSmrg   const char *func = dsa ? "glCreateRenderbuffers" : "glGenRenderbuffers";
209901e04c3fSmrg
210001e04c3fSmrg   if (n < 0) {
210101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", func);
210201e04c3fSmrg      return;
21037117f1b4Smrg   }
210401e04c3fSmrg
210501e04c3fSmrg   create_render_buffers(ctx, n, renderbuffers, dsa);
210601e04c3fSmrg}
210701e04c3fSmrg
210801e04c3fSmrg
210901e04c3fSmrgvoid GLAPIENTRY
211001e04c3fSmrg_mesa_GenRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers)
211101e04c3fSmrg{
211201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
211301e04c3fSmrg   create_render_buffers(ctx, n, renderbuffers, false);
211401e04c3fSmrg}
211501e04c3fSmrg
211601e04c3fSmrg
211701e04c3fSmrgvoid GLAPIENTRY
211801e04c3fSmrg_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers)
211901e04c3fSmrg{
212001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
212101e04c3fSmrg   create_render_buffers_err(ctx, n, renderbuffers, false);
212201e04c3fSmrg}
212301e04c3fSmrg
212401e04c3fSmrg
212501e04c3fSmrgvoid GLAPIENTRY
212601e04c3fSmrg_mesa_CreateRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers)
212701e04c3fSmrg{
212801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
212901e04c3fSmrg   create_render_buffers(ctx, n, renderbuffers, true);
213001e04c3fSmrg}
213101e04c3fSmrg
213201e04c3fSmrg
213301e04c3fSmrgvoid GLAPIENTRY
213401e04c3fSmrg_mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers)
213501e04c3fSmrg{
213601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
213701e04c3fSmrg   create_render_buffers_err(ctx, n, renderbuffers, true);
21387117f1b4Smrg}
21397117f1b4Smrg
21407117f1b4Smrg
21417117f1b4Smrg/**
21427117f1b4Smrg * Given an internal format token for a render buffer, return the
21433464ebd5Sriastradh * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
21443464ebd5Sriastradh * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE,
21453464ebd5Sriastradh * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc).
21467117f1b4Smrg *
21473464ebd5Sriastradh * This is similar to _mesa_base_tex_format() but the set of valid
21483464ebd5Sriastradh * internal formats is different.
2149cdc920a0Smrg *
21503464ebd5Sriastradh * Note that even if a format is determined to be legal here, validation
21513464ebd5Sriastradh * of the FBO may fail if the format is not supported by the driver/GPU.
21523464ebd5Sriastradh *
21533464ebd5Sriastradh * \param internalFormat  as passed to glRenderbufferStorage()
21543464ebd5Sriastradh * \return the base internal format, or 0 if internalFormat is illegal
21557117f1b4Smrg */
21567117f1b4SmrgGLenum
215701e04c3fSmrg_mesa_base_fbo_format(const struct gl_context *ctx, GLenum internalFormat)
21587117f1b4Smrg{
21593464ebd5Sriastradh   /*
21603464ebd5Sriastradh    * Notes: some formats such as alpha, luminance, etc. were added
21613464ebd5Sriastradh    * with GL_ARB_framebuffer_object.
21623464ebd5Sriastradh    */
21637117f1b4Smrg   switch (internalFormat) {
21643464ebd5Sriastradh   case GL_ALPHA:
21653464ebd5Sriastradh   case GL_ALPHA4:
21663464ebd5Sriastradh   case GL_ALPHA8:
21673464ebd5Sriastradh   case GL_ALPHA12:
21683464ebd5Sriastradh   case GL_ALPHA16:
2169af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
2170af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_ALPHA : 0;
21713464ebd5Sriastradh   case GL_LUMINANCE:
21723464ebd5Sriastradh   case GL_LUMINANCE4:
21733464ebd5Sriastradh   case GL_LUMINANCE8:
21743464ebd5Sriastradh   case GL_LUMINANCE12:
21753464ebd5Sriastradh   case GL_LUMINANCE16:
2176af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
2177af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE : 0;
21783464ebd5Sriastradh   case GL_LUMINANCE_ALPHA:
21793464ebd5Sriastradh   case GL_LUMINANCE4_ALPHA4:
21803464ebd5Sriastradh   case GL_LUMINANCE6_ALPHA2:
21813464ebd5Sriastradh   case GL_LUMINANCE8_ALPHA8:
21823464ebd5Sriastradh   case GL_LUMINANCE12_ALPHA4:
21833464ebd5Sriastradh   case GL_LUMINANCE12_ALPHA12:
21843464ebd5Sriastradh   case GL_LUMINANCE16_ALPHA16:
2185af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
2186af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_LUMINANCE_ALPHA : 0;
21873464ebd5Sriastradh   case GL_INTENSITY:
21883464ebd5Sriastradh   case GL_INTENSITY4:
21893464ebd5Sriastradh   case GL_INTENSITY8:
21903464ebd5Sriastradh   case GL_INTENSITY12:
21913464ebd5Sriastradh   case GL_INTENSITY16:
2192af69d88dSmrg      return (ctx->API == API_OPENGL_COMPAT &&
2193af69d88dSmrg              ctx->Extensions.ARB_framebuffer_object) ? GL_INTENSITY : 0;
2194af69d88dSmrg   case GL_RGB8:
2195af69d88dSmrg      return GL_RGB;
21967117f1b4Smrg   case GL_RGB:
21977117f1b4Smrg   case GL_R3_G3_B2:
21987117f1b4Smrg   case GL_RGB4:
21997117f1b4Smrg   case GL_RGB5:
22007117f1b4Smrg   case GL_RGB10:
22017117f1b4Smrg   case GL_RGB12:
22027117f1b4Smrg   case GL_RGB16:
2203af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0;
22043464ebd5Sriastradh   case GL_SRGB8_EXT:
2205af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0;
22067117f1b4Smrg   case GL_RGBA4:
22077117f1b4Smrg   case GL_RGB5_A1:
22087117f1b4Smrg   case GL_RGBA8:
2209af69d88dSmrg      return GL_RGBA;
2210af69d88dSmrg   case GL_RGBA:
2211af69d88dSmrg   case GL_RGBA2:
22127117f1b4Smrg   case GL_RGBA12:
2213af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0;
221401e04c3fSmrg   case GL_RGBA16:
221501e04c3fSmrg      return _mesa_is_desktop_gl(ctx) || _mesa_has_EXT_texture_norm16(ctx)
221601e04c3fSmrg         ? GL_RGBA : 0;
2217af69d88dSmrg   case GL_RGB10_A2:
22183464ebd5Sriastradh   case GL_SRGB8_ALPHA8_EXT:
2219af69d88dSmrg      return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0;
22207117f1b4Smrg   case GL_STENCIL_INDEX:
22217117f1b4Smrg   case GL_STENCIL_INDEX1_EXT:
22227117f1b4Smrg   case GL_STENCIL_INDEX4_EXT:
22237117f1b4Smrg   case GL_STENCIL_INDEX16_EXT:
2224af69d88dSmrg      /* There are extensions for GL_STENCIL_INDEX1 and GL_STENCIL_INDEX4 in
2225af69d88dSmrg       * OpenGL ES, but Mesa does not currently support them.
2226af69d88dSmrg       */
2227af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_STENCIL_INDEX : 0;
2228af69d88dSmrg   case GL_STENCIL_INDEX8_EXT:
22297117f1b4Smrg      return GL_STENCIL_INDEX;
22307117f1b4Smrg   case GL_DEPTH_COMPONENT:
2231af69d88dSmrg   case GL_DEPTH_COMPONENT32:
2232af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_COMPONENT : 0;
22337117f1b4Smrg   case GL_DEPTH_COMPONENT16:
22347117f1b4Smrg   case GL_DEPTH_COMPONENT24:
22357117f1b4Smrg      return GL_DEPTH_COMPONENT;
2236af69d88dSmrg   case GL_DEPTH_STENCIL:
2237af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_STENCIL : 0;
2238af69d88dSmrg   case GL_DEPTH24_STENCIL8:
2239af69d88dSmrg      return GL_DEPTH_STENCIL;
2240af69d88dSmrg   case GL_DEPTH_COMPONENT32F:
2241af69d88dSmrg      return ctx->Version >= 30
2242af69d88dSmrg         || (ctx->API == API_OPENGL_COMPAT &&
2243af69d88dSmrg             ctx->Extensions.ARB_depth_buffer_float)
2244af69d88dSmrg         ? GL_DEPTH_COMPONENT : 0;
2245af69d88dSmrg   case GL_DEPTH32F_STENCIL8:
2246af69d88dSmrg      return ctx->Version >= 30
2247af69d88dSmrg         || (ctx->API == API_OPENGL_COMPAT &&
2248af69d88dSmrg             ctx->Extensions.ARB_depth_buffer_float)
2249af69d88dSmrg         ? GL_DEPTH_STENCIL : 0;
22503464ebd5Sriastradh   case GL_RED:
225101e04c3fSmrg      return _mesa_has_ARB_texture_rg(ctx) ? GL_RED : 0;
22523464ebd5Sriastradh   case GL_R16:
225301e04c3fSmrg      return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx)
2254af69d88dSmrg         ? GL_RED : 0;
2255af69d88dSmrg   case GL_R8:
2256af69d88dSmrg      return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
2257af69d88dSmrg         ? GL_RED : 0;
22583464ebd5Sriastradh   case GL_RG:
225901e04c3fSmrg      return _mesa_has_ARB_texture_rg(ctx) ? GL_RG : 0;
22603464ebd5Sriastradh   case GL_RG16:
226101e04c3fSmrg      return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx)
2262af69d88dSmrg         ? GL_RG : 0;
2263af69d88dSmrg   case GL_RG8:
2264af69d88dSmrg      return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
2265af69d88dSmrg         ? GL_RG : 0;
22663464ebd5Sriastradh   /* signed normalized texture formats */
22673464ebd5Sriastradh   case GL_R8_SNORM:
226801e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx)
226901e04c3fSmrg         ? GL_RED : 0;
227001e04c3fSmrg   case GL_RED_SNORM:
227101e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ? GL_RED : 0;
22723464ebd5Sriastradh   case GL_R16_SNORM:
227301e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ||
227401e04c3fSmrg             (_mesa_has_EXT_render_snorm(ctx) &&
227501e04c3fSmrg              _mesa_has_EXT_texture_norm16(ctx))
2276af69d88dSmrg         ? GL_RED : 0;
22773464ebd5Sriastradh   case GL_RG8_SNORM:
227801e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx)
227901e04c3fSmrg         ? GL_RG : 0;
228001e04c3fSmrg   case GL_RG_SNORM:
228101e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ? GL_RG : 0;
22823464ebd5Sriastradh   case GL_RG16_SNORM:
228301e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ||
228401e04c3fSmrg             (_mesa_has_EXT_render_snorm(ctx) &&
228501e04c3fSmrg              _mesa_has_EXT_texture_norm16(ctx))
2286af69d88dSmrg         ? GL_RG : 0;
22873464ebd5Sriastradh   case GL_RGB_SNORM:
22883464ebd5Sriastradh   case GL_RGB8_SNORM:
22893464ebd5Sriastradh   case GL_RGB16_SNORM:
2290af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
2291af69d88dSmrg         ? GL_RGB : 0;
22923464ebd5Sriastradh   case GL_RGBA8_SNORM:
229301e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx)
229401e04c3fSmrg         ? GL_RGBA : 0;
229501e04c3fSmrg   case GL_RGBA_SNORM:
229601e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ? GL_RGBA : 0;
22973464ebd5Sriastradh   case GL_RGBA16_SNORM:
229801e04c3fSmrg      return _mesa_has_EXT_texture_snorm(ctx) ||
229901e04c3fSmrg             (_mesa_has_EXT_render_snorm(ctx) &&
230001e04c3fSmrg              _mesa_has_EXT_texture_norm16(ctx))
2301af69d88dSmrg         ? GL_RGBA : 0;
23023464ebd5Sriastradh   case GL_ALPHA_SNORM:
23033464ebd5Sriastradh   case GL_ALPHA8_SNORM:
23043464ebd5Sriastradh   case GL_ALPHA16_SNORM:
2305af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2306af69d88dSmrg             ctx->Extensions.EXT_texture_snorm &&
23073464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
23083464ebd5Sriastradh   case GL_LUMINANCE_SNORM:
23093464ebd5Sriastradh   case GL_LUMINANCE8_SNORM:
23103464ebd5Sriastradh   case GL_LUMINANCE16_SNORM:
2311af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
2312af69d88dSmrg         ? GL_LUMINANCE : 0;
23133464ebd5Sriastradh   case GL_LUMINANCE_ALPHA_SNORM:
23143464ebd5Sriastradh   case GL_LUMINANCE8_ALPHA8_SNORM:
23153464ebd5Sriastradh   case GL_LUMINANCE16_ALPHA16_SNORM:
2316af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
2317af69d88dSmrg         ? GL_LUMINANCE_ALPHA : 0;
23183464ebd5Sriastradh   case GL_INTENSITY_SNORM:
23193464ebd5Sriastradh   case GL_INTENSITY8_SNORM:
23203464ebd5Sriastradh   case GL_INTENSITY16_SNORM:
2321af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
2322af69d88dSmrg         ? GL_INTENSITY : 0;
2323af69d88dSmrg
23243464ebd5Sriastradh   case GL_R16F:
23257ec681f3Smrg      return ((_mesa_is_desktop_gl(ctx) &&
23267ec681f3Smrg               ctx->Extensions.ARB_texture_rg &&
23277ec681f3Smrg               ctx->Extensions.ARB_texture_float) ||
23287ec681f3Smrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ||
23297ec681f3Smrg              (_mesa_has_EXT_color_buffer_half_float(ctx) &&
23307ec681f3Smrg               _mesa_has_EXT_texture_rg(ctx)))
23317ec681f3Smrg         ? GL_RED : 0;
23323464ebd5Sriastradh   case GL_R32F:
2333af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) &&
2334af69d88dSmrg               ctx->Extensions.ARB_texture_rg &&
2335af69d88dSmrg               ctx->Extensions.ARB_texture_float) ||
2336af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
2337af69d88dSmrg         ? GL_RED : 0;
23383464ebd5Sriastradh   case GL_RG16F:
23397ec681f3Smrg      return ((_mesa_is_desktop_gl(ctx) &&
23407ec681f3Smrg               ctx->Extensions.ARB_texture_rg &&
23417ec681f3Smrg               ctx->Extensions.ARB_texture_float) ||
23427ec681f3Smrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ||
23437ec681f3Smrg              (_mesa_has_EXT_color_buffer_half_float(ctx) &&
23447ec681f3Smrg               _mesa_has_EXT_texture_rg(ctx)))
23457ec681f3Smrg         ? GL_RG : 0;
23463464ebd5Sriastradh   case GL_RG32F:
2347af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) &&
2348af69d88dSmrg               ctx->Extensions.ARB_texture_rg &&
2349af69d88dSmrg               ctx->Extensions.ARB_texture_float) ||
2350af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
2351af69d88dSmrg         ? GL_RG : 0;
23523464ebd5Sriastradh   case GL_RGB16F:
23537ec681f3Smrg      return (_mesa_has_ARB_texture_float(ctx) ||
23547ec681f3Smrg              _mesa_has_EXT_color_buffer_half_float(ctx))
23557ec681f3Smrg         ? GL_RGB : 0;
23563464ebd5Sriastradh   case GL_RGB32F:
2357af69d88dSmrg      return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float)
2358af69d88dSmrg         ? GL_RGB : 0;
23593464ebd5Sriastradh   case GL_RGBA16F:
23607ec681f3Smrg      return (_mesa_has_ARB_texture_float(ctx) ||
23617ec681f3Smrg              _mesa_is_gles3(ctx) ||
23627ec681f3Smrg              _mesa_has_EXT_color_buffer_half_float(ctx))
23637ec681f3Smrg         ? GL_RGBA : 0;
23643464ebd5Sriastradh   case GL_RGBA32F:
2365af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) &&
2366af69d88dSmrg               ctx->Extensions.ARB_texture_float) ||
2367af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
2368af69d88dSmrg         ? GL_RGBA : 0;
236901e04c3fSmrg   case GL_RGB9_E5:
237001e04c3fSmrg      return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_shared_exponent)
237101e04c3fSmrg         ? GL_RGB: 0;
23723464ebd5Sriastradh   case GL_ALPHA16F_ARB:
23733464ebd5Sriastradh   case GL_ALPHA32F_ARB:
2374af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2375af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
23763464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
23773464ebd5Sriastradh   case GL_LUMINANCE16F_ARB:
23783464ebd5Sriastradh   case GL_LUMINANCE32F_ARB:
2379af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2380af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
23813464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
23823464ebd5Sriastradh   case GL_LUMINANCE_ALPHA16F_ARB:
23833464ebd5Sriastradh   case GL_LUMINANCE_ALPHA32F_ARB:
2384af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2385af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
23863464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
23873464ebd5Sriastradh   case GL_INTENSITY16F_ARB:
23883464ebd5Sriastradh   case GL_INTENSITY32F_ARB:
2389af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2390af69d88dSmrg             ctx->Extensions.ARB_texture_float &&
23913464ebd5Sriastradh             ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
23923464ebd5Sriastradh   case GL_R11F_G11F_B10F:
2393af69d88dSmrg      return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) ||
2394af69d88dSmrg              _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
2395af69d88dSmrg         ? GL_RGB : 0;
2396af69d88dSmrg
2397af69d88dSmrg   case GL_RGBA8UI_EXT:
2398af69d88dSmrg   case GL_RGBA16UI_EXT:
2399af69d88dSmrg   case GL_RGBA32UI_EXT:
2400af69d88dSmrg   case GL_RGBA8I_EXT:
2401af69d88dSmrg   case GL_RGBA16I_EXT:
2402af69d88dSmrg   case GL_RGBA32I_EXT:
2403af69d88dSmrg      return ctx->Version >= 30
2404af69d88dSmrg         || (_mesa_is_desktop_gl(ctx) &&
2405af69d88dSmrg             ctx->Extensions.EXT_texture_integer) ? GL_RGBA : 0;
2406af69d88dSmrg
2407af69d88dSmrg   case GL_RGB8UI_EXT:
2408af69d88dSmrg   case GL_RGB16UI_EXT:
2409af69d88dSmrg   case GL_RGB32UI_EXT:
2410af69d88dSmrg   case GL_RGB8I_EXT:
2411af69d88dSmrg   case GL_RGB16I_EXT:
2412af69d88dSmrg   case GL_RGB32I_EXT:
2413af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_integer
2414af69d88dSmrg         ? GL_RGB : 0;
2415af69d88dSmrg   case GL_R8UI:
2416af69d88dSmrg   case GL_R8I:
2417af69d88dSmrg   case GL_R16UI:
2418af69d88dSmrg   case GL_R16I:
2419af69d88dSmrg   case GL_R32UI:
2420af69d88dSmrg   case GL_R32I:
2421af69d88dSmrg      return ctx->Version >= 30
2422af69d88dSmrg         || (_mesa_is_desktop_gl(ctx) &&
2423af69d88dSmrg             ctx->Extensions.ARB_texture_rg &&
2424af69d88dSmrg             ctx->Extensions.EXT_texture_integer) ? GL_RED : 0;
2425af69d88dSmrg
2426af69d88dSmrg   case GL_RG8UI:
2427af69d88dSmrg   case GL_RG8I:
2428af69d88dSmrg   case GL_RG16UI:
2429af69d88dSmrg   case GL_RG16I:
2430af69d88dSmrg   case GL_RG32UI:
2431af69d88dSmrg   case GL_RG32I:
2432af69d88dSmrg      return ctx->Version >= 30
2433af69d88dSmrg         || (_mesa_is_desktop_gl(ctx) &&
2434af69d88dSmrg             ctx->Extensions.ARB_texture_rg &&
2435af69d88dSmrg             ctx->Extensions.EXT_texture_integer) ? GL_RG : 0;
2436af69d88dSmrg
2437af69d88dSmrg   case GL_INTENSITY8I_EXT:
2438af69d88dSmrg   case GL_INTENSITY8UI_EXT:
2439af69d88dSmrg   case GL_INTENSITY16I_EXT:
2440af69d88dSmrg   case GL_INTENSITY16UI_EXT:
2441af69d88dSmrg   case GL_INTENSITY32I_EXT:
2442af69d88dSmrg   case GL_INTENSITY32UI_EXT:
2443af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2444af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
2445af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
2446af69d88dSmrg
2447af69d88dSmrg   case GL_LUMINANCE8I_EXT:
2448af69d88dSmrg   case GL_LUMINANCE8UI_EXT:
2449af69d88dSmrg   case GL_LUMINANCE16I_EXT:
2450af69d88dSmrg   case GL_LUMINANCE16UI_EXT:
2451af69d88dSmrg   case GL_LUMINANCE32I_EXT:
2452af69d88dSmrg   case GL_LUMINANCE32UI_EXT:
2453af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2454af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
2455af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
2456af69d88dSmrg
2457af69d88dSmrg   case GL_LUMINANCE_ALPHA8I_EXT:
2458af69d88dSmrg   case GL_LUMINANCE_ALPHA8UI_EXT:
2459af69d88dSmrg   case GL_LUMINANCE_ALPHA16I_EXT:
2460af69d88dSmrg   case GL_LUMINANCE_ALPHA16UI_EXT:
2461af69d88dSmrg   case GL_LUMINANCE_ALPHA32I_EXT:
2462af69d88dSmrg   case GL_LUMINANCE_ALPHA32UI_EXT:
2463af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2464af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
2465af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
2466af69d88dSmrg
2467af69d88dSmrg   case GL_ALPHA8I_EXT:
2468af69d88dSmrg   case GL_ALPHA8UI_EXT:
2469af69d88dSmrg   case GL_ALPHA16I_EXT:
2470af69d88dSmrg   case GL_ALPHA16UI_EXT:
2471af69d88dSmrg   case GL_ALPHA32I_EXT:
2472af69d88dSmrg   case GL_ALPHA32UI_EXT:
2473af69d88dSmrg      return ctx->API == API_OPENGL_COMPAT &&
2474af69d88dSmrg             ctx->Extensions.EXT_texture_integer &&
2475af69d88dSmrg             ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
2476af69d88dSmrg
2477af69d88dSmrg   case GL_RGB10_A2UI:
2478af69d88dSmrg      return (_mesa_is_desktop_gl(ctx) &&
2479af69d88dSmrg              ctx->Extensions.ARB_texture_rgb10_a2ui)
2480af69d88dSmrg         || _mesa_is_gles3(ctx) ? GL_RGBA : 0;
2481af69d88dSmrg
2482af69d88dSmrg   case GL_RGB565:
2483af69d88dSmrg      return _mesa_is_gles(ctx) || ctx->Extensions.ARB_ES2_compatibility
2484af69d88dSmrg         ? GL_RGB : 0;
2485af69d88dSmrg   default:
2486af69d88dSmrg      return 0;
2487af69d88dSmrg   }
24887117f1b4Smrg}
24897117f1b4Smrg
24907117f1b4Smrg
24913464ebd5Sriastradh/**
24923464ebd5Sriastradh * Invalidate a renderbuffer attachment.  Called from _mesa_HashWalk().
24933464ebd5Sriastradh */
24943464ebd5Sriastradhstatic void
24957ec681f3Smrginvalidate_rb(void *data, void *userData)
24963464ebd5Sriastradh{
24973464ebd5Sriastradh   struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
24983464ebd5Sriastradh   struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData;
24993464ebd5Sriastradh
25003464ebd5Sriastradh   /* If this is a user-created FBO */
2501af69d88dSmrg   if (_mesa_is_user_fbo(fb)) {
25023464ebd5Sriastradh      GLuint i;
25033464ebd5Sriastradh      for (i = 0; i < BUFFER_COUNT; i++) {
25043464ebd5Sriastradh         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
25053464ebd5Sriastradh         if (att->Type == GL_RENDERBUFFER &&
25063464ebd5Sriastradh             att->Renderbuffer == rb) {
25073464ebd5Sriastradh            /* Mark fb status as indeterminate to force re-validation */
25083464ebd5Sriastradh            fb->_Status = 0;
25093464ebd5Sriastradh            return;
25103464ebd5Sriastradh         }
25113464ebd5Sriastradh      }
25123464ebd5Sriastradh   }
25133464ebd5Sriastradh}
25143464ebd5Sriastradh
25153464ebd5Sriastradh
25164a49301eSmrg/** sentinal value, see below */
25174a49301eSmrg#define NO_SAMPLES 1000
25184a49301eSmrg
251901e04c3fSmrgvoid
252001e04c3fSmrg_mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
252101e04c3fSmrg                           GLenum internalFormat, GLsizei width,
252201e04c3fSmrg                           GLsizei height, GLsizei samples,
252301e04c3fSmrg                           GLsizei storageSamples)
25247117f1b4Smrg{
252501e04c3fSmrg   const GLenum baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
252601e04c3fSmrg
252701e04c3fSmrg   assert(baseFormat != 0);
252801e04c3fSmrg   assert(width >= 0 && width <= (GLsizei) ctx->Const.MaxRenderbufferSize);
252901e04c3fSmrg   assert(height >= 0 && height <= (GLsizei) ctx->Const.MaxRenderbufferSize);
253001e04c3fSmrg   assert(samples != NO_SAMPLES);
253101e04c3fSmrg   if (samples != 0) {
253201e04c3fSmrg      assert(samples > 0);
253301e04c3fSmrg      assert(_mesa_check_sample_count(ctx, GL_RENDERBUFFER,
253401e04c3fSmrg                                      internalFormat, samples,
253501e04c3fSmrg                                      storageSamples) == GL_NO_ERROR);
25367117f1b4Smrg   }
25377117f1b4Smrg
25387ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
25397117f1b4Smrg
254001e04c3fSmrg   if (rb->InternalFormat == internalFormat &&
254101e04c3fSmrg       rb->Width == (GLuint) width &&
254201e04c3fSmrg       rb->Height == (GLuint) height &&
254301e04c3fSmrg       rb->NumSamples == samples &&
254401e04c3fSmrg       rb->NumStorageSamples == storageSamples) {
254501e04c3fSmrg      /* no change in allocation needed */
25467117f1b4Smrg      return;
25477117f1b4Smrg   }
25487117f1b4Smrg
25497117f1b4Smrg   /* These MUST get set by the AllocStorage func */
25504a49301eSmrg   rb->Format = MESA_FORMAT_NONE;
25514a49301eSmrg   rb->NumSamples = samples;
255201e04c3fSmrg   rb->NumStorageSamples = storageSamples;
25537117f1b4Smrg
25547117f1b4Smrg   /* Now allocate the storage */
255501e04c3fSmrg   assert(rb->AllocStorage);
25567117f1b4Smrg   if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
25577117f1b4Smrg      /* No error - check/set fields now */
2558af69d88dSmrg      /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */
25597117f1b4Smrg      assert(rb->Width == (GLuint) width);
25607117f1b4Smrg      assert(rb->Height == (GLuint) height);
25617117f1b4Smrg      rb->InternalFormat = internalFormat;
2562cdc920a0Smrg      rb->_BaseFormat = baseFormat;
25634a49301eSmrg      assert(rb->_BaseFormat != 0);
25647117f1b4Smrg   }
25657117f1b4Smrg   else {
25667117f1b4Smrg      /* Probably ran out of memory - clear the fields */
25677117f1b4Smrg      rb->Width = 0;
25687117f1b4Smrg      rb->Height = 0;
25694a49301eSmrg      rb->Format = MESA_FORMAT_NONE;
25707117f1b4Smrg      rb->InternalFormat = GL_NONE;
25717117f1b4Smrg      rb->_BaseFormat = GL_NONE;
25724a49301eSmrg      rb->NumSamples = 0;
257301e04c3fSmrg      rb->NumStorageSamples = 0;
25747117f1b4Smrg   }
25757117f1b4Smrg
25763464ebd5Sriastradh   /* Invalidate the framebuffers the renderbuffer is attached in. */
25773464ebd5Sriastradh   if (rb->AttachedAnytime) {
25783464ebd5Sriastradh      _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb);
25793464ebd5Sriastradh   }
25807117f1b4Smrg}
25817117f1b4Smrg
258201e04c3fSmrg/**
258301e04c3fSmrg * Helper function used by renderbuffer_storage_direct() and
258401e04c3fSmrg * renderbuffer_storage_target().
258501e04c3fSmrg * samples will be NO_SAMPLES if called by a non-multisample function.
258601e04c3fSmrg */
258701e04c3fSmrgstatic void
258801e04c3fSmrgrenderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
258901e04c3fSmrg                     GLenum internalFormat, GLsizei width,
259001e04c3fSmrg                     GLsizei height, GLsizei samples, GLsizei storageSamples,
259101e04c3fSmrg                     const char *func)
259201e04c3fSmrg{
259301e04c3fSmrg   GLenum baseFormat;
259401e04c3fSmrg   GLenum sample_count_error;
259501e04c3fSmrg
259601e04c3fSmrg   baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
259701e04c3fSmrg   if (baseFormat == 0) {
259801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)",
259901e04c3fSmrg                  func, _mesa_enum_to_string(internalFormat));
260001e04c3fSmrg      return;
260101e04c3fSmrg   }
260201e04c3fSmrg
260301e04c3fSmrg   if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
260401e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid width %d)", func,
260501e04c3fSmrg                  width);
260601e04c3fSmrg      return;
260701e04c3fSmrg   }
260801e04c3fSmrg
260901e04c3fSmrg   if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
261001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid height %d)", func,
261101e04c3fSmrg                  height);
261201e04c3fSmrg      return;
261301e04c3fSmrg   }
261401e04c3fSmrg
261501e04c3fSmrg   if (samples == NO_SAMPLES) {
261601e04c3fSmrg      /* NumSamples == 0 indicates non-multisampling */
261701e04c3fSmrg      samples = 0;
261801e04c3fSmrg      storageSamples = 0;
261901e04c3fSmrg   }
262001e04c3fSmrg   else {
262101e04c3fSmrg      /* check the sample count;
262201e04c3fSmrg       * note: driver may choose to use more samples than what's requested
262301e04c3fSmrg       */
262401e04c3fSmrg      sample_count_error = _mesa_check_sample_count(ctx, GL_RENDERBUFFER,
262501e04c3fSmrg            internalFormat, samples, storageSamples);
262601e04c3fSmrg
262701e04c3fSmrg      /* Section 2.5 (GL Errors) of OpenGL 3.0 specification, page 16:
262801e04c3fSmrg       *
262901e04c3fSmrg       * "If a negative number is provided where an argument of type sizei or
263001e04c3fSmrg       * sizeiptr is specified, the error INVALID VALUE is generated."
263101e04c3fSmrg       */
263201e04c3fSmrg      if (samples < 0 || storageSamples < 0) {
263301e04c3fSmrg         sample_count_error = GL_INVALID_VALUE;
263401e04c3fSmrg      }
263501e04c3fSmrg
263601e04c3fSmrg      if (sample_count_error != GL_NO_ERROR) {
263701e04c3fSmrg         _mesa_error(ctx, sample_count_error,
263801e04c3fSmrg                     "%s(samples=%d, storageSamples=%d)", func, samples,
263901e04c3fSmrg                     storageSamples);
264001e04c3fSmrg         return;
264101e04c3fSmrg      }
264201e04c3fSmrg   }
264301e04c3fSmrg
264401e04c3fSmrg   _mesa_renderbuffer_storage(ctx, rb, internalFormat, width, height, samples,
264501e04c3fSmrg                              storageSamples);
264601e04c3fSmrg}
264701e04c3fSmrg
264801e04c3fSmrg/**
264901e04c3fSmrg * Helper function used by _mesa_NamedRenderbufferStorage*().
265001e04c3fSmrg * samples will be NO_SAMPLES if called by a non-multisample function.
265101e04c3fSmrg */
265201e04c3fSmrgstatic void
265301e04c3fSmrgrenderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat,
265401e04c3fSmrg                           GLsizei width, GLsizei height, GLsizei samples,
265501e04c3fSmrg                           GLsizei storageSamples, const char *func)
265601e04c3fSmrg{
265701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
265801e04c3fSmrg
265901e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
266001e04c3fSmrg      if (samples == NO_SAMPLES)
266101e04c3fSmrg         _mesa_debug(ctx, "%s(%u, %s, %d, %d)\n",
266201e04c3fSmrg                     func, renderbuffer,
266301e04c3fSmrg                     _mesa_enum_to_string(internalFormat),
266401e04c3fSmrg                     width, height);
266501e04c3fSmrg      else
266601e04c3fSmrg         _mesa_debug(ctx, "%s(%u, %s, %d, %d, %d)\n",
266701e04c3fSmrg                     func, renderbuffer,
266801e04c3fSmrg                     _mesa_enum_to_string(internalFormat),
266901e04c3fSmrg                     width, height, samples);
267001e04c3fSmrg   }
267101e04c3fSmrg
267201e04c3fSmrg   struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
267301e04c3fSmrg   if (!rb || rb == &DummyRenderbuffer) {
267401e04c3fSmrg      /* ID was reserved, but no real renderbuffer object made yet */
267501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid renderbuffer %u)",
267601e04c3fSmrg                  func, renderbuffer);
267701e04c3fSmrg      return;
267801e04c3fSmrg   }
267901e04c3fSmrg
268001e04c3fSmrg   renderbuffer_storage(ctx, rb, internalFormat, width, height, samples,
268101e04c3fSmrg                        storageSamples, func);
268201e04c3fSmrg}
268301e04c3fSmrg
268401e04c3fSmrg/**
268501e04c3fSmrg * Helper function used by _mesa_RenderbufferStorage() and
268601e04c3fSmrg * _mesa_RenderbufferStorageMultisample().
268701e04c3fSmrg * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorage().
268801e04c3fSmrg */
268901e04c3fSmrgstatic void
269001e04c3fSmrgrenderbuffer_storage_target(GLenum target, GLenum internalFormat,
269101e04c3fSmrg                            GLsizei width, GLsizei height, GLsizei samples,
269201e04c3fSmrg                            GLsizei storageSamples, const char *func)
269301e04c3fSmrg{
269401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
269501e04c3fSmrg
269601e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
269701e04c3fSmrg      if (samples == NO_SAMPLES)
269801e04c3fSmrg         _mesa_debug(ctx, "%s(%s, %s, %d, %d)\n",
269901e04c3fSmrg                     func,
270001e04c3fSmrg                     _mesa_enum_to_string(target),
270101e04c3fSmrg                     _mesa_enum_to_string(internalFormat),
270201e04c3fSmrg                     width, height);
270301e04c3fSmrg      else
270401e04c3fSmrg         _mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n",
270501e04c3fSmrg                     func,
270601e04c3fSmrg                     _mesa_enum_to_string(target),
270701e04c3fSmrg                     _mesa_enum_to_string(internalFormat),
270801e04c3fSmrg                     width, height, samples);
270901e04c3fSmrg   }
271001e04c3fSmrg
271101e04c3fSmrg   if (target != GL_RENDERBUFFER_EXT) {
271201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
271301e04c3fSmrg      return;
271401e04c3fSmrg   }
271501e04c3fSmrg
271601e04c3fSmrg   if (!ctx->CurrentRenderbuffer) {
271701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no renderbuffer bound)",
271801e04c3fSmrg                  func);
271901e04c3fSmrg      return;
272001e04c3fSmrg   }
272101e04c3fSmrg
272201e04c3fSmrg   renderbuffer_storage(ctx, ctx->CurrentRenderbuffer, internalFormat, width,
272301e04c3fSmrg                        height, samples, storageSamples, func);
272401e04c3fSmrg}
272501e04c3fSmrg
27263464ebd5Sriastradh
2727cdc920a0Smrgvoid GLAPIENTRY
27283464ebd5Sriastradh_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
2729cdc920a0Smrg{
2730cdc920a0Smrg   struct gl_renderbuffer *rb;
2731cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
2732cdc920a0Smrg
27333464ebd5Sriastradh   if (!ctx->Extensions.OES_EGL_image) {
27343464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
27353464ebd5Sriastradh                  "glEGLImageTargetRenderbufferStorageOES(unsupported)");
27363464ebd5Sriastradh      return;
27373464ebd5Sriastradh   }
27383464ebd5Sriastradh
2739cdc920a0Smrg   if (target != GL_RENDERBUFFER) {
27403464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_ENUM,
27413464ebd5Sriastradh                  "EGLImageTargetRenderbufferStorageOES");
2742cdc920a0Smrg      return;
2743cdc920a0Smrg   }
2744cdc920a0Smrg
2745cdc920a0Smrg   rb = ctx->CurrentRenderbuffer;
2746cdc920a0Smrg   if (!rb) {
27473464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
27483464ebd5Sriastradh                  "EGLImageTargetRenderbufferStorageOES");
2749cdc920a0Smrg      return;
2750cdc920a0Smrg   }
2751cdc920a0Smrg
27527ec681f3Smrg   if (!image || (ctx->Driver.ValidateEGLImage &&
27537ec681f3Smrg                  !ctx->Driver.ValidateEGLImage(ctx, image))) {
27547ec681f3Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
27557ec681f3Smrg                  "EGLImageTargetRenderbufferStorageOES");
27567ec681f3Smrg      return;
27577ec681f3Smrg   }
27587ec681f3Smrg
27597ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
2760cdc920a0Smrg
2761cdc920a0Smrg   ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
2762cdc920a0Smrg}
27637117f1b4Smrg
27643464ebd5Sriastradh
27654a49301eSmrg/**
2766af69d88dSmrg * Helper function for _mesa_GetRenderbufferParameteriv() and
2767af69d88dSmrg * _mesa_GetFramebufferAttachmentParameteriv()
27684a49301eSmrg * We have to be careful to respect the base format.  For example, if a
27694a49301eSmrg * renderbuffer/texture was created with internalFormat=GL_RGB but the
27704a49301eSmrg * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
27714a49301eSmrg * we need to return zero.
27724a49301eSmrg */
27734a49301eSmrgstatic GLint
2774af69d88dSmrgget_component_bits(GLenum pname, GLenum baseFormat, mesa_format format)
27754a49301eSmrg{
2776af69d88dSmrg   if (_mesa_base_format_has_channel(baseFormat, pname))
2777af69d88dSmrg      return _mesa_get_format_bits(format, pname);
2778af69d88dSmrg   else
27794a49301eSmrg      return 0;
27804a49301eSmrg}
27814a49301eSmrg
27824a49301eSmrg
27834a49301eSmrg
27844a49301eSmrgvoid GLAPIENTRY
2785af69d88dSmrg_mesa_RenderbufferStorage(GLenum target, GLenum internalFormat,
27864a49301eSmrg                             GLsizei width, GLsizei height)
27874a49301eSmrg{
27884a49301eSmrg   /* GL_ARB_fbo says calling this function is equivalent to calling
27894a49301eSmrg    * glRenderbufferStorageMultisample() with samples=0.  We pass in
27904a49301eSmrg    * a token value here just for error reporting purposes.
27914a49301eSmrg    */
279201e04c3fSmrg   renderbuffer_storage_target(target, internalFormat, width, height,
279301e04c3fSmrg                               NO_SAMPLES, 0, "glRenderbufferStorage");
27944a49301eSmrg}
27954a49301eSmrg
27964a49301eSmrg
27974a49301eSmrgvoid GLAPIENTRY
27984a49301eSmrg_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
27994a49301eSmrg                                     GLenum internalFormat,
28004a49301eSmrg                                     GLsizei width, GLsizei height)
28014a49301eSmrg{
280201e04c3fSmrg   renderbuffer_storage_target(target, internalFormat, width, height,
280301e04c3fSmrg                               samples, samples,
280401e04c3fSmrg                               "glRenderbufferStorageMultisample");
280501e04c3fSmrg}
280601e04c3fSmrg
280701e04c3fSmrg
280801e04c3fSmrgvoid GLAPIENTRY
280901e04c3fSmrg_mesa_RenderbufferStorageMultisampleAdvancedAMD(
281001e04c3fSmrg      GLenum target, GLsizei samples, GLsizei storageSamples,
281101e04c3fSmrg      GLenum internalFormat, GLsizei width, GLsizei height)
281201e04c3fSmrg{
281301e04c3fSmrg   renderbuffer_storage_target(target, internalFormat, width, height,
281401e04c3fSmrg                               samples, storageSamples,
281501e04c3fSmrg                               "glRenderbufferStorageMultisampleAdvancedAMD");
28164a49301eSmrg}
28174a49301eSmrg
28184a49301eSmrg
28193464ebd5Sriastradh/**
28203464ebd5Sriastradh * OpenGL ES version of glRenderBufferStorage.
28213464ebd5Sriastradh */
28223464ebd5Sriastradhvoid GLAPIENTRY
28233464ebd5Sriastradh_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
282401e04c3fSmrg                           GLsizei width, GLsizei height)
28253464ebd5Sriastradh{
28263464ebd5Sriastradh   switch (internalFormat) {
28273464ebd5Sriastradh   case GL_RGB565:
28283464ebd5Sriastradh      /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
28293464ebd5Sriastradh      /* choose a closest format */
28303464ebd5Sriastradh      internalFormat = GL_RGB5;
28313464ebd5Sriastradh      break;
28323464ebd5Sriastradh   default:
28333464ebd5Sriastradh      break;
28343464ebd5Sriastradh   }
28353464ebd5Sriastradh
283601e04c3fSmrg   renderbuffer_storage_target(target, internalFormat, width, height, 0, 0,
283701e04c3fSmrg                               "glRenderbufferStorageEXT");
28383464ebd5Sriastradh}
28393464ebd5Sriastradh
284001e04c3fSmrgvoid GLAPIENTRY
284101e04c3fSmrg_mesa_NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat,
284201e04c3fSmrg                               GLsizei width, GLsizei height)
284301e04c3fSmrg{
284401e04c3fSmrg   /* GL_ARB_fbo says calling this function is equivalent to calling
284501e04c3fSmrg    * glRenderbufferStorageMultisample() with samples=0.  We pass in
284601e04c3fSmrg    * a token value here just for error reporting purposes.
284701e04c3fSmrg    */
284801e04c3fSmrg   renderbuffer_storage_named(renderbuffer, internalformat, width, height,
284901e04c3fSmrg                              NO_SAMPLES, 0, "glNamedRenderbufferStorage");
285001e04c3fSmrg}
28514a49301eSmrg
28527ec681f3Smrgvoid GLAPIENTRY
28537ec681f3Smrg_mesa_NamedRenderbufferStorageEXT(GLuint renderbuffer, GLenum internalformat,
28547ec681f3Smrg                                  GLsizei width, GLsizei height)
28557ec681f3Smrg{
28567ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
28577ec681f3Smrg   struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
28587ec681f3Smrg   if (!rb || rb == &DummyRenderbuffer) {
28597ec681f3Smrg      _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
28607ec681f3Smrg      rb = allocate_renderbuffer_locked(ctx, renderbuffer, rb != NULL,
28617ec681f3Smrg                                        "glNamedRenderbufferStorageEXT");
28627ec681f3Smrg      _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
28637ec681f3Smrg   }
28647ec681f3Smrg   renderbuffer_storage(ctx, rb, internalformat, width, height, NO_SAMPLES,
28657ec681f3Smrg                        0, "glNamedRenderbufferStorageEXT");
28667ec681f3Smrg}
28677ec681f3Smrg
28687ec681f3Smrg
28697117f1b4Smrgvoid GLAPIENTRY
287001e04c3fSmrg_mesa_NamedRenderbufferStorageMultisample(GLuint renderbuffer, GLsizei samples,
287101e04c3fSmrg                                          GLenum internalformat,
287201e04c3fSmrg                                          GLsizei width, GLsizei height)
28737117f1b4Smrg{
287401e04c3fSmrg   renderbuffer_storage_named(renderbuffer, internalformat, width, height,
287501e04c3fSmrg                              samples, samples,
287601e04c3fSmrg                              "glNamedRenderbufferStorageMultisample");
287701e04c3fSmrg}
28787117f1b4Smrg
28797117f1b4Smrg
28807ec681f3Smrgvoid GLAPIENTRY
28817ec681f3Smrg_mesa_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer, GLsizei samples,
28827ec681f3Smrg                                             GLenum internalformat,
28837ec681f3Smrg                                             GLsizei width, GLsizei height)
28847ec681f3Smrg{
28857ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
28867ec681f3Smrg   struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
28877ec681f3Smrg   if (!rb || rb == &DummyRenderbuffer) {
28887ec681f3Smrg      _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
28897ec681f3Smrg      rb = allocate_renderbuffer_locked(ctx, renderbuffer, rb != NULL,
28907ec681f3Smrg                                        "glNamedRenderbufferStorageMultisampleEXT");
28917ec681f3Smrg      _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
28927ec681f3Smrg   }
28937ec681f3Smrg   renderbuffer_storage(ctx, rb, internalformat, width, height,
28947ec681f3Smrg                        samples, samples,
28957ec681f3Smrg                        "glNamedRenderbufferStorageMultisample");
28967ec681f3Smrg}
28977ec681f3Smrg
28987ec681f3Smrg
289901e04c3fSmrgvoid GLAPIENTRY
290001e04c3fSmrg_mesa_NamedRenderbufferStorageMultisampleAdvancedAMD(
290101e04c3fSmrg      GLuint renderbuffer, GLsizei samples, GLsizei storageSamples,
290201e04c3fSmrg      GLenum internalformat, GLsizei width, GLsizei height)
290301e04c3fSmrg{
290401e04c3fSmrg   renderbuffer_storage_named(renderbuffer, internalformat, width, height,
290501e04c3fSmrg                              samples, storageSamples,
290601e04c3fSmrg                              "glNamedRenderbufferStorageMultisampleAdvancedAMD");
290701e04c3fSmrg}
290801e04c3fSmrg
29097117f1b4Smrg
291001e04c3fSmrgstatic void
291101e04c3fSmrgget_render_buffer_parameteriv(struct gl_context *ctx,
291201e04c3fSmrg                              struct gl_renderbuffer *rb, GLenum pname,
291301e04c3fSmrg                              GLint *params, const char *func)
291401e04c3fSmrg{
29154a49301eSmrg   /* No need to flush here since we're just quering state which is
29164a49301eSmrg    * not effected by rendering.
29174a49301eSmrg    */
29187117f1b4Smrg
29197117f1b4Smrg   switch (pname) {
29207117f1b4Smrg   case GL_RENDERBUFFER_WIDTH_EXT:
29214a49301eSmrg      *params = rb->Width;
29227117f1b4Smrg      return;
29237117f1b4Smrg   case GL_RENDERBUFFER_HEIGHT_EXT:
29244a49301eSmrg      *params = rb->Height;
29257117f1b4Smrg      return;
29267117f1b4Smrg   case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
29274a49301eSmrg      *params = rb->InternalFormat;
29287117f1b4Smrg      return;
29297117f1b4Smrg   case GL_RENDERBUFFER_RED_SIZE_EXT:
29307117f1b4Smrg   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
29317117f1b4Smrg   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
29327117f1b4Smrg   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
29337117f1b4Smrg   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
29347117f1b4Smrg   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
29354a49301eSmrg      *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
293601e04c3fSmrg      return;
29374a49301eSmrg   case GL_RENDERBUFFER_SAMPLES:
2938af69d88dSmrg      if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object)
2939af69d88dSmrg          || _mesa_is_gles3(ctx)) {
29404a49301eSmrg         *params = rb->NumSamples;
294101e04c3fSmrg         return;
29424a49301eSmrg      }
294301e04c3fSmrg      break;
294401e04c3fSmrg   case GL_RENDERBUFFER_STORAGE_SAMPLES_AMD:
294501e04c3fSmrg      if (ctx->Extensions.AMD_framebuffer_multisample_advanced) {
294601e04c3fSmrg         *params = rb->NumStorageSamples;
294701e04c3fSmrg         return;
294801e04c3fSmrg      }
294901e04c3fSmrg      break;
295001e04c3fSmrg   }
295101e04c3fSmrg
295201e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname=%s)", func,
295301e04c3fSmrg               _mesa_enum_to_string(pname));
295401e04c3fSmrg}
295501e04c3fSmrg
295601e04c3fSmrg
295701e04c3fSmrgvoid GLAPIENTRY
295801e04c3fSmrg_mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params)
295901e04c3fSmrg{
296001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
296101e04c3fSmrg
296201e04c3fSmrg   if (target != GL_RENDERBUFFER_EXT) {
29637117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
29647117f1b4Smrg                  "glGetRenderbufferParameterivEXT(target)");
29657117f1b4Smrg      return;
29667117f1b4Smrg   }
296701e04c3fSmrg
296801e04c3fSmrg   if (!ctx->CurrentRenderbuffer) {
296901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetRenderbufferParameterivEXT"
297001e04c3fSmrg                  "(no renderbuffer bound)");
297101e04c3fSmrg      return;
297201e04c3fSmrg   }
297301e04c3fSmrg
297401e04c3fSmrg   get_render_buffer_parameteriv(ctx, ctx->CurrentRenderbuffer, pname,
297501e04c3fSmrg                                 params, "glGetRenderbufferParameteriv");
297601e04c3fSmrg}
297701e04c3fSmrg
297801e04c3fSmrg
297901e04c3fSmrgvoid GLAPIENTRY
298001e04c3fSmrg_mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname,
298101e04c3fSmrg                                      GLint *params)
298201e04c3fSmrg{
298301e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
298401e04c3fSmrg
298501e04c3fSmrg   struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
298601e04c3fSmrg   if (!rb || rb == &DummyRenderbuffer) {
298701e04c3fSmrg      /* ID was reserved, but no real renderbuffer object made yet */
298801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetNamedRenderbufferParameteriv"
298901e04c3fSmrg                  "(invalid renderbuffer %i)", renderbuffer);
299001e04c3fSmrg      return;
299101e04c3fSmrg   }
299201e04c3fSmrg
299301e04c3fSmrg   get_render_buffer_parameteriv(ctx, rb, pname, params,
299401e04c3fSmrg                                 "glGetNamedRenderbufferParameteriv");
29957117f1b4Smrg}
29967117f1b4Smrg
29977117f1b4Smrg
29987ec681f3Smrgvoid GLAPIENTRY
29997ec681f3Smrg_mesa_GetNamedRenderbufferParameterivEXT(GLuint renderbuffer, GLenum pname,
30007ec681f3Smrg                                         GLint *params)
30017ec681f3Smrg{
30027ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
30037ec681f3Smrg
30047ec681f3Smrg   struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
30057ec681f3Smrg   if (!rb || rb == &DummyRenderbuffer) {
30067ec681f3Smrg      _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
30077ec681f3Smrg      rb = allocate_renderbuffer_locked(ctx, renderbuffer, rb != NULL,
30087ec681f3Smrg                                        "glGetNamedRenderbufferParameterivEXT");
30097ec681f3Smrg      _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
30107ec681f3Smrg   }
30117ec681f3Smrg
30127ec681f3Smrg   get_render_buffer_parameteriv(ctx, rb, pname, params,
30137ec681f3Smrg                                 "glGetNamedRenderbufferParameterivEXT");
30147ec681f3Smrg}
30157ec681f3Smrg
30167ec681f3Smrg
30177117f1b4SmrgGLboolean GLAPIENTRY
3018af69d88dSmrg_mesa_IsFramebuffer(GLuint framebuffer)
30197117f1b4Smrg{
30207117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
30217117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
30227117f1b4Smrg   if (framebuffer) {
30237117f1b4Smrg      struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
30247117f1b4Smrg      if (rb != NULL && rb != &DummyFramebuffer)
30257117f1b4Smrg         return GL_TRUE;
30267117f1b4Smrg   }
30277117f1b4Smrg   return GL_FALSE;
30287117f1b4Smrg}
30297117f1b4Smrg
30307117f1b4Smrg
30314a49301eSmrg/**
30324a49301eSmrg * Check if any of the attachments of the given framebuffer are textures
30334a49301eSmrg * (render to texture).  Call ctx->Driver.RenderTexture() for such
30344a49301eSmrg * attachments.
30354a49301eSmrg */
30367117f1b4Smrgstatic void
30373464ebd5Sriastradhcheck_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
30387117f1b4Smrg{
30397117f1b4Smrg   GLuint i;
304001e04c3fSmrg   assert(ctx->Driver.RenderTexture);
30414a49301eSmrg
3042af69d88dSmrg   if (_mesa_is_winsys_fbo(fb))
30434a49301eSmrg      return; /* can't render to texture with winsys framebuffers */
30444a49301eSmrg
30457117f1b4Smrg   for (i = 0; i < BUFFER_COUNT; i++) {
30467117f1b4Smrg      struct gl_renderbuffer_attachment *att = fb->Attachment + i;
3047af69d88dSmrg      if (att->Texture && att->Renderbuffer->TexImage
3048af69d88dSmrg          && driver_RenderTexture_is_safe(att)) {
30497117f1b4Smrg         ctx->Driver.RenderTexture(ctx, fb, att);
30507117f1b4Smrg      }
30517117f1b4Smrg   }
30527117f1b4Smrg}
30537117f1b4Smrg
30547117f1b4Smrg
30557117f1b4Smrg/**
30567117f1b4Smrg * Examine all the framebuffer's attachments to see if any are textures.
30577117f1b4Smrg * If so, call ctx->Driver.FinishRenderTexture() for each texture to
30587117f1b4Smrg * notify the device driver that the texture image may have changed.
30597117f1b4Smrg */
30607117f1b4Smrgstatic void
30613464ebd5Sriastradhcheck_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
30627117f1b4Smrg{
3063af69d88dSmrg   /* Skip if we know NeedsFinishRenderTexture won't be set. */
3064af69d88dSmrg   if (_mesa_is_winsys_fbo(fb) && !ctx->Driver.BindRenderbufferTexImage)
3065af69d88dSmrg      return;
30664a49301eSmrg
30677117f1b4Smrg   if (ctx->Driver.FinishRenderTexture) {
30687117f1b4Smrg      GLuint i;
30697117f1b4Smrg      for (i = 0; i < BUFFER_COUNT; i++) {
30707117f1b4Smrg         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
3071af69d88dSmrg         struct gl_renderbuffer *rb = att->Renderbuffer;
3072af69d88dSmrg         if (rb && rb->NeedsFinishRenderTexture) {
3073af69d88dSmrg            ctx->Driver.FinishRenderTexture(ctx, rb);
30747117f1b4Smrg         }
30757117f1b4Smrg      }
30767117f1b4Smrg   }
30777117f1b4Smrg}
30787117f1b4Smrg
30797117f1b4Smrg
3080af69d88dSmrgstatic void
308101e04c3fSmrgbind_framebuffer(GLenum target, GLuint framebuffer)
30827117f1b4Smrg{
30834a49301eSmrg   struct gl_framebuffer *newDrawFb, *newReadFb;
30847117f1b4Smrg   GLboolean bindReadBuf, bindDrawBuf;
30857117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
30867117f1b4Smrg
30877117f1b4Smrg   switch (target) {
30887117f1b4Smrg   case GL_DRAW_FRAMEBUFFER_EXT:
30897117f1b4Smrg      bindDrawBuf = GL_TRUE;
30907117f1b4Smrg      bindReadBuf = GL_FALSE;
30917117f1b4Smrg      break;
30927117f1b4Smrg   case GL_READ_FRAMEBUFFER_EXT:
30937117f1b4Smrg      bindDrawBuf = GL_FALSE;
30947117f1b4Smrg      bindReadBuf = GL_TRUE;
30957117f1b4Smrg      break;
30967117f1b4Smrg   case GL_FRAMEBUFFER_EXT:
30977117f1b4Smrg      bindDrawBuf = GL_TRUE;
30987117f1b4Smrg      bindReadBuf = GL_TRUE;
30997117f1b4Smrg      break;
31007117f1b4Smrg   default:
31017117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
31027117f1b4Smrg      return;
31037117f1b4Smrg   }
31047117f1b4Smrg
31057117f1b4Smrg   if (framebuffer) {
31067ec681f3Smrg      bool isGenName = false;
31077117f1b4Smrg      /* Binding a user-created framebuffer object */
31084a49301eSmrg      newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
31094a49301eSmrg      if (newDrawFb == &DummyFramebuffer) {
31107117f1b4Smrg         /* ID was reserved, but no real framebuffer object made yet */
31114a49301eSmrg         newDrawFb = NULL;
31127ec681f3Smrg         isGenName = true;
31137117f1b4Smrg      }
311401e04c3fSmrg      else if (!newDrawFb && ctx->API == API_OPENGL_CORE) {
31154a49301eSmrg         /* All FBO IDs must be Gen'd */
311601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
311701e04c3fSmrg                     "glBindFramebuffer(non-gen name)");
31184a49301eSmrg         return;
31194a49301eSmrg      }
31204a49301eSmrg
31214a49301eSmrg      if (!newDrawFb) {
312201e04c3fSmrg         /* create new framebuffer object */
312301e04c3fSmrg         newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
312401e04c3fSmrg         if (!newDrawFb) {
312501e04c3fSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
312601e04c3fSmrg            return;
312701e04c3fSmrg         }
31287ec681f3Smrg         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb, isGenName);
31297117f1b4Smrg      }
31304a49301eSmrg      newReadFb = newDrawFb;
31317117f1b4Smrg   }
31327117f1b4Smrg   else {
31337117f1b4Smrg      /* Binding the window system framebuffer (which was originally set
31347117f1b4Smrg       * with MakeCurrent).
31357117f1b4Smrg       */
31364a49301eSmrg      newDrawFb = ctx->WinSysDrawBuffer;
31374a49301eSmrg      newReadFb = ctx->WinSysReadBuffer;
31387117f1b4Smrg   }
31397117f1b4Smrg
314001e04c3fSmrg   _mesa_bind_framebuffers(ctx,
314101e04c3fSmrg                           bindDrawBuf ? newDrawFb : ctx->DrawBuffer,
314201e04c3fSmrg                           bindReadBuf ? newReadFb : ctx->ReadBuffer);
314301e04c3fSmrg}
31444a49301eSmrg
314501e04c3fSmrgvoid
314601e04c3fSmrg_mesa_bind_framebuffers(struct gl_context *ctx,
314701e04c3fSmrg                        struct gl_framebuffer *newDrawFb,
314801e04c3fSmrg                        struct gl_framebuffer *newReadFb)
314901e04c3fSmrg{
315001e04c3fSmrg   struct gl_framebuffer *const oldDrawFb = ctx->DrawBuffer;
315101e04c3fSmrg   struct gl_framebuffer *const oldReadFb = ctx->ReadBuffer;
315201e04c3fSmrg   const bool bindDrawBuf = oldDrawFb != newDrawFb;
315301e04c3fSmrg   const bool bindReadBuf = oldReadFb != newReadFb;
31544a49301eSmrg
315501e04c3fSmrg   assert(newDrawFb);
315601e04c3fSmrg   assert(newDrawFb != &DummyFramebuffer);
31577117f1b4Smrg
31587117f1b4Smrg   /*
31594a49301eSmrg    * OK, now bind the new Draw/Read framebuffers, if they're changing.
31604a49301eSmrg    *
31614a49301eSmrg    * We also check if we're beginning and/or ending render-to-texture.
31624a49301eSmrg    * When a framebuffer with texture attachments is unbound, call
31634a49301eSmrg    * ctx->Driver.FinishRenderTexture().
31644a49301eSmrg    * When a framebuffer with texture attachments is bound, call
31654a49301eSmrg    * ctx->Driver.RenderTexture().
31664a49301eSmrg    *
31674a49301eSmrg    * Note that if the ReadBuffer has texture attachments we don't consider
31684a49301eSmrg    * that a render-to-texture case.
31697117f1b4Smrg    */
31707117f1b4Smrg   if (bindReadBuf) {
31717ec681f3Smrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
31724a49301eSmrg
31734a49301eSmrg      _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
31747117f1b4Smrg   }
31757117f1b4Smrg
31767117f1b4Smrg   if (bindDrawBuf) {
31777ec681f3Smrg      FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
317801e04c3fSmrg      ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
31797117f1b4Smrg
3180af69d88dSmrg      /* check if old framebuffer had any texture attachments */
3181af69d88dSmrg      if (oldDrawFb)
31824a49301eSmrg         check_end_texture_render(ctx, oldDrawFb);
31834a49301eSmrg
31844a49301eSmrg      /* check if newly bound framebuffer has any texture attachments */
31854a49301eSmrg      check_begin_texture_render(ctx, newDrawFb);
31864a49301eSmrg
31874a49301eSmrg      _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
31887ec681f3Smrg      _mesa_update_allow_draw_out_of_order(ctx);
31897ec681f3Smrg      _mesa_update_valid_to_render_state(ctx);
31907117f1b4Smrg   }
31917117f1b4Smrg
31924a49301eSmrg   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
319301e04c3fSmrg      /* The few classic drivers that actually hook this function really only
319401e04c3fSmrg       * want to know if the draw framebuffer changed.
319501e04c3fSmrg       */
319601e04c3fSmrg      ctx->Driver.BindFramebuffer(ctx,
319701e04c3fSmrg                                  bindDrawBuf ? GL_FRAMEBUFFER : GL_READ_FRAMEBUFFER,
319801e04c3fSmrg                                  newDrawFb, newReadFb);
31997117f1b4Smrg   }
32007117f1b4Smrg}
32017117f1b4Smrg
3202af69d88dSmrgvoid GLAPIENTRY
3203af69d88dSmrg_mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
3204af69d88dSmrg{
3205af69d88dSmrg   /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry
3206af69d88dSmrg    * point, but they allow the use of user-generated names.
3207af69d88dSmrg    */
320801e04c3fSmrg   bind_framebuffer(target, framebuffer);
3209af69d88dSmrg}
3210af69d88dSmrg
32117117f1b4Smrg
32127117f1b4Smrgvoid GLAPIENTRY
3213af69d88dSmrg_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
3214af69d88dSmrg{
321501e04c3fSmrg   bind_framebuffer(target, framebuffer);
3216af69d88dSmrg}
3217af69d88dSmrg
3218af69d88dSmrg
3219af69d88dSmrgvoid GLAPIENTRY
3220af69d88dSmrg_mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
32217117f1b4Smrg{
32227117f1b4Smrg   GLint i;
32237117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
32247117f1b4Smrg
322501e04c3fSmrg   if (n < 0) {
322601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteFramebuffers(n < 0)");
322701e04c3fSmrg      return;
322801e04c3fSmrg   }
322901e04c3fSmrg
32307ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
32317117f1b4Smrg
32327117f1b4Smrg   for (i = 0; i < n; i++) {
32337117f1b4Smrg      if (framebuffers[i] > 0) {
323401e04c3fSmrg         struct gl_framebuffer *fb;
323501e04c3fSmrg         fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
323601e04c3fSmrg         if (fb) {
323701e04c3fSmrg            assert(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
32387117f1b4Smrg
32397117f1b4Smrg            /* check if deleting currently bound framebuffer object */
3240af69d88dSmrg            if (fb == ctx->DrawBuffer) {
3241af69d88dSmrg               /* bind default */
324201e04c3fSmrg               assert(fb->RefCount >= 2);
3243af69d88dSmrg               _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
32444a49301eSmrg            }
3245af69d88dSmrg            if (fb == ctx->ReadBuffer) {
3246af69d88dSmrg               /* bind default */
324701e04c3fSmrg               assert(fb->RefCount >= 2);
3248af69d88dSmrg               _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, 0);
32497117f1b4Smrg            }
32507117f1b4Smrg
325101e04c3fSmrg            /* remove from hash table immediately, to free the ID */
325201e04c3fSmrg            _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
32537117f1b4Smrg
32547117f1b4Smrg            if (fb != &DummyFramebuffer) {
32557117f1b4Smrg               /* But the object will not be freed until it's no longer
32567117f1b4Smrg                * bound in any context.
32577117f1b4Smrg                */
32584a49301eSmrg               _mesa_reference_framebuffer(&fb, NULL);
325901e04c3fSmrg            }
326001e04c3fSmrg         }
32617117f1b4Smrg      }
32627117f1b4Smrg   }
32637117f1b4Smrg}
32647117f1b4Smrg
32657117f1b4Smrg
326601e04c3fSmrg/**
326701e04c3fSmrg * This is the implementation for glGenFramebuffers and glCreateFramebuffers.
326801e04c3fSmrg * It is not exposed to the rest of Mesa to encourage the use of
326901e04c3fSmrg * nameless buffers in driver internals.
327001e04c3fSmrg */
327101e04c3fSmrgstatic void
327201e04c3fSmrgcreate_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa)
32737117f1b4Smrg{
32747117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
32757117f1b4Smrg   GLint i;
327601e04c3fSmrg   struct gl_framebuffer *fb;
327701e04c3fSmrg
327801e04c3fSmrg   const char *func = dsa ? "glCreateFramebuffers" : "glGenFramebuffers";
32797117f1b4Smrg
32807117f1b4Smrg   if (n < 0) {
328101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
32827117f1b4Smrg      return;
32837117f1b4Smrg   }
32847117f1b4Smrg
32857117f1b4Smrg   if (!framebuffers)
32867117f1b4Smrg      return;
32877117f1b4Smrg
328801e04c3fSmrg   _mesa_HashLockMutex(ctx->Shared->FrameBuffers);
328901e04c3fSmrg
32907ec681f3Smrg   _mesa_HashFindFreeKeys(ctx->Shared->FrameBuffers, framebuffers, n);
32917117f1b4Smrg
32927117f1b4Smrg   for (i = 0; i < n; i++) {
329301e04c3fSmrg      if (dsa) {
329401e04c3fSmrg         fb = ctx->Driver.NewFramebuffer(ctx, framebuffers[i]);
329501e04c3fSmrg         if (!fb) {
329601e04c3fSmrg            _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers);
329701e04c3fSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
329801e04c3fSmrg            return;
329901e04c3fSmrg         }
330001e04c3fSmrg      }
330101e04c3fSmrg      else
330201e04c3fSmrg         fb = &DummyFramebuffer;
330301e04c3fSmrg
33047ec681f3Smrg      _mesa_HashInsertLocked(ctx->Shared->FrameBuffers, framebuffers[i],
33057ec681f3Smrg                             fb, true);
33067117f1b4Smrg   }
330701e04c3fSmrg
330801e04c3fSmrg   _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers);
33097117f1b4Smrg}
33107117f1b4Smrg
33117117f1b4Smrg
331201e04c3fSmrgvoid GLAPIENTRY
331301e04c3fSmrg_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers)
33147117f1b4Smrg{
331501e04c3fSmrg   create_framebuffers(n, framebuffers, false);
331601e04c3fSmrg}
33177117f1b4Smrg
33187117f1b4Smrg
331901e04c3fSmrgvoid GLAPIENTRY
332001e04c3fSmrg_mesa_CreateFramebuffers(GLsizei n, GLuint *framebuffers)
332101e04c3fSmrg{
332201e04c3fSmrg   create_framebuffers(n, framebuffers, true);
332301e04c3fSmrg}
3324af69d88dSmrg
332501e04c3fSmrg
332601e04c3fSmrgGLenum
332701e04c3fSmrg_mesa_check_framebuffer_status(struct gl_context *ctx,
332801e04c3fSmrg                               struct gl_framebuffer *buffer)
332901e04c3fSmrg{
333001e04c3fSmrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
33317117f1b4Smrg
3332af69d88dSmrg   if (_mesa_is_winsys_fbo(buffer)) {
3333af69d88dSmrg      /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */
3334af69d88dSmrg      if (buffer != &IncompleteFramebuffer) {
3335af69d88dSmrg         return GL_FRAMEBUFFER_COMPLETE_EXT;
3336af69d88dSmrg      } else {
3337af69d88dSmrg         return GL_FRAMEBUFFER_UNDEFINED;
3338af69d88dSmrg      }
33397117f1b4Smrg   }
33407117f1b4Smrg
33414a49301eSmrg   /* No need to flush here */
33424a49301eSmrg
33434a49301eSmrg   if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
33444a49301eSmrg      _mesa_test_framebuffer_completeness(ctx, buffer);
33454a49301eSmrg   }
33467117f1b4Smrg
33477117f1b4Smrg   return buffer->_Status;
33487117f1b4Smrg}
33497117f1b4Smrg
33507117f1b4Smrg
335101e04c3fSmrgGLenum GLAPIENTRY
335201e04c3fSmrg_mesa_CheckFramebufferStatus_no_error(GLenum target)
3353af69d88dSmrg{
335401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
3355af69d88dSmrg
335601e04c3fSmrg   struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
335701e04c3fSmrg   return _mesa_check_framebuffer_status(ctx, fb);
335801e04c3fSmrg}
335901e04c3fSmrg
336001e04c3fSmrg
336101e04c3fSmrgGLenum GLAPIENTRY
336201e04c3fSmrg_mesa_CheckFramebufferStatus(GLenum target)
336301e04c3fSmrg{
336401e04c3fSmrg   struct gl_framebuffer *fb;
336501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
336601e04c3fSmrg
336701e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API)
336801e04c3fSmrg      _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n",
336901e04c3fSmrg                  _mesa_enum_to_string(target));
337001e04c3fSmrg
337101e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
337201e04c3fSmrg   if (!fb) {
337301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
337401e04c3fSmrg                  "glCheckFramebufferStatus(invalid target %s)",
337501e04c3fSmrg                  _mesa_enum_to_string(target));
337601e04c3fSmrg      return 0;
337701e04c3fSmrg   }
337801e04c3fSmrg
337901e04c3fSmrg   return _mesa_check_framebuffer_status(ctx, fb);
338001e04c3fSmrg}
338101e04c3fSmrg
338201e04c3fSmrg
338301e04c3fSmrgGLenum GLAPIENTRY
338401e04c3fSmrg_mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target)
338501e04c3fSmrg{
338601e04c3fSmrg   struct gl_framebuffer *fb;
338701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
338801e04c3fSmrg
338901e04c3fSmrg   /* Validate the target (for conformance's sake) and grab a reference to the
339001e04c3fSmrg    * default framebuffer in case framebuffer = 0.
339101e04c3fSmrg    * Section 9.4 Framebuffer Completeness of the OpenGL 4.5 core spec
339201e04c3fSmrg    * (30.10.2014, PDF page 336) says:
339301e04c3fSmrg    *    "If framebuffer is zero, then the status of the default read or
339401e04c3fSmrg    *    draw framebuffer (as determined by target) is returned."
339501e04c3fSmrg    */
339601e04c3fSmrg   switch (target) {
339701e04c3fSmrg      case GL_DRAW_FRAMEBUFFER:
339801e04c3fSmrg      case GL_FRAMEBUFFER:
339901e04c3fSmrg         fb = ctx->WinSysDrawBuffer;
340001e04c3fSmrg         break;
340101e04c3fSmrg      case GL_READ_FRAMEBUFFER:
340201e04c3fSmrg         fb = ctx->WinSysReadBuffer;
340301e04c3fSmrg         break;
340401e04c3fSmrg      default:
340501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
340601e04c3fSmrg                     "glCheckNamedFramebufferStatus(invalid target %s)",
340701e04c3fSmrg                     _mesa_enum_to_string(target));
340801e04c3fSmrg         return 0;
340901e04c3fSmrg   }
341001e04c3fSmrg
341101e04c3fSmrg   if (framebuffer) {
341201e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
341301e04c3fSmrg                                        "glCheckNamedFramebufferStatus");
341401e04c3fSmrg      if (!fb)
341501e04c3fSmrg         return 0;
341601e04c3fSmrg   }
341701e04c3fSmrg
341801e04c3fSmrg   return _mesa_check_framebuffer_status(ctx, fb);
341901e04c3fSmrg}
342001e04c3fSmrg
342101e04c3fSmrg
34227ec681f3SmrgGLenum GLAPIENTRY
34237ec681f3Smrg_mesa_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target)
34247ec681f3Smrg{
34257ec681f3Smrg   struct gl_framebuffer *fb;
34267ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
34277ec681f3Smrg
34287ec681f3Smrg   switch (target) {
34297ec681f3Smrg      case GL_DRAW_FRAMEBUFFER:
34307ec681f3Smrg      case GL_FRAMEBUFFER:
34317ec681f3Smrg      case GL_READ_FRAMEBUFFER:
34327ec681f3Smrg         break;
34337ec681f3Smrg      default:
34347ec681f3Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
34357ec681f3Smrg                     "glCheckNamedFramebufferStatusEXT(invalid target %s)",
34367ec681f3Smrg                     _mesa_enum_to_string(target));
34377ec681f3Smrg         return 0;
34387ec681f3Smrg   }
34397ec681f3Smrg
34407ec681f3Smrg   if (framebuffer == 0) {
34417ec681f3Smrg      return _mesa_CheckNamedFramebufferStatus(0, target);
34427ec681f3Smrg   }
34437ec681f3Smrg
34447ec681f3Smrg   fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer,
34457ec681f3Smrg                                     "glCheckNamedFramebufferStatusEXT");
34467ec681f3Smrg   if (!fb)
34477ec681f3Smrg      return 0;
34487ec681f3Smrg
34497ec681f3Smrg   return _mesa_check_framebuffer_status(ctx, fb);
34507ec681f3Smrg}
34517ec681f3Smrg
34527ec681f3Smrg
345301e04c3fSmrg/**
345401e04c3fSmrg * Replicate the src attachment point. Used by framebuffer_texture() when
345501e04c3fSmrg * the same texture is attached at GL_DEPTH_ATTACHMENT and
345601e04c3fSmrg * GL_STENCIL_ATTACHMENT.
345701e04c3fSmrg */
345801e04c3fSmrgstatic void
345901e04c3fSmrgreuse_framebuffer_texture_attachment(struct gl_framebuffer *fb,
346001e04c3fSmrg                                     gl_buffer_index dst,
346101e04c3fSmrg                                     gl_buffer_index src)
346201e04c3fSmrg{
346301e04c3fSmrg   struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst];
346401e04c3fSmrg   struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src];
346501e04c3fSmrg
346601e04c3fSmrg   assert(src_att->Texture != NULL);
346701e04c3fSmrg   assert(src_att->Renderbuffer != NULL);
3468af69d88dSmrg
3469af69d88dSmrg   _mesa_reference_texobj(&dst_att->Texture, src_att->Texture);
3470af69d88dSmrg   _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer);
3471af69d88dSmrg   dst_att->Type = src_att->Type;
3472af69d88dSmrg   dst_att->Complete = src_att->Complete;
3473af69d88dSmrg   dst_att->TextureLevel = src_att->TextureLevel;
347401e04c3fSmrg   dst_att->CubeMapFace = src_att->CubeMapFace;
3475af69d88dSmrg   dst_att->Zoffset = src_att->Zoffset;
347601e04c3fSmrg   dst_att->Layered = src_att->Layered;
347701e04c3fSmrg}
347801e04c3fSmrg
347901e04c3fSmrg
348001e04c3fSmrgstatic struct gl_texture_object *
348101e04c3fSmrgget_texture_for_framebuffer(struct gl_context *ctx, GLuint texture)
348201e04c3fSmrg{
348301e04c3fSmrg   if (!texture)
348401e04c3fSmrg      return NULL;
348501e04c3fSmrg
348601e04c3fSmrg   return _mesa_lookup_texture(ctx, texture);
3487af69d88dSmrg}
3488af69d88dSmrg
34897117f1b4Smrg
34907117f1b4Smrg/**
349101e04c3fSmrg * Common code called by gl*FramebufferTexture*() to retrieve the correct
349201e04c3fSmrg * texture object pointer.
3493af69d88dSmrg *
349401e04c3fSmrg * \param texObj where the pointer to the texture object is returned.  Note
349501e04c3fSmrg * that a successful call may return texObj = NULL.
3496af69d88dSmrg *
349701e04c3fSmrg * \return true if no errors, false if errors
34987117f1b4Smrg */
349901e04c3fSmrgstatic bool
350001e04c3fSmrgget_texture_for_framebuffer_err(struct gl_context *ctx, GLuint texture,
350101e04c3fSmrg                                bool layered, const char *caller,
350201e04c3fSmrg                                struct gl_texture_object **texObj)
35037117f1b4Smrg{
350401e04c3fSmrg   *texObj = NULL; /* This will get returned if texture = 0. */
35057117f1b4Smrg
350601e04c3fSmrg   if (!texture)
350701e04c3fSmrg      return true;
350801e04c3fSmrg
350901e04c3fSmrg   *texObj = _mesa_lookup_texture(ctx, texture);
351001e04c3fSmrg   if (*texObj == NULL || (*texObj)->Target == 0) {
351101e04c3fSmrg      /* Can't render to a non-existent texture object.
351201e04c3fSmrg       *
351301e04c3fSmrg       * The OpenGL 4.5 core spec (02.02.2015) in Section 9.2 Binding and
351401e04c3fSmrg       * Managing Framebuffer Objects specifies a different error
351501e04c3fSmrg       * depending upon the calling function (PDF pages 325-328).
351601e04c3fSmrg       * *FramebufferTexture (where layered = GL_TRUE) throws invalid
351701e04c3fSmrg       * value, while the other commands throw invalid operation (where
351801e04c3fSmrg       * layered = GL_FALSE).
351901e04c3fSmrg       */
352001e04c3fSmrg      const GLenum error = layered ? GL_INVALID_VALUE :
352101e04c3fSmrg                           GL_INVALID_OPERATION;
352201e04c3fSmrg      _mesa_error(ctx, error,
352301e04c3fSmrg                  "%s(non-existent texture %u)", caller, texture);
352401e04c3fSmrg      return false;
352501e04c3fSmrg   }
352601e04c3fSmrg
352701e04c3fSmrg   return true;
352801e04c3fSmrg}
352901e04c3fSmrg
353001e04c3fSmrg
353101e04c3fSmrg/**
353201e04c3fSmrg * Common code called by gl*FramebufferTexture() to verify the texture target
353301e04c3fSmrg * and decide whether or not the attachment should truly be considered
353401e04c3fSmrg * layered.
353501e04c3fSmrg *
353601e04c3fSmrg * \param layered true if attachment should be considered layered, false if
353701e04c3fSmrg * not
353801e04c3fSmrg *
353901e04c3fSmrg * \return true if no errors, false if errors
354001e04c3fSmrg */
354101e04c3fSmrgstatic bool
354201e04c3fSmrgcheck_layered_texture_target(struct gl_context *ctx, GLenum target,
354301e04c3fSmrg                             const char *caller, GLboolean *layered)
354401e04c3fSmrg{
354501e04c3fSmrg   *layered = GL_TRUE;
354601e04c3fSmrg
354701e04c3fSmrg   switch (target) {
354801e04c3fSmrg   case GL_TEXTURE_3D:
354901e04c3fSmrg   case GL_TEXTURE_1D_ARRAY_EXT:
355001e04c3fSmrg   case GL_TEXTURE_2D_ARRAY_EXT:
355101e04c3fSmrg   case GL_TEXTURE_CUBE_MAP:
355201e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_ARRAY:
355301e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
355401e04c3fSmrg      return true;
355501e04c3fSmrg   case GL_TEXTURE_1D:
355601e04c3fSmrg   case GL_TEXTURE_2D:
355701e04c3fSmrg   case GL_TEXTURE_RECTANGLE:
355801e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE:
355901e04c3fSmrg      /* These texture types are valid to pass to
356001e04c3fSmrg       * glFramebufferTexture(), but since they aren't layered, it
356101e04c3fSmrg       * is equivalent to calling glFramebufferTexture{1D,2D}().
356201e04c3fSmrg       */
356301e04c3fSmrg      *layered = GL_FALSE;
356401e04c3fSmrg      return true;
356501e04c3fSmrg   }
356601e04c3fSmrg
356701e04c3fSmrg   _mesa_error(ctx, GL_INVALID_OPERATION,
356801e04c3fSmrg               "%s(invalid texture target %s)", caller,
356901e04c3fSmrg               _mesa_enum_to_string(target));
357001e04c3fSmrg   return false;
357101e04c3fSmrg}
357201e04c3fSmrg
357301e04c3fSmrg
357401e04c3fSmrg/**
357501e04c3fSmrg * Common code called by gl*FramebufferTextureLayer() to verify the texture
357601e04c3fSmrg * target.
357701e04c3fSmrg *
357801e04c3fSmrg * \return true if no errors, false if errors
357901e04c3fSmrg */
358001e04c3fSmrgstatic bool
358101e04c3fSmrgcheck_texture_target(struct gl_context *ctx, GLenum target,
358201e04c3fSmrg                     const char *caller)
358301e04c3fSmrg{
358401e04c3fSmrg   /* We're being called by glFramebufferTextureLayer().
358501e04c3fSmrg    * The only legal texture types for that function are 3D,
358601e04c3fSmrg    * cube-map, and 1D/2D/cube-map array textures.
358701e04c3fSmrg    *
358801e04c3fSmrg    * We don't need to check for GL_ARB_texture_cube_map_array because the
358901e04c3fSmrg    * application wouldn't have been able to create a texture with a
359001e04c3fSmrg    * GL_TEXTURE_CUBE_MAP_ARRAY target if the extension were not enabled.
359101e04c3fSmrg    */
359201e04c3fSmrg   switch (target) {
359301e04c3fSmrg   case GL_TEXTURE_3D:
359401e04c3fSmrg   case GL_TEXTURE_1D_ARRAY:
359501e04c3fSmrg   case GL_TEXTURE_2D_ARRAY:
359601e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_ARRAY:
359701e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
359801e04c3fSmrg      return true;
359901e04c3fSmrg   case GL_TEXTURE_CUBE_MAP:
360001e04c3fSmrg      /* GL_TEXTURE_CUBE_MAP is only allowed by OpenGL 4.5 here, which
360101e04c3fSmrg       * includes the DSA API.
360201e04c3fSmrg       *
360301e04c3fSmrg       * Because DSA is only enabled for GL 3.1+ and this can be called
360401e04c3fSmrg       * from _mesa_FramebufferTextureLayer in compatibility profile,
360501e04c3fSmrg       * we need to check the version.
360601e04c3fSmrg       */
360701e04c3fSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Version >= 31;
360801e04c3fSmrg   }
360901e04c3fSmrg
361001e04c3fSmrg   _mesa_error(ctx, GL_INVALID_OPERATION,
361101e04c3fSmrg               "%s(invalid texture target %s)", caller,
361201e04c3fSmrg               _mesa_enum_to_string(target));
361301e04c3fSmrg   return false;
361401e04c3fSmrg}
361501e04c3fSmrg
361601e04c3fSmrg
361701e04c3fSmrg/**
361801e04c3fSmrg * Common code called by glFramebufferTexture*D() to verify the texture
361901e04c3fSmrg * target.
362001e04c3fSmrg *
362101e04c3fSmrg * \return true if no errors, false if errors
362201e04c3fSmrg */
362301e04c3fSmrgstatic bool
362401e04c3fSmrgcheck_textarget(struct gl_context *ctx, int dims, GLenum target,
362501e04c3fSmrg                GLenum textarget, const char *caller)
362601e04c3fSmrg{
362701e04c3fSmrg   bool err = false;
362801e04c3fSmrg
362901e04c3fSmrg   switch (textarget) {
363001e04c3fSmrg   case GL_TEXTURE_1D:
363101e04c3fSmrg      err = dims != 1;
363201e04c3fSmrg      break;
363301e04c3fSmrg   case GL_TEXTURE_1D_ARRAY:
363401e04c3fSmrg      err = dims != 1 || !ctx->Extensions.EXT_texture_array;
363501e04c3fSmrg      break;
363601e04c3fSmrg   case GL_TEXTURE_2D:
363701e04c3fSmrg      err = dims != 2;
363801e04c3fSmrg      break;
363901e04c3fSmrg   case GL_TEXTURE_2D_ARRAY:
364001e04c3fSmrg      err = dims != 2 || !ctx->Extensions.EXT_texture_array ||
364101e04c3fSmrg            (_mesa_is_gles(ctx) && ctx->Version < 30);
364201e04c3fSmrg      break;
364301e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE:
364401e04c3fSmrg   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
364501e04c3fSmrg      err = dims != 2 ||
364601e04c3fSmrg            !ctx->Extensions.ARB_texture_multisample ||
364701e04c3fSmrg            (_mesa_is_gles(ctx) && ctx->Version < 31);
364801e04c3fSmrg      break;
364901e04c3fSmrg   case GL_TEXTURE_RECTANGLE:
365001e04c3fSmrg      err = dims != 2 || _mesa_is_gles(ctx) ||
365101e04c3fSmrg            !ctx->Extensions.NV_texture_rectangle;
365201e04c3fSmrg      break;
365301e04c3fSmrg   case GL_TEXTURE_CUBE_MAP:
365401e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_ARRAY:
365501e04c3fSmrg      err = true;
365601e04c3fSmrg      break;
365701e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
365801e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
365901e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
366001e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
366101e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
366201e04c3fSmrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
366301e04c3fSmrg      err = dims != 2 || !ctx->Extensions.ARB_texture_cube_map;
366401e04c3fSmrg      break;
366501e04c3fSmrg   case GL_TEXTURE_3D:
366601e04c3fSmrg      err = dims != 3;
366701e04c3fSmrg      break;
366801e04c3fSmrg   default:
36697117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
367001e04c3fSmrg                  "%s(unknown textarget 0x%x)", caller, textarget);
367101e04c3fSmrg      return false;
36727117f1b4Smrg   }
36737117f1b4Smrg
367401e04c3fSmrg   if (err) {
36757117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
367601e04c3fSmrg                  "%s(invalid textarget %s)",
367701e04c3fSmrg                  caller, _mesa_enum_to_string(textarget));
367801e04c3fSmrg      return false;
36797117f1b4Smrg   }
36807117f1b4Smrg
368101e04c3fSmrg   /* Make sure textarget is consistent with the texture's type */
368201e04c3fSmrg   err = (target == GL_TEXTURE_CUBE_MAP) ?
368301e04c3fSmrg          !_mesa_is_cube_face(textarget): (target != textarget);
36847117f1b4Smrg
368501e04c3fSmrg   if (err) {
368601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
368701e04c3fSmrg                  "%s(mismatched texture target)", caller);
368801e04c3fSmrg      return false;
368901e04c3fSmrg   }
36907117f1b4Smrg
369101e04c3fSmrg   return true;
369201e04c3fSmrg}
369301e04c3fSmrg
369401e04c3fSmrg
369501e04c3fSmrg/**
369601e04c3fSmrg * Common code called by gl*FramebufferTextureLayer() and
369701e04c3fSmrg * glFramebufferTexture3D() to validate the layer.
369801e04c3fSmrg *
369901e04c3fSmrg * \return true if no errors, false if errors
370001e04c3fSmrg */
370101e04c3fSmrgstatic bool
370201e04c3fSmrgcheck_layer(struct gl_context *ctx, GLenum target, GLint layer,
370301e04c3fSmrg            const char *caller)
370401e04c3fSmrg{
370501e04c3fSmrg   /* Page 306 (page 328 of the PDF) of the OpenGL 4.5 (Core Profile)
370601e04c3fSmrg    * spec says:
370701e04c3fSmrg    *
370801e04c3fSmrg    *    "An INVALID_VALUE error is generated if texture is non-zero
370901e04c3fSmrg    *     and layer is negative."
371001e04c3fSmrg    */
371101e04c3fSmrg   if (layer < 0) {
371201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(layer %d < 0)", caller, layer);
371301e04c3fSmrg      return false;
371401e04c3fSmrg   }
371501e04c3fSmrg
371601e04c3fSmrg   if (target == GL_TEXTURE_3D) {
371701e04c3fSmrg      const GLuint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
371801e04c3fSmrg      if (layer >= maxSize) {
371901e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
372001e04c3fSmrg                     "%s(invalid layer %u)", caller, layer);
372101e04c3fSmrg         return false;
37227117f1b4Smrg      }
372301e04c3fSmrg   }
372401e04c3fSmrg   else if ((target == GL_TEXTURE_1D_ARRAY) ||
372501e04c3fSmrg            (target == GL_TEXTURE_2D_ARRAY) ||
372601e04c3fSmrg            (target == GL_TEXTURE_CUBE_MAP_ARRAY) ||
372701e04c3fSmrg            (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) {
372801e04c3fSmrg      if (layer >= ctx->Const.MaxArrayTextureLayers) {
372901e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
373001e04c3fSmrg                     "%s(layer %u >= GL_MAX_ARRAY_TEXTURE_LAYERS)",
373101e04c3fSmrg                     caller, layer);
373201e04c3fSmrg         return false;
3733c1f859d4Smrg      }
373401e04c3fSmrg   }
373501e04c3fSmrg   else if (target == GL_TEXTURE_CUBE_MAP) {
373601e04c3fSmrg      if (layer >= 6) {
37377117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
373801e04c3fSmrg                     "%s(layer %u >= 6)", caller, layer);
373901e04c3fSmrg         return false;
37407117f1b4Smrg      }
37417117f1b4Smrg   }
37427117f1b4Smrg
374301e04c3fSmrg   return true;
374401e04c3fSmrg}
374501e04c3fSmrg
374601e04c3fSmrg
374701e04c3fSmrg/**
374801e04c3fSmrg * Common code called by all gl*FramebufferTexture*() entry points to verify
374901e04c3fSmrg * the level.
375001e04c3fSmrg *
375101e04c3fSmrg * \return true if no errors, false if errors
375201e04c3fSmrg */
375301e04c3fSmrgstatic bool
375401e04c3fSmrgcheck_level(struct gl_context *ctx, struct gl_texture_object *texObj,
375501e04c3fSmrg            GLenum target, GLint level, const char *caller)
375601e04c3fSmrg{
375701e04c3fSmrg   /* Section 9.2.8 of the OpenGL 4.6 specification says:
375801e04c3fSmrg    *
375901e04c3fSmrg    *    "If texture refers to an immutable-format texture, level must be
376001e04c3fSmrg    *     greater than or equal to zero and smaller than the value of
376101e04c3fSmrg    *     TEXTURE_VIEW_NUM_LEVELS for texture."
376201e04c3fSmrg    */
37637ec681f3Smrg   const int max_levels = texObj->Immutable ? texObj->Attrib.ImmutableLevels :
376401e04c3fSmrg                          _mesa_max_texture_levels(ctx, target);
376501e04c3fSmrg
376601e04c3fSmrg   if (level < 0 || level >= max_levels) {
376701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
376801e04c3fSmrg                  "%s(invalid level %d)", caller, level);
376901e04c3fSmrg      return false;
377001e04c3fSmrg   }
377101e04c3fSmrg
377201e04c3fSmrg   return true;
377301e04c3fSmrg}
377401e04c3fSmrg
377501e04c3fSmrg
377601e04c3fSmrgstruct gl_renderbuffer_attachment *
377701e04c3fSmrg_mesa_get_and_validate_attachment(struct gl_context *ctx,
377801e04c3fSmrg                                  struct gl_framebuffer *fb,
377901e04c3fSmrg                                  GLenum attachment, const char *caller)
378001e04c3fSmrg{
378101e04c3fSmrg   /* The window-system framebuffer object is immutable */
378201e04c3fSmrg   if (_mesa_is_winsys_fbo(fb)) {
378301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(window-system framebuffer)",
378401e04c3fSmrg                  caller);
378501e04c3fSmrg      return NULL;
378601e04c3fSmrg   }
378701e04c3fSmrg
378801e04c3fSmrg   /* Not a hash lookup, so we can afford to get the attachment here. */
378901e04c3fSmrg   bool is_color_attachment;
379001e04c3fSmrg   struct gl_renderbuffer_attachment *att =
379101e04c3fSmrg      get_attachment(ctx, fb, attachment, &is_color_attachment);
37927117f1b4Smrg   if (att == NULL) {
379301e04c3fSmrg      if (is_color_attachment) {
379401e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
379501e04c3fSmrg                     "%s(invalid color attachment %s)", caller,
379601e04c3fSmrg                     _mesa_enum_to_string(attachment));
379701e04c3fSmrg      } else {
379801e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
379901e04c3fSmrg                     "%s(invalid attachment %s)", caller,
380001e04c3fSmrg                     _mesa_enum_to_string(attachment));
380101e04c3fSmrg      }
380201e04c3fSmrg      return NULL;
38037117f1b4Smrg   }
38047117f1b4Smrg
380501e04c3fSmrg   return att;
380601e04c3fSmrg}
380701e04c3fSmrg
380801e04c3fSmrg
380901e04c3fSmrgvoid
381001e04c3fSmrg_mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb,
381101e04c3fSmrg                          GLenum attachment,
381201e04c3fSmrg                          struct gl_renderbuffer_attachment *att,
381301e04c3fSmrg                          struct gl_texture_object *texObj, GLenum textarget,
3814a8bb7a65Smaya                          GLint level, GLsizei samples,
3815a8bb7a65Smaya                          GLuint layer, GLboolean layered)
381601e04c3fSmrg{
38177ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
38187117f1b4Smrg
381901e04c3fSmrg   simple_mtx_lock(&fb->Mutex);
38207117f1b4Smrg   if (texObj) {
3821af69d88dSmrg      if (attachment == GL_DEPTH_ATTACHMENT &&
3822af69d88dSmrg          texObj == fb->Attachment[BUFFER_STENCIL].Texture &&
3823af69d88dSmrg          level == fb->Attachment[BUFFER_STENCIL].TextureLevel &&
3824af69d88dSmrg          _mesa_tex_target_to_face(textarget) ==
3825af69d88dSmrg          fb->Attachment[BUFFER_STENCIL].CubeMapFace &&
3826a8bb7a65Smaya          samples == fb->Attachment[BUFFER_STENCIL].NumSamples &&
382701e04c3fSmrg          layer == fb->Attachment[BUFFER_STENCIL].Zoffset) {
382801e04c3fSmrg         /* The texture object is already attached to the stencil attachment
382901e04c3fSmrg          * point. Don't create a new renderbuffer; just reuse the stencil
383001e04c3fSmrg          * attachment's. This is required to prevent a GL error in
383101e04c3fSmrg          * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL).
383201e04c3fSmrg          */
383301e04c3fSmrg         reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH,
383401e04c3fSmrg                                              BUFFER_STENCIL);
3835af69d88dSmrg      } else if (attachment == GL_STENCIL_ATTACHMENT &&
383601e04c3fSmrg                 texObj == fb->Attachment[BUFFER_DEPTH].Texture &&
3837af69d88dSmrg                 level == fb->Attachment[BUFFER_DEPTH].TextureLevel &&
3838af69d88dSmrg                 _mesa_tex_target_to_face(textarget) ==
3839af69d88dSmrg                 fb->Attachment[BUFFER_DEPTH].CubeMapFace &&
3840a8bb7a65Smaya                 samples == fb->Attachment[BUFFER_DEPTH].NumSamples &&
384101e04c3fSmrg                 layer == fb->Attachment[BUFFER_DEPTH].Zoffset) {
384201e04c3fSmrg         /* As above, but with depth and stencil transposed. */
384301e04c3fSmrg         reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL,
384401e04c3fSmrg                                              BUFFER_DEPTH);
3845af69d88dSmrg      } else {
384601e04c3fSmrg         set_texture_attachment(ctx, fb, att, texObj, textarget,
3847a8bb7a65Smaya                                level, samples, layer, layered);
384801e04c3fSmrg
384901e04c3fSmrg         if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
385001e04c3fSmrg            /* Above we created a new renderbuffer and attached it to the
385101e04c3fSmrg             * depth attachment point. Now attach it to the stencil attachment
385201e04c3fSmrg             * point too.
385301e04c3fSmrg             */
385401e04c3fSmrg            assert(att == &fb->Attachment[BUFFER_DEPTH]);
385501e04c3fSmrg            reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL,
385601e04c3fSmrg                                                 BUFFER_DEPTH);
385701e04c3fSmrg         }
3858af69d88dSmrg      }
3859af69d88dSmrg
38604a49301eSmrg      /* Set the render-to-texture flag.  We'll check this flag in
38614a49301eSmrg       * glTexImage() and friends to determine if we need to revalidate
38624a49301eSmrg       * any FBOs that might be rendering into this texture.
38634a49301eSmrg       * This flag never gets cleared since it's non-trivial to determine
38644a49301eSmrg       * when all FBOs might be done rendering to this texture.  That's OK
38654a49301eSmrg       * though since it's uncommon to render to a texture then repeatedly
38664a49301eSmrg       * call glTexImage() to change images in the texture.
38674a49301eSmrg       */
38684a49301eSmrg      texObj->_RenderToTexture = GL_TRUE;
38697117f1b4Smrg   }
38707117f1b4Smrg   else {
3871af69d88dSmrg      remove_attachment(ctx, att);
3872af69d88dSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
387301e04c3fSmrg         assert(att == &fb->Attachment[BUFFER_DEPTH]);
387401e04c3fSmrg         remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]);
3875af69d88dSmrg      }
38767117f1b4Smrg   }
38774a49301eSmrg
38784a49301eSmrg   invalidate_framebuffer(fb);
38794a49301eSmrg
388001e04c3fSmrg   simple_mtx_unlock(&fb->Mutex);
38817117f1b4Smrg}
38827117f1b4Smrg
38837117f1b4Smrg
388401e04c3fSmrgstatic void
388501e04c3fSmrgframebuffer_texture_with_dims_no_error(GLenum target, GLenum attachment,
388601e04c3fSmrg                                       GLenum textarget, GLuint texture,
388701e04c3fSmrg                                       GLint level, GLint layer)
38887117f1b4Smrg{
38897117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
38907117f1b4Smrg
389101e04c3fSmrg   /* Get the framebuffer object */
389201e04c3fSmrg   struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
3893af69d88dSmrg
389401e04c3fSmrg   /* Get the texture object */
389501e04c3fSmrg   struct gl_texture_object *texObj =
389601e04c3fSmrg      get_texture_for_framebuffer(ctx, texture);
3897af69d88dSmrg
389801e04c3fSmrg   struct gl_renderbuffer_attachment *att =
389901e04c3fSmrg      get_attachment(ctx, fb, attachment, NULL);
390001e04c3fSmrg
390101e04c3fSmrg   _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
3902a8bb7a65Smaya                             level, 0, layer, GL_FALSE);
390301e04c3fSmrg}
390401e04c3fSmrg
390501e04c3fSmrg
390601e04c3fSmrgstatic void
39077ec681f3Smrgframebuffer_texture_with_dims(int dims, GLenum target, GLuint framebuffer,
390801e04c3fSmrg                              GLenum attachment, GLenum textarget,
3909a8bb7a65Smaya                              GLuint texture, GLint level, GLsizei samples,
39107ec681f3Smrg                              GLint layer, const char *caller, bool dsa)
391101e04c3fSmrg{
391201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
391301e04c3fSmrg   struct gl_framebuffer *fb;
391401e04c3fSmrg   struct gl_texture_object *texObj;
391501e04c3fSmrg
391601e04c3fSmrg   /* Get the framebuffer object */
39177ec681f3Smrg   if (dsa) {
39187ec681f3Smrg      fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, caller);
39197ec681f3Smrg   } else {
39207ec681f3Smrg      fb = get_framebuffer_target(ctx, target);
39217ec681f3Smrg   }
392201e04c3fSmrg   if (!fb) {
392301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller,
392401e04c3fSmrg                  _mesa_enum_to_string(target));
392501e04c3fSmrg      return;
392601e04c3fSmrg   }
392701e04c3fSmrg
392801e04c3fSmrg   /* Get the texture object */
392901e04c3fSmrg   if (!get_texture_for_framebuffer_err(ctx, texture, false, caller, &texObj))
393001e04c3fSmrg      return;
393101e04c3fSmrg
393201e04c3fSmrg   if (texObj) {
393301e04c3fSmrg      if (!check_textarget(ctx, dims, texObj->Target, textarget, caller))
393401e04c3fSmrg         return;
393501e04c3fSmrg
393601e04c3fSmrg      if ((dims == 3) && !check_layer(ctx, texObj->Target, layer, caller))
393701e04c3fSmrg         return;
393801e04c3fSmrg
393901e04c3fSmrg      if (!check_level(ctx, texObj, textarget, level, caller))
3940af69d88dSmrg         return;
39417117f1b4Smrg   }
39427117f1b4Smrg
394301e04c3fSmrg   struct gl_renderbuffer_attachment *att =
394401e04c3fSmrg      _mesa_get_and_validate_attachment(ctx, fb, attachment, caller);
394501e04c3fSmrg   if (!att)
394601e04c3fSmrg      return;
394701e04c3fSmrg
394801e04c3fSmrg   _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
3949a8bb7a65Smaya                             level, samples, layer, GL_FALSE);
39507117f1b4Smrg}
39517117f1b4Smrg
39527117f1b4Smrg
39537117f1b4Smrgvoid GLAPIENTRY
395401e04c3fSmrg_mesa_FramebufferTexture1D_no_error(GLenum target, GLenum attachment,
395501e04c3fSmrg                                    GLenum textarget, GLuint texture,
395601e04c3fSmrg                                    GLint level)
395701e04c3fSmrg{
395801e04c3fSmrg   framebuffer_texture_with_dims_no_error(target, attachment, textarget,
395901e04c3fSmrg                                          texture, level, 0);
396001e04c3fSmrg}
396101e04c3fSmrg
396201e04c3fSmrg
396301e04c3fSmrgvoid GLAPIENTRY
396401e04c3fSmrg_mesa_FramebufferTexture1D(GLenum target, GLenum attachment,
3965af69d88dSmrg                           GLenum textarget, GLuint texture, GLint level)
39667117f1b4Smrg{
39677ec681f3Smrg   framebuffer_texture_with_dims(1, target, 0, attachment, textarget, texture,
39687ec681f3Smrg                                 level, 0, 0, "glFramebufferTexture1D", false);
396901e04c3fSmrg}
39707117f1b4Smrg
3971af69d88dSmrg
397201e04c3fSmrgvoid GLAPIENTRY
397301e04c3fSmrg_mesa_FramebufferTexture2D_no_error(GLenum target, GLenum attachment,
397401e04c3fSmrg                                    GLenum textarget, GLuint texture,
397501e04c3fSmrg                                    GLint level)
397601e04c3fSmrg{
397701e04c3fSmrg   framebuffer_texture_with_dims_no_error(target, attachment, textarget,
397801e04c3fSmrg                                          texture, level, 0);
397901e04c3fSmrg}
3980af69d88dSmrg
39817117f1b4Smrg
398201e04c3fSmrgvoid GLAPIENTRY
398301e04c3fSmrg_mesa_FramebufferTexture2D(GLenum target, GLenum attachment,
398401e04c3fSmrg                           GLenum textarget, GLuint texture, GLint level)
398501e04c3fSmrg{
39867ec681f3Smrg   framebuffer_texture_with_dims(2, target, 0, attachment, textarget, texture,
39877ec681f3Smrg                                 level, 0, 0, "glFramebufferTexture2D", false);
3988a8bb7a65Smaya}
3989a8bb7a65Smaya
3990a8bb7a65Smaya
3991a8bb7a65Smayavoid GLAPIENTRY
3992a8bb7a65Smaya_mesa_FramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment,
3993a8bb7a65Smaya                                         GLenum textarget, GLuint texture,
3994a8bb7a65Smaya                                         GLint level, GLsizei samples)
3995a8bb7a65Smaya{
39967ec681f3Smrg   framebuffer_texture_with_dims(2, target, 0, attachment, textarget, texture,
39977ec681f3Smrg                                 level, samples, 0,
39987ec681f3Smrg                                 "glFramebufferTexture2DMultisampleEXT",
39997ec681f3Smrg                                 false);
400001e04c3fSmrg}
400101e04c3fSmrg
400201e04c3fSmrg
400301e04c3fSmrgvoid GLAPIENTRY
400401e04c3fSmrg_mesa_FramebufferTexture3D_no_error(GLenum target, GLenum attachment,
400501e04c3fSmrg                                    GLenum textarget, GLuint texture,
400601e04c3fSmrg                                    GLint level, GLint layer)
400701e04c3fSmrg{
400801e04c3fSmrg   framebuffer_texture_with_dims_no_error(target, attachment, textarget,
400901e04c3fSmrg                                          texture, level, layer);
40107117f1b4Smrg}
40117117f1b4Smrg
40127117f1b4Smrg
40137117f1b4Smrgvoid GLAPIENTRY
4014af69d88dSmrg_mesa_FramebufferTexture3D(GLenum target, GLenum attachment,
4015af69d88dSmrg                           GLenum textarget, GLuint texture,
401601e04c3fSmrg                           GLint level, GLint layer)
401701e04c3fSmrg{
40187ec681f3Smrg   framebuffer_texture_with_dims(3, target, 0, attachment, textarget, texture,
40197ec681f3Smrg                                 level, 0, layer, "glFramebufferTexture3D", false);
402001e04c3fSmrg}
402101e04c3fSmrg
402201e04c3fSmrg
402301e04c3fSmrgstatic ALWAYS_INLINE void
402401e04c3fSmrgframe_buffer_texture(GLuint framebuffer, GLenum target,
402501e04c3fSmrg                     GLenum attachment, GLuint texture,
402601e04c3fSmrg                     GLint level, GLint layer, const char *func,
402701e04c3fSmrg                     bool dsa, bool no_error, bool check_layered)
40287117f1b4Smrg{
40297117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
403001e04c3fSmrg   GLboolean layered = GL_FALSE;
40317117f1b4Smrg
403201e04c3fSmrg   if (!no_error && check_layered) {
403301e04c3fSmrg      if (!_mesa_has_geometry_shaders(ctx)) {
403401e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
403501e04c3fSmrg                     "unsupported function (%s) called", func);
403601e04c3fSmrg         return;
403701e04c3fSmrg      }
40387117f1b4Smrg   }
40397117f1b4Smrg
404001e04c3fSmrg   /* Get the framebuffer object */
404101e04c3fSmrg   struct gl_framebuffer *fb;
404201e04c3fSmrg   if (no_error) {
404301e04c3fSmrg      if (dsa) {
404401e04c3fSmrg         fb = _mesa_lookup_framebuffer(ctx, framebuffer);
404501e04c3fSmrg      } else {
404601e04c3fSmrg         fb = get_framebuffer_target(ctx, target);
404701e04c3fSmrg      }
404801e04c3fSmrg   } else {
404901e04c3fSmrg      if (dsa) {
405001e04c3fSmrg         fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func);
405101e04c3fSmrg         if (!fb)
405201e04c3fSmrg            return;
405301e04c3fSmrg      } else {
405401e04c3fSmrg         fb = get_framebuffer_target(ctx, target);
405501e04c3fSmrg         if (!fb) {
405601e04c3fSmrg            _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)",
405701e04c3fSmrg                        func, _mesa_enum_to_string(target));
405801e04c3fSmrg            return;
405901e04c3fSmrg         }
406001e04c3fSmrg      }
406101e04c3fSmrg   }
406201e04c3fSmrg
406301e04c3fSmrg   /* Get the texture object and framebuffer attachment*/
406401e04c3fSmrg   struct gl_renderbuffer_attachment *att;
406501e04c3fSmrg   struct gl_texture_object *texObj;
406601e04c3fSmrg   if (no_error) {
406701e04c3fSmrg      texObj = get_texture_for_framebuffer(ctx, texture);
406801e04c3fSmrg      att = get_attachment(ctx, fb, attachment, NULL);
406901e04c3fSmrg   } else {
407001e04c3fSmrg      if (!get_texture_for_framebuffer_err(ctx, texture, check_layered, func,
407101e04c3fSmrg                                           &texObj))
407201e04c3fSmrg         return;
407301e04c3fSmrg
407401e04c3fSmrg      att = _mesa_get_and_validate_attachment(ctx, fb, attachment, func);
407501e04c3fSmrg      if (!att)
407601e04c3fSmrg         return;
407701e04c3fSmrg   }
407801e04c3fSmrg
407901e04c3fSmrg   GLenum textarget = 0;
408001e04c3fSmrg   if (texObj) {
408101e04c3fSmrg      if (check_layered) {
408201e04c3fSmrg         /* We do this regardless of no_error because this sets layered */
408301e04c3fSmrg         if (!check_layered_texture_target(ctx, texObj->Target, func,
408401e04c3fSmrg                                           &layered))
408501e04c3fSmrg            return;
408601e04c3fSmrg      }
408701e04c3fSmrg
408801e04c3fSmrg      if (!no_error) {
408901e04c3fSmrg         if (!check_layered) {
409001e04c3fSmrg            if (!check_texture_target(ctx, texObj->Target, func))
409101e04c3fSmrg               return;
409201e04c3fSmrg
409301e04c3fSmrg            if (!check_layer(ctx, texObj->Target, layer, func))
409401e04c3fSmrg               return;
409501e04c3fSmrg         }
409601e04c3fSmrg
409701e04c3fSmrg         if (!check_level(ctx, texObj, texObj->Target, level, func))
409801e04c3fSmrg            return;
409901e04c3fSmrg      }
410001e04c3fSmrg
410101e04c3fSmrg      if (!check_layered && texObj->Target == GL_TEXTURE_CUBE_MAP) {
410201e04c3fSmrg         assert(layer >= 0 && layer < 6);
410301e04c3fSmrg         textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
410401e04c3fSmrg         layer = 0;
410501e04c3fSmrg      }
410601e04c3fSmrg   }
410701e04c3fSmrg
410801e04c3fSmrg   _mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
4109a8bb7a65Smaya                             level, 0, layer, layered);
411001e04c3fSmrg}
411101e04c3fSmrg
411201e04c3fSmrgvoid GLAPIENTRY
411301e04c3fSmrg_mesa_FramebufferTextureLayer_no_error(GLenum target, GLenum attachment,
411401e04c3fSmrg                                       GLuint texture, GLint level,
411501e04c3fSmrg                                       GLint layer)
411601e04c3fSmrg{
411701e04c3fSmrg   frame_buffer_texture(0, target, attachment, texture, level, layer,
411801e04c3fSmrg                        "glFramebufferTextureLayer", false, true, false);
41197117f1b4Smrg}
41207117f1b4Smrg
41217117f1b4Smrg
4122c1f859d4Smrgvoid GLAPIENTRY
4123af69d88dSmrg_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment,
4124af69d88dSmrg                              GLuint texture, GLint level, GLint layer)
4125c1f859d4Smrg{
412601e04c3fSmrg   frame_buffer_texture(0, target, attachment, texture, level, layer,
412701e04c3fSmrg                        "glFramebufferTextureLayer", false, false, false);
412801e04c3fSmrg}
412901e04c3fSmrg
413001e04c3fSmrg
413101e04c3fSmrgvoid GLAPIENTRY
413201e04c3fSmrg_mesa_NamedFramebufferTextureLayer_no_error(GLuint framebuffer,
413301e04c3fSmrg                                            GLenum attachment,
413401e04c3fSmrg                                            GLuint texture, GLint level,
413501e04c3fSmrg                                            GLint layer)
413601e04c3fSmrg{
413701e04c3fSmrg   frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer,
413801e04c3fSmrg                        "glNamedFramebufferTextureLayer", true, true, false);
413901e04c3fSmrg}
414001e04c3fSmrg
414101e04c3fSmrg
414201e04c3fSmrgvoid GLAPIENTRY
414301e04c3fSmrg_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment,
414401e04c3fSmrg                                   GLuint texture, GLint level, GLint layer)
414501e04c3fSmrg{
414601e04c3fSmrg   frame_buffer_texture(framebuffer, 0, attachment, texture, level, layer,
414701e04c3fSmrg                        "glNamedFramebufferTextureLayer", true, false, false);
414801e04c3fSmrg}
4149c1f859d4Smrg
415001e04c3fSmrg
415101e04c3fSmrgvoid GLAPIENTRY
415201e04c3fSmrg_mesa_FramebufferTexture_no_error(GLenum target, GLenum attachment,
415301e04c3fSmrg                                  GLuint texture, GLint level)
415401e04c3fSmrg{
415501e04c3fSmrg   frame_buffer_texture(0, target, attachment, texture, level, 0,
415601e04c3fSmrg                        "glFramebufferTexture", false, true, true);
4157af69d88dSmrg}
4158af69d88dSmrg
4159af69d88dSmrg
4160af69d88dSmrgvoid GLAPIENTRY
4161af69d88dSmrg_mesa_FramebufferTexture(GLenum target, GLenum attachment,
4162af69d88dSmrg                         GLuint texture, GLint level)
4163af69d88dSmrg{
416401e04c3fSmrg   frame_buffer_texture(0, target, attachment, texture, level, 0,
416501e04c3fSmrg                        "glFramebufferTexture", false, false, true);
416601e04c3fSmrg}
4167af69d88dSmrg
416801e04c3fSmrgvoid GLAPIENTRY
416901e04c3fSmrg_mesa_NamedFramebufferTexture_no_error(GLuint framebuffer, GLenum attachment,
417001e04c3fSmrg                                       GLuint texture, GLint level)
417101e04c3fSmrg{
417201e04c3fSmrg   frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0,
417301e04c3fSmrg                        "glNamedFramebufferTexture", true, true, true);
4174c1f859d4Smrg}
4175c1f859d4Smrg
4176c1f859d4Smrg
41777117f1b4Smrgvoid GLAPIENTRY
417801e04c3fSmrg_mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment,
417901e04c3fSmrg                              GLuint texture, GLint level)
41807117f1b4Smrg{
418101e04c3fSmrg   frame_buffer_texture(framebuffer, 0, attachment, texture, level, 0,
418201e04c3fSmrg                        "glNamedFramebufferTexture", true, false, true);
418301e04c3fSmrg}
41847117f1b4Smrg
41857117f1b4Smrg
41867ec681f3Smrgvoid GLAPIENTRY
41877ec681f3Smrg_mesa_NamedFramebufferTexture1DEXT(GLuint framebuffer, GLenum attachment,
41887ec681f3Smrg                                   GLenum textarget, GLuint texture, GLint level)
41897ec681f3Smrg{
41907ec681f3Smrg   framebuffer_texture_with_dims(1, GL_FRAMEBUFFER, framebuffer, attachment,
41917ec681f3Smrg                                 textarget, texture, level, 0, 0,
41927ec681f3Smrg                                 "glNamedFramebufferTexture1DEXT", true);
41937ec681f3Smrg}
41947ec681f3Smrg
41957ec681f3Smrg
41967ec681f3Smrgvoid GLAPIENTRY
41977ec681f3Smrg_mesa_NamedFramebufferTexture2DEXT(GLuint framebuffer, GLenum attachment,
41987ec681f3Smrg                                   GLenum textarget, GLuint texture, GLint level)
41997ec681f3Smrg{
42007ec681f3Smrg   framebuffer_texture_with_dims(2, GL_FRAMEBUFFER, framebuffer, attachment,
42017ec681f3Smrg                                 textarget, texture, level, 0, 0,
42027ec681f3Smrg                                 "glNamedFramebufferTexture2DEXT", true);
42037ec681f3Smrg}
42047ec681f3Smrg
42057ec681f3Smrg
42067ec681f3Smrgvoid GLAPIENTRY
42077ec681f3Smrg_mesa_NamedFramebufferTexture3DEXT(GLuint framebuffer, GLenum attachment,
42087ec681f3Smrg                                   GLenum textarget, GLuint texture,
42097ec681f3Smrg                                   GLint level, GLint zoffset)
42107ec681f3Smrg{
42117ec681f3Smrg   framebuffer_texture_with_dims(3, GL_FRAMEBUFFER, framebuffer, attachment,
42127ec681f3Smrg                                 textarget, texture, level, 0, zoffset,
42137ec681f3Smrg                                 "glNamedFramebufferTexture3DEXT", true);
42147ec681f3Smrg}
42157ec681f3Smrg
42167ec681f3Smrg
421701e04c3fSmrgvoid
421801e04c3fSmrg_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
421901e04c3fSmrg                               struct gl_framebuffer *fb,
422001e04c3fSmrg                               GLenum attachment,
422101e04c3fSmrg                               struct gl_renderbuffer *rb)
422201e04c3fSmrg{
422301e04c3fSmrg   assert(!_mesa_is_winsys_fbo(fb));
42247117f1b4Smrg
42257ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_BUFFERS, 0);
42267117f1b4Smrg
422701e04c3fSmrg   assert(ctx->Driver.FramebufferRenderbuffer);
422801e04c3fSmrg   ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
422901e04c3fSmrg
423001e04c3fSmrg   /* Some subsequent GL commands may depend on the framebuffer's visual
423101e04c3fSmrg    * after the binding is updated.  Update visual info now.
423201e04c3fSmrg    */
423301e04c3fSmrg   _mesa_update_framebuffer_visual(ctx, fb);
423401e04c3fSmrg}
423501e04c3fSmrg
423601e04c3fSmrgstatic ALWAYS_INLINE void
423701e04c3fSmrgframebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
423801e04c3fSmrg                         GLenum attachment, GLenum renderbuffertarget,
423901e04c3fSmrg                         GLuint renderbuffer, const char *func, bool no_error)
424001e04c3fSmrg{
424101e04c3fSmrg   struct gl_renderbuffer_attachment *att;
424201e04c3fSmrg   struct gl_renderbuffer *rb;
424301e04c3fSmrg   bool is_color_attachment;
424401e04c3fSmrg
424501e04c3fSmrg   if (!no_error && renderbuffertarget != GL_RENDERBUFFER) {
42467117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
424701e04c3fSmrg                  "%s(renderbuffertarget is not GL_RENDERBUFFER)", func);
42487117f1b4Smrg      return;
42497117f1b4Smrg   }
42507117f1b4Smrg
42517117f1b4Smrg   if (renderbuffer) {
425201e04c3fSmrg      if (!no_error) {
425301e04c3fSmrg         rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, func);
425401e04c3fSmrg         if (!rb)
425501e04c3fSmrg            return;
425601e04c3fSmrg      } else {
425701e04c3fSmrg         rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
42583464ebd5Sriastradh      }
425901e04c3fSmrg   } else {
42607117f1b4Smrg      /* remove renderbuffer attachment */
42617117f1b4Smrg      rb = NULL;
42627117f1b4Smrg   }
42637117f1b4Smrg
426401e04c3fSmrg   if (!no_error) {
426501e04c3fSmrg      if (_mesa_is_winsys_fbo(fb)) {
426601e04c3fSmrg         /* Can't attach new renderbuffers to a window system framebuffer */
42674a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
426801e04c3fSmrg                     "%s(window-system framebuffer)", func);
42694a49301eSmrg         return;
42704a49301eSmrg      }
42714a49301eSmrg
427201e04c3fSmrg      att = get_attachment(ctx, fb, attachment, &is_color_attachment);
427301e04c3fSmrg      if (att == NULL) {
427401e04c3fSmrg         /*
427501e04c3fSmrg          * From OpenGL 4.5 spec, section 9.2.7 "Attaching Renderbuffer Images
427601e04c3fSmrg          * to a Framebuffer":
427701e04c3fSmrg          *
427801e04c3fSmrg          *    "An INVALID_OPERATION error is generated if attachment is
427901e04c3fSmrg          *    COLOR_- ATTACHMENTm where m is greater than or equal to the
428001e04c3fSmrg          *    value of MAX_COLOR_- ATTACHMENTS ."
428101e04c3fSmrg          *
428201e04c3fSmrg          * If we are at this point, is because the attachment is not valid, so
428301e04c3fSmrg          * if is_color_attachment is true, is because of the previous reason.
428401e04c3fSmrg          */
428501e04c3fSmrg         if (is_color_attachment) {
428601e04c3fSmrg            _mesa_error(ctx, GL_INVALID_OPERATION,
428701e04c3fSmrg                        "%s(invalid color attachment %s)", func,
428801e04c3fSmrg                        _mesa_enum_to_string(attachment));
428901e04c3fSmrg         } else {
429001e04c3fSmrg            _mesa_error(ctx, GL_INVALID_ENUM,
429101e04c3fSmrg                        "%s(invalid attachment %s)", func,
429201e04c3fSmrg                        _mesa_enum_to_string(attachment));
429301e04c3fSmrg         }
42947117f1b4Smrg
429501e04c3fSmrg         return;
429601e04c3fSmrg      }
42977117f1b4Smrg
429801e04c3fSmrg      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
429901e04c3fSmrg          rb && rb->Format != MESA_FORMAT_NONE) {
430001e04c3fSmrg         /* make sure the renderbuffer is a depth/stencil format */
430101e04c3fSmrg         const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
430201e04c3fSmrg         if (baseFormat != GL_DEPTH_STENCIL) {
430301e04c3fSmrg            _mesa_error(ctx, GL_INVALID_OPERATION,
430401e04c3fSmrg                        "%s(renderbuffer is not DEPTH_STENCIL format)", func);
430501e04c3fSmrg            return;
430601e04c3fSmrg         }
430701e04c3fSmrg      }
430801e04c3fSmrg   }
430901e04c3fSmrg
431001e04c3fSmrg   _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
43117117f1b4Smrg}
43127117f1b4Smrg
431301e04c3fSmrgstatic void
431401e04c3fSmrgframebuffer_renderbuffer_error(struct gl_context *ctx,
431501e04c3fSmrg                               struct gl_framebuffer *fb, GLenum attachment,
431601e04c3fSmrg                               GLenum renderbuffertarget,
431701e04c3fSmrg                               GLuint renderbuffer, const char *func)
431801e04c3fSmrg{
431901e04c3fSmrg   framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget,
432001e04c3fSmrg                            renderbuffer, func, false);
432101e04c3fSmrg}
432201e04c3fSmrg
432301e04c3fSmrgstatic void
432401e04c3fSmrgframebuffer_renderbuffer_no_error(struct gl_context *ctx,
432501e04c3fSmrg                                  struct gl_framebuffer *fb, GLenum attachment,
432601e04c3fSmrg                                  GLenum renderbuffertarget,
432701e04c3fSmrg                                  GLuint renderbuffer, const char *func)
432801e04c3fSmrg{
432901e04c3fSmrg   framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget,
433001e04c3fSmrg                            renderbuffer, func, true);
433101e04c3fSmrg}
43327117f1b4Smrg
43337117f1b4Smrgvoid GLAPIENTRY
433401e04c3fSmrg_mesa_FramebufferRenderbuffer_no_error(GLenum target, GLenum attachment,
433501e04c3fSmrg                                       GLenum renderbuffertarget,
433601e04c3fSmrg                                       GLuint renderbuffer)
43377117f1b4Smrg{
43387117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
43397117f1b4Smrg
434001e04c3fSmrg   struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
434101e04c3fSmrg   framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget,
434201e04c3fSmrg                                     renderbuffer, "glFramebufferRenderbuffer");
434301e04c3fSmrg}
43443464ebd5Sriastradh
434501e04c3fSmrgvoid GLAPIENTRY
434601e04c3fSmrg_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment,
434701e04c3fSmrg                              GLenum renderbuffertarget,
434801e04c3fSmrg                              GLuint renderbuffer)
434901e04c3fSmrg{
435001e04c3fSmrg   struct gl_framebuffer *fb;
435101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
435201e04c3fSmrg
435301e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
435401e04c3fSmrg   if (!fb) {
43557117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
435601e04c3fSmrg                  "glFramebufferRenderbuffer(invalid target %s)",
435701e04c3fSmrg                  _mesa_enum_to_string(target));
43587117f1b4Smrg      return;
43597117f1b4Smrg   }
43607117f1b4Smrg
436101e04c3fSmrg   framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
436201e04c3fSmrg                                  renderbuffer, "glFramebufferRenderbuffer");
436301e04c3fSmrg}
436401e04c3fSmrg
436501e04c3fSmrgvoid GLAPIENTRY
436601e04c3fSmrg_mesa_NamedFramebufferRenderbuffer_no_error(GLuint framebuffer,
436701e04c3fSmrg                                            GLenum attachment,
436801e04c3fSmrg                                            GLenum renderbuffertarget,
436901e04c3fSmrg                                            GLuint renderbuffer)
437001e04c3fSmrg{
437101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
437201e04c3fSmrg
437301e04c3fSmrg   struct gl_framebuffer *fb = _mesa_lookup_framebuffer(ctx, framebuffer);
437401e04c3fSmrg   framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget,
437501e04c3fSmrg                                     renderbuffer,
437601e04c3fSmrg                                     "glNamedFramebufferRenderbuffer");
437701e04c3fSmrg}
437801e04c3fSmrg
437901e04c3fSmrgvoid GLAPIENTRY
438001e04c3fSmrg_mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment,
438101e04c3fSmrg                                   GLenum renderbuffertarget,
438201e04c3fSmrg                                   GLuint renderbuffer)
438301e04c3fSmrg{
438401e04c3fSmrg   struct gl_framebuffer *fb;
438501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
438601e04c3fSmrg
438701e04c3fSmrg   fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
438801e04c3fSmrg                                     "glNamedFramebufferRenderbuffer");
438901e04c3fSmrg   if (!fb)
439001e04c3fSmrg      return;
439101e04c3fSmrg
439201e04c3fSmrg   framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
439301e04c3fSmrg                                  renderbuffer,
439401e04c3fSmrg                                  "glNamedFramebufferRenderbuffer");
439501e04c3fSmrg}
439601e04c3fSmrg
439701e04c3fSmrg
43987ec681f3Smrgvoid GLAPIENTRY
43997ec681f3Smrg_mesa_NamedFramebufferRenderbufferEXT(GLuint framebuffer, GLenum attachment,
44007ec681f3Smrg                                      GLenum renderbuffertarget,
44017ec681f3Smrg                                      GLuint renderbuffer)
44027ec681f3Smrg{
44037ec681f3Smrg   struct gl_framebuffer *fb;
44047ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
44057ec681f3Smrg
44067ec681f3Smrg   fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer,
44077ec681f3Smrg                                     "glNamedFramebufferRenderbufferEXT");
44087ec681f3Smrg   if (!fb)
44097ec681f3Smrg      return;
44107ec681f3Smrg
44117ec681f3Smrg   framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
44127ec681f3Smrg                                  renderbuffer,
44137ec681f3Smrg                                  "glNamedFramebufferRenderbuffer");
44147ec681f3Smrg}
44157ec681f3Smrg
44167ec681f3Smrg
441701e04c3fSmrgstatic void
441801e04c3fSmrgget_framebuffer_attachment_parameter(struct gl_context *ctx,
441901e04c3fSmrg                                     struct gl_framebuffer *buffer,
442001e04c3fSmrg                                     GLenum attachment, GLenum pname,
442101e04c3fSmrg                                     GLint *params, const char *caller)
442201e04c3fSmrg{
442301e04c3fSmrg   const struct gl_renderbuffer_attachment *att;
442401e04c3fSmrg   bool is_color_attachment = false;
442501e04c3fSmrg   GLenum err;
442601e04c3fSmrg
442701e04c3fSmrg   /* The error code for an attachment type of GL_NONE differs between APIs.
442801e04c3fSmrg    *
442901e04c3fSmrg    * From the ES 2.0.25 specification, page 127:
443001e04c3fSmrg    * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then
443101e04c3fSmrg    *  querying any other pname will generate INVALID_ENUM."
443201e04c3fSmrg    *
443301e04c3fSmrg    * From the OpenGL 3.0 specification, page 337, or identically,
443401e04c3fSmrg    * the OpenGL ES 3.0.4 specification, page 240:
443501e04c3fSmrg    *
443601e04c3fSmrg    * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, no
443701e04c3fSmrg    *  framebuffer is bound to target.  In this case querying pname
443801e04c3fSmrg    *  FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero, and all other
443901e04c3fSmrg    *  queries will generate an INVALID_OPERATION error."
444001e04c3fSmrg    */
444101e04c3fSmrg   err = ctx->API == API_OPENGLES2 && ctx->Version < 30 ?
444201e04c3fSmrg      GL_INVALID_ENUM : GL_INVALID_OPERATION;
444301e04c3fSmrg
4444af69d88dSmrg   if (_mesa_is_winsys_fbo(buffer)) {
4445af69d88dSmrg      /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec
4446af69d88dSmrg       * says:
4447af69d88dSmrg       *
4448af69d88dSmrg       *     "If the framebuffer currently bound to target is zero, then
4449af69d88dSmrg       *     INVALID_OPERATION is generated."
4450af69d88dSmrg       *
4451af69d88dSmrg       * The EXT_framebuffer_object spec has the same wording, and the
4452af69d88dSmrg       * OES_framebuffer_object spec refers to the EXT_framebuffer_object
4453af69d88dSmrg       * spec.
4454af69d88dSmrg       */
4455af69d88dSmrg      if ((!_mesa_is_desktop_gl(ctx) ||
4456af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
4457af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
445801e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
445901e04c3fSmrg                     "%s(window-system framebuffer)", caller);
446001e04c3fSmrg         return;
4461af69d88dSmrg      }
4462af69d88dSmrg
4463af69d88dSmrg      if (_mesa_is_gles3(ctx) && attachment != GL_BACK &&
4464af69d88dSmrg          attachment != GL_DEPTH && attachment != GL_STENCIL) {
446501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
446601e04c3fSmrg                     "%s(invalid attachment %s)", caller,
446701e04c3fSmrg                     _mesa_enum_to_string(attachment));
446801e04c3fSmrg         return;
446901e04c3fSmrg      }
447001e04c3fSmrg
447101e04c3fSmrg      /* The specs are not clear about how to handle
447201e04c3fSmrg       * GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME with the default framebuffer,
447301e04c3fSmrg       * but dEQP-GLES3 expects an INVALID_ENUM error. This has also been
447401e04c3fSmrg       * discussed in:
447501e04c3fSmrg       *
447601e04c3fSmrg       * https://cvs.khronos.org/bugzilla/show_bug.cgi?id=12928#c1
447701e04c3fSmrg       * and https://bugs.freedesktop.org/show_bug.cgi?id=31947
447801e04c3fSmrg       */
447901e04c3fSmrg      if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
448001e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM,
448101e04c3fSmrg                     "%s(requesting GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME "
448201e04c3fSmrg                     "when GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is "
448301e04c3fSmrg                     "GL_FRAMEBUFFER_DEFAULT is not allowed)", caller);
4484af69d88dSmrg         return;
4485af69d88dSmrg      }
448601e04c3fSmrg
44873464ebd5Sriastradh      /* the default / window-system FBO */
448801e04c3fSmrg      att = get_fb0_attachment(ctx, buffer, attachment);
44893464ebd5Sriastradh   }
44903464ebd5Sriastradh   else {
44913464ebd5Sriastradh      /* user-created framebuffer FBO */
449201e04c3fSmrg      att = get_attachment(ctx, buffer, attachment, &is_color_attachment);
44937117f1b4Smrg   }
44947117f1b4Smrg
44957117f1b4Smrg   if (att == NULL) {
449601e04c3fSmrg      /*
449701e04c3fSmrg       * From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries":
449801e04c3fSmrg       *
449901e04c3fSmrg       *    "An INVALID_OPERATION error is generated if a framebuffer object
450001e04c3fSmrg       *     is bound to target and attachment is COLOR_ATTACHMENTm where m is
450101e04c3fSmrg       *     greater than or equal to the value of MAX_COLOR_ATTACHMENTS."
450201e04c3fSmrg       *
450301e04c3fSmrg       * If we are at this point, is because the attachment is not valid, so
450401e04c3fSmrg       * if is_color_attachment is true, is because of the previous reason.
450501e04c3fSmrg       */
450601e04c3fSmrg      if (is_color_attachment) {
450701e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid color attachment %s)",
450801e04c3fSmrg                     caller, _mesa_enum_to_string(attachment));
450901e04c3fSmrg      } else {
451001e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller,
451101e04c3fSmrg                     _mesa_enum_to_string(attachment));
451201e04c3fSmrg      }
45137117f1b4Smrg      return;
45147117f1b4Smrg   }
45157117f1b4Smrg
45164a49301eSmrg   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
45174a49301eSmrg      const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
4518af69d88dSmrg      if (pname == GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) {
4519af69d88dSmrg         /* This behavior is first specified in OpenGL 4.4 specification.
4520af69d88dSmrg          *
4521af69d88dSmrg          * From the OpenGL 4.4 spec page 275:
4522af69d88dSmrg          *   "This query cannot be performed for a combined depth+stencil
4523af69d88dSmrg          *    attachment, since it does not have a single format."
4524af69d88dSmrg          */
4525af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
452601e04c3fSmrg                     "%s(GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE"
452701e04c3fSmrg                     " is invalid for depth+stencil attachment)", caller);
4528af69d88dSmrg         return;
4529af69d88dSmrg      }
4530af69d88dSmrg      /* the depth and stencil attachments must point to the same buffer */
453101e04c3fSmrg      depthAtt = get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT, NULL);
453201e04c3fSmrg      stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT, NULL);
45334a49301eSmrg      if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
45344a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
453501e04c3fSmrg                     "%s(DEPTH/STENCIL attachments differ)", caller);
45364a49301eSmrg         return;
45374a49301eSmrg      }
45384a49301eSmrg   }
45394a49301eSmrg
45404a49301eSmrg   /* No need to flush here */
45417117f1b4Smrg
45427117f1b4Smrg   switch (pname) {
45437117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
454401e04c3fSmrg      /* From the OpenGL spec, 9.2. Binding and Managing Framebuffer Objects:
454501e04c3fSmrg       *
454601e04c3fSmrg       * "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then
454701e04c3fSmrg       *  either no framebuffer is bound to target; or the default framebuffer
454801e04c3fSmrg       *  is bound, attachment is DEPTH or STENCIL, and the number of depth or
454901e04c3fSmrg       *  stencil bits, respectively, is zero."
455001e04c3fSmrg       *
455101e04c3fSmrg       * Note that we don't need explicit checks on DEPTH and STENCIL, because
455201e04c3fSmrg       * on the case the spec is pointing, att->Type is already NONE, so we
455301e04c3fSmrg       * just need to check att->Type.
455401e04c3fSmrg       */
455501e04c3fSmrg      *params = (_mesa_is_winsys_fbo(buffer) && att->Type != GL_NONE) ?
455601e04c3fSmrg         GL_FRAMEBUFFER_DEFAULT : att->Type;
45577117f1b4Smrg      return;
45587117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
45597117f1b4Smrg      if (att->Type == GL_RENDERBUFFER_EXT) {
456001e04c3fSmrg         *params = att->Renderbuffer->Name;
45617117f1b4Smrg      }
45627117f1b4Smrg      else if (att->Type == GL_TEXTURE) {
456301e04c3fSmrg         *params = att->Texture->Name;
45647117f1b4Smrg      }
45657117f1b4Smrg      else {
45663464ebd5Sriastradh         assert(att->Type == GL_NONE);
4567af69d88dSmrg         if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
45683464ebd5Sriastradh            *params = 0;
45693464ebd5Sriastradh         } else {
4570af69d88dSmrg            goto invalid_pname_enum;
45713464ebd5Sriastradh         }
45727117f1b4Smrg      }
45737117f1b4Smrg      return;
45747117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
45757117f1b4Smrg      if (att->Type == GL_TEXTURE) {
457601e04c3fSmrg         *params = att->TextureLevel;
45777117f1b4Smrg      }
45783464ebd5Sriastradh      else if (att->Type == GL_NONE) {
457901e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
458001e04c3fSmrg                     _mesa_enum_to_string(pname));
45813464ebd5Sriastradh      }
45827117f1b4Smrg      else {
4583af69d88dSmrg         goto invalid_pname_enum;
45847117f1b4Smrg      }
45857117f1b4Smrg      return;
45867117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
45877117f1b4Smrg      if (att->Type == GL_TEXTURE) {
4588c1f859d4Smrg         if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
4589c1f859d4Smrg            *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
4590c1f859d4Smrg         }
4591c1f859d4Smrg         else {
4592c1f859d4Smrg            *params = 0;
4593c1f859d4Smrg         }
45947117f1b4Smrg      }
45953464ebd5Sriastradh      else if (att->Type == GL_NONE) {
459601e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
459701e04c3fSmrg                     _mesa_enum_to_string(pname));
45983464ebd5Sriastradh      }
45997117f1b4Smrg      else {
4600af69d88dSmrg         goto invalid_pname_enum;
46017117f1b4Smrg      }
46027117f1b4Smrg      return;
46037117f1b4Smrg   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
4604af69d88dSmrg      if (ctx->API == API_OPENGLES) {
4605af69d88dSmrg         goto invalid_pname_enum;
4606af69d88dSmrg      } else if (att->Type == GL_NONE) {
460701e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
460801e04c3fSmrg                     _mesa_enum_to_string(pname));
4609af69d88dSmrg      } else if (att->Type == GL_TEXTURE) {
461001e04c3fSmrg         if (att->Texture && (att->Texture->Target == GL_TEXTURE_3D ||
461101e04c3fSmrg             att->Texture->Target == GL_TEXTURE_2D_ARRAY)) {
4612c1f859d4Smrg            *params = att->Zoffset;
4613c1f859d4Smrg         }
4614c1f859d4Smrg         else {
4615c1f859d4Smrg            *params = 0;
4616c1f859d4Smrg         }
46177117f1b4Smrg      }
46187117f1b4Smrg      else {
4619af69d88dSmrg         goto invalid_pname_enum;
46207117f1b4Smrg      }
46217117f1b4Smrg      return;
46224a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
4623af69d88dSmrg      if ((!_mesa_is_desktop_gl(ctx) ||
4624af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
4625af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
4626af69d88dSmrg         goto invalid_pname_enum;
46274a49301eSmrg      }
46283464ebd5Sriastradh      else if (att->Type == GL_NONE) {
462901e04c3fSmrg         if (_mesa_is_winsys_fbo(buffer) &&
463001e04c3fSmrg             (attachment == GL_DEPTH || attachment == GL_STENCIL)) {
463101e04c3fSmrg            *params = GL_LINEAR;
463201e04c3fSmrg         } else {
463301e04c3fSmrg            _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
463401e04c3fSmrg                        _mesa_enum_to_string(pname));
463501e04c3fSmrg         }
46363464ebd5Sriastradh      }
46374a49301eSmrg      else {
4638a8bb7a65Smaya         if (ctx->Extensions.EXT_sRGB) {
46397ec681f3Smrg            *params = (_mesa_is_format_srgb(att->Renderbuffer->Format) ?
46407ec681f3Smrg                       GL_SRGB : GL_LINEAR);
46413464ebd5Sriastradh         }
46423464ebd5Sriastradh         else {
46433464ebd5Sriastradh            /* According to ARB_framebuffer_sRGB, we should return LINEAR
46443464ebd5Sriastradh             * if the sRGB conversion is unsupported. */
46453464ebd5Sriastradh            *params = GL_LINEAR;
46463464ebd5Sriastradh         }
46474a49301eSmrg      }
46484a49301eSmrg      return;
46494a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
4650af69d88dSmrg      if ((ctx->API != API_OPENGL_COMPAT ||
4651af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
4652af69d88dSmrg          && ctx->API != API_OPENGL_CORE
4653af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
4654af69d88dSmrg         goto invalid_pname_enum;
46554a49301eSmrg      }
46563464ebd5Sriastradh      else if (att->Type == GL_NONE) {
465701e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
465801e04c3fSmrg                     _mesa_enum_to_string(pname));
46593464ebd5Sriastradh      }
46604a49301eSmrg      else {
4661af69d88dSmrg         mesa_format format = att->Renderbuffer->Format;
4662af69d88dSmrg
4663af69d88dSmrg         /* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES
4664af69d88dSmrg          * 3.0.1 spec says:
4665af69d88dSmrg          *
4666af69d88dSmrg          *     "If pname is FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE.... If
4667af69d88dSmrg          *     attachment is DEPTH_STENCIL_ATTACHMENT the query will fail and
4668af69d88dSmrg          *     generate an INVALID_OPERATION error.
4669af69d88dSmrg          */
4670af69d88dSmrg         if (_mesa_is_gles3(ctx) &&
4671af69d88dSmrg             attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
4672af69d88dSmrg            _mesa_error(ctx, GL_INVALID_OPERATION,
467301e04c3fSmrg                        "%s(cannot query "
4674af69d88dSmrg                        "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of "
467501e04c3fSmrg                        "GL_DEPTH_STENCIL_ATTACHMENT)", caller);
4676af69d88dSmrg            return;
4677af69d88dSmrg         }
4678af69d88dSmrg
4679af69d88dSmrg         if (format == MESA_FORMAT_S_UINT8) {
46804a49301eSmrg            /* special cases */
46814a49301eSmrg            *params = GL_INDEX;
46824a49301eSmrg         }
4683af69d88dSmrg         else if (format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) {
4684af69d88dSmrg            /* depends on the attachment parameter */
4685af69d88dSmrg            if (attachment == GL_STENCIL_ATTACHMENT) {
4686af69d88dSmrg               *params = GL_INDEX;
4687af69d88dSmrg            }
4688af69d88dSmrg            else {
4689af69d88dSmrg               *params = GL_FLOAT;
4690af69d88dSmrg            }
4691af69d88dSmrg         }
46924a49301eSmrg         else {
46934a49301eSmrg            *params = _mesa_get_format_datatype(format);
46944a49301eSmrg         }
46954a49301eSmrg      }
46964a49301eSmrg      return;
46974a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
46984a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
46994a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
47004a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
47014a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
47024a49301eSmrg   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
4703af69d88dSmrg      if ((!_mesa_is_desktop_gl(ctx) ||
4704af69d88dSmrg           !ctx->Extensions.ARB_framebuffer_object)
4705af69d88dSmrg          && !_mesa_is_gles3(ctx)) {
4706af69d88dSmrg         goto invalid_pname_enum;
47074a49301eSmrg      }
47084a49301eSmrg      else if (att->Texture) {
47094a49301eSmrg         const struct gl_texture_image *texImage =
471001e04c3fSmrg            _mesa_select_tex_image(att->Texture, att->Texture->Target,
47114a49301eSmrg                                   att->TextureLevel);
47124a49301eSmrg         if (texImage) {
47134a49301eSmrg            *params = get_component_bits(pname, texImage->_BaseFormat,
47144a49301eSmrg                                         texImage->TexFormat);
47154a49301eSmrg         }
47164a49301eSmrg         else {
47174a49301eSmrg            *params = 0;
47184a49301eSmrg         }
47194a49301eSmrg      }
47204a49301eSmrg      else if (att->Renderbuffer) {
47214a49301eSmrg         *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
47224a49301eSmrg                                      att->Renderbuffer->Format);
47234a49301eSmrg      }
47244a49301eSmrg      else {
472501e04c3fSmrg         assert(att->Type == GL_NONE);
472601e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
472701e04c3fSmrg                     _mesa_enum_to_string(pname));
47284a49301eSmrg      }
47294a49301eSmrg      return;
4730af69d88dSmrg   case GL_FRAMEBUFFER_ATTACHMENT_LAYERED:
4731af69d88dSmrg      if (!_mesa_has_geometry_shaders(ctx)) {
4732af69d88dSmrg         goto invalid_pname_enum;
4733af69d88dSmrg      } else if (att->Type == GL_TEXTURE) {
4734af69d88dSmrg         *params = att->Layered;
4735af69d88dSmrg      } else if (att->Type == GL_NONE) {
473601e04c3fSmrg         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
473701e04c3fSmrg                     _mesa_enum_to_string(pname));
4738af69d88dSmrg      } else {
4739af69d88dSmrg         goto invalid_pname_enum;
4740af69d88dSmrg      }
47417117f1b4Smrg      return;
4742a8bb7a65Smaya   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT:
4743a8bb7a65Smaya      if (!ctx->Extensions.EXT_multisampled_render_to_texture) {
4744a8bb7a65Smaya         goto invalid_pname_enum;
4745a8bb7a65Smaya      } else if (att->Type == GL_TEXTURE) {
4746a8bb7a65Smaya         *params = att->NumSamples;
4747a8bb7a65Smaya      } else if (att->Type == GL_NONE) {
4748a8bb7a65Smaya         _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
4749a8bb7a65Smaya                     _mesa_enum_to_string(pname));
4750a8bb7a65Smaya      } else {
4751a8bb7a65Smaya         goto invalid_pname_enum;
4752a8bb7a65Smaya      }
4753a8bb7a65Smaya      return;
4754af69d88dSmrg   default:
4755af69d88dSmrg      goto invalid_pname_enum;
47567117f1b4Smrg   }
4757af69d88dSmrg
4758af69d88dSmrg   return;
4759af69d88dSmrg
4760af69d88dSmrginvalid_pname_enum:
476101e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname %s)", caller,
476201e04c3fSmrg               _mesa_enum_to_string(pname));
4763af69d88dSmrg   return;
47647117f1b4Smrg}
47657117f1b4Smrg
47667117f1b4Smrg
476701e04c3fSmrgvoid GLAPIENTRY
476801e04c3fSmrg_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment,
476901e04c3fSmrg                                          GLenum pname, GLint *params)
477001e04c3fSmrg{
477101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
477201e04c3fSmrg   struct gl_framebuffer *buffer;
477301e04c3fSmrg
477401e04c3fSmrg   buffer = get_framebuffer_target(ctx, target);
477501e04c3fSmrg   if (!buffer) {
477601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
477701e04c3fSmrg                  "glGetFramebufferAttachmentParameteriv(invalid target %s)",
477801e04c3fSmrg                  _mesa_enum_to_string(target));
477901e04c3fSmrg      return;
478001e04c3fSmrg   }
478101e04c3fSmrg
478201e04c3fSmrg   get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
478301e04c3fSmrg                                        params,
478401e04c3fSmrg                                    "glGetFramebufferAttachmentParameteriv");
478501e04c3fSmrg}
478601e04c3fSmrg
478701e04c3fSmrg
478801e04c3fSmrgvoid GLAPIENTRY
478901e04c3fSmrg_mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer,
479001e04c3fSmrg                                               GLenum attachment,
479101e04c3fSmrg                                               GLenum pname, GLint *params)
479201e04c3fSmrg{
479301e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
479401e04c3fSmrg   struct gl_framebuffer *buffer;
479501e04c3fSmrg
479601e04c3fSmrg   if (framebuffer) {
479701e04c3fSmrg      buffer = _mesa_lookup_framebuffer_err(ctx, framebuffer,
479801e04c3fSmrg                              "glGetNamedFramebufferAttachmentParameteriv");
479901e04c3fSmrg      if (!buffer)
480001e04c3fSmrg         return;
480101e04c3fSmrg   }
480201e04c3fSmrg   else {
480301e04c3fSmrg      /*
480401e04c3fSmrg       * Section 9.2 Binding and Managing Framebuffer Objects of the OpenGL
480501e04c3fSmrg       * 4.5 core spec (30.10.2014, PDF page 314):
480601e04c3fSmrg       *    "If framebuffer is zero, then the default draw framebuffer is
480701e04c3fSmrg       *    queried."
480801e04c3fSmrg       */
480901e04c3fSmrg      buffer = ctx->WinSysDrawBuffer;
481001e04c3fSmrg   }
481101e04c3fSmrg
481201e04c3fSmrg   get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
481301e04c3fSmrg                                        params,
481401e04c3fSmrg                              "glGetNamedFramebufferAttachmentParameteriv");
481501e04c3fSmrg}
481601e04c3fSmrg
481701e04c3fSmrg
48187ec681f3Smrgvoid GLAPIENTRY
48197ec681f3Smrg_mesa_GetNamedFramebufferAttachmentParameterivEXT(GLuint framebuffer,
48207ec681f3Smrg                                                  GLenum attachment,
48217ec681f3Smrg                                                  GLenum pname, GLint *params)
48227ec681f3Smrg{
48237ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
48247ec681f3Smrg   struct gl_framebuffer *buffer;
48257ec681f3Smrg
48267ec681f3Smrg   if (framebuffer) {
48277ec681f3Smrg      buffer = _mesa_lookup_framebuffer_dsa(ctx, framebuffer,
48287ec681f3Smrg                              "glGetNamedFramebufferAttachmentParameterivEXT");
48297ec681f3Smrg      if (!buffer)
48307ec681f3Smrg         return;
48317ec681f3Smrg   }
48327ec681f3Smrg   else {
48337ec681f3Smrg      /*
48347ec681f3Smrg       * Section 9.2 Binding and Managing Framebuffer Objects of the OpenGL
48357ec681f3Smrg       * 4.5 core spec (30.10.2014, PDF page 314):
48367ec681f3Smrg       *    "If framebuffer is zero, then the default draw framebuffer is
48377ec681f3Smrg       *    queried."
48387ec681f3Smrg       */
48397ec681f3Smrg      buffer = ctx->WinSysDrawBuffer;
48407ec681f3Smrg   }
48417ec681f3Smrg
48427ec681f3Smrg   get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
48437ec681f3Smrg                                        params,
48447ec681f3Smrg                              "glGetNamedFramebufferAttachmentParameterivEXT");
48457ec681f3Smrg}
48467ec681f3Smrg
48477ec681f3Smrg
484801e04c3fSmrgvoid GLAPIENTRY
484901e04c3fSmrg_mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname,
485001e04c3fSmrg                                 GLint param)
485101e04c3fSmrg{
485201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
485301e04c3fSmrg   struct gl_framebuffer *fb = NULL;
485401e04c3fSmrg
485501e04c3fSmrg   if (!ctx->Extensions.ARB_framebuffer_no_attachments &&
485601e04c3fSmrg       !ctx->Extensions.ARB_sample_locations) {
485701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
485801e04c3fSmrg                  "glNamedFramebufferParameteri("
485901e04c3fSmrg                  "neither ARB_framebuffer_no_attachments nor "
486001e04c3fSmrg                  "ARB_sample_locations is available)");
486101e04c3fSmrg      return;
486201e04c3fSmrg   }
486301e04c3fSmrg
486401e04c3fSmrg   if (framebuffer) {
486501e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
486601e04c3fSmrg                                        "glNamedFramebufferParameteri");
486701e04c3fSmrg   } else {
486801e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
486901e04c3fSmrg   }
487001e04c3fSmrg
487101e04c3fSmrg   if (fb) {
487201e04c3fSmrg      framebuffer_parameteri(ctx, fb, pname, param,
487301e04c3fSmrg                             "glNamedFramebufferParameteriv");
487401e04c3fSmrg   }
487501e04c3fSmrg}
487601e04c3fSmrg
487701e04c3fSmrg
48787ec681f3Smrg/* Helper function for ARB_framebuffer_no_attachments functions interacting with EXT_direct_state_access */
48797ec681f3Smrgstatic struct gl_framebuffer *
48807ec681f3Smrglookup_named_framebuffer_ext_dsa(struct gl_context *ctx, GLuint framebuffer, const char* caller)
48817ec681f3Smrg{
48827ec681f3Smrg   struct gl_framebuffer *fb = NULL;
48837ec681f3Smrg
48847ec681f3Smrg   if (framebuffer) {
48857ec681f3Smrg      /* The ARB_framebuffer_no_attachments spec says:
48867ec681f3Smrg       *
48877ec681f3Smrg       *     "The error INVALID_VALUE is generated if <framebuffer> is not
48887ec681f3Smrg       *     a name returned by GenFramebuffers.  If a framebuffer object
48897ec681f3Smrg       *     named <framebuffer> does not yet exist, it will be created."
48907ec681f3Smrg       *
48917ec681f3Smrg       * This is different from the EXT_direct_state_access spec which says:
48927ec681f3Smrg       *
48937ec681f3Smrg       *     "If the framebuffer object named by the framebuffer parameter has not
48947ec681f3Smrg       *      been previously bound or has been deleted since the last binding,
48957ec681f3Smrg       *     the GL first creates a new state vector in the same manner as when
48967ec681f3Smrg       *    BindFramebuffer creates a new framebuffer object"
48977ec681f3Smrg       *
48987ec681f3Smrg       * So first we verify that the name exists.
48997ec681f3Smrg       */
49007ec681f3Smrg      fb = _mesa_lookup_framebuffer(ctx, framebuffer);
49017ec681f3Smrg      if (!fb) {
49027ec681f3Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s(frameBuffer)", caller);
49037ec681f3Smrg         return NULL;
49047ec681f3Smrg      }
49057ec681f3Smrg      /* Then, make sure it's initialized */
49067ec681f3Smrg      if (fb == &DummyFramebuffer) {
49077ec681f3Smrg         fb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
49087ec681f3Smrg         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, fb, true);
49097ec681f3Smrg      }
49107ec681f3Smrg   }
49117ec681f3Smrg   else
49127ec681f3Smrg      fb = ctx->WinSysDrawBuffer;
49137ec681f3Smrg
49147ec681f3Smrg   return fb;
49157ec681f3Smrg}
49167ec681f3Smrg
49177ec681f3Smrg
49187ec681f3Smrgvoid GLAPIENTRY
49197ec681f3Smrg_mesa_NamedFramebufferParameteriEXT(GLuint framebuffer, GLenum pname,
49207ec681f3Smrg                                    GLint param)
49217ec681f3Smrg{
49227ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
49237ec681f3Smrg   struct gl_framebuffer *fb =
49247ec681f3Smrg      lookup_named_framebuffer_ext_dsa(ctx, framebuffer,
49257ec681f3Smrg                                       "glNamedFramebufferParameteriEXT");
49267ec681f3Smrg
49277ec681f3Smrg   if (!fb)
49287ec681f3Smrg      return;
49297ec681f3Smrg
49307ec681f3Smrg   framebuffer_parameteri(ctx, fb, pname, param,
49317ec681f3Smrg                             "glNamedFramebufferParameteriEXT");
49327ec681f3Smrg}
49337ec681f3Smrg
49347ec681f3Smrg
49357ec681f3Smrgvoid GLAPIENTRY
49367ec681f3Smrg_mesa_GetFramebufferParameterivEXT(GLuint framebuffer, GLenum pname,
49377ec681f3Smrg                                   GLint *param)
49387ec681f3Smrg{
49397ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
49407ec681f3Smrg   struct gl_framebuffer *fb;
49417ec681f3Smrg
49427ec681f3Smrg   if (framebuffer)
49437ec681f3Smrg      fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer,
49447ec681f3Smrg                                        "glGetFramebufferParameterivEXT");
49457ec681f3Smrg   else
49467ec681f3Smrg      fb = ctx->WinSysDrawBuffer;
49477ec681f3Smrg
49487ec681f3Smrg   if (fb) {
49497ec681f3Smrg      /* The GL_EXT_direct_state_access says:
49507ec681f3Smrg       *
49517ec681f3Smrg       * The pname parameter must be one of framebuffer dependent values
49527ec681f3Smrg       * listed in either table 4.nnn (namely DRAW_BUFFER, READ_BUFFER,
49537ec681f3Smrg       * or DRAW_BUFFER0 through DRAW_BUFFER15).
49547ec681f3Smrg       */
49557ec681f3Smrg      if (pname == GL_DRAW_BUFFER) {
49567ec681f3Smrg         *param = fb->ColorDrawBuffer[0];
49577ec681f3Smrg
49587ec681f3Smrg      }
49597ec681f3Smrg      else if (pname == GL_READ_BUFFER) {
49607ec681f3Smrg         *param = fb->ColorReadBuffer;
49617ec681f3Smrg      }
49627ec681f3Smrg      else if (GL_DRAW_BUFFER0 <= pname && pname <= GL_DRAW_BUFFER15) {
49637ec681f3Smrg         unsigned buffer = pname - GL_DRAW_BUFFER0;
49647ec681f3Smrg         if (buffer < ARRAY_SIZE(fb->ColorDrawBuffer))
49657ec681f3Smrg            *param = fb->ColorDrawBuffer[buffer];
49667ec681f3Smrg         else
49677ec681f3Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferParameterivEXT(pname)");
49687ec681f3Smrg      }
49697ec681f3Smrg      else {
49707ec681f3Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferParameterivEXT(pname)");
49717ec681f3Smrg      }
49727ec681f3Smrg   }
49737ec681f3Smrg}
49747ec681f3Smrg
49757ec681f3Smrg
497601e04c3fSmrgvoid GLAPIENTRY
497701e04c3fSmrg_mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname,
497801e04c3fSmrg                                     GLint *param)
497901e04c3fSmrg{
498001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
498101e04c3fSmrg   struct gl_framebuffer *fb;
498201e04c3fSmrg
498301e04c3fSmrg   if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
498401e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
498501e04c3fSmrg                  "glNamedFramebufferParameteriv("
498601e04c3fSmrg                  "neither ARB_framebuffer_no_attachments nor ARB_sample_locations"
498701e04c3fSmrg                  " is available)");
498801e04c3fSmrg      return;
498901e04c3fSmrg   }
499001e04c3fSmrg
499101e04c3fSmrg   if (framebuffer)
499201e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
499301e04c3fSmrg                                        "glGetNamedFramebufferParameteriv");
499401e04c3fSmrg   else
499501e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
499601e04c3fSmrg
499701e04c3fSmrg   if (fb) {
499801e04c3fSmrg      get_framebuffer_parameteriv(ctx, fb, pname, param,
499901e04c3fSmrg                                  "glGetNamedFramebufferParameteriv");
500001e04c3fSmrg   }
500101e04c3fSmrg}
500201e04c3fSmrg
500301e04c3fSmrg
50047ec681f3Smrgvoid GLAPIENTRY
50057ec681f3Smrg_mesa_GetNamedFramebufferParameterivEXT(GLuint framebuffer, GLenum pname,
50067ec681f3Smrg                                     GLint *param)
50077ec681f3Smrg{
50087ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
50097ec681f3Smrg   struct gl_framebuffer *fb =
50107ec681f3Smrg      lookup_named_framebuffer_ext_dsa(ctx, framebuffer,
50117ec681f3Smrg                                       "glGetNamedFramebufferParameterivEXT");
50127ec681f3Smrg
50137ec681f3Smrg   if (!fb)
50147ec681f3Smrg      return;
50157ec681f3Smrg
50167ec681f3Smrg   get_framebuffer_parameteriv(ctx, fb, pname, param,
50177ec681f3Smrg                               "glGetNamedFramebufferParameterivEXT");
50187ec681f3Smrg}
50197ec681f3Smrg
50207ec681f3Smrg
5021af69d88dSmrgstatic void
502201e04c3fSmrginvalidate_framebuffer_storage(struct gl_context *ctx,
502301e04c3fSmrg                               struct gl_framebuffer *fb,
502401e04c3fSmrg                               GLsizei numAttachments,
5025af69d88dSmrg                               const GLenum *attachments, GLint x, GLint y,
5026af69d88dSmrg                               GLsizei width, GLsizei height, const char *name)
50277117f1b4Smrg{
5028af69d88dSmrg   int i;
50297117f1b4Smrg
503001e04c3fSmrg   /* Section 17.4 Whole Framebuffer Operations of the OpenGL 4.5 Core
503101e04c3fSmrg    * Spec (2.2.2015, PDF page 522) says:
503201e04c3fSmrg    *    "An INVALID_VALUE error is generated if numAttachments, width, or
503301e04c3fSmrg    *    height is negative."
503401e04c3fSmrg    */
503501e04c3fSmrg   if (numAttachments < 0) {
503601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
503701e04c3fSmrg                  "%s(numAttachments < 0)", name);
50387117f1b4Smrg      return;
50397117f1b4Smrg   }
50407117f1b4Smrg
504101e04c3fSmrg   if (width < 0) {
5042af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
504301e04c3fSmrg                  "%s(width < 0)", name);
504401e04c3fSmrg      return;
504501e04c3fSmrg   }
504601e04c3fSmrg
504701e04c3fSmrg   if (height < 0) {
504801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
504901e04c3fSmrg                  "%s(height < 0)", name);
50504a49301eSmrg      return;
50514a49301eSmrg   }
50527117f1b4Smrg
5053af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
5054af69d88dSmrg    *
5055af69d88dSmrg    *     "If an attachment is specified that does not exist in the
5056af69d88dSmrg    *     framebuffer bound to <target>, it is ignored."
5057af69d88dSmrg    *
5058af69d88dSmrg    * It also says:
5059af69d88dSmrg    *
5060af69d88dSmrg    *     "If <attachments> contains COLOR_ATTACHMENTm and m is greater than
5061af69d88dSmrg    *     or equal to the value of MAX_COLOR_ATTACHMENTS, then the error
5062af69d88dSmrg    *     INVALID_OPERATION is generated."
5063af69d88dSmrg    *
5064af69d88dSmrg    * No mention is made of GL_AUXi being out of range.  Therefore, we allow
5065af69d88dSmrg    * any enum that can be allowed by the API (OpenGL ES 3.0 has a different
5066af69d88dSmrg    * set of retrictions).
5067af69d88dSmrg    */
5068af69d88dSmrg   for (i = 0; i < numAttachments; i++) {
5069af69d88dSmrg      if (_mesa_is_winsys_fbo(fb)) {
5070af69d88dSmrg         switch (attachments[i]) {
5071af69d88dSmrg         case GL_ACCUM:
5072af69d88dSmrg         case GL_AUX0:
5073af69d88dSmrg         case GL_AUX1:
5074af69d88dSmrg         case GL_AUX2:
5075af69d88dSmrg         case GL_AUX3:
5076af69d88dSmrg            /* Accumulation buffers and auxilary buffers were removed in
5077af69d88dSmrg             * OpenGL 3.1, and they never existed in OpenGL ES.
5078af69d88dSmrg             */
5079af69d88dSmrg            if (ctx->API != API_OPENGL_COMPAT)
5080af69d88dSmrg               goto invalid_enum;
5081af69d88dSmrg            break;
5082af69d88dSmrg         case GL_COLOR:
5083af69d88dSmrg         case GL_DEPTH:
5084af69d88dSmrg         case GL_STENCIL:
5085af69d88dSmrg            break;
5086af69d88dSmrg         case GL_BACK_LEFT:
5087af69d88dSmrg         case GL_BACK_RIGHT:
5088af69d88dSmrg         case GL_FRONT_LEFT:
5089af69d88dSmrg         case GL_FRONT_RIGHT:
5090af69d88dSmrg            if (!_mesa_is_desktop_gl(ctx))
5091af69d88dSmrg               goto invalid_enum;
5092af69d88dSmrg            break;
5093af69d88dSmrg         default:
5094af69d88dSmrg            goto invalid_enum;
5095af69d88dSmrg         }
5096af69d88dSmrg      } else {
5097af69d88dSmrg         switch (attachments[i]) {
5098af69d88dSmrg         case GL_DEPTH_ATTACHMENT:
5099af69d88dSmrg         case GL_STENCIL_ATTACHMENT:
5100af69d88dSmrg            break;
510101e04c3fSmrg         case GL_DEPTH_STENCIL_ATTACHMENT:
510201e04c3fSmrg            /* GL_DEPTH_STENCIL_ATTACHMENT is a valid attachment point only
510301e04c3fSmrg             * in desktop and ES 3.0 profiles. Note that OES_packed_depth_stencil
510401e04c3fSmrg             * extension does not make this attachment point valid on ES 2.0.
510501e04c3fSmrg             */
510601e04c3fSmrg            if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx))
510701e04c3fSmrg               break;
51087ec681f3Smrg            FALLTHROUGH;
5109af69d88dSmrg         case GL_COLOR_ATTACHMENT0:
5110af69d88dSmrg         case GL_COLOR_ATTACHMENT1:
5111af69d88dSmrg         case GL_COLOR_ATTACHMENT2:
5112af69d88dSmrg         case GL_COLOR_ATTACHMENT3:
5113af69d88dSmrg         case GL_COLOR_ATTACHMENT4:
5114af69d88dSmrg         case GL_COLOR_ATTACHMENT5:
5115af69d88dSmrg         case GL_COLOR_ATTACHMENT6:
5116af69d88dSmrg         case GL_COLOR_ATTACHMENT7:
5117af69d88dSmrg         case GL_COLOR_ATTACHMENT8:
5118af69d88dSmrg         case GL_COLOR_ATTACHMENT9:
5119af69d88dSmrg         case GL_COLOR_ATTACHMENT10:
5120af69d88dSmrg         case GL_COLOR_ATTACHMENT11:
5121af69d88dSmrg         case GL_COLOR_ATTACHMENT12:
5122af69d88dSmrg         case GL_COLOR_ATTACHMENT13:
5123af69d88dSmrg         case GL_COLOR_ATTACHMENT14:
5124af69d88dSmrg         case GL_COLOR_ATTACHMENT15: {
5125af69d88dSmrg            unsigned k = attachments[i] - GL_COLOR_ATTACHMENT0;
5126af69d88dSmrg            if (k >= ctx->Const.MaxColorAttachments) {
5127af69d88dSmrg               _mesa_error(ctx, GL_INVALID_OPERATION,
5128af69d88dSmrg                           "%s(attachment >= max. color attachments)", name);
5129af69d88dSmrg               return;
5130af69d88dSmrg            }
5131af69d88dSmrg            break;
5132af69d88dSmrg         }
5133af69d88dSmrg         default:
5134af69d88dSmrg            goto invalid_enum;
5135af69d88dSmrg         }
5136af69d88dSmrg      }
51373464ebd5Sriastradh   }
51383464ebd5Sriastradh
5139af69d88dSmrg   /* We don't actually do anything for this yet.  Just return after
5140af69d88dSmrg    * validating the parameters and generating the required errors.
5141af69d88dSmrg    */
5142af69d88dSmrg   return;
51437117f1b4Smrg
5144af69d88dSmrginvalid_enum:
514501e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", name,
514601e04c3fSmrg               _mesa_enum_to_string(attachments[i]));
5147af69d88dSmrg   return;
5148af69d88dSmrg}
51497117f1b4Smrg
5150a8bb7a65Smayastatic struct gl_renderbuffer_attachment *
5151a8bb7a65Smayaget_fb_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
5152a8bb7a65Smaya                  const GLenum attachment)
5153a8bb7a65Smaya{
5154a8bb7a65Smaya   switch (attachment) {
5155a8bb7a65Smaya   case GL_COLOR:
5156a8bb7a65Smaya      return &fb->Attachment[BUFFER_BACK_LEFT];
5157a8bb7a65Smaya   case GL_COLOR_ATTACHMENT0:
5158a8bb7a65Smaya   case GL_COLOR_ATTACHMENT1:
5159a8bb7a65Smaya   case GL_COLOR_ATTACHMENT2:
5160a8bb7a65Smaya   case GL_COLOR_ATTACHMENT3:
5161a8bb7a65Smaya   case GL_COLOR_ATTACHMENT4:
5162a8bb7a65Smaya   case GL_COLOR_ATTACHMENT5:
5163a8bb7a65Smaya   case GL_COLOR_ATTACHMENT6:
5164a8bb7a65Smaya   case GL_COLOR_ATTACHMENT7:
5165a8bb7a65Smaya   case GL_COLOR_ATTACHMENT8:
5166a8bb7a65Smaya   case GL_COLOR_ATTACHMENT9:
5167a8bb7a65Smaya   case GL_COLOR_ATTACHMENT10:
5168a8bb7a65Smaya   case GL_COLOR_ATTACHMENT11:
5169a8bb7a65Smaya   case GL_COLOR_ATTACHMENT12:
5170a8bb7a65Smaya   case GL_COLOR_ATTACHMENT13:
5171a8bb7a65Smaya   case GL_COLOR_ATTACHMENT14:
5172a8bb7a65Smaya   case GL_COLOR_ATTACHMENT15: {
5173a8bb7a65Smaya      const unsigned i = attachment - GL_COLOR_ATTACHMENT0;
5174a8bb7a65Smaya      if (i >= ctx->Const.MaxColorAttachments)
5175a8bb7a65Smaya         return NULL;
51767ec681f3Smrg      assert(BUFFER_COLOR0 + i < ARRAY_SIZE(fb->Attachment));
5177a8bb7a65Smaya      return &fb->Attachment[BUFFER_COLOR0 + i];
5178a8bb7a65Smaya   }
5179a8bb7a65Smaya   case GL_DEPTH:
5180a8bb7a65Smaya   case GL_DEPTH_ATTACHMENT:
5181a8bb7a65Smaya   case GL_DEPTH_STENCIL_ATTACHMENT:
5182a8bb7a65Smaya      return &fb->Attachment[BUFFER_DEPTH];
5183a8bb7a65Smaya   case GL_STENCIL:
5184a8bb7a65Smaya   case GL_STENCIL_ATTACHMENT:
5185a8bb7a65Smaya      return &fb->Attachment[BUFFER_STENCIL];
5186a8bb7a65Smaya   default:
5187a8bb7a65Smaya      return NULL;
5188a8bb7a65Smaya   }
5189a8bb7a65Smaya}
5190a8bb7a65Smaya
5191a8bb7a65Smayastatic void
5192a8bb7a65Smayadiscard_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
5193a8bb7a65Smaya                    GLsizei numAttachments, const GLenum *attachments)
5194a8bb7a65Smaya{
5195a8bb7a65Smaya   if (!ctx->Driver.DiscardFramebuffer)
5196a8bb7a65Smaya      return;
5197a8bb7a65Smaya
5198a8bb7a65Smaya   for (int i = 0; i < numAttachments; i++) {
5199a8bb7a65Smaya      struct gl_renderbuffer_attachment *att =
5200a8bb7a65Smaya            get_fb_attachment(ctx, fb, attachments[i]);
5201a8bb7a65Smaya
5202a8bb7a65Smaya      if (!att)
5203a8bb7a65Smaya         continue;
5204a8bb7a65Smaya
5205a8bb7a65Smaya      /* If we're asked to invalidate just depth or just stencil, but the
5206a8bb7a65Smaya       * attachment is packed depth/stencil, then we can only use
5207a8bb7a65Smaya       * Driver.DiscardFramebuffer if the attachments list includes both depth
5208a8bb7a65Smaya       * and stencil and they both point at the same renderbuffer.
5209a8bb7a65Smaya       */
5210a8bb7a65Smaya      if ((attachments[i] == GL_DEPTH_ATTACHMENT ||
5211a8bb7a65Smaya           attachments[i] == GL_STENCIL_ATTACHMENT) &&
5212a8bb7a65Smaya          (!att->Renderbuffer ||
5213a8bb7a65Smaya           att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL)) {
5214a8bb7a65Smaya         GLenum other_format = (attachments[i] == GL_DEPTH_ATTACHMENT ?
5215a8bb7a65Smaya                                GL_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT);
5216a8bb7a65Smaya         bool has_both = false;
5217a8bb7a65Smaya         for (int j = 0; j < numAttachments; j++) {
52187ec681f3Smrg            if (attachments[j] == other_format) {
5219a8bb7a65Smaya               has_both = true;
52207ec681f3Smrg               break;
52217ec681f3Smrg            }
5222a8bb7a65Smaya         }
5223a8bb7a65Smaya
5224a8bb7a65Smaya         if (fb->Attachment[BUFFER_DEPTH].Renderbuffer !=
5225a8bb7a65Smaya             fb->Attachment[BUFFER_STENCIL].Renderbuffer || !has_both)
5226a8bb7a65Smaya            continue;
5227a8bb7a65Smaya      }
5228a8bb7a65Smaya
5229a8bb7a65Smaya      ctx->Driver.DiscardFramebuffer(ctx, fb, att);
5230a8bb7a65Smaya   }
5231a8bb7a65Smaya}
52324a49301eSmrg
523301e04c3fSmrgvoid GLAPIENTRY
523401e04c3fSmrg_mesa_InvalidateSubFramebuffer_no_error(GLenum target, GLsizei numAttachments,
523501e04c3fSmrg                                        const GLenum *attachments, GLint x,
523601e04c3fSmrg                                        GLint y, GLsizei width, GLsizei height)
523701e04c3fSmrg{
523801e04c3fSmrg   /* no-op */
523901e04c3fSmrg}
524001e04c3fSmrg
524101e04c3fSmrg
5242af69d88dSmrgvoid GLAPIENTRY
5243af69d88dSmrg_mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
5244af69d88dSmrg                               const GLenum *attachments, GLint x, GLint y,
5245af69d88dSmrg                               GLsizei width, GLsizei height)
52464a49301eSmrg{
524701e04c3fSmrg   struct gl_framebuffer *fb;
524801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
524901e04c3fSmrg
525001e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
525101e04c3fSmrg   if (!fb) {
525201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
525301e04c3fSmrg                  "glInvalidateSubFramebuffer(invalid target %s)",
525401e04c3fSmrg                  _mesa_enum_to_string(target));
525501e04c3fSmrg      return;
525601e04c3fSmrg   }
525701e04c3fSmrg
525801e04c3fSmrg   invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
5259af69d88dSmrg                                  x, y, width, height,
5260af69d88dSmrg                                  "glInvalidateSubFramebuffer");
52614a49301eSmrg}
52624a49301eSmrg
52634a49301eSmrg
526401e04c3fSmrgvoid GLAPIENTRY
526501e04c3fSmrg_mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer,
526601e04c3fSmrg                                        GLsizei numAttachments,
526701e04c3fSmrg                                        const GLenum *attachments,
526801e04c3fSmrg                                        GLint x, GLint y,
526901e04c3fSmrg                                        GLsizei width, GLsizei height)
527001e04c3fSmrg{
527101e04c3fSmrg   struct gl_framebuffer *fb;
527201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
527301e04c3fSmrg
527401e04c3fSmrg   /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole
527501e04c3fSmrg    * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the
527601e04c3fSmrg    * default draw framebuffer is affected."
527701e04c3fSmrg    */
527801e04c3fSmrg   if (framebuffer) {
527901e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
528001e04c3fSmrg                                        "glInvalidateNamedFramebufferSubData");
528101e04c3fSmrg      if (!fb)
528201e04c3fSmrg         return;
528301e04c3fSmrg   }
528401e04c3fSmrg   else
528501e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
528601e04c3fSmrg
528701e04c3fSmrg   invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
528801e04c3fSmrg                                  x, y, width, height,
528901e04c3fSmrg                                  "glInvalidateNamedFramebufferSubData");
529001e04c3fSmrg}
529101e04c3fSmrg
529201e04c3fSmrgvoid GLAPIENTRY
529301e04c3fSmrg_mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments,
529401e04c3fSmrg                                     const GLenum *attachments)
529501e04c3fSmrg{
5296a8bb7a65Smaya   struct gl_framebuffer *fb;
5297a8bb7a65Smaya   GET_CURRENT_CONTEXT(ctx);
5298a8bb7a65Smaya
5299a8bb7a65Smaya   fb = get_framebuffer_target(ctx, target);
5300a8bb7a65Smaya   if (!fb)
5301a8bb7a65Smaya      return;
5302a8bb7a65Smaya
5303a8bb7a65Smaya   discard_framebuffer(ctx, fb, numAttachments, attachments);
530401e04c3fSmrg}
530501e04c3fSmrg
530601e04c3fSmrg
53077117f1b4Smrgvoid GLAPIENTRY
5308af69d88dSmrg_mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments,
5309af69d88dSmrg                            const GLenum *attachments)
53107117f1b4Smrg{
531101e04c3fSmrg   struct gl_framebuffer *fb;
531201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
531301e04c3fSmrg
531401e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
531501e04c3fSmrg   if (!fb) {
531601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
531701e04c3fSmrg                  "glInvalidateFramebuffer(invalid target %s)",
531801e04c3fSmrg                  _mesa_enum_to_string(target));
531901e04c3fSmrg      return;
532001e04c3fSmrg   }
532101e04c3fSmrg
5322af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
5323af69d88dSmrg    *
5324af69d88dSmrg    *     "The command
5325af69d88dSmrg    *
5326af69d88dSmrg    *        void InvalidateFramebuffer(enum target,
5327af69d88dSmrg    *                                   sizei numAttachments,
5328af69d88dSmrg    *                                   const enum *attachments);
5329af69d88dSmrg    *
5330af69d88dSmrg    *     is equivalent to the command InvalidateSubFramebuffer with <x>, <y>,
5331af69d88dSmrg    *     <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>,
5332af69d88dSmrg    *     <MAX_VIEWPORT_DIMS[1]> respectively."
5333af69d88dSmrg    */
533401e04c3fSmrg   invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
5335af69d88dSmrg                                  0, 0,
533601e04c3fSmrg                                  ctx->Const.MaxViewportWidth,
533701e04c3fSmrg                                  ctx->Const.MaxViewportHeight,
5338af69d88dSmrg                                  "glInvalidateFramebuffer");
5339a8bb7a65Smaya
5340a8bb7a65Smaya   discard_framebuffer(ctx, fb, numAttachments, attachments);
5341af69d88dSmrg}
53424a49301eSmrg
53433464ebd5Sriastradh
534401e04c3fSmrgvoid GLAPIENTRY
534501e04c3fSmrg_mesa_InvalidateNamedFramebufferData(GLuint framebuffer,
534601e04c3fSmrg                                     GLsizei numAttachments,
534701e04c3fSmrg                                     const GLenum *attachments)
534801e04c3fSmrg{
534901e04c3fSmrg   struct gl_framebuffer *fb;
535001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
535101e04c3fSmrg
535201e04c3fSmrg   /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole
535301e04c3fSmrg    * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the
535401e04c3fSmrg    * default draw framebuffer is affected."
535501e04c3fSmrg    */
535601e04c3fSmrg   if (framebuffer) {
535701e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
535801e04c3fSmrg                                        "glInvalidateNamedFramebufferData");
535901e04c3fSmrg      if (!fb)
536001e04c3fSmrg         return;
536101e04c3fSmrg   }
536201e04c3fSmrg   else
536301e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
536401e04c3fSmrg
536501e04c3fSmrg   /* The GL_ARB_invalidate_subdata spec says:
536601e04c3fSmrg    *
536701e04c3fSmrg    *     "The command
536801e04c3fSmrg    *
536901e04c3fSmrg    *        void InvalidateFramebuffer(enum target,
537001e04c3fSmrg    *                                   sizei numAttachments,
537101e04c3fSmrg    *                                   const enum *attachments);
537201e04c3fSmrg    *
537301e04c3fSmrg    *     is equivalent to the command InvalidateSubFramebuffer with <x>, <y>,
537401e04c3fSmrg    *     <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>,
537501e04c3fSmrg    *     <MAX_VIEWPORT_DIMS[1]> respectively."
537601e04c3fSmrg    */
537701e04c3fSmrg   invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments,
537801e04c3fSmrg                                  0, 0,
537901e04c3fSmrg                                  ctx->Const.MaxViewportWidth,
538001e04c3fSmrg                                  ctx->Const.MaxViewportHeight,
538101e04c3fSmrg                                  "glInvalidateNamedFramebufferData");
538201e04c3fSmrg}
538301e04c3fSmrg
538401e04c3fSmrg
5385af69d88dSmrgvoid GLAPIENTRY
5386af69d88dSmrg_mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments,
5387af69d88dSmrg                            const GLenum *attachments)
5388af69d88dSmrg{
5389af69d88dSmrg   struct gl_framebuffer *fb;
5390af69d88dSmrg   GLint i;
53913464ebd5Sriastradh
5392af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
53937117f1b4Smrg
5394af69d88dSmrg   fb = get_framebuffer_target(ctx, target);
5395af69d88dSmrg   if (!fb) {
5396af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
5397af69d88dSmrg         "glDiscardFramebufferEXT(target %s)",
539801e04c3fSmrg         _mesa_enum_to_string(target));
53994a49301eSmrg      return;
54004a49301eSmrg   }
54014a49301eSmrg
5402af69d88dSmrg   if (numAttachments < 0) {
5403af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
5404af69d88dSmrg                  "glDiscardFramebufferEXT(numAttachments < 0)");
54057117f1b4Smrg      return;
54067117f1b4Smrg   }
54077117f1b4Smrg
5408af69d88dSmrg   for (i = 0; i < numAttachments; i++) {
5409af69d88dSmrg      switch (attachments[i]) {
5410af69d88dSmrg      case GL_COLOR:
5411af69d88dSmrg      case GL_DEPTH:
5412af69d88dSmrg      case GL_STENCIL:
5413af69d88dSmrg         if (_mesa_is_user_fbo(fb))
5414af69d88dSmrg            goto invalid_enum;
5415af69d88dSmrg         break;
5416af69d88dSmrg      case GL_COLOR_ATTACHMENT0:
5417af69d88dSmrg      case GL_DEPTH_ATTACHMENT:
5418af69d88dSmrg      case GL_STENCIL_ATTACHMENT:
5419af69d88dSmrg         if (_mesa_is_winsys_fbo(fb))
5420af69d88dSmrg            goto invalid_enum;
5421af69d88dSmrg         break;
5422af69d88dSmrg      default:
5423af69d88dSmrg         goto invalid_enum;
54244a49301eSmrg      }
54254a49301eSmrg   }
54264a49301eSmrg
5427a8bb7a65Smaya   discard_framebuffer(ctx, fb, numAttachments, attachments);
54283464ebd5Sriastradh
5429af69d88dSmrg   return;
54303464ebd5Sriastradh
5431af69d88dSmrginvalid_enum:
5432af69d88dSmrg   _mesa_error(ctx, GL_INVALID_ENUM,
5433af69d88dSmrg               "glDiscardFramebufferEXT(attachment %s)",
543401e04c3fSmrg              _mesa_enum_to_string(attachments[i]));
543501e04c3fSmrg}
543601e04c3fSmrg
543701e04c3fSmrgstatic void
543801e04c3fSmrgsample_locations(struct gl_context *ctx, struct gl_framebuffer *fb,
543901e04c3fSmrg                 GLuint start, GLsizei count, const GLfloat *v, bool no_error,
544001e04c3fSmrg                 const char *name)
544101e04c3fSmrg{
544201e04c3fSmrg   GLsizei i;
544301e04c3fSmrg
544401e04c3fSmrg   if (!no_error) {
544501e04c3fSmrg      if (!ctx->Extensions.ARB_sample_locations) {
544601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
544701e04c3fSmrg                     "%s not supported "
544801e04c3fSmrg                     "(ARB_sample_locations not available)", name);
544901e04c3fSmrg         return;
545001e04c3fSmrg      }
545101e04c3fSmrg
545201e04c3fSmrg      if (start + count > MAX_SAMPLE_LOCATION_TABLE_SIZE) {
545301e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
545401e04c3fSmrg                     "%s(start+size > sample location table size)", name);
545501e04c3fSmrg         return;
545601e04c3fSmrg      }
545701e04c3fSmrg   }
545801e04c3fSmrg
545901e04c3fSmrg   if (!fb->SampleLocationTable) {
546001e04c3fSmrg      size_t size = MAX_SAMPLE_LOCATION_TABLE_SIZE * 2 * sizeof(GLfloat);
546101e04c3fSmrg      fb->SampleLocationTable = malloc(size);
546201e04c3fSmrg      if (!fb->SampleLocationTable) {
546301e04c3fSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY,
546401e04c3fSmrg                     "Cannot allocate sample location table");
546501e04c3fSmrg         return;
546601e04c3fSmrg      }
546701e04c3fSmrg      for (i = 0; i < MAX_SAMPLE_LOCATION_TABLE_SIZE * 2; i++)
546801e04c3fSmrg         fb->SampleLocationTable[i] = 0.5f;
546901e04c3fSmrg   }
547001e04c3fSmrg
547101e04c3fSmrg   for (i = 0; i < count * 2; i++) {
547201e04c3fSmrg      /* The ARB_sample_locations spec says:
547301e04c3fSmrg       *
547401e04c3fSmrg       *    Sample locations outside of [0,1] result in undefined
547501e04c3fSmrg       *    behavior.
547601e04c3fSmrg       *
547701e04c3fSmrg       * To simplify driver implementations, we choose to clamp to
547801e04c3fSmrg       * [0,1] and change NaN into 0.5.
547901e04c3fSmrg       */
548001e04c3fSmrg      if (isnan(v[i]) || v[i] < 0.0f || v[i] > 1.0f) {
548101e04c3fSmrg         static GLuint msg_id = 0;
548201e04c3fSmrg         static const char* msg = "Invalid sample location specified";
548301e04c3fSmrg         _mesa_debug_get_id(&msg_id);
548401e04c3fSmrg
548501e04c3fSmrg         _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_UNDEFINED,
548601e04c3fSmrg                       msg_id, MESA_DEBUG_SEVERITY_HIGH, strlen(msg), msg);
548701e04c3fSmrg      }
548801e04c3fSmrg
548901e04c3fSmrg      if (isnan(v[i]))
549001e04c3fSmrg         fb->SampleLocationTable[start * 2 + i] = 0.5f;
549101e04c3fSmrg      else
54927ec681f3Smrg         fb->SampleLocationTable[start * 2 + i] = SATURATE(v[i]);
549301e04c3fSmrg   }
549401e04c3fSmrg
549501e04c3fSmrg   if (fb == ctx->DrawBuffer)
549601e04c3fSmrg      ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
549701e04c3fSmrg}
549801e04c3fSmrg
549901e04c3fSmrgvoid GLAPIENTRY
550001e04c3fSmrg_mesa_FramebufferSampleLocationsfvARB(GLenum target, GLuint start,
550101e04c3fSmrg                                      GLsizei count, const GLfloat *v)
550201e04c3fSmrg{
550301e04c3fSmrg   struct gl_framebuffer *fb;
550401e04c3fSmrg
550501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
550601e04c3fSmrg
550701e04c3fSmrg   fb = get_framebuffer_target(ctx, target);
550801e04c3fSmrg   if (!fb) {
550901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
551001e04c3fSmrg                  "glFramebufferSampleLocationsfvARB(target %s)",
551101e04c3fSmrg                  _mesa_enum_to_string(target));
551201e04c3fSmrg      return;
551301e04c3fSmrg   }
551401e04c3fSmrg
551501e04c3fSmrg   sample_locations(ctx, fb, start, count, v, false,
551601e04c3fSmrg                    "glFramebufferSampleLocationsfvARB");
551701e04c3fSmrg}
551801e04c3fSmrg
551901e04c3fSmrgvoid GLAPIENTRY
552001e04c3fSmrg_mesa_NamedFramebufferSampleLocationsfvARB(GLuint framebuffer, GLuint start,
552101e04c3fSmrg                                           GLsizei count, const GLfloat *v)
552201e04c3fSmrg{
552301e04c3fSmrg   struct gl_framebuffer *fb;
552401e04c3fSmrg
552501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
552601e04c3fSmrg
552701e04c3fSmrg   if (framebuffer) {
552801e04c3fSmrg      fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
552901e04c3fSmrg                                        "glNamedFramebufferSampleLocationsfvARB");
553001e04c3fSmrg      if (!fb)
553101e04c3fSmrg         return;
553201e04c3fSmrg   }
553301e04c3fSmrg   else
553401e04c3fSmrg      fb = ctx->WinSysDrawBuffer;
553501e04c3fSmrg
553601e04c3fSmrg   sample_locations(ctx, fb, start, count, v, false,
553701e04c3fSmrg                    "glNamedFramebufferSampleLocationsfvARB");
553801e04c3fSmrg}
553901e04c3fSmrg
554001e04c3fSmrgvoid GLAPIENTRY
554101e04c3fSmrg_mesa_FramebufferSampleLocationsfvARB_no_error(GLenum target, GLuint start,
554201e04c3fSmrg                                               GLsizei count, const GLfloat *v)
554301e04c3fSmrg{
554401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
554501e04c3fSmrg   sample_locations(ctx, get_framebuffer_target(ctx, target), start,
554601e04c3fSmrg                    count, v, true, "glFramebufferSampleLocationsfvARB");
554701e04c3fSmrg}
554801e04c3fSmrg
554901e04c3fSmrgvoid GLAPIENTRY
555001e04c3fSmrg_mesa_NamedFramebufferSampleLocationsfvARB_no_error(GLuint framebuffer,
555101e04c3fSmrg                                                    GLuint start, GLsizei count,
555201e04c3fSmrg                                                    const GLfloat *v)
555301e04c3fSmrg{
555401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
555501e04c3fSmrg   sample_locations(ctx, _mesa_lookup_framebuffer(ctx, framebuffer), start,
555601e04c3fSmrg                    count, v, true, "glNamedFramebufferSampleLocationsfvARB");
555701e04c3fSmrg}
555801e04c3fSmrg
555901e04c3fSmrgvoid GLAPIENTRY
556001e04c3fSmrg_mesa_EvaluateDepthValuesARB(void)
556101e04c3fSmrg{
556201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
556301e04c3fSmrg
556401e04c3fSmrg   if (!ctx->Extensions.ARB_sample_locations) {
556501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
556601e04c3fSmrg                  "EvaluateDepthValuesARB not supported (neither "
556701e04c3fSmrg                  "ARB_sample_locations nor NV_sample_locations is available)");
556801e04c3fSmrg      return;
556901e04c3fSmrg   }
557001e04c3fSmrg
557101e04c3fSmrg   if (ctx->Driver.EvaluateDepthValues)
557201e04c3fSmrg      ctx->Driver.EvaluateDepthValues(ctx);
55733464ebd5Sriastradh}
5574