blob: f56369483973c2e70eca6fe557c3680f6dd94453 [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 Paulc26c2002009-09-15 17:20:32 -060052/** Set this to 1 to help debug FBO incompleteness problems */
53#define DEBUG_FBO 0
54
Brian Paul21f8d312009-10-27 16:59:23 -060055/** Set this to 1 to debug/log glBlitFramebuffer() calls */
56#define DEBUG_BLIT 0
57
Brian Paulc26c2002009-09-15 17:20:32 -060058
Brian Pauld9468c92005-02-10 16:08:07 +000059/**
60 * Notes:
61 *
62 * None of the GL_EXT_framebuffer_object functions are compiled into
63 * display lists.
64 */
65
66
67
Brian Paul923b6fc2005-02-08 04:08:56 +000068/*
69 * When glGenRender/FramebuffersEXT() is called we insert pointers to
70 * these placeholder objects into the hash table.
71 * Later, when the object ID is first bound, we replace the placeholder
72 * with the real frame/renderbuffer.
73 */
Brian Paul2c6f9112005-02-24 05:47:06 +000074static struct gl_framebuffer DummyFramebuffer;
75static struct gl_renderbuffer DummyRenderbuffer;
Brian Paul1864c7d2005-02-08 03:46:37 +000076
Kristian Høgsberg144356f2010-09-09 17:08:12 -040077/* We bind this framebuffer when applications pass a NULL
78 * drawable/surface in make current. */
79static struct gl_framebuffer IncompleteFramebuffer;
80
Brian Paul1864c7d2005-02-08 03:46:37 +000081
Brian Paul3dc65912008-07-03 15:40:38 -060082static void
83delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
84{
85 /* no op */
86}
87
88static void
89delete_dummy_framebuffer(struct gl_framebuffer *fb)
90{
91 /* no op */
92}
93
94
95void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -040096_mesa_init_fbobjects(struct gl_context *ctx)
Brian Paul3dc65912008-07-03 15:40:38 -060097{
Vladimir Vukicevic07317012010-09-01 08:54:21 -060098 _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
99 _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
Kristian Høgsberg144356f2010-09-09 17:08:12 -0400100 _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex);
Brian Paul3dc65912008-07-03 15:40:38 -0600101 DummyFramebuffer.Delete = delete_dummy_framebuffer;
102 DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
Kristian Høgsberg144356f2010-09-09 17:08:12 -0400103 IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
Brian Paul3dc65912008-07-03 15:40:38 -0600104}
105
Kristian Høgsberg9456e222010-06-04 14:28:59 -0400106struct gl_framebuffer *
107_mesa_get_incomplete_framebuffer(void)
108{
Kristian Høgsberg144356f2010-09-09 17:08:12 -0400109 return &IncompleteFramebuffer;
Kristian Høgsberg9456e222010-06-04 14:28:59 -0400110}
Brian Paul3dc65912008-07-03 15:40:38 -0600111
Brian Paulddc82ee2005-02-05 19:56:45 +0000112/**
Brian Paul2c6f9112005-02-24 05:47:06 +0000113 * Helper routine for getting a gl_renderbuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +0000114 */
Brian Paulea4fe662006-03-26 05:22:17 +0000115struct gl_renderbuffer *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400116_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +0000117{
Brian Paul2c6f9112005-02-24 05:47:06 +0000118 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000119
Brian Paul1864c7d2005-02-08 03:46:37 +0000120 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +0000121 return NULL;
122
Brian Paul2c6f9112005-02-24 05:47:06 +0000123 rb = (struct gl_renderbuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000124 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
125 return rb;
126}
127
128
129/**
Brian Paul2c6f9112005-02-24 05:47:06 +0000130 * Helper routine for getting a gl_framebuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +0000131 */
Brian Paulea4fe662006-03-26 05:22:17 +0000132struct gl_framebuffer *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400133_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +0000134{
Brian Paul2c6f9112005-02-24 05:47:06 +0000135 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000136
Brian Paul1864c7d2005-02-08 03:46:37 +0000137 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +0000138 return NULL;
139
Brian Paul2c6f9112005-02-24 05:47:06 +0000140 fb = (struct gl_framebuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000141 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
Brian Paul463642c2005-02-08 02:06:00 +0000142 return fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000143}
144
145
146/**
Brian Paul72966362009-01-21 16:28:38 -0700147 * Mark the given framebuffer as invalid. This will force the
148 * test for framebuffer completeness to be done before the framebuffer
149 * is used.
150 */
151static void
152invalidate_framebuffer(struct gl_framebuffer *fb)
153{
154 fb->_Status = 0; /* "indeterminate" */
155}
156
157
158/**
Brian Paulc6991432011-02-28 18:24:25 -0700159 * Return the gl_framebuffer object which corresponds to the given
160 * framebuffer target, such as GL_DRAW_FRAMEBUFFER.
161 * Check support for GL_EXT_framebuffer_blit to determine if certain
162 * targets are legal.
163 * \return gl_framebuffer pointer or NULL if target is illegal
164 */
165static struct gl_framebuffer *
166get_framebuffer_target(struct gl_context *ctx, GLenum target)
167{
168 switch (target) {
169 case GL_DRAW_FRAMEBUFFER:
Ian Romanick6dd8e762011-09-20 15:10:50 -0700170 return ctx->Extensions.EXT_framebuffer_blit && ctx->API == API_OPENGL
171 ? ctx->DrawBuffer : NULL;
Brian Paulc6991432011-02-28 18:24:25 -0700172 case GL_READ_FRAMEBUFFER:
Ian Romanick6dd8e762011-09-20 15:10:50 -0700173 return ctx->Extensions.EXT_framebuffer_blit && ctx->API == API_OPENGL
174 ? ctx->ReadBuffer : NULL;
Brian Paulc6991432011-02-28 18:24:25 -0700175 case GL_FRAMEBUFFER_EXT:
176 return ctx->DrawBuffer;
177 default:
178 return NULL;
179 }
180}
181
182
183/**
Brian Pauld9468c92005-02-10 16:08:07 +0000184 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
Brian Paul2c6f9112005-02-24 05:47:06 +0000185 * gl_renderbuffer_attachment object.
Brian Paul61ec2052010-06-22 08:37:44 -0600186 * This function is only used for user-created FB objects, not the
187 * default / window-system FB object.
Brian Paul30590072009-01-21 11:06:11 -0700188 * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
189 * the depth buffer attachment point.
Brian Pauld9468c92005-02-10 16:08:07 +0000190 */
Brian Paul84716042005-11-16 04:05:54 +0000191struct gl_renderbuffer_attachment *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400192_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
Brian Paul84716042005-11-16 04:05:54 +0000193 GLenum attachment)
Brian Paul3deaa012005-02-07 05:08:24 +0000194{
195 GLuint i;
196
Brian Paul36ede892012-01-12 09:17:23 -0700197 assert(_mesa_is_user_fbo(fb));
Brian Paul61ec2052010-06-22 08:37:44 -0600198
Brian Paul3deaa012005-02-07 05:08:24 +0000199 switch (attachment) {
200 case GL_COLOR_ATTACHMENT0_EXT:
201 case GL_COLOR_ATTACHMENT1_EXT:
202 case GL_COLOR_ATTACHMENT2_EXT:
203 case GL_COLOR_ATTACHMENT3_EXT:
204 case GL_COLOR_ATTACHMENT4_EXT:
205 case GL_COLOR_ATTACHMENT5_EXT:
206 case GL_COLOR_ATTACHMENT6_EXT:
207 case GL_COLOR_ATTACHMENT7_EXT:
208 case GL_COLOR_ATTACHMENT8_EXT:
209 case GL_COLOR_ATTACHMENT9_EXT:
210 case GL_COLOR_ATTACHMENT10_EXT:
211 case GL_COLOR_ATTACHMENT11_EXT:
212 case GL_COLOR_ATTACHMENT12_EXT:
213 case GL_COLOR_ATTACHMENT13_EXT:
214 case GL_COLOR_ATTACHMENT14_EXT:
215 case GL_COLOR_ATTACHMENT15_EXT:
Ian Romanick2e3a4ab2011-10-02 15:03:07 -0700216 /* Only OpenGL ES 1.x forbids color attachments other than
217 * GL_COLOR_ATTACHMENT0. For all other APIs the limit set by the
218 * hardware is used.
219 */
Brian Paul3deaa012005-02-07 05:08:24 +0000220 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
Ian Romanick7e4cb322011-10-02 14:50:21 -0700221 if (i >= ctx->Const.MaxColorAttachments
Ian Romanick2e3a4ab2011-10-02 15:03:07 -0700222 || (i > 0 && ctx->API == API_OPENGLES)) {
Brian Paul3deaa012005-02-07 05:08:24 +0000223 return NULL;
224 }
Brian Paule4b23562005-05-04 20:11:35 +0000225 return &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paul30590072009-01-21 11:06:11 -0700226 case GL_DEPTH_STENCIL_ATTACHMENT:
Ian Romanick7e4cb322011-10-02 14:50:21 -0700227 if (ctx->API != API_OPENGL)
228 return NULL;
Brian Paul30590072009-01-21 11:06:11 -0700229 /* fall-through */
Brian Paul3deaa012005-02-07 05:08:24 +0000230 case GL_DEPTH_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000231 return &fb->Attachment[BUFFER_DEPTH];
Brian Paul3deaa012005-02-07 05:08:24 +0000232 case GL_STENCIL_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000233 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul61ec2052010-06-22 08:37:44 -0600234 default:
235 return NULL;
236 }
237}
238
239
240/**
241 * As above, but only used for getting attachments of the default /
242 * window-system framebuffer (not user-created framebuffer objects).
243 */
244static struct gl_renderbuffer_attachment *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400245_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
Brian Paul61ec2052010-06-22 08:37:44 -0600246 GLenum attachment)
247{
Brian Paul36ede892012-01-12 09:17:23 -0700248 assert(_mesa_is_winsys_fbo(fb));
Brian Paul61ec2052010-06-22 08:37:44 -0600249
250 switch (attachment) {
Kristian Høgsberg80dfec32010-06-15 13:07:01 -0400251 case GL_FRONT_LEFT:
252 return &fb->Attachment[BUFFER_FRONT_LEFT];
253 case GL_FRONT_RIGHT:
254 return &fb->Attachment[BUFFER_FRONT_RIGHT];
255 case GL_BACK_LEFT:
256 return &fb->Attachment[BUFFER_BACK_LEFT];
257 case GL_BACK_RIGHT:
258 return &fb->Attachment[BUFFER_BACK_RIGHT];
Brian Paul61ec2052010-06-22 08:37:44 -0600259 case GL_AUX0:
260 if (fb->Visual.numAuxBuffers == 1) {
261 return &fb->Attachment[BUFFER_AUX0];
262 }
263 return NULL;
Ian Romanicka8328cc2011-10-03 12:02:18 -0700264
265 /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says:
266 *
267 * "If the default framebuffer is bound to target, then attachment must
268 * be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi,
269 * identifying a color buffer; DEPTH, identifying the depth buffer; or
270 * STENCIL, identifying the stencil buffer."
271 *
272 * Revision #34 of the ARB_framebuffer_object spec has essentially the same
273 * language. However, revision #33 of the ARB_framebuffer_object spec
274 * says:
275 *
276 * "If the default framebuffer is bound to <target>, then <attachment>
277 * must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi,
278 * DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the
279 * depth buffer, or the stencil buffer, and <pname> may be
280 * FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or
281 * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME."
282 *
283 * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed
284 * from glext.h, so shipping apps should not use those values.
285 *
286 * Note that neither EXT_framebuffer_object nor OES_framebuffer_object
287 * support queries of the window system FBO.
288 */
289 case GL_DEPTH:
Brian Paul61ec2052010-06-22 08:37:44 -0600290 return &fb->Attachment[BUFFER_DEPTH];
Ian Romanicka8328cc2011-10-03 12:02:18 -0700291 case GL_STENCIL:
Brian Paul61ec2052010-06-22 08:37:44 -0600292 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul3deaa012005-02-07 05:08:24 +0000293 default:
294 return NULL;
295 }
296}
297
298
Brian Paul61ec2052010-06-22 08:37:44 -0600299
Brian Pauld9468c92005-02-10 16:08:07 +0000300/**
301 * Remove any texture or renderbuffer attached to the given attachment
302 * point. Update reference counts, etc.
303 */
Brian Paule4b23562005-05-04 20:11:35 +0000304void
Brian Paulf9288542010-10-22 11:25:14 -0600305_mesa_remove_attachment(struct gl_context *ctx,
306 struct gl_renderbuffer_attachment *att)
Brian Paul3deaa012005-02-07 05:08:24 +0000307{
308 if (att->Type == GL_TEXTURE) {
309 ASSERT(att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100310 if (ctx->Driver.FinishRenderTexture) {
Brian Paul0e31e022005-12-01 00:25:00 +0000311 /* tell driver that we're done rendering to this texture. */
Brian9e01b912007-08-13 11:29:46 +0100312 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000313 }
Brian9e01b912007-08-13 11:29:46 +0100314 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
315 ASSERT(!att->Texture);
Brian Paul3deaa012005-02-07 05:08:24 +0000316 }
Brian Paul0e31e022005-12-01 00:25:00 +0000317 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul3deaa012005-02-07 05:08:24 +0000318 ASSERT(!att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100319 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
320 ASSERT(!att->Renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000321 }
322 att->Type = GL_NONE;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000323 att->Complete = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +0000324}
325
326
Brian Pauld9468c92005-02-10 16:08:07 +0000327/**
328 * Bind a texture object to an attachment point.
329 * The previous binding, if any, will be removed first.
330 */
Brian Paule4b23562005-05-04 20:11:35 +0000331void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400332_mesa_set_texture_attachment(struct gl_context *ctx,
Brian Paul519b23b2006-03-20 18:51:57 +0000333 struct gl_framebuffer *fb,
Brian Paule4b23562005-05-04 20:11:35 +0000334 struct gl_renderbuffer_attachment *att,
335 struct gl_texture_object *texObj,
336 GLenum texTarget, GLuint level, GLuint zoffset)
Brian Paul3deaa012005-02-07 05:08:24 +0000337{
Brian Paul0e31e022005-12-01 00:25:00 +0000338 if (att->Texture == texObj) {
339 /* re-attaching same texture */
340 ASSERT(att->Type == GL_TEXTURE);
Eric Anholt6b684822009-11-04 14:31:30 -0800341 if (ctx->Driver.FinishRenderTexture)
342 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000343 }
344 else {
345 /* new attachment */
Eric Anholt6b684822009-11-04 14:31:30 -0800346 if (ctx->Driver.FinishRenderTexture && att->Texture)
347 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000348 _mesa_remove_attachment(ctx, att);
349 att->Type = GL_TEXTURE;
Brian9e01b912007-08-13 11:29:46 +0100350 assert(!att->Texture);
351 _mesa_reference_texobj(&att->Texture, texObj);
Brian Paul0e31e022005-12-01 00:25:00 +0000352 }
353
354 /* always update these fields */
Brian Paul3deaa012005-02-07 05:08:24 +0000355 att->TextureLevel = level;
Brian Paul26f1ad62009-10-23 18:15:55 -0600356 att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
Brian Paul3deaa012005-02-07 05:08:24 +0000357 att->Zoffset = zoffset;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000358 att->Complete = GL_FALSE;
Brian Paul519b23b2006-03-20 18:51:57 +0000359
Brian Pauldb0f9e72011-04-05 07:51:01 -0600360 if (_mesa_get_attachment_teximage(att)) {
Brian Paulea4fe662006-03-26 05:22:17 +0000361 ctx->Driver.RenderTexture(ctx, fb, att);
Brian Paul519b23b2006-03-20 18:51:57 +0000362 }
Brian Paul72966362009-01-21 16:28:38 -0700363
364 invalidate_framebuffer(fb);
Brian Paul3deaa012005-02-07 05:08:24 +0000365}
366
367
Brian Pauld9468c92005-02-10 16:08:07 +0000368/**
369 * Bind a renderbuffer to an attachment point.
370 * The previous binding, if any, will be removed first.
371 */
Brian Paule4b23562005-05-04 20:11:35 +0000372void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400373_mesa_set_renderbuffer_attachment(struct gl_context *ctx,
Brian Paule4b23562005-05-04 20:11:35 +0000374 struct gl_renderbuffer_attachment *att,
375 struct gl_renderbuffer *rb)
Brian Paul3deaa012005-02-07 05:08:24 +0000376{
Brian Paulea4fe662006-03-26 05:22:17 +0000377 /* XXX check if re-doing same attachment, exit early */
Brian Paule4b23562005-05-04 20:11:35 +0000378 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000379 att->Type = GL_RENDERBUFFER_EXT;
Brian Paul2c6f9112005-02-24 05:47:06 +0000380 att->Texture = NULL; /* just to be safe */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000381 att->Complete = GL_FALSE;
Briandccd9c42007-04-02 09:56:28 -0600382 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
Brian Paul3deaa012005-02-07 05:08:24 +0000383}
384
Brian Paulddc82ee2005-02-05 19:56:45 +0000385
Brian Paulf0bbbf62005-02-09 03:50:30 +0000386/**
Brian Paule4b23562005-05-04 20:11:35 +0000387 * Fallback for ctx->Driver.FramebufferRenderbuffer()
Brian Paul84716042005-11-16 04:05:54 +0000388 * Attach a renderbuffer object to a framebuffer object.
Brian Paule4b23562005-05-04 20:11:35 +0000389 */
390void
Brian Paulf9288542010-10-22 11:25:14 -0600391_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
392 struct gl_framebuffer *fb,
Brian Paul84716042005-11-16 04:05:54 +0000393 GLenum attachment, struct gl_renderbuffer *rb)
Brian Paule4b23562005-05-04 20:11:35 +0000394{
Brian Paul84716042005-11-16 04:05:54 +0000395 struct gl_renderbuffer_attachment *att;
396
Brian Paulea4fe662006-03-26 05:22:17 +0000397 _glthread_LOCK_MUTEX(fb->Mutex);
Brian Paulea4fe662006-03-26 05:22:17 +0000398
Brian Paul84716042005-11-16 04:05:54 +0000399 att = _mesa_get_attachment(ctx, fb, attachment);
400 ASSERT(att);
Brian Paule4b23562005-05-04 20:11:35 +0000401 if (rb) {
402 _mesa_set_renderbuffer_attachment(ctx, att, rb);
Brian Paul30590072009-01-21 11:06:11 -0700403 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
404 /* do stencil attachment here (depth already done above) */
405 att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
406 assert(att);
407 _mesa_set_renderbuffer_attachment(ctx, att, rb);
408 }
Marek Olšákdf818d52011-03-06 05:26:12 +0100409 rb->AttachedAnytime = GL_TRUE;
Brian Paule4b23562005-05-04 20:11:35 +0000410 }
411 else {
412 _mesa_remove_attachment(ctx, att);
413 }
Brian Paulea4fe662006-03-26 05:22:17 +0000414
Brian Paul72966362009-01-21 16:28:38 -0700415 invalidate_framebuffer(fb);
416
Brian Paulea4fe662006-03-26 05:22:17 +0000417 _glthread_UNLOCK_MUTEX(fb->Mutex);
Brian Paule4b23562005-05-04 20:11:35 +0000418}
419
420
421/**
Brian Paul62c66b32011-01-24 19:38:52 -0700422 * Fallback for ctx->Driver.ValidateFramebuffer()
423 * Check if the renderbuffer's formats are supported by the software
424 * renderer.
425 * Drivers should probably override this.
426 */
427void
428_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
429{
430 gl_buffer_index buf;
431 for (buf = 0; buf < BUFFER_COUNT; buf++) {
432 const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer;
433 if (rb) {
434 switch (rb->_BaseFormat) {
435 case GL_ALPHA:
436 case GL_LUMINANCE_ALPHA:
437 case GL_LUMINANCE:
438 case GL_INTENSITY:
Brian Pauld3015652011-01-24 19:38:52 -0700439 case GL_RED:
440 case GL_RG:
Brian Paul62c66b32011-01-24 19:38:52 -0700441 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
442 return;
Marek Olšáka3ac28a2011-05-14 04:42:29 +0200443
444 default:
Marek Olšák9d7698c2011-04-26 02:18:24 +0200445 switch (rb->Format) {
Marek Olšáka3ac28a2011-05-14 04:42:29 +0200446 /* XXX This list is likely incomplete. */
Marek Olšák9d7698c2011-04-26 02:18:24 +0200447 case MESA_FORMAT_RGB9_E5_FLOAT:
448 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
449 return;
450 default:;
Marek Olšáka3ac28a2011-05-14 04:42:29 +0200451 /* render buffer format is supported by software rendering */
Marek Olšák9d7698c2011-04-26 02:18:24 +0200452 }
Brian Paul62c66b32011-01-24 19:38:52 -0700453 }
454 }
455 }
456}
457
458
459/**
Brian Paul9f731c82009-02-17 16:47:54 -0700460 * For debug only.
461 */
462static void
463att_incomplete(const char *msg)
464{
Brian Paulc26c2002009-09-15 17:20:32 -0600465#if DEBUG_FBO
466 _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
Brian Paul9f731c82009-02-17 16:47:54 -0700467#else
468 (void) msg;
469#endif
470}
471
472
473/**
Brian Paulc26c2002009-09-15 17:20:32 -0600474 * For debug only.
475 */
476static void
477fbo_incomplete(const char *msg, int index)
478{
479#if DEBUG_FBO
480 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
481#else
482 (void) msg;
483 (void) index;
484#endif
485}
486
487
Brian Paule67f6ee2010-10-22 11:38:23 -0600488/**
489 * Is the given base format a legal format for a color renderbuffer?
490 */
Eric Anholt059cca92011-01-02 17:58:07 -0800491GLboolean
492_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
Brian Paule67f6ee2010-10-22 11:38:23 -0600493{
494 switch (baseFormat) {
495 case GL_RGB:
496 case GL_RGBA:
497 return GL_TRUE;
Marek Olšák6e618532010-10-02 21:53:03 +0200498 case GL_LUMINANCE:
499 case GL_LUMINANCE_ALPHA:
500 case GL_INTENSITY:
Brian Paule67f6ee2010-10-22 11:38:23 -0600501 case GL_ALPHA:
502 return ctx->Extensions.ARB_framebuffer_object;
503 case GL_RED:
504 case GL_RG:
505 return ctx->Extensions.ARB_texture_rg;
506 default:
507 return GL_FALSE;
508 }
509}
510
511
512/**
513 * Is the given base format a legal format for a depth/stencil renderbuffer?
514 */
515static GLboolean
516is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
517{
518 switch (baseFormat) {
519 case GL_DEPTH_COMPONENT:
520 case GL_DEPTH_STENCIL_EXT:
521 return GL_TRUE;
522 default:
523 return GL_FALSE;
524 }
525}
Brian Paulc26c2002009-09-15 17:20:32 -0600526
527
528/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000529 * Test if an attachment point is complete and update its Complete field.
530 * \param format if GL_COLOR, this is a color attachment point,
531 * if GL_DEPTH, this is a depth component attachment point,
532 * if GL_STENCIL, this is a stencil component attachment point.
533 */
534static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400535test_attachment_completeness(const struct gl_context *ctx, GLenum format,
Brian Paul2c6f9112005-02-24 05:47:06 +0000536 struct gl_renderbuffer_attachment *att)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000537{
538 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
539
540 /* assume complete */
541 att->Complete = GL_TRUE;
542
Brian Paulf0bbbf62005-02-09 03:50:30 +0000543 /* Look for reasons why the attachment might be incomplete */
544 if (att->Type == GL_TEXTURE) {
Brian Paule4b23562005-05-04 20:11:35 +0000545 const struct gl_texture_object *texObj = att->Texture;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000546 struct gl_texture_image *texImage;
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600547 GLenum baseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000548
Brian Paule4b23562005-05-04 20:11:35 +0000549 if (!texObj) {
Brian Paul9f731c82009-02-17 16:47:54 -0700550 att_incomplete("no texobj");
Brian Paule4b23562005-05-04 20:11:35 +0000551 att->Complete = GL_FALSE;
552 return;
553 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000554
555 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
556 if (!texImage) {
Brian Paul9f731c82009-02-17 16:47:54 -0700557 att_incomplete("no teximage");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000558 att->Complete = GL_FALSE;
559 return;
560 }
561 if (texImage->Width < 1 || texImage->Height < 1) {
Brian Paul9f731c82009-02-17 16:47:54 -0700562 att_incomplete("teximage width/height=0");
Kristian Høgsberg298be2b2010-02-19 12:32:24 -0500563 printf("texobj = %u\n", texObj->Name);
564 printf("level = %d\n", att->TextureLevel);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000565 att->Complete = GL_FALSE;
566 return;
567 }
568 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
Brian Paul9f731c82009-02-17 16:47:54 -0700569 att_incomplete("bad z offset");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000570 att->Complete = GL_FALSE;
571 return;
572 }
573
Brian Paul1f7c9142009-09-30 20:28:45 -0600574 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600575
Brian Paulf0bbbf62005-02-09 03:50:30 +0000576 if (format == GL_COLOR) {
Eric Anholt059cca92011-01-02 17:58:07 -0800577 if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
Brian Paul9f731c82009-02-17 16:47:54 -0700578 att_incomplete("bad format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000579 att->Complete = GL_FALSE;
580 return;
581 }
Brian Paul1f7c9142009-09-30 20:28:45 -0600582 if (_mesa_is_format_compressed(texImage->TexFormat)) {
Eric Anholt957f3c82009-05-15 16:24:59 -0700583 att_incomplete("compressed internalformat");
584 att->Complete = GL_FALSE;
585 return;
586 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000587 }
588 else if (format == GL_DEPTH) {
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600589 if (baseFormat == GL_DEPTH_COMPONENT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000590 /* OK */
591 }
592 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600593 ctx->Extensions.ARB_depth_texture &&
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600594 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000595 /* OK */
596 }
597 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000598 att->Complete = GL_FALSE;
Brian Paul9f731c82009-02-17 16:47:54 -0700599 att_incomplete("bad depth format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000600 return;
601 }
602 }
603 else {
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600604 ASSERT(format == GL_STENCIL);
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600605 if (ctx->Extensions.EXT_packed_depth_stencil &&
606 ctx->Extensions.ARB_depth_texture &&
Brian Paul45e76d22009-10-08 20:27:27 -0600607 baseFormat == GL_DEPTH_STENCIL_EXT) {
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600608 /* OK */
609 }
610 else {
611 /* no such thing as stencil-only textures */
612 att_incomplete("illegal stencil texture");
613 att->Complete = GL_FALSE;
614 return;
615 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000616 }
617 }
Brian Paule4b23562005-05-04 20:11:35 +0000618 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul45e76d22009-10-08 20:27:27 -0600619 const GLenum baseFormat =
620 _mesa_get_format_base_format(att->Renderbuffer->Format);
621
Brian Paul49918882006-03-20 15:27:55 +0000622 ASSERT(att->Renderbuffer);
623 if (!att->Renderbuffer->InternalFormat ||
624 att->Renderbuffer->Width < 1 ||
625 att->Renderbuffer->Height < 1) {
Brian Paul9f731c82009-02-17 16:47:54 -0700626 att_incomplete("0x0 renderbuffer");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000627 att->Complete = GL_FALSE;
628 return;
629 }
630 if (format == GL_COLOR) {
Eric Anholt059cca92011-01-02 17:58:07 -0800631 if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
Brian Paul9f731c82009-02-17 16:47:54 -0700632 att_incomplete("bad renderbuffer color format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000633 att->Complete = GL_FALSE;
634 return;
635 }
636 }
637 else if (format == GL_DEPTH) {
Brian Paul45e76d22009-10-08 20:27:27 -0600638 if (baseFormat == GL_DEPTH_COMPONENT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000639 /* OK */
640 }
641 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Brian Paul45e76d22009-10-08 20:27:27 -0600642 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000643 /* OK */
644 }
645 else {
Brian Paul9f731c82009-02-17 16:47:54 -0700646 att_incomplete("bad renderbuffer depth format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000647 att->Complete = GL_FALSE;
648 return;
649 }
650 }
651 else {
652 assert(format == GL_STENCIL);
Brian Paul45e76d22009-10-08 20:27:27 -0600653 if (baseFormat == GL_STENCIL_INDEX) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000654 /* OK */
655 }
656 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Brian Paul45e76d22009-10-08 20:27:27 -0600657 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000658 /* OK */
659 }
660 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000661 att->Complete = GL_FALSE;
Brian Paul9f731c82009-02-17 16:47:54 -0700662 att_incomplete("bad renderbuffer stencil format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000663 return;
664 }
665 }
666 }
Brian Paule4b23562005-05-04 20:11:35 +0000667 else {
668 ASSERT(att->Type == GL_NONE);
669 /* complete */
670 return;
671 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000672}
673
674
675/**
676 * Test if the given framebuffer object is complete and update its
677 * Status field with the results.
Brian Paul3528f692009-01-22 15:13:18 -0700678 * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
679 * driver to make hardware-specific validation/completeness checks.
Brian Paule4b23562005-05-04 20:11:35 +0000680 * Also update the framebuffer's Width and Height fields if the
681 * framebuffer is complete.
Brian Paulf0bbbf62005-02-09 03:50:30 +0000682 */
Brian Paule4b23562005-05-04 20:11:35 +0000683void
Brian Paulf9288542010-10-22 11:25:14 -0600684_mesa_test_framebuffer_completeness(struct gl_context *ctx,
685 struct gl_framebuffer *fb)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000686{
Brian Paul989edea2009-01-22 15:05:13 -0700687 GLuint numImages;
688 GLenum intFormat = GL_NONE; /* color buffers' internal format */
689 GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
Brian Paul722d9762009-01-20 16:58:49 -0700690 GLint numSamples = -1;
Brian Paule4b23562005-05-04 20:11:35 +0000691 GLint i;
Brian Paul28b014e2006-04-05 03:05:17 +0000692 GLuint j;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000693
Brian Paul36ede892012-01-12 09:17:23 -0700694 assert(_mesa_is_user_fbo(fb));
Brian Paulc7264412005-06-01 00:50:23 +0000695
Brian Paulf0bbbf62005-02-09 03:50:30 +0000696 numImages = 0;
Brian Paule4b23562005-05-04 20:11:35 +0000697 fb->Width = 0;
698 fb->Height = 0;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000699
Brian Paul989edea2009-01-22 15:05:13 -0700700 /* Start at -2 to more easily loop over all attachment points.
701 * -2: depth buffer
702 * -1: stencil buffer
703 * >=0: color buffer
704 */
Brian Paule4b23562005-05-04 20:11:35 +0000705 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000706 struct gl_renderbuffer_attachment *att;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000707 GLenum f;
Brian Paulca1b5512011-02-28 18:23:23 -0700708 gl_format attFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000709
Brian Paul1bc59bf2009-01-22 15:07:34 -0700710 /*
711 * XXX for ARB_fbo, only check color buffers that are named by
712 * GL_READ_BUFFER and GL_DRAW_BUFFERi.
713 */
714
Brian Paul989edea2009-01-22 15:05:13 -0700715 /* check for attachment completeness
716 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000717 if (i == -2) {
Brian Paule4b23562005-05-04 20:11:35 +0000718 att = &fb->Attachment[BUFFER_DEPTH];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000719 test_attachment_completeness(ctx, GL_DEPTH, att);
720 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000721 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000722 fbo_incomplete("depth attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000723 return;
724 }
725 }
726 else if (i == -1) {
Brian Paule4b23562005-05-04 20:11:35 +0000727 att = &fb->Attachment[BUFFER_STENCIL];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000728 test_attachment_completeness(ctx, GL_STENCIL, att);
729 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000730 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000731 fbo_incomplete("stencil attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000732 return;
733 }
734 }
735 else {
Brian Paule4b23562005-05-04 20:11:35 +0000736 att = &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000737 test_attachment_completeness(ctx, GL_COLOR, att);
738 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000739 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000740 fbo_incomplete("color attachment incomplete", i);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000741 return;
742 }
743 }
744
Brian Paul989edea2009-01-22 15:05:13 -0700745 /* get width, height, format of the renderbuffer/texture
746 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000747 if (att->Type == GL_TEXTURE) {
Brian Pauldb0f9e72011-04-05 07:51:01 -0600748 const struct gl_texture_image *texImg =
749 _mesa_get_attachment_teximage(att);
Brian Paul989edea2009-01-22 15:05:13 -0700750 minWidth = MIN2(minWidth, texImg->Width);
751 maxWidth = MAX2(maxWidth, texImg->Width);
752 minHeight = MIN2(minHeight, texImg->Height);
753 maxHeight = MAX2(maxHeight, texImg->Height);
Brian Paula9fc8ba2005-10-05 01:48:07 +0000754 f = texImg->_BaseFormat;
Brian Paulca1b5512011-02-28 18:23:23 -0700755 attFormat = texImg->TexFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000756 numImages++;
Eric Anholt059cca92011-01-02 17:58:07 -0800757 if (!_mesa_is_legal_color_format(ctx, f) &&
Brian Paule67f6ee2010-10-22 11:38:23 -0600758 !is_legal_depth_format(ctx, f)) {
Brian Pauled7f3ae2005-06-07 15:03:40 +0000759 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000760 fbo_incomplete("texture attachment incomplete", -1);
Brian Pauled7f3ae2005-06-07 15:03:40 +0000761 return;
762 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000763 }
764 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul989edea2009-01-22 15:05:13 -0700765 minWidth = MIN2(minWidth, att->Renderbuffer->Width);
766 maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
767 minHeight = MIN2(minHeight, att->Renderbuffer->Height);
768 maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000769 f = att->Renderbuffer->InternalFormat;
Brian Paulca1b5512011-02-28 18:23:23 -0700770 attFormat = att->Renderbuffer->Format;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000771 numImages++;
772 }
773 else {
774 assert(att->Type == GL_NONE);
775 continue;
776 }
777
Fabian Bielerc7339d42011-04-05 07:51:01 -0600778 if (att->Renderbuffer && numSamples < 0) {
Brian Paul72966362009-01-21 16:28:38 -0700779 /* first buffer */
780 numSamples = att->Renderbuffer->NumSamples;
781 }
782
Brian Paulc7d18372010-10-23 09:38:45 -0600783 /* check if integer color */
Brian Paulca1b5512011-02-28 18:23:23 -0700784 fb->_IntegerColor = _mesa_is_format_integer_color(attFormat);
Brian Paulc7d18372010-10-23 09:38:45 -0600785
Brian Paul722d9762009-01-20 16:58:49 -0700786 /* Error-check width, height, format, samples
Brian Paul989edea2009-01-22 15:05:13 -0700787 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000788 if (numImages == 1) {
Brian Paul722d9762009-01-20 16:58:49 -0700789 /* save format, num samples */
790 if (i >= 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000791 intFormat = f;
Brian Paul722d9762009-01-20 16:58:49 -0700792 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000793 }
794 else {
Brian Paul989edea2009-01-22 15:05:13 -0700795 if (!ctx->Extensions.ARB_framebuffer_object) {
796 /* check that width, height, format are same */
797 if (minWidth != maxWidth || minHeight != maxHeight) {
798 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
799 fbo_incomplete("width or height mismatch", -1);
800 return;
801 }
Brian Paul45bd5c42011-12-16 08:44:43 -0700802 /* check that all color buffers are the same format */
Brian Paul989edea2009-01-22 15:05:13 -0700803 if (intFormat != GL_NONE && f != intFormat) {
804 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
805 fbo_incomplete("format mismatch", -1);
806 return;
807 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000808 }
Brian Paul722d9762009-01-20 16:58:49 -0700809 if (att->Renderbuffer &&
810 att->Renderbuffer->NumSamples != numSamples) {
Brian Paul72966362009-01-21 16:28:38 -0700811 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
Brian Paul722d9762009-01-20 16:58:49 -0700812 fbo_incomplete("inconsistant number of samples", i);
813 return;
Brian Paul45bd5c42011-12-16 08:44:43 -0700814 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000815 }
816 }
817
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400818#if FEATURE_GL
Eric Anholtd3451f72011-05-25 13:51:26 -0700819 if (ctx->API == API_OPENGL && !ctx->Extensions.ARB_ES2_compatibility) {
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400820 /* Check that all DrawBuffers are present */
821 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
822 if (fb->ColorDrawBuffer[j] != GL_NONE) {
823 const struct gl_renderbuffer_attachment *att
824 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
825 assert(att);
826 if (att->Type == GL_NONE) {
827 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
828 fbo_incomplete("missing drawbuffer", j);
829 return;
830 }
831 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000832 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000833
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400834 /* Check that the ReadBuffer is present */
835 if (fb->ColorReadBuffer != GL_NONE) {
836 const struct gl_renderbuffer_attachment *att
837 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
838 assert(att);
839 if (att->Type == GL_NONE) {
840 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000841 fbo_incomplete("missing readbuffer", -1);
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400842 return;
843 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000844 }
845 }
Chia-I Wu9927d7f2009-10-02 15:32:04 +0800846#else
847 (void) j;
Brian Paul868c09a2008-08-08 13:06:54 -0600848#endif
Brian Paulf0bbbf62005-02-09 03:50:30 +0000849
850 if (numImages == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000851 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000852 fbo_incomplete("no attachments", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000853 return;
854 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000855
Brian Paul3528f692009-01-22 15:13:18 -0700856 /* Provisionally set status = COMPLETE ... */
Brian Paule4b23562005-05-04 20:11:35 +0000857 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
Brian Paul3528f692009-01-22 15:13:18 -0700858
Brian Paul777a2ef2009-01-22 15:17:42 -0700859 /* ... but the driver may say the FB is incomplete.
860 * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
861 * if anything.
862 */
Brian Paul3528f692009-01-22 15:13:18 -0700863 if (ctx->Driver.ValidateFramebuffer) {
864 ctx->Driver.ValidateFramebuffer(ctx, fb);
Brian Paul1f32c412009-01-19 17:34:19 -0700865 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
866 fbo_incomplete("driver marked FBO as incomplete", -1);
867 }
Brian Paul3528f692009-01-22 15:13:18 -0700868 }
869
870 if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
871 /*
872 * Note that if ARB_framebuffer_object is supported and the attached
873 * renderbuffers/textures are different sizes, the framebuffer
874 * width/height will be set to the smallest width/height.
875 */
876 fb->Width = minWidth;
877 fb->Height = minHeight;
Brian Paul38768db2009-01-27 09:49:27 -0700878
879 /* finally, update the visual info for the framebuffer */
Eric Anholt059cca92011-01-02 17:58:07 -0800880 _mesa_update_framebuffer_visual(ctx, fb);
Brian Paul3528f692009-01-22 15:13:18 -0700881 }
Brian Paule4b23562005-05-04 20:11:35 +0000882}
Brian Paulf0bbbf62005-02-09 03:50:30 +0000883
884
Brian Paul1864c7d2005-02-08 03:46:37 +0000885GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000886_mesa_IsRenderbufferEXT(GLuint renderbuffer)
887{
Brian Paulddc82ee2005-02-05 19:56:45 +0000888 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000889 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000890 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000891 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000892 if (rb != NULL && rb != &DummyRenderbuffer)
893 return GL_TRUE;
894 }
895 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000896}
897
898
Brian Paul1864c7d2005-02-08 03:46:37 +0000899void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000900_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
901{
Brian42aaa542007-03-25 10:39:36 -0600902 struct gl_renderbuffer *newRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000903 GET_CURRENT_CONTEXT(ctx);
904
905 ASSERT_OUTSIDE_BEGIN_END(ctx);
906
Brian Paul3deaa012005-02-07 05:08:24 +0000907 if (target != GL_RENDERBUFFER_EXT) {
Brian Paul4de18fb2009-11-02 15:30:51 -0700908 _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000909 return;
910 }
911
Brian Paul800e5532009-11-02 15:39:39 -0700912 /* No need to flush here since the render buffer binding has no
913 * effect on rendering state.
914 */
Brian Paul474f28e2005-10-08 14:41:17 +0000915
Brian Paul3deaa012005-02-07 05:08:24 +0000916 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000917 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000918 if (newRb == &DummyRenderbuffer) {
919 /* ID was reserved, but no real renderbuffer object made yet */
920 newRb = NULL;
921 }
Brian Paul1bc59bf2009-01-22 15:07:34 -0700922 else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
923 /* All RB IDs must be Gen'd */
924 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
925 return;
926 }
927
Brian Paul3deaa012005-02-07 05:08:24 +0000928 if (!newRb) {
929 /* create new renderbuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000930 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000931 if (!newRb) {
932 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
933 return;
934 }
Brian Paul2c6f9112005-02-24 05:47:06 +0000935 ASSERT(newRb->AllocStorage);
Brian Paul1864c7d2005-02-08 03:46:37 +0000936 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
Brian42aaa542007-03-25 10:39:36 -0600937 newRb->RefCount = 1; /* referenced by hash table */
Brian Paul3deaa012005-02-07 05:08:24 +0000938 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000939 }
Brian Paul463642c2005-02-08 02:06:00 +0000940 else {
941 newRb = NULL;
942 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000943
Brian Paul1864c7d2005-02-08 03:46:37 +0000944 ASSERT(newRb != &DummyRenderbuffer);
945
Brian42aaa542007-03-25 10:39:36 -0600946 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
Brian Paulddc82ee2005-02-05 19:56:45 +0000947}
948
949
Brian Pauld0f13fa2009-01-21 11:17:45 -0700950/**
951 * If the given renderbuffer is anywhere attached to the framebuffer, detach
952 * the renderbuffer.
953 * This is used when a renderbuffer object is deleted.
954 * The spec calls for unbinding.
955 */
956static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400957detach_renderbuffer(struct gl_context *ctx,
Brian Pauld0f13fa2009-01-21 11:17:45 -0700958 struct gl_framebuffer *fb,
959 struct gl_renderbuffer *rb)
960{
961 GLuint i;
962 for (i = 0; i < BUFFER_COUNT; i++) {
963 if (fb->Attachment[i].Renderbuffer == rb) {
964 _mesa_remove_attachment(ctx, &fb->Attachment[i]);
965 }
966 }
Brian Paul72966362009-01-21 16:28:38 -0700967 invalidate_framebuffer(fb);
Brian Pauld0f13fa2009-01-21 11:17:45 -0700968}
969
970
Brian Paul1864c7d2005-02-08 03:46:37 +0000971void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000972_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
973{
974 GLint i;
975 GET_CURRENT_CONTEXT(ctx);
976
977 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000978 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000979
980 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000981 if (renderbuffers[i] > 0) {
982 struct gl_renderbuffer *rb;
Brian Paulea4fe662006-03-26 05:22:17 +0000983 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +0000984 if (rb) {
Brian Paul91802fd2005-10-04 16:01:02 +0000985 /* check if deleting currently bound renderbuffer object */
986 if (rb == ctx->CurrentRenderbuffer) {
987 /* bind default */
988 ASSERT(rb->RefCount >= 2);
989 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
990 }
991
Brian Paul36ede892012-01-12 09:17:23 -0700992 if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
Brian Pauld0f13fa2009-01-21 11:17:45 -0700993 detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
994 }
Brian Paul36ede892012-01-12 09:17:23 -0700995 if (_mesa_is_user_fbo(ctx->ReadBuffer)
Brian Paulfc8c4a32011-06-16 07:31:58 -0600996 && ctx->ReadBuffer != ctx->DrawBuffer) {
Brian Pauld0f13fa2009-01-21 11:17:45 -0700997 detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
998 }
999
Brian42aaa542007-03-25 10:39:36 -06001000 /* Remove from hash table immediately, to free the ID.
1001 * But the object will not be freed until it's no longer
1002 * referenced anywhere else.
1003 */
Brian Paul3deaa012005-02-07 05:08:24 +00001004 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +00001005
Brian Paul1864c7d2005-02-08 03:46:37 +00001006 if (rb != &DummyRenderbuffer) {
Brian42aaa542007-03-25 10:39:36 -06001007 /* no longer referenced by hash table */
1008 _mesa_reference_renderbuffer(&rb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +00001009 }
1010 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001011 }
1012 }
1013}
1014
1015
Brian Paul1864c7d2005-02-08 03:46:37 +00001016void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001017_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
1018{
1019 GET_CURRENT_CONTEXT(ctx);
1020 GLuint first;
1021 GLint i;
1022
1023 ASSERT_OUTSIDE_BEGIN_END(ctx);
1024
1025 if (n < 0) {
1026 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
1027 return;
1028 }
1029
1030 if (!renderbuffers)
1031 return;
1032
1033 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
1034
1035 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001036 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001037 renderbuffers[i] = name;
Brian Paul1864c7d2005-02-08 03:46:37 +00001038 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001039 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001040 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001041 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001042 }
1043}
1044
1045
Brian Pauld9468c92005-02-10 16:08:07 +00001046/**
Brian Paulf41bbc72011-01-24 19:38:52 -07001047 * Given an internal format token for a render buffer, return the
Brian Paul976ea9d2011-01-24 19:38:52 -07001048 * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
1049 * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE,
1050 * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc).
Brian Paulf41bbc72011-01-24 19:38:52 -07001051 *
Brian Paul976ea9d2011-01-24 19:38:52 -07001052 * This is similar to _mesa_base_tex_format() but the set of valid
1053 * internal formats is different.
Brian Paulf41bbc72011-01-24 19:38:52 -07001054 *
Brian Paul976ea9d2011-01-24 19:38:52 -07001055 * Note that even if a format is determined to be legal here, validation
Brian Paulb3cfcdf2011-01-28 20:25:26 -07001056 * of the FBO may fail if the format is not supported by the driver/GPU.
Brian Paul976ea9d2011-01-24 19:38:52 -07001057 *
1058 * \param internalFormat as passed to glRenderbufferStorage()
1059 * \return the base internal format, or 0 if internalFormat is illegal
Brian Pauld9468c92005-02-10 16:08:07 +00001060 */
Brian Paul59e0faa2006-03-15 17:48:00 +00001061GLenum
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001062_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
Brian Paul463642c2005-02-08 02:06:00 +00001063{
Brian Paul976ea9d2011-01-24 19:38:52 -07001064 /*
1065 * Notes: some formats such as alpha, luminance, etc. were added
1066 * with GL_ARB_framebuffer_object.
1067 */
Brian Paul463642c2005-02-08 02:06:00 +00001068 switch (internalFormat) {
Brian Paulf41bbc72011-01-24 19:38:52 -07001069 case GL_ALPHA:
1070 case GL_ALPHA4:
1071 case GL_ALPHA8:
1072 case GL_ALPHA12:
1073 case GL_ALPHA16:
Brian Paul976ea9d2011-01-24 19:38:52 -07001074 return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1075 case GL_LUMINANCE:
1076 case GL_LUMINANCE4:
1077 case GL_LUMINANCE8:
1078 case GL_LUMINANCE12:
1079 case GL_LUMINANCE16:
1080 return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1081 case GL_LUMINANCE_ALPHA:
1082 case GL_LUMINANCE4_ALPHA4:
1083 case GL_LUMINANCE6_ALPHA2:
1084 case GL_LUMINANCE8_ALPHA8:
1085 case GL_LUMINANCE12_ALPHA4:
1086 case GL_LUMINANCE12_ALPHA12:
1087 case GL_LUMINANCE16_ALPHA16:
1088 return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
1089 case GL_INTENSITY:
1090 case GL_INTENSITY4:
1091 case GL_INTENSITY8:
1092 case GL_INTENSITY12:
1093 case GL_INTENSITY16:
1094 return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
Brian Paulf41bbc72011-01-24 19:38:52 -07001095 case GL_RGB:
1096 case GL_R3_G3_B2:
1097 case GL_RGB4:
1098 case GL_RGB5:
1099 case GL_RGB8:
1100 case GL_RGB10:
1101 case GL_RGB12:
1102 case GL_RGB16:
1103 case GL_SRGB8_EXT:
1104 return GL_RGB;
1105 case GL_RGBA:
1106 case GL_RGBA2:
1107 case GL_RGBA4:
1108 case GL_RGB5_A1:
1109 case GL_RGBA8:
1110 case GL_RGB10_A2:
1111 case GL_RGBA12:
1112 case GL_RGBA16:
Brian Paulf41bbc72011-01-24 19:38:52 -07001113 case GL_SRGB8_ALPHA8_EXT:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001114 return GL_RGBA;
1115 case GL_STENCIL_INDEX:
1116 case GL_STENCIL_INDEX1_EXT:
1117 case GL_STENCIL_INDEX4_EXT:
1118 case GL_STENCIL_INDEX8_EXT:
1119 case GL_STENCIL_INDEX16_EXT:
1120 return GL_STENCIL_INDEX;
1121 case GL_DEPTH_COMPONENT:
Brian Paul2c6f9112005-02-24 05:47:06 +00001122 case GL_DEPTH_COMPONENT16:
1123 case GL_DEPTH_COMPONENT24:
1124 case GL_DEPTH_COMPONENT32:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001125 return GL_DEPTH_COMPONENT;
Brian Paulf41bbc72011-01-24 19:38:52 -07001126 case GL_DEPTH_STENCIL_EXT:
1127 case GL_DEPTH24_STENCIL8_EXT:
1128 if (ctx->Extensions.EXT_packed_depth_stencil)
1129 return GL_DEPTH_STENCIL_EXT;
1130 else
1131 return 0;
Marek Olšák11652802011-06-01 15:48:51 +02001132 case GL_DEPTH_COMPONENT32F:
1133 if (ctx->Extensions.ARB_depth_buffer_float)
1134 return GL_DEPTH_COMPONENT;
1135 else
1136 return 0;
1137 case GL_DEPTH32F_STENCIL8:
1138 if (ctx->Extensions.ARB_depth_buffer_float)
1139 return GL_DEPTH_STENCIL;
1140 else
1141 return 0;
Brian Pauld3015652011-01-24 19:38:52 -07001142 case GL_RED:
1143 case GL_R8:
1144 case GL_R16:
1145 return ctx->Extensions.ARB_texture_rg ? GL_RED : 0;
1146 case GL_RG:
1147 case GL_RG8:
1148 case GL_RG16:
1149 return ctx->Extensions.ARB_texture_rg ? GL_RG : 0;
Marek Olšák0be36992011-03-18 13:44:51 +01001150 /* signed normalized texture formats */
1151 case GL_RED_SNORM:
1152 case GL_R8_SNORM:
1153 case GL_R16_SNORM:
1154 return ctx->Extensions.EXT_texture_snorm ? GL_RED : 0;
1155 case GL_RG_SNORM:
1156 case GL_RG8_SNORM:
1157 case GL_RG16_SNORM:
1158 return ctx->Extensions.EXT_texture_snorm ? GL_RG : 0;
1159 case GL_RGB_SNORM:
1160 case GL_RGB8_SNORM:
1161 case GL_RGB16_SNORM:
1162 return ctx->Extensions.EXT_texture_snorm ? GL_RGB : 0;
1163 case GL_RGBA_SNORM:
1164 case GL_RGBA8_SNORM:
1165 case GL_RGBA16_SNORM:
1166 return ctx->Extensions.EXT_texture_snorm ? GL_RGBA : 0;
1167 case GL_ALPHA_SNORM:
1168 case GL_ALPHA8_SNORM:
1169 case GL_ALPHA16_SNORM:
1170 return ctx->Extensions.EXT_texture_snorm &&
1171 ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1172 case GL_LUMINANCE_SNORM:
1173 case GL_LUMINANCE8_SNORM:
1174 case GL_LUMINANCE16_SNORM:
1175 return ctx->Extensions.EXT_texture_snorm &&
1176 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1177 case GL_LUMINANCE_ALPHA_SNORM:
1178 case GL_LUMINANCE8_ALPHA8_SNORM:
1179 case GL_LUMINANCE16_ALPHA16_SNORM:
1180 return ctx->Extensions.EXT_texture_snorm &&
1181 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
1182 case GL_INTENSITY_SNORM:
1183 case GL_INTENSITY8_SNORM:
1184 case GL_INTENSITY16_SNORM:
1185 return ctx->Extensions.EXT_texture_snorm &&
1186 ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
Marek Olšák15f99d12011-02-16 00:35:44 +01001187 case GL_R16F:
1188 case GL_R32F:
1189 return ctx->Extensions.ARB_texture_rg &&
1190 ctx->Extensions.ARB_texture_float ? GL_RED : 0;
1191 case GL_RG16F:
1192 case GL_RG32F:
1193 return ctx->Extensions.ARB_texture_rg &&
1194 ctx->Extensions.ARB_texture_float ? GL_RG : 0;
1195 case GL_RGB16F:
1196 case GL_RGB32F:
1197 return ctx->Extensions.ARB_texture_float ? GL_RGB : 0;
1198 case GL_RGBA16F:
1199 case GL_RGBA32F:
1200 return ctx->Extensions.ARB_texture_float ? GL_RGBA : 0;
1201 case GL_ALPHA16F_ARB:
1202 case GL_ALPHA32F_ARB:
1203 return ctx->Extensions.ARB_texture_float &&
1204 ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1205 case GL_LUMINANCE16F_ARB:
1206 case GL_LUMINANCE32F_ARB:
1207 return ctx->Extensions.ARB_texture_float &&
1208 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1209 case GL_LUMINANCE_ALPHA16F_ARB:
1210 case GL_LUMINANCE_ALPHA32F_ARB:
1211 return ctx->Extensions.ARB_texture_float &&
1212 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
1213 case GL_INTENSITY16F_ARB:
1214 case GL_INTENSITY32F_ARB:
1215 return ctx->Extensions.ARB_texture_float &&
1216 ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
Marek Olšák9d7698c2011-04-26 02:18:24 +02001217 case GL_RGB9_E5:
1218 return ctx->Extensions.EXT_texture_shared_exponent ? GL_RGB : 0;
Marek Olšák631d23d2011-04-26 02:27:25 +02001219 case GL_R11F_G11F_B10F:
1220 return ctx->Extensions.EXT_packed_float ? GL_RGB : 0;
Dave Airlie9c697a92011-10-04 20:59:40 +01001221
1222 case GL_RGBA8UI_EXT:
1223 case GL_RGBA16UI_EXT:
1224 case GL_RGBA32UI_EXT:
1225 case GL_RGBA8I_EXT:
1226 case GL_RGBA16I_EXT:
1227 case GL_RGBA32I_EXT:
Marek Olšák3363e872012-01-22 20:25:42 +01001228 return ctx->VersionMajor >= 3 ||
1229 ctx->Extensions.EXT_texture_integer ? GL_RGBA : 0;
Dave Airlie9c697a92011-10-04 20:59:40 +01001230
1231 case GL_RGB8UI_EXT:
1232 case GL_RGB16UI_EXT:
1233 case GL_RGB32UI_EXT:
1234 case GL_RGB8I_EXT:
1235 case GL_RGB16I_EXT:
1236 case GL_RGB32I_EXT:
Marek Olšák3363e872012-01-22 20:25:42 +01001237 return ctx->VersionMajor >= 3 ||
1238 ctx->Extensions.EXT_texture_integer ? GL_RGB : 0;
Dave Airlie9c697a92011-10-04 20:59:40 +01001239
1240 case GL_R8UI:
1241 case GL_R8I:
1242 case GL_R16UI:
1243 case GL_R16I:
1244 case GL_R32UI:
1245 case GL_R32I:
Marek Olšák3363e872012-01-22 20:25:42 +01001246 return ctx->VersionMajor >= 3 ||
1247 (ctx->Extensions.ARB_texture_rg &&
1248 ctx->Extensions.EXT_texture_integer) ? GL_RED : 0;
Dave Airlie9c697a92011-10-04 20:59:40 +01001249
1250 case GL_RG8UI:
1251 case GL_RG8I:
1252 case GL_RG16UI:
1253 case GL_RG16I:
1254 case GL_RG32UI:
1255 case GL_RG32I:
Marek Olšák3363e872012-01-22 20:25:42 +01001256 return ctx->VersionMajor >= 3 ||
1257 (ctx->Extensions.ARB_texture_rg &&
1258 ctx->Extensions.EXT_texture_integer) ? GL_RG : 0;
Brian Paul45bd5c42011-12-16 08:44:43 -07001259
Dave Airlie9c697a92011-10-04 20:59:40 +01001260 case GL_INTENSITY8I_EXT:
1261 case GL_INTENSITY8UI_EXT:
1262 case GL_INTENSITY16I_EXT:
1263 case GL_INTENSITY16UI_EXT:
1264 case GL_INTENSITY32I_EXT:
1265 case GL_INTENSITY32UI_EXT:
1266 return ctx->Extensions.EXT_texture_integer &&
1267 ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
1268
1269 case GL_LUMINANCE8I_EXT:
1270 case GL_LUMINANCE8UI_EXT:
1271 case GL_LUMINANCE16I_EXT:
1272 case GL_LUMINANCE16UI_EXT:
1273 case GL_LUMINANCE32I_EXT:
1274 case GL_LUMINANCE32UI_EXT:
1275 return ctx->Extensions.EXT_texture_integer &&
1276 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1277
1278 case GL_LUMINANCE_ALPHA8I_EXT:
1279 case GL_LUMINANCE_ALPHA8UI_EXT:
1280 case GL_LUMINANCE_ALPHA16I_EXT:
1281 case GL_LUMINANCE_ALPHA16UI_EXT:
1282 case GL_LUMINANCE_ALPHA32I_EXT:
1283 case GL_LUMINANCE_ALPHA32UI_EXT:
1284 return ctx->Extensions.EXT_texture_integer &&
1285 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
Dave Airlief449be62011-11-27 16:21:02 +00001286
Marek Olšák636802f2012-01-22 20:21:36 +01001287 case GL_ALPHA8I_EXT:
1288 case GL_ALPHA8UI_EXT:
1289 case GL_ALPHA16I_EXT:
1290 case GL_ALPHA16UI_EXT:
1291 case GL_ALPHA32I_EXT:
1292 case GL_ALPHA32UI_EXT:
1293 return ctx->Extensions.EXT_texture_integer &&
1294 ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1295
Dave Airlief449be62011-11-27 16:21:02 +00001296 case GL_RGB10_A2UI:
1297 return ctx->Extensions.ARB_texture_rgb10_a2ui ? GL_RGBA : 0;
Brian Paulf41bbc72011-01-24 19:38:52 -07001298 default:
Eric Anholt65c41d52011-01-13 10:05:50 -08001299 return 0;
Brian Paulf41bbc72011-01-24 19:38:52 -07001300 }
Brian Paul463642c2005-02-08 02:06:00 +00001301}
1302
1303
Marek Olšákdf818d52011-03-06 05:26:12 +01001304/**
1305 * Invalidate a renderbuffer attachment. Called from _mesa_HashWalk().
1306 */
1307static void
1308invalidate_rb(GLuint key, void *data, void *userData)
1309{
1310 struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
1311 struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData;
1312
1313 /* If this is a user-created FBO */
Brian Paul36ede892012-01-12 09:17:23 -07001314 if (_mesa_is_user_fbo(fb)) {
Marek Olšákdf818d52011-03-06 05:26:12 +01001315 GLuint i;
1316 for (i = 0; i < BUFFER_COUNT; i++) {
1317 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1318 if (att->Type == GL_RENDERBUFFER &&
1319 att->Renderbuffer == rb) {
1320 /* Mark fb status as indeterminate to force re-validation */
1321 fb->_Status = 0;
Marek Olšáka674ef72011-03-07 23:33:36 +01001322 return;
Marek Olšákdf818d52011-03-06 05:26:12 +01001323 }
1324 }
1325 }
1326}
1327
1328
Brian Paul4f3514e2009-01-22 15:19:56 -07001329/** sentinal value, see below */
1330#define NO_SAMPLES 1000
1331
1332
1333/**
1334 * Helper function used by _mesa_RenderbufferStorageEXT() and
1335 * _mesa_RenderbufferStorageMultisample().
1336 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
1337 */
1338static void
1339renderbuffer_storage(GLenum target, GLenum internalFormat,
1340 GLsizei width, GLsizei height, GLsizei samples)
Brian Paulddc82ee2005-02-05 19:56:45 +00001341{
Brian Paul4f3514e2009-01-22 15:19:56 -07001342 const char *func = samples == NO_SAMPLES ?
1343 "glRenderbufferStorage" : "RenderbufferStorageMultisample";
Brian Paul2c6f9112005-02-24 05:47:06 +00001344 struct gl_renderbuffer *rb;
Brian Paul463642c2005-02-08 02:06:00 +00001345 GLenum baseFormat;
Brian Paulddc82ee2005-02-05 19:56:45 +00001346 GET_CURRENT_CONTEXT(ctx);
1347
1348 ASSERT_OUTSIDE_BEGIN_END(ctx);
1349
Brian Paul463642c2005-02-08 02:06:00 +00001350 if (target != GL_RENDERBUFFER_EXT) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001351 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001352 return;
1353 }
1354
Brian Paul59e0faa2006-03-15 17:48:00 +00001355 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
Brian Paul463642c2005-02-08 02:06:00 +00001356 if (baseFormat == 0) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001357 _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001358 return;
1359 }
1360
Yuanhan Liu49f84472011-10-25 15:36:59 +08001361 if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001362 _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001363 return;
1364 }
1365
Yuanhan Liu49f84472011-10-25 15:36:59 +08001366 if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001367 _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
1368 return;
1369 }
1370
1371 if (samples == NO_SAMPLES) {
1372 /* NumSamples == 0 indicates non-multisampling */
1373 samples = 0;
1374 }
Brian Paulca0d0482010-01-27 17:01:54 -07001375 else if (samples > (GLsizei) ctx->Const.MaxSamples) {
Brian Paul722d9762009-01-20 16:58:49 -07001376 /* note: driver may choose to use more samples than what's requested */
Brian Paul4f3514e2009-01-22 15:19:56 -07001377 _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001378 return;
1379 }
1380
Brian Paul2c6f9112005-02-24 05:47:06 +00001381 rb = ctx->CurrentRenderbuffer;
Brian Paul2c6f9112005-02-24 05:47:06 +00001382 if (!rb) {
Vinson Leec5dde532010-09-02 16:03:32 -07001383 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
Brian Paul463642c2005-02-08 02:06:00 +00001384 return;
1385 }
1386
Brian Paul474f28e2005-10-08 14:41:17 +00001387 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1388
Brian Paul311bcf52005-11-18 02:24:14 +00001389 if (rb->InternalFormat == internalFormat &&
Brian Paul13abf912006-04-13 19:17:13 +00001390 rb->Width == (GLuint) width &&
Eric Anholt0e8d1562012-01-11 13:46:43 -08001391 rb->Height == (GLuint) height &&
1392 rb->NumSamples == samples) {
Brian Paul311bcf52005-11-18 02:24:14 +00001393 /* no change in allocation needed */
1394 return;
1395 }
1396
Brian Paulea4fe662006-03-26 05:22:17 +00001397 /* These MUST get set by the AllocStorage func */
Brian Paul45e76d22009-10-08 20:27:27 -06001398 rb->Format = MESA_FORMAT_NONE;
Brian Paul4f3514e2009-01-22 15:19:56 -07001399 rb->NumSamples = samples;
Brian Paulea4fe662006-03-26 05:22:17 +00001400
Brian Paul2c6f9112005-02-24 05:47:06 +00001401 /* Now allocate the storage */
1402 ASSERT(rb->AllocStorage);
1403 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
1404 /* No error - check/set fields now */
Brian Paul45e76d22009-10-08 20:27:27 -06001405 assert(rb->Format != MESA_FORMAT_NONE);
Brian Paul13abf912006-04-13 19:17:13 +00001406 assert(rb->Width == (GLuint) width);
1407 assert(rb->Height == (GLuint) height);
Brian Paulea4fe662006-03-26 05:22:17 +00001408 rb->InternalFormat = internalFormat;
Brian Paula8dafe72010-02-25 19:03:55 -07001409 rb->_BaseFormat = baseFormat;
Brian Paul45e76d22009-10-08 20:27:27 -06001410 assert(rb->_BaseFormat != 0);
Brian Paul2c6f9112005-02-24 05:47:06 +00001411 }
1412 else {
1413 /* Probably ran out of memory - clear the fields */
1414 rb->Width = 0;
1415 rb->Height = 0;
Brian Paul45e76d22009-10-08 20:27:27 -06001416 rb->Format = MESA_FORMAT_NONE;
Brian Paul2c6f9112005-02-24 05:47:06 +00001417 rb->InternalFormat = GL_NONE;
1418 rb->_BaseFormat = GL_NONE;
Brian Paul4f3514e2009-01-22 15:19:56 -07001419 rb->NumSamples = 0;
Brian Paul463642c2005-02-08 02:06:00 +00001420 }
1421
Marek Olšákdf818d52011-03-06 05:26:12 +01001422 /* Invalidate the framebuffers the renderbuffer is attached in. */
1423 if (rb->AttachedAnytime) {
1424 _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb);
1425 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001426}
1427
Brian Paul23c5b212010-05-28 13:33:03 -06001428
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001429#if FEATURE_OES_EGL_image
1430void GLAPIENTRY
Brian Paul23c5b212010-05-28 13:33:03 -06001431_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001432{
Brian Paul51b79922010-02-24 11:57:26 -07001433 struct gl_renderbuffer *rb;
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001434 GET_CURRENT_CONTEXT(ctx);
1435 ASSERT_OUTSIDE_BEGIN_END(ctx);
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001436
Chia-I Wu2002e4d02010-04-06 17:46:17 +08001437 if (!ctx->Extensions.OES_EGL_image) {
1438 _mesa_error(ctx, GL_INVALID_OPERATION,
1439 "glEGLImageTargetRenderbufferStorageOES(unsupported)");
1440 return;
1441 }
1442
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001443 if (target != GL_RENDERBUFFER) {
Brian Paul23c5b212010-05-28 13:33:03 -06001444 _mesa_error(ctx, GL_INVALID_ENUM,
1445 "EGLImageTargetRenderbufferStorageOES");
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001446 return;
1447 }
1448
1449 rb = ctx->CurrentRenderbuffer;
1450 if (!rb) {
Brian Paul23c5b212010-05-28 13:33:03 -06001451 _mesa_error(ctx, GL_INVALID_OPERATION,
1452 "EGLImageTargetRenderbufferStorageOES");
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001453 return;
1454 }
1455
1456 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1457
1458 ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1459}
1460#endif
Brian Paulddc82ee2005-02-05 19:56:45 +00001461
Brian Paul23c5b212010-05-28 13:33:03 -06001462
Brian Paul45e76d22009-10-08 20:27:27 -06001463/**
1464 * Helper function for _mesa_GetRenderbufferParameterivEXT() and
1465 * _mesa_GetFramebufferAttachmentParameterivEXT()
1466 * We have to be careful to respect the base format. For example, if a
1467 * renderbuffer/texture was created with internalFormat=GL_RGB but the
1468 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
1469 * we need to return zero.
1470 */
1471static GLint
1472get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
1473{
Brian Paulf0b6e9a2011-11-23 15:33:45 -07001474 if (_mesa_base_format_has_channel(baseFormat, pname))
1475 return _mesa_get_format_bits(format, pname);
1476 else
Brian Paul45e76d22009-10-08 20:27:27 -06001477 return 0;
Brian Paul45e76d22009-10-08 20:27:27 -06001478}
1479
1480
1481
Brian Paul1864c7d2005-02-08 03:46:37 +00001482void GLAPIENTRY
Brian Paul4f3514e2009-01-22 15:19:56 -07001483_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1484 GLsizei width, GLsizei height)
1485{
Brian Paul722d9762009-01-20 16:58:49 -07001486 /* GL_ARB_fbo says calling this function is equivalent to calling
1487 * glRenderbufferStorageMultisample() with samples=0. We pass in
1488 * a token value here just for error reporting purposes.
1489 */
Brian Paul4f3514e2009-01-22 15:19:56 -07001490 renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
1491}
1492
1493
1494void GLAPIENTRY
Brian Paul777a2ef2009-01-22 15:17:42 -07001495_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
Brian Paul4f3514e2009-01-22 15:19:56 -07001496 GLenum internalFormat,
Brian Paul777a2ef2009-01-22 15:17:42 -07001497 GLsizei width, GLsizei height)
1498{
Brian Paul4f3514e2009-01-22 15:19:56 -07001499 renderbuffer_storage(target, internalFormat, width, height, samples);
Brian Paul777a2ef2009-01-22 15:17:42 -07001500}
1501
Brian Paul23c5b212010-05-28 13:33:03 -06001502
1503/**
1504 * OpenGL ES version of glRenderBufferStorage.
1505 */
Kristian Høgsberg61d94dd2010-04-22 21:11:56 -04001506void GLAPIENTRY
1507_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1508 GLsizei width, GLsizei height)
1509{
1510 switch (internalFormat) {
1511 case GL_RGB565:
1512 /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
1513 /* choose a closest format */
1514 internalFormat = GL_RGB5;
1515 break;
1516 default:
1517 break;
1518 }
Brian Paul777a2ef2009-01-22 15:17:42 -07001519
Kristian Høgsberg61d94dd2010-04-22 21:11:56 -04001520 renderbuffer_storage(target, internalFormat, width, height, 0);
1521}
Brian Paul777a2ef2009-01-22 15:17:42 -07001522
Brian Paul23c5b212010-05-28 13:33:03 -06001523
Brian Paul777a2ef2009-01-22 15:17:42 -07001524void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001525_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
1526{
Brian Paul722d9762009-01-20 16:58:49 -07001527 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001528 GET_CURRENT_CONTEXT(ctx);
1529
1530 ASSERT_OUTSIDE_BEGIN_END(ctx);
1531
Brian Paul463642c2005-02-08 02:06:00 +00001532 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001533 _mesa_error(ctx, GL_INVALID_ENUM,
1534 "glGetRenderbufferParameterivEXT(target)");
1535 return;
1536 }
1537
Brian Paul722d9762009-01-20 16:58:49 -07001538 rb = ctx->CurrentRenderbuffer;
1539 if (!rb) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001540 _mesa_error(ctx, GL_INVALID_OPERATION,
1541 "glGetRenderbufferParameterivEXT");
1542 return;
1543 }
1544
Brian Paul800e5532009-11-02 15:39:39 -07001545 /* No need to flush here since we're just quering state which is
1546 * not effected by rendering.
1547 */
Brian Paul474f28e2005-10-08 14:41:17 +00001548
Brian Paul463642c2005-02-08 02:06:00 +00001549 switch (pname) {
1550 case GL_RENDERBUFFER_WIDTH_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001551 *params = rb->Width;
Brian Paul463642c2005-02-08 02:06:00 +00001552 return;
1553 case GL_RENDERBUFFER_HEIGHT_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001554 *params = rb->Height;
Brian Paul463642c2005-02-08 02:06:00 +00001555 return;
1556 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001557 *params = rb->InternalFormat;
Brian Paul463642c2005-02-08 02:06:00 +00001558 return;
Brian Paul1b939532005-05-31 23:55:21 +00001559 case GL_RENDERBUFFER_RED_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001560 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001561 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001562 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001563 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001564 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
Brian Paul45e76d22009-10-08 20:27:27 -06001565 *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
Brian Paul1b939532005-05-31 23:55:21 +00001566 break;
Brian Paul722d9762009-01-20 16:58:49 -07001567 case GL_RENDERBUFFER_SAMPLES:
1568 if (ctx->Extensions.ARB_framebuffer_object) {
1569 *params = rb->NumSamples;
1570 break;
1571 }
1572 /* fallthrough */
Brian Paul463642c2005-02-08 02:06:00 +00001573 default:
1574 _mesa_error(ctx, GL_INVALID_ENUM,
1575 "glGetRenderbufferParameterivEXT(target)");
1576 return;
1577 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001578}
1579
1580
Brian Paul1864c7d2005-02-08 03:46:37 +00001581GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001582_mesa_IsFramebufferEXT(GLuint framebuffer)
1583{
Brian Paulddc82ee2005-02-05 19:56:45 +00001584 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +00001585 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +00001586 if (framebuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00001587 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +00001588 if (rb != NULL && rb != &DummyFramebuffer)
1589 return GL_TRUE;
1590 }
1591 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +00001592}
1593
1594
briana492ab72009-11-10 15:33:31 -07001595/**
1596 * Check if any of the attachments of the given framebuffer are textures
1597 * (render to texture). Call ctx->Driver.RenderTexture() for such
1598 * attachments.
1599 */
Brian Paulea4fe662006-03-26 05:22:17 +00001600static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001601check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
Brian Paulea4fe662006-03-26 05:22:17 +00001602{
1603 GLuint i;
1604 ASSERT(ctx->Driver.RenderTexture);
briana65b84d2009-11-10 18:02:03 -07001605
Brian Paul36ede892012-01-12 09:17:23 -07001606 if (_mesa_is_winsys_fbo(fb))
briana65b84d2009-11-10 18:02:03 -07001607 return; /* can't render to texture with winsys framebuffers */
1608
Brian Paulea4fe662006-03-26 05:22:17 +00001609 for (i = 0; i < BUFFER_COUNT; i++) {
1610 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
Brian Pauldb0f9e72011-04-05 07:51:01 -06001611 if (att->Texture && _mesa_get_attachment_teximage(att)) {
Brian Paulea4fe662006-03-26 05:22:17 +00001612 ctx->Driver.RenderTexture(ctx, fb, att);
1613 }
1614 }
1615}
1616
1617
Brian Paul0e31e022005-12-01 00:25:00 +00001618/**
1619 * Examine all the framebuffer's attachments to see if any are textures.
1620 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
1621 * notify the device driver that the texture image may have changed.
1622 */
1623static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001624check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
Brian Paul0e31e022005-12-01 00:25:00 +00001625{
Brian Paul36ede892012-01-12 09:17:23 -07001626 if (_mesa_is_winsys_fbo(fb))
briana65b84d2009-11-10 18:02:03 -07001627 return; /* can't render to texture with winsys framebuffers */
1628
Brian Paul0e31e022005-12-01 00:25:00 +00001629 if (ctx->Driver.FinishRenderTexture) {
1630 GLuint i;
1631 for (i = 0; i < BUFFER_COUNT; i++) {
1632 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
Brian8b361662007-11-09 08:55:49 -07001633 if (att->Texture && att->Renderbuffer) {
Brian Paul519b23b2006-03-20 18:51:57 +00001634 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +00001635 }
1636 }
1637 }
1638}
1639
1640
Brian Paul1864c7d2005-02-08 03:46:37 +00001641void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001642_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
1643{
briane6f60d32009-11-10 15:47:34 -07001644 struct gl_framebuffer *newDrawFb, *newReadFb;
briand96e55f2009-11-10 15:50:22 -07001645 struct gl_framebuffer *oldDrawFb, *oldReadFb;
Brian Paul0bffb112005-11-08 14:45:48 +00001646 GLboolean bindReadBuf, bindDrawBuf;
Brian Paulddc82ee2005-02-05 19:56:45 +00001647 GET_CURRENT_CONTEXT(ctx);
1648
Brian Paul1bc59bf2009-01-22 15:07:34 -07001649#ifdef DEBUG
1650 if (ctx->Extensions.ARB_framebuffer_object) {
1651 ASSERT(ctx->Extensions.EXT_framebuffer_object);
1652 ASSERT(ctx->Extensions.EXT_framebuffer_blit);
1653 }
1654#endif
1655
Brian Paulddc82ee2005-02-05 19:56:45 +00001656 ASSERT_OUTSIDE_BEGIN_END(ctx);
1657
Brian Paulea4fe662006-03-26 05:22:17 +00001658 if (!ctx->Extensions.EXT_framebuffer_object) {
1659 _mesa_error(ctx, GL_INVALID_OPERATION,
1660 "glBindFramebufferEXT(unsupported)");
1661 return;
1662 }
1663
Brian Paul0bffb112005-11-08 14:45:48 +00001664 switch (target) {
1665#if FEATURE_EXT_framebuffer_blit
1666 case GL_DRAW_FRAMEBUFFER_EXT:
1667 if (!ctx->Extensions.EXT_framebuffer_blit) {
1668 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1669 return;
1670 }
1671 bindDrawBuf = GL_TRUE;
1672 bindReadBuf = GL_FALSE;
1673 break;
1674 case GL_READ_FRAMEBUFFER_EXT:
1675 if (!ctx->Extensions.EXT_framebuffer_blit) {
1676 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1677 return;
1678 }
1679 bindDrawBuf = GL_FALSE;
1680 bindReadBuf = GL_TRUE;
1681 break;
1682#endif
1683 case GL_FRAMEBUFFER_EXT:
1684 bindDrawBuf = GL_TRUE;
1685 bindReadBuf = GL_TRUE;
1686 break;
1687 default:
Brian Pauleba4ff62005-09-06 21:22:16 +00001688 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +00001689 return;
1690 }
1691
Brian Paul3deaa012005-02-07 05:08:24 +00001692 if (framebuffer) {
Brian Paule4b23562005-05-04 20:11:35 +00001693 /* Binding a user-created framebuffer object */
briane6f60d32009-11-10 15:47:34 -07001694 newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
1695 if (newDrawFb == &DummyFramebuffer) {
Brian Paul923b6fc2005-02-08 04:08:56 +00001696 /* ID was reserved, but no real framebuffer object made yet */
briane6f60d32009-11-10 15:47:34 -07001697 newDrawFb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001698 }
briane6f60d32009-11-10 15:47:34 -07001699 else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
Brian Paul1bc59bf2009-01-22 15:07:34 -07001700 /* All FBO IDs must be Gen'd */
1701 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
1702 return;
1703 }
1704
briane6f60d32009-11-10 15:47:34 -07001705 if (!newDrawFb) {
Brian Paul3deaa012005-02-07 05:08:24 +00001706 /* create new framebuffer object */
briane6f60d32009-11-10 15:47:34 -07001707 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
1708 if (!newDrawFb) {
Brian Paul3deaa012005-02-07 05:08:24 +00001709 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1710 return;
1711 }
briane6f60d32009-11-10 15:47:34 -07001712 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
Brian Paul3deaa012005-02-07 05:08:24 +00001713 }
briane6f60d32009-11-10 15:47:34 -07001714 newReadFb = newDrawFb;
Brian Paul3deaa012005-02-07 05:08:24 +00001715 }
Brian Paul463642c2005-02-08 02:06:00 +00001716 else {
Brian Paule4b23562005-05-04 20:11:35 +00001717 /* Binding the window system framebuffer (which was originally set
1718 * with MakeCurrent).
1719 */
briane6f60d32009-11-10 15:47:34 -07001720 newDrawFb = ctx->WinSysDrawBuffer;
1721 newReadFb = ctx->WinSysReadBuffer;
Brian Paul3deaa012005-02-07 05:08:24 +00001722 }
1723
briane6f60d32009-11-10 15:47:34 -07001724 ASSERT(newDrawFb);
1725 ASSERT(newDrawFb != &DummyFramebuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001726
briana65b84d2009-11-10 18:02:03 -07001727 /* save pointers to current/old framebuffers */
briand96e55f2009-11-10 15:50:22 -07001728 oldDrawFb = ctx->DrawBuffer;
1729 oldReadFb = ctx->ReadBuffer;
1730
briana65b84d2009-11-10 18:02:03 -07001731 /* check if really changing bindings */
1732 if (oldDrawFb == newDrawFb)
1733 bindDrawBuf = GL_FALSE;
1734 if (oldReadFb == newReadFb)
1735 bindReadBuf = GL_FALSE;
1736
Brian Paulea4fe662006-03-26 05:22:17 +00001737 /*
Brian Paul16144632009-02-26 14:49:24 -07001738 * OK, now bind the new Draw/Read framebuffers, if they're changing.
briana65b84d2009-11-10 18:02:03 -07001739 *
1740 * We also check if we're beginning and/or ending render-to-texture.
1741 * When a framebuffer with texture attachments is unbound, call
1742 * ctx->Driver.FinishRenderTexture().
1743 * When a framebuffer with texture attachments is bound, call
1744 * ctx->Driver.RenderTexture().
1745 *
1746 * Note that if the ReadBuffer has texture attachments we don't consider
1747 * that a render-to-texture case.
Brian Paulea4fe662006-03-26 05:22:17 +00001748 */
Brian Paul0bffb112005-11-08 14:45:48 +00001749 if (bindReadBuf) {
briana65b84d2009-11-10 18:02:03 -07001750 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
brianbc569cd2009-11-10 16:00:35 -07001751
briana65b84d2009-11-10 18:02:03 -07001752 /* check if old readbuffer was render-to-texture */
1753 check_end_texture_render(ctx, oldReadFb);
1754
1755 _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001756 }
1757
1758 if (bindDrawBuf) {
briana65b84d2009-11-10 18:02:03 -07001759 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian32d86eb2007-08-16 18:52:48 +01001760
Eric Anholta1fd13f2012-02-10 12:05:16 -08001761 /* check if old framebuffer had any texture attachments */
1762 if (oldDrawFb)
briana65b84d2009-11-10 18:02:03 -07001763 check_end_texture_render(ctx, oldDrawFb);
brianbc569cd2009-11-10 16:00:35 -07001764
briana65b84d2009-11-10 18:02:03 -07001765 /* check if newly bound framebuffer has any texture attachments */
1766 check_begin_texture_render(ctx, newDrawFb);
1767
1768 _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001769 }
Brian Paul59e0faa2006-03-15 17:48:00 +00001770
Brian Paul16144632009-02-26 14:49:24 -07001771 if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
briane6f60d32009-11-10 15:47:34 -07001772 ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
Brian Paul59e0faa2006-03-15 17:48:00 +00001773 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001774}
1775
1776
Brian Paul1864c7d2005-02-08 03:46:37 +00001777void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001778_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1779{
1780 GLint i;
1781 GET_CURRENT_CONTEXT(ctx);
1782
1783 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul800e5532009-11-02 15:39:39 -07001784 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00001785
1786 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +00001787 if (framebuffers[i] > 0) {
1788 struct gl_framebuffer *fb;
Brian Paulea4fe662006-03-26 05:22:17 +00001789 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +00001790 if (fb) {
Brian Paule4b23562005-05-04 20:11:35 +00001791 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
Brian Paul91802fd2005-10-04 16:01:02 +00001792
1793 /* check if deleting currently bound framebuffer object */
Erik Wien68ca19a2010-01-26 13:19:30 -07001794 if (ctx->Extensions.EXT_framebuffer_blit) {
1795 /* separate draw/read binding points */
1796 if (fb == ctx->DrawBuffer) {
1797 /* bind default */
1798 ASSERT(fb->RefCount >= 2);
1799 _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1800 }
1801 if (fb == ctx->ReadBuffer) {
1802 /* bind default */
1803 ASSERT(fb->RefCount >= 2);
1804 _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1805 }
Brian Pauld0f13fa2009-01-21 11:17:45 -07001806 }
Erik Wien68ca19a2010-01-26 13:19:30 -07001807 else {
1808 /* only one binding point for read/draw buffers */
1809 if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
1810 /* bind default */
1811 ASSERT(fb->RefCount >= 2);
1812 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
Brian Paul45bd5c42011-12-16 08:44:43 -07001813 }
Brian Paul91802fd2005-10-04 16:01:02 +00001814 }
1815
Brian Paul3deaa012005-02-07 05:08:24 +00001816 /* remove from hash table immediately, to free the ID */
1817 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +00001818
Brian Paul1864c7d2005-02-08 03:46:37 +00001819 if (fb != &DummyFramebuffer) {
1820 /* But the object will not be freed until it's no longer
1821 * bound in any context.
1822 */
Brian Pauld5229442009-02-09 08:30:55 -07001823 _mesa_reference_framebuffer(&fb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +00001824 }
1825 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001826 }
1827 }
1828}
1829
1830
Brian Paul1864c7d2005-02-08 03:46:37 +00001831void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001832_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1833{
1834 GET_CURRENT_CONTEXT(ctx);
1835 GLuint first;
1836 GLint i;
1837
1838 ASSERT_OUTSIDE_BEGIN_END(ctx);
1839
1840 if (n < 0) {
1841 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1842 return;
1843 }
1844
1845 if (!framebuffers)
1846 return;
1847
1848 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1849
1850 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001851 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001852 framebuffers[i] = name;
1853 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001854 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001855 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001856 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001857 }
1858}
1859
1860
1861
Brian Paul1864c7d2005-02-08 03:46:37 +00001862GLenum GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001863_mesa_CheckFramebufferStatusEXT(GLenum target)
1864{
Brian Paul0bffb112005-11-08 14:45:48 +00001865 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001866 GET_CURRENT_CONTEXT(ctx);
1867
Brian Paule4b23562005-05-04 20:11:35 +00001868 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001869
Brian Paulc6991432011-02-28 18:24:25 -07001870 buffer = get_framebuffer_target(ctx, target);
1871 if (!buffer) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001872 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
Brian Paulc6991432011-02-28 18:24:25 -07001873 return 0;
Brian Paulddc82ee2005-02-05 19:56:45 +00001874 }
1875
Brian Paul36ede892012-01-12 09:17:23 -07001876 if (_mesa_is_winsys_fbo(buffer)) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001877 /* The window system / default framebuffer is always complete */
1878 return GL_FRAMEBUFFER_COMPLETE_EXT;
1879 }
1880
Brian Paul800e5532009-11-02 15:39:39 -07001881 /* No need to flush here */
Brian Paul474f28e2005-10-08 14:41:17 +00001882
Brian Paul72966362009-01-21 16:28:38 -07001883 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
1884 _mesa_test_framebuffer_completeness(ctx, buffer);
1885 }
1886
Brian Paul0bffb112005-11-08 14:45:48 +00001887 return buffer->_Status;
Brian Paulddc82ee2005-02-05 19:56:45 +00001888}
1889
Brian Paul45bd5c42011-12-16 08:44:43 -07001890
Chad Versacebf8ad172011-11-10 10:19:20 -08001891/**
1892 * Replicate the src attachment point. Used by framebuffer_texture() when
1893 * the same texture is attached at GL_DEPTH_ATTACHMENT and
1894 * GL_STENCIL_ATTACHMENT.
1895 */
1896static void
1897reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb,
1898 gl_buffer_index dst,
1899 gl_buffer_index src)
1900{
1901 struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst];
1902 struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src];
Brian Paulddc82ee2005-02-05 19:56:45 +00001903
Chad Versacebf8ad172011-11-10 10:19:20 -08001904 assert(src_att->Texture != NULL);
Brian Paul45bd5c42011-12-16 08:44:43 -07001905 assert(src_att->Renderbuffer != NULL);
Chad Versacebf8ad172011-11-10 10:19:20 -08001906
1907 _mesa_reference_texobj(&dst_att->Texture, src_att->Texture);
1908 _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer);
1909 dst_att->Type = src_att->Type;
1910 dst_att->Complete = src_att->Complete;
1911 dst_att->TextureLevel = src_att->TextureLevel;
1912 dst_att->Zoffset = src_att->Zoffset;
1913}
Brian Paulddc82ee2005-02-05 19:56:45 +00001914
Brian Paul45bd5c42011-12-16 08:44:43 -07001915
Brian Paulddc82ee2005-02-05 19:56:45 +00001916/**
Brian Paul534cbbe2012-03-12 11:03:59 -06001917 * Common code called by glFramebufferTexture1D/2D/3DEXT() and
1918 * glFramebufferTextureLayerEXT().
1919 * Note: glFramebufferTextureLayerEXT() has no textarget parameter so we'll
1920 * get textarget=0 in that case.
Brian Paulddc82ee2005-02-05 19:56:45 +00001921 */
Brian Paulea4fe662006-03-26 05:22:17 +00001922static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001923framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001924 GLenum attachment, GLenum textarget, GLuint texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001925 GLint level, GLint zoffset)
Brian Paulddc82ee2005-02-05 19:56:45 +00001926{
Brian Paul2c6f9112005-02-24 05:47:06 +00001927 struct gl_renderbuffer_attachment *att;
Brian Paulea4fe662006-03-26 05:22:17 +00001928 struct gl_texture_object *texObj = NULL;
1929 struct gl_framebuffer *fb;
Anuj Phogatcc5b0ff2012-03-12 10:39:48 -07001930 GLenum maxLevelsTarget;
Brian Paulddc82ee2005-02-05 19:56:45 +00001931
1932 ASSERT_OUTSIDE_BEGIN_END(ctx);
1933
Brian Paulc6991432011-02-28 18:24:25 -07001934 fb = get_framebuffer_target(ctx, target);
1935 if (!fb) {
Brian Paulea4fe662006-03-26 05:22:17 +00001936 _mesa_error(ctx, GL_INVALID_ENUM,
Brian Paul5fec84a2009-01-29 15:01:09 -07001937 "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
Brian Paulddc82ee2005-02-05 19:56:45 +00001938 return;
Brian Paulea4fe662006-03-26 05:22:17 +00001939 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001940
Brian Paulea4fe662006-03-26 05:22:17 +00001941 /* check framebuffer binding */
Brian Paul36ede892012-01-12 09:17:23 -07001942 if (_mesa_is_winsys_fbo(fb)) {
Brian Paulea4fe662006-03-26 05:22:17 +00001943 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001944 "glFramebufferTexture%sEXT", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001945 return;
1946 }
1947
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001948 /* The textarget, level, and zoffset parameters are only validated if
1949 * texture is non-zero.
1950 */
1951 if (texture) {
1952 GLboolean err = GL_TRUE;
1953
1954 texObj = _mesa_lookup_texture(ctx, texture);
1955 if (texObj != NULL) {
Ian Romanickbb372f12007-05-16 15:34:22 -07001956 if (textarget == 0) {
Brian Paul534cbbe2012-03-12 11:03:59 -06001957 /* If textarget == 0 it means we're being called by
1958 * glFramebufferTextureLayer() and textarget is not used.
1959 * The only legal texture types for that function are 3D and
1960 * 1D/2D arrays textures.
1961 */
Ian Romanickbb372f12007-05-16 15:34:22 -07001962 err = (texObj->Target != GL_TEXTURE_3D) &&
1963 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1964 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1965 }
1966 else {
Brian Paul534cbbe2012-03-12 11:03:59 -06001967 /* Make sure textarget is consistent with the texture's type */
Ian Romanickbb372f12007-05-16 15:34:22 -07001968 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
Brian Paul2efa3d42011-11-18 17:39:00 -07001969 ? !_mesa_is_cube_face(textarget)
Ian Romanickbb372f12007-05-16 15:34:22 -07001970 : (texObj->Target != textarget);
1971 }
Brian Paulea4fe662006-03-26 05:22:17 +00001972 }
Brian Paul7a2e32d2010-03-10 10:54:24 -07001973 else {
1974 /* can't render to a non-existant texture */
1975 _mesa_error(ctx, GL_INVALID_OPERATION,
1976 "glFramebufferTexture%sEXT(non existant texture)",
1977 caller);
1978 return;
1979 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001980
1981 if (err) {
Brian Paulea4fe662006-03-26 05:22:17 +00001982 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001983 "glFramebufferTexture%sEXT(texture target mismatch)",
1984 caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001985 return;
1986 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001987
1988 if (texObj->Target == GL_TEXTURE_3D) {
Brian Paulea4fe662006-03-26 05:22:17 +00001989 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1990 if (zoffset < 0 || zoffset >= maxSize) {
1991 _mesa_error(ctx, GL_INVALID_VALUE,
Ian Romanickbb372f12007-05-16 15:34:22 -07001992 "glFramebufferTexture%sEXT(zoffset)", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001993 return;
1994 }
1995 }
Ian Romanickbb372f12007-05-16 15:34:22 -07001996 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1997 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1998 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1999 _mesa_error(ctx, GL_INVALID_VALUE,
2000 "glFramebufferTexture%sEXT(layer)", caller);
2001 return;
2002 }
2003 }
2004
Anuj Phogatcc5b0ff2012-03-12 10:39:48 -07002005 maxLevelsTarget = textarget ? textarget : texObj->Target;
Brian Paul45bd5c42011-12-16 08:44:43 -07002006 if ((level < 0) ||
Anuj Phogatcc5b0ff2012-03-12 10:39:48 -07002007 (level >= _mesa_max_texture_levels(ctx, maxLevelsTarget))) {
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002008 _mesa_error(ctx, GL_INVALID_VALUE,
2009 "glFramebufferTexture%sEXT(level)", caller);
2010 return;
2011 }
Brian Paulea4fe662006-03-26 05:22:17 +00002012 }
2013
2014 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00002015 if (att == NULL) {
2016 _mesa_error(ctx, GL_INVALID_ENUM,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002017 "glFramebufferTexture%sEXT(attachment)", caller);
Brian Paul3deaa012005-02-07 05:08:24 +00002018 return;
2019 }
2020
Brian Paul800e5532009-11-02 15:39:39 -07002021 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paul474f28e2005-10-08 14:41:17 +00002022
Brian Paulea4fe662006-03-26 05:22:17 +00002023 _glthread_LOCK_MUTEX(fb->Mutex);
2024 if (texObj) {
Chad Versacebf8ad172011-11-10 10:19:20 -08002025 if (attachment == GL_DEPTH_ATTACHMENT &&
Paul Berryb9819a02012-04-13 21:50:08 -07002026 texObj == fb->Attachment[BUFFER_STENCIL].Texture &&
2027 level == fb->Attachment[BUFFER_STENCIL].TextureLevel &&
2028 _mesa_tex_target_to_face(textarget) ==
2029 fb->Attachment[BUFFER_STENCIL].CubeMapFace &&
2030 zoffset == fb->Attachment[BUFFER_STENCIL].Zoffset) {
Chad Versacebf8ad172011-11-10 10:19:20 -08002031 /* The texture object is already attached to the stencil attachment
2032 * point. Don't create a new renderbuffer; just reuse the stencil
2033 * attachment's. This is required to prevent a GL error in
2034 * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL).
2035 */
2036 reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH,
2037 BUFFER_STENCIL);
2038 } else if (attachment == GL_STENCIL_ATTACHMENT &&
Paul Berryb9819a02012-04-13 21:50:08 -07002039 texObj == fb->Attachment[BUFFER_DEPTH].Texture &&
2040 level == fb->Attachment[BUFFER_DEPTH].TextureLevel &&
2041 _mesa_tex_target_to_face(textarget) ==
2042 fb->Attachment[BUFFER_DEPTH].CubeMapFace &&
2043 zoffset == fb->Attachment[BUFFER_DEPTH].Zoffset) {
2044 /* As above, but with depth and stencil transposed. */
Chad Versacebf8ad172011-11-10 10:19:20 -08002045 reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL,
2046 BUFFER_DEPTH);
2047 } else {
2048 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
2049 level, zoffset);
2050 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2051 /* Above we created a new renderbuffer and attached it to the
2052 * depth attachment point. Now attach it to the stencil attachment
2053 * point too.
2054 */
2055 assert(att == &fb->Attachment[BUFFER_DEPTH]);
2056 reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL,
2057 BUFFER_DEPTH);
2058 }
2059 }
2060
Brian Paul2897cee2009-01-29 09:20:18 -07002061 /* Set the render-to-texture flag. We'll check this flag in
2062 * glTexImage() and friends to determine if we need to revalidate
2063 * any FBOs that might be rendering into this texture.
2064 * This flag never gets cleared since it's non-trivial to determine
2065 * when all FBOs might be done rendering to this texture. That's OK
2066 * though since it's uncommon to render to a texture then repeatedly
2067 * call glTexImage() to change images in the texture.
2068 */
2069 texObj->_RenderToTexture = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +00002070 }
2071 else {
Brian Paul519b23b2006-03-20 18:51:57 +00002072 _mesa_remove_attachment(ctx, att);
Chad Versacebf8ad172011-11-10 10:19:20 -08002073 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2074 assert(att == &fb->Attachment[BUFFER_DEPTH]);
2075 _mesa_remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]);
2076 }
Brian Paul3deaa012005-02-07 05:08:24 +00002077 }
Brian Paul72966362009-01-21 16:28:38 -07002078
2079 invalidate_framebuffer(fb);
2080
Brian Paulea4fe662006-03-26 05:22:17 +00002081 _glthread_UNLOCK_MUTEX(fb->Mutex);
2082}
2083
2084
2085
2086void GLAPIENTRY
2087_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
2088 GLenum textarget, GLuint texture, GLint level)
2089{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002090 GET_CURRENT_CONTEXT(ctx);
2091
Brian Paul352cab42011-08-18 14:35:27 -06002092 if (texture != 0) {
2093 GLboolean error;
2094
2095 switch (textarget) {
2096 case GL_TEXTURE_1D:
2097 error = GL_FALSE;
2098 break;
Brian Paul3e9dc512011-08-18 15:59:33 -06002099 case GL_TEXTURE_1D_ARRAY:
2100 error = !ctx->Extensions.EXT_texture_array;
2101 break;
Brian Paul352cab42011-08-18 14:35:27 -06002102 default:
2103 error = GL_TRUE;
2104 }
2105
2106 if (error) {
2107 _mesa_error(ctx, GL_INVALID_OPERATION,
2108 "glFramebufferTexture1DEXT(textarget=%s)",
2109 _mesa_lookup_enum_by_nr(textarget));
2110 return;
2111 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002112 }
2113
2114 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
2115 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00002116}
2117
2118
Brian Paul1864c7d2005-02-08 03:46:37 +00002119void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002120_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
2121 GLenum textarget, GLuint texture, GLint level)
2122{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002123 GET_CURRENT_CONTEXT(ctx);
2124
Brian Paul352cab42011-08-18 14:35:27 -06002125 if (texture != 0) {
2126 GLboolean error;
2127
2128 switch (textarget) {
2129 case GL_TEXTURE_2D:
2130 error = GL_FALSE;
2131 break;
2132 case GL_TEXTURE_RECTANGLE:
2133 error = !ctx->Extensions.NV_texture_rectangle;
2134 break;
2135 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2136 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2137 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2138 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2139 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2140 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2141 error = !ctx->Extensions.ARB_texture_cube_map;
2142 break;
Brian Paul3e9dc512011-08-18 15:59:33 -06002143 case GL_TEXTURE_2D_ARRAY:
2144 error = !ctx->Extensions.EXT_texture_array;
2145 break;
Brian Paul352cab42011-08-18 14:35:27 -06002146 default:
Chia-I Wud8ba30a2011-10-22 22:17:31 +08002147 error = GL_TRUE;
Brian Paul352cab42011-08-18 14:35:27 -06002148 }
2149
2150 if (error) {
2151 _mesa_error(ctx, GL_INVALID_OPERATION,
2152 "glFramebufferTexture2DEXT(textarget=%s)",
2153 _mesa_lookup_enum_by_nr(textarget));
2154 return;
2155 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002156 }
2157
2158 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
2159 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00002160}
2161
2162
Brian Paul1864c7d2005-02-08 03:46:37 +00002163void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002164_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
2165 GLenum textarget, GLuint texture,
2166 GLint level, GLint zoffset)
2167{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002168 GET_CURRENT_CONTEXT(ctx);
2169
2170 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
Brian Paulccecc082011-08-18 11:51:48 -06002171 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07002172 "glFramebufferTexture3DEXT(textarget)");
2173 return;
2174 }
2175
2176 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
Brian Paulea4fe662006-03-26 05:22:17 +00002177 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00002178}
2179
2180
Brian Paul1864c7d2005-02-08 03:46:37 +00002181void GLAPIENTRY
Ian Romanickbb372f12007-05-16 15:34:22 -07002182_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
2183 GLuint texture, GLint level, GLint layer)
2184{
2185 GET_CURRENT_CONTEXT(ctx);
2186
2187 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
2188 level, layer);
2189}
2190
2191
2192void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002193_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
2194 GLenum renderbufferTarget,
2195 GLuint renderbuffer)
2196{
Brian Paul2c6f9112005-02-24 05:47:06 +00002197 struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00002198 struct gl_framebuffer *fb;
Brian Paule4b23562005-05-04 20:11:35 +00002199 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00002200 GET_CURRENT_CONTEXT(ctx);
2201
2202 ASSERT_OUTSIDE_BEGIN_END(ctx);
2203
Brian Paulc6991432011-02-28 18:24:25 -07002204 fb = get_framebuffer_target(ctx, target);
2205 if (!fb) {
2206 _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +00002207 return;
2208 }
2209
Brian Paul3deaa012005-02-07 05:08:24 +00002210 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
Brian Paule4b23562005-05-04 20:11:35 +00002211 _mesa_error(ctx, GL_INVALID_ENUM,
2212 "glFramebufferRenderbufferEXT(renderbufferTarget)");
Brian Paul3deaa012005-02-07 05:08:24 +00002213 return;
2214 }
2215
Brian Paul36ede892012-01-12 09:17:23 -07002216 if (_mesa_is_winsys_fbo(fb)) {
Brian Paulab8ef282005-09-07 23:21:59 +00002217 /* Can't attach new renderbuffers to a window system framebuffer */
Brian Paul3deaa012005-02-07 05:08:24 +00002218 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
2219 return;
2220 }
2221
Brian Paul84716042005-11-16 04:05:54 +00002222 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00002223 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00002224 _mesa_error(ctx, GL_INVALID_ENUM,
Brian Paul9b50cea2009-10-23 11:34:14 -06002225 "glFramebufferRenderbufferEXT(invalid attachment %s)",
2226 _mesa_lookup_enum_by_nr(attachment));
Brian Paulddc82ee2005-02-05 19:56:45 +00002227 return;
2228 }
2229
Brian Paul1864c7d2005-02-08 03:46:37 +00002230 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00002231 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00002232 if (!rb) {
Brian Paule4b23562005-05-04 20:11:35 +00002233 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul9b50cea2009-10-23 11:34:14 -06002234 "glFramebufferRenderbufferEXT(non-existant"
2235 " renderbuffer %u)", renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00002236 return;
2237 }
Brian Pauldd973cd2011-01-12 18:14:14 -07002238 else if (rb == &DummyRenderbuffer) {
2239 /* This is what NVIDIA does */
2240 _mesa_error(ctx, GL_INVALID_VALUE,
2241 "glFramebufferRenderbufferEXT(renderbuffer %u)",
2242 renderbuffer);
2243 return;
2244 }
Brian Paul1864c7d2005-02-08 03:46:37 +00002245 }
2246 else {
Brian Paule4b23562005-05-04 20:11:35 +00002247 /* remove renderbuffer attachment */
2248 rb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00002249 }
Brian Paule4b23562005-05-04 20:11:35 +00002250
Brian Paula504f232010-05-27 13:05:23 -06002251 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
2252 rb && rb->Format != MESA_FORMAT_NONE) {
Brian Paul30590072009-01-21 11:06:11 -07002253 /* make sure the renderbuffer is a depth/stencil format */
Brian Paula504f232010-05-27 13:05:23 -06002254 const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
Brian Paul45e76d22009-10-08 20:27:27 -06002255 if (baseFormat != GL_DEPTH_STENCIL) {
Brian Paul30590072009-01-21 11:06:11 -07002256 _mesa_error(ctx, GL_INVALID_OPERATION,
2257 "glFramebufferRenderbufferEXT(renderbuffer"
2258 " is not DEPTH_STENCIL format)");
2259 return;
2260 }
2261 }
2262
2263
Brian Paul800e5532009-11-02 15:39:39 -07002264 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paul474f28e2005-10-08 14:41:17 +00002265
Brian Paule4b23562005-05-04 20:11:35 +00002266 assert(ctx->Driver.FramebufferRenderbuffer);
Brian Paul84716042005-11-16 04:05:54 +00002267 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
Brian Paul2e019182006-03-07 01:43:52 +00002268
2269 /* Some subsequent GL commands may depend on the framebuffer's visual
2270 * after the binding is updated. Update visual info now.
2271 */
Eric Anholt059cca92011-01-02 17:58:07 -08002272 _mesa_update_framebuffer_visual(ctx, fb);
Brian Paulddc82ee2005-02-05 19:56:45 +00002273}
2274
2275
Brian Paul1864c7d2005-02-08 03:46:37 +00002276void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002277_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
2278 GLenum pname, GLint *params)
2279{
Brian Paul2c6f9112005-02-24 05:47:06 +00002280 const struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00002281 struct gl_framebuffer *buffer;
Marek Olšák000896c2011-07-19 03:05:07 +02002282 GLenum err;
Brian Paulddc82ee2005-02-05 19:56:45 +00002283 GET_CURRENT_CONTEXT(ctx);
2284
2285 ASSERT_OUTSIDE_BEGIN_END(ctx);
2286
Brian Pauldbe88512012-02-10 16:22:33 -07002287 /* The error differs in GL and GLES. */
Marek Olšák000896c2011-07-19 03:05:07 +02002288 err = ctx->API == API_OPENGL ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
2289
Brian Paulc6991432011-02-28 18:24:25 -07002290 buffer = get_framebuffer_target(ctx, target);
2291 if (!buffer) {
Brian Paulddc82ee2005-02-05 19:56:45 +00002292 _mesa_error(ctx, GL_INVALID_ENUM,
2293 "glGetFramebufferAttachmentParameterivEXT(target)");
2294 return;
2295 }
2296
Brian Paul36ede892012-01-12 09:17:23 -07002297 if (_mesa_is_winsys_fbo(buffer)) {
Ian Romanickda2e41c2011-10-03 12:04:09 -07002298 /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec
2299 * says:
2300 *
2301 * "If the framebuffer currently bound to target is zero, then
2302 * INVALID_OPERATION is generated."
2303 *
2304 * The EXT_framebuffer_object spec has the same wording, and the
2305 * OES_framebuffer_object spec refers to the EXT_framebuffer_object
2306 * spec.
2307 */
2308 if (ctx->API != API_OPENGL || !ctx->Extensions.ARB_framebuffer_object) {
2309 _mesa_error(ctx, GL_INVALID_OPERATION,
2310 "glGetFramebufferAttachmentParameteriv(bound FBO = 0)");
2311 return;
2312 }
Brian Paul61ec2052010-06-22 08:37:44 -06002313 /* the default / window-system FBO */
2314 att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
2315 }
2316 else {
2317 /* user-created framebuffer FBO */
2318 att = _mesa_get_attachment(ctx, buffer, attachment);
2319 }
2320
Brian Paul3deaa012005-02-07 05:08:24 +00002321 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00002322 _mesa_error(ctx, GL_INVALID_ENUM,
2323 "glGetFramebufferAttachmentParameterivEXT(attachment)");
2324 return;
2325 }
2326
Brian Paul30590072009-01-21 11:06:11 -07002327 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2328 /* the depth and stencil attachments must point to the same buffer */
2329 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
2330 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
2331 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
2332 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
2333 _mesa_error(ctx, GL_INVALID_OPERATION,
2334 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
2335 " attachments differ)");
2336 return;
2337 }
2338 }
2339
Brian Paul800e5532009-11-02 15:39:39 -07002340 /* No need to flush here */
Brian Paul474f28e2005-10-08 14:41:17 +00002341
Brian Paulddc82ee2005-02-05 19:56:45 +00002342 switch (pname) {
2343 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
Brian Paul36ede892012-01-12 09:17:23 -07002344 *params = _mesa_is_winsys_fbo(buffer)
2345 ? GL_FRAMEBUFFER_DEFAULT : att->Type;
Brian Paul3deaa012005-02-07 05:08:24 +00002346 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002347 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002348 if (att->Type == GL_RENDERBUFFER_EXT) {
2349 *params = att->Renderbuffer->Name;
2350 }
2351 else if (att->Type == GL_TEXTURE) {
2352 *params = att->Texture->Name;
2353 }
2354 else {
Brian Paul20cf1852010-12-03 08:23:31 -07002355 assert(att->Type == GL_NONE);
Marek Olšák000896c2011-07-19 03:05:07 +02002356 if (ctx->API == API_OPENGL) {
2357 *params = 0;
2358 } else {
2359 _mesa_error(ctx, GL_INVALID_ENUM,
2360 "glGetFramebufferAttachmentParameterivEXT(pname)");
2361 }
Brian Paul3deaa012005-02-07 05:08:24 +00002362 }
2363 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002364 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002365 if (att->Type == GL_TEXTURE) {
2366 *params = att->TextureLevel;
2367 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002368 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002369 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002370 "glGetFramebufferAttachmentParameterivEXT(pname)");
2371 }
Brian Paul3deaa012005-02-07 05:08:24 +00002372 else {
2373 _mesa_error(ctx, GL_INVALID_ENUM,
2374 "glGetFramebufferAttachmentParameterivEXT(pname)");
2375 }
2376 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002377 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002378 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06002379 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
2380 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
2381 }
2382 else {
2383 *params = 0;
2384 }
Brian Paul3deaa012005-02-07 05:08:24 +00002385 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002386 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002387 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002388 "glGetFramebufferAttachmentParameterivEXT(pname)");
2389 }
Brian Paul3deaa012005-02-07 05:08:24 +00002390 else {
2391 _mesa_error(ctx, GL_INVALID_ENUM,
2392 "glGetFramebufferAttachmentParameterivEXT(pname)");
2393 }
2394 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002395 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002396 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06002397 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2398 *params = att->Zoffset;
2399 }
2400 else {
2401 *params = 0;
2402 }
Brian Paul3deaa012005-02-07 05:08:24 +00002403 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002404 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002405 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002406 "glGetFramebufferAttachmentParameterivEXT(pname)");
2407 }
Brian Paul3deaa012005-02-07 05:08:24 +00002408 else {
2409 _mesa_error(ctx, GL_INVALID_ENUM,
2410 "glGetFramebufferAttachmentParameterivEXT(pname)");
2411 }
2412 return;
Brian Paul1bc59bf2009-01-22 15:07:34 -07002413 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2414 if (!ctx->Extensions.ARB_framebuffer_object) {
2415 _mesa_error(ctx, GL_INVALID_ENUM,
2416 "glGetFramebufferAttachmentParameterivEXT(pname)");
2417 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002418 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002419 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002420 "glGetFramebufferAttachmentParameterivEXT(pname)");
2421 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002422 else {
Marek Olšák69c8f462012-01-24 23:39:31 +01002423 if (ctx->Extensions.EXT_framebuffer_sRGB) {
Marek Olšák81ae8c62011-01-23 13:26:43 +01002424 *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
2425 }
2426 else {
2427 /* According to ARB_framebuffer_sRGB, we should return LINEAR
2428 * if the sRGB conversion is unsupported. */
2429 *params = GL_LINEAR;
2430 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002431 }
2432 return;
2433 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2434 if (!ctx->Extensions.ARB_framebuffer_object) {
2435 _mesa_error(ctx, GL_INVALID_ENUM,
2436 "glGetFramebufferAttachmentParameterivEXT(pname)");
2437 return;
2438 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002439 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002440 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002441 "glGetFramebufferAttachmentParameterivEXT(pname)");
2442 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002443 else {
Brian Paul45e76d22009-10-08 20:27:27 -06002444 gl_format format = att->Renderbuffer->Format;
Ian Romanick55d232a2011-08-26 12:20:00 -07002445 if (format == MESA_FORMAT_S8) {
Brian Paul45e76d22009-10-08 20:27:27 -06002446 /* special cases */
2447 *params = GL_INDEX;
2448 }
Marek Olšák11652802011-06-01 15:48:51 +02002449 else if (format == MESA_FORMAT_Z32_FLOAT_X24S8) {
2450 /* depends on the attachment parameter */
2451 if (attachment == GL_STENCIL_ATTACHMENT) {
2452 *params = GL_INDEX;
2453 }
2454 else {
2455 *params = GL_FLOAT;
2456 }
2457 }
Brian Paul45e76d22009-10-08 20:27:27 -06002458 else {
2459 *params = _mesa_get_format_datatype(format);
2460 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002461 }
2462 return;
2463 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002464 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002465 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002466 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002467 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002468 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2469 if (!ctx->Extensions.ARB_framebuffer_object) {
2470 _mesa_error(ctx, GL_INVALID_ENUM,
2471 "glGetFramebufferAttachmentParameterivEXT(pname)");
2472 }
Marek Olšákb9e9df72011-05-31 20:36:07 +02002473 else if (att->Type == GL_NONE) {
Marek Olšák000896c2011-07-19 03:05:07 +02002474 _mesa_error(ctx, err,
Marek Olšákb9e9df72011-05-31 20:36:07 +02002475 "glGetFramebufferAttachmentParameterivEXT(pname)");
2476 }
Brian Paul45e76d22009-10-08 20:27:27 -06002477 else if (att->Texture) {
2478 const struct gl_texture_image *texImage =
2479 _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
2480 att->TextureLevel);
2481 if (texImage) {
2482 *params = get_component_bits(pname, texImage->_BaseFormat,
2483 texImage->TexFormat);
2484 }
2485 else {
2486 *params = 0;
2487 }
2488 }
2489 else if (att->Renderbuffer) {
2490 *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
2491 att->Renderbuffer->Format);
2492 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002493 else {
Marek Olšákb9e9df72011-05-31 20:36:07 +02002494 _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:"
2495 " invalid FBO attachment structure");
Brian Paul1bc59bf2009-01-22 15:07:34 -07002496 }
2497 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002498 default:
2499 _mesa_error(ctx, GL_INVALID_ENUM,
2500 "glGetFramebufferAttachmentParameterivEXT(pname)");
2501 return;
2502 }
Brian Paulddc82ee2005-02-05 19:56:45 +00002503}
2504
2505
Brian Paul1864c7d2005-02-08 03:46:37 +00002506void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002507_mesa_GenerateMipmapEXT(GLenum target)
2508{
Eric Anholtf80e1e72011-10-18 11:52:39 -07002509 struct gl_texture_image *srcImage;
Brian Paul463642c2005-02-08 02:06:00 +00002510 struct gl_texture_object *texObj;
Brian Paul3e9dc512011-08-18 15:59:33 -06002511 GLboolean error;
2512
Brian Paulddc82ee2005-02-05 19:56:45 +00002513 GET_CURRENT_CONTEXT(ctx);
2514
2515 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00002516 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00002517
2518 switch (target) {
2519 case GL_TEXTURE_1D:
2520 case GL_TEXTURE_2D:
Brian Paulddc82ee2005-02-05 19:56:45 +00002521 case GL_TEXTURE_3D:
Brian Paul3e9dc512011-08-18 15:59:33 -06002522 error = GL_FALSE;
2523 break;
Brian Paul463642c2005-02-08 02:06:00 +00002524 case GL_TEXTURE_CUBE_MAP:
Brian Paul3e9dc512011-08-18 15:59:33 -06002525 error = !ctx->Extensions.ARB_texture_cube_map;
2526 break;
2527 case GL_TEXTURE_1D_ARRAY:
2528 case GL_TEXTURE_2D_ARRAY:
2529 error = !ctx->Extensions.EXT_texture_array;
Brian Paulddc82ee2005-02-05 19:56:45 +00002530 break;
2531 default:
Brian Paul3e9dc512011-08-18 15:59:33 -06002532 error = GL_TRUE;
2533 }
2534
2535 if (error) {
2536 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target=%s)",
2537 _mesa_lookup_enum_by_nr(target));
Brian Paulddc82ee2005-02-05 19:56:45 +00002538 return;
2539 }
2540
Brian Paula7193952009-11-16 08:21:28 -07002541 texObj = _mesa_get_current_tex_object(ctx, target);
Brian Paul463642c2005-02-08 02:06:00 +00002542
Brian Paul652828e2009-11-16 08:25:17 -07002543 if (texObj->BaseLevel >= texObj->MaxLevel) {
2544 /* nothing to do */
2545 return;
2546 }
2547
Brian Paulecb7cc32010-12-06 15:11:41 -07002548 if (texObj->Target == GL_TEXTURE_CUBE_MAP &&
2549 !_mesa_cube_complete(texObj)) {
2550 _mesa_error(ctx, GL_INVALID_OPERATION,
2551 "glGenerateMipmap(incomplete cube map)");
2552 return;
2553 }
2554
Keith Whitwell5ac93f82006-11-01 14:21:57 +00002555 _mesa_lock_texture(ctx, texObj);
Eric Anholtf80e1e72011-10-18 11:52:39 -07002556
2557 srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel);
2558 if (!srcImage) {
2559 _mesa_unlock_texture(ctx, texObj);
2560 return;
2561 }
2562
Eric Anholtf849d362008-12-06 21:14:56 -08002563 if (target == GL_TEXTURE_CUBE_MAP) {
Brian Paulef6ee072009-09-15 18:09:03 -06002564 GLuint face;
Eric Anholtf849d362008-12-06 21:14:56 -08002565 for (face = 0; face < 6; face++)
2566 ctx->Driver.GenerateMipmap(ctx,
2567 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2568 texObj);
Brian Paulef6ee072009-09-15 18:09:03 -06002569 }
2570 else {
Eric Anholtf849d362008-12-06 21:14:56 -08002571 ctx->Driver.GenerateMipmap(ctx, target, texObj);
2572 }
Keith Whitwell5ac93f82006-11-01 14:21:57 +00002573 _mesa_unlock_texture(ctx, texObj);
Brian Paulddc82ee2005-02-05 19:56:45 +00002574}
Brian Paul0bffb112005-11-08 14:45:48 +00002575
2576
2577#if FEATURE_EXT_framebuffer_blit
Brian Paul21f8d312009-10-27 16:59:23 -06002578
2579static const struct gl_renderbuffer_attachment *
Brian Paulb3cfcdf2011-01-28 20:25:26 -07002580find_attachment(const struct gl_framebuffer *fb,
2581 const struct gl_renderbuffer *rb)
Brian Paul21f8d312009-10-27 16:59:23 -06002582{
2583 GLuint i;
2584 for (i = 0; i < Elements(fb->Attachment); i++) {
2585 if (fb->Attachment[i].Renderbuffer == rb)
2586 return &fb->Attachment[i];
2587 }
2588 return NULL;
2589}
2590
2591
Brian Paul9b111702012-01-09 12:38:49 -07002592/**
2593 * Helper function for checking if the datatypes of color buffers are
2594 * compatible for glBlitFramebuffer. From the 3.1 spec, page 198:
2595 *
2596 * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT
2597 * and any of the following conditions hold:
2598 * - The read buffer contains fixed-point or floating-point values and any
2599 * draw buffer contains neither fixed-point nor floating-point values.
2600 * - The read buffer contains unsigned integer values and any draw buffer
2601 * does not contain unsigned integer values.
2602 * - The read buffer contains signed integer values and any draw buffer
2603 * does not contain signed integer values."
2604 */
2605static GLboolean
2606compatible_color_datatypes(gl_format srcFormat, gl_format dstFormat)
2607{
2608 GLenum srcType = _mesa_get_format_datatype(srcFormat);
2609 GLenum dstType = _mesa_get_format_datatype(dstFormat);
2610
2611 if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) {
2612 assert(srcType == GL_UNSIGNED_NORMALIZED ||
2613 srcType == GL_SIGNED_NORMALIZED ||
2614 srcType == GL_FLOAT);
2615 /* Boil any of those types down to GL_FLOAT */
2616 srcType = GL_FLOAT;
2617 }
2618
2619 if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) {
2620 assert(dstType == GL_UNSIGNED_NORMALIZED ||
2621 dstType == GL_SIGNED_NORMALIZED ||
2622 dstType == GL_FLOAT);
2623 /* Boil any of those types down to GL_FLOAT */
2624 dstType = GL_FLOAT;
2625 }
2626
2627 return srcType == dstType;
2628}
2629
Brian Paul21f8d312009-10-27 16:59:23 -06002630
Brian Paul722d9762009-01-20 16:58:49 -07002631/**
2632 * Blit rectangular region, optionally from one framebuffer to another.
2633 *
2634 * Note, if the src buffer is multisampled and the dest is not, this is
2635 * when the samples must be resolved to a single color.
2636 */
Brian Paul0bffb112005-11-08 14:45:48 +00002637void GLAPIENTRY
2638_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
2639 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
2640 GLbitfield mask, GLenum filter)
2641{
Brian Paul722d9762009-01-20 16:58:49 -07002642 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
2643 GL_DEPTH_BUFFER_BIT |
2644 GL_STENCIL_BUFFER_BIT);
2645 const struct gl_framebuffer *readFb, *drawFb;
2646 const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
Brian Paul0bffb112005-11-08 14:45:48 +00002647 GET_CURRENT_CONTEXT(ctx);
2648
2649 ASSERT_OUTSIDE_BEGIN_END(ctx);
2650 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2651
Brian Paul6364d752011-02-18 09:53:29 -07002652 if (MESA_VERBOSE & VERBOSE_API)
2653 _mesa_debug(ctx,
2654 "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n",
2655 srcX0, srcY0, srcX1, srcY1,
2656 dstX0, dstY0, dstX1, dstY1,
2657 mask, _mesa_lookup_enum_by_nr(filter));
2658
Brian Paul99745402006-03-01 02:02:43 +00002659 if (ctx->NewState) {
2660 _mesa_update_state(ctx);
2661 }
2662
Brian Paul722d9762009-01-20 16:58:49 -07002663 readFb = ctx->ReadBuffer;
2664 drawFb = ctx->DrawBuffer;
2665
2666 if (!readFb || !drawFb) {
2667 /* This will normally never happen but someday we may want to
2668 * support MakeCurrent() with no drawables.
2669 */
2670 return;
Brian Paul99745402006-03-01 02:02:43 +00002671 }
2672
Brian Paul0bffb112005-11-08 14:45:48 +00002673 /* check for complete framebuffers */
Brian Paul722d9762009-01-20 16:58:49 -07002674 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
2675 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
Brian Paul0bffb112005-11-08 14:45:48 +00002676 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
2677 "glBlitFramebufferEXT(incomplete draw/read buffers)");
2678 return;
2679 }
2680
Brian Paul99745402006-03-01 02:02:43 +00002681 if (filter != GL_NEAREST && filter != GL_LINEAR) {
2682 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
2683 return;
2684 }
2685
Brian Paul722d9762009-01-20 16:58:49 -07002686 if (mask & ~legalMaskBits) {
Brian Paul99745402006-03-01 02:02:43 +00002687 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
2688 return;
2689 }
2690
Brian Paul0bffb112005-11-08 14:45:48 +00002691 /* depth/stencil must be blitted with nearest filtering */
2692 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
2693 && filter != GL_NEAREST) {
2694 _mesa_error(ctx, GL_INVALID_OPERATION,
Vinson Lee4f94e0b2011-03-28 20:32:01 -07002695 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)");
Brian Paul0bffb112005-11-08 14:45:48 +00002696 return;
2697 }
2698
Brian Paul722d9762009-01-20 16:58:49 -07002699 /* get color read/draw renderbuffers */
2700 if (mask & GL_COLOR_BUFFER_BIT) {
2701 colorReadRb = readFb->_ColorReadBuffer;
2702 colorDrawRb = drawFb->_ColorDrawBuffers[0];
Ian Romanickbb475862011-06-07 12:38:39 -07002703
2704 /* From the EXT_framebuffer_object spec:
2705 *
2706 * "If a buffer is specified in <mask> and does not exist in both
2707 * the read and draw framebuffers, the corresponding bit is silently
2708 * ignored."
2709 */
2710 if ((colorReadRb == NULL) || (colorDrawRb == NULL)) {
2711 colorReadRb = colorDrawRb = NULL;
2712 mask &= ~GL_COLOR_BUFFER_BIT;
2713 }
Brian Paul9b111702012-01-09 12:38:49 -07002714 else if (!compatible_color_datatypes(colorReadRb->Format,
2715 colorDrawRb->Format)) {
2716 _mesa_error(ctx, GL_INVALID_OPERATION,
2717 "glBlitFramebufferEXT(color buffer datatypes mismatch)");
2718 return;
2719 }
Brian Paul722d9762009-01-20 16:58:49 -07002720 }
2721 else {
2722 colorReadRb = colorDrawRb = NULL;
2723 }
2724
Brian Paul99745402006-03-01 02:02:43 +00002725 if (mask & GL_STENCIL_BUFFER_BIT) {
Brian Pauld1240922011-12-10 11:44:43 -07002726 struct gl_renderbuffer *readRb =
2727 readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
2728 struct gl_renderbuffer *drawRb =
2729 drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;
Ian Romanickbb475862011-06-07 12:38:39 -07002730
2731 /* From the EXT_framebuffer_object spec:
2732 *
2733 * "If a buffer is specified in <mask> and does not exist in both
2734 * the read and draw framebuffers, the corresponding bit is silently
2735 * ignored."
2736 */
2737 if ((readRb == NULL) || (drawRb == NULL)) {
Ian Romanickbb475862011-06-07 12:38:39 -07002738 mask &= ~GL_STENCIL_BUFFER_BIT;
2739 }
Chad Versacef74d8aa2012-01-17 12:01:34 -08002740 else if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
2741 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
2742 /* There is no need to check the stencil datatype here, because
2743 * there is only one: GL_UNSIGNED_INT.
2744 */
Brian Paul99745402006-03-01 02:02:43 +00002745 _mesa_error(ctx, GL_INVALID_OPERATION,
Chad Versacef74d8aa2012-01-17 12:01:34 -08002746 "glBlitFramebufferEXT(stencil buffer size mismatch)");
Brian Paul99745402006-03-01 02:02:43 +00002747 return;
2748 }
2749 }
2750
2751 if (mask & GL_DEPTH_BUFFER_BIT) {
Brian Pauld1240922011-12-10 11:44:43 -07002752 struct gl_renderbuffer *readRb =
2753 readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
2754 struct gl_renderbuffer *drawRb =
2755 drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
Ian Romanickbb475862011-06-07 12:38:39 -07002756
2757 /* From the EXT_framebuffer_object spec:
2758 *
2759 * "If a buffer is specified in <mask> and does not exist in both
2760 * the read and draw framebuffers, the corresponding bit is silently
2761 * ignored."
2762 */
2763 if ((readRb == NULL) || (drawRb == NULL)) {
Ian Romanickbb475862011-06-07 12:38:39 -07002764 mask &= ~GL_DEPTH_BUFFER_BIT;
2765 }
Chad Versacef74d8aa2012-01-17 12:01:34 -08002766 else if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
2767 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
2768 (_mesa_get_format_datatype(readRb->Format) !=
2769 _mesa_get_format_datatype(drawRb->Format))) {
Brian Paul99745402006-03-01 02:02:43 +00002770 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul3f1fab02012-01-09 08:11:33 -07002771 "glBlitFramebufferEXT(depth buffer format mismatch)");
Brian Paul99745402006-03-01 02:02:43 +00002772 return;
2773 }
Brian Paul0bffb112005-11-08 14:45:48 +00002774 }
2775
Brian Paul722d9762009-01-20 16:58:49 -07002776 if (readFb->Visual.samples > 0 &&
2777 drawFb->Visual.samples > 0 &&
2778 readFb->Visual.samples != drawFb->Visual.samples) {
2779 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paulb87b8572012-01-09 08:11:33 -07002780 "glBlitFramebufferEXT(mismatched samples)");
Brian Paul722d9762009-01-20 16:58:49 -07002781 return;
2782 }
2783
2784 /* extra checks for multisample copies... */
2785 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
2786 /* src and dest region sizes must be the same */
2787 if (srcX1 - srcX0 != dstX1 - dstX0 ||
2788 srcY1 - srcY0 != dstY1 - dstY0) {
2789 _mesa_error(ctx, GL_INVALID_OPERATION,
Vinson Lee4f94e0b2011-03-28 20:32:01 -07002790 "glBlitFramebufferEXT(bad src/dst multisample region sizes)");
Brian Paul722d9762009-01-20 16:58:49 -07002791 return;
2792 }
2793
2794 /* color formats must match */
2795 if (colorReadRb &&
2796 colorDrawRb &&
Brian Paul45e76d22009-10-08 20:27:27 -06002797 colorReadRb->Format != colorDrawRb->Format) {
Brian Paul722d9762009-01-20 16:58:49 -07002798 _mesa_error(ctx, GL_INVALID_OPERATION,
Vinson Lee4f94e0b2011-03-28 20:32:01 -07002799 "glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
Brian Paul722d9762009-01-20 16:58:49 -07002800 return;
2801 }
2802 }
2803
Brian Paul84c38c72012-01-09 08:11:33 -07002804 if (filter == GL_LINEAR && (mask & GL_COLOR_BUFFER_BIT)) {
2805 /* 3.1 spec, page 199:
2806 * "Calling BlitFramebuffer will result in an INVALID_OPERATION error
2807 * if filter is LINEAR and read buffer contains integer data."
2808 */
2809 GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
2810 if (type == GL_INT || type == GL_UNSIGNED_INT) {
2811 _mesa_error(ctx, GL_INVALID_OPERATION,
2812 "glBlitFramebufferEXT(integer color type)");
2813 return;
2814 }
2815 }
2816
Brian Paul0bffb112005-11-08 14:45:48 +00002817 if (!ctx->Extensions.EXT_framebuffer_blit) {
2818 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
2819 return;
2820 }
2821
Brian Paul21f8d312009-10-27 16:59:23 -06002822 /* Debug code */
2823 if (DEBUG_BLIT) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002824 printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
2825 " 0x%x, 0x%x)\n",
2826 srcX0, srcY0, srcX1, srcY1,
2827 dstX0, dstY0, dstX1, dstY1,
2828 mask, filter);
Brian Paul21f8d312009-10-27 16:59:23 -06002829 if (colorReadRb) {
2830 const struct gl_renderbuffer_attachment *att;
2831
2832 att = find_attachment(readFb, colorReadRb);
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002833 printf(" Src FBO %u RB %u (%dx%d) ",
2834 readFb->Name, colorReadRb->Name,
2835 colorReadRb->Width, colorReadRb->Height);
Brian Paul21f8d312009-10-27 16:59:23 -06002836 if (att && att->Texture) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002837 printf("Tex %u tgt 0x%x level %u face %u",
2838 att->Texture->Name,
2839 att->Texture->Target,
2840 att->TextureLevel,
2841 att->CubeMapFace);
Brian Paul21f8d312009-10-27 16:59:23 -06002842 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002843 printf("\n");
Brian Paul21f8d312009-10-27 16:59:23 -06002844
2845 att = find_attachment(drawFb, colorDrawRb);
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002846 printf(" Dst FBO %u RB %u (%dx%d) ",
2847 drawFb->Name, colorDrawRb->Name,
2848 colorDrawRb->Width, colorDrawRb->Height);
Brian Paul21f8d312009-10-27 16:59:23 -06002849 if (att && att->Texture) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002850 printf("Tex %u tgt 0x%x level %u face %u",
2851 att->Texture->Name,
2852 att->Texture->Target,
2853 att->TextureLevel,
2854 att->CubeMapFace);
Brian Paul21f8d312009-10-27 16:59:23 -06002855 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002856 printf("\n");
Brian Paul21f8d312009-10-27 16:59:23 -06002857 }
2858 }
2859
Marek Olšák83478e52011-07-10 20:01:33 +02002860 if (!mask) {
2861 return;
2862 }
2863
Brian Paul0bffb112005-11-08 14:45:48 +00002864 ASSERT(ctx->Driver.BlitFramebuffer);
2865 ctx->Driver.BlitFramebuffer(ctx,
2866 srcX0, srcY0, srcX1, srcY1,
2867 dstX0, dstY0, dstX1, dstY1,
2868 mask, filter);
2869}
2870#endif /* FEATURE_EXT_framebuffer_blit */
Zack Rusinda7bd6a2010-06-28 17:31:21 -04002871
Brian Paul45bd5c42011-12-16 08:44:43 -07002872
Zack Rusinda7bd6a2010-06-28 17:31:21 -04002873#if FEATURE_ARB_geometry_shader4
2874void GLAPIENTRY
2875_mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
2876 GLuint texture, GLint level)
2877{
2878 GET_CURRENT_CONTEXT(ctx);
2879 _mesa_error(ctx, GL_INVALID_OPERATION,
2880 "glFramebufferTextureARB "
2881 "not implemented!");
2882}
2883
Brian Paul45bd5c42011-12-16 08:44:43 -07002884
Zack Rusinda7bd6a2010-06-28 17:31:21 -04002885void GLAPIENTRY
2886_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
2887 GLuint texture, GLint level, GLenum face)
2888{
2889 GET_CURRENT_CONTEXT(ctx);
2890 _mesa_error(ctx, GL_INVALID_OPERATION,
2891 "glFramebufferTextureFaceARB "
2892 "not implemented!");
2893}
2894#endif /* FEATURE_ARB_geometry_shader4 */