blob: ca43f810553e834d9de3698fc9c2be96c20fb0e7 [file] [log] [blame]
Brian Paulddc82ee2005-02-05 19:56:45 +00001/*
2 * Mesa 3-D graphics library
Brian Paul3dc65912008-07-03 15:40:38 -06003 * Version: 7.1
Brian Paulddc82ee2005-02-05 19:56:45 +00004 *
Brian Paul3dc65912008-07-03 15:40:38 -06005 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
Brian Paul989edea2009-01-22 15:05:13 -07006 * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved.
Brian Paulddc82ee2005-02-05 19:56:45 +00007 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
Brian Paul463642c2005-02-08 02:06:00 +000027/*
Brian Paul989edea2009-01-22 15:05:13 -070028 * GL_EXT/ARB_framebuffer_object extensions
29 *
Brian Paul463642c2005-02-08 02:06:00 +000030 * Authors:
31 * Brian Paul
32 */
33
34
Roland Scheideggera1bc0d02007-07-18 20:17:14 +020035#include "buffers.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000036#include "context.h"
Brian Paul9b50cea2009-10-23 11:34:14 -060037#include "enums.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000038#include "fbobject.h"
Brian Paul5cf5d4b2009-09-27 20:51:18 -060039#include "formats.h"
Brian Paule4b23562005-05-04 20:11:35 +000040#include "framebuffer.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000041#include "hash.h"
Brian Paul37bf7202011-11-23 15:33:46 -070042#include "image.h"
Brian Paul989edea2009-01-22 15:05:13 -070043#include "macros.h"
Vinson Leedb61b9c2011-01-07 00:08:24 -080044#include "mfeatures.h"
Vinson Lee0117da42011-01-05 23:11:54 -080045#include "mtypes.h"
Brian Paule4b23562005-05-04 20:11:35 +000046#include "renderbuffer.h"
Brian Paul99745402006-03-01 02:02:43 +000047#include "state.h"
Brian Paul463642c2005-02-08 02:06:00 +000048#include "teximage.h"
Brian Paulea4fe662006-03-26 05:22:17 +000049#include "texobj.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000050
51
Brian Paul21f8d312009-10-27 16:59:23 -060052/** Set this to 1 to debug/log glBlitFramebuffer() calls */
53#define DEBUG_BLIT 0
54
Brian Paulc26c2002009-09-15 17:20:32 -060055
Brian Pauld9468c92005-02-10 16:08:07 +000056/**
57 * Notes:
58 *
59 * None of the GL_EXT_framebuffer_object functions are compiled into
60 * display lists.
61 */
62
63
64
Brian Paul923b6fc2005-02-08 04:08:56 +000065/*
66 * When glGenRender/FramebuffersEXT() is called we insert pointers to
67 * these placeholder objects into the hash table.
68 * Later, when the object ID is first bound, we replace the placeholder
69 * with the real frame/renderbuffer.
70 */
Brian Paul2c6f9112005-02-24 05:47:06 +000071static struct gl_framebuffer DummyFramebuffer;
72static struct gl_renderbuffer DummyRenderbuffer;
Brian Paul1864c7d2005-02-08 03:46:37 +000073
Kristian Høgsberg144356f2010-09-09 17:08:12 -040074/* We bind this framebuffer when applications pass a NULL
75 * drawable/surface in make current. */
76static struct gl_framebuffer IncompleteFramebuffer;
77
Brian Paul1864c7d2005-02-08 03:46:37 +000078
Brian Paul3dc65912008-07-03 15:40:38 -060079static void
80delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
81{
82 /* no op */
83}
84
85static void
86delete_dummy_framebuffer(struct gl_framebuffer *fb)
87{
88 /* no op */
89}
90
91
92void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -040093_mesa_init_fbobjects(struct gl_context *ctx)
Brian Paul3dc65912008-07-03 15:40:38 -060094{
Vladimir Vukicevic07317012010-09-01 08:54:21 -060095 _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
96 _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
Kristian Høgsberg144356f2010-09-09 17:08:12 -040097 _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex);
Brian Paul3dc65912008-07-03 15:40:38 -060098 DummyFramebuffer.Delete = delete_dummy_framebuffer;
99 DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
Kristian Høgsberg144356f2010-09-09 17:08:12 -0400100 IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
Brian Paul3dc65912008-07-03 15:40:38 -0600101}
102
Kristian Høgsberg9456e222010-06-04 14:28:59 -0400103struct gl_framebuffer *
104_mesa_get_incomplete_framebuffer(void)
105{
Kristian Høgsberg144356f2010-09-09 17:08:12 -0400106 return &IncompleteFramebuffer;
Kristian Høgsberg9456e222010-06-04 14:28:59 -0400107}
Brian Paul3dc65912008-07-03 15:40:38 -0600108
Brian Paulddc82ee2005-02-05 19:56:45 +0000109/**
Brian Paul2c6f9112005-02-24 05:47:06 +0000110 * Helper routine for getting a gl_renderbuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +0000111 */
Brian Paulea4fe662006-03-26 05:22:17 +0000112struct gl_renderbuffer *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400113_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +0000114{
Brian Paul2c6f9112005-02-24 05:47:06 +0000115 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000116
Brian Paul1864c7d2005-02-08 03:46:37 +0000117 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +0000118 return NULL;
119
Brian Paul2c6f9112005-02-24 05:47:06 +0000120 rb = (struct gl_renderbuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000121 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
122 return rb;
123}
124
125
126/**
Brian Paul2c6f9112005-02-24 05:47:06 +0000127 * Helper routine for getting a gl_framebuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +0000128 */
Brian Paulea4fe662006-03-26 05:22:17 +0000129struct gl_framebuffer *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400130_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +0000131{
Brian Paul2c6f9112005-02-24 05:47:06 +0000132 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000133
Brian Paul1864c7d2005-02-08 03:46:37 +0000134 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +0000135 return NULL;
136
Brian Paul2c6f9112005-02-24 05:47:06 +0000137 fb = (struct gl_framebuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000138 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
Brian Paul463642c2005-02-08 02:06:00 +0000139 return fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000140}
141
142
143/**
Brian Paul72966362009-01-21 16:28:38 -0700144 * Mark the given framebuffer as invalid. This will force the
145 * test for framebuffer completeness to be done before the framebuffer
146 * is used.
147 */
148static void
149invalidate_framebuffer(struct gl_framebuffer *fb)
150{
151 fb->_Status = 0; /* "indeterminate" */
152}
153
154
155/**
Brian Paulc6991432011-02-28 18:24:25 -0700156 * Return the gl_framebuffer object which corresponds to the given
157 * framebuffer target, such as GL_DRAW_FRAMEBUFFER.
158 * Check support for GL_EXT_framebuffer_blit to determine if certain
159 * targets are legal.
160 * \return gl_framebuffer pointer or NULL if target is illegal
161 */
162static struct gl_framebuffer *
163get_framebuffer_target(struct gl_context *ctx, GLenum target)
164{
165 switch (target) {
166 case GL_DRAW_FRAMEBUFFER:
Ian Romanick6dd8e762011-09-20 15:10:50 -0700167 return ctx->Extensions.EXT_framebuffer_blit && ctx->API == API_OPENGL
168 ? ctx->DrawBuffer : NULL;
Brian Paulc6991432011-02-28 18:24:25 -0700169 case GL_READ_FRAMEBUFFER:
Ian Romanick6dd8e762011-09-20 15:10:50 -0700170 return ctx->Extensions.EXT_framebuffer_blit && ctx->API == API_OPENGL
171 ? ctx->ReadBuffer : NULL;
Brian Paulc6991432011-02-28 18:24:25 -0700172 case GL_FRAMEBUFFER_EXT:
173 return ctx->DrawBuffer;
174 default:
175 return NULL;
176 }
177}
178
179
180/**
Brian Pauld9468c92005-02-10 16:08:07 +0000181 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
Brian Paul2c6f9112005-02-24 05:47:06 +0000182 * gl_renderbuffer_attachment object.
Brian Paul61ec2052010-06-22 08:37:44 -0600183 * This function is only used for user-created FB objects, not the
184 * default / window-system FB object.
Brian Paul30590072009-01-21 11:06:11 -0700185 * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
186 * the depth buffer attachment point.
Brian Pauld9468c92005-02-10 16:08:07 +0000187 */
Brian Paul84716042005-11-16 04:05:54 +0000188struct gl_renderbuffer_attachment *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400189_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
Brian Paul84716042005-11-16 04:05:54 +0000190 GLenum attachment)
Brian Paul3deaa012005-02-07 05:08:24 +0000191{
192 GLuint i;
193
Brian Paul36ede892012-01-12 09:17:23 -0700194 assert(_mesa_is_user_fbo(fb));
Brian Paul61ec2052010-06-22 08:37:44 -0600195
Brian Paul3deaa012005-02-07 05:08:24 +0000196 switch (attachment) {
197 case GL_COLOR_ATTACHMENT0_EXT:
198 case GL_COLOR_ATTACHMENT1_EXT:
199 case GL_COLOR_ATTACHMENT2_EXT:
200 case GL_COLOR_ATTACHMENT3_EXT:
201 case GL_COLOR_ATTACHMENT4_EXT:
202 case GL_COLOR_ATTACHMENT5_EXT:
203 case GL_COLOR_ATTACHMENT6_EXT:
204 case GL_COLOR_ATTACHMENT7_EXT:
205 case GL_COLOR_ATTACHMENT8_EXT:
206 case GL_COLOR_ATTACHMENT9_EXT:
207 case GL_COLOR_ATTACHMENT10_EXT:
208 case GL_COLOR_ATTACHMENT11_EXT:
209 case GL_COLOR_ATTACHMENT12_EXT:
210 case GL_COLOR_ATTACHMENT13_EXT:
211 case GL_COLOR_ATTACHMENT14_EXT:
212 case GL_COLOR_ATTACHMENT15_EXT:
Ian Romanick2e3a4ab2011-10-02 15:03:07 -0700213 /* Only OpenGL ES 1.x forbids color attachments other than
214 * GL_COLOR_ATTACHMENT0. For all other APIs the limit set by the
215 * hardware is used.
216 */
Brian Paul3deaa012005-02-07 05:08:24 +0000217 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
Ian Romanick7e4cb322011-10-02 14:50:21 -0700218 if (i >= ctx->Const.MaxColorAttachments
Ian Romanick2e3a4ab2011-10-02 15:03:07 -0700219 || (i > 0 && ctx->API == API_OPENGLES)) {
Brian Paul3deaa012005-02-07 05:08:24 +0000220 return NULL;
221 }
Brian Paule4b23562005-05-04 20:11:35 +0000222 return &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paul30590072009-01-21 11:06:11 -0700223 case GL_DEPTH_STENCIL_ATTACHMENT:
Ian Romanick7e4cb322011-10-02 14:50:21 -0700224 if (ctx->API != API_OPENGL)
225 return NULL;
Brian Paul30590072009-01-21 11:06:11 -0700226 /* fall-through */
Brian Paul3deaa012005-02-07 05:08:24 +0000227 case GL_DEPTH_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000228 return &fb->Attachment[BUFFER_DEPTH];
Brian Paul3deaa012005-02-07 05:08:24 +0000229 case GL_STENCIL_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000230 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul61ec2052010-06-22 08:37:44 -0600231 default:
232 return NULL;
233 }
234}
235
236
237/**
238 * As above, but only used for getting attachments of the default /
239 * window-system framebuffer (not user-created framebuffer objects).
240 */
241static struct gl_renderbuffer_attachment *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400242_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
Brian Paul61ec2052010-06-22 08:37:44 -0600243 GLenum attachment)
244{
Brian Paul36ede892012-01-12 09:17:23 -0700245 assert(_mesa_is_winsys_fbo(fb));
Brian Paul61ec2052010-06-22 08:37:44 -0600246
247 switch (attachment) {
Kristian Høgsberg80dfec32010-06-15 13:07:01 -0400248 case GL_FRONT_LEFT:
249 return &fb->Attachment[BUFFER_FRONT_LEFT];
250 case GL_FRONT_RIGHT:
251 return &fb->Attachment[BUFFER_FRONT_RIGHT];
252 case GL_BACK_LEFT:
253 return &fb->Attachment[BUFFER_BACK_LEFT];
254 case GL_BACK_RIGHT:
255 return &fb->Attachment[BUFFER_BACK_RIGHT];
Brian Paul61ec2052010-06-22 08:37:44 -0600256 case GL_AUX0:
257 if (fb->Visual.numAuxBuffers == 1) {
258 return &fb->Attachment[BUFFER_AUX0];
259 }
260 return NULL;
Ian Romanicka8328cc2011-10-03 12:02:18 -0700261
262 /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says:
263 *
264 * "If the default framebuffer is bound to target, then attachment must
265 * be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi,
266 * identifying a color buffer; DEPTH, identifying the depth buffer; or
267 * STENCIL, identifying the stencil buffer."
268 *
269 * Revision #34 of the ARB_framebuffer_object spec has essentially the same
270 * language. However, revision #33 of the ARB_framebuffer_object spec
271 * says:
272 *
273 * "If the default framebuffer is bound to <target>, then <attachment>
274 * must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi,
275 * DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the
276 * depth buffer, or the stencil buffer, and <pname> may be
277 * FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or
278 * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME."
279 *
280 * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed
281 * from glext.h, so shipping apps should not use those values.
282 *
283 * Note that neither EXT_framebuffer_object nor OES_framebuffer_object
284 * support queries of the window system FBO.
285 */
286 case GL_DEPTH:
Brian Paul61ec2052010-06-22 08:37:44 -0600287 return &fb->Attachment[BUFFER_DEPTH];
Ian Romanicka8328cc2011-10-03 12:02:18 -0700288 case GL_STENCIL:
Brian Paul61ec2052010-06-22 08:37:44 -0600289 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul3deaa012005-02-07 05:08:24 +0000290 default:
291 return NULL;
292 }
293}
294
295
Brian Paul61ec2052010-06-22 08:37:44 -0600296
Brian Pauld9468c92005-02-10 16:08:07 +0000297/**
298 * Remove any texture or renderbuffer attached to the given attachment
299 * point. Update reference counts, etc.
300 */
Brian Paule4b23562005-05-04 20:11:35 +0000301void
Brian Paulf9288542010-10-22 11:25:14 -0600302_mesa_remove_attachment(struct gl_context *ctx,
303 struct gl_renderbuffer_attachment *att)
Brian Paul3deaa012005-02-07 05:08:24 +0000304{
305 if (att->Type == GL_TEXTURE) {
306 ASSERT(att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100307 if (ctx->Driver.FinishRenderTexture) {
Brian Paul0e31e022005-12-01 00:25:00 +0000308 /* tell driver that we're done rendering to this texture. */
Brian9e01b912007-08-13 11:29:46 +0100309 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000310 }
Brian9e01b912007-08-13 11:29:46 +0100311 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
312 ASSERT(!att->Texture);
Brian Paul3deaa012005-02-07 05:08:24 +0000313 }
Brian Paul0e31e022005-12-01 00:25:00 +0000314 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul3deaa012005-02-07 05:08:24 +0000315 ASSERT(!att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100316 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
317 ASSERT(!att->Renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000318 }
319 att->Type = GL_NONE;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000320 att->Complete = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +0000321}
322
323
Brian Pauld9468c92005-02-10 16:08:07 +0000324/**
325 * Bind a texture object to an attachment point.
326 * The previous binding, if any, will be removed first.
327 */
Brian Paule4b23562005-05-04 20:11:35 +0000328void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400329_mesa_set_texture_attachment(struct gl_context *ctx,
Brian Paul519b23b2006-03-20 18:51:57 +0000330 struct gl_framebuffer *fb,
Brian Paule4b23562005-05-04 20:11:35 +0000331 struct gl_renderbuffer_attachment *att,
332 struct gl_texture_object *texObj,
333 GLenum texTarget, GLuint level, GLuint zoffset)
Brian Paul3deaa012005-02-07 05:08:24 +0000334{
Brian Paul0e31e022005-12-01 00:25:00 +0000335 if (att->Texture == texObj) {
336 /* re-attaching same texture */
337 ASSERT(att->Type == GL_TEXTURE);
Eric Anholt6b684822009-11-04 14:31:30 -0800338 if (ctx->Driver.FinishRenderTexture)
339 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000340 }
341 else {
342 /* new attachment */
Eric Anholt6b684822009-11-04 14:31:30 -0800343 if (ctx->Driver.FinishRenderTexture && att->Texture)
344 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000345 _mesa_remove_attachment(ctx, att);
346 att->Type = GL_TEXTURE;
Brian9e01b912007-08-13 11:29:46 +0100347 assert(!att->Texture);
348 _mesa_reference_texobj(&att->Texture, texObj);
Brian Paul0e31e022005-12-01 00:25:00 +0000349 }
350
351 /* always update these fields */
Brian Paul3deaa012005-02-07 05:08:24 +0000352 att->TextureLevel = level;
Brian Paul26f1ad62009-10-23 18:15:55 -0600353 att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
Brian Paul3deaa012005-02-07 05:08:24 +0000354 att->Zoffset = zoffset;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000355 att->Complete = GL_FALSE;
Brian Paul519b23b2006-03-20 18:51:57 +0000356
Brian Pauldb0f9e72011-04-05 07:51:01 -0600357 if (_mesa_get_attachment_teximage(att)) {
Brian Paulea4fe662006-03-26 05:22:17 +0000358 ctx->Driver.RenderTexture(ctx, fb, att);
Brian Paul519b23b2006-03-20 18:51:57 +0000359 }
Brian Paul72966362009-01-21 16:28:38 -0700360
361 invalidate_framebuffer(fb);
Brian Paul3deaa012005-02-07 05:08:24 +0000362}
363
364
Brian Pauld9468c92005-02-10 16:08:07 +0000365/**
366 * Bind a renderbuffer to an attachment point.
367 * The previous binding, if any, will be removed first.
368 */
Brian Paule4b23562005-05-04 20:11:35 +0000369void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400370_mesa_set_renderbuffer_attachment(struct gl_context *ctx,
Brian Paule4b23562005-05-04 20:11:35 +0000371 struct gl_renderbuffer_attachment *att,
372 struct gl_renderbuffer *rb)
Brian Paul3deaa012005-02-07 05:08:24 +0000373{
Brian Paulea4fe662006-03-26 05:22:17 +0000374 /* XXX check if re-doing same attachment, exit early */
Brian Paule4b23562005-05-04 20:11:35 +0000375 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000376 att->Type = GL_RENDERBUFFER_EXT;
Brian Paul2c6f9112005-02-24 05:47:06 +0000377 att->Texture = NULL; /* just to be safe */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000378 att->Complete = GL_FALSE;
Briandccd9c42007-04-02 09:56:28 -0600379 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
Brian Paul3deaa012005-02-07 05:08:24 +0000380}
381
Brian Paulddc82ee2005-02-05 19:56:45 +0000382
Brian Paulf0bbbf62005-02-09 03:50:30 +0000383/**
Brian Paule4b23562005-05-04 20:11:35 +0000384 * Fallback for ctx->Driver.FramebufferRenderbuffer()
Brian Paul84716042005-11-16 04:05:54 +0000385 * Attach a renderbuffer object to a framebuffer object.
Brian Paule4b23562005-05-04 20:11:35 +0000386 */
387void
Brian Paulf9288542010-10-22 11:25:14 -0600388_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
389 struct gl_framebuffer *fb,
Brian Paul84716042005-11-16 04:05:54 +0000390 GLenum attachment, struct gl_renderbuffer *rb)
Brian Paule4b23562005-05-04 20:11:35 +0000391{
Brian Paul84716042005-11-16 04:05:54 +0000392 struct gl_renderbuffer_attachment *att;
393
Brian Paulea4fe662006-03-26 05:22:17 +0000394 _glthread_LOCK_MUTEX(fb->Mutex);
Brian Paulea4fe662006-03-26 05:22:17 +0000395
Brian Paul84716042005-11-16 04:05:54 +0000396 att = _mesa_get_attachment(ctx, fb, attachment);
397 ASSERT(att);
Brian Paule4b23562005-05-04 20:11:35 +0000398 if (rb) {
399 _mesa_set_renderbuffer_attachment(ctx, att, rb);
Brian Paul30590072009-01-21 11:06:11 -0700400 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
401 /* do stencil attachment here (depth already done above) */
402 att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
403 assert(att);
404 _mesa_set_renderbuffer_attachment(ctx, att, rb);
405 }
Marek Olšákdf818d52011-03-06 05:26:12 +0100406 rb->AttachedAnytime = GL_TRUE;
Brian Paule4b23562005-05-04 20:11:35 +0000407 }
408 else {
409 _mesa_remove_attachment(ctx, att);
410 }
Brian Paulea4fe662006-03-26 05:22:17 +0000411
Brian Paul72966362009-01-21 16:28:38 -0700412 invalidate_framebuffer(fb);
413
Brian Paulea4fe662006-03-26 05:22:17 +0000414 _glthread_UNLOCK_MUTEX(fb->Mutex);
Brian Paule4b23562005-05-04 20:11:35 +0000415}
416
417
418/**
Brian Paul62c66b32011-01-24 19:38:52 -0700419 * Fallback for ctx->Driver.ValidateFramebuffer()
420 * Check if the renderbuffer's formats are supported by the software
421 * renderer.
422 * Drivers should probably override this.
423 */
424void
425_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
426{
427 gl_buffer_index buf;
428 for (buf = 0; buf < BUFFER_COUNT; buf++) {
429 const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer;
430 if (rb) {
431 switch (rb->_BaseFormat) {
432 case GL_ALPHA:
433 case GL_LUMINANCE_ALPHA:
434 case GL_LUMINANCE:
435 case GL_INTENSITY:
Brian Pauld3015652011-01-24 19:38:52 -0700436 case GL_RED:
437 case GL_RG:
Brian Paul62c66b32011-01-24 19:38:52 -0700438 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
439 return;
Marek Olšáka3ac28a2011-05-14 04:42:29 +0200440
441 default:
Marek Olšák9d7698c2011-04-26 02:18:24 +0200442 switch (rb->Format) {
Marek Olšáka3ac28a2011-05-14 04:42:29 +0200443 /* XXX This list is likely incomplete. */
Marek Olšák9d7698c2011-04-26 02:18:24 +0200444 case MESA_FORMAT_RGB9_E5_FLOAT:
445 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
446 return;
447 default:;
Marek Olšáka3ac28a2011-05-14 04:42:29 +0200448 /* render buffer format is supported by software rendering */
Marek Olšák9d7698c2011-04-26 02:18:24 +0200449 }
Brian Paul62c66b32011-01-24 19:38:52 -0700450 }
451 }
452 }
453}
454
455
456/**
Brian Paul9f731c82009-02-17 16:47:54 -0700457 * For debug only.
458 */
459static void
460att_incomplete(const char *msg)
461{
Brian Paul93bcf782012-05-09 12:09:21 -0600462 if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
463 _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
464 }
Brian Paul9f731c82009-02-17 16:47:54 -0700465}
466
467
468/**
Brian Paulc26c2002009-09-15 17:20:32 -0600469 * For debug only.
470 */
471static void
472fbo_incomplete(const char *msg, int index)
473{
Brian Paul93bcf782012-05-09 12:09:21 -0600474 if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
475 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
476 }
Brian Paulc26c2002009-09-15 17:20:32 -0600477}
478
479
Brian Paule67f6ee2010-10-22 11:38:23 -0600480/**
481 * Is the given base format a legal format for a color renderbuffer?
482 */
Eric Anholt059cca92011-01-02 17:58:07 -0800483GLboolean
484_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
Brian Paule67f6ee2010-10-22 11:38:23 -0600485{
486 switch (baseFormat) {
487 case GL_RGB:
488 case GL_RGBA:
489 return GL_TRUE;
Marek Olšák6e618532010-10-02 21:53:03 +0200490 case GL_LUMINANCE:
491 case GL_LUMINANCE_ALPHA:
492 case GL_INTENSITY:
Brian Paule67f6ee2010-10-22 11:38:23 -0600493 case GL_ALPHA:
494 return ctx->Extensions.ARB_framebuffer_object;
495 case GL_RED:
496 case GL_RG:
497 return ctx->Extensions.ARB_texture_rg;
498 default:
499 return GL_FALSE;
500 }
501}
502
503
504/**
505 * Is the given base format a legal format for a depth/stencil renderbuffer?
506 */
507static GLboolean
508is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
509{
510 switch (baseFormat) {
511 case GL_DEPTH_COMPONENT:
512 case GL_DEPTH_STENCIL_EXT:
513 return GL_TRUE;
514 default:
515 return GL_FALSE;
516 }
517}
Brian Paulc26c2002009-09-15 17:20:32 -0600518
519
520/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000521 * Test if an attachment point is complete and update its Complete field.
522 * \param format if GL_COLOR, this is a color attachment point,
523 * if GL_DEPTH, this is a depth component attachment point,
524 * if GL_STENCIL, this is a stencil component attachment point.
525 */
526static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400527test_attachment_completeness(const struct gl_context *ctx, GLenum format,
Brian Paul2c6f9112005-02-24 05:47:06 +0000528 struct gl_renderbuffer_attachment *att)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000529{
530 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
531
532 /* assume complete */
533 att->Complete = GL_TRUE;
534
Brian Paulf0bbbf62005-02-09 03:50:30 +0000535 /* Look for reasons why the attachment might be incomplete */
536 if (att->Type == GL_TEXTURE) {
Brian Paule4b23562005-05-04 20:11:35 +0000537 const struct gl_texture_object *texObj = att->Texture;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000538 struct gl_texture_image *texImage;
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600539 GLenum baseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000540
Brian Paule4b23562005-05-04 20:11:35 +0000541 if (!texObj) {
Brian Paul9f731c82009-02-17 16:47:54 -0700542 att_incomplete("no texobj");
Brian Paule4b23562005-05-04 20:11:35 +0000543 att->Complete = GL_FALSE;
544 return;
545 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000546
547 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
548 if (!texImage) {
Brian Paul9f731c82009-02-17 16:47:54 -0700549 att_incomplete("no teximage");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000550 att->Complete = GL_FALSE;
551 return;
552 }
553 if (texImage->Width < 1 || texImage->Height < 1) {
Brian Paul9f731c82009-02-17 16:47:54 -0700554 att_incomplete("teximage width/height=0");
Kristian Høgsberg298be2b2010-02-19 12:32:24 -0500555 printf("texobj = %u\n", texObj->Name);
556 printf("level = %d\n", att->TextureLevel);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000557 att->Complete = GL_FALSE;
558 return;
559 }
560 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
Brian Paul9f731c82009-02-17 16:47:54 -0700561 att_incomplete("bad z offset");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000562 att->Complete = GL_FALSE;
563 return;
564 }
565
Brian Paul1f7c9142009-09-30 20:28:45 -0600566 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600567
Brian Paulf0bbbf62005-02-09 03:50:30 +0000568 if (format == GL_COLOR) {
Eric Anholt059cca92011-01-02 17:58:07 -0800569 if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
Brian Paul9f731c82009-02-17 16:47:54 -0700570 att_incomplete("bad format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000571 att->Complete = GL_FALSE;
572 return;
573 }
Brian Paul1f7c9142009-09-30 20:28:45 -0600574 if (_mesa_is_format_compressed(texImage->TexFormat)) {
Eric Anholt957f3c82009-05-15 16:24:59 -0700575 att_incomplete("compressed internalformat");
576 att->Complete = GL_FALSE;
577 return;
578 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000579 }
580 else if (format == GL_DEPTH) {
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600581 if (baseFormat == GL_DEPTH_COMPONENT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000582 /* OK */
583 }
584 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600585 ctx->Extensions.ARB_depth_texture &&
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600586 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000587 /* OK */
588 }
589 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000590 att->Complete = GL_FALSE;
Brian Paul9f731c82009-02-17 16:47:54 -0700591 att_incomplete("bad depth format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000592 return;
593 }
594 }
595 else {
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600596 ASSERT(format == GL_STENCIL);
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600597 if (ctx->Extensions.EXT_packed_depth_stencil &&
598 ctx->Extensions.ARB_depth_texture &&
Brian Paul45e76d22009-10-08 20:27:27 -0600599 baseFormat == GL_DEPTH_STENCIL_EXT) {
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600600 /* OK */
601 }
602 else {
603 /* no such thing as stencil-only textures */
604 att_incomplete("illegal stencil texture");
605 att->Complete = GL_FALSE;
606 return;
607 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000608 }
609 }
Brian Paule4b23562005-05-04 20:11:35 +0000610 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul45e76d22009-10-08 20:27:27 -0600611 const GLenum baseFormat =
612 _mesa_get_format_base_format(att->Renderbuffer->Format);
613
Brian Paul49918882006-03-20 15:27:55 +0000614 ASSERT(att->Renderbuffer);
615 if (!att->Renderbuffer->InternalFormat ||
616 att->Renderbuffer->Width < 1 ||
617 att->Renderbuffer->Height < 1) {
Brian Paul9f731c82009-02-17 16:47:54 -0700618 att_incomplete("0x0 renderbuffer");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000619 att->Complete = GL_FALSE;
620 return;
621 }
622 if (format == GL_COLOR) {
Eric Anholt059cca92011-01-02 17:58:07 -0800623 if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
Brian Paul9f731c82009-02-17 16:47:54 -0700624 att_incomplete("bad renderbuffer color format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000625 att->Complete = GL_FALSE;
626 return;
627 }
628 }
629 else if (format == GL_DEPTH) {
Brian Paul45e76d22009-10-08 20:27:27 -0600630 if (baseFormat == GL_DEPTH_COMPONENT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000631 /* OK */
632 }
633 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Brian Paul45e76d22009-10-08 20:27:27 -0600634 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000635 /* OK */
636 }
637 else {
Brian Paul9f731c82009-02-17 16:47:54 -0700638 att_incomplete("bad renderbuffer depth format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000639 att->Complete = GL_FALSE;
640 return;
641 }
642 }
643 else {
644 assert(format == GL_STENCIL);
Brian Paul45e76d22009-10-08 20:27:27 -0600645 if (baseFormat == GL_STENCIL_INDEX) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000646 /* OK */
647 }
648 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Brian Paul45e76d22009-10-08 20:27:27 -0600649 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000650 /* OK */
651 }
652 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000653 att->Complete = GL_FALSE;
Brian Paul9f731c82009-02-17 16:47:54 -0700654 att_incomplete("bad renderbuffer stencil format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000655 return;
656 }
657 }
658 }
Brian Paule4b23562005-05-04 20:11:35 +0000659 else {
660 ASSERT(att->Type == GL_NONE);
661 /* complete */
662 return;
663 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000664}
665
666
667/**
668 * Test if the given framebuffer object is complete and update its
669 * Status field with the results.
Brian Paul3528f692009-01-22 15:13:18 -0700670 * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
671 * driver to make hardware-specific validation/completeness checks.
Brian Paule4b23562005-05-04 20:11:35 +0000672 * Also update the framebuffer's Width and Height fields if the
673 * framebuffer is complete.
Brian Paulf0bbbf62005-02-09 03:50:30 +0000674 */
Brian Paule4b23562005-05-04 20:11:35 +0000675void
Brian Paulf9288542010-10-22 11:25:14 -0600676_mesa_test_framebuffer_completeness(struct gl_context *ctx,
677 struct gl_framebuffer *fb)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000678{
Brian Paul989edea2009-01-22 15:05:13 -0700679 GLuint numImages;
680 GLenum intFormat = GL_NONE; /* color buffers' internal format */
681 GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
Brian Paul722d9762009-01-20 16:58:49 -0700682 GLint numSamples = -1;
Brian Paule4b23562005-05-04 20:11:35 +0000683 GLint i;
Brian Paul28b014e2006-04-05 03:05:17 +0000684 GLuint j;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000685
Brian Paul36ede892012-01-12 09:17:23 -0700686 assert(_mesa_is_user_fbo(fb));
Brian Paulc7264412005-06-01 00:50:23 +0000687
Brian Paulf0bbbf62005-02-09 03:50:30 +0000688 numImages = 0;
Brian Paule4b23562005-05-04 20:11:35 +0000689 fb->Width = 0;
690 fb->Height = 0;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000691
Brian Paul989edea2009-01-22 15:05:13 -0700692 /* Start at -2 to more easily loop over all attachment points.
693 * -2: depth buffer
694 * -1: stencil buffer
695 * >=0: color buffer
696 */
Brian Paule4b23562005-05-04 20:11:35 +0000697 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000698 struct gl_renderbuffer_attachment *att;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000699 GLenum f;
Brian Paulca1b5512011-02-28 18:23:23 -0700700 gl_format attFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000701
Brian Paul1bc59bf2009-01-22 15:07:34 -0700702 /*
703 * XXX for ARB_fbo, only check color buffers that are named by
704 * GL_READ_BUFFER and GL_DRAW_BUFFERi.
705 */
706
Brian Paul989edea2009-01-22 15:05:13 -0700707 /* check for attachment completeness
708 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000709 if (i == -2) {
Brian Paule4b23562005-05-04 20:11:35 +0000710 att = &fb->Attachment[BUFFER_DEPTH];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000711 test_attachment_completeness(ctx, GL_DEPTH, att);
712 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000713 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000714 fbo_incomplete("depth attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000715 return;
716 }
717 }
718 else if (i == -1) {
Brian Paule4b23562005-05-04 20:11:35 +0000719 att = &fb->Attachment[BUFFER_STENCIL];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000720 test_attachment_completeness(ctx, GL_STENCIL, att);
721 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000722 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000723 fbo_incomplete("stencil attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000724 return;
725 }
726 }
727 else {
Brian Paule4b23562005-05-04 20:11:35 +0000728 att = &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000729 test_attachment_completeness(ctx, GL_COLOR, att);
730 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000731 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000732 fbo_incomplete("color attachment incomplete", i);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000733 return;
734 }
735 }
736
Brian Paul989edea2009-01-22 15:05:13 -0700737 /* get width, height, format of the renderbuffer/texture
738 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000739 if (att->Type == GL_TEXTURE) {
Brian Pauldb0f9e72011-04-05 07:51:01 -0600740 const struct gl_texture_image *texImg =
741 _mesa_get_attachment_teximage(att);
Brian Paul989edea2009-01-22 15:05:13 -0700742 minWidth = MIN2(minWidth, texImg->Width);
743 maxWidth = MAX2(maxWidth, texImg->Width);
744 minHeight = MIN2(minHeight, texImg->Height);
745 maxHeight = MAX2(maxHeight, texImg->Height);
Brian Paula9fc8ba2005-10-05 01:48:07 +0000746 f = texImg->_BaseFormat;
Brian Paulca1b5512011-02-28 18:23:23 -0700747 attFormat = texImg->TexFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000748 numImages++;
Eric Anholt059cca92011-01-02 17:58:07 -0800749 if (!_mesa_is_legal_color_format(ctx, f) &&
Brian Paule67f6ee2010-10-22 11:38:23 -0600750 !is_legal_depth_format(ctx, f)) {
Brian Pauled7f3ae2005-06-07 15:03:40 +0000751 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000752 fbo_incomplete("texture attachment incomplete", -1);
Brian Pauled7f3ae2005-06-07 15:03:40 +0000753 return;
754 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000755 }
756 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul989edea2009-01-22 15:05:13 -0700757 minWidth = MIN2(minWidth, att->Renderbuffer->Width);
758 maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
759 minHeight = MIN2(minHeight, att->Renderbuffer->Height);
760 maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000761 f = att->Renderbuffer->InternalFormat;
Brian Paulca1b5512011-02-28 18:23:23 -0700762 attFormat = att->Renderbuffer->Format;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000763 numImages++;
764 }
765 else {
766 assert(att->Type == GL_NONE);
767 continue;
768 }
769
Fabian Bielerc7339d42011-04-05 07:51:01 -0600770 if (att->Renderbuffer && numSamples < 0) {
Brian Paul72966362009-01-21 16:28:38 -0700771 /* first buffer */
772 numSamples = att->Renderbuffer->NumSamples;
773 }
774
Brian Paulc7d18372010-10-23 09:38:45 -0600775 /* check if integer color */
Brian Paulca1b5512011-02-28 18:23:23 -0700776 fb->_IntegerColor = _mesa_is_format_integer_color(attFormat);
Brian Paulc7d18372010-10-23 09:38:45 -0600777
Brian Paul722d9762009-01-20 16:58:49 -0700778 /* Error-check width, height, format, samples
Brian Paul989edea2009-01-22 15:05:13 -0700779 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000780 if (numImages == 1) {
Brian Paul722d9762009-01-20 16:58:49 -0700781 /* save format, num samples */
782 if (i >= 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000783 intFormat = f;
Brian Paul722d9762009-01-20 16:58:49 -0700784 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000785 }
786 else {
Brian Paul989edea2009-01-22 15:05:13 -0700787 if (!ctx->Extensions.ARB_framebuffer_object) {
788 /* check that width, height, format are same */
789 if (minWidth != maxWidth || minHeight != maxHeight) {
790 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
791 fbo_incomplete("width or height mismatch", -1);
792 return;
793 }
Brian Paul45bd5c42011-12-16 08:44:43 -0700794 /* check that all color buffers are the same format */
Brian Paul989edea2009-01-22 15:05:13 -0700795 if (intFormat != GL_NONE && f != intFormat) {
796 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
797 fbo_incomplete("format mismatch", -1);
798 return;
799 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000800 }
Brian Paul722d9762009-01-20 16:58:49 -0700801 if (att->Renderbuffer &&
802 att->Renderbuffer->NumSamples != numSamples) {
Brian Paul72966362009-01-21 16:28:38 -0700803 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
Brian Paul722d9762009-01-20 16:58:49 -0700804 fbo_incomplete("inconsistant number of samples", i);
805 return;
Brian Paul45bd5c42011-12-16 08:44:43 -0700806 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000807 }
Marek Olšáka82227c2012-06-15 17:21:05 +0200808
809 /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported)
810 */
811 if (att->Type == GL_RENDERBUFFER &&
812 att->Renderbuffer->Format == MESA_FORMAT_NONE) {
813 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
814 fbo_incomplete("unsupported renderbuffer format", i);
815 return;
816 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000817 }
818
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400819#if FEATURE_GL
Eric Anholtd3451f72011-05-25 13:51:26 -0700820 if (ctx->API == API_OPENGL && !ctx->Extensions.ARB_ES2_compatibility) {
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400821 /* Check that all DrawBuffers are present */
822 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
823 if (fb->ColorDrawBuffer[j] != GL_NONE) {
824 const struct gl_renderbuffer_attachment *att
825 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
826 assert(att);
827 if (att->Type == GL_NONE) {
828 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
829 fbo_incomplete("missing drawbuffer", j);
830 return;
831 }
832 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000833 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000834
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400835 /* Check that the ReadBuffer is present */
836 if (fb->ColorReadBuffer != GL_NONE) {
837 const struct gl_renderbuffer_attachment *att
838 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
839 assert(att);
840 if (att->Type == GL_NONE) {
841 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000842 fbo_incomplete("missing readbuffer", -1);
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400843 return;
844 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000845 }
846 }
Chia-I Wu9927d7f2009-10-02 15:32:04 +0800847#else
848 (void) j;
Brian Paul868c09a2008-08-08 13:06:54 -0600849#endif
Brian Paulf0bbbf62005-02-09 03:50:30 +0000850
851 if (numImages == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000852 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000853 fbo_incomplete("no attachments", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000854 return;
855 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000856
Brian Paul3528f692009-01-22 15:13:18 -0700857 /* Provisionally set status = COMPLETE ... */
Brian Paule4b23562005-05-04 20:11:35 +0000858 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
Brian Paul3528f692009-01-22 15:13:18 -0700859
Brian Paul777a2ef2009-01-22 15:17:42 -0700860 /* ... but the driver may say the FB is incomplete.
861 * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
862 * if anything.
863 */
Brian Paul3528f692009-01-22 15:13:18 -0700864 if (ctx->Driver.ValidateFramebuffer) {
865 ctx->Driver.ValidateFramebuffer(ctx, fb);
Brian Paul1f32c412009-01-19 17:34:19 -0700866 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
867 fbo_incomplete("driver marked FBO as incomplete", -1);
868 }
Brian Paul3528f692009-01-22 15:13:18 -0700869 }
870
871 if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
872 /*
873 * Note that if ARB_framebuffer_object is supported and the attached
874 * renderbuffers/textures are different sizes, the framebuffer
875 * width/height will be set to the smallest width/height.
876 */
877 fb->Width = minWidth;
878 fb->Height = minHeight;
Brian Paul38768db2009-01-27 09:49:27 -0700879
880 /* finally, update the visual info for the framebuffer */
Eric Anholt059cca92011-01-02 17:58:07 -0800881 _mesa_update_framebuffer_visual(ctx, fb);
Brian Paul3528f692009-01-22 15:13:18 -0700882 }
Brian Paule4b23562005-05-04 20:11:35 +0000883}
Brian Paulf0bbbf62005-02-09 03:50:30 +0000884
885
Brian Paul1864c7d2005-02-08 03:46:37 +0000886GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000887_mesa_IsRenderbufferEXT(GLuint renderbuffer)
888{
Brian Paulddc82ee2005-02-05 19:56:45 +0000889 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000890 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000891 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000892 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000893 if (rb != NULL && rb != &DummyRenderbuffer)
894 return GL_TRUE;
895 }
896 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000897}
898
899
Brian Paul1864c7d2005-02-08 03:46:37 +0000900void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000901_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
902{
Brian42aaa542007-03-25 10:39:36 -0600903 struct gl_renderbuffer *newRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000904 GET_CURRENT_CONTEXT(ctx);
905
906 ASSERT_OUTSIDE_BEGIN_END(ctx);
907
Brian Paul3deaa012005-02-07 05:08:24 +0000908 if (target != GL_RENDERBUFFER_EXT) {
Brian Paul4de18fb2009-11-02 15:30:51 -0700909 _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000910 return;
911 }
912
Brian Paul800e5532009-11-02 15:39:39 -0700913 /* No need to flush here since the render buffer binding has no
914 * effect on rendering state.
915 */
Brian Paul474f28e2005-10-08 14:41:17 +0000916
Brian Paul3deaa012005-02-07 05:08:24 +0000917 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000918 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000919 if (newRb == &DummyRenderbuffer) {
920 /* ID was reserved, but no real renderbuffer object made yet */
921 newRb = NULL;
922 }
Brian Paul1bc59bf2009-01-22 15:07:34 -0700923 else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
924 /* All RB IDs must be Gen'd */
925 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
926 return;
927 }
928
Brian Paul3deaa012005-02-07 05:08:24 +0000929 if (!newRb) {
930 /* create new renderbuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000931 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000932 if (!newRb) {
933 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
934 return;
935 }
Brian Paul2c6f9112005-02-24 05:47:06 +0000936 ASSERT(newRb->AllocStorage);
Brian Paul1864c7d2005-02-08 03:46:37 +0000937 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
Brian42aaa542007-03-25 10:39:36 -0600938 newRb->RefCount = 1; /* referenced by hash table */
Brian Paul3deaa012005-02-07 05:08:24 +0000939 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000940 }
Brian Paul463642c2005-02-08 02:06:00 +0000941 else {
942 newRb = NULL;
943 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000944
Brian Paul1864c7d2005-02-08 03:46:37 +0000945 ASSERT(newRb != &DummyRenderbuffer);
946
Brian42aaa542007-03-25 10:39:36 -0600947 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
Brian Paulddc82ee2005-02-05 19:56:45 +0000948}
949
950
Brian Pauld0f13fa2009-01-21 11:17:45 -0700951/**
952 * If the given renderbuffer is anywhere attached to the framebuffer, detach
953 * the renderbuffer.
954 * This is used when a renderbuffer object is deleted.
955 * The spec calls for unbinding.
956 */
957static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400958detach_renderbuffer(struct gl_context *ctx,
Brian Pauld0f13fa2009-01-21 11:17:45 -0700959 struct gl_framebuffer *fb,
960 struct gl_renderbuffer *rb)
961{
962 GLuint i;
963 for (i = 0; i < BUFFER_COUNT; i++) {
964 if (fb->Attachment[i].Renderbuffer == rb) {
965 _mesa_remove_attachment(ctx, &fb->Attachment[i]);
966 }
967 }
Brian Paul72966362009-01-21 16:28:38 -0700968 invalidate_framebuffer(fb);
Brian Pauld0f13fa2009-01-21 11:17:45 -0700969}
970
971
Brian Paul1864c7d2005-02-08 03:46:37 +0000972void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000973_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
974{
975 GLint i;
976 GET_CURRENT_CONTEXT(ctx);
977
978 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000979 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000980
981 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000982 if (renderbuffers[i] > 0) {
983 struct gl_renderbuffer *rb;
Brian Paulea4fe662006-03-26 05:22:17 +0000984 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +0000985 if (rb) {
Brian Paul91802fd2005-10-04 16:01:02 +0000986 /* check if deleting currently bound renderbuffer object */
987 if (rb == ctx->CurrentRenderbuffer) {
988 /* bind default */
989 ASSERT(rb->RefCount >= 2);
990 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
991 }
992
Brian Paul36ede892012-01-12 09:17:23 -0700993 if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
Brian Pauld0f13fa2009-01-21 11:17:45 -0700994 detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
995 }
Brian Paul36ede892012-01-12 09:17:23 -0700996 if (_mesa_is_user_fbo(ctx->ReadBuffer)
Brian Paulfc8c4a32011-06-16 07:31:58 -0600997 && ctx->ReadBuffer != ctx->DrawBuffer) {
Brian Pauld0f13fa2009-01-21 11:17:45 -0700998 detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
999 }
1000
Brian42aaa542007-03-25 10:39:36 -06001001 /* Remove from hash table immediately, to free the ID.
1002 * But the object will not be freed until it's no longer
1003 * referenced anywhere else.
1004 */
Brian Paul3deaa012005-02-07 05:08:24 +00001005 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +00001006
Brian Paul1864c7d2005-02-08 03:46:37 +00001007 if (rb != &DummyRenderbuffer) {
Brian42aaa542007-03-25 10:39:36 -06001008 /* no longer referenced by hash table */
1009 _mesa_reference_renderbuffer(&rb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +00001010 }
1011 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001012 }
1013 }
1014}
1015
1016
Brian Paul1864c7d2005-02-08 03:46:37 +00001017void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001018_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
1019{
1020 GET_CURRENT_CONTEXT(ctx);
1021 GLuint first;
1022 GLint i;
1023
1024 ASSERT_OUTSIDE_BEGIN_END(ctx);
1025
1026 if (n < 0) {
1027 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
1028 return;
1029 }
1030
1031 if (!renderbuffers)
1032 return;
1033
1034 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
1035
1036 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001037 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001038 renderbuffers[i] = name;
Brian Paul1864c7d2005-02-08 03:46:37 +00001039 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001040 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001041 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001042 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001043 }
1044}
1045
1046
Brian Pauld9468c92005-02-10 16:08:07 +00001047/**
Brian Paulf41bbc72011-01-24 19:38:52 -07001048 * Given an internal format token for a render buffer, return the
Brian Paul976ea9d2011-01-24 19:38:52 -07001049 * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
1050 * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE,
1051 * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc).
Brian Paulf41bbc72011-01-24 19:38:52 -07001052 *
Brian Paul976ea9d2011-01-24 19:38:52 -07001053 * This is similar to _mesa_base_tex_format() but the set of valid
1054 * internal formats is different.
Brian Paulf41bbc72011-01-24 19:38:52 -07001055 *
Brian Paul976ea9d2011-01-24 19:38:52 -07001056 * Note that even if a format is determined to be legal here, validation
Brian Paulb3cfcdf2011-01-28 20:25:26 -07001057 * of the FBO may fail if the format is not supported by the driver/GPU.
Brian Paul976ea9d2011-01-24 19:38:52 -07001058 *
1059 * \param internalFormat as passed to glRenderbufferStorage()
1060 * \return the base internal format, or 0 if internalFormat is illegal
Brian Pauld9468c92005-02-10 16:08:07 +00001061 */
Brian Paul59e0faa2006-03-15 17:48:00 +00001062GLenum
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001063_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
Brian Paul463642c2005-02-08 02:06:00 +00001064{
Brian Paul976ea9d2011-01-24 19:38:52 -07001065 /*
1066 * Notes: some formats such as alpha, luminance, etc. were added
1067 * with GL_ARB_framebuffer_object.
1068 */
Brian Paul463642c2005-02-08 02:06:00 +00001069 switch (internalFormat) {
Brian Paulf41bbc72011-01-24 19:38:52 -07001070 case GL_ALPHA:
1071 case GL_ALPHA4:
1072 case GL_ALPHA8:
1073 case GL_ALPHA12:
1074 case GL_ALPHA16:
Brian Paul976ea9d2011-01-24 19:38:52 -07001075 return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1076 case GL_LUMINANCE:
1077 case GL_LUMINANCE4:
1078 case GL_LUMINANCE8:
1079 case GL_LUMINANCE12:
1080 case GL_LUMINANCE16:
1081 return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1082 case GL_LUMINANCE_ALPHA:
1083 case GL_LUMINANCE4_ALPHA4:
1084 case GL_LUMINANCE6_ALPHA2:
1085 case GL_LUMINANCE8_ALPHA8:
1086 case GL_LUMINANCE12_ALPHA4:
1087 case GL_LUMINANCE12_ALPHA12:
1088 case GL_LUMINANCE16_ALPHA16:
1089 return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
1090 case GL_INTENSITY:
1091 case GL_INTENSITY4:
1092 case GL_INTENSITY8:
1093 case GL_INTENSITY12:
1094 case GL_INTENSITY16:
1095 return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
Brian Paulf41bbc72011-01-24 19:38:52 -07001096 case GL_RGB:
1097 case GL_R3_G3_B2:
1098 case GL_RGB4:
1099 case GL_RGB5:
1100 case GL_RGB8:
1101 case GL_RGB10:
1102 case GL_RGB12:
1103 case GL_RGB16:
1104 case GL_SRGB8_EXT:
1105 return GL_RGB;
1106 case GL_RGBA:
1107 case GL_RGBA2:
1108 case GL_RGBA4:
1109 case GL_RGB5_A1:
1110 case GL_RGBA8:
1111 case GL_RGB10_A2:
1112 case GL_RGBA12:
1113 case GL_RGBA16:
Brian Paulf41bbc72011-01-24 19:38:52 -07001114 case GL_SRGB8_ALPHA8_EXT:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001115 return GL_RGBA;
1116 case GL_STENCIL_INDEX:
1117 case GL_STENCIL_INDEX1_EXT:
1118 case GL_STENCIL_INDEX4_EXT:
1119 case GL_STENCIL_INDEX8_EXT:
1120 case GL_STENCIL_INDEX16_EXT:
1121 return GL_STENCIL_INDEX;
1122 case GL_DEPTH_COMPONENT:
Brian Paul2c6f9112005-02-24 05:47:06 +00001123 case GL_DEPTH_COMPONENT16:
1124 case GL_DEPTH_COMPONENT24:
1125 case GL_DEPTH_COMPONENT32:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001126 return GL_DEPTH_COMPONENT;
Brian Paulf41bbc72011-01-24 19:38:52 -07001127 case GL_DEPTH_STENCIL_EXT:
1128 case GL_DEPTH24_STENCIL8_EXT:
1129 if (ctx->Extensions.EXT_packed_depth_stencil)
1130 return GL_DEPTH_STENCIL_EXT;
1131 else
1132 return 0;
Marek Olšák11652802011-06-01 15:48:51 +02001133 case GL_DEPTH_COMPONENT32F:
1134 if (ctx->Extensions.ARB_depth_buffer_float)
1135 return GL_DEPTH_COMPONENT;
1136 else
1137 return 0;
1138 case GL_DEPTH32F_STENCIL8:
1139 if (ctx->Extensions.ARB_depth_buffer_float)
1140 return GL_DEPTH_STENCIL;
1141 else
1142 return 0;
Brian Pauld3015652011-01-24 19:38:52 -07001143 case GL_RED:
1144 case GL_R8:
1145 case GL_R16:
1146 return ctx->Extensions.ARB_texture_rg ? GL_RED : 0;
1147 case GL_RG:
1148 case GL_RG8:
1149 case GL_RG16:
1150 return ctx->Extensions.ARB_texture_rg ? GL_RG : 0;
Marek Olšák0be36992011-03-18 13:44:51 +01001151 /* signed normalized texture formats */
1152 case GL_RED_SNORM:
1153 case GL_R8_SNORM:
1154 case GL_R16_SNORM:
1155 return ctx->Extensions.EXT_texture_snorm ? GL_RED : 0;
1156 case GL_RG_SNORM:
1157 case GL_RG8_SNORM:
1158 case GL_RG16_SNORM:
1159 return ctx->Extensions.EXT_texture_snorm ? GL_RG : 0;
1160 case GL_RGB_SNORM:
1161 case GL_RGB8_SNORM:
1162 case GL_RGB16_SNORM:
1163 return ctx->Extensions.EXT_texture_snorm ? GL_RGB : 0;
1164 case GL_RGBA_SNORM:
1165 case GL_RGBA8_SNORM:
1166 case GL_RGBA16_SNORM:
1167 return ctx->Extensions.EXT_texture_snorm ? GL_RGBA : 0;
1168 case GL_ALPHA_SNORM:
1169 case GL_ALPHA8_SNORM:
1170 case GL_ALPHA16_SNORM:
1171 return ctx->Extensions.EXT_texture_snorm &&
1172 ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1173 case GL_LUMINANCE_SNORM:
1174 case GL_LUMINANCE8_SNORM:
1175 case GL_LUMINANCE16_SNORM:
1176 return ctx->Extensions.EXT_texture_snorm &&
1177 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1178 case GL_LUMINANCE_ALPHA_SNORM:
1179 case GL_LUMINANCE8_ALPHA8_SNORM:
1180 case GL_LUMINANCE16_ALPHA16_SNORM:
1181 return ctx->Extensions.EXT_texture_snorm &&
1182 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
1183 case GL_INTENSITY_SNORM:
1184 case GL_INTENSITY8_SNORM:
1185 case GL_INTENSITY16_SNORM:
1186 return ctx->Extensions.EXT_texture_snorm &&
1187 ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
Marek Olšák15f99d12011-02-16 00:35:44 +01001188 case GL_R16F:
1189 case GL_R32F:
1190 return ctx->Extensions.ARB_texture_rg &&
1191 ctx->Extensions.ARB_texture_float ? GL_RED : 0;
1192 case GL_RG16F:
1193 case GL_RG32F:
1194 return ctx->Extensions.ARB_texture_rg &&
1195 ctx->Extensions.ARB_texture_float ? GL_RG : 0;
1196 case GL_RGB16F:
1197 case GL_RGB32F:
1198 return ctx->Extensions.ARB_texture_float ? GL_RGB : 0;
1199 case GL_RGBA16F:
1200 case GL_RGBA32F:
1201 return ctx->Extensions.ARB_texture_float ? GL_RGBA : 0;
1202 case GL_ALPHA16F_ARB:
1203 case GL_ALPHA32F_ARB:
1204 return ctx->Extensions.ARB_texture_float &&
1205 ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1206 case GL_LUMINANCE16F_ARB:
1207 case GL_LUMINANCE32F_ARB:
1208 return ctx->Extensions.ARB_texture_float &&
1209 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1210 case GL_LUMINANCE_ALPHA16F_ARB:
1211 case GL_LUMINANCE_ALPHA32F_ARB:
1212 return ctx->Extensions.ARB_texture_float &&
1213 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
1214 case GL_INTENSITY16F_ARB:
1215 case GL_INTENSITY32F_ARB:
1216 return ctx->Extensions.ARB_texture_float &&
1217 ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
Marek Olšák9d7698c2011-04-26 02:18:24 +02001218 case GL_RGB9_E5:
1219 return ctx->Extensions.EXT_texture_shared_exponent ? GL_RGB : 0;
Marek Olšák631d23d2011-04-26 02:27:25 +02001220 case GL_R11F_G11F_B10F:
1221 return ctx->Extensions.EXT_packed_float ? GL_RGB : 0;
Dave Airlie9c697a92011-10-04 20:59:40 +01001222
1223 case GL_RGBA8UI_EXT:
1224 case GL_RGBA16UI_EXT:
1225 case GL_RGBA32UI_EXT:
1226 case GL_RGBA8I_EXT:
1227 case GL_RGBA16I_EXT:
1228 case GL_RGBA32I_EXT:
Marek Olšák3363e872012-01-22 20:25:42 +01001229 return ctx->VersionMajor >= 3 ||
1230 ctx->Extensions.EXT_texture_integer ? GL_RGBA : 0;
Dave Airlie9c697a92011-10-04 20:59:40 +01001231
1232 case GL_RGB8UI_EXT:
1233 case GL_RGB16UI_EXT:
1234 case GL_RGB32UI_EXT:
1235 case GL_RGB8I_EXT:
1236 case GL_RGB16I_EXT:
1237 case GL_RGB32I_EXT:
Marek Olšák3363e872012-01-22 20:25:42 +01001238 return ctx->VersionMajor >= 3 ||
1239 ctx->Extensions.EXT_texture_integer ? GL_RGB : 0;
Dave Airlie9c697a92011-10-04 20:59:40 +01001240
1241 case GL_R8UI:
1242 case GL_R8I:
1243 case GL_R16UI:
1244 case GL_R16I:
1245 case GL_R32UI:
1246 case GL_R32I:
Marek Olšák3363e872012-01-22 20:25:42 +01001247 return ctx->VersionMajor >= 3 ||
1248 (ctx->Extensions.ARB_texture_rg &&
1249 ctx->Extensions.EXT_texture_integer) ? GL_RED : 0;
Dave Airlie9c697a92011-10-04 20:59:40 +01001250
1251 case GL_RG8UI:
1252 case GL_RG8I:
1253 case GL_RG16UI:
1254 case GL_RG16I:
1255 case GL_RG32UI:
1256 case GL_RG32I:
Marek Olšák3363e872012-01-22 20:25:42 +01001257 return ctx->VersionMajor >= 3 ||
1258 (ctx->Extensions.ARB_texture_rg &&
1259 ctx->Extensions.EXT_texture_integer) ? GL_RG : 0;
Brian Paul45bd5c42011-12-16 08:44:43 -07001260
Dave Airlie9c697a92011-10-04 20:59:40 +01001261 case GL_INTENSITY8I_EXT:
1262 case GL_INTENSITY8UI_EXT:
1263 case GL_INTENSITY16I_EXT:
1264 case GL_INTENSITY16UI_EXT:
1265 case GL_INTENSITY32I_EXT:
1266 case GL_INTENSITY32UI_EXT:
1267 return ctx->Extensions.EXT_texture_integer &&
1268 ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
1269
1270 case GL_LUMINANCE8I_EXT:
1271 case GL_LUMINANCE8UI_EXT:
1272 case GL_LUMINANCE16I_EXT:
1273 case GL_LUMINANCE16UI_EXT:
1274 case GL_LUMINANCE32I_EXT:
1275 case GL_LUMINANCE32UI_EXT:
1276 return ctx->Extensions.EXT_texture_integer &&
1277 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1278
1279 case GL_LUMINANCE_ALPHA8I_EXT:
1280 case GL_LUMINANCE_ALPHA8UI_EXT:
1281 case GL_LUMINANCE_ALPHA16I_EXT:
1282 case GL_LUMINANCE_ALPHA16UI_EXT:
1283 case GL_LUMINANCE_ALPHA32I_EXT:
1284 case GL_LUMINANCE_ALPHA32UI_EXT:
1285 return ctx->Extensions.EXT_texture_integer &&
1286 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
Dave Airlief449be62011-11-27 16:21:02 +00001287
Marek Olšák636802f2012-01-22 20:21:36 +01001288 case GL_ALPHA8I_EXT:
1289 case GL_ALPHA8UI_EXT:
1290 case GL_ALPHA16I_EXT:
1291 case GL_ALPHA16UI_EXT:
1292 case GL_ALPHA32I_EXT:
1293 case GL_ALPHA32UI_EXT:
1294 return ctx->Extensions.EXT_texture_integer &&
1295 ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1296
Dave Airlief449be62011-11-27 16:21:02 +00001297 case GL_RGB10_A2UI:
1298 return ctx->Extensions.ARB_texture_rgb10_a2ui ? GL_RGBA : 0;
Marek Olšák1a06e842012-07-12 14:07:41 +02001299
1300 case GL_RGB565:
1301 return ctx->Extensions.ARB_ES2_compatibility ? GL_RGB : 0;
Brian Paulf41bbc72011-01-24 19:38:52 -07001302 default:
Eric Anholt65c41d52011-01-13 10:05:50 -08001303 return 0;
Brian Paulf41bbc72011-01-24 19:38:52 -07001304 }
Brian Paul463642c2005-02-08 02:06:00 +00001305}
1306
1307
Marek Olšákdf818d52011-03-06 05:26:12 +01001308/**
1309 * Invalidate a renderbuffer attachment. Called from _mesa_HashWalk().
1310 */
1311static void
1312invalidate_rb(GLuint key, void *data, void *userData)
1313{
1314 struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
1315 struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData;
1316
1317 /* If this is a user-created FBO */
Brian Paul36ede892012-01-12 09:17:23 -07001318 if (_mesa_is_user_fbo(fb)) {
Marek Olšákdf818d52011-03-06 05:26:12 +01001319 GLuint i;
1320 for (i = 0; i < BUFFER_COUNT; i++) {
1321 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1322 if (att->Type == GL_RENDERBUFFER &&
1323 att->Renderbuffer == rb) {
1324 /* Mark fb status as indeterminate to force re-validation */
1325 fb->_Status = 0;
Marek Olšáka674ef72011-03-07 23:33:36 +01001326 return;
Marek Olšákdf818d52011-03-06 05:26:12 +01001327 }
1328 }
1329 }
1330}
1331
1332
Brian Paul4f3514e2009-01-22 15:19:56 -07001333/** sentinal value, see below */
1334#define NO_SAMPLES 1000
1335
1336
1337/**
1338 * Helper function used by _mesa_RenderbufferStorageEXT() and
1339 * _mesa_RenderbufferStorageMultisample().
1340 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
1341 */
1342static void
1343renderbuffer_storage(GLenum target, GLenum internalFormat,
1344 GLsizei width, GLsizei height, GLsizei samples)
Brian Paulddc82ee2005-02-05 19:56:45 +00001345{
Brian Paul4f3514e2009-01-22 15:19:56 -07001346 const char *func = samples == NO_SAMPLES ?
1347 "glRenderbufferStorage" : "RenderbufferStorageMultisample";
Brian Paul2c6f9112005-02-24 05:47:06 +00001348 struct gl_renderbuffer *rb;
Brian Paul463642c2005-02-08 02:06:00 +00001349 GLenum baseFormat;
Brian Paulddc82ee2005-02-05 19:56:45 +00001350 GET_CURRENT_CONTEXT(ctx);
1351
1352 ASSERT_OUTSIDE_BEGIN_END(ctx);
1353
Brian Paul463642c2005-02-08 02:06:00 +00001354 if (target != GL_RENDERBUFFER_EXT) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001355 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001356 return;
1357 }
1358
Brian Paul59e0faa2006-03-15 17:48:00 +00001359 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
Brian Paul463642c2005-02-08 02:06:00 +00001360 if (baseFormat == 0) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001361 _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001362 return;
1363 }
1364
Yuanhan Liu49f84472011-10-25 15:36:59 +08001365 if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001366 _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001367 return;
1368 }
1369
Yuanhan Liu49f84472011-10-25 15:36:59 +08001370 if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001371 _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
1372 return;
1373 }
1374
1375 if (samples == NO_SAMPLES) {
1376 /* NumSamples == 0 indicates non-multisampling */
1377 samples = 0;
1378 }
Brian Paulca0d0482010-01-27 17:01:54 -07001379 else if (samples > (GLsizei) ctx->Const.MaxSamples) {
Brian Paul722d9762009-01-20 16:58:49 -07001380 /* note: driver may choose to use more samples than what's requested */
Brian Paul4f3514e2009-01-22 15:19:56 -07001381 _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001382 return;
1383 }
1384
Brian Paul2c6f9112005-02-24 05:47:06 +00001385 rb = ctx->CurrentRenderbuffer;
Brian Paul2c6f9112005-02-24 05:47:06 +00001386 if (!rb) {
Vinson Leec5dde532010-09-02 16:03:32 -07001387 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
Brian Paul463642c2005-02-08 02:06:00 +00001388 return;
1389 }
1390
Brian Paul474f28e2005-10-08 14:41:17 +00001391 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1392
Brian Paul311bcf52005-11-18 02:24:14 +00001393 if (rb->InternalFormat == internalFormat &&
Brian Paul13abf912006-04-13 19:17:13 +00001394 rb->Width == (GLuint) width &&
Eric Anholt0e8d1562012-01-11 13:46:43 -08001395 rb->Height == (GLuint) height &&
1396 rb->NumSamples == samples) {
Brian Paul311bcf52005-11-18 02:24:14 +00001397 /* no change in allocation needed */
1398 return;
1399 }
1400
Brian Paulea4fe662006-03-26 05:22:17 +00001401 /* These MUST get set by the AllocStorage func */
Brian Paul45e76d22009-10-08 20:27:27 -06001402 rb->Format = MESA_FORMAT_NONE;
Brian Paul4f3514e2009-01-22 15:19:56 -07001403 rb->NumSamples = samples;
Brian Paulea4fe662006-03-26 05:22:17 +00001404
Brian Paul2c6f9112005-02-24 05:47:06 +00001405 /* Now allocate the storage */
1406 ASSERT(rb->AllocStorage);
1407 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
1408 /* No error - check/set fields now */
Marek Olšáka82227c2012-06-15 17:21:05 +02001409 /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */
Brian Paul13abf912006-04-13 19:17:13 +00001410 assert(rb->Width == (GLuint) width);
1411 assert(rb->Height == (GLuint) height);
Brian Paulea4fe662006-03-26 05:22:17 +00001412 rb->InternalFormat = internalFormat;
Brian Paula8dafe72010-02-25 19:03:55 -07001413 rb->_BaseFormat = baseFormat;
Brian Paul45e76d22009-10-08 20:27:27 -06001414 assert(rb->_BaseFormat != 0);
Brian Paul2c6f9112005-02-24 05:47:06 +00001415 }
1416 else {
1417 /* Probably ran out of memory - clear the fields */
1418 rb->Width = 0;
1419 rb->Height = 0;
Brian Paul45e76d22009-10-08 20:27:27 -06001420 rb->Format = MESA_FORMAT_NONE;
Brian Paul2c6f9112005-02-24 05:47:06 +00001421 rb->InternalFormat = GL_NONE;
1422 rb->_BaseFormat = GL_NONE;
Brian Paul4f3514e2009-01-22 15:19:56 -07001423 rb->NumSamples = 0;
Brian Paul463642c2005-02-08 02:06:00 +00001424 }
1425
Marek Olšákdf818d52011-03-06 05:26:12 +01001426 /* Invalidate the framebuffers the renderbuffer is attached in. */
1427 if (rb->AttachedAnytime) {
1428 _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb);
1429 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001430}
1431
Brian Paul23c5b212010-05-28 13:33:03 -06001432
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001433#if FEATURE_OES_EGL_image
1434void GLAPIENTRY
Brian Paul23c5b212010-05-28 13:33:03 -06001435_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001436{
Brian Paul51b79922010-02-24 11:57:26 -07001437 struct gl_renderbuffer *rb;
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001438 GET_CURRENT_CONTEXT(ctx);
1439 ASSERT_OUTSIDE_BEGIN_END(ctx);
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001440
Chia-I Wu2002e4d02010-04-06 17:46:17 +08001441 if (!ctx->Extensions.OES_EGL_image) {
1442 _mesa_error(ctx, GL_INVALID_OPERATION,
1443 "glEGLImageTargetRenderbufferStorageOES(unsupported)");
1444 return;
1445 }
1446
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001447 if (target != GL_RENDERBUFFER) {
Brian Paul23c5b212010-05-28 13:33:03 -06001448 _mesa_error(ctx, GL_INVALID_ENUM,
1449 "EGLImageTargetRenderbufferStorageOES");
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001450 return;
1451 }
1452
1453 rb = ctx->CurrentRenderbuffer;
1454 if (!rb) {
Brian Paul23c5b212010-05-28 13:33:03 -06001455 _mesa_error(ctx, GL_INVALID_OPERATION,
1456 "EGLImageTargetRenderbufferStorageOES");
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001457 return;
1458 }
1459
1460 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1461
1462 ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1463}
1464#endif
Brian Paulddc82ee2005-02-05 19:56:45 +00001465
Brian Paul23c5b212010-05-28 13:33:03 -06001466
Brian Paul45e76d22009-10-08 20:27:27 -06001467/**
1468 * Helper function for _mesa_GetRenderbufferParameterivEXT() and
1469 * _mesa_GetFramebufferAttachmentParameterivEXT()
1470 * We have to be careful to respect the base format. For example, if a
1471 * renderbuffer/texture was created with internalFormat=GL_RGB but the
1472 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
1473 * we need to return zero.
1474 */
1475static GLint
1476get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
1477{
Brian Paulf0b6e9a2011-11-23 15:33:45 -07001478 if (_mesa_base_format_has_channel(baseFormat, pname))
1479 return _mesa_get_format_bits(format, pname);
1480 else
Brian Paul45e76d22009-10-08 20:27:27 -06001481 return 0;
Brian Paul45e76d22009-10-08 20:27:27 -06001482}
1483
1484
1485
Brian Paul1864c7d2005-02-08 03:46:37 +00001486void GLAPIENTRY
Brian Paul4f3514e2009-01-22 15:19:56 -07001487_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1488 GLsizei width, GLsizei height)
1489{
Brian Paul722d9762009-01-20 16:58:49 -07001490 /* GL_ARB_fbo says calling this function is equivalent to calling
1491 * glRenderbufferStorageMultisample() with samples=0. We pass in
1492 * a token value here just for error reporting purposes.
1493 */
Brian Paul4f3514e2009-01-22 15:19:56 -07001494 renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
1495}
1496
1497
1498void GLAPIENTRY
Brian Paul777a2ef2009-01-22 15:17:42 -07001499_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
Brian Paul4f3514e2009-01-22 15:19:56 -07001500 GLenum internalFormat,
Brian Paul777a2ef2009-01-22 15:17:42 -07001501 GLsizei width, GLsizei height)
1502{
Brian Paul4f3514e2009-01-22 15:19:56 -07001503 renderbuffer_storage(target, internalFormat, width, height, samples);
Brian Paul777a2ef2009-01-22 15:17:42 -07001504}
1505
Brian Paul23c5b212010-05-28 13:33:03 -06001506
1507/**
1508 * OpenGL ES version of glRenderBufferStorage.
1509 */
Kristian Høgsberg61d94dd2010-04-22 21:11:56 -04001510void GLAPIENTRY
1511_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1512 GLsizei width, GLsizei height)
1513{
1514 switch (internalFormat) {
1515 case GL_RGB565:
1516 /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
1517 /* choose a closest format */
1518 internalFormat = GL_RGB5;
1519 break;
1520 default:
1521 break;
1522 }
Brian Paul777a2ef2009-01-22 15:17:42 -07001523
Kristian Høgsberg61d94dd2010-04-22 21:11:56 -04001524 renderbuffer_storage(target, internalFormat, width, height, 0);
1525}
Brian Paul777a2ef2009-01-22 15:17:42 -07001526
Brian Paul23c5b212010-05-28 13:33:03 -06001527
Brian Paul777a2ef2009-01-22 15:17:42 -07001528void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001529_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
1530{
Brian Paul722d9762009-01-20 16:58:49 -07001531 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001532 GET_CURRENT_CONTEXT(ctx);
1533
1534 ASSERT_OUTSIDE_BEGIN_END(ctx);
1535
Brian Paul463642c2005-02-08 02:06:00 +00001536 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001537 _mesa_error(ctx, GL_INVALID_ENUM,
1538 "glGetRenderbufferParameterivEXT(target)");
1539 return;
1540 }
1541
Brian Paul722d9762009-01-20 16:58:49 -07001542 rb = ctx->CurrentRenderbuffer;
1543 if (!rb) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001544 _mesa_error(ctx, GL_INVALID_OPERATION,
1545 "glGetRenderbufferParameterivEXT");
1546 return;
1547 }
1548
Brian Paul800e5532009-11-02 15:39:39 -07001549 /* No need to flush here since we're just quering state which is
1550 * not effected by rendering.
1551 */
Brian Paul474f28e2005-10-08 14:41:17 +00001552
Brian Paul463642c2005-02-08 02:06:00 +00001553 switch (pname) {
1554 case GL_RENDERBUFFER_WIDTH_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001555 *params = rb->Width;
Brian Paul463642c2005-02-08 02:06:00 +00001556 return;
1557 case GL_RENDERBUFFER_HEIGHT_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001558 *params = rb->Height;
Brian Paul463642c2005-02-08 02:06:00 +00001559 return;
1560 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001561 *params = rb->InternalFormat;
Brian Paul463642c2005-02-08 02:06:00 +00001562 return;
Brian Paul1b939532005-05-31 23:55:21 +00001563 case GL_RENDERBUFFER_RED_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001564 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001565 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001566 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001567 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001568 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
Brian Paul45e76d22009-10-08 20:27:27 -06001569 *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
Brian Paul1b939532005-05-31 23:55:21 +00001570 break;
Brian Paul722d9762009-01-20 16:58:49 -07001571 case GL_RENDERBUFFER_SAMPLES:
1572 if (ctx->Extensions.ARB_framebuffer_object) {
1573 *params = rb->NumSamples;
1574 break;
1575 }
1576 /* fallthrough */
Brian Paul463642c2005-02-08 02:06:00 +00001577 default:
1578 _mesa_error(ctx, GL_INVALID_ENUM,
1579 "glGetRenderbufferParameterivEXT(target)");
1580 return;
1581 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001582}
1583
1584
Brian Paul1864c7d2005-02-08 03:46:37 +00001585GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001586_mesa_IsFramebufferEXT(GLuint framebuffer)
1587{
Brian Paulddc82ee2005-02-05 19:56:45 +00001588 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +00001589 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +00001590 if (framebuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00001591 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +00001592 if (rb != NULL && rb != &DummyFramebuffer)
1593 return GL_TRUE;
1594 }
1595 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +00001596}
1597
1598
briana492ab72009-11-10 15:33:31 -07001599/**
1600 * Check if any of the attachments of the given framebuffer are textures
1601 * (render to texture). Call ctx->Driver.RenderTexture() for such
1602 * attachments.
1603 */
Brian Paulea4fe662006-03-26 05:22:17 +00001604static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001605check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
Brian Paulea4fe662006-03-26 05:22:17 +00001606{
1607 GLuint i;
1608 ASSERT(ctx->Driver.RenderTexture);
briana65b84d2009-11-10 18:02:03 -07001609
Brian Paul36ede892012-01-12 09:17:23 -07001610 if (_mesa_is_winsys_fbo(fb))
briana65b84d2009-11-10 18:02:03 -07001611 return; /* can't render to texture with winsys framebuffers */
1612
Brian Paulea4fe662006-03-26 05:22:17 +00001613 for (i = 0; i < BUFFER_COUNT; i++) {
1614 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
Brian Pauldb0f9e72011-04-05 07:51:01 -06001615 if (att->Texture && _mesa_get_attachment_teximage(att)) {
Brian Paulea4fe662006-03-26 05:22:17 +00001616 ctx->Driver.RenderTexture(ctx, fb, att);
1617 }
1618 }
1619}
1620
1621
Brian Paul0e31e022005-12-01 00:25:00 +00001622/**
1623 * Examine all the framebuffer's attachments to see if any are textures.
1624 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
1625 * notify the device driver that the texture image may have changed.
1626 */
1627static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001628check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
Brian Paul0e31e022005-12-01 00:25:00 +00001629{
Brian Paul36ede892012-01-12 09:17:23 -07001630 if (_mesa_is_winsys_fbo(fb))
briana65b84d2009-11-10 18:02:03 -07001631 return; /* can't render to texture with winsys framebuffers */
1632
Brian Paul0e31e022005-12-01 00:25:00 +00001633 if (ctx->Driver.FinishRenderTexture) {
1634 GLuint i;
1635 for (i = 0; i < BUFFER_COUNT; i++) {
1636 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
Brian8b361662007-11-09 08:55:49 -07001637 if (att->Texture && att->Renderbuffer) {
Brian Paul519b23b2006-03-20 18:51:57 +00001638 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +00001639 }
1640 }
1641 }
1642}
1643
1644
Brian Paul1864c7d2005-02-08 03:46:37 +00001645void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001646_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
1647{
briane6f60d32009-11-10 15:47:34 -07001648 struct gl_framebuffer *newDrawFb, *newReadFb;
briand96e55f2009-11-10 15:50:22 -07001649 struct gl_framebuffer *oldDrawFb, *oldReadFb;
Brian Paul0bffb112005-11-08 14:45:48 +00001650 GLboolean bindReadBuf, bindDrawBuf;
Brian Paulddc82ee2005-02-05 19:56:45 +00001651 GET_CURRENT_CONTEXT(ctx);
1652
Brian Paul1bc59bf2009-01-22 15:07:34 -07001653#ifdef DEBUG
1654 if (ctx->Extensions.ARB_framebuffer_object) {
1655 ASSERT(ctx->Extensions.EXT_framebuffer_object);
1656 ASSERT(ctx->Extensions.EXT_framebuffer_blit);
1657 }
1658#endif
1659
Brian Paulddc82ee2005-02-05 19:56:45 +00001660 ASSERT_OUTSIDE_BEGIN_END(ctx);
1661
Brian Paulea4fe662006-03-26 05:22:17 +00001662 if (!ctx->Extensions.EXT_framebuffer_object) {
1663 _mesa_error(ctx, GL_INVALID_OPERATION,
1664 "glBindFramebufferEXT(unsupported)");
1665 return;
1666 }
1667
Brian Paul0bffb112005-11-08 14:45:48 +00001668 switch (target) {
1669#if FEATURE_EXT_framebuffer_blit
1670 case GL_DRAW_FRAMEBUFFER_EXT:
1671 if (!ctx->Extensions.EXT_framebuffer_blit) {
1672 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1673 return;
1674 }
1675 bindDrawBuf = GL_TRUE;
1676 bindReadBuf = GL_FALSE;
1677 break;
1678 case GL_READ_FRAMEBUFFER_EXT:
1679 if (!ctx->Extensions.EXT_framebuffer_blit) {
1680 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1681 return;
1682 }
1683 bindDrawBuf = GL_FALSE;
1684 bindReadBuf = GL_TRUE;
1685 break;
1686#endif
1687 case GL_FRAMEBUFFER_EXT:
1688 bindDrawBuf = GL_TRUE;
1689 bindReadBuf = GL_TRUE;
1690 break;
1691 default:
Brian Pauleba4ff62005-09-06 21:22:16 +00001692 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +00001693 return;
1694 }
1695
Brian Paul3deaa012005-02-07 05:08:24 +00001696 if (framebuffer) {
Brian Paule4b23562005-05-04 20:11:35 +00001697 /* Binding a user-created framebuffer object */
briane6f60d32009-11-10 15:47:34 -07001698 newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
1699 if (newDrawFb == &DummyFramebuffer) {
Brian Paul923b6fc2005-02-08 04:08:56 +00001700 /* ID was reserved, but no real framebuffer object made yet */
briane6f60d32009-11-10 15:47:34 -07001701 newDrawFb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001702 }
briane6f60d32009-11-10 15:47:34 -07001703 else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
Brian Paul1bc59bf2009-01-22 15:07:34 -07001704 /* All FBO IDs must be Gen'd */
1705 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
1706 return;
1707 }
1708
briane6f60d32009-11-10 15:47:34 -07001709 if (!newDrawFb) {
Brian Paul3deaa012005-02-07 05:08:24 +00001710 /* create new framebuffer object */
briane6f60d32009-11-10 15:47:34 -07001711 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
1712 if (!newDrawFb) {
Brian Paul3deaa012005-02-07 05:08:24 +00001713 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1714 return;
1715 }
briane6f60d32009-11-10 15:47:34 -07001716 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
Brian Paul3deaa012005-02-07 05:08:24 +00001717 }
briane6f60d32009-11-10 15:47:34 -07001718 newReadFb = newDrawFb;
Brian Paul3deaa012005-02-07 05:08:24 +00001719 }
Brian Paul463642c2005-02-08 02:06:00 +00001720 else {
Brian Paule4b23562005-05-04 20:11:35 +00001721 /* Binding the window system framebuffer (which was originally set
1722 * with MakeCurrent).
1723 */
briane6f60d32009-11-10 15:47:34 -07001724 newDrawFb = ctx->WinSysDrawBuffer;
1725 newReadFb = ctx->WinSysReadBuffer;
Brian Paul3deaa012005-02-07 05:08:24 +00001726 }
1727
briane6f60d32009-11-10 15:47:34 -07001728 ASSERT(newDrawFb);
1729 ASSERT(newDrawFb != &DummyFramebuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001730
briana65b84d2009-11-10 18:02:03 -07001731 /* save pointers to current/old framebuffers */
briand96e55f2009-11-10 15:50:22 -07001732 oldDrawFb = ctx->DrawBuffer;
1733 oldReadFb = ctx->ReadBuffer;
1734
briana65b84d2009-11-10 18:02:03 -07001735 /* check if really changing bindings */
1736 if (oldDrawFb == newDrawFb)
1737 bindDrawBuf = GL_FALSE;
1738 if (oldReadFb == newReadFb)
1739 bindReadBuf = GL_FALSE;
1740
Brian Paulea4fe662006-03-26 05:22:17 +00001741 /*
Brian Paul16144632009-02-26 14:49:24 -07001742 * OK, now bind the new Draw/Read framebuffers, if they're changing.
briana65b84d2009-11-10 18:02:03 -07001743 *
1744 * We also check if we're beginning and/or ending render-to-texture.
1745 * When a framebuffer with texture attachments is unbound, call
1746 * ctx->Driver.FinishRenderTexture().
1747 * When a framebuffer with texture attachments is bound, call
1748 * ctx->Driver.RenderTexture().
1749 *
1750 * Note that if the ReadBuffer has texture attachments we don't consider
1751 * that a render-to-texture case.
Brian Paulea4fe662006-03-26 05:22:17 +00001752 */
Brian Paul0bffb112005-11-08 14:45:48 +00001753 if (bindReadBuf) {
briana65b84d2009-11-10 18:02:03 -07001754 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
brianbc569cd2009-11-10 16:00:35 -07001755
briana65b84d2009-11-10 18:02:03 -07001756 /* check if old readbuffer was render-to-texture */
1757 check_end_texture_render(ctx, oldReadFb);
1758
1759 _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001760 }
1761
1762 if (bindDrawBuf) {
briana65b84d2009-11-10 18:02:03 -07001763 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian32d86eb2007-08-16 18:52:48 +01001764
Eric Anholta1fd13f2012-02-10 12:05:16 -08001765 /* check if old framebuffer had any texture attachments */
1766 if (oldDrawFb)
briana65b84d2009-11-10 18:02:03 -07001767 check_end_texture_render(ctx, oldDrawFb);
brianbc569cd2009-11-10 16:00:35 -07001768
briana65b84d2009-11-10 18:02:03 -07001769 /* check if newly bound framebuffer has any texture attachments */
1770 check_begin_texture_render(ctx, newDrawFb);
1771
1772 _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001773 }
Brian Paul59e0faa2006-03-15 17:48:00 +00001774
Brian Paul16144632009-02-26 14:49:24 -07001775 if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
briane6f60d32009-11-10 15:47:34 -07001776 ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
Brian Paul59e0faa2006-03-15 17:48:00 +00001777 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001778}
1779
1780
Brian Paul1864c7d2005-02-08 03:46:37 +00001781void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001782_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1783{
1784 GLint i;
1785 GET_CURRENT_CONTEXT(ctx);
1786
1787 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul800e5532009-11-02 15:39:39 -07001788 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00001789
1790 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +00001791 if (framebuffers[i] > 0) {
1792 struct gl_framebuffer *fb;
Brian Paulea4fe662006-03-26 05:22:17 +00001793 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +00001794 if (fb) {
Brian Paule4b23562005-05-04 20:11:35 +00001795 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
Brian Paul91802fd2005-10-04 16:01:02 +00001796
1797 /* check if deleting currently bound framebuffer object */
Erik Wien68ca19a2010-01-26 13:19:30 -07001798 if (ctx->Extensions.EXT_framebuffer_blit) {
1799 /* separate draw/read binding points */
1800 if (fb == ctx->DrawBuffer) {
1801 /* bind default */
1802 ASSERT(fb->RefCount >= 2);
1803 _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1804 }
1805 if (fb == ctx->ReadBuffer) {
1806 /* bind default */
1807 ASSERT(fb->RefCount >= 2);
1808 _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1809 }
Brian Pauld0f13fa2009-01-21 11:17:45 -07001810 }
Erik Wien68ca19a2010-01-26 13:19:30 -07001811 else {
1812 /* only one binding point for read/draw buffers */
1813 if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
1814 /* bind default */
1815 ASSERT(fb->RefCount >= 2);
1816 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
Brian Paul45bd5c42011-12-16 08:44:43 -07001817 }
Brian Paul91802fd2005-10-04 16:01:02 +00001818 }
1819
Brian Paul3deaa012005-02-07 05:08:24 +00001820 /* remove from hash table immediately, to free the ID */
1821 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +00001822
Brian Paul1864c7d2005-02-08 03:46:37 +00001823 if (fb != &DummyFramebuffer) {
1824 /* But the object will not be freed until it's no longer
1825 * bound in any context.
1826 */
Brian Pauld5229442009-02-09 08:30:55 -07001827 _mesa_reference_framebuffer(&fb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +00001828 }
1829 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001830 }
1831 }
1832}
1833
1834
Brian Paul1864c7d2005-02-08 03:46:37 +00001835void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001836_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1837{
1838 GET_CURRENT_CONTEXT(ctx);
1839 GLuint first;
1840 GLint i;
1841
1842 ASSERT_OUTSIDE_BEGIN_END(ctx);
1843
1844 if (n < 0) {
1845 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1846 return;
1847 }
1848
1849 if (!framebuffers)
1850 return;
1851
1852 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1853
1854 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001855 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001856 framebuffers[i] = name;
1857 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001858 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001859 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001860 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001861 }
1862}
1863
1864
1865
Brian Paul1864c7d2005-02-08 03:46:37 +00001866GLenum GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001867_mesa_CheckFramebufferStatusEXT(GLenum target)
1868{
Brian Paul0bffb112005-11-08 14:45:48 +00001869 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001870 GET_CURRENT_CONTEXT(ctx);
1871
Brian Paule4b23562005-05-04 20:11:35 +00001872 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001873
Brian Paulc6991432011-02-28 18:24:25 -07001874 buffer = get_framebuffer_target(ctx, target);
1875 if (!buffer) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001876 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
Brian Paulc6991432011-02-28 18:24:25 -07001877 return 0;
Brian Paulddc82ee2005-02-05 19:56:45 +00001878 }
1879
Brian Paul36ede892012-01-12 09:17:23 -07001880 if (_mesa_is_winsys_fbo(buffer)) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001881 /* The window system / default framebuffer is always complete */
1882 return GL_FRAMEBUFFER_COMPLETE_EXT;
1883 }
1884
Brian Paul800e5532009-11-02 15:39:39 -07001885 /* No need to flush here */
Brian Paul474f28e2005-10-08 14:41:17 +00001886
Brian Paul72966362009-01-21 16:28:38 -07001887 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
1888 _mesa_test_framebuffer_completeness(ctx, buffer);
1889 }
1890
Brian Paul0bffb112005-11-08 14:45:48 +00001891 return buffer->_Status;
Brian Paulddc82ee2005-02-05 19:56:45 +00001892}
1893
Brian Paul45bd5c42011-12-16 08:44:43 -07001894
Chad Versacebf8ad172011-11-10 10:19:20 -08001895/**
1896 * Replicate the src attachment point. Used by framebuffer_texture() when
1897 * the same texture is attached at GL_DEPTH_ATTACHMENT and
1898 * GL_STENCIL_ATTACHMENT.
1899 */
1900static void
1901reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb,
1902 gl_buffer_index dst,
1903 gl_buffer_index src)
1904{
1905 struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst];
1906 struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src];
Brian Paulddc82ee2005-02-05 19:56:45 +00001907
Chad Versacebf8ad172011-11-10 10:19:20 -08001908 assert(src_att->Texture != NULL);
Brian Paul45bd5c42011-12-16 08:44:43 -07001909 assert(src_att->Renderbuffer != NULL);
Chad Versacebf8ad172011-11-10 10:19:20 -08001910
1911 _mesa_reference_texobj(&dst_att->Texture, src_att->Texture);
1912 _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer);
1913 dst_att->Type = src_att->Type;
1914 dst_att->Complete = src_att->Complete;
1915 dst_att->TextureLevel = src_att->TextureLevel;
1916 dst_att->Zoffset = src_att->Zoffset;
1917}
Brian Paulddc82ee2005-02-05 19:56:45 +00001918
Brian Paul45bd5c42011-12-16 08:44:43 -07001919
Brian Paulddc82ee2005-02-05 19:56:45 +00001920/**
Brian Paul534cbbe2012-03-12 11:03:59 -06001921 * Common code called by glFramebufferTexture1D/2D/3DEXT() and
1922 * glFramebufferTextureLayerEXT().
1923 * Note: glFramebufferTextureLayerEXT() has no textarget parameter so we'll
1924 * get textarget=0 in that case.
Brian Paulddc82ee2005-02-05 19:56:45 +00001925 */
Brian Paulea4fe662006-03-26 05:22:17 +00001926static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001927framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001928 GLenum attachment, GLenum textarget, GLuint texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001929 GLint level, GLint zoffset)
Brian Paulddc82ee2005-02-05 19:56:45 +00001930{
Brian Paul2c6f9112005-02-24 05:47:06 +00001931 struct gl_renderbuffer_attachment *att;
Brian Paulea4fe662006-03-26 05:22:17 +00001932 struct gl_texture_object *texObj = NULL;
1933 struct gl_framebuffer *fb;
Anuj Phogatcc5b0ff2012-03-12 10:39:48 -07001934 GLenum maxLevelsTarget;
Brian Paulddc82ee2005-02-05 19:56:45 +00001935
1936 ASSERT_OUTSIDE_BEGIN_END(ctx);
1937
Brian Paulc6991432011-02-28 18:24:25 -07001938 fb = get_framebuffer_target(ctx, target);
1939 if (!fb) {
Brian Paulea4fe662006-03-26 05:22:17 +00001940 _mesa_error(ctx, GL_INVALID_ENUM,
Brian Paul5fec84a2009-01-29 15:01:09 -07001941 "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
Brian Paulddc82ee2005-02-05 19:56:45 +00001942 return;
Brian Paulea4fe662006-03-26 05:22:17 +00001943 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001944
Brian Paulea4fe662006-03-26 05:22:17 +00001945 /* check framebuffer binding */
Brian Paul36ede892012-01-12 09:17:23 -07001946 if (_mesa_is_winsys_fbo(fb)) {
Brian Paulea4fe662006-03-26 05:22:17 +00001947 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001948 "glFramebufferTexture%sEXT", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001949 return;
1950 }
1951
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001952 /* The textarget, level, and zoffset parameters are only validated if
1953 * texture is non-zero.
1954 */
1955 if (texture) {
1956 GLboolean err = GL_TRUE;
1957
1958 texObj = _mesa_lookup_texture(ctx, texture);
1959 if (texObj != NULL) {
Ian Romanickbb372f12007-05-16 15:34:22 -07001960 if (textarget == 0) {
Brian Paul534cbbe2012-03-12 11:03:59 -06001961 /* If textarget == 0 it means we're being called by
1962 * glFramebufferTextureLayer() and textarget is not used.
1963 * The only legal texture types for that function are 3D and
1964 * 1D/2D arrays textures.
1965 */
Ian Romanickbb372f12007-05-16 15:34:22 -07001966 err = (texObj->Target != GL_TEXTURE_3D) &&
1967 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1968 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1969 }
1970 else {
Brian Paul534cbbe2012-03-12 11:03:59 -06001971 /* Make sure textarget is consistent with the texture's type */
Ian Romanickbb372f12007-05-16 15:34:22 -07001972 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
Brian Paul2efa3d42011-11-18 17:39:00 -07001973 ? !_mesa_is_cube_face(textarget)
Ian Romanickbb372f12007-05-16 15:34:22 -07001974 : (texObj->Target != textarget);
1975 }
Brian Paulea4fe662006-03-26 05:22:17 +00001976 }
Brian Paul7a2e32d2010-03-10 10:54:24 -07001977 else {
1978 /* can't render to a non-existant texture */
1979 _mesa_error(ctx, GL_INVALID_OPERATION,
1980 "glFramebufferTexture%sEXT(non existant texture)",
1981 caller);
1982 return;
1983 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001984
1985 if (err) {
Brian Paulea4fe662006-03-26 05:22:17 +00001986 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001987 "glFramebufferTexture%sEXT(texture target mismatch)",
1988 caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001989 return;
1990 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001991
1992 if (texObj->Target == GL_TEXTURE_3D) {
Brian Paulea4fe662006-03-26 05:22:17 +00001993 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1994 if (zoffset < 0 || zoffset >= maxSize) {
1995 _mesa_error(ctx, GL_INVALID_VALUE,
Ian Romanickbb372f12007-05-16 15:34:22 -07001996 "glFramebufferTexture%sEXT(zoffset)", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001997 return;
1998 }
1999 }
Ian Romanickbb372f12007-05-16 15:34:22 -07002000 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
2001 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
2002 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
2003 _mesa_error(ctx, GL_INVALID_VALUE,
2004 "glFramebufferTexture%sEXT(layer)", caller);
2005 return;
2006 }
2007 }
2008
Anuj Phogatcc5b0ff2012-03-12 10:39:48 -07002009 maxLevelsTarget = textarget ? textarget : texObj->Target;
Brian Paul45bd5c42011-12-16 08:44:43 -07002010 if ((level < 0) ||
Anuj Phogatcc5b0ff2012-03-12 10:39:48 -07002011 (level >= _mesa_max_texture_levels(ctx, maxLevelsTarget))) {
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002012 _mesa_error(ctx, GL_INVALID_VALUE,
2013 "glFramebufferTexture%sEXT(level)", caller);
2014 return;
2015 }
Brian Paulea4fe662006-03-26 05:22:17 +00002016 }
2017
2018 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00002019 if (att == NULL) {
2020 _mesa_error(ctx, GL_INVALID_ENUM,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002021 "glFramebufferTexture%sEXT(attachment)", caller);
Brian Paul3deaa012005-02-07 05:08:24 +00002022 return;
2023 }
2024
Brian Paul800e5532009-11-02 15:39:39 -07002025 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paul474f28e2005-10-08 14:41:17 +00002026
Brian Paulea4fe662006-03-26 05:22:17 +00002027 _glthread_LOCK_MUTEX(fb->Mutex);
2028 if (texObj) {
Chad Versacebf8ad172011-11-10 10:19:20 -08002029 if (attachment == GL_DEPTH_ATTACHMENT &&
Paul Berryb9819a02012-04-13 21:50:08 -07002030 texObj == fb->Attachment[BUFFER_STENCIL].Texture &&
2031 level == fb->Attachment[BUFFER_STENCIL].TextureLevel &&
2032 _mesa_tex_target_to_face(textarget) ==
2033 fb->Attachment[BUFFER_STENCIL].CubeMapFace &&
2034 zoffset == fb->Attachment[BUFFER_STENCIL].Zoffset) {
Chad Versacebf8ad172011-11-10 10:19:20 -08002035 /* The texture object is already attached to the stencil attachment
2036 * point. Don't create a new renderbuffer; just reuse the stencil
2037 * attachment's. This is required to prevent a GL error in
2038 * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL).
2039 */
2040 reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH,
2041 BUFFER_STENCIL);
2042 } else if (attachment == GL_STENCIL_ATTACHMENT &&
Paul Berryb9819a02012-04-13 21:50:08 -07002043 texObj == fb->Attachment[BUFFER_DEPTH].Texture &&
2044 level == fb->Attachment[BUFFER_DEPTH].TextureLevel &&
2045 _mesa_tex_target_to_face(textarget) ==
2046 fb->Attachment[BUFFER_DEPTH].CubeMapFace &&
2047 zoffset == fb->Attachment[BUFFER_DEPTH].Zoffset) {
2048 /* As above, but with depth and stencil transposed. */
Chad Versacebf8ad172011-11-10 10:19:20 -08002049 reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL,
2050 BUFFER_DEPTH);
2051 } else {
2052 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
2053 level, zoffset);
2054 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2055 /* Above we created a new renderbuffer and attached it to the
2056 * depth attachment point. Now attach it to the stencil attachment
2057 * point too.
2058 */
2059 assert(att == &fb->Attachment[BUFFER_DEPTH]);
2060 reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL,
2061 BUFFER_DEPTH);
2062 }
2063 }
2064
Brian Paul2897cee2009-01-29 09:20:18 -07002065 /* Set the render-to-texture flag. We'll check this flag in
2066 * glTexImage() and friends to determine if we need to revalidate
2067 * any FBOs that might be rendering into this texture.
2068 * This flag never gets cleared since it's non-trivial to determine
2069 * when all FBOs might be done rendering to this texture. That's OK
2070 * though since it's uncommon to render to a texture then repeatedly
2071 * call glTexImage() to change images in the texture.
2072 */
2073 texObj->_RenderToTexture = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +00002074 }
2075 else {
Brian Paul519b23b2006-03-20 18:51:57 +00002076 _mesa_remove_attachment(ctx, att);
Chad Versacebf8ad172011-11-10 10:19:20 -08002077 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2078 assert(att == &fb->Attachment[BUFFER_DEPTH]);
2079 _mesa_remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]);
2080 }
Brian Paul3deaa012005-02-07 05:08:24 +00002081 }
Brian Paul72966362009-01-21 16:28:38 -07002082
2083 invalidate_framebuffer(fb);
2084
Brian Paulea4fe662006-03-26 05:22:17 +00002085 _glthread_UNLOCK_MUTEX(fb->Mutex);
2086}
2087
2088
2089
2090void GLAPIENTRY
2091_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
2092 GLenum textarget, GLuint texture, GLint level)
2093{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002094 GET_CURRENT_CONTEXT(ctx);
2095
Brian Paul352cab42011-08-18 14:35:27 -06002096 if (texture != 0) {
2097 GLboolean error;
2098
2099 switch (textarget) {
2100 case GL_TEXTURE_1D:
2101 error = GL_FALSE;
2102 break;
Brian Paul3e9dc512011-08-18 15:59:33 -06002103 case GL_TEXTURE_1D_ARRAY:
2104 error = !ctx->Extensions.EXT_texture_array;
2105 break;
Brian Paul352cab42011-08-18 14:35:27 -06002106 default:
2107 error = GL_TRUE;
2108 }
2109
2110 if (error) {
2111 _mesa_error(ctx, GL_INVALID_OPERATION,
2112 "glFramebufferTexture1DEXT(textarget=%s)",
2113 _mesa_lookup_enum_by_nr(textarget));
2114 return;
2115 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002116 }
2117
2118 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
2119 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00002120}
2121
2122
Brian Paul1864c7d2005-02-08 03:46:37 +00002123void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002124_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
2125 GLenum textarget, GLuint texture, GLint level)
2126{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002127 GET_CURRENT_CONTEXT(ctx);
2128
Brian Paul352cab42011-08-18 14:35:27 -06002129 if (texture != 0) {
2130 GLboolean error;
2131
2132 switch (textarget) {
2133 case GL_TEXTURE_2D:
2134 error = GL_FALSE;
2135 break;
2136 case GL_TEXTURE_RECTANGLE:
2137 error = !ctx->Extensions.NV_texture_rectangle;
2138 break;
2139 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2140 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2141 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2142 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2143 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2144 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2145 error = !ctx->Extensions.ARB_texture_cube_map;
2146 break;
Brian Paul3e9dc512011-08-18 15:59:33 -06002147 case GL_TEXTURE_2D_ARRAY:
2148 error = !ctx->Extensions.EXT_texture_array;
2149 break;
Brian Paul352cab42011-08-18 14:35:27 -06002150 default:
Chia-I Wud8ba30a2011-10-22 22:17:31 +08002151 error = GL_TRUE;
Brian Paul352cab42011-08-18 14:35:27 -06002152 }
2153
2154 if (error) {
2155 _mesa_error(ctx, GL_INVALID_OPERATION,
2156 "glFramebufferTexture2DEXT(textarget=%s)",
2157 _mesa_lookup_enum_by_nr(textarget));
2158 return;
2159 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002160 }
2161
2162 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
2163 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00002164}
2165
2166
Brian Paul1864c7d2005-02-08 03:46:37 +00002167void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002168_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
2169 GLenum textarget, GLuint texture,
2170 GLint level, GLint zoffset)
2171{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002172 GET_CURRENT_CONTEXT(ctx);
2173
2174 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
Brian Paulccecc082011-08-18 11:51:48 -06002175 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002176 "glFramebufferTexture3DEXT(textarget)");
2177 return;
2178 }
2179
2180 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
Brian Paulea4fe662006-03-26 05:22:17 +00002181 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00002182}
2183
2184
Brian Paul1864c7d2005-02-08 03:46:37 +00002185void GLAPIENTRY
Ian Romanickbb372f12007-05-16 15:34:22 -07002186_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
2187 GLuint texture, GLint level, GLint layer)
2188{
2189 GET_CURRENT_CONTEXT(ctx);
2190
2191 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
2192 level, layer);
2193}
2194
2195
2196void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002197_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
2198 GLenum renderbufferTarget,
2199 GLuint renderbuffer)
2200{
Brian Paul2c6f9112005-02-24 05:47:06 +00002201 struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00002202 struct gl_framebuffer *fb;
Brian Paule4b23562005-05-04 20:11:35 +00002203 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00002204 GET_CURRENT_CONTEXT(ctx);
2205
2206 ASSERT_OUTSIDE_BEGIN_END(ctx);
2207
Brian Paulc6991432011-02-28 18:24:25 -07002208 fb = get_framebuffer_target(ctx, target);
2209 if (!fb) {
2210 _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +00002211 return;
2212 }
2213
Brian Paul3deaa012005-02-07 05:08:24 +00002214 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
Brian Paule4b23562005-05-04 20:11:35 +00002215 _mesa_error(ctx, GL_INVALID_ENUM,
2216 "glFramebufferRenderbufferEXT(renderbufferTarget)");
Brian Paul3deaa012005-02-07 05:08:24 +00002217 return;
2218 }
2219
Brian Paul36ede892012-01-12 09:17:23 -07002220 if (_mesa_is_winsys_fbo(fb)) {
Brian Paulab8ef282005-09-07 23:21:59 +00002221 /* Can't attach new renderbuffers to a window system framebuffer */
Brian Paul3deaa012005-02-07 05:08:24 +00002222 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
2223 return;
2224 }
2225
Brian Paul84716042005-11-16 04:05:54 +00002226 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00002227 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00002228 _mesa_error(ctx, GL_INVALID_ENUM,
Brian Paul9b50cea2009-10-23 11:34:14 -06002229 "glFramebufferRenderbufferEXT(invalid attachment %s)",
2230 _mesa_lookup_enum_by_nr(attachment));
Brian Paulddc82ee2005-02-05 19:56:45 +00002231 return;
2232 }
2233
Brian Paul1864c7d2005-02-08 03:46:37 +00002234 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00002235 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00002236 if (!rb) {
Brian Paule4b23562005-05-04 20:11:35 +00002237 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul9b50cea2009-10-23 11:34:14 -06002238 "glFramebufferRenderbufferEXT(non-existant"
2239 " renderbuffer %u)", renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00002240 return;
2241 }
Brian Pauldd973cd2011-01-12 18:14:14 -07002242 else if (rb == &DummyRenderbuffer) {
2243 /* This is what NVIDIA does */
2244 _mesa_error(ctx, GL_INVALID_VALUE,
2245 "glFramebufferRenderbufferEXT(renderbuffer %u)",
2246 renderbuffer);
2247 return;
2248 }
Brian Paul1864c7d2005-02-08 03:46:37 +00002249 }
2250 else {
Brian Paule4b23562005-05-04 20:11:35 +00002251 /* remove renderbuffer attachment */
2252 rb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00002253 }
Brian Paule4b23562005-05-04 20:11:35 +00002254
Brian Paula504f232010-05-27 13:05:23 -06002255 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
2256 rb && rb->Format != MESA_FORMAT_NONE) {
Brian Paul30590072009-01-21 11:06:11 -07002257 /* make sure the renderbuffer is a depth/stencil format */
Brian Paula504f232010-05-27 13:05:23 -06002258 const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
Brian Paul45e76d22009-10-08 20:27:27 -06002259 if (baseFormat != GL_DEPTH_STENCIL) {
Brian Paul30590072009-01-21 11:06:11 -07002260 _mesa_error(ctx, GL_INVALID_OPERATION,
2261 "glFramebufferRenderbufferEXT(renderbuffer"
2262 " is not DEPTH_STENCIL format)");
2263 return;
2264 }
2265 }
2266
2267
Brian Paul800e5532009-11-02 15:39:39 -07002268 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paul474f28e2005-10-08 14:41:17 +00002269
Brian Paule4b23562005-05-04 20:11:35 +00002270 assert(ctx->Driver.FramebufferRenderbuffer);
Brian Paul84716042005-11-16 04:05:54 +00002271 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
Brian Paul2e019182006-03-07 01:43:52 +00002272
2273 /* Some subsequent GL commands may depend on the framebuffer's visual
2274 * after the binding is updated. Update visual info now.
2275 */
Eric Anholt059cca92011-01-02 17:58:07 -08002276 _mesa_update_framebuffer_visual(ctx, fb);
Brian Paulddc82ee2005-02-05 19:56:45 +00002277}
2278
2279
Brian Paul1864c7d2005-02-08 03:46:37 +00002280void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002281_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
2282 GLenum pname, GLint *params)
2283{
Brian Paul2c6f9112005-02-24 05:47:06 +00002284 const struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00002285 struct gl_framebuffer *buffer;
Marek Olšák000896c2011-07-19 03:05:07 +02002286 GLenum err;
Brian Paulddc82ee2005-02-05 19:56:45 +00002287 GET_CURRENT_CONTEXT(ctx);
2288
2289 ASSERT_OUTSIDE_BEGIN_END(ctx);
2290
Brian Pauldbe88512012-02-10 16:22:33 -07002291 /* The error differs in GL and GLES. */
Marek Olšák000896c2011-07-19 03:05:07 +02002292 err = ctx->API == API_OPENGL ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
2293
Brian Paulc6991432011-02-28 18:24:25 -07002294 buffer = get_framebuffer_target(ctx, target);
2295 if (!buffer) {
Brian Paulddc82ee2005-02-05 19:56:45 +00002296 _mesa_error(ctx, GL_INVALID_ENUM,
2297 "glGetFramebufferAttachmentParameterivEXT(target)");
2298 return;
2299 }
2300
Brian Paul36ede892012-01-12 09:17:23 -07002301 if (_mesa_is_winsys_fbo(buffer)) {
Ian Romanickda2e41c2011-10-03 12:04:09 -07002302 /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec
2303 * says:
2304 *
2305 * "If the framebuffer currently bound to target is zero, then
2306 * INVALID_OPERATION is generated."
2307 *
2308 * The EXT_framebuffer_object spec has the same wording, and the
2309 * OES_framebuffer_object spec refers to the EXT_framebuffer_object
2310 * spec.
2311 */
2312 if (ctx->API != API_OPENGL || !ctx->Extensions.ARB_framebuffer_object) {
2313 _mesa_error(ctx, GL_INVALID_OPERATION,
2314 "glGetFramebufferAttachmentParameteriv(bound FBO = 0)");
2315 return;
2316 }
Brian Paul61ec2052010-06-22 08:37:44 -06002317 /* the default / window-system FBO */
2318 att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
2319 }
2320 else {
2321 /* user-created framebuffer FBO */
2322 att = _mesa_get_attachment(ctx, buffer, attachment);
2323 }
2324
Brian Paul3deaa012005-02-07 05:08:24 +00002325 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00002326 _mesa_error(ctx, GL_INVALID_ENUM,
2327 "glGetFramebufferAttachmentParameterivEXT(attachment)");
2328 return;
2329 }
2330
Brian Paul30590072009-01-21 11:06:11 -07002331 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2332 /* the depth and stencil attachments must point to the same buffer */
2333 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
2334 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
2335 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
2336 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
2337 _mesa_error(ctx, GL_INVALID_OPERATION,
2338 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
2339 " attachments differ)");
2340 return;
2341 }
2342 }
2343
Brian Paul800e5532009-11-02 15:39:39 -07002344 /* No need to flush here */
Brian Paul474f28e2005-10-08 14:41:17 +00002345
Brian Paulddc82ee2005-02-05 19:56:45 +00002346 switch (pname) {
2347 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
Brian Paul36ede892012-01-12 09:17:23 -07002348 *params = _mesa_is_winsys_fbo(buffer)
2349 ? GL_FRAMEBUFFER_DEFAULT : att->Type;
Brian Paul3deaa012005-02-07 05:08:24 +00002350 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002351 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002352 if (att->Type == GL_RENDERBUFFER_EXT) {
2353 *params = att->Renderbuffer->Name;
2354 }
2355 else if (att->Type == GL_TEXTURE) {
2356 *params = att->Texture->Name;
2357 }
2358 else {
Brian Paul20cf1852010-12-03 08:23:31 -07002359 assert(att->Type == GL_NONE);
Marek Olšák000896c2011-07-19 03:05:07 +02002360 if (ctx->API == API_OPENGL) {
2361 *params = 0;
2362 } else {
2363 _mesa_error(ctx, GL_INVALID_ENUM,
2364 "glGetFramebufferAttachmentParameterivEXT(pname)");
2365 }
Brian Paul3deaa012005-02-07 05:08:24 +00002366 }
2367 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002368 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002369 if (att->Type == GL_TEXTURE) {
2370 *params = att->TextureLevel;
2371 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002372 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002373 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002374 "glGetFramebufferAttachmentParameterivEXT(pname)");
2375 }
Brian Paul3deaa012005-02-07 05:08:24 +00002376 else {
2377 _mesa_error(ctx, GL_INVALID_ENUM,
2378 "glGetFramebufferAttachmentParameterivEXT(pname)");
2379 }
2380 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002381 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002382 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06002383 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
2384 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
2385 }
2386 else {
2387 *params = 0;
2388 }
Brian Paul3deaa012005-02-07 05:08:24 +00002389 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002390 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002391 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002392 "glGetFramebufferAttachmentParameterivEXT(pname)");
2393 }
Brian Paul3deaa012005-02-07 05:08:24 +00002394 else {
2395 _mesa_error(ctx, GL_INVALID_ENUM,
2396 "glGetFramebufferAttachmentParameterivEXT(pname)");
2397 }
2398 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002399 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002400 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06002401 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2402 *params = att->Zoffset;
2403 }
2404 else {
2405 *params = 0;
2406 }
Brian Paul3deaa012005-02-07 05:08:24 +00002407 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002408 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002409 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002410 "glGetFramebufferAttachmentParameterivEXT(pname)");
2411 }
Brian Paul3deaa012005-02-07 05:08:24 +00002412 else {
2413 _mesa_error(ctx, GL_INVALID_ENUM,
2414 "glGetFramebufferAttachmentParameterivEXT(pname)");
2415 }
2416 return;
Brian Paul1bc59bf2009-01-22 15:07:34 -07002417 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2418 if (!ctx->Extensions.ARB_framebuffer_object) {
2419 _mesa_error(ctx, GL_INVALID_ENUM,
2420 "glGetFramebufferAttachmentParameterivEXT(pname)");
2421 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002422 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002423 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002424 "glGetFramebufferAttachmentParameterivEXT(pname)");
2425 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002426 else {
Marek Olšák69c8f462012-01-24 23:39:31 +01002427 if (ctx->Extensions.EXT_framebuffer_sRGB) {
Marek Olšák81ae8c62011-01-23 13:26:43 +01002428 *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
2429 }
2430 else {
2431 /* According to ARB_framebuffer_sRGB, we should return LINEAR
2432 * if the sRGB conversion is unsupported. */
2433 *params = GL_LINEAR;
2434 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002435 }
2436 return;
2437 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2438 if (!ctx->Extensions.ARB_framebuffer_object) {
2439 _mesa_error(ctx, GL_INVALID_ENUM,
2440 "glGetFramebufferAttachmentParameterivEXT(pname)");
2441 return;
2442 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002443 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002444 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002445 "glGetFramebufferAttachmentParameterivEXT(pname)");
2446 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002447 else {
Brian Paul45e76d22009-10-08 20:27:27 -06002448 gl_format format = att->Renderbuffer->Format;
Ian Romanick55d232a2011-08-26 12:20:00 -07002449 if (format == MESA_FORMAT_S8) {
Brian Paul45e76d22009-10-08 20:27:27 -06002450 /* special cases */
2451 *params = GL_INDEX;
2452 }
Marek Olšák11652802011-06-01 15:48:51 +02002453 else if (format == MESA_FORMAT_Z32_FLOAT_X24S8) {
2454 /* depends on the attachment parameter */
2455 if (attachment == GL_STENCIL_ATTACHMENT) {
2456 *params = GL_INDEX;
2457 }
2458 else {
2459 *params = GL_FLOAT;
2460 }
2461 }
Brian Paul45e76d22009-10-08 20:27:27 -06002462 else {
2463 *params = _mesa_get_format_datatype(format);
2464 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002465 }
2466 return;
2467 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002468 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002469 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002470 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002471 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002472 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2473 if (!ctx->Extensions.ARB_framebuffer_object) {
2474 _mesa_error(ctx, GL_INVALID_ENUM,
2475 "glGetFramebufferAttachmentParameterivEXT(pname)");
2476 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002477 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002478 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002479 "glGetFramebufferAttachmentParameterivEXT(pname)");
2480 }
Brian Paul45e76d22009-10-08 20:27:27 -06002481 else if (att->Texture) {
2482 const struct gl_texture_image *texImage =
2483 _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
2484 att->TextureLevel);
2485 if (texImage) {
2486 *params = get_component_bits(pname, texImage->_BaseFormat,
2487 texImage->TexFormat);
2488 }
2489 else {
2490 *params = 0;
2491 }
2492 }
2493 else if (att->Renderbuffer) {
2494 *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
2495 att->Renderbuffer->Format);
2496 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002497 else {
Marek Olšákb9e9df72011-05-31 20:36:07 +02002498 _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:"
2499 " invalid FBO attachment structure");
Brian Paul1bc59bf2009-01-22 15:07:34 -07002500 }
2501 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002502 default:
2503 _mesa_error(ctx, GL_INVALID_ENUM,
2504 "glGetFramebufferAttachmentParameterivEXT(pname)");
2505 return;
2506 }
Brian Paulddc82ee2005-02-05 19:56:45 +00002507}
2508
2509
Brian Paul1864c7d2005-02-08 03:46:37 +00002510void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002511_mesa_GenerateMipmapEXT(GLenum target)
2512{
Eric Anholtf80e1e72011-10-18 11:52:39 -07002513 struct gl_texture_image *srcImage;
Brian Paul463642c2005-02-08 02:06:00 +00002514 struct gl_texture_object *texObj;
Brian Paul3e9dc512011-08-18 15:59:33 -06002515 GLboolean error;
2516
Brian Paulddc82ee2005-02-05 19:56:45 +00002517 GET_CURRENT_CONTEXT(ctx);
2518
2519 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00002520 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00002521
2522 switch (target) {
2523 case GL_TEXTURE_1D:
2524 case GL_TEXTURE_2D:
Brian Paulddc82ee2005-02-05 19:56:45 +00002525 case GL_TEXTURE_3D:
Brian Paul3e9dc512011-08-18 15:59:33 -06002526 error = GL_FALSE;
2527 break;
Brian Paul463642c2005-02-08 02:06:00 +00002528 case GL_TEXTURE_CUBE_MAP:
Brian Paul3e9dc512011-08-18 15:59:33 -06002529 error = !ctx->Extensions.ARB_texture_cube_map;
2530 break;
2531 case GL_TEXTURE_1D_ARRAY:
2532 case GL_TEXTURE_2D_ARRAY:
2533 error = !ctx->Extensions.EXT_texture_array;
Brian Paulddc82ee2005-02-05 19:56:45 +00002534 break;
2535 default:
Brian Paul3e9dc512011-08-18 15:59:33 -06002536 error = GL_TRUE;
2537 }
2538
2539 if (error) {
2540 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target=%s)",
2541 _mesa_lookup_enum_by_nr(target));
Brian Paulddc82ee2005-02-05 19:56:45 +00002542 return;
2543 }
2544
Brian Paula7193952009-11-16 08:21:28 -07002545 texObj = _mesa_get_current_tex_object(ctx, target);
Brian Paul463642c2005-02-08 02:06:00 +00002546
Brian Paul652828e2009-11-16 08:25:17 -07002547 if (texObj->BaseLevel >= texObj->MaxLevel) {
2548 /* nothing to do */
2549 return;
2550 }
2551
Brian Paulecb7cc32010-12-06 15:11:41 -07002552 if (texObj->Target == GL_TEXTURE_CUBE_MAP &&
2553 !_mesa_cube_complete(texObj)) {
2554 _mesa_error(ctx, GL_INVALID_OPERATION,
2555 "glGenerateMipmap(incomplete cube map)");
2556 return;
2557 }
2558
Keith Whitwell5ac93f82006-11-01 14:21:57 +00002559 _mesa_lock_texture(ctx, texObj);
Eric Anholtf80e1e72011-10-18 11:52:39 -07002560
2561 srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel);
2562 if (!srcImage) {
2563 _mesa_unlock_texture(ctx, texObj);
2564 return;
2565 }
2566
Eric Anholtf849d362008-12-06 21:14:56 -08002567 if (target == GL_TEXTURE_CUBE_MAP) {
Brian Paulef6ee072009-09-15 18:09:03 -06002568 GLuint face;
Eric Anholtf849d362008-12-06 21:14:56 -08002569 for (face = 0; face < 6; face++)
2570 ctx->Driver.GenerateMipmap(ctx,
2571 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2572 texObj);
Brian Paulef6ee072009-09-15 18:09:03 -06002573 }
2574 else {
Eric Anholtf849d362008-12-06 21:14:56 -08002575 ctx->Driver.GenerateMipmap(ctx, target, texObj);
2576 }
Keith Whitwell5ac93f82006-11-01 14:21:57 +00002577 _mesa_unlock_texture(ctx, texObj);
Brian Paulddc82ee2005-02-05 19:56:45 +00002578}
Brian Paul0bffb112005-11-08 14:45:48 +00002579
2580
2581#if FEATURE_EXT_framebuffer_blit
Brian Paul21f8d312009-10-27 16:59:23 -06002582
2583static const struct gl_renderbuffer_attachment *
Brian Paulb3cfcdf2011-01-28 20:25:26 -07002584find_attachment(const struct gl_framebuffer *fb,
2585 const struct gl_renderbuffer *rb)
Brian Paul21f8d312009-10-27 16:59:23 -06002586{
2587 GLuint i;
2588 for (i = 0; i < Elements(fb->Attachment); i++) {
2589 if (fb->Attachment[i].Renderbuffer == rb)
2590 return &fb->Attachment[i];
2591 }
2592 return NULL;
2593}
2594
2595
Brian Paul9b111702012-01-09 12:38:49 -07002596/**
2597 * Helper function for checking if the datatypes of color buffers are
2598 * compatible for glBlitFramebuffer. From the 3.1 spec, page 198:
2599 *
2600 * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT
2601 * and any of the following conditions hold:
2602 * - The read buffer contains fixed-point or floating-point values and any
2603 * draw buffer contains neither fixed-point nor floating-point values.
2604 * - The read buffer contains unsigned integer values and any draw buffer
2605 * does not contain unsigned integer values.
2606 * - The read buffer contains signed integer values and any draw buffer
2607 * does not contain signed integer values."
2608 */
2609static GLboolean
2610compatible_color_datatypes(gl_format srcFormat, gl_format dstFormat)
2611{
2612 GLenum srcType = _mesa_get_format_datatype(srcFormat);
2613 GLenum dstType = _mesa_get_format_datatype(dstFormat);
2614
2615 if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) {
2616 assert(srcType == GL_UNSIGNED_NORMALIZED ||
2617 srcType == GL_SIGNED_NORMALIZED ||
2618 srcType == GL_FLOAT);
2619 /* Boil any of those types down to GL_FLOAT */
2620 srcType = GL_FLOAT;
2621 }
2622
2623 if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) {
2624 assert(dstType == GL_UNSIGNED_NORMALIZED ||
2625 dstType == GL_SIGNED_NORMALIZED ||
2626 dstType == GL_FLOAT);
2627 /* Boil any of those types down to GL_FLOAT */
2628 dstType = GL_FLOAT;
2629 }
2630
2631 return srcType == dstType;
2632}
2633
Brian Paul21f8d312009-10-27 16:59:23 -06002634
Brian Paul722d9762009-01-20 16:58:49 -07002635/**
Marek Olšák59272272012-07-21 15:16:15 +02002636 * Return the equivalent non-generic internal format.
2637 * This is useful for comparing whether two internal formats are semantically
2638 * equivalent.
2639 */
2640static GLenum
2641get_nongeneric_internalformat(GLenum format)
2642{
2643 switch (format) {
2644 /* GL 1.1 formats. */
2645 case 4:
2646 case GL_RGBA:
2647 return GL_RGBA8;
2648
2649 case 3:
2650 case GL_RGB:
2651 return GL_RGB8;
2652
2653 case 2:
2654 case GL_LUMINANCE_ALPHA:
2655 return GL_LUMINANCE8_ALPHA8;
2656
2657 case 1:
2658 case GL_LUMINANCE:
2659 return GL_LUMINANCE8;
2660
2661 case GL_ALPHA:
2662 return GL_ALPHA8;
2663
2664 case GL_INTENSITY:
2665 return GL_INTENSITY8;
2666
2667 /* GL_ARB_texture_rg */
2668 case GL_RED:
2669 return GL_R8;
2670
2671 case GL_RG:
2672 return GL_RG8;
2673
2674 /* GL_EXT_texture_sRGB */
2675 case GL_SRGB:
2676 return GL_SRGB8;
2677
2678 case GL_SRGB_ALPHA:
2679 return GL_SRGB8_ALPHA8;
2680
2681 case GL_SLUMINANCE:
2682 return GL_SLUMINANCE8;
2683
2684 case GL_SLUMINANCE_ALPHA:
2685 return GL_SLUMINANCE8_ALPHA8;
2686
2687 /* GL_EXT_texture_snorm */
2688 case GL_RGBA_SNORM:
2689 return GL_RGBA8_SNORM;
2690
2691 case GL_RGB_SNORM:
2692 return GL_RGB8_SNORM;
2693
2694 case GL_RG_SNORM:
2695 return GL_RG8_SNORM;
2696
2697 case GL_RED_SNORM:
2698 return GL_R8_SNORM;
2699
2700 case GL_LUMINANCE_ALPHA_SNORM:
2701 return GL_LUMINANCE8_ALPHA8_SNORM;
2702
2703 case GL_LUMINANCE_SNORM:
2704 return GL_LUMINANCE8_SNORM;
2705
2706 case GL_ALPHA_SNORM:
2707 return GL_ALPHA8_SNORM;
2708
2709 case GL_INTENSITY_SNORM:
2710 return GL_INTENSITY8_SNORM;
2711
2712 default:
2713 return format;
2714 }
2715}
2716
2717
2718static GLboolean
2719compatible_resolve_formats(const struct gl_renderbuffer *colorReadRb,
2720 const struct gl_renderbuffer *colorDrawRb)
2721{
2722 /* The simple case where we know the backing formats are the same.
2723 */
2724 if (colorReadRb->Format == colorDrawRb->Format) {
2725 return GL_TRUE;
2726 }
2727
2728 /* The Mesa formats are different, so we must check whether the internal
2729 * formats are compatible.
2730 *
2731 * Under some circumstances, the user may request e.g. two GL_RGBA8
2732 * textures and get two entirely different Mesa formats like RGBA8888 and
2733 * ARGB8888. Drivers behaving like that should be able to cope with
2734 * non-matching formats by themselves, because it's not the user's fault.
2735 */
2736 if (get_nongeneric_internalformat(colorReadRb->InternalFormat) ==
2737 get_nongeneric_internalformat(colorDrawRb->InternalFormat)) {
2738 return GL_TRUE;
2739 }
2740
2741 return GL_FALSE;
2742}
2743
2744
2745/**
Brian Paul722d9762009-01-20 16:58:49 -07002746 * Blit rectangular region, optionally from one framebuffer to another.
2747 *
2748 * Note, if the src buffer is multisampled and the dest is not, this is
2749 * when the samples must be resolved to a single color.
2750 */
Brian Paul0bffb112005-11-08 14:45:48 +00002751void GLAPIENTRY
2752_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
2753 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
2754 GLbitfield mask, GLenum filter)
2755{
Brian Paul722d9762009-01-20 16:58:49 -07002756 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
2757 GL_DEPTH_BUFFER_BIT |
2758 GL_STENCIL_BUFFER_BIT);
2759 const struct gl_framebuffer *readFb, *drawFb;
2760 const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
Brian Paul0bffb112005-11-08 14:45:48 +00002761 GET_CURRENT_CONTEXT(ctx);
2762
2763 ASSERT_OUTSIDE_BEGIN_END(ctx);
2764 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2765
Brian Paul6364d752011-02-18 09:53:29 -07002766 if (MESA_VERBOSE & VERBOSE_API)
2767 _mesa_debug(ctx,
2768 "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n",
2769 srcX0, srcY0, srcX1, srcY1,
2770 dstX0, dstY0, dstX1, dstY1,
2771 mask, _mesa_lookup_enum_by_nr(filter));
2772
Brian Paul99745402006-03-01 02:02:43 +00002773 if (ctx->NewState) {
2774 _mesa_update_state(ctx);
2775 }
2776
Brian Paul722d9762009-01-20 16:58:49 -07002777 readFb = ctx->ReadBuffer;
2778 drawFb = ctx->DrawBuffer;
2779
2780 if (!readFb || !drawFb) {
2781 /* This will normally never happen but someday we may want to
2782 * support MakeCurrent() with no drawables.
2783 */
2784 return;
Brian Paul99745402006-03-01 02:02:43 +00002785 }
2786
Brian Paul0bffb112005-11-08 14:45:48 +00002787 /* check for complete framebuffers */
Brian Paul722d9762009-01-20 16:58:49 -07002788 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
2789 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
Brian Paul0bffb112005-11-08 14:45:48 +00002790 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
2791 "glBlitFramebufferEXT(incomplete draw/read buffers)");
2792 return;
2793 }
2794
Brian Paul99745402006-03-01 02:02:43 +00002795 if (filter != GL_NEAREST && filter != GL_LINEAR) {
2796 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
2797 return;
2798 }
2799
Brian Paul722d9762009-01-20 16:58:49 -07002800 if (mask & ~legalMaskBits) {
Brian Paul99745402006-03-01 02:02:43 +00002801 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
2802 return;
2803 }
2804
Brian Paul0bffb112005-11-08 14:45:48 +00002805 /* depth/stencil must be blitted with nearest filtering */
2806 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
2807 && filter != GL_NEAREST) {
2808 _mesa_error(ctx, GL_INVALID_OPERATION,
Vinson Lee4f94e0b2011-03-28 20:32:01 -07002809 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)");
Brian Paul0bffb112005-11-08 14:45:48 +00002810 return;
2811 }
2812
Brian Paul722d9762009-01-20 16:58:49 -07002813 /* get color read/draw renderbuffers */
2814 if (mask & GL_COLOR_BUFFER_BIT) {
2815 colorReadRb = readFb->_ColorReadBuffer;
2816 colorDrawRb = drawFb->_ColorDrawBuffers[0];
Ian Romanickbb475862011-06-07 12:38:39 -07002817
2818 /* From the EXT_framebuffer_object spec:
2819 *
2820 * "If a buffer is specified in <mask> and does not exist in both
2821 * the read and draw framebuffers, the corresponding bit is silently
2822 * ignored."
2823 */
2824 if ((colorReadRb == NULL) || (colorDrawRb == NULL)) {
2825 colorReadRb = colorDrawRb = NULL;
2826 mask &= ~GL_COLOR_BUFFER_BIT;
2827 }
Brian Paul9b111702012-01-09 12:38:49 -07002828 else if (!compatible_color_datatypes(colorReadRb->Format,
2829 colorDrawRb->Format)) {
2830 _mesa_error(ctx, GL_INVALID_OPERATION,
2831 "glBlitFramebufferEXT(color buffer datatypes mismatch)");
2832 return;
2833 }
Brian Paul722d9762009-01-20 16:58:49 -07002834 }
2835 else {
2836 colorReadRb = colorDrawRb = NULL;
2837 }
2838
Brian Paul99745402006-03-01 02:02:43 +00002839 if (mask & GL_STENCIL_BUFFER_BIT) {
Brian Pauld1240922011-12-10 11:44:43 -07002840 struct gl_renderbuffer *readRb =
2841 readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
2842 struct gl_renderbuffer *drawRb =
2843 drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;
Ian Romanickbb475862011-06-07 12:38:39 -07002844
2845 /* From the EXT_framebuffer_object spec:
2846 *
2847 * "If a buffer is specified in <mask> and does not exist in both
2848 * the read and draw framebuffers, the corresponding bit is silently
2849 * ignored."
2850 */
2851 if ((readRb == NULL) || (drawRb == NULL)) {
Ian Romanickbb475862011-06-07 12:38:39 -07002852 mask &= ~GL_STENCIL_BUFFER_BIT;
2853 }
Chad Versacef74d8aa2012-01-17 12:01:34 -08002854 else if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
2855 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
2856 /* There is no need to check the stencil datatype here, because
2857 * there is only one: GL_UNSIGNED_INT.
2858 */
Brian Paul99745402006-03-01 02:02:43 +00002859 _mesa_error(ctx, GL_INVALID_OPERATION,
Chad Versacef74d8aa2012-01-17 12:01:34 -08002860 "glBlitFramebufferEXT(stencil buffer size mismatch)");
Brian Paul99745402006-03-01 02:02:43 +00002861 return;
2862 }
2863 }
2864
2865 if (mask & GL_DEPTH_BUFFER_BIT) {
Brian Pauld1240922011-12-10 11:44:43 -07002866 struct gl_renderbuffer *readRb =
2867 readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
2868 struct gl_renderbuffer *drawRb =
2869 drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
Ian Romanickbb475862011-06-07 12:38:39 -07002870
2871 /* From the EXT_framebuffer_object spec:
2872 *
2873 * "If a buffer is specified in <mask> and does not exist in both
2874 * the read and draw framebuffers, the corresponding bit is silently
2875 * ignored."
2876 */
2877 if ((readRb == NULL) || (drawRb == NULL)) {
Ian Romanickbb475862011-06-07 12:38:39 -07002878 mask &= ~GL_DEPTH_BUFFER_BIT;
2879 }
Chad Versacef74d8aa2012-01-17 12:01:34 -08002880 else if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
2881 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
2882 (_mesa_get_format_datatype(readRb->Format) !=
2883 _mesa_get_format_datatype(drawRb->Format))) {
Brian Paul99745402006-03-01 02:02:43 +00002884 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul3f1fab02012-01-09 08:11:33 -07002885 "glBlitFramebufferEXT(depth buffer format mismatch)");
Brian Paul99745402006-03-01 02:02:43 +00002886 return;
2887 }
Brian Paul0bffb112005-11-08 14:45:48 +00002888 }
2889
Brian Paul722d9762009-01-20 16:58:49 -07002890 if (readFb->Visual.samples > 0 &&
2891 drawFb->Visual.samples > 0 &&
2892 readFb->Visual.samples != drawFb->Visual.samples) {
2893 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paulb87b8572012-01-09 08:11:33 -07002894 "glBlitFramebufferEXT(mismatched samples)");
Brian Paul722d9762009-01-20 16:58:49 -07002895 return;
2896 }
2897
2898 /* extra checks for multisample copies... */
2899 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
2900 /* src and dest region sizes must be the same */
2901 if (srcX1 - srcX0 != dstX1 - dstX0 ||
2902 srcY1 - srcY0 != dstY1 - dstY0) {
2903 _mesa_error(ctx, GL_INVALID_OPERATION,
Vinson Lee4f94e0b2011-03-28 20:32:01 -07002904 "glBlitFramebufferEXT(bad src/dst multisample region sizes)");
Brian Paul722d9762009-01-20 16:58:49 -07002905 return;
2906 }
2907
2908 /* color formats must match */
2909 if (colorReadRb &&
2910 colorDrawRb &&
Marek Olšák59272272012-07-21 15:16:15 +02002911 !compatible_resolve_formats(colorReadRb, colorDrawRb)) {
Brian Paul722d9762009-01-20 16:58:49 -07002912 _mesa_error(ctx, GL_INVALID_OPERATION,
Vinson Lee4f94e0b2011-03-28 20:32:01 -07002913 "glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
Brian Paul722d9762009-01-20 16:58:49 -07002914 return;
2915 }
2916 }
2917
Brian Paul84c38c72012-01-09 08:11:33 -07002918 if (filter == GL_LINEAR && (mask & GL_COLOR_BUFFER_BIT)) {
2919 /* 3.1 spec, page 199:
2920 * "Calling BlitFramebuffer will result in an INVALID_OPERATION error
2921 * if filter is LINEAR and read buffer contains integer data."
2922 */
2923 GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
2924 if (type == GL_INT || type == GL_UNSIGNED_INT) {
2925 _mesa_error(ctx, GL_INVALID_OPERATION,
2926 "glBlitFramebufferEXT(integer color type)");
2927 return;
2928 }
2929 }
2930
Brian Paul0bffb112005-11-08 14:45:48 +00002931 if (!ctx->Extensions.EXT_framebuffer_blit) {
2932 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
2933 return;
2934 }
2935
Brian Paul21f8d312009-10-27 16:59:23 -06002936 /* Debug code */
2937 if (DEBUG_BLIT) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002938 printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
2939 " 0x%x, 0x%x)\n",
2940 srcX0, srcY0, srcX1, srcY1,
2941 dstX0, dstY0, dstX1, dstY1,
2942 mask, filter);
Brian Paul21f8d312009-10-27 16:59:23 -06002943 if (colorReadRb) {
2944 const struct gl_renderbuffer_attachment *att;
2945
2946 att = find_attachment(readFb, colorReadRb);
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002947 printf(" Src FBO %u RB %u (%dx%d) ",
2948 readFb->Name, colorReadRb->Name,
2949 colorReadRb->Width, colorReadRb->Height);
Brian Paul21f8d312009-10-27 16:59:23 -06002950 if (att && att->Texture) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002951 printf("Tex %u tgt 0x%x level %u face %u",
2952 att->Texture->Name,
2953 att->Texture->Target,
2954 att->TextureLevel,
2955 att->CubeMapFace);
Brian Paul21f8d312009-10-27 16:59:23 -06002956 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002957 printf("\n");
Brian Paul21f8d312009-10-27 16:59:23 -06002958
2959 att = find_attachment(drawFb, colorDrawRb);
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002960 printf(" Dst FBO %u RB %u (%dx%d) ",
2961 drawFb->Name, colorDrawRb->Name,
2962 colorDrawRb->Width, colorDrawRb->Height);
Brian Paul21f8d312009-10-27 16:59:23 -06002963 if (att && att->Texture) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002964 printf("Tex %u tgt 0x%x level %u face %u",
2965 att->Texture->Name,
2966 att->Texture->Target,
2967 att->TextureLevel,
2968 att->CubeMapFace);
Brian Paul21f8d312009-10-27 16:59:23 -06002969 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002970 printf("\n");
Brian Paul21f8d312009-10-27 16:59:23 -06002971 }
2972 }
2973
Marek Olšák83478e52011-07-10 20:01:33 +02002974 if (!mask) {
2975 return;
2976 }
2977
Brian Paul0bffb112005-11-08 14:45:48 +00002978 ASSERT(ctx->Driver.BlitFramebuffer);
2979 ctx->Driver.BlitFramebuffer(ctx,
2980 srcX0, srcY0, srcX1, srcY1,
2981 dstX0, dstY0, dstX1, dstY1,
2982 mask, filter);
2983}
2984#endif /* FEATURE_EXT_framebuffer_blit */
Zack Rusinda7bd6a2010-06-28 17:31:21 -04002985
Brian Paul45bd5c42011-12-16 08:44:43 -07002986
Zack Rusinda7bd6a2010-06-28 17:31:21 -04002987#if FEATURE_ARB_geometry_shader4
2988void GLAPIENTRY
2989_mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
2990 GLuint texture, GLint level)
2991{
2992 GET_CURRENT_CONTEXT(ctx);
2993 _mesa_error(ctx, GL_INVALID_OPERATION,
2994 "glFramebufferTextureARB "
2995 "not implemented!");
2996}
2997
Brian Paul45bd5c42011-12-16 08:44:43 -07002998
Zack Rusinda7bd6a2010-06-28 17:31:21 -04002999void GLAPIENTRY
3000_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
3001 GLuint texture, GLint level, GLenum face)
3002{
3003 GET_CURRENT_CONTEXT(ctx);
3004 _mesa_error(ctx, GL_INVALID_OPERATION,
3005 "glFramebufferTextureFaceARB "
3006 "not implemented!");
3007}
3008#endif /* FEATURE_ARB_geometry_shader4 */