blob: 3dc78f2bf530cb51ef874b2316c8df68c64a6960 [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 Paul989edea2009-01-22 15:05:13 -070042#include "macros.h"
Brian Paule4b23562005-05-04 20:11:35 +000043#include "renderbuffer.h"
Brian Paul99745402006-03-01 02:02:43 +000044#include "state.h"
Brian Paul463642c2005-02-08 02:06:00 +000045#include "teximage.h"
Brian Paulea4fe662006-03-26 05:22:17 +000046#include "texobj.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000047
48
Brian Paulc26c2002009-09-15 17:20:32 -060049/** Set this to 1 to help debug FBO incompleteness problems */
50#define DEBUG_FBO 0
51
Brian Paul21f8d312009-10-27 16:59:23 -060052/** Set this to 1 to debug/log glBlitFramebuffer() calls */
53#define DEBUG_BLIT 0
54
Brian Paulc26c2002009-09-15 17:20:32 -060055
Brian Pauld9468c92005-02-10 16:08:07 +000056/**
57 * Notes:
58 *
59 * None of the GL_EXT_framebuffer_object functions are compiled into
60 * display lists.
61 */
62
63
64
Brian Paul923b6fc2005-02-08 04:08:56 +000065/*
66 * When glGenRender/FramebuffersEXT() is called we insert pointers to
67 * these placeholder objects into the hash table.
68 * Later, when the object ID is first bound, we replace the placeholder
69 * with the real frame/renderbuffer.
70 */
Brian Paul2c6f9112005-02-24 05:47:06 +000071static struct gl_framebuffer DummyFramebuffer;
72static struct gl_renderbuffer DummyRenderbuffer;
Brian Paul1864c7d2005-02-08 03:46:37 +000073
Kristian Høgsberg144356f2010-09-09 17:08:12 -040074/* We bind this framebuffer when applications pass a NULL
75 * drawable/surface in make current. */
76static struct gl_framebuffer IncompleteFramebuffer;
77
Brian Paul1864c7d2005-02-08 03:46:37 +000078
Brian Paul3deaa012005-02-07 05:08:24 +000079#define IS_CUBE_FACE(TARGET) \
80 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
81 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
Brian Paulddc82ee2005-02-05 19:56:45 +000082
83
Brian Paul3dc65912008-07-03 15:40:38 -060084static void
85delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
86{
87 /* no op */
88}
89
90static void
91delete_dummy_framebuffer(struct gl_framebuffer *fb)
92{
93 /* no op */
94}
95
96
97void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -040098_mesa_init_fbobjects(struct gl_context *ctx)
Brian Paul3dc65912008-07-03 15:40:38 -060099{
Vladimir Vukicevic07317012010-09-01 08:54:21 -0600100 _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
101 _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
Kristian Høgsberg144356f2010-09-09 17:08:12 -0400102 _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex);
Brian Paul3dc65912008-07-03 15:40:38 -0600103 DummyFramebuffer.Delete = delete_dummy_framebuffer;
104 DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
Kristian Høgsberg144356f2010-09-09 17:08:12 -0400105 IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
Brian Paul3dc65912008-07-03 15:40:38 -0600106}
107
Kristian Høgsberg9456e222010-06-04 14:28:59 -0400108struct gl_framebuffer *
109_mesa_get_incomplete_framebuffer(void)
110{
Kristian Høgsberg144356f2010-09-09 17:08:12 -0400111 return &IncompleteFramebuffer;
Kristian Høgsberg9456e222010-06-04 14:28:59 -0400112}
Brian Paul3dc65912008-07-03 15:40:38 -0600113
Brian Paulddc82ee2005-02-05 19:56:45 +0000114/**
Brian Paul2c6f9112005-02-24 05:47:06 +0000115 * Helper routine for getting a gl_renderbuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +0000116 */
Brian Paulea4fe662006-03-26 05:22:17 +0000117struct gl_renderbuffer *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400118_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +0000119{
Brian Paul2c6f9112005-02-24 05:47:06 +0000120 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000121
Brian Paul1864c7d2005-02-08 03:46:37 +0000122 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +0000123 return NULL;
124
Brian Paul2c6f9112005-02-24 05:47:06 +0000125 rb = (struct gl_renderbuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000126 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
127 return rb;
128}
129
130
131/**
Brian Paul2c6f9112005-02-24 05:47:06 +0000132 * Helper routine for getting a gl_framebuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +0000133 */
Brian Paulea4fe662006-03-26 05:22:17 +0000134struct gl_framebuffer *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400135_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +0000136{
Brian Paul2c6f9112005-02-24 05:47:06 +0000137 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000138
Brian Paul1864c7d2005-02-08 03:46:37 +0000139 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +0000140 return NULL;
141
Brian Paul2c6f9112005-02-24 05:47:06 +0000142 fb = (struct gl_framebuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000143 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
Brian Paul463642c2005-02-08 02:06:00 +0000144 return fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000145}
146
147
148/**
Brian Paul72966362009-01-21 16:28:38 -0700149 * Mark the given framebuffer as invalid. This will force the
150 * test for framebuffer completeness to be done before the framebuffer
151 * is used.
152 */
153static void
154invalidate_framebuffer(struct gl_framebuffer *fb)
155{
156 fb->_Status = 0; /* "indeterminate" */
157}
158
159
160/**
Brian Pauld9468c92005-02-10 16:08:07 +0000161 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
Brian Paul2c6f9112005-02-24 05:47:06 +0000162 * gl_renderbuffer_attachment object.
Brian Paul61ec2052010-06-22 08:37:44 -0600163 * This function is only used for user-created FB objects, not the
164 * default / window-system FB object.
Brian Paul30590072009-01-21 11:06:11 -0700165 * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
166 * the depth buffer attachment point.
Brian Pauld9468c92005-02-10 16:08:07 +0000167 */
Brian Paul84716042005-11-16 04:05:54 +0000168struct gl_renderbuffer_attachment *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400169_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
Brian Paul84716042005-11-16 04:05:54 +0000170 GLenum attachment)
Brian Paul3deaa012005-02-07 05:08:24 +0000171{
172 GLuint i;
173
Brian Paul61ec2052010-06-22 08:37:44 -0600174 assert(fb->Name > 0);
175
Brian Paul3deaa012005-02-07 05:08:24 +0000176 switch (attachment) {
177 case GL_COLOR_ATTACHMENT0_EXT:
178 case GL_COLOR_ATTACHMENT1_EXT:
179 case GL_COLOR_ATTACHMENT2_EXT:
180 case GL_COLOR_ATTACHMENT3_EXT:
181 case GL_COLOR_ATTACHMENT4_EXT:
182 case GL_COLOR_ATTACHMENT5_EXT:
183 case GL_COLOR_ATTACHMENT6_EXT:
184 case GL_COLOR_ATTACHMENT7_EXT:
185 case GL_COLOR_ATTACHMENT8_EXT:
186 case GL_COLOR_ATTACHMENT9_EXT:
187 case GL_COLOR_ATTACHMENT10_EXT:
188 case GL_COLOR_ATTACHMENT11_EXT:
189 case GL_COLOR_ATTACHMENT12_EXT:
190 case GL_COLOR_ATTACHMENT13_EXT:
191 case GL_COLOR_ATTACHMENT14_EXT:
192 case GL_COLOR_ATTACHMENT15_EXT:
193 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
194 if (i >= ctx->Const.MaxColorAttachments) {
195 return NULL;
196 }
Brian Paule4b23562005-05-04 20:11:35 +0000197 return &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paul30590072009-01-21 11:06:11 -0700198 case GL_DEPTH_STENCIL_ATTACHMENT:
199 /* fall-through */
Brian Paul8829e062010-03-20 11:50:55 -0600200 case GL_DEPTH_BUFFER:
201 /* fall-through / new in GL 3.0 */
Brian Paul3deaa012005-02-07 05:08:24 +0000202 case GL_DEPTH_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000203 return &fb->Attachment[BUFFER_DEPTH];
Brian Paul8829e062010-03-20 11:50:55 -0600204 case GL_STENCIL_BUFFER:
205 /* fall-through / new in GL 3.0 */
Brian Paul3deaa012005-02-07 05:08:24 +0000206 case GL_STENCIL_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000207 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul61ec2052010-06-22 08:37:44 -0600208 default:
209 return NULL;
210 }
211}
212
213
214/**
215 * As above, but only used for getting attachments of the default /
216 * window-system framebuffer (not user-created framebuffer objects).
217 */
218static struct gl_renderbuffer_attachment *
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400219_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
Brian Paul61ec2052010-06-22 08:37:44 -0600220 GLenum attachment)
221{
222 assert(fb->Name == 0);
223
224 switch (attachment) {
Kristian Høgsberg80dfec32010-06-15 13:07:01 -0400225 case GL_FRONT_LEFT:
226 return &fb->Attachment[BUFFER_FRONT_LEFT];
227 case GL_FRONT_RIGHT:
228 return &fb->Attachment[BUFFER_FRONT_RIGHT];
229 case GL_BACK_LEFT:
230 return &fb->Attachment[BUFFER_BACK_LEFT];
231 case GL_BACK_RIGHT:
232 return &fb->Attachment[BUFFER_BACK_RIGHT];
Brian Paul61ec2052010-06-22 08:37:44 -0600233 case GL_AUX0:
234 if (fb->Visual.numAuxBuffers == 1) {
235 return &fb->Attachment[BUFFER_AUX0];
236 }
237 return NULL;
238 case GL_DEPTH_BUFFER:
239 /* fall-through / new in GL 3.0 */
240 case GL_DEPTH_ATTACHMENT_EXT:
241 return &fb->Attachment[BUFFER_DEPTH];
242 case GL_STENCIL_BUFFER:
243 /* fall-through / new in GL 3.0 */
244 case GL_STENCIL_ATTACHMENT_EXT:
245 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul3deaa012005-02-07 05:08:24 +0000246 default:
247 return NULL;
248 }
249}
250
251
Brian Paul61ec2052010-06-22 08:37:44 -0600252
Brian Pauld9468c92005-02-10 16:08:07 +0000253/**
254 * Remove any texture or renderbuffer attached to the given attachment
255 * point. Update reference counts, etc.
256 */
Brian Paule4b23562005-05-04 20:11:35 +0000257void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400258_mesa_remove_attachment(struct gl_context *ctx, struct gl_renderbuffer_attachment *att)
Brian Paul3deaa012005-02-07 05:08:24 +0000259{
260 if (att->Type == GL_TEXTURE) {
261 ASSERT(att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100262 if (ctx->Driver.FinishRenderTexture) {
Brian Paul0e31e022005-12-01 00:25:00 +0000263 /* tell driver that we're done rendering to this texture. */
Brian9e01b912007-08-13 11:29:46 +0100264 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000265 }
Brian9e01b912007-08-13 11:29:46 +0100266 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
267 ASSERT(!att->Texture);
Brian Paul3deaa012005-02-07 05:08:24 +0000268 }
Brian Paul0e31e022005-12-01 00:25:00 +0000269 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul3deaa012005-02-07 05:08:24 +0000270 ASSERT(!att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100271 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
272 ASSERT(!att->Renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000273 }
274 att->Type = GL_NONE;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000275 att->Complete = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +0000276}
277
278
Brian Pauld9468c92005-02-10 16:08:07 +0000279/**
280 * Bind a texture object to an attachment point.
281 * The previous binding, if any, will be removed first.
282 */
Brian Paule4b23562005-05-04 20:11:35 +0000283void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400284_mesa_set_texture_attachment(struct gl_context *ctx,
Brian Paul519b23b2006-03-20 18:51:57 +0000285 struct gl_framebuffer *fb,
Brian Paule4b23562005-05-04 20:11:35 +0000286 struct gl_renderbuffer_attachment *att,
287 struct gl_texture_object *texObj,
288 GLenum texTarget, GLuint level, GLuint zoffset)
Brian Paul3deaa012005-02-07 05:08:24 +0000289{
Brian Paul0e31e022005-12-01 00:25:00 +0000290 if (att->Texture == texObj) {
291 /* re-attaching same texture */
292 ASSERT(att->Type == GL_TEXTURE);
Eric Anholt6b684822009-11-04 14:31:30 -0800293 if (ctx->Driver.FinishRenderTexture)
294 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000295 }
296 else {
297 /* new attachment */
Eric Anholt6b684822009-11-04 14:31:30 -0800298 if (ctx->Driver.FinishRenderTexture && att->Texture)
299 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000300 _mesa_remove_attachment(ctx, att);
301 att->Type = GL_TEXTURE;
Brian9e01b912007-08-13 11:29:46 +0100302 assert(!att->Texture);
303 _mesa_reference_texobj(&att->Texture, texObj);
Brian Paul0e31e022005-12-01 00:25:00 +0000304 }
305
306 /* always update these fields */
Brian Paul3deaa012005-02-07 05:08:24 +0000307 att->TextureLevel = level;
Brian Paul26f1ad62009-10-23 18:15:55 -0600308 att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
Brian Paul3deaa012005-02-07 05:08:24 +0000309 att->Zoffset = zoffset;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000310 att->Complete = GL_FALSE;
Brian Paul519b23b2006-03-20 18:51:57 +0000311
312 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +0000313 ctx->Driver.RenderTexture(ctx, fb, att);
Brian Paul519b23b2006-03-20 18:51:57 +0000314 }
Brian Paul72966362009-01-21 16:28:38 -0700315
316 invalidate_framebuffer(fb);
Brian Paul3deaa012005-02-07 05:08:24 +0000317}
318
319
Brian Pauld9468c92005-02-10 16:08:07 +0000320/**
321 * Bind a renderbuffer to an attachment point.
322 * The previous binding, if any, will be removed first.
323 */
Brian Paule4b23562005-05-04 20:11:35 +0000324void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400325_mesa_set_renderbuffer_attachment(struct gl_context *ctx,
Brian Paule4b23562005-05-04 20:11:35 +0000326 struct gl_renderbuffer_attachment *att,
327 struct gl_renderbuffer *rb)
Brian Paul3deaa012005-02-07 05:08:24 +0000328{
Brian Paulea4fe662006-03-26 05:22:17 +0000329 /* XXX check if re-doing same attachment, exit early */
Brian Paule4b23562005-05-04 20:11:35 +0000330 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000331 att->Type = GL_RENDERBUFFER_EXT;
Brian Paul2c6f9112005-02-24 05:47:06 +0000332 att->Texture = NULL; /* just to be safe */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000333 att->Complete = GL_FALSE;
Briandccd9c42007-04-02 09:56:28 -0600334 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
Brian Paul3deaa012005-02-07 05:08:24 +0000335}
336
Brian Paulddc82ee2005-02-05 19:56:45 +0000337
Brian Paulf0bbbf62005-02-09 03:50:30 +0000338/**
Brian Paule4b23562005-05-04 20:11:35 +0000339 * Fallback for ctx->Driver.FramebufferRenderbuffer()
Brian Paul84716042005-11-16 04:05:54 +0000340 * Attach a renderbuffer object to a framebuffer object.
Brian Paule4b23562005-05-04 20:11:35 +0000341 */
342void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400343_mesa_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
Brian Paul84716042005-11-16 04:05:54 +0000344 GLenum attachment, struct gl_renderbuffer *rb)
Brian Paule4b23562005-05-04 20:11:35 +0000345{
Brian Paul84716042005-11-16 04:05:54 +0000346 struct gl_renderbuffer_attachment *att;
347
Brian Paulea4fe662006-03-26 05:22:17 +0000348 _glthread_LOCK_MUTEX(fb->Mutex);
Brian Paulea4fe662006-03-26 05:22:17 +0000349
Brian Paul84716042005-11-16 04:05:54 +0000350 att = _mesa_get_attachment(ctx, fb, attachment);
351 ASSERT(att);
Brian Paule4b23562005-05-04 20:11:35 +0000352 if (rb) {
353 _mesa_set_renderbuffer_attachment(ctx, att, rb);
Brian Paul30590072009-01-21 11:06:11 -0700354 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
355 /* do stencil attachment here (depth already done above) */
356 att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
357 assert(att);
358 _mesa_set_renderbuffer_attachment(ctx, att, rb);
359 }
Brian Paule4b23562005-05-04 20:11:35 +0000360 }
361 else {
362 _mesa_remove_attachment(ctx, att);
363 }
Brian Paulea4fe662006-03-26 05:22:17 +0000364
Brian Paul72966362009-01-21 16:28:38 -0700365 invalidate_framebuffer(fb);
366
Brian Paulea4fe662006-03-26 05:22:17 +0000367 _glthread_UNLOCK_MUTEX(fb->Mutex);
Brian Paule4b23562005-05-04 20:11:35 +0000368}
369
370
371/**
Brian Paul9f731c82009-02-17 16:47:54 -0700372 * For debug only.
373 */
374static void
375att_incomplete(const char *msg)
376{
Brian Paulc26c2002009-09-15 17:20:32 -0600377#if DEBUG_FBO
378 _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
Brian Paul9f731c82009-02-17 16:47:54 -0700379#else
380 (void) msg;
381#endif
382}
383
384
385/**
Brian Paulc26c2002009-09-15 17:20:32 -0600386 * For debug only.
387 */
388static void
389fbo_incomplete(const char *msg, int index)
390{
391#if DEBUG_FBO
392 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
393#else
394 (void) msg;
395 (void) index;
396#endif
397}
398
399
400
401
402/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000403 * Test if an attachment point is complete and update its Complete field.
404 * \param format if GL_COLOR, this is a color attachment point,
405 * if GL_DEPTH, this is a depth component attachment point,
406 * if GL_STENCIL, this is a stencil component attachment point.
407 */
408static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400409test_attachment_completeness(const struct gl_context *ctx, GLenum format,
Brian Paul2c6f9112005-02-24 05:47:06 +0000410 struct gl_renderbuffer_attachment *att)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000411{
412 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
413
414 /* assume complete */
415 att->Complete = GL_TRUE;
416
Brian Paulf0bbbf62005-02-09 03:50:30 +0000417 /* Look for reasons why the attachment might be incomplete */
418 if (att->Type == GL_TEXTURE) {
Brian Paule4b23562005-05-04 20:11:35 +0000419 const struct gl_texture_object *texObj = att->Texture;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000420 struct gl_texture_image *texImage;
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600421 GLenum baseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000422
Brian Paule4b23562005-05-04 20:11:35 +0000423 if (!texObj) {
Brian Paul9f731c82009-02-17 16:47:54 -0700424 att_incomplete("no texobj");
Brian Paule4b23562005-05-04 20:11:35 +0000425 att->Complete = GL_FALSE;
426 return;
427 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000428
429 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
430 if (!texImage) {
Brian Paul9f731c82009-02-17 16:47:54 -0700431 att_incomplete("no teximage");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000432 att->Complete = GL_FALSE;
433 return;
434 }
435 if (texImage->Width < 1 || texImage->Height < 1) {
Brian Paul9f731c82009-02-17 16:47:54 -0700436 att_incomplete("teximage width/height=0");
Kristian Høgsberg298be2b2010-02-19 12:32:24 -0500437 printf("texobj = %u\n", texObj->Name);
438 printf("level = %d\n", att->TextureLevel);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000439 att->Complete = GL_FALSE;
440 return;
441 }
442 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
Brian Paul9f731c82009-02-17 16:47:54 -0700443 att_incomplete("bad z offset");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000444 att->Complete = GL_FALSE;
445 return;
446 }
447
Brian Paul1f7c9142009-09-30 20:28:45 -0600448 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600449
Brian Paulf0bbbf62005-02-09 03:50:30 +0000450 if (format == GL_COLOR) {
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600451 if (baseFormat != GL_RGB &&
Eric Anholt262cdbd2010-05-25 08:00:51 -0700452 baseFormat != GL_RGBA &&
453 (!ctx->Extensions.ARB_framebuffer_object ||
Ian Romanick421f4d82010-09-30 16:30:09 -0700454 baseFormat != GL_ALPHA) &&
455 (!ctx->Extensions.ARB_texture_rg ||
456 baseFormat != GL_RED) &&
457 (!ctx->Extensions.ARB_texture_rg ||
458 baseFormat != GL_RG)) {
Brian Paul9f731c82009-02-17 16:47:54 -0700459 att_incomplete("bad format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000460 att->Complete = GL_FALSE;
461 return;
462 }
Brian Paul1f7c9142009-09-30 20:28:45 -0600463 if (_mesa_is_format_compressed(texImage->TexFormat)) {
Eric Anholt957f3c82009-05-15 16:24:59 -0700464 att_incomplete("compressed internalformat");
465 att->Complete = GL_FALSE;
466 return;
467 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000468 }
469 else if (format == GL_DEPTH) {
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600470 if (baseFormat == GL_DEPTH_COMPONENT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000471 /* OK */
472 }
473 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600474 ctx->Extensions.ARB_depth_texture &&
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600475 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000476 /* OK */
477 }
478 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000479 att->Complete = GL_FALSE;
Brian Paul9f731c82009-02-17 16:47:54 -0700480 att_incomplete("bad depth format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000481 return;
482 }
483 }
484 else {
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600485 ASSERT(format == GL_STENCIL);
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600486 if (ctx->Extensions.EXT_packed_depth_stencil &&
487 ctx->Extensions.ARB_depth_texture &&
Brian Paul45e76d22009-10-08 20:27:27 -0600488 baseFormat == GL_DEPTH_STENCIL_EXT) {
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600489 /* OK */
490 }
491 else {
492 /* no such thing as stencil-only textures */
493 att_incomplete("illegal stencil texture");
494 att->Complete = GL_FALSE;
495 return;
496 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000497 }
498 }
Brian Paule4b23562005-05-04 20:11:35 +0000499 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul45e76d22009-10-08 20:27:27 -0600500 const GLenum baseFormat =
501 _mesa_get_format_base_format(att->Renderbuffer->Format);
502
Brian Paul49918882006-03-20 15:27:55 +0000503 ASSERT(att->Renderbuffer);
504 if (!att->Renderbuffer->InternalFormat ||
505 att->Renderbuffer->Width < 1 ||
506 att->Renderbuffer->Height < 1) {
Brian Paul9f731c82009-02-17 16:47:54 -0700507 att_incomplete("0x0 renderbuffer");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000508 att->Complete = GL_FALSE;
509 return;
510 }
511 if (format == GL_COLOR) {
Brian Paul45e76d22009-10-08 20:27:27 -0600512 if (baseFormat != GL_RGB &&
513 baseFormat != GL_RGBA) {
Brian Paul9f731c82009-02-17 16:47:54 -0700514 att_incomplete("bad renderbuffer color format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000515 att->Complete = GL_FALSE;
516 return;
517 }
518 }
519 else if (format == GL_DEPTH) {
Brian Paul45e76d22009-10-08 20:27:27 -0600520 if (baseFormat == GL_DEPTH_COMPONENT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000521 /* OK */
522 }
523 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Brian Paul45e76d22009-10-08 20:27:27 -0600524 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000525 /* OK */
526 }
527 else {
Brian Paul9f731c82009-02-17 16:47:54 -0700528 att_incomplete("bad renderbuffer depth format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000529 att->Complete = GL_FALSE;
530 return;
531 }
532 }
533 else {
534 assert(format == GL_STENCIL);
Brian Paul45e76d22009-10-08 20:27:27 -0600535 if (baseFormat == GL_STENCIL_INDEX) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000536 /* OK */
537 }
538 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Brian Paul45e76d22009-10-08 20:27:27 -0600539 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000540 /* OK */
541 }
542 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000543 att->Complete = GL_FALSE;
Brian Paul9f731c82009-02-17 16:47:54 -0700544 att_incomplete("bad renderbuffer stencil format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000545 return;
546 }
547 }
548 }
Brian Paule4b23562005-05-04 20:11:35 +0000549 else {
550 ASSERT(att->Type == GL_NONE);
551 /* complete */
552 return;
553 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000554}
555
556
557/**
558 * Test if the given framebuffer object is complete and update its
559 * Status field with the results.
Brian Paul3528f692009-01-22 15:13:18 -0700560 * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
561 * driver to make hardware-specific validation/completeness checks.
Brian Paule4b23562005-05-04 20:11:35 +0000562 * Also update the framebuffer's Width and Height fields if the
563 * framebuffer is complete.
Brian Paulf0bbbf62005-02-09 03:50:30 +0000564 */
Brian Paule4b23562005-05-04 20:11:35 +0000565void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400566_mesa_test_framebuffer_completeness(struct gl_context *ctx, struct gl_framebuffer *fb)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000567{
Brian Paul989edea2009-01-22 15:05:13 -0700568 GLuint numImages;
569 GLenum intFormat = GL_NONE; /* color buffers' internal format */
570 GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
Brian Paul722d9762009-01-20 16:58:49 -0700571 GLint numSamples = -1;
Brian Paule4b23562005-05-04 20:11:35 +0000572 GLint i;
Brian Paul28b014e2006-04-05 03:05:17 +0000573 GLuint j;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000574
Brian Paulc7264412005-06-01 00:50:23 +0000575 assert(fb->Name != 0);
576
Brian Paulf0bbbf62005-02-09 03:50:30 +0000577 numImages = 0;
Brian Paule4b23562005-05-04 20:11:35 +0000578 fb->Width = 0;
579 fb->Height = 0;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000580
Brian Paul989edea2009-01-22 15:05:13 -0700581 /* Start at -2 to more easily loop over all attachment points.
582 * -2: depth buffer
583 * -1: stencil buffer
584 * >=0: color buffer
585 */
Brian Paule4b23562005-05-04 20:11:35 +0000586 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000587 struct gl_renderbuffer_attachment *att;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000588 GLenum f;
589
Brian Paul1bc59bf2009-01-22 15:07:34 -0700590 /*
591 * XXX for ARB_fbo, only check color buffers that are named by
592 * GL_READ_BUFFER and GL_DRAW_BUFFERi.
593 */
594
Brian Paul989edea2009-01-22 15:05:13 -0700595 /* check for attachment completeness
596 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000597 if (i == -2) {
Brian Paule4b23562005-05-04 20:11:35 +0000598 att = &fb->Attachment[BUFFER_DEPTH];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000599 test_attachment_completeness(ctx, GL_DEPTH, att);
600 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000601 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000602 fbo_incomplete("depth attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000603 return;
604 }
605 }
606 else if (i == -1) {
Brian Paule4b23562005-05-04 20:11:35 +0000607 att = &fb->Attachment[BUFFER_STENCIL];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000608 test_attachment_completeness(ctx, GL_STENCIL, att);
609 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000610 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000611 fbo_incomplete("stencil attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000612 return;
613 }
614 }
615 else {
Brian Paule4b23562005-05-04 20:11:35 +0000616 att = &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000617 test_attachment_completeness(ctx, GL_COLOR, att);
618 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000619 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000620 fbo_incomplete("color attachment incomplete", i);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000621 return;
622 }
623 }
624
Brian Paul989edea2009-01-22 15:05:13 -0700625 /* get width, height, format of the renderbuffer/texture
626 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000627 if (att->Type == GL_TEXTURE) {
Brian Paula9fc8ba2005-10-05 01:48:07 +0000628 const struct gl_texture_image *texImg
629 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
Brian Paul989edea2009-01-22 15:05:13 -0700630 minWidth = MIN2(minWidth, texImg->Width);
631 maxWidth = MAX2(maxWidth, texImg->Width);
632 minHeight = MIN2(minHeight, texImg->Height);
633 maxHeight = MAX2(maxHeight, texImg->Height);
Brian Paula9fc8ba2005-10-05 01:48:07 +0000634 f = texImg->_BaseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000635 numImages++;
Brian Paul9f6ff492006-03-28 15:24:50 +0000636 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT
Eric Anholt262cdbd2010-05-25 08:00:51 -0700637 && f != GL_DEPTH_STENCIL_EXT
Ian Romanick421f4d82010-09-30 16:30:09 -0700638 && (!ctx->Extensions.ARB_framebuffer_object || f != GL_ALPHA)
639 && (!ctx->Extensions.ARB_texture_rg || f != GL_RED)
640 && (!ctx->Extensions.ARB_texture_rg || f != GL_RG)) {
Brian Pauled7f3ae2005-06-07 15:03:40 +0000641 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000642 fbo_incomplete("texture attachment incomplete", -1);
Brian Pauled7f3ae2005-06-07 15:03:40 +0000643 return;
644 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000645 }
646 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul989edea2009-01-22 15:05:13 -0700647 minWidth = MIN2(minWidth, att->Renderbuffer->Width);
648 maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
649 minHeight = MIN2(minHeight, att->Renderbuffer->Height);
650 maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000651 f = att->Renderbuffer->InternalFormat;
652 numImages++;
653 }
654 else {
655 assert(att->Type == GL_NONE);
656 continue;
657 }
658
Brian Paul72966362009-01-21 16:28:38 -0700659 if (numSamples < 0) {
660 /* first buffer */
661 numSamples = att->Renderbuffer->NumSamples;
662 }
663
Brian Paul722d9762009-01-20 16:58:49 -0700664 /* Error-check width, height, format, samples
Brian Paul989edea2009-01-22 15:05:13 -0700665 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000666 if (numImages == 1) {
Brian Paul722d9762009-01-20 16:58:49 -0700667 /* save format, num samples */
668 if (i >= 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000669 intFormat = f;
Brian Paul722d9762009-01-20 16:58:49 -0700670 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000671 }
672 else {
Brian Paul989edea2009-01-22 15:05:13 -0700673 if (!ctx->Extensions.ARB_framebuffer_object) {
674 /* check that width, height, format are same */
675 if (minWidth != maxWidth || minHeight != maxHeight) {
676 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
677 fbo_incomplete("width or height mismatch", -1);
678 return;
679 }
680 /* check that all color buffer have same format */
681 if (intFormat != GL_NONE && f != intFormat) {
682 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
683 fbo_incomplete("format mismatch", -1);
684 return;
685 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000686 }
Brian Paul722d9762009-01-20 16:58:49 -0700687 if (att->Renderbuffer &&
688 att->Renderbuffer->NumSamples != numSamples) {
Brian Paul72966362009-01-21 16:28:38 -0700689 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
Brian Paul722d9762009-01-20 16:58:49 -0700690 fbo_incomplete("inconsistant number of samples", i);
691 return;
692 }
693
Brian Paulf0bbbf62005-02-09 03:50:30 +0000694 }
695 }
696
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400697#if FEATURE_GL
698 if (ctx->API == API_OPENGL) {
699 /* Check that all DrawBuffers are present */
700 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
701 if (fb->ColorDrawBuffer[j] != GL_NONE) {
702 const struct gl_renderbuffer_attachment *att
703 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
704 assert(att);
705 if (att->Type == GL_NONE) {
706 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
707 fbo_incomplete("missing drawbuffer", j);
708 return;
709 }
710 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000711 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000712
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400713 /* Check that the ReadBuffer is present */
714 if (fb->ColorReadBuffer != GL_NONE) {
715 const struct gl_renderbuffer_attachment *att
716 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
717 assert(att);
718 if (att->Type == GL_NONE) {
719 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000720 fbo_incomplete("missing readbuffer", -1);
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400721 return;
722 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000723 }
724 }
Chia-I Wu9927d7f2009-10-02 15:32:04 +0800725#else
726 (void) j;
Brian Paul868c09a2008-08-08 13:06:54 -0600727#endif
Brian Paulf0bbbf62005-02-09 03:50:30 +0000728
729 if (numImages == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000730 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000731 fbo_incomplete("no attachments", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000732 return;
733 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000734
Brian Paul3528f692009-01-22 15:13:18 -0700735 /* Provisionally set status = COMPLETE ... */
Brian Paule4b23562005-05-04 20:11:35 +0000736 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
Brian Paul3528f692009-01-22 15:13:18 -0700737
Brian Paul777a2ef2009-01-22 15:17:42 -0700738 /* ... but the driver may say the FB is incomplete.
739 * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
740 * if anything.
741 */
Brian Paul3528f692009-01-22 15:13:18 -0700742 if (ctx->Driver.ValidateFramebuffer) {
743 ctx->Driver.ValidateFramebuffer(ctx, fb);
Brian Paul1f32c412009-01-19 17:34:19 -0700744 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
745 fbo_incomplete("driver marked FBO as incomplete", -1);
746 }
Brian Paul3528f692009-01-22 15:13:18 -0700747 }
748
749 if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
750 /*
751 * Note that if ARB_framebuffer_object is supported and the attached
752 * renderbuffers/textures are different sizes, the framebuffer
753 * width/height will be set to the smallest width/height.
754 */
755 fb->Width = minWidth;
756 fb->Height = minHeight;
Brian Paul38768db2009-01-27 09:49:27 -0700757
758 /* finally, update the visual info for the framebuffer */
759 _mesa_update_framebuffer_visual(fb);
Brian Paul3528f692009-01-22 15:13:18 -0700760 }
Brian Paule4b23562005-05-04 20:11:35 +0000761}
Brian Paulf0bbbf62005-02-09 03:50:30 +0000762
763
Brian Paul1864c7d2005-02-08 03:46:37 +0000764GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000765_mesa_IsRenderbufferEXT(GLuint renderbuffer)
766{
Brian Paulddc82ee2005-02-05 19:56:45 +0000767 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000768 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000769 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000770 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000771 if (rb != NULL && rb != &DummyRenderbuffer)
772 return GL_TRUE;
773 }
774 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000775}
776
777
Brian Paul1864c7d2005-02-08 03:46:37 +0000778void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000779_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
780{
Brian42aaa542007-03-25 10:39:36 -0600781 struct gl_renderbuffer *newRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000782 GET_CURRENT_CONTEXT(ctx);
783
784 ASSERT_OUTSIDE_BEGIN_END(ctx);
785
Brian Paul3deaa012005-02-07 05:08:24 +0000786 if (target != GL_RENDERBUFFER_EXT) {
Brian Paul4de18fb2009-11-02 15:30:51 -0700787 _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000788 return;
789 }
790
Brian Paul800e5532009-11-02 15:39:39 -0700791 /* No need to flush here since the render buffer binding has no
792 * effect on rendering state.
793 */
Brian Paul474f28e2005-10-08 14:41:17 +0000794
Brian Paul3deaa012005-02-07 05:08:24 +0000795 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000796 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000797 if (newRb == &DummyRenderbuffer) {
798 /* ID was reserved, but no real renderbuffer object made yet */
799 newRb = NULL;
800 }
Brian Paul1bc59bf2009-01-22 15:07:34 -0700801 else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
802 /* All RB IDs must be Gen'd */
803 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
804 return;
805 }
806
Brian Paul3deaa012005-02-07 05:08:24 +0000807 if (!newRb) {
808 /* create new renderbuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000809 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000810 if (!newRb) {
811 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
812 return;
813 }
Brian Paul2c6f9112005-02-24 05:47:06 +0000814 ASSERT(newRb->AllocStorage);
Brian Paul1864c7d2005-02-08 03:46:37 +0000815 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
Brian42aaa542007-03-25 10:39:36 -0600816 newRb->RefCount = 1; /* referenced by hash table */
Brian Paul3deaa012005-02-07 05:08:24 +0000817 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000818 }
Brian Paul463642c2005-02-08 02:06:00 +0000819 else {
820 newRb = NULL;
821 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000822
Brian Paul1864c7d2005-02-08 03:46:37 +0000823 ASSERT(newRb != &DummyRenderbuffer);
824
Brian42aaa542007-03-25 10:39:36 -0600825 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
Brian Paulddc82ee2005-02-05 19:56:45 +0000826}
827
828
Brian Pauld0f13fa2009-01-21 11:17:45 -0700829/**
830 * If the given renderbuffer is anywhere attached to the framebuffer, detach
831 * the renderbuffer.
832 * This is used when a renderbuffer object is deleted.
833 * The spec calls for unbinding.
834 */
835static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400836detach_renderbuffer(struct gl_context *ctx,
Brian Pauld0f13fa2009-01-21 11:17:45 -0700837 struct gl_framebuffer *fb,
838 struct gl_renderbuffer *rb)
839{
840 GLuint i;
841 for (i = 0; i < BUFFER_COUNT; i++) {
842 if (fb->Attachment[i].Renderbuffer == rb) {
843 _mesa_remove_attachment(ctx, &fb->Attachment[i]);
844 }
845 }
Brian Paul72966362009-01-21 16:28:38 -0700846 invalidate_framebuffer(fb);
Brian Pauld0f13fa2009-01-21 11:17:45 -0700847}
848
849
Brian Paul1864c7d2005-02-08 03:46:37 +0000850void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000851_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
852{
853 GLint i;
854 GET_CURRENT_CONTEXT(ctx);
855
856 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000857 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000858
859 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000860 if (renderbuffers[i] > 0) {
861 struct gl_renderbuffer *rb;
Brian Paulea4fe662006-03-26 05:22:17 +0000862 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +0000863 if (rb) {
Brian Paul91802fd2005-10-04 16:01:02 +0000864 /* check if deleting currently bound renderbuffer object */
865 if (rb == ctx->CurrentRenderbuffer) {
866 /* bind default */
867 ASSERT(rb->RefCount >= 2);
868 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
869 }
870
Brian Pauld0f13fa2009-01-21 11:17:45 -0700871 if (ctx->DrawBuffer->Name) {
872 detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
873 }
874 if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) {
875 detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
876 }
877
Brian42aaa542007-03-25 10:39:36 -0600878 /* Remove from hash table immediately, to free the ID.
879 * But the object will not be freed until it's no longer
880 * referenced anywhere else.
881 */
Brian Paul3deaa012005-02-07 05:08:24 +0000882 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +0000883
Brian Paul1864c7d2005-02-08 03:46:37 +0000884 if (rb != &DummyRenderbuffer) {
Brian42aaa542007-03-25 10:39:36 -0600885 /* no longer referenced by hash table */
886 _mesa_reference_renderbuffer(&rb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +0000887 }
888 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000889 }
890 }
891}
892
893
Brian Paul1864c7d2005-02-08 03:46:37 +0000894void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000895_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
896{
897 GET_CURRENT_CONTEXT(ctx);
898 GLuint first;
899 GLint i;
900
901 ASSERT_OUTSIDE_BEGIN_END(ctx);
902
903 if (n < 0) {
904 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
905 return;
906 }
907
908 if (!renderbuffers)
909 return;
910
911 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
912
913 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000914 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000915 renderbuffers[i] = name;
Brian Paul1864c7d2005-02-08 03:46:37 +0000916 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +0000917 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +0000918 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +0000919 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +0000920 }
921}
922
923
Brian Pauld9468c92005-02-10 16:08:07 +0000924/**
925 * Given an internal format token for a render buffer, return the
926 * corresponding base format.
Brian Paul59e0faa2006-03-15 17:48:00 +0000927 * This is very similar to _mesa_base_tex_format() but the set of valid
928 * internal formats is somewhat different.
929 *
Brian Pauld9468c92005-02-10 16:08:07 +0000930 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
Brian Paul1ad7b992005-09-28 02:29:50 +0000931 * GL_DEPTH_STENCIL_EXT or zero if error.
Brian Paul031f23a2010-01-19 17:59:50 -0700932 *
933 * XXX in the future when we support red-only and red-green formats
934 * we'll also return GL_RED and GL_RG.
Brian Pauld9468c92005-02-10 16:08:07 +0000935 */
Brian Paul59e0faa2006-03-15 17:48:00 +0000936GLenum
Kristian Høgsbergf9995b32010-10-12 12:26:10 -0400937_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
Brian Paul463642c2005-02-08 02:06:00 +0000938{
939 switch (internalFormat) {
Eric Anholt50a33492010-09-07 14:31:22 -0700940 case GL_ALPHA:
941 case GL_ALPHA4:
942 case GL_ALPHA8:
943 case GL_ALPHA12:
944 case GL_ALPHA16:
945 return GL_ALPHA;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000946 case GL_RGB:
947 case GL_R3_G3_B2:
948 case GL_RGB4:
949 case GL_RGB5:
950 case GL_RGB8:
951 case GL_RGB10:
952 case GL_RGB12:
953 case GL_RGB16:
954 return GL_RGB;
955 case GL_RGBA:
956 case GL_RGBA2:
957 case GL_RGBA4:
958 case GL_RGB5_A1:
959 case GL_RGBA8:
960 case GL_RGB10_A2:
961 case GL_RGBA12:
962 case GL_RGBA16:
Brian Paul8ea61482010-05-09 18:42:14 -0600963 case GL_RGBA16_SNORM:
Brian Paulf0bbbf62005-02-09 03:50:30 +0000964 return GL_RGBA;
965 case GL_STENCIL_INDEX:
966 case GL_STENCIL_INDEX1_EXT:
967 case GL_STENCIL_INDEX4_EXT:
968 case GL_STENCIL_INDEX8_EXT:
969 case GL_STENCIL_INDEX16_EXT:
970 return GL_STENCIL_INDEX;
971 case GL_DEPTH_COMPONENT:
Brian Paul2c6f9112005-02-24 05:47:06 +0000972 case GL_DEPTH_COMPONENT16:
973 case GL_DEPTH_COMPONENT24:
974 case GL_DEPTH_COMPONENT32:
Brian Paulf0bbbf62005-02-09 03:50:30 +0000975 return GL_DEPTH_COMPONENT;
Brian Paul1ad7b992005-09-28 02:29:50 +0000976 case GL_DEPTH_STENCIL_EXT:
977 case GL_DEPTH24_STENCIL8_EXT:
978 if (ctx->Extensions.EXT_packed_depth_stencil)
979 return GL_DEPTH_STENCIL_EXT;
980 else
981 return 0;
Brian Pauld9468c92005-02-10 16:08:07 +0000982 /* XXX add floating point formats eventually */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000983 default:
984 return 0;
Brian Paul463642c2005-02-08 02:06:00 +0000985 }
Brian Paul463642c2005-02-08 02:06:00 +0000986}
987
988
Brian Paul4f3514e2009-01-22 15:19:56 -0700989/** sentinal value, see below */
990#define NO_SAMPLES 1000
991
992
993/**
994 * Helper function used by _mesa_RenderbufferStorageEXT() and
995 * _mesa_RenderbufferStorageMultisample().
996 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
997 */
998static void
999renderbuffer_storage(GLenum target, GLenum internalFormat,
1000 GLsizei width, GLsizei height, GLsizei samples)
Brian Paulddc82ee2005-02-05 19:56:45 +00001001{
Brian Paul4f3514e2009-01-22 15:19:56 -07001002 const char *func = samples == NO_SAMPLES ?
1003 "glRenderbufferStorage" : "RenderbufferStorageMultisample";
Brian Paul2c6f9112005-02-24 05:47:06 +00001004 struct gl_renderbuffer *rb;
Brian Paul463642c2005-02-08 02:06:00 +00001005 GLenum baseFormat;
Brian Paulddc82ee2005-02-05 19:56:45 +00001006 GET_CURRENT_CONTEXT(ctx);
1007
1008 ASSERT_OUTSIDE_BEGIN_END(ctx);
1009
Brian Paul463642c2005-02-08 02:06:00 +00001010 if (target != GL_RENDERBUFFER_EXT) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001011 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001012 return;
1013 }
1014
Brian Paul59e0faa2006-03-15 17:48:00 +00001015 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
Brian Paul463642c2005-02-08 02:06:00 +00001016 if (baseFormat == 0) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001017 _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001018 return;
1019 }
1020
Brian Paul13abf912006-04-13 19:17:13 +00001021 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001022 _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001023 return;
1024 }
1025
Brian Paul13abf912006-04-13 19:17:13 +00001026 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001027 _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
1028 return;
1029 }
1030
1031 if (samples == NO_SAMPLES) {
1032 /* NumSamples == 0 indicates non-multisampling */
1033 samples = 0;
1034 }
Brian Paulca0d0482010-01-27 17:01:54 -07001035 else if (samples > (GLsizei) ctx->Const.MaxSamples) {
Brian Paul722d9762009-01-20 16:58:49 -07001036 /* note: driver may choose to use more samples than what's requested */
Brian Paul4f3514e2009-01-22 15:19:56 -07001037 _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001038 return;
1039 }
1040
Brian Paul2c6f9112005-02-24 05:47:06 +00001041 rb = ctx->CurrentRenderbuffer;
Brian Paul2c6f9112005-02-24 05:47:06 +00001042 if (!rb) {
Vinson Leec5dde532010-09-02 16:03:32 -07001043 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
Brian Paul463642c2005-02-08 02:06:00 +00001044 return;
1045 }
1046
Brian Paul474f28e2005-10-08 14:41:17 +00001047 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1048
Brian Paul311bcf52005-11-18 02:24:14 +00001049 if (rb->InternalFormat == internalFormat &&
Brian Paul13abf912006-04-13 19:17:13 +00001050 rb->Width == (GLuint) width &&
1051 rb->Height == (GLuint) height) {
Brian Paul311bcf52005-11-18 02:24:14 +00001052 /* no change in allocation needed */
1053 return;
1054 }
1055
Brian Paulea4fe662006-03-26 05:22:17 +00001056 /* These MUST get set by the AllocStorage func */
Brian Paul45e76d22009-10-08 20:27:27 -06001057 rb->Format = MESA_FORMAT_NONE;
Brian Paul4f3514e2009-01-22 15:19:56 -07001058 rb->NumSamples = samples;
Brian Paulea4fe662006-03-26 05:22:17 +00001059
Brian Paul2c6f9112005-02-24 05:47:06 +00001060 /* Now allocate the storage */
1061 ASSERT(rb->AllocStorage);
1062 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
1063 /* No error - check/set fields now */
Brian Paul45e76d22009-10-08 20:27:27 -06001064 assert(rb->Format != MESA_FORMAT_NONE);
Brian Paul13abf912006-04-13 19:17:13 +00001065 assert(rb->Width == (GLuint) width);
1066 assert(rb->Height == (GLuint) height);
Brian Paulea4fe662006-03-26 05:22:17 +00001067 rb->InternalFormat = internalFormat;
Brian Paula8dafe72010-02-25 19:03:55 -07001068 rb->_BaseFormat = baseFormat;
Brian Paul45e76d22009-10-08 20:27:27 -06001069 assert(rb->_BaseFormat != 0);
Brian Paul2c6f9112005-02-24 05:47:06 +00001070 }
1071 else {
1072 /* Probably ran out of memory - clear the fields */
1073 rb->Width = 0;
1074 rb->Height = 0;
Brian Paul45e76d22009-10-08 20:27:27 -06001075 rb->Format = MESA_FORMAT_NONE;
Brian Paul2c6f9112005-02-24 05:47:06 +00001076 rb->InternalFormat = GL_NONE;
1077 rb->_BaseFormat = GL_NONE;
Brian Paul4f3514e2009-01-22 15:19:56 -07001078 rb->NumSamples = 0;
Brian Paul463642c2005-02-08 02:06:00 +00001079 }
1080
Brian Paule4b23562005-05-04 20:11:35 +00001081 /*
1082 test_framebuffer_completeness(ctx, fb);
1083 */
Brian Paul2c6f9112005-02-24 05:47:06 +00001084 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
1085 * points???
1086 */
Brian Paulddc82ee2005-02-05 19:56:45 +00001087}
1088
Brian Paul23c5b212010-05-28 13:33:03 -06001089
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001090#if FEATURE_OES_EGL_image
1091void GLAPIENTRY
Brian Paul23c5b212010-05-28 13:33:03 -06001092_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001093{
Brian Paul51b79922010-02-24 11:57:26 -07001094 struct gl_renderbuffer *rb;
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001095 GET_CURRENT_CONTEXT(ctx);
1096 ASSERT_OUTSIDE_BEGIN_END(ctx);
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001097
Chia-I Wu2002e4d02010-04-06 17:46:17 +08001098 if (!ctx->Extensions.OES_EGL_image) {
1099 _mesa_error(ctx, GL_INVALID_OPERATION,
1100 "glEGLImageTargetRenderbufferStorageOES(unsupported)");
1101 return;
1102 }
1103
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001104 if (target != GL_RENDERBUFFER) {
Brian Paul23c5b212010-05-28 13:33:03 -06001105 _mesa_error(ctx, GL_INVALID_ENUM,
1106 "EGLImageTargetRenderbufferStorageOES");
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001107 return;
1108 }
1109
1110 rb = ctx->CurrentRenderbuffer;
1111 if (!rb) {
Brian Paul23c5b212010-05-28 13:33:03 -06001112 _mesa_error(ctx, GL_INVALID_OPERATION,
1113 "EGLImageTargetRenderbufferStorageOES");
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001114 return;
1115 }
1116
1117 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1118
1119 ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1120}
1121#endif
Brian Paulddc82ee2005-02-05 19:56:45 +00001122
Brian Paul23c5b212010-05-28 13:33:03 -06001123
Brian Paul45e76d22009-10-08 20:27:27 -06001124/**
1125 * Helper function for _mesa_GetRenderbufferParameterivEXT() and
1126 * _mesa_GetFramebufferAttachmentParameterivEXT()
1127 * We have to be careful to respect the base format. For example, if a
1128 * renderbuffer/texture was created with internalFormat=GL_RGB but the
1129 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
1130 * we need to return zero.
1131 */
1132static GLint
1133get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
1134{
1135 switch (pname) {
1136 case GL_RENDERBUFFER_RED_SIZE_EXT:
1137 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
1138 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1139 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
1140 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1141 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
1142 if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
1143 return _mesa_get_format_bits(format, pname);
1144 else
1145 return 0;
1146 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1147 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
1148 if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA)
1149 return _mesa_get_format_bits(format, pname);
1150 else
1151 return 0;
1152 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1153 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
1154 if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
1155 return _mesa_get_format_bits(format, pname);
1156 else
1157 return 0;
1158 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1159 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
1160 if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
1161 return _mesa_get_format_bits(format, pname);
1162 else
1163 return 0;
1164 default:
1165 return 0;
1166 }
1167}
1168
1169
1170
Brian Paul1864c7d2005-02-08 03:46:37 +00001171void GLAPIENTRY
Brian Paul4f3514e2009-01-22 15:19:56 -07001172_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1173 GLsizei width, GLsizei height)
1174{
Brian Paul722d9762009-01-20 16:58:49 -07001175 /* GL_ARB_fbo says calling this function is equivalent to calling
1176 * glRenderbufferStorageMultisample() with samples=0. We pass in
1177 * a token value here just for error reporting purposes.
1178 */
Brian Paul4f3514e2009-01-22 15:19:56 -07001179 renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
1180}
1181
1182
1183void GLAPIENTRY
Brian Paul777a2ef2009-01-22 15:17:42 -07001184_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
Brian Paul4f3514e2009-01-22 15:19:56 -07001185 GLenum internalFormat,
Brian Paul777a2ef2009-01-22 15:17:42 -07001186 GLsizei width, GLsizei height)
1187{
Brian Paul4f3514e2009-01-22 15:19:56 -07001188 renderbuffer_storage(target, internalFormat, width, height, samples);
Brian Paul777a2ef2009-01-22 15:17:42 -07001189}
1190
Brian Paul23c5b212010-05-28 13:33:03 -06001191
1192/**
1193 * OpenGL ES version of glRenderBufferStorage.
1194 */
Kristian Høgsberg61d94dd2010-04-22 21:11:56 -04001195void GLAPIENTRY
1196_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1197 GLsizei width, GLsizei height)
1198{
1199 switch (internalFormat) {
1200 case GL_RGB565:
1201 /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
1202 /* choose a closest format */
1203 internalFormat = GL_RGB5;
1204 break;
1205 default:
1206 break;
1207 }
Brian Paul777a2ef2009-01-22 15:17:42 -07001208
Kristian Høgsberg61d94dd2010-04-22 21:11:56 -04001209 renderbuffer_storage(target, internalFormat, width, height, 0);
1210}
Brian Paul777a2ef2009-01-22 15:17:42 -07001211
Brian Paul23c5b212010-05-28 13:33:03 -06001212
Brian Paul777a2ef2009-01-22 15:17:42 -07001213void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001214_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
1215{
Brian Paul722d9762009-01-20 16:58:49 -07001216 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001217 GET_CURRENT_CONTEXT(ctx);
1218
1219 ASSERT_OUTSIDE_BEGIN_END(ctx);
1220
Brian Paul463642c2005-02-08 02:06:00 +00001221 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001222 _mesa_error(ctx, GL_INVALID_ENUM,
1223 "glGetRenderbufferParameterivEXT(target)");
1224 return;
1225 }
1226
Brian Paul722d9762009-01-20 16:58:49 -07001227 rb = ctx->CurrentRenderbuffer;
1228 if (!rb) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001229 _mesa_error(ctx, GL_INVALID_OPERATION,
1230 "glGetRenderbufferParameterivEXT");
1231 return;
1232 }
1233
Brian Paul800e5532009-11-02 15:39:39 -07001234 /* No need to flush here since we're just quering state which is
1235 * not effected by rendering.
1236 */
Brian Paul474f28e2005-10-08 14:41:17 +00001237
Brian Paul463642c2005-02-08 02:06:00 +00001238 switch (pname) {
1239 case GL_RENDERBUFFER_WIDTH_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001240 *params = rb->Width;
Brian Paul463642c2005-02-08 02:06:00 +00001241 return;
1242 case GL_RENDERBUFFER_HEIGHT_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001243 *params = rb->Height;
Brian Paul463642c2005-02-08 02:06:00 +00001244 return;
1245 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001246 *params = rb->InternalFormat;
Brian Paul463642c2005-02-08 02:06:00 +00001247 return;
Brian Paul1b939532005-05-31 23:55:21 +00001248 case GL_RENDERBUFFER_RED_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001249 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001250 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001251 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001252 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001253 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
Brian Paul45e76d22009-10-08 20:27:27 -06001254 *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
Brian Paul1b939532005-05-31 23:55:21 +00001255 break;
Brian Paul722d9762009-01-20 16:58:49 -07001256 case GL_RENDERBUFFER_SAMPLES:
1257 if (ctx->Extensions.ARB_framebuffer_object) {
1258 *params = rb->NumSamples;
1259 break;
1260 }
1261 /* fallthrough */
Brian Paul463642c2005-02-08 02:06:00 +00001262 default:
1263 _mesa_error(ctx, GL_INVALID_ENUM,
1264 "glGetRenderbufferParameterivEXT(target)");
1265 return;
1266 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001267}
1268
1269
Brian Paul1864c7d2005-02-08 03:46:37 +00001270GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001271_mesa_IsFramebufferEXT(GLuint framebuffer)
1272{
Brian Paulddc82ee2005-02-05 19:56:45 +00001273 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +00001274 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +00001275 if (framebuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00001276 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +00001277 if (rb != NULL && rb != &DummyFramebuffer)
1278 return GL_TRUE;
1279 }
1280 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +00001281}
1282
1283
briana492ab72009-11-10 15:33:31 -07001284/**
1285 * Check if any of the attachments of the given framebuffer are textures
1286 * (render to texture). Call ctx->Driver.RenderTexture() for such
1287 * attachments.
1288 */
Brian Paulea4fe662006-03-26 05:22:17 +00001289static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001290check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
Brian Paulea4fe662006-03-26 05:22:17 +00001291{
1292 GLuint i;
1293 ASSERT(ctx->Driver.RenderTexture);
briana65b84d2009-11-10 18:02:03 -07001294
1295 if (fb->Name == 0)
1296 return; /* can't render to texture with winsys framebuffers */
1297
Brian Paulea4fe662006-03-26 05:22:17 +00001298 for (i = 0; i < BUFFER_COUNT; i++) {
1299 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1300 struct gl_texture_object *texObj = att->Texture;
Brian Paul9f6ff492006-03-28 15:24:50 +00001301 if (texObj
Brian Paulb5d6a8e2009-10-12 18:09:32 -06001302 && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +00001303 ctx->Driver.RenderTexture(ctx, fb, att);
1304 }
1305 }
1306}
1307
1308
Brian Paul0e31e022005-12-01 00:25:00 +00001309/**
1310 * Examine all the framebuffer's attachments to see if any are textures.
1311 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
1312 * notify the device driver that the texture image may have changed.
1313 */
1314static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001315check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
Brian Paul0e31e022005-12-01 00:25:00 +00001316{
briana65b84d2009-11-10 18:02:03 -07001317 if (fb->Name == 0)
1318 return; /* can't render to texture with winsys framebuffers */
1319
Brian Paul0e31e022005-12-01 00:25:00 +00001320 if (ctx->Driver.FinishRenderTexture) {
1321 GLuint i;
1322 for (i = 0; i < BUFFER_COUNT; i++) {
1323 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
Brian8b361662007-11-09 08:55:49 -07001324 if (att->Texture && att->Renderbuffer) {
Brian Paul519b23b2006-03-20 18:51:57 +00001325 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +00001326 }
1327 }
1328 }
1329}
1330
1331
Brian Paul1864c7d2005-02-08 03:46:37 +00001332void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001333_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
1334{
briane6f60d32009-11-10 15:47:34 -07001335 struct gl_framebuffer *newDrawFb, *newReadFb;
briand96e55f2009-11-10 15:50:22 -07001336 struct gl_framebuffer *oldDrawFb, *oldReadFb;
Brian Paul0bffb112005-11-08 14:45:48 +00001337 GLboolean bindReadBuf, bindDrawBuf;
Brian Paulddc82ee2005-02-05 19:56:45 +00001338 GET_CURRENT_CONTEXT(ctx);
1339
Brian Paul1bc59bf2009-01-22 15:07:34 -07001340#ifdef DEBUG
1341 if (ctx->Extensions.ARB_framebuffer_object) {
1342 ASSERT(ctx->Extensions.EXT_framebuffer_object);
1343 ASSERT(ctx->Extensions.EXT_framebuffer_blit);
1344 }
1345#endif
1346
Brian Paulddc82ee2005-02-05 19:56:45 +00001347 ASSERT_OUTSIDE_BEGIN_END(ctx);
1348
Brian Paulea4fe662006-03-26 05:22:17 +00001349 if (!ctx->Extensions.EXT_framebuffer_object) {
1350 _mesa_error(ctx, GL_INVALID_OPERATION,
1351 "glBindFramebufferEXT(unsupported)");
1352 return;
1353 }
1354
Brian Paul0bffb112005-11-08 14:45:48 +00001355 switch (target) {
1356#if FEATURE_EXT_framebuffer_blit
1357 case GL_DRAW_FRAMEBUFFER_EXT:
1358 if (!ctx->Extensions.EXT_framebuffer_blit) {
1359 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1360 return;
1361 }
1362 bindDrawBuf = GL_TRUE;
1363 bindReadBuf = GL_FALSE;
1364 break;
1365 case GL_READ_FRAMEBUFFER_EXT:
1366 if (!ctx->Extensions.EXT_framebuffer_blit) {
1367 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1368 return;
1369 }
1370 bindDrawBuf = GL_FALSE;
1371 bindReadBuf = GL_TRUE;
1372 break;
1373#endif
1374 case GL_FRAMEBUFFER_EXT:
1375 bindDrawBuf = GL_TRUE;
1376 bindReadBuf = GL_TRUE;
1377 break;
1378 default:
Brian Pauleba4ff62005-09-06 21:22:16 +00001379 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +00001380 return;
1381 }
1382
Brian Paul3deaa012005-02-07 05:08:24 +00001383 if (framebuffer) {
Brian Paule4b23562005-05-04 20:11:35 +00001384 /* Binding a user-created framebuffer object */
briane6f60d32009-11-10 15:47:34 -07001385 newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
1386 if (newDrawFb == &DummyFramebuffer) {
Brian Paul923b6fc2005-02-08 04:08:56 +00001387 /* ID was reserved, but no real framebuffer object made yet */
briane6f60d32009-11-10 15:47:34 -07001388 newDrawFb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001389 }
briane6f60d32009-11-10 15:47:34 -07001390 else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
Brian Paul1bc59bf2009-01-22 15:07:34 -07001391 /* All FBO IDs must be Gen'd */
1392 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
1393 return;
1394 }
1395
briane6f60d32009-11-10 15:47:34 -07001396 if (!newDrawFb) {
Brian Paul3deaa012005-02-07 05:08:24 +00001397 /* create new framebuffer object */
briane6f60d32009-11-10 15:47:34 -07001398 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
1399 if (!newDrawFb) {
Brian Paul3deaa012005-02-07 05:08:24 +00001400 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1401 return;
1402 }
briane6f60d32009-11-10 15:47:34 -07001403 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
Brian Paul3deaa012005-02-07 05:08:24 +00001404 }
briane6f60d32009-11-10 15:47:34 -07001405 newReadFb = newDrawFb;
Brian Paul3deaa012005-02-07 05:08:24 +00001406 }
Brian Paul463642c2005-02-08 02:06:00 +00001407 else {
Brian Paule4b23562005-05-04 20:11:35 +00001408 /* Binding the window system framebuffer (which was originally set
1409 * with MakeCurrent).
1410 */
briane6f60d32009-11-10 15:47:34 -07001411 newDrawFb = ctx->WinSysDrawBuffer;
1412 newReadFb = ctx->WinSysReadBuffer;
Brian Paul3deaa012005-02-07 05:08:24 +00001413 }
1414
briane6f60d32009-11-10 15:47:34 -07001415 ASSERT(newDrawFb);
1416 ASSERT(newDrawFb != &DummyFramebuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001417
briana65b84d2009-11-10 18:02:03 -07001418 /* save pointers to current/old framebuffers */
briand96e55f2009-11-10 15:50:22 -07001419 oldDrawFb = ctx->DrawBuffer;
1420 oldReadFb = ctx->ReadBuffer;
1421
briana65b84d2009-11-10 18:02:03 -07001422 /* check if really changing bindings */
1423 if (oldDrawFb == newDrawFb)
1424 bindDrawBuf = GL_FALSE;
1425 if (oldReadFb == newReadFb)
1426 bindReadBuf = GL_FALSE;
1427
Brian Paulea4fe662006-03-26 05:22:17 +00001428 /*
Brian Paul16144632009-02-26 14:49:24 -07001429 * OK, now bind the new Draw/Read framebuffers, if they're changing.
briana65b84d2009-11-10 18:02:03 -07001430 *
1431 * We also check if we're beginning and/or ending render-to-texture.
1432 * When a framebuffer with texture attachments is unbound, call
1433 * ctx->Driver.FinishRenderTexture().
1434 * When a framebuffer with texture attachments is bound, call
1435 * ctx->Driver.RenderTexture().
1436 *
1437 * Note that if the ReadBuffer has texture attachments we don't consider
1438 * that a render-to-texture case.
Brian Paulea4fe662006-03-26 05:22:17 +00001439 */
Brian Paul0bffb112005-11-08 14:45:48 +00001440 if (bindReadBuf) {
briana65b84d2009-11-10 18:02:03 -07001441 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
brianbc569cd2009-11-10 16:00:35 -07001442
briana65b84d2009-11-10 18:02:03 -07001443 /* check if old readbuffer was render-to-texture */
1444 check_end_texture_render(ctx, oldReadFb);
1445
1446 _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001447 }
1448
1449 if (bindDrawBuf) {
briana65b84d2009-11-10 18:02:03 -07001450 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian32d86eb2007-08-16 18:52:48 +01001451
briana65b84d2009-11-10 18:02:03 -07001452 /* check if old read/draw buffers were render-to-texture */
1453 if (!bindReadBuf)
1454 check_end_texture_render(ctx, oldReadFb);
brianbc569cd2009-11-10 16:00:35 -07001455
briana65b84d2009-11-10 18:02:03 -07001456 if (oldDrawFb != oldReadFb)
1457 check_end_texture_render(ctx, oldDrawFb);
brianbc569cd2009-11-10 16:00:35 -07001458
briana65b84d2009-11-10 18:02:03 -07001459 /* check if newly bound framebuffer has any texture attachments */
1460 check_begin_texture_render(ctx, newDrawFb);
1461
1462 _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001463 }
Brian Paul59e0faa2006-03-15 17:48:00 +00001464
Brian Paul16144632009-02-26 14:49:24 -07001465 if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
briane6f60d32009-11-10 15:47:34 -07001466 ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
Brian Paul59e0faa2006-03-15 17:48:00 +00001467 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001468}
1469
1470
Brian Paul1864c7d2005-02-08 03:46:37 +00001471void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001472_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1473{
1474 GLint i;
1475 GET_CURRENT_CONTEXT(ctx);
1476
1477 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul800e5532009-11-02 15:39:39 -07001478 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00001479
1480 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +00001481 if (framebuffers[i] > 0) {
1482 struct gl_framebuffer *fb;
Brian Paulea4fe662006-03-26 05:22:17 +00001483 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +00001484 if (fb) {
Brian Paule4b23562005-05-04 20:11:35 +00001485 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
Brian Paul91802fd2005-10-04 16:01:02 +00001486
1487 /* check if deleting currently bound framebuffer object */
Erik Wien68ca19a2010-01-26 13:19:30 -07001488 if (ctx->Extensions.EXT_framebuffer_blit) {
1489 /* separate draw/read binding points */
1490 if (fb == ctx->DrawBuffer) {
1491 /* bind default */
1492 ASSERT(fb->RefCount >= 2);
1493 _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1494 }
1495 if (fb == ctx->ReadBuffer) {
1496 /* bind default */
1497 ASSERT(fb->RefCount >= 2);
1498 _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1499 }
Brian Pauld0f13fa2009-01-21 11:17:45 -07001500 }
Erik Wien68ca19a2010-01-26 13:19:30 -07001501 else {
1502 /* only one binding point for read/draw buffers */
1503 if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
1504 /* bind default */
1505 ASSERT(fb->RefCount >= 2);
1506 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1507 }
Brian Paul91802fd2005-10-04 16:01:02 +00001508 }
1509
Brian Paul3deaa012005-02-07 05:08:24 +00001510 /* remove from hash table immediately, to free the ID */
1511 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +00001512
Brian Paul1864c7d2005-02-08 03:46:37 +00001513 if (fb != &DummyFramebuffer) {
1514 /* But the object will not be freed until it's no longer
1515 * bound in any context.
1516 */
Brian Pauld5229442009-02-09 08:30:55 -07001517 _mesa_reference_framebuffer(&fb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +00001518 }
1519 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001520 }
1521 }
1522}
1523
1524
Brian Paul1864c7d2005-02-08 03:46:37 +00001525void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001526_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1527{
1528 GET_CURRENT_CONTEXT(ctx);
1529 GLuint first;
1530 GLint i;
1531
1532 ASSERT_OUTSIDE_BEGIN_END(ctx);
1533
1534 if (n < 0) {
1535 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1536 return;
1537 }
1538
1539 if (!framebuffers)
1540 return;
1541
1542 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1543
1544 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001545 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001546 framebuffers[i] = name;
1547 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001548 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001549 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001550 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001551 }
1552}
1553
1554
1555
Brian Paul1864c7d2005-02-08 03:46:37 +00001556GLenum GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001557_mesa_CheckFramebufferStatusEXT(GLenum target)
1558{
Brian Paul0bffb112005-11-08 14:45:48 +00001559 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001560 GET_CURRENT_CONTEXT(ctx);
1561
Brian Paule4b23562005-05-04 20:11:35 +00001562 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001563
Brian Paul0bffb112005-11-08 14:45:48 +00001564 switch (target) {
1565#if FEATURE_EXT_framebuffer_blit
1566 case GL_DRAW_FRAMEBUFFER_EXT:
1567 if (!ctx->Extensions.EXT_framebuffer_blit) {
1568 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1569 return 0;
1570 }
1571 buffer = ctx->DrawBuffer;
1572 break;
1573 case GL_READ_FRAMEBUFFER_EXT:
1574 if (!ctx->Extensions.EXT_framebuffer_blit) {
1575 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1576 return 0;
1577 }
1578 buffer = ctx->ReadBuffer;
1579 break;
1580#endif
1581 case GL_FRAMEBUFFER_EXT:
1582 buffer = ctx->DrawBuffer;
1583 break;
1584 default:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001585 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
Brian Paule4b23562005-05-04 20:11:35 +00001586 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
Brian Paulddc82ee2005-02-05 19:56:45 +00001587 }
1588
Brian Paul0bffb112005-11-08 14:45:48 +00001589 if (buffer->Name == 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001590 /* The window system / default framebuffer is always complete */
1591 return GL_FRAMEBUFFER_COMPLETE_EXT;
1592 }
1593
Brian Paul800e5532009-11-02 15:39:39 -07001594 /* No need to flush here */
Brian Paul474f28e2005-10-08 14:41:17 +00001595
Brian Paul72966362009-01-21 16:28:38 -07001596 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
1597 _mesa_test_framebuffer_completeness(ctx, buffer);
1598 }
1599
Brian Paul0bffb112005-11-08 14:45:48 +00001600 return buffer->_Status;
Brian Paulddc82ee2005-02-05 19:56:45 +00001601}
1602
1603
1604
1605/**
Brian Paulea4fe662006-03-26 05:22:17 +00001606 * Common code called by glFramebufferTexture1D/2D/3DEXT().
Brian Paulddc82ee2005-02-05 19:56:45 +00001607 */
Brian Paulea4fe662006-03-26 05:22:17 +00001608static void
Kristian Høgsbergf9995b32010-10-12 12:26:10 -04001609framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001610 GLenum attachment, GLenum textarget, GLuint texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001611 GLint level, GLint zoffset)
Brian Paulddc82ee2005-02-05 19:56:45 +00001612{
Brian Paul2c6f9112005-02-24 05:47:06 +00001613 struct gl_renderbuffer_attachment *att;
Brian Paulea4fe662006-03-26 05:22:17 +00001614 struct gl_texture_object *texObj = NULL;
1615 struct gl_framebuffer *fb;
Brian Paul5fec84a2009-01-29 15:01:09 -07001616 GLboolean error = GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +00001617
1618 ASSERT_OUTSIDE_BEGIN_END(ctx);
1619
Brian Paul5fec84a2009-01-29 15:01:09 -07001620 switch (target) {
1621 case GL_READ_FRAMEBUFFER_EXT:
1622 error = !ctx->Extensions.EXT_framebuffer_blit;
1623 fb = ctx->ReadBuffer;
1624 break;
1625 case GL_DRAW_FRAMEBUFFER_EXT:
1626 error = !ctx->Extensions.EXT_framebuffer_blit;
1627 /* fall-through */
1628 case GL_FRAMEBUFFER_EXT:
1629 fb = ctx->DrawBuffer;
1630 break;
1631 default:
1632 error = GL_TRUE;
1633 }
1634
1635 if (error) {
Brian Paulea4fe662006-03-26 05:22:17 +00001636 _mesa_error(ctx, GL_INVALID_ENUM,
Brian Paul5fec84a2009-01-29 15:01:09 -07001637 "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
Brian Paulddc82ee2005-02-05 19:56:45 +00001638 return;
Brian Paulea4fe662006-03-26 05:22:17 +00001639 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001640
Brian Paulea4fe662006-03-26 05:22:17 +00001641 ASSERT(fb);
Brian Paul3deaa012005-02-07 05:08:24 +00001642
Brian Paulea4fe662006-03-26 05:22:17 +00001643 /* check framebuffer binding */
1644 if (fb->Name == 0) {
1645 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001646 "glFramebufferTexture%sEXT", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001647 return;
1648 }
1649
Brian Paulea4fe662006-03-26 05:22:17 +00001650
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001651 /* The textarget, level, and zoffset parameters are only validated if
1652 * texture is non-zero.
1653 */
1654 if (texture) {
1655 GLboolean err = GL_TRUE;
1656
1657 texObj = _mesa_lookup_texture(ctx, texture);
1658 if (texObj != NULL) {
Ian Romanickbb372f12007-05-16 15:34:22 -07001659 if (textarget == 0) {
Brian Paul7a2e32d2010-03-10 10:54:24 -07001660 /* XXX what's the purpose of this? */
Ian Romanickbb372f12007-05-16 15:34:22 -07001661 err = (texObj->Target != GL_TEXTURE_3D) &&
1662 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1663 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1664 }
1665 else {
1666 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1667 ? !IS_CUBE_FACE(textarget)
1668 : (texObj->Target != textarget);
1669 }
Brian Paulea4fe662006-03-26 05:22:17 +00001670 }
Brian Paul7a2e32d2010-03-10 10:54:24 -07001671 else {
1672 /* can't render to a non-existant texture */
1673 _mesa_error(ctx, GL_INVALID_OPERATION,
1674 "glFramebufferTexture%sEXT(non existant texture)",
1675 caller);
1676 return;
1677 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001678
1679 if (err) {
Brian Paulea4fe662006-03-26 05:22:17 +00001680 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001681 "glFramebufferTexture%sEXT(texture target mismatch)",
1682 caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001683 return;
1684 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001685
1686 if (texObj->Target == GL_TEXTURE_3D) {
Brian Paulea4fe662006-03-26 05:22:17 +00001687 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1688 if (zoffset < 0 || zoffset >= maxSize) {
1689 _mesa_error(ctx, GL_INVALID_VALUE,
Ian Romanickbb372f12007-05-16 15:34:22 -07001690 "glFramebufferTexture%sEXT(zoffset)", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001691 return;
1692 }
1693 }
Ian Romanickbb372f12007-05-16 15:34:22 -07001694 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1695 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1696 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1697 _mesa_error(ctx, GL_INVALID_VALUE,
1698 "glFramebufferTexture%sEXT(layer)", caller);
1699 return;
1700 }
1701 }
1702
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001703 if ((level < 0) ||
1704 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1705 _mesa_error(ctx, GL_INVALID_VALUE,
1706 "glFramebufferTexture%sEXT(level)", caller);
1707 return;
1708 }
Brian Paulea4fe662006-03-26 05:22:17 +00001709 }
1710
1711 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001712 if (att == NULL) {
1713 _mesa_error(ctx, GL_INVALID_ENUM,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001714 "glFramebufferTexture%sEXT(attachment)", caller);
Brian Paul3deaa012005-02-07 05:08:24 +00001715 return;
1716 }
1717
Brian Paul800e5532009-11-02 15:39:39 -07001718 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paul474f28e2005-10-08 14:41:17 +00001719
Brian Paulea4fe662006-03-26 05:22:17 +00001720 _glthread_LOCK_MUTEX(fb->Mutex);
1721 if (texObj) {
1722 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1723 level, zoffset);
Brian Paul2897cee2009-01-29 09:20:18 -07001724 /* Set the render-to-texture flag. We'll check this flag in
1725 * glTexImage() and friends to determine if we need to revalidate
1726 * any FBOs that might be rendering into this texture.
1727 * This flag never gets cleared since it's non-trivial to determine
1728 * when all FBOs might be done rendering to this texture. That's OK
1729 * though since it's uncommon to render to a texture then repeatedly
1730 * call glTexImage() to change images in the texture.
1731 */
1732 texObj->_RenderToTexture = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +00001733 }
1734 else {
Brian Paul519b23b2006-03-20 18:51:57 +00001735 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +00001736 }
Brian Paul72966362009-01-21 16:28:38 -07001737
1738 invalidate_framebuffer(fb);
1739
Brian Paulea4fe662006-03-26 05:22:17 +00001740 _glthread_UNLOCK_MUTEX(fb->Mutex);
1741}
1742
1743
1744
1745void GLAPIENTRY
1746_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1747 GLenum textarget, GLuint texture, GLint level)
1748{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001749 GET_CURRENT_CONTEXT(ctx);
1750
1751 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1752 _mesa_error(ctx, GL_INVALID_ENUM,
1753 "glFramebufferTexture1DEXT(textarget)");
1754 return;
1755 }
1756
1757 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1758 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001759}
1760
1761
Brian Paul1864c7d2005-02-08 03:46:37 +00001762void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001763_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1764 GLenum textarget, GLuint texture, GLint level)
1765{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001766 GET_CURRENT_CONTEXT(ctx);
1767
1768 if ((texture != 0) &&
1769 (textarget != GL_TEXTURE_2D) &&
1770 (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1771 (!IS_CUBE_FACE(textarget))) {
1772 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul5fec84a2009-01-29 15:01:09 -07001773 "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001774 return;
1775 }
1776
1777 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1778 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001779}
1780
1781
Brian Paul1864c7d2005-02-08 03:46:37 +00001782void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001783_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1784 GLenum textarget, GLuint texture,
1785 GLint level, GLint zoffset)
1786{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001787 GET_CURRENT_CONTEXT(ctx);
1788
1789 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1790 _mesa_error(ctx, GL_INVALID_ENUM,
1791 "glFramebufferTexture3DEXT(textarget)");
1792 return;
1793 }
1794
1795 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001796 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00001797}
1798
1799
Brian Paul1864c7d2005-02-08 03:46:37 +00001800void GLAPIENTRY
Ian Romanickbb372f12007-05-16 15:34:22 -07001801_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1802 GLuint texture, GLint level, GLint layer)
1803{
1804 GET_CURRENT_CONTEXT(ctx);
1805
1806 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1807 level, layer);
1808}
1809
1810
1811void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001812_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1813 GLenum renderbufferTarget,
1814 GLuint renderbuffer)
1815{
Brian Paul2c6f9112005-02-24 05:47:06 +00001816 struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001817 struct gl_framebuffer *fb;
Brian Paule4b23562005-05-04 20:11:35 +00001818 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001819 GET_CURRENT_CONTEXT(ctx);
1820
1821 ASSERT_OUTSIDE_BEGIN_END(ctx);
1822
Brian Paul0bffb112005-11-08 14:45:48 +00001823 switch (target) {
1824#if FEATURE_EXT_framebuffer_blit
1825 case GL_DRAW_FRAMEBUFFER_EXT:
1826 if (!ctx->Extensions.EXT_framebuffer_blit) {
1827 _mesa_error(ctx, GL_INVALID_ENUM,
1828 "glFramebufferRenderbufferEXT(target)");
1829 return;
1830 }
1831 fb = ctx->DrawBuffer;
1832 break;
1833 case GL_READ_FRAMEBUFFER_EXT:
1834 if (!ctx->Extensions.EXT_framebuffer_blit) {
1835 _mesa_error(ctx, GL_INVALID_ENUM,
1836 "glFramebufferRenderbufferEXT(target)");
1837 return;
1838 }
1839 fb = ctx->ReadBuffer;
1840 break;
1841#endif
1842 case GL_FRAMEBUFFER_EXT:
1843 fb = ctx->DrawBuffer;
1844 break;
1845 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001846 _mesa_error(ctx, GL_INVALID_ENUM,
1847 "glFramebufferRenderbufferEXT(target)");
1848 return;
1849 }
1850
Brian Paul3deaa012005-02-07 05:08:24 +00001851 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
Brian Paule4b23562005-05-04 20:11:35 +00001852 _mesa_error(ctx, GL_INVALID_ENUM,
1853 "glFramebufferRenderbufferEXT(renderbufferTarget)");
Brian Paul3deaa012005-02-07 05:08:24 +00001854 return;
1855 }
1856
Brian Paul0bffb112005-11-08 14:45:48 +00001857 if (fb->Name == 0) {
Brian Paulab8ef282005-09-07 23:21:59 +00001858 /* Can't attach new renderbuffers to a window system framebuffer */
Brian Paul3deaa012005-02-07 05:08:24 +00001859 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1860 return;
1861 }
1862
Brian Paul84716042005-11-16 04:05:54 +00001863 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001864 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001865 _mesa_error(ctx, GL_INVALID_ENUM,
Brian Paul9b50cea2009-10-23 11:34:14 -06001866 "glFramebufferRenderbufferEXT(invalid attachment %s)",
1867 _mesa_lookup_enum_by_nr(attachment));
Brian Paulddc82ee2005-02-05 19:56:45 +00001868 return;
1869 }
1870
Brian Paul1864c7d2005-02-08 03:46:37 +00001871 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00001872 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001873 if (!rb) {
Brian Paule4b23562005-05-04 20:11:35 +00001874 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul9b50cea2009-10-23 11:34:14 -06001875 "glFramebufferRenderbufferEXT(non-existant"
1876 " renderbuffer %u)", renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001877 return;
1878 }
Brian Paul1864c7d2005-02-08 03:46:37 +00001879 }
1880 else {
Brian Paule4b23562005-05-04 20:11:35 +00001881 /* remove renderbuffer attachment */
1882 rb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001883 }
Brian Paule4b23562005-05-04 20:11:35 +00001884
Brian Paula504f232010-05-27 13:05:23 -06001885 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
1886 rb && rb->Format != MESA_FORMAT_NONE) {
Brian Paul30590072009-01-21 11:06:11 -07001887 /* make sure the renderbuffer is a depth/stencil format */
Brian Paula504f232010-05-27 13:05:23 -06001888 const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
Brian Paul45e76d22009-10-08 20:27:27 -06001889 if (baseFormat != GL_DEPTH_STENCIL) {
Brian Paul30590072009-01-21 11:06:11 -07001890 _mesa_error(ctx, GL_INVALID_OPERATION,
1891 "glFramebufferRenderbufferEXT(renderbuffer"
1892 " is not DEPTH_STENCIL format)");
1893 return;
1894 }
1895 }
1896
1897
Brian Paul800e5532009-11-02 15:39:39 -07001898 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paul474f28e2005-10-08 14:41:17 +00001899
Brian Paule4b23562005-05-04 20:11:35 +00001900 assert(ctx->Driver.FramebufferRenderbuffer);
Brian Paul84716042005-11-16 04:05:54 +00001901 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
Brian Paul2e019182006-03-07 01:43:52 +00001902
1903 /* Some subsequent GL commands may depend on the framebuffer's visual
1904 * after the binding is updated. Update visual info now.
1905 */
1906 _mesa_update_framebuffer_visual(fb);
Brian Paulddc82ee2005-02-05 19:56:45 +00001907}
1908
1909
Brian Paul1864c7d2005-02-08 03:46:37 +00001910void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001911_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1912 GLenum pname, GLint *params)
1913{
Brian Paul2c6f9112005-02-24 05:47:06 +00001914 const struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001915 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001916 GET_CURRENT_CONTEXT(ctx);
1917
1918 ASSERT_OUTSIDE_BEGIN_END(ctx);
1919
Brian Paul0bffb112005-11-08 14:45:48 +00001920 switch (target) {
1921#if FEATURE_EXT_framebuffer_blit
1922 case GL_DRAW_FRAMEBUFFER_EXT:
1923 if (!ctx->Extensions.EXT_framebuffer_blit) {
1924 _mesa_error(ctx, GL_INVALID_ENUM,
1925 "glGetFramebufferAttachmentParameterivEXT(target)");
1926 return;
1927 }
1928 buffer = ctx->DrawBuffer;
1929 break;
1930 case GL_READ_FRAMEBUFFER_EXT:
1931 if (!ctx->Extensions.EXT_framebuffer_blit) {
1932 _mesa_error(ctx, GL_INVALID_ENUM,
1933 "glGetFramebufferAttachmentParameterivEXT(target)");
1934 return;
1935 }
1936 buffer = ctx->ReadBuffer;
1937 break;
1938#endif
1939 case GL_FRAMEBUFFER_EXT:
1940 buffer = ctx->DrawBuffer;
1941 break;
1942 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001943 _mesa_error(ctx, GL_INVALID_ENUM,
1944 "glGetFramebufferAttachmentParameterivEXT(target)");
1945 return;
1946 }
1947
Brian Paul61ec2052010-06-22 08:37:44 -06001948 if (buffer->Name == 0) {
1949 /* the default / window-system FBO */
1950 att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
1951 }
1952 else {
1953 /* user-created framebuffer FBO */
1954 att = _mesa_get_attachment(ctx, buffer, attachment);
1955 }
1956
Brian Paul3deaa012005-02-07 05:08:24 +00001957 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001958 _mesa_error(ctx, GL_INVALID_ENUM,
1959 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1960 return;
1961 }
1962
Brian Paul30590072009-01-21 11:06:11 -07001963 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
1964 /* the depth and stencil attachments must point to the same buffer */
1965 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
1966 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
1967 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
1968 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
1969 _mesa_error(ctx, GL_INVALID_OPERATION,
1970 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
1971 " attachments differ)");
1972 return;
1973 }
1974 }
1975
Brian Paul800e5532009-11-02 15:39:39 -07001976 /* No need to flush here */
Brian Paul474f28e2005-10-08 14:41:17 +00001977
Brian Paulddc82ee2005-02-05 19:56:45 +00001978 switch (pname) {
1979 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001980 *params = att->Type;
1981 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001982 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001983 if (att->Type == GL_RENDERBUFFER_EXT) {
1984 *params = att->Renderbuffer->Name;
1985 }
1986 else if (att->Type == GL_TEXTURE) {
1987 *params = att->Texture->Name;
1988 }
1989 else {
1990 _mesa_error(ctx, GL_INVALID_ENUM,
1991 "glGetFramebufferAttachmentParameterivEXT(pname)");
1992 }
1993 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001994 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001995 if (att->Type == GL_TEXTURE) {
1996 *params = att->TextureLevel;
1997 }
1998 else {
1999 _mesa_error(ctx, GL_INVALID_ENUM,
2000 "glGetFramebufferAttachmentParameterivEXT(pname)");
2001 }
2002 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002003 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002004 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06002005 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
2006 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
2007 }
2008 else {
2009 *params = 0;
2010 }
Brian Paul3deaa012005-02-07 05:08:24 +00002011 }
2012 else {
2013 _mesa_error(ctx, GL_INVALID_ENUM,
2014 "glGetFramebufferAttachmentParameterivEXT(pname)");
2015 }
2016 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002017 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002018 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06002019 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2020 *params = att->Zoffset;
2021 }
2022 else {
2023 *params = 0;
2024 }
Brian Paul3deaa012005-02-07 05:08:24 +00002025 }
2026 else {
2027 _mesa_error(ctx, GL_INVALID_ENUM,
2028 "glGetFramebufferAttachmentParameterivEXT(pname)");
2029 }
2030 return;
Brian Paul1bc59bf2009-01-22 15:07:34 -07002031 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2032 if (!ctx->Extensions.ARB_framebuffer_object) {
2033 _mesa_error(ctx, GL_INVALID_ENUM,
2034 "glGetFramebufferAttachmentParameterivEXT(pname)");
2035 }
2036 else {
Brian Paul45e76d22009-10-08 20:27:27 -06002037 *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
Brian Paul1bc59bf2009-01-22 15:07:34 -07002038 }
2039 return;
2040 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2041 if (!ctx->Extensions.ARB_framebuffer_object) {
2042 _mesa_error(ctx, GL_INVALID_ENUM,
2043 "glGetFramebufferAttachmentParameterivEXT(pname)");
2044 return;
2045 }
2046 else {
Brian Paul45e76d22009-10-08 20:27:27 -06002047 gl_format format = att->Renderbuffer->Format;
2048 if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
2049 /* special cases */
2050 *params = GL_INDEX;
2051 }
2052 else {
2053 *params = _mesa_get_format_datatype(format);
2054 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002055 }
2056 return;
2057 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002058 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002059 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002060 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002061 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002062 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2063 if (!ctx->Extensions.ARB_framebuffer_object) {
2064 _mesa_error(ctx, GL_INVALID_ENUM,
2065 "glGetFramebufferAttachmentParameterivEXT(pname)");
2066 }
Brian Paul45e76d22009-10-08 20:27:27 -06002067 else if (att->Texture) {
2068 const struct gl_texture_image *texImage =
2069 _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
2070 att->TextureLevel);
2071 if (texImage) {
2072 *params = get_component_bits(pname, texImage->_BaseFormat,
2073 texImage->TexFormat);
2074 }
2075 else {
2076 *params = 0;
2077 }
2078 }
2079 else if (att->Renderbuffer) {
2080 *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
2081 att->Renderbuffer->Format);
2082 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002083 else {
Brian Paul45e76d22009-10-08 20:27:27 -06002084 *params = 0;
Brian Paul1bc59bf2009-01-22 15:07:34 -07002085 }
2086 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002087 default:
2088 _mesa_error(ctx, GL_INVALID_ENUM,
2089 "glGetFramebufferAttachmentParameterivEXT(pname)");
2090 return;
2091 }
Brian Paulddc82ee2005-02-05 19:56:45 +00002092}
2093
2094
Brian Paul1864c7d2005-02-08 03:46:37 +00002095void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002096_mesa_GenerateMipmapEXT(GLenum target)
2097{
Brian Paul463642c2005-02-08 02:06:00 +00002098 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00002099 GET_CURRENT_CONTEXT(ctx);
2100
2101 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00002102 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00002103
2104 switch (target) {
2105 case GL_TEXTURE_1D:
2106 case GL_TEXTURE_2D:
Brian Paulddc82ee2005-02-05 19:56:45 +00002107 case GL_TEXTURE_3D:
Brian Paul463642c2005-02-08 02:06:00 +00002108 case GL_TEXTURE_CUBE_MAP:
Brian Paul1b939532005-05-31 23:55:21 +00002109 /* OK, legal value */
Brian Paulddc82ee2005-02-05 19:56:45 +00002110 break;
2111 default:
2112 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
2113 return;
2114 }
2115
Brian Paula7193952009-11-16 08:21:28 -07002116 texObj = _mesa_get_current_tex_object(ctx, target);
Brian Paul463642c2005-02-08 02:06:00 +00002117
Brian Paul652828e2009-11-16 08:25:17 -07002118 if (texObj->BaseLevel >= texObj->MaxLevel) {
2119 /* nothing to do */
2120 return;
2121 }
2122
Keith Whitwell5ac93f82006-11-01 14:21:57 +00002123 _mesa_lock_texture(ctx, texObj);
Eric Anholtf849d362008-12-06 21:14:56 -08002124 if (target == GL_TEXTURE_CUBE_MAP) {
Brian Paulef6ee072009-09-15 18:09:03 -06002125 GLuint face;
Eric Anholtf849d362008-12-06 21:14:56 -08002126 for (face = 0; face < 6; face++)
2127 ctx->Driver.GenerateMipmap(ctx,
2128 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2129 texObj);
Brian Paulef6ee072009-09-15 18:09:03 -06002130 }
2131 else {
Eric Anholtf849d362008-12-06 21:14:56 -08002132 ctx->Driver.GenerateMipmap(ctx, target, texObj);
2133 }
Keith Whitwell5ac93f82006-11-01 14:21:57 +00002134 _mesa_unlock_texture(ctx, texObj);
Brian Paulddc82ee2005-02-05 19:56:45 +00002135}
Brian Paul0bffb112005-11-08 14:45:48 +00002136
2137
2138#if FEATURE_EXT_framebuffer_blit
Brian Paul21f8d312009-10-27 16:59:23 -06002139
2140static const struct gl_renderbuffer_attachment *
2141find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb)
2142{
2143 GLuint i;
2144 for (i = 0; i < Elements(fb->Attachment); i++) {
2145 if (fb->Attachment[i].Renderbuffer == rb)
2146 return &fb->Attachment[i];
2147 }
2148 return NULL;
2149}
2150
2151
2152
Brian Paul722d9762009-01-20 16:58:49 -07002153/**
2154 * Blit rectangular region, optionally from one framebuffer to another.
2155 *
2156 * Note, if the src buffer is multisampled and the dest is not, this is
2157 * when the samples must be resolved to a single color.
2158 */
Brian Paul0bffb112005-11-08 14:45:48 +00002159void GLAPIENTRY
2160_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
2161 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
2162 GLbitfield mask, GLenum filter)
2163{
Brian Paul722d9762009-01-20 16:58:49 -07002164 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
2165 GL_DEPTH_BUFFER_BIT |
2166 GL_STENCIL_BUFFER_BIT);
2167 const struct gl_framebuffer *readFb, *drawFb;
2168 const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
Brian Paul0bffb112005-11-08 14:45:48 +00002169 GET_CURRENT_CONTEXT(ctx);
2170
2171 ASSERT_OUTSIDE_BEGIN_END(ctx);
2172 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2173
Brian Paul99745402006-03-01 02:02:43 +00002174 if (ctx->NewState) {
2175 _mesa_update_state(ctx);
2176 }
2177
Brian Paul722d9762009-01-20 16:58:49 -07002178 readFb = ctx->ReadBuffer;
2179 drawFb = ctx->DrawBuffer;
2180
2181 if (!readFb || !drawFb) {
2182 /* This will normally never happen but someday we may want to
2183 * support MakeCurrent() with no drawables.
2184 */
2185 return;
Brian Paul99745402006-03-01 02:02:43 +00002186 }
2187
Brian Paul0bffb112005-11-08 14:45:48 +00002188 /* check for complete framebuffers */
Brian Paul722d9762009-01-20 16:58:49 -07002189 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
2190 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
Brian Paul0bffb112005-11-08 14:45:48 +00002191 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
2192 "glBlitFramebufferEXT(incomplete draw/read buffers)");
2193 return;
2194 }
2195
Brian Paul99745402006-03-01 02:02:43 +00002196 if (filter != GL_NEAREST && filter != GL_LINEAR) {
2197 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
2198 return;
2199 }
2200
Brian Paul722d9762009-01-20 16:58:49 -07002201 if (mask & ~legalMaskBits) {
Brian Paul99745402006-03-01 02:02:43 +00002202 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
2203 return;
2204 }
2205
Brian Paul0bffb112005-11-08 14:45:48 +00002206 /* depth/stencil must be blitted with nearest filtering */
2207 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
2208 && filter != GL_NEAREST) {
2209 _mesa_error(ctx, GL_INVALID_OPERATION,
2210 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
2211 return;
2212 }
2213
Brian Paul722d9762009-01-20 16:58:49 -07002214 /* get color read/draw renderbuffers */
2215 if (mask & GL_COLOR_BUFFER_BIT) {
2216 colorReadRb = readFb->_ColorReadBuffer;
2217 colorDrawRb = drawFb->_ColorDrawBuffers[0];
2218 }
2219 else {
2220 colorReadRb = colorDrawRb = NULL;
2221 }
2222
Brian Paul99745402006-03-01 02:02:43 +00002223 if (mask & GL_STENCIL_BUFFER_BIT) {
Brian Paul722d9762009-01-20 16:58:49 -07002224 struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
2225 struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
Brian Pauldcebe222009-08-05 13:44:59 -06002226 if (!readRb ||
2227 !drawRb ||
Brian Paul45e76d22009-10-08 20:27:27 -06002228 _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
2229 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
Brian Paul99745402006-03-01 02:02:43 +00002230 _mesa_error(ctx, GL_INVALID_OPERATION,
2231 "glBlitFramebufferEXT(stencil buffer size mismatch");
2232 return;
2233 }
2234 }
2235
2236 if (mask & GL_DEPTH_BUFFER_BIT) {
Brian Paul722d9762009-01-20 16:58:49 -07002237 struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
2238 struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
Brian Pauldcebe222009-08-05 13:44:59 -06002239 if (!readRb ||
2240 !drawRb ||
Brian Paul45e76d22009-10-08 20:27:27 -06002241 _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
2242 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
Brian Paul99745402006-03-01 02:02:43 +00002243 _mesa_error(ctx, GL_INVALID_OPERATION,
2244 "glBlitFramebufferEXT(depth buffer size mismatch");
2245 return;
2246 }
Brian Paul0bffb112005-11-08 14:45:48 +00002247 }
2248
Brian Paul722d9762009-01-20 16:58:49 -07002249 if (readFb->Visual.samples > 0 &&
2250 drawFb->Visual.samples > 0 &&
2251 readFb->Visual.samples != drawFb->Visual.samples) {
2252 _mesa_error(ctx, GL_INVALID_OPERATION,
2253 "glBlitFramebufferEXT(mismatched samples");
2254 return;
2255 }
2256
2257 /* extra checks for multisample copies... */
2258 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
2259 /* src and dest region sizes must be the same */
2260 if (srcX1 - srcX0 != dstX1 - dstX0 ||
2261 srcY1 - srcY0 != dstY1 - dstY0) {
2262 _mesa_error(ctx, GL_INVALID_OPERATION,
2263 "glBlitFramebufferEXT(bad src/dst multisample region sizes");
2264 return;
2265 }
2266
2267 /* color formats must match */
2268 if (colorReadRb &&
2269 colorDrawRb &&
Brian Paul45e76d22009-10-08 20:27:27 -06002270 colorReadRb->Format != colorDrawRb->Format) {
Brian Paul722d9762009-01-20 16:58:49 -07002271 _mesa_error(ctx, GL_INVALID_OPERATION,
2272 "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
2273 return;
2274 }
2275 }
2276
Brian Paul0bffb112005-11-08 14:45:48 +00002277 if (!ctx->Extensions.EXT_framebuffer_blit) {
2278 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
2279 return;
2280 }
2281
Brian Paul21f8d312009-10-27 16:59:23 -06002282 /* Debug code */
2283 if (DEBUG_BLIT) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002284 printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
2285 " 0x%x, 0x%x)\n",
2286 srcX0, srcY0, srcX1, srcY1,
2287 dstX0, dstY0, dstX1, dstY1,
2288 mask, filter);
Brian Paul21f8d312009-10-27 16:59:23 -06002289 if (colorReadRb) {
2290 const struct gl_renderbuffer_attachment *att;
2291
2292 att = find_attachment(readFb, colorReadRb);
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002293 printf(" Src FBO %u RB %u (%dx%d) ",
2294 readFb->Name, colorReadRb->Name,
2295 colorReadRb->Width, colorReadRb->Height);
Brian Paul21f8d312009-10-27 16:59:23 -06002296 if (att && att->Texture) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002297 printf("Tex %u tgt 0x%x level %u face %u",
2298 att->Texture->Name,
2299 att->Texture->Target,
2300 att->TextureLevel,
2301 att->CubeMapFace);
Brian Paul21f8d312009-10-27 16:59:23 -06002302 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002303 printf("\n");
Brian Paul21f8d312009-10-27 16:59:23 -06002304
2305 att = find_attachment(drawFb, colorDrawRb);
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002306 printf(" Dst FBO %u RB %u (%dx%d) ",
2307 drawFb->Name, colorDrawRb->Name,
2308 colorDrawRb->Width, colorDrawRb->Height);
Brian Paul21f8d312009-10-27 16:59:23 -06002309 if (att && att->Texture) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002310 printf("Tex %u tgt 0x%x level %u face %u",
2311 att->Texture->Name,
2312 att->Texture->Target,
2313 att->TextureLevel,
2314 att->CubeMapFace);
Brian Paul21f8d312009-10-27 16:59:23 -06002315 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002316 printf("\n");
Brian Paul21f8d312009-10-27 16:59:23 -06002317 }
2318 }
2319
Brian Paul0bffb112005-11-08 14:45:48 +00002320 ASSERT(ctx->Driver.BlitFramebuffer);
2321 ctx->Driver.BlitFramebuffer(ctx,
2322 srcX0, srcY0, srcX1, srcY1,
2323 dstX0, dstY0, dstX1, dstY1,
2324 mask, filter);
2325}
2326#endif /* FEATURE_EXT_framebuffer_blit */
Zack Rusinda7bd6a2010-06-28 17:31:21 -04002327
2328#if FEATURE_ARB_geometry_shader4
2329void GLAPIENTRY
2330_mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
2331 GLuint texture, GLint level)
2332{
2333 GET_CURRENT_CONTEXT(ctx);
2334 _mesa_error(ctx, GL_INVALID_OPERATION,
2335 "glFramebufferTextureARB "
2336 "not implemented!");
2337}
2338
2339void GLAPIENTRY
2340_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
2341 GLuint texture, GLint level, GLenum face)
2342{
2343 GET_CURRENT_CONTEXT(ctx);
2344 _mesa_error(ctx, GL_INVALID_OPERATION,
2345 "glFramebufferTextureFaceARB "
2346 "not implemented!");
2347}
2348#endif /* FEATURE_ARB_geometry_shader4 */