blob: f80dd8599362ade9cc3dc46ec40ee71b8b5e93f0 [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
74
Brian Paul3deaa012005-02-07 05:08:24 +000075#define IS_CUBE_FACE(TARGET) \
76 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
77 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
Brian Paulddc82ee2005-02-05 19:56:45 +000078
79
Brian Paul3dc65912008-07-03 15:40:38 -060080static void
81delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
82{
83 /* no op */
84}
85
86static void
87delete_dummy_framebuffer(struct gl_framebuffer *fb)
88{
89 /* no op */
90}
91
92
93void
94_mesa_init_fbobjects(GLcontext *ctx)
95{
Vladimir Vukicevic07317012010-09-01 08:54:21 -060096 _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
97 _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
Brian Paul3dc65912008-07-03 15:40:38 -060098 DummyFramebuffer.Delete = delete_dummy_framebuffer;
99 DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
100}
101
Kristian Høgsberg9456e222010-06-04 14:28:59 -0400102struct gl_framebuffer *
103_mesa_get_incomplete_framebuffer(void)
104{
105 return &DummyFramebuffer;
106}
Brian Paul3dc65912008-07-03 15:40:38 -0600107
Brian Paulddc82ee2005-02-05 19:56:45 +0000108/**
Brian Paul2c6f9112005-02-24 05:47:06 +0000109 * Helper routine for getting a gl_renderbuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +0000110 */
Brian Paulea4fe662006-03-26 05:22:17 +0000111struct gl_renderbuffer *
112_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +0000113{
Brian Paul2c6f9112005-02-24 05:47:06 +0000114 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000115
Brian Paul1864c7d2005-02-08 03:46:37 +0000116 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +0000117 return NULL;
118
Brian Paul2c6f9112005-02-24 05:47:06 +0000119 rb = (struct gl_renderbuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000120 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
121 return rb;
122}
123
124
125/**
Brian Paul2c6f9112005-02-24 05:47:06 +0000126 * Helper routine for getting a gl_framebuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +0000127 */
Brian Paulea4fe662006-03-26 05:22:17 +0000128struct gl_framebuffer *
129_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +0000130{
Brian Paul2c6f9112005-02-24 05:47:06 +0000131 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000132
Brian Paul1864c7d2005-02-08 03:46:37 +0000133 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +0000134 return NULL;
135
Brian Paul2c6f9112005-02-24 05:47:06 +0000136 fb = (struct gl_framebuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000137 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
Brian Paul463642c2005-02-08 02:06:00 +0000138 return fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000139}
140
141
142/**
Brian Paul72966362009-01-21 16:28:38 -0700143 * Mark the given framebuffer as invalid. This will force the
144 * test for framebuffer completeness to be done before the framebuffer
145 * is used.
146 */
147static void
148invalidate_framebuffer(struct gl_framebuffer *fb)
149{
150 fb->_Status = 0; /* "indeterminate" */
151}
152
153
154/**
Brian Pauld9468c92005-02-10 16:08:07 +0000155 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
Brian Paul2c6f9112005-02-24 05:47:06 +0000156 * gl_renderbuffer_attachment object.
Brian Paul61ec2052010-06-22 08:37:44 -0600157 * This function is only used for user-created FB objects, not the
158 * default / window-system FB object.
Brian Paul30590072009-01-21 11:06:11 -0700159 * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
160 * the depth buffer attachment point.
Brian Pauld9468c92005-02-10 16:08:07 +0000161 */
Brian Paul84716042005-11-16 04:05:54 +0000162struct gl_renderbuffer_attachment *
163_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
164 GLenum attachment)
Brian Paul3deaa012005-02-07 05:08:24 +0000165{
166 GLuint i;
167
Brian Paul61ec2052010-06-22 08:37:44 -0600168 assert(fb->Name > 0);
169
Brian Paul3deaa012005-02-07 05:08:24 +0000170 switch (attachment) {
171 case GL_COLOR_ATTACHMENT0_EXT:
172 case GL_COLOR_ATTACHMENT1_EXT:
173 case GL_COLOR_ATTACHMENT2_EXT:
174 case GL_COLOR_ATTACHMENT3_EXT:
175 case GL_COLOR_ATTACHMENT4_EXT:
176 case GL_COLOR_ATTACHMENT5_EXT:
177 case GL_COLOR_ATTACHMENT6_EXT:
178 case GL_COLOR_ATTACHMENT7_EXT:
179 case GL_COLOR_ATTACHMENT8_EXT:
180 case GL_COLOR_ATTACHMENT9_EXT:
181 case GL_COLOR_ATTACHMENT10_EXT:
182 case GL_COLOR_ATTACHMENT11_EXT:
183 case GL_COLOR_ATTACHMENT12_EXT:
184 case GL_COLOR_ATTACHMENT13_EXT:
185 case GL_COLOR_ATTACHMENT14_EXT:
186 case GL_COLOR_ATTACHMENT15_EXT:
187 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
188 if (i >= ctx->Const.MaxColorAttachments) {
189 return NULL;
190 }
Brian Paule4b23562005-05-04 20:11:35 +0000191 return &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paul30590072009-01-21 11:06:11 -0700192 case GL_DEPTH_STENCIL_ATTACHMENT:
193 /* fall-through */
Brian Paul8829e062010-03-20 11:50:55 -0600194 case GL_DEPTH_BUFFER:
195 /* fall-through / new in GL 3.0 */
Brian Paul3deaa012005-02-07 05:08:24 +0000196 case GL_DEPTH_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000197 return &fb->Attachment[BUFFER_DEPTH];
Brian Paul8829e062010-03-20 11:50:55 -0600198 case GL_STENCIL_BUFFER:
199 /* fall-through / new in GL 3.0 */
Brian Paul3deaa012005-02-07 05:08:24 +0000200 case GL_STENCIL_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000201 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul61ec2052010-06-22 08:37:44 -0600202 default:
203 return NULL;
204 }
205}
206
207
208/**
209 * As above, but only used for getting attachments of the default /
210 * window-system framebuffer (not user-created framebuffer objects).
211 */
212static struct gl_renderbuffer_attachment *
213_mesa_get_fb0_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
214 GLenum attachment)
215{
216 assert(fb->Name == 0);
217
218 switch (attachment) {
Kristian Høgsberg80dfec32010-06-15 13:07:01 -0400219 case GL_FRONT_LEFT:
220 return &fb->Attachment[BUFFER_FRONT_LEFT];
221 case GL_FRONT_RIGHT:
222 return &fb->Attachment[BUFFER_FRONT_RIGHT];
223 case GL_BACK_LEFT:
224 return &fb->Attachment[BUFFER_BACK_LEFT];
225 case GL_BACK_RIGHT:
226 return &fb->Attachment[BUFFER_BACK_RIGHT];
Brian Paul61ec2052010-06-22 08:37:44 -0600227 case GL_AUX0:
228 if (fb->Visual.numAuxBuffers == 1) {
229 return &fb->Attachment[BUFFER_AUX0];
230 }
231 return NULL;
232 case GL_DEPTH_BUFFER:
233 /* fall-through / new in GL 3.0 */
234 case GL_DEPTH_ATTACHMENT_EXT:
235 return &fb->Attachment[BUFFER_DEPTH];
236 case GL_STENCIL_BUFFER:
237 /* fall-through / new in GL 3.0 */
238 case GL_STENCIL_ATTACHMENT_EXT:
239 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul3deaa012005-02-07 05:08:24 +0000240 default:
241 return NULL;
242 }
243}
244
245
Brian Paul61ec2052010-06-22 08:37:44 -0600246
Brian Pauld9468c92005-02-10 16:08:07 +0000247/**
248 * Remove any texture or renderbuffer attached to the given attachment
249 * point. Update reference counts, etc.
250 */
Brian Paule4b23562005-05-04 20:11:35 +0000251void
252_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
Brian Paul3deaa012005-02-07 05:08:24 +0000253{
254 if (att->Type == GL_TEXTURE) {
255 ASSERT(att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100256 if (ctx->Driver.FinishRenderTexture) {
Brian Paul0e31e022005-12-01 00:25:00 +0000257 /* tell driver that we're done rendering to this texture. */
Brian9e01b912007-08-13 11:29:46 +0100258 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000259 }
Brian9e01b912007-08-13 11:29:46 +0100260 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
261 ASSERT(!att->Texture);
Brian Paul3deaa012005-02-07 05:08:24 +0000262 }
Brian Paul0e31e022005-12-01 00:25:00 +0000263 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul3deaa012005-02-07 05:08:24 +0000264 ASSERT(!att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100265 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
266 ASSERT(!att->Renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000267 }
268 att->Type = GL_NONE;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000269 att->Complete = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +0000270}
271
272
Brian Pauld9468c92005-02-10 16:08:07 +0000273/**
274 * Bind a texture object to an attachment point.
275 * The previous binding, if any, will be removed first.
276 */
Brian Paule4b23562005-05-04 20:11:35 +0000277void
278_mesa_set_texture_attachment(GLcontext *ctx,
Brian Paul519b23b2006-03-20 18:51:57 +0000279 struct gl_framebuffer *fb,
Brian Paule4b23562005-05-04 20:11:35 +0000280 struct gl_renderbuffer_attachment *att,
281 struct gl_texture_object *texObj,
282 GLenum texTarget, GLuint level, GLuint zoffset)
Brian Paul3deaa012005-02-07 05:08:24 +0000283{
Brian Paul0e31e022005-12-01 00:25:00 +0000284 if (att->Texture == texObj) {
285 /* re-attaching same texture */
286 ASSERT(att->Type == GL_TEXTURE);
Eric Anholt6b684822009-11-04 14:31:30 -0800287 if (ctx->Driver.FinishRenderTexture)
288 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000289 }
290 else {
291 /* new attachment */
Eric Anholt6b684822009-11-04 14:31:30 -0800292 if (ctx->Driver.FinishRenderTexture && att->Texture)
293 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000294 _mesa_remove_attachment(ctx, att);
295 att->Type = GL_TEXTURE;
Brian9e01b912007-08-13 11:29:46 +0100296 assert(!att->Texture);
297 _mesa_reference_texobj(&att->Texture, texObj);
Brian Paul0e31e022005-12-01 00:25:00 +0000298 }
299
300 /* always update these fields */
Brian Paul3deaa012005-02-07 05:08:24 +0000301 att->TextureLevel = level;
Brian Paul26f1ad62009-10-23 18:15:55 -0600302 att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
Brian Paul3deaa012005-02-07 05:08:24 +0000303 att->Zoffset = zoffset;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000304 att->Complete = GL_FALSE;
Brian Paul519b23b2006-03-20 18:51:57 +0000305
306 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +0000307 ctx->Driver.RenderTexture(ctx, fb, att);
Brian Paul519b23b2006-03-20 18:51:57 +0000308 }
Brian Paul72966362009-01-21 16:28:38 -0700309
310 invalidate_framebuffer(fb);
Brian Paul3deaa012005-02-07 05:08:24 +0000311}
312
313
Brian Pauld9468c92005-02-10 16:08:07 +0000314/**
315 * Bind a renderbuffer to an attachment point.
316 * The previous binding, if any, will be removed first.
317 */
Brian Paule4b23562005-05-04 20:11:35 +0000318void
319_mesa_set_renderbuffer_attachment(GLcontext *ctx,
320 struct gl_renderbuffer_attachment *att,
321 struct gl_renderbuffer *rb)
Brian Paul3deaa012005-02-07 05:08:24 +0000322{
Brian Paulea4fe662006-03-26 05:22:17 +0000323 /* XXX check if re-doing same attachment, exit early */
Brian Paule4b23562005-05-04 20:11:35 +0000324 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000325 att->Type = GL_RENDERBUFFER_EXT;
Brian Paul2c6f9112005-02-24 05:47:06 +0000326 att->Texture = NULL; /* just to be safe */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000327 att->Complete = GL_FALSE;
Briandccd9c42007-04-02 09:56:28 -0600328 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
Brian Paul3deaa012005-02-07 05:08:24 +0000329}
330
Brian Paulddc82ee2005-02-05 19:56:45 +0000331
Brian Paulf0bbbf62005-02-09 03:50:30 +0000332/**
Brian Paule4b23562005-05-04 20:11:35 +0000333 * Fallback for ctx->Driver.FramebufferRenderbuffer()
Brian Paul84716042005-11-16 04:05:54 +0000334 * Attach a renderbuffer object to a framebuffer object.
Brian Paule4b23562005-05-04 20:11:35 +0000335 */
336void
Brian Paul84716042005-11-16 04:05:54 +0000337_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
338 GLenum attachment, struct gl_renderbuffer *rb)
Brian Paule4b23562005-05-04 20:11:35 +0000339{
Brian Paul84716042005-11-16 04:05:54 +0000340 struct gl_renderbuffer_attachment *att;
341
Brian Paulea4fe662006-03-26 05:22:17 +0000342 _glthread_LOCK_MUTEX(fb->Mutex);
Brian Paulea4fe662006-03-26 05:22:17 +0000343
Brian Paul84716042005-11-16 04:05:54 +0000344 att = _mesa_get_attachment(ctx, fb, attachment);
345 ASSERT(att);
Brian Paule4b23562005-05-04 20:11:35 +0000346 if (rb) {
347 _mesa_set_renderbuffer_attachment(ctx, att, rb);
Brian Paul30590072009-01-21 11:06:11 -0700348 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
349 /* do stencil attachment here (depth already done above) */
350 att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
351 assert(att);
352 _mesa_set_renderbuffer_attachment(ctx, att, rb);
353 }
Brian Paule4b23562005-05-04 20:11:35 +0000354 }
355 else {
356 _mesa_remove_attachment(ctx, att);
357 }
Brian Paulea4fe662006-03-26 05:22:17 +0000358
Brian Paul72966362009-01-21 16:28:38 -0700359 invalidate_framebuffer(fb);
360
Brian Paulea4fe662006-03-26 05:22:17 +0000361 _glthread_UNLOCK_MUTEX(fb->Mutex);
Brian Paule4b23562005-05-04 20:11:35 +0000362}
363
364
365/**
Brian Paul9f731c82009-02-17 16:47:54 -0700366 * For debug only.
367 */
368static void
369att_incomplete(const char *msg)
370{
Brian Paulc26c2002009-09-15 17:20:32 -0600371#if DEBUG_FBO
372 _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
Brian Paul9f731c82009-02-17 16:47:54 -0700373#else
374 (void) msg;
375#endif
376}
377
378
379/**
Brian Paulc26c2002009-09-15 17:20:32 -0600380 * For debug only.
381 */
382static void
383fbo_incomplete(const char *msg, int index)
384{
385#if DEBUG_FBO
386 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
387#else
388 (void) msg;
389 (void) index;
390#endif
391}
392
393
394
395
396/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000397 * Test if an attachment point is complete and update its Complete field.
398 * \param format if GL_COLOR, this is a color attachment point,
399 * if GL_DEPTH, this is a depth component attachment point,
400 * if GL_STENCIL, this is a stencil component attachment point.
401 */
402static void
403test_attachment_completeness(const GLcontext *ctx, GLenum format,
Brian Paul2c6f9112005-02-24 05:47:06 +0000404 struct gl_renderbuffer_attachment *att)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000405{
406 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
407
408 /* assume complete */
409 att->Complete = GL_TRUE;
410
Brian Paulf0bbbf62005-02-09 03:50:30 +0000411 /* Look for reasons why the attachment might be incomplete */
412 if (att->Type == GL_TEXTURE) {
Brian Paule4b23562005-05-04 20:11:35 +0000413 const struct gl_texture_object *texObj = att->Texture;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000414 struct gl_texture_image *texImage;
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600415 GLenum baseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000416
Brian Paule4b23562005-05-04 20:11:35 +0000417 if (!texObj) {
Brian Paul9f731c82009-02-17 16:47:54 -0700418 att_incomplete("no texobj");
Brian Paule4b23562005-05-04 20:11:35 +0000419 att->Complete = GL_FALSE;
420 return;
421 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000422
423 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
424 if (!texImage) {
Brian Paul9f731c82009-02-17 16:47:54 -0700425 att_incomplete("no teximage");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000426 att->Complete = GL_FALSE;
427 return;
428 }
429 if (texImage->Width < 1 || texImage->Height < 1) {
Brian Paul9f731c82009-02-17 16:47:54 -0700430 att_incomplete("teximage width/height=0");
Kristian Høgsberg298be2b2010-02-19 12:32:24 -0500431 printf("texobj = %u\n", texObj->Name);
432 printf("level = %d\n", att->TextureLevel);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000433 att->Complete = GL_FALSE;
434 return;
435 }
436 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
Brian Paul9f731c82009-02-17 16:47:54 -0700437 att_incomplete("bad z offset");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000438 att->Complete = GL_FALSE;
439 return;
440 }
441
Brian Paul1f7c9142009-09-30 20:28:45 -0600442 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600443
Brian Paulf0bbbf62005-02-09 03:50:30 +0000444 if (format == GL_COLOR) {
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600445 if (baseFormat != GL_RGB &&
Eric Anholt262cdbd2010-05-25 08:00:51 -0700446 baseFormat != GL_RGBA &&
447 (!ctx->Extensions.ARB_framebuffer_object ||
448 baseFormat != GL_ALPHA)) {
Brian Paul9f731c82009-02-17 16:47:54 -0700449 att_incomplete("bad format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000450 att->Complete = GL_FALSE;
451 return;
452 }
Brian Paul1f7c9142009-09-30 20:28:45 -0600453 if (_mesa_is_format_compressed(texImage->TexFormat)) {
Eric Anholt957f3c82009-05-15 16:24:59 -0700454 att_incomplete("compressed internalformat");
455 att->Complete = GL_FALSE;
456 return;
457 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000458 }
459 else if (format == GL_DEPTH) {
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600460 if (baseFormat == GL_DEPTH_COMPONENT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000461 /* OK */
462 }
463 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600464 ctx->Extensions.ARB_depth_texture &&
Brian Paul5cf5d4b2009-09-27 20:51:18 -0600465 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000466 /* OK */
467 }
468 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000469 att->Complete = GL_FALSE;
Brian Paul9f731c82009-02-17 16:47:54 -0700470 att_incomplete("bad depth format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000471 return;
472 }
473 }
474 else {
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600475 ASSERT(format == GL_STENCIL);
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600476 if (ctx->Extensions.EXT_packed_depth_stencil &&
477 ctx->Extensions.ARB_depth_texture &&
Brian Paul45e76d22009-10-08 20:27:27 -0600478 baseFormat == GL_DEPTH_STENCIL_EXT) {
Mathias Fröhlich042d9a52009-05-19 09:59:01 -0600479 /* OK */
480 }
481 else {
482 /* no such thing as stencil-only textures */
483 att_incomplete("illegal stencil texture");
484 att->Complete = GL_FALSE;
485 return;
486 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000487 }
488 }
Brian Paule4b23562005-05-04 20:11:35 +0000489 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul45e76d22009-10-08 20:27:27 -0600490 const GLenum baseFormat =
491 _mesa_get_format_base_format(att->Renderbuffer->Format);
492
Brian Paul49918882006-03-20 15:27:55 +0000493 ASSERT(att->Renderbuffer);
494 if (!att->Renderbuffer->InternalFormat ||
495 att->Renderbuffer->Width < 1 ||
496 att->Renderbuffer->Height < 1) {
Brian Paul9f731c82009-02-17 16:47:54 -0700497 att_incomplete("0x0 renderbuffer");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000498 att->Complete = GL_FALSE;
499 return;
500 }
501 if (format == GL_COLOR) {
Brian Paul45e76d22009-10-08 20:27:27 -0600502 if (baseFormat != GL_RGB &&
503 baseFormat != GL_RGBA) {
Brian Paul9f731c82009-02-17 16:47:54 -0700504 att_incomplete("bad renderbuffer color format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000505 att->Complete = GL_FALSE;
506 return;
507 }
508 }
509 else if (format == GL_DEPTH) {
Brian Paul45e76d22009-10-08 20:27:27 -0600510 if (baseFormat == GL_DEPTH_COMPONENT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000511 /* OK */
512 }
513 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Brian Paul45e76d22009-10-08 20:27:27 -0600514 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000515 /* OK */
516 }
517 else {
Brian Paul9f731c82009-02-17 16:47:54 -0700518 att_incomplete("bad renderbuffer depth format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000519 att->Complete = GL_FALSE;
520 return;
521 }
522 }
523 else {
524 assert(format == GL_STENCIL);
Brian Paul45e76d22009-10-08 20:27:27 -0600525 if (baseFormat == GL_STENCIL_INDEX) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000526 /* OK */
527 }
528 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Brian Paul45e76d22009-10-08 20:27:27 -0600529 baseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000530 /* OK */
531 }
532 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000533 att->Complete = GL_FALSE;
Brian Paul9f731c82009-02-17 16:47:54 -0700534 att_incomplete("bad renderbuffer stencil format");
Brian Paulf0bbbf62005-02-09 03:50:30 +0000535 return;
536 }
537 }
538 }
Brian Paule4b23562005-05-04 20:11:35 +0000539 else {
540 ASSERT(att->Type == GL_NONE);
541 /* complete */
542 return;
543 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000544}
545
546
547/**
548 * Test if the given framebuffer object is complete and update its
549 * Status field with the results.
Brian Paul3528f692009-01-22 15:13:18 -0700550 * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
551 * driver to make hardware-specific validation/completeness checks.
Brian Paule4b23562005-05-04 20:11:35 +0000552 * Also update the framebuffer's Width and Height fields if the
553 * framebuffer is complete.
Brian Paulf0bbbf62005-02-09 03:50:30 +0000554 */
Brian Paule4b23562005-05-04 20:11:35 +0000555void
556_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000557{
Brian Paul989edea2009-01-22 15:05:13 -0700558 GLuint numImages;
559 GLenum intFormat = GL_NONE; /* color buffers' internal format */
560 GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
Brian Paul722d9762009-01-20 16:58:49 -0700561 GLint numSamples = -1;
Brian Paule4b23562005-05-04 20:11:35 +0000562 GLint i;
Brian Paul28b014e2006-04-05 03:05:17 +0000563 GLuint j;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000564
Brian Paulc7264412005-06-01 00:50:23 +0000565 assert(fb->Name != 0);
566
Brian Paulf0bbbf62005-02-09 03:50:30 +0000567 numImages = 0;
Brian Paule4b23562005-05-04 20:11:35 +0000568 fb->Width = 0;
569 fb->Height = 0;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000570
Brian Paul989edea2009-01-22 15:05:13 -0700571 /* Start at -2 to more easily loop over all attachment points.
572 * -2: depth buffer
573 * -1: stencil buffer
574 * >=0: color buffer
575 */
Brian Paule4b23562005-05-04 20:11:35 +0000576 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000577 struct gl_renderbuffer_attachment *att;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000578 GLenum f;
579
Brian Paul1bc59bf2009-01-22 15:07:34 -0700580 /*
581 * XXX for ARB_fbo, only check color buffers that are named by
582 * GL_READ_BUFFER and GL_DRAW_BUFFERi.
583 */
584
Brian Paul989edea2009-01-22 15:05:13 -0700585 /* check for attachment completeness
586 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000587 if (i == -2) {
Brian Paule4b23562005-05-04 20:11:35 +0000588 att = &fb->Attachment[BUFFER_DEPTH];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000589 test_attachment_completeness(ctx, GL_DEPTH, att);
590 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000591 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000592 fbo_incomplete("depth attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000593 return;
594 }
595 }
596 else if (i == -1) {
Brian Paule4b23562005-05-04 20:11:35 +0000597 att = &fb->Attachment[BUFFER_STENCIL];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000598 test_attachment_completeness(ctx, GL_STENCIL, att);
599 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000600 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000601 fbo_incomplete("stencil attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000602 return;
603 }
604 }
605 else {
Brian Paule4b23562005-05-04 20:11:35 +0000606 att = &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000607 test_attachment_completeness(ctx, GL_COLOR, att);
608 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000609 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000610 fbo_incomplete("color attachment incomplete", i);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000611 return;
612 }
613 }
614
Brian Paul989edea2009-01-22 15:05:13 -0700615 /* get width, height, format of the renderbuffer/texture
616 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000617 if (att->Type == GL_TEXTURE) {
Brian Paula9fc8ba2005-10-05 01:48:07 +0000618 const struct gl_texture_image *texImg
619 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
Brian Paul989edea2009-01-22 15:05:13 -0700620 minWidth = MIN2(minWidth, texImg->Width);
621 maxWidth = MAX2(maxWidth, texImg->Width);
622 minHeight = MIN2(minHeight, texImg->Height);
623 maxHeight = MAX2(maxHeight, texImg->Height);
Brian Paula9fc8ba2005-10-05 01:48:07 +0000624 f = texImg->_BaseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000625 numImages++;
Brian Paul9f6ff492006-03-28 15:24:50 +0000626 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT
Eric Anholt262cdbd2010-05-25 08:00:51 -0700627 && f != GL_DEPTH_STENCIL_EXT
628 && (!ctx->Extensions.ARB_framebuffer_object || f != GL_ALPHA)) {
Brian Pauled7f3ae2005-06-07 15:03:40 +0000629 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000630 fbo_incomplete("texture attachment incomplete", -1);
Brian Pauled7f3ae2005-06-07 15:03:40 +0000631 return;
632 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000633 }
634 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul989edea2009-01-22 15:05:13 -0700635 minWidth = MIN2(minWidth, att->Renderbuffer->Width);
636 maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
637 minHeight = MIN2(minHeight, att->Renderbuffer->Height);
638 maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000639 f = att->Renderbuffer->InternalFormat;
640 numImages++;
641 }
642 else {
643 assert(att->Type == GL_NONE);
644 continue;
645 }
646
Brian Paul72966362009-01-21 16:28:38 -0700647 if (numSamples < 0) {
648 /* first buffer */
649 numSamples = att->Renderbuffer->NumSamples;
650 }
651
Brian Paul722d9762009-01-20 16:58:49 -0700652 /* Error-check width, height, format, samples
Brian Paul989edea2009-01-22 15:05:13 -0700653 */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000654 if (numImages == 1) {
Brian Paul722d9762009-01-20 16:58:49 -0700655 /* save format, num samples */
656 if (i >= 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000657 intFormat = f;
Brian Paul722d9762009-01-20 16:58:49 -0700658 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000659 }
660 else {
Brian Paul989edea2009-01-22 15:05:13 -0700661 if (!ctx->Extensions.ARB_framebuffer_object) {
662 /* check that width, height, format are same */
663 if (minWidth != maxWidth || minHeight != maxHeight) {
664 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
665 fbo_incomplete("width or height mismatch", -1);
666 return;
667 }
668 /* check that all color buffer have same format */
669 if (intFormat != GL_NONE && f != intFormat) {
670 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
671 fbo_incomplete("format mismatch", -1);
672 return;
673 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000674 }
Brian Paul722d9762009-01-20 16:58:49 -0700675 if (att->Renderbuffer &&
676 att->Renderbuffer->NumSamples != numSamples) {
Brian Paul72966362009-01-21 16:28:38 -0700677 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
Brian Paul722d9762009-01-20 16:58:49 -0700678 fbo_incomplete("inconsistant number of samples", i);
679 return;
680 }
681
Brian Paulf0bbbf62005-02-09 03:50:30 +0000682 }
683 }
684
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400685#if FEATURE_GL
686 if (ctx->API == API_OPENGL) {
687 /* Check that all DrawBuffers are present */
688 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
689 if (fb->ColorDrawBuffer[j] != GL_NONE) {
690 const struct gl_renderbuffer_attachment *att
691 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
692 assert(att);
693 if (att->Type == GL_NONE) {
694 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
695 fbo_incomplete("missing drawbuffer", j);
696 return;
697 }
698 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000699 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000700
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400701 /* Check that the ReadBuffer is present */
702 if (fb->ColorReadBuffer != GL_NONE) {
703 const struct gl_renderbuffer_attachment *att
704 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
705 assert(att);
706 if (att->Type == GL_NONE) {
707 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000708 fbo_incomplete("missing readbuffer", -1);
Kristian Høgsberge88cef32010-05-24 16:56:12 -0400709 return;
710 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000711 }
712 }
Chia-I Wu9927d7f2009-10-02 15:32:04 +0800713#else
714 (void) j;
Brian Paul868c09a2008-08-08 13:06:54 -0600715#endif
Brian Paulf0bbbf62005-02-09 03:50:30 +0000716
717 if (numImages == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000718 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000719 fbo_incomplete("no attachments", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000720 return;
721 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000722
Brian Paul3528f692009-01-22 15:13:18 -0700723 /* Provisionally set status = COMPLETE ... */
Brian Paule4b23562005-05-04 20:11:35 +0000724 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
Brian Paul3528f692009-01-22 15:13:18 -0700725
Brian Paul777a2ef2009-01-22 15:17:42 -0700726 /* ... but the driver may say the FB is incomplete.
727 * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
728 * if anything.
729 */
Brian Paul3528f692009-01-22 15:13:18 -0700730 if (ctx->Driver.ValidateFramebuffer) {
731 ctx->Driver.ValidateFramebuffer(ctx, fb);
Brian Paul1f32c412009-01-19 17:34:19 -0700732 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
733 fbo_incomplete("driver marked FBO as incomplete", -1);
734 }
Brian Paul3528f692009-01-22 15:13:18 -0700735 }
736
737 if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
738 /*
739 * Note that if ARB_framebuffer_object is supported and the attached
740 * renderbuffers/textures are different sizes, the framebuffer
741 * width/height will be set to the smallest width/height.
742 */
743 fb->Width = minWidth;
744 fb->Height = minHeight;
Brian Paul38768db2009-01-27 09:49:27 -0700745
746 /* finally, update the visual info for the framebuffer */
747 _mesa_update_framebuffer_visual(fb);
Brian Paul3528f692009-01-22 15:13:18 -0700748 }
Brian Paule4b23562005-05-04 20:11:35 +0000749}
Brian Paulf0bbbf62005-02-09 03:50:30 +0000750
751
Brian Paul1864c7d2005-02-08 03:46:37 +0000752GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000753_mesa_IsRenderbufferEXT(GLuint renderbuffer)
754{
Brian Paulddc82ee2005-02-05 19:56:45 +0000755 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000756 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000757 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000758 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000759 if (rb != NULL && rb != &DummyRenderbuffer)
760 return GL_TRUE;
761 }
762 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000763}
764
765
Brian Paul1864c7d2005-02-08 03:46:37 +0000766void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000767_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
768{
Brian42aaa542007-03-25 10:39:36 -0600769 struct gl_renderbuffer *newRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000770 GET_CURRENT_CONTEXT(ctx);
771
772 ASSERT_OUTSIDE_BEGIN_END(ctx);
773
Brian Paul3deaa012005-02-07 05:08:24 +0000774 if (target != GL_RENDERBUFFER_EXT) {
Brian Paul4de18fb2009-11-02 15:30:51 -0700775 _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000776 return;
777 }
778
Brian Paul800e5532009-11-02 15:39:39 -0700779 /* No need to flush here since the render buffer binding has no
780 * effect on rendering state.
781 */
Brian Paul474f28e2005-10-08 14:41:17 +0000782
Brian Paul3deaa012005-02-07 05:08:24 +0000783 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000784 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000785 if (newRb == &DummyRenderbuffer) {
786 /* ID was reserved, but no real renderbuffer object made yet */
787 newRb = NULL;
788 }
Brian Paul1bc59bf2009-01-22 15:07:34 -0700789 else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
790 /* All RB IDs must be Gen'd */
791 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
792 return;
793 }
794
Brian Paul3deaa012005-02-07 05:08:24 +0000795 if (!newRb) {
796 /* create new renderbuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000797 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000798 if (!newRb) {
799 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
800 return;
801 }
Brian Paul2c6f9112005-02-24 05:47:06 +0000802 ASSERT(newRb->AllocStorage);
Brian Paul1864c7d2005-02-08 03:46:37 +0000803 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
Brian42aaa542007-03-25 10:39:36 -0600804 newRb->RefCount = 1; /* referenced by hash table */
Brian Paul3deaa012005-02-07 05:08:24 +0000805 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000806 }
Brian Paul463642c2005-02-08 02:06:00 +0000807 else {
808 newRb = NULL;
809 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000810
Brian Paul1864c7d2005-02-08 03:46:37 +0000811 ASSERT(newRb != &DummyRenderbuffer);
812
Brian42aaa542007-03-25 10:39:36 -0600813 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
Brian Paulddc82ee2005-02-05 19:56:45 +0000814}
815
816
Brian Pauld0f13fa2009-01-21 11:17:45 -0700817/**
818 * If the given renderbuffer is anywhere attached to the framebuffer, detach
819 * the renderbuffer.
820 * This is used when a renderbuffer object is deleted.
821 * The spec calls for unbinding.
822 */
823static void
824detach_renderbuffer(GLcontext *ctx,
825 struct gl_framebuffer *fb,
826 struct gl_renderbuffer *rb)
827{
828 GLuint i;
829 for (i = 0; i < BUFFER_COUNT; i++) {
830 if (fb->Attachment[i].Renderbuffer == rb) {
831 _mesa_remove_attachment(ctx, &fb->Attachment[i]);
832 }
833 }
Brian Paul72966362009-01-21 16:28:38 -0700834 invalidate_framebuffer(fb);
Brian Pauld0f13fa2009-01-21 11:17:45 -0700835}
836
837
Brian Paul1864c7d2005-02-08 03:46:37 +0000838void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000839_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
840{
841 GLint i;
842 GET_CURRENT_CONTEXT(ctx);
843
844 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000845 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000846
847 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000848 if (renderbuffers[i] > 0) {
849 struct gl_renderbuffer *rb;
Brian Paulea4fe662006-03-26 05:22:17 +0000850 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +0000851 if (rb) {
Brian Paul91802fd2005-10-04 16:01:02 +0000852 /* check if deleting currently bound renderbuffer object */
853 if (rb == ctx->CurrentRenderbuffer) {
854 /* bind default */
855 ASSERT(rb->RefCount >= 2);
856 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
857 }
858
Brian Pauld0f13fa2009-01-21 11:17:45 -0700859 if (ctx->DrawBuffer->Name) {
860 detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
861 }
862 if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) {
863 detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
864 }
865
Brian42aaa542007-03-25 10:39:36 -0600866 /* Remove from hash table immediately, to free the ID.
867 * But the object will not be freed until it's no longer
868 * referenced anywhere else.
869 */
Brian Paul3deaa012005-02-07 05:08:24 +0000870 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +0000871
Brian Paul1864c7d2005-02-08 03:46:37 +0000872 if (rb != &DummyRenderbuffer) {
Brian42aaa542007-03-25 10:39:36 -0600873 /* no longer referenced by hash table */
874 _mesa_reference_renderbuffer(&rb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +0000875 }
876 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000877 }
878 }
879}
880
881
Brian Paul1864c7d2005-02-08 03:46:37 +0000882void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000883_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
884{
885 GET_CURRENT_CONTEXT(ctx);
886 GLuint first;
887 GLint i;
888
889 ASSERT_OUTSIDE_BEGIN_END(ctx);
890
891 if (n < 0) {
892 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
893 return;
894 }
895
896 if (!renderbuffers)
897 return;
898
899 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
900
901 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000902 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000903 renderbuffers[i] = name;
Brian Paul1864c7d2005-02-08 03:46:37 +0000904 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +0000905 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +0000906 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +0000907 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +0000908 }
909}
910
911
Brian Pauld9468c92005-02-10 16:08:07 +0000912/**
913 * Given an internal format token for a render buffer, return the
914 * corresponding base format.
Brian Paul59e0faa2006-03-15 17:48:00 +0000915 * This is very similar to _mesa_base_tex_format() but the set of valid
916 * internal formats is somewhat different.
917 *
Brian Pauld9468c92005-02-10 16:08:07 +0000918 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
Brian Paul1ad7b992005-09-28 02:29:50 +0000919 * GL_DEPTH_STENCIL_EXT or zero if error.
Brian Paul031f23a2010-01-19 17:59:50 -0700920 *
921 * XXX in the future when we support red-only and red-green formats
922 * we'll also return GL_RED and GL_RG.
Brian Pauld9468c92005-02-10 16:08:07 +0000923 */
Brian Paul59e0faa2006-03-15 17:48:00 +0000924GLenum
925_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
Brian Paul463642c2005-02-08 02:06:00 +0000926{
927 switch (internalFormat) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000928 case GL_RGB:
929 case GL_R3_G3_B2:
930 case GL_RGB4:
931 case GL_RGB5:
932 case GL_RGB8:
933 case GL_RGB10:
934 case GL_RGB12:
935 case GL_RGB16:
936 return GL_RGB;
937 case GL_RGBA:
938 case GL_RGBA2:
939 case GL_RGBA4:
940 case GL_RGB5_A1:
941 case GL_RGBA8:
942 case GL_RGB10_A2:
943 case GL_RGBA12:
944 case GL_RGBA16:
Brian Paul8ea61482010-05-09 18:42:14 -0600945 case GL_RGBA16_SNORM:
Brian Paulf0bbbf62005-02-09 03:50:30 +0000946 return GL_RGBA;
947 case GL_STENCIL_INDEX:
948 case GL_STENCIL_INDEX1_EXT:
949 case GL_STENCIL_INDEX4_EXT:
950 case GL_STENCIL_INDEX8_EXT:
951 case GL_STENCIL_INDEX16_EXT:
952 return GL_STENCIL_INDEX;
953 case GL_DEPTH_COMPONENT:
Brian Paul2c6f9112005-02-24 05:47:06 +0000954 case GL_DEPTH_COMPONENT16:
955 case GL_DEPTH_COMPONENT24:
956 case GL_DEPTH_COMPONENT32:
Brian Paulf0bbbf62005-02-09 03:50:30 +0000957 return GL_DEPTH_COMPONENT;
Brian Paul1ad7b992005-09-28 02:29:50 +0000958 case GL_DEPTH_STENCIL_EXT:
959 case GL_DEPTH24_STENCIL8_EXT:
960 if (ctx->Extensions.EXT_packed_depth_stencil)
961 return GL_DEPTH_STENCIL_EXT;
962 else
963 return 0;
Brian Pauld9468c92005-02-10 16:08:07 +0000964 /* XXX add floating point formats eventually */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000965 default:
966 return 0;
Brian Paul463642c2005-02-08 02:06:00 +0000967 }
Brian Paul463642c2005-02-08 02:06:00 +0000968}
969
970
Brian Paul4f3514e2009-01-22 15:19:56 -0700971/** sentinal value, see below */
972#define NO_SAMPLES 1000
973
974
975/**
976 * Helper function used by _mesa_RenderbufferStorageEXT() and
977 * _mesa_RenderbufferStorageMultisample().
978 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
979 */
980static void
981renderbuffer_storage(GLenum target, GLenum internalFormat,
982 GLsizei width, GLsizei height, GLsizei samples)
Brian Paulddc82ee2005-02-05 19:56:45 +0000983{
Brian Paul4f3514e2009-01-22 15:19:56 -0700984 const char *func = samples == NO_SAMPLES ?
985 "glRenderbufferStorage" : "RenderbufferStorageMultisample";
Brian Paul2c6f9112005-02-24 05:47:06 +0000986 struct gl_renderbuffer *rb;
Brian Paul463642c2005-02-08 02:06:00 +0000987 GLenum baseFormat;
Brian Paulddc82ee2005-02-05 19:56:45 +0000988 GET_CURRENT_CONTEXT(ctx);
989
990 ASSERT_OUTSIDE_BEGIN_END(ctx);
991
Brian Paul463642c2005-02-08 02:06:00 +0000992 if (target != GL_RENDERBUFFER_EXT) {
Brian Paul4f3514e2009-01-22 15:19:56 -0700993 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +0000994 return;
995 }
996
Brian Paul59e0faa2006-03-15 17:48:00 +0000997 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
Brian Paul463642c2005-02-08 02:06:00 +0000998 if (baseFormat == 0) {
Brian Paul4f3514e2009-01-22 15:19:56 -0700999 _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001000 return;
1001 }
1002
Brian Paul13abf912006-04-13 19:17:13 +00001003 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001004 _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001005 return;
1006 }
1007
Brian Paul13abf912006-04-13 19:17:13 +00001008 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001009 _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
1010 return;
1011 }
1012
1013 if (samples == NO_SAMPLES) {
1014 /* NumSamples == 0 indicates non-multisampling */
1015 samples = 0;
1016 }
Brian Paulca0d0482010-01-27 17:01:54 -07001017 else if (samples > (GLsizei) ctx->Const.MaxSamples) {
Brian Paul722d9762009-01-20 16:58:49 -07001018 /* note: driver may choose to use more samples than what's requested */
Brian Paul4f3514e2009-01-22 15:19:56 -07001019 _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
Brian Paulddc82ee2005-02-05 19:56:45 +00001020 return;
1021 }
1022
Brian Paul2c6f9112005-02-24 05:47:06 +00001023 rb = ctx->CurrentRenderbuffer;
Brian Paul2c6f9112005-02-24 05:47:06 +00001024 if (!rb) {
Brian Paul4f3514e2009-01-22 15:19:56 -07001025 _mesa_error(ctx, GL_INVALID_OPERATION, func);
Brian Paul463642c2005-02-08 02:06:00 +00001026 return;
1027 }
1028
Brian Paul474f28e2005-10-08 14:41:17 +00001029 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1030
Brian Paul311bcf52005-11-18 02:24:14 +00001031 if (rb->InternalFormat == internalFormat &&
Brian Paul13abf912006-04-13 19:17:13 +00001032 rb->Width == (GLuint) width &&
1033 rb->Height == (GLuint) height) {
Brian Paul311bcf52005-11-18 02:24:14 +00001034 /* no change in allocation needed */
1035 return;
1036 }
1037
Brian Paulea4fe662006-03-26 05:22:17 +00001038 /* These MUST get set by the AllocStorage func */
Brian Paul45e76d22009-10-08 20:27:27 -06001039 rb->Format = MESA_FORMAT_NONE;
Brian Paul4f3514e2009-01-22 15:19:56 -07001040 rb->NumSamples = samples;
Brian Paulea4fe662006-03-26 05:22:17 +00001041
Brian Paul2c6f9112005-02-24 05:47:06 +00001042 /* Now allocate the storage */
1043 ASSERT(rb->AllocStorage);
1044 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
1045 /* No error - check/set fields now */
Brian Paul45e76d22009-10-08 20:27:27 -06001046 assert(rb->Format != MESA_FORMAT_NONE);
Brian Paul13abf912006-04-13 19:17:13 +00001047 assert(rb->Width == (GLuint) width);
1048 assert(rb->Height == (GLuint) height);
Brian Paulea4fe662006-03-26 05:22:17 +00001049 rb->InternalFormat = internalFormat;
Brian Paula8dafe72010-02-25 19:03:55 -07001050 rb->_BaseFormat = baseFormat;
Brian Paul45e76d22009-10-08 20:27:27 -06001051 assert(rb->_BaseFormat != 0);
Brian Paul2c6f9112005-02-24 05:47:06 +00001052 }
1053 else {
1054 /* Probably ran out of memory - clear the fields */
1055 rb->Width = 0;
1056 rb->Height = 0;
Brian Paul45e76d22009-10-08 20:27:27 -06001057 rb->Format = MESA_FORMAT_NONE;
Brian Paul2c6f9112005-02-24 05:47:06 +00001058 rb->InternalFormat = GL_NONE;
1059 rb->_BaseFormat = GL_NONE;
Brian Paul4f3514e2009-01-22 15:19:56 -07001060 rb->NumSamples = 0;
Brian Paul463642c2005-02-08 02:06:00 +00001061 }
1062
Brian Paule4b23562005-05-04 20:11:35 +00001063 /*
1064 test_framebuffer_completeness(ctx, fb);
1065 */
Brian Paul2c6f9112005-02-24 05:47:06 +00001066 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
1067 * points???
1068 */
Brian Paulddc82ee2005-02-05 19:56:45 +00001069}
1070
Brian Paul23c5b212010-05-28 13:33:03 -06001071
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001072#if FEATURE_OES_EGL_image
1073void GLAPIENTRY
Brian Paul23c5b212010-05-28 13:33:03 -06001074_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001075{
Brian Paul51b79922010-02-24 11:57:26 -07001076 struct gl_renderbuffer *rb;
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001077 GET_CURRENT_CONTEXT(ctx);
1078 ASSERT_OUTSIDE_BEGIN_END(ctx);
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001079
Chia-I Wu2002e4d02010-04-06 17:46:17 +08001080 if (!ctx->Extensions.OES_EGL_image) {
1081 _mesa_error(ctx, GL_INVALID_OPERATION,
1082 "glEGLImageTargetRenderbufferStorageOES(unsupported)");
1083 return;
1084 }
1085
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001086 if (target != GL_RENDERBUFFER) {
Brian Paul23c5b212010-05-28 13:33:03 -06001087 _mesa_error(ctx, GL_INVALID_ENUM,
1088 "EGLImageTargetRenderbufferStorageOES");
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001089 return;
1090 }
1091
1092 rb = ctx->CurrentRenderbuffer;
1093 if (!rb) {
Brian Paul23c5b212010-05-28 13:33:03 -06001094 _mesa_error(ctx, GL_INVALID_OPERATION,
1095 "EGLImageTargetRenderbufferStorageOES");
Kristian Høgsbergd1dc5b12010-02-11 17:42:30 -05001096 return;
1097 }
1098
1099 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1100
1101 ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1102}
1103#endif
Brian Paulddc82ee2005-02-05 19:56:45 +00001104
Brian Paul23c5b212010-05-28 13:33:03 -06001105
Brian Paul45e76d22009-10-08 20:27:27 -06001106/**
1107 * Helper function for _mesa_GetRenderbufferParameterivEXT() and
1108 * _mesa_GetFramebufferAttachmentParameterivEXT()
1109 * We have to be careful to respect the base format. For example, if a
1110 * renderbuffer/texture was created with internalFormat=GL_RGB but the
1111 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
1112 * we need to return zero.
1113 */
1114static GLint
1115get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
1116{
1117 switch (pname) {
1118 case GL_RENDERBUFFER_RED_SIZE_EXT:
1119 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
1120 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1121 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
1122 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1123 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
1124 if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
1125 return _mesa_get_format_bits(format, pname);
1126 else
1127 return 0;
1128 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1129 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
1130 if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA)
1131 return _mesa_get_format_bits(format, pname);
1132 else
1133 return 0;
1134 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1135 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
1136 if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
1137 return _mesa_get_format_bits(format, pname);
1138 else
1139 return 0;
1140 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1141 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
1142 if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
1143 return _mesa_get_format_bits(format, pname);
1144 else
1145 return 0;
1146 default:
1147 return 0;
1148 }
1149}
1150
1151
1152
Brian Paul1864c7d2005-02-08 03:46:37 +00001153void GLAPIENTRY
Brian Paul4f3514e2009-01-22 15:19:56 -07001154_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1155 GLsizei width, GLsizei height)
1156{
Brian Paul722d9762009-01-20 16:58:49 -07001157 /* GL_ARB_fbo says calling this function is equivalent to calling
1158 * glRenderbufferStorageMultisample() with samples=0. We pass in
1159 * a token value here just for error reporting purposes.
1160 */
Brian Paul4f3514e2009-01-22 15:19:56 -07001161 renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
1162}
1163
1164
1165void GLAPIENTRY
Brian Paul777a2ef2009-01-22 15:17:42 -07001166_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
Brian Paul4f3514e2009-01-22 15:19:56 -07001167 GLenum internalFormat,
Brian Paul777a2ef2009-01-22 15:17:42 -07001168 GLsizei width, GLsizei height)
1169{
Brian Paul4f3514e2009-01-22 15:19:56 -07001170 renderbuffer_storage(target, internalFormat, width, height, samples);
Brian Paul777a2ef2009-01-22 15:17:42 -07001171}
1172
Brian Paul23c5b212010-05-28 13:33:03 -06001173
1174/**
1175 * OpenGL ES version of glRenderBufferStorage.
1176 */
Kristian Høgsberg61d94dd2010-04-22 21:11:56 -04001177void GLAPIENTRY
1178_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1179 GLsizei width, GLsizei height)
1180{
1181 switch (internalFormat) {
1182 case GL_RGB565:
1183 /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
1184 /* choose a closest format */
1185 internalFormat = GL_RGB5;
1186 break;
1187 default:
1188 break;
1189 }
Brian Paul777a2ef2009-01-22 15:17:42 -07001190
Kristian Høgsberg61d94dd2010-04-22 21:11:56 -04001191 renderbuffer_storage(target, internalFormat, width, height, 0);
1192}
Brian Paul777a2ef2009-01-22 15:17:42 -07001193
Brian Paul23c5b212010-05-28 13:33:03 -06001194
Brian Paul777a2ef2009-01-22 15:17:42 -07001195void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001196_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
1197{
Brian Paul722d9762009-01-20 16:58:49 -07001198 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001199 GET_CURRENT_CONTEXT(ctx);
1200
1201 ASSERT_OUTSIDE_BEGIN_END(ctx);
1202
Brian Paul463642c2005-02-08 02:06:00 +00001203 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001204 _mesa_error(ctx, GL_INVALID_ENUM,
1205 "glGetRenderbufferParameterivEXT(target)");
1206 return;
1207 }
1208
Brian Paul722d9762009-01-20 16:58:49 -07001209 rb = ctx->CurrentRenderbuffer;
1210 if (!rb) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001211 _mesa_error(ctx, GL_INVALID_OPERATION,
1212 "glGetRenderbufferParameterivEXT");
1213 return;
1214 }
1215
Brian Paul800e5532009-11-02 15:39:39 -07001216 /* No need to flush here since we're just quering state which is
1217 * not effected by rendering.
1218 */
Brian Paul474f28e2005-10-08 14:41:17 +00001219
Brian Paul463642c2005-02-08 02:06:00 +00001220 switch (pname) {
1221 case GL_RENDERBUFFER_WIDTH_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001222 *params = rb->Width;
Brian Paul463642c2005-02-08 02:06:00 +00001223 return;
1224 case GL_RENDERBUFFER_HEIGHT_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001225 *params = rb->Height;
Brian Paul463642c2005-02-08 02:06:00 +00001226 return;
1227 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
Brian Paul722d9762009-01-20 16:58:49 -07001228 *params = rb->InternalFormat;
Brian Paul463642c2005-02-08 02:06:00 +00001229 return;
Brian Paul1b939532005-05-31 23:55:21 +00001230 case GL_RENDERBUFFER_RED_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001231 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001232 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001233 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001234 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
Brian Paul1b939532005-05-31 23:55:21 +00001235 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
Brian Paul45e76d22009-10-08 20:27:27 -06001236 *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
Brian Paul1b939532005-05-31 23:55:21 +00001237 break;
Brian Paul722d9762009-01-20 16:58:49 -07001238 case GL_RENDERBUFFER_SAMPLES:
1239 if (ctx->Extensions.ARB_framebuffer_object) {
1240 *params = rb->NumSamples;
1241 break;
1242 }
1243 /* fallthrough */
Brian Paul463642c2005-02-08 02:06:00 +00001244 default:
1245 _mesa_error(ctx, GL_INVALID_ENUM,
1246 "glGetRenderbufferParameterivEXT(target)");
1247 return;
1248 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001249}
1250
1251
Brian Paul1864c7d2005-02-08 03:46:37 +00001252GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001253_mesa_IsFramebufferEXT(GLuint framebuffer)
1254{
Brian Paulddc82ee2005-02-05 19:56:45 +00001255 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +00001256 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +00001257 if (framebuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00001258 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +00001259 if (rb != NULL && rb != &DummyFramebuffer)
1260 return GL_TRUE;
1261 }
1262 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +00001263}
1264
1265
briana492ab72009-11-10 15:33:31 -07001266/**
1267 * Check if any of the attachments of the given framebuffer are textures
1268 * (render to texture). Call ctx->Driver.RenderTexture() for such
1269 * attachments.
1270 */
Brian Paulea4fe662006-03-26 05:22:17 +00001271static void
1272check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
1273{
1274 GLuint i;
1275 ASSERT(ctx->Driver.RenderTexture);
briana65b84d2009-11-10 18:02:03 -07001276
1277 if (fb->Name == 0)
1278 return; /* can't render to texture with winsys framebuffers */
1279
Brian Paulea4fe662006-03-26 05:22:17 +00001280 for (i = 0; i < BUFFER_COUNT; i++) {
1281 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1282 struct gl_texture_object *texObj = att->Texture;
Brian Paul9f6ff492006-03-28 15:24:50 +00001283 if (texObj
Brian Paulb5d6a8e2009-10-12 18:09:32 -06001284 && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +00001285 ctx->Driver.RenderTexture(ctx, fb, att);
1286 }
1287 }
1288}
1289
1290
Brian Paul0e31e022005-12-01 00:25:00 +00001291/**
1292 * Examine all the framebuffer's attachments to see if any are textures.
1293 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
1294 * notify the device driver that the texture image may have changed.
1295 */
1296static void
Brian Paulea4fe662006-03-26 05:22:17 +00001297check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
Brian Paul0e31e022005-12-01 00:25:00 +00001298{
briana65b84d2009-11-10 18:02:03 -07001299 if (fb->Name == 0)
1300 return; /* can't render to texture with winsys framebuffers */
1301
Brian Paul0e31e022005-12-01 00:25:00 +00001302 if (ctx->Driver.FinishRenderTexture) {
1303 GLuint i;
1304 for (i = 0; i < BUFFER_COUNT; i++) {
1305 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
Brian8b361662007-11-09 08:55:49 -07001306 if (att->Texture && att->Renderbuffer) {
Brian Paul519b23b2006-03-20 18:51:57 +00001307 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +00001308 }
1309 }
1310 }
1311}
1312
1313
Brian Paul1864c7d2005-02-08 03:46:37 +00001314void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001315_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
1316{
briane6f60d32009-11-10 15:47:34 -07001317 struct gl_framebuffer *newDrawFb, *newReadFb;
briand96e55f2009-11-10 15:50:22 -07001318 struct gl_framebuffer *oldDrawFb, *oldReadFb;
Brian Paul0bffb112005-11-08 14:45:48 +00001319 GLboolean bindReadBuf, bindDrawBuf;
Brian Paulddc82ee2005-02-05 19:56:45 +00001320 GET_CURRENT_CONTEXT(ctx);
1321
Brian Paul1bc59bf2009-01-22 15:07:34 -07001322#ifdef DEBUG
1323 if (ctx->Extensions.ARB_framebuffer_object) {
1324 ASSERT(ctx->Extensions.EXT_framebuffer_object);
1325 ASSERT(ctx->Extensions.EXT_framebuffer_blit);
1326 }
1327#endif
1328
Brian Paulddc82ee2005-02-05 19:56:45 +00001329 ASSERT_OUTSIDE_BEGIN_END(ctx);
1330
Brian Paulea4fe662006-03-26 05:22:17 +00001331 if (!ctx->Extensions.EXT_framebuffer_object) {
1332 _mesa_error(ctx, GL_INVALID_OPERATION,
1333 "glBindFramebufferEXT(unsupported)");
1334 return;
1335 }
1336
Brian Paul0bffb112005-11-08 14:45:48 +00001337 switch (target) {
1338#if FEATURE_EXT_framebuffer_blit
1339 case GL_DRAW_FRAMEBUFFER_EXT:
1340 if (!ctx->Extensions.EXT_framebuffer_blit) {
1341 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1342 return;
1343 }
1344 bindDrawBuf = GL_TRUE;
1345 bindReadBuf = GL_FALSE;
1346 break;
1347 case GL_READ_FRAMEBUFFER_EXT:
1348 if (!ctx->Extensions.EXT_framebuffer_blit) {
1349 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1350 return;
1351 }
1352 bindDrawBuf = GL_FALSE;
1353 bindReadBuf = GL_TRUE;
1354 break;
1355#endif
1356 case GL_FRAMEBUFFER_EXT:
1357 bindDrawBuf = GL_TRUE;
1358 bindReadBuf = GL_TRUE;
1359 break;
1360 default:
Brian Pauleba4ff62005-09-06 21:22:16 +00001361 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +00001362 return;
1363 }
1364
Brian Paul3deaa012005-02-07 05:08:24 +00001365 if (framebuffer) {
Brian Paule4b23562005-05-04 20:11:35 +00001366 /* Binding a user-created framebuffer object */
briane6f60d32009-11-10 15:47:34 -07001367 newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
1368 if (newDrawFb == &DummyFramebuffer) {
Brian Paul923b6fc2005-02-08 04:08:56 +00001369 /* ID was reserved, but no real framebuffer object made yet */
briane6f60d32009-11-10 15:47:34 -07001370 newDrawFb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001371 }
briane6f60d32009-11-10 15:47:34 -07001372 else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
Brian Paul1bc59bf2009-01-22 15:07:34 -07001373 /* All FBO IDs must be Gen'd */
1374 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
1375 return;
1376 }
1377
briane6f60d32009-11-10 15:47:34 -07001378 if (!newDrawFb) {
Brian Paul3deaa012005-02-07 05:08:24 +00001379 /* create new framebuffer object */
briane6f60d32009-11-10 15:47:34 -07001380 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
1381 if (!newDrawFb) {
Brian Paul3deaa012005-02-07 05:08:24 +00001382 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1383 return;
1384 }
briane6f60d32009-11-10 15:47:34 -07001385 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
Brian Paul3deaa012005-02-07 05:08:24 +00001386 }
briane6f60d32009-11-10 15:47:34 -07001387 newReadFb = newDrawFb;
Brian Paul3deaa012005-02-07 05:08:24 +00001388 }
Brian Paul463642c2005-02-08 02:06:00 +00001389 else {
Brian Paule4b23562005-05-04 20:11:35 +00001390 /* Binding the window system framebuffer (which was originally set
1391 * with MakeCurrent).
1392 */
briane6f60d32009-11-10 15:47:34 -07001393 newDrawFb = ctx->WinSysDrawBuffer;
1394 newReadFb = ctx->WinSysReadBuffer;
Brian Paul3deaa012005-02-07 05:08:24 +00001395 }
1396
briane6f60d32009-11-10 15:47:34 -07001397 ASSERT(newDrawFb);
1398 ASSERT(newDrawFb != &DummyFramebuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001399
briana65b84d2009-11-10 18:02:03 -07001400 /* save pointers to current/old framebuffers */
briand96e55f2009-11-10 15:50:22 -07001401 oldDrawFb = ctx->DrawBuffer;
1402 oldReadFb = ctx->ReadBuffer;
1403
briana65b84d2009-11-10 18:02:03 -07001404 /* check if really changing bindings */
1405 if (oldDrawFb == newDrawFb)
1406 bindDrawBuf = GL_FALSE;
1407 if (oldReadFb == newReadFb)
1408 bindReadBuf = GL_FALSE;
1409
Brian Paulea4fe662006-03-26 05:22:17 +00001410 /*
Brian Paul16144632009-02-26 14:49:24 -07001411 * OK, now bind the new Draw/Read framebuffers, if they're changing.
briana65b84d2009-11-10 18:02:03 -07001412 *
1413 * We also check if we're beginning and/or ending render-to-texture.
1414 * When a framebuffer with texture attachments is unbound, call
1415 * ctx->Driver.FinishRenderTexture().
1416 * When a framebuffer with texture attachments is bound, call
1417 * ctx->Driver.RenderTexture().
1418 *
1419 * Note that if the ReadBuffer has texture attachments we don't consider
1420 * that a render-to-texture case.
Brian Paulea4fe662006-03-26 05:22:17 +00001421 */
Brian Paul0bffb112005-11-08 14:45:48 +00001422 if (bindReadBuf) {
briana65b84d2009-11-10 18:02:03 -07001423 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
brianbc569cd2009-11-10 16:00:35 -07001424
briana65b84d2009-11-10 18:02:03 -07001425 /* check if old readbuffer was render-to-texture */
1426 check_end_texture_render(ctx, oldReadFb);
1427
1428 _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001429 }
1430
1431 if (bindDrawBuf) {
briana65b84d2009-11-10 18:02:03 -07001432 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian32d86eb2007-08-16 18:52:48 +01001433
briana65b84d2009-11-10 18:02:03 -07001434 /* check if old read/draw buffers were render-to-texture */
1435 if (!bindReadBuf)
1436 check_end_texture_render(ctx, oldReadFb);
brianbc569cd2009-11-10 16:00:35 -07001437
briana65b84d2009-11-10 18:02:03 -07001438 if (oldDrawFb != oldReadFb)
1439 check_end_texture_render(ctx, oldDrawFb);
brianbc569cd2009-11-10 16:00:35 -07001440
briana65b84d2009-11-10 18:02:03 -07001441 /* check if newly bound framebuffer has any texture attachments */
1442 check_begin_texture_render(ctx, newDrawFb);
1443
1444 _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001445 }
Brian Paul59e0faa2006-03-15 17:48:00 +00001446
Brian Paul16144632009-02-26 14:49:24 -07001447 if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
briane6f60d32009-11-10 15:47:34 -07001448 ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
Brian Paul59e0faa2006-03-15 17:48:00 +00001449 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001450}
1451
1452
Brian Paul1864c7d2005-02-08 03:46:37 +00001453void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001454_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1455{
1456 GLint i;
1457 GET_CURRENT_CONTEXT(ctx);
1458
1459 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul800e5532009-11-02 15:39:39 -07001460 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00001461
1462 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +00001463 if (framebuffers[i] > 0) {
1464 struct gl_framebuffer *fb;
Brian Paulea4fe662006-03-26 05:22:17 +00001465 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +00001466 if (fb) {
Brian Paule4b23562005-05-04 20:11:35 +00001467 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
Brian Paul91802fd2005-10-04 16:01:02 +00001468
1469 /* check if deleting currently bound framebuffer object */
Erik Wien68ca19a2010-01-26 13:19:30 -07001470 if (ctx->Extensions.EXT_framebuffer_blit) {
1471 /* separate draw/read binding points */
1472 if (fb == ctx->DrawBuffer) {
1473 /* bind default */
1474 ASSERT(fb->RefCount >= 2);
1475 _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1476 }
1477 if (fb == ctx->ReadBuffer) {
1478 /* bind default */
1479 ASSERT(fb->RefCount >= 2);
1480 _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1481 }
Brian Pauld0f13fa2009-01-21 11:17:45 -07001482 }
Erik Wien68ca19a2010-01-26 13:19:30 -07001483 else {
1484 /* only one binding point for read/draw buffers */
1485 if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
1486 /* bind default */
1487 ASSERT(fb->RefCount >= 2);
1488 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1489 }
Brian Paul91802fd2005-10-04 16:01:02 +00001490 }
1491
Brian Paul3deaa012005-02-07 05:08:24 +00001492 /* remove from hash table immediately, to free the ID */
1493 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +00001494
Brian Paul1864c7d2005-02-08 03:46:37 +00001495 if (fb != &DummyFramebuffer) {
1496 /* But the object will not be freed until it's no longer
1497 * bound in any context.
1498 */
Brian Pauld5229442009-02-09 08:30:55 -07001499 _mesa_reference_framebuffer(&fb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +00001500 }
1501 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001502 }
1503 }
1504}
1505
1506
Brian Paul1864c7d2005-02-08 03:46:37 +00001507void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001508_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1509{
1510 GET_CURRENT_CONTEXT(ctx);
1511 GLuint first;
1512 GLint i;
1513
1514 ASSERT_OUTSIDE_BEGIN_END(ctx);
1515
1516 if (n < 0) {
1517 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1518 return;
1519 }
1520
1521 if (!framebuffers)
1522 return;
1523
1524 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1525
1526 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001527 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001528 framebuffers[i] = name;
1529 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001530 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001531 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001532 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001533 }
1534}
1535
1536
1537
Brian Paul1864c7d2005-02-08 03:46:37 +00001538GLenum GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001539_mesa_CheckFramebufferStatusEXT(GLenum target)
1540{
Brian Paul0bffb112005-11-08 14:45:48 +00001541 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001542 GET_CURRENT_CONTEXT(ctx);
1543
Brian Paule4b23562005-05-04 20:11:35 +00001544 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001545
Brian Paul0bffb112005-11-08 14:45:48 +00001546 switch (target) {
1547#if FEATURE_EXT_framebuffer_blit
1548 case GL_DRAW_FRAMEBUFFER_EXT:
1549 if (!ctx->Extensions.EXT_framebuffer_blit) {
1550 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1551 return 0;
1552 }
1553 buffer = ctx->DrawBuffer;
1554 break;
1555 case GL_READ_FRAMEBUFFER_EXT:
1556 if (!ctx->Extensions.EXT_framebuffer_blit) {
1557 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1558 return 0;
1559 }
1560 buffer = ctx->ReadBuffer;
1561 break;
1562#endif
1563 case GL_FRAMEBUFFER_EXT:
1564 buffer = ctx->DrawBuffer;
1565 break;
1566 default:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001567 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
Brian Paule4b23562005-05-04 20:11:35 +00001568 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
Brian Paulddc82ee2005-02-05 19:56:45 +00001569 }
1570
Brian Paul0bffb112005-11-08 14:45:48 +00001571 if (buffer->Name == 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001572 /* The window system / default framebuffer is always complete */
1573 return GL_FRAMEBUFFER_COMPLETE_EXT;
1574 }
1575
Brian Paul800e5532009-11-02 15:39:39 -07001576 /* No need to flush here */
Brian Paul474f28e2005-10-08 14:41:17 +00001577
Brian Paul72966362009-01-21 16:28:38 -07001578 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
1579 _mesa_test_framebuffer_completeness(ctx, buffer);
1580 }
1581
Brian Paul0bffb112005-11-08 14:45:48 +00001582 return buffer->_Status;
Brian Paulddc82ee2005-02-05 19:56:45 +00001583}
1584
1585
1586
1587/**
Brian Paulea4fe662006-03-26 05:22:17 +00001588 * Common code called by glFramebufferTexture1D/2D/3DEXT().
Brian Paulddc82ee2005-02-05 19:56:45 +00001589 */
Brian Paulea4fe662006-03-26 05:22:17 +00001590static void
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001591framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
1592 GLenum attachment, GLenum textarget, GLuint texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001593 GLint level, GLint zoffset)
Brian Paulddc82ee2005-02-05 19:56:45 +00001594{
Brian Paul2c6f9112005-02-24 05:47:06 +00001595 struct gl_renderbuffer_attachment *att;
Brian Paulea4fe662006-03-26 05:22:17 +00001596 struct gl_texture_object *texObj = NULL;
1597 struct gl_framebuffer *fb;
Brian Paul5fec84a2009-01-29 15:01:09 -07001598 GLboolean error = GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +00001599
1600 ASSERT_OUTSIDE_BEGIN_END(ctx);
1601
Brian Paul5fec84a2009-01-29 15:01:09 -07001602 switch (target) {
1603 case GL_READ_FRAMEBUFFER_EXT:
1604 error = !ctx->Extensions.EXT_framebuffer_blit;
1605 fb = ctx->ReadBuffer;
1606 break;
1607 case GL_DRAW_FRAMEBUFFER_EXT:
1608 error = !ctx->Extensions.EXT_framebuffer_blit;
1609 /* fall-through */
1610 case GL_FRAMEBUFFER_EXT:
1611 fb = ctx->DrawBuffer;
1612 break;
1613 default:
1614 error = GL_TRUE;
1615 }
1616
1617 if (error) {
Brian Paulea4fe662006-03-26 05:22:17 +00001618 _mesa_error(ctx, GL_INVALID_ENUM,
Brian Paul5fec84a2009-01-29 15:01:09 -07001619 "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
Brian Paulddc82ee2005-02-05 19:56:45 +00001620 return;
Brian Paulea4fe662006-03-26 05:22:17 +00001621 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001622
Brian Paulea4fe662006-03-26 05:22:17 +00001623 ASSERT(fb);
Brian Paul3deaa012005-02-07 05:08:24 +00001624
Brian Paulea4fe662006-03-26 05:22:17 +00001625 /* check framebuffer binding */
1626 if (fb->Name == 0) {
1627 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001628 "glFramebufferTexture%sEXT", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001629 return;
1630 }
1631
Brian Paulea4fe662006-03-26 05:22:17 +00001632
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001633 /* The textarget, level, and zoffset parameters are only validated if
1634 * texture is non-zero.
1635 */
1636 if (texture) {
1637 GLboolean err = GL_TRUE;
1638
1639 texObj = _mesa_lookup_texture(ctx, texture);
1640 if (texObj != NULL) {
Ian Romanickbb372f12007-05-16 15:34:22 -07001641 if (textarget == 0) {
Brian Paul7a2e32d2010-03-10 10:54:24 -07001642 /* XXX what's the purpose of this? */
Ian Romanickbb372f12007-05-16 15:34:22 -07001643 err = (texObj->Target != GL_TEXTURE_3D) &&
1644 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1645 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1646 }
1647 else {
1648 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1649 ? !IS_CUBE_FACE(textarget)
1650 : (texObj->Target != textarget);
1651 }
Brian Paulea4fe662006-03-26 05:22:17 +00001652 }
Brian Paul7a2e32d2010-03-10 10:54:24 -07001653 else {
1654 /* can't render to a non-existant texture */
1655 _mesa_error(ctx, GL_INVALID_OPERATION,
1656 "glFramebufferTexture%sEXT(non existant texture)",
1657 caller);
1658 return;
1659 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001660
1661 if (err) {
Brian Paulea4fe662006-03-26 05:22:17 +00001662 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001663 "glFramebufferTexture%sEXT(texture target mismatch)",
1664 caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001665 return;
1666 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001667
1668 if (texObj->Target == GL_TEXTURE_3D) {
Brian Paulea4fe662006-03-26 05:22:17 +00001669 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1670 if (zoffset < 0 || zoffset >= maxSize) {
1671 _mesa_error(ctx, GL_INVALID_VALUE,
Ian Romanickbb372f12007-05-16 15:34:22 -07001672 "glFramebufferTexture%sEXT(zoffset)", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001673 return;
1674 }
1675 }
Ian Romanickbb372f12007-05-16 15:34:22 -07001676 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1677 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1678 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1679 _mesa_error(ctx, GL_INVALID_VALUE,
1680 "glFramebufferTexture%sEXT(layer)", caller);
1681 return;
1682 }
1683 }
1684
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001685 if ((level < 0) ||
1686 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1687 _mesa_error(ctx, GL_INVALID_VALUE,
1688 "glFramebufferTexture%sEXT(level)", caller);
1689 return;
1690 }
Brian Paulea4fe662006-03-26 05:22:17 +00001691 }
1692
1693 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001694 if (att == NULL) {
1695 _mesa_error(ctx, GL_INVALID_ENUM,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001696 "glFramebufferTexture%sEXT(attachment)", caller);
Brian Paul3deaa012005-02-07 05:08:24 +00001697 return;
1698 }
1699
Brian Paul800e5532009-11-02 15:39:39 -07001700 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paul474f28e2005-10-08 14:41:17 +00001701
Brian Paulea4fe662006-03-26 05:22:17 +00001702 _glthread_LOCK_MUTEX(fb->Mutex);
1703 if (texObj) {
1704 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1705 level, zoffset);
Brian Paul2897cee2009-01-29 09:20:18 -07001706 /* Set the render-to-texture flag. We'll check this flag in
1707 * glTexImage() and friends to determine if we need to revalidate
1708 * any FBOs that might be rendering into this texture.
1709 * This flag never gets cleared since it's non-trivial to determine
1710 * when all FBOs might be done rendering to this texture. That's OK
1711 * though since it's uncommon to render to a texture then repeatedly
1712 * call glTexImage() to change images in the texture.
1713 */
1714 texObj->_RenderToTexture = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +00001715 }
1716 else {
Brian Paul519b23b2006-03-20 18:51:57 +00001717 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +00001718 }
Brian Paul72966362009-01-21 16:28:38 -07001719
1720 invalidate_framebuffer(fb);
1721
Brian Paulea4fe662006-03-26 05:22:17 +00001722 _glthread_UNLOCK_MUTEX(fb->Mutex);
1723}
1724
1725
1726
1727void GLAPIENTRY
1728_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1729 GLenum textarget, GLuint texture, GLint level)
1730{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001731 GET_CURRENT_CONTEXT(ctx);
1732
1733 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1734 _mesa_error(ctx, GL_INVALID_ENUM,
1735 "glFramebufferTexture1DEXT(textarget)");
1736 return;
1737 }
1738
1739 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1740 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001741}
1742
1743
Brian Paul1864c7d2005-02-08 03:46:37 +00001744void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001745_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1746 GLenum textarget, GLuint texture, GLint level)
1747{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001748 GET_CURRENT_CONTEXT(ctx);
1749
1750 if ((texture != 0) &&
1751 (textarget != GL_TEXTURE_2D) &&
1752 (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1753 (!IS_CUBE_FACE(textarget))) {
1754 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul5fec84a2009-01-29 15:01:09 -07001755 "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001756 return;
1757 }
1758
1759 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1760 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001761}
1762
1763
Brian Paul1864c7d2005-02-08 03:46:37 +00001764void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001765_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1766 GLenum textarget, GLuint texture,
1767 GLint level, GLint zoffset)
1768{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001769 GET_CURRENT_CONTEXT(ctx);
1770
1771 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1772 _mesa_error(ctx, GL_INVALID_ENUM,
1773 "glFramebufferTexture3DEXT(textarget)");
1774 return;
1775 }
1776
1777 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001778 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00001779}
1780
1781
Brian Paul1864c7d2005-02-08 03:46:37 +00001782void GLAPIENTRY
Ian Romanickbb372f12007-05-16 15:34:22 -07001783_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1784 GLuint texture, GLint level, GLint layer)
1785{
1786 GET_CURRENT_CONTEXT(ctx);
1787
1788 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1789 level, layer);
1790}
1791
1792
1793void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001794_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1795 GLenum renderbufferTarget,
1796 GLuint renderbuffer)
1797{
Brian Paul2c6f9112005-02-24 05:47:06 +00001798 struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001799 struct gl_framebuffer *fb;
Brian Paule4b23562005-05-04 20:11:35 +00001800 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001801 GET_CURRENT_CONTEXT(ctx);
1802
1803 ASSERT_OUTSIDE_BEGIN_END(ctx);
1804
Brian Paul0bffb112005-11-08 14:45:48 +00001805 switch (target) {
1806#if FEATURE_EXT_framebuffer_blit
1807 case GL_DRAW_FRAMEBUFFER_EXT:
1808 if (!ctx->Extensions.EXT_framebuffer_blit) {
1809 _mesa_error(ctx, GL_INVALID_ENUM,
1810 "glFramebufferRenderbufferEXT(target)");
1811 return;
1812 }
1813 fb = ctx->DrawBuffer;
1814 break;
1815 case GL_READ_FRAMEBUFFER_EXT:
1816 if (!ctx->Extensions.EXT_framebuffer_blit) {
1817 _mesa_error(ctx, GL_INVALID_ENUM,
1818 "glFramebufferRenderbufferEXT(target)");
1819 return;
1820 }
1821 fb = ctx->ReadBuffer;
1822 break;
1823#endif
1824 case GL_FRAMEBUFFER_EXT:
1825 fb = ctx->DrawBuffer;
1826 break;
1827 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001828 _mesa_error(ctx, GL_INVALID_ENUM,
1829 "glFramebufferRenderbufferEXT(target)");
1830 return;
1831 }
1832
Brian Paul3deaa012005-02-07 05:08:24 +00001833 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
Brian Paule4b23562005-05-04 20:11:35 +00001834 _mesa_error(ctx, GL_INVALID_ENUM,
1835 "glFramebufferRenderbufferEXT(renderbufferTarget)");
Brian Paul3deaa012005-02-07 05:08:24 +00001836 return;
1837 }
1838
Brian Paul0bffb112005-11-08 14:45:48 +00001839 if (fb->Name == 0) {
Brian Paulab8ef282005-09-07 23:21:59 +00001840 /* Can't attach new renderbuffers to a window system framebuffer */
Brian Paul3deaa012005-02-07 05:08:24 +00001841 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1842 return;
1843 }
1844
Brian Paul84716042005-11-16 04:05:54 +00001845 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001846 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001847 _mesa_error(ctx, GL_INVALID_ENUM,
Brian Paul9b50cea2009-10-23 11:34:14 -06001848 "glFramebufferRenderbufferEXT(invalid attachment %s)",
1849 _mesa_lookup_enum_by_nr(attachment));
Brian Paulddc82ee2005-02-05 19:56:45 +00001850 return;
1851 }
1852
Brian Paul1864c7d2005-02-08 03:46:37 +00001853 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00001854 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001855 if (!rb) {
Brian Paule4b23562005-05-04 20:11:35 +00001856 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul9b50cea2009-10-23 11:34:14 -06001857 "glFramebufferRenderbufferEXT(non-existant"
1858 " renderbuffer %u)", renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001859 return;
1860 }
Brian Paul1864c7d2005-02-08 03:46:37 +00001861 }
1862 else {
Brian Paule4b23562005-05-04 20:11:35 +00001863 /* remove renderbuffer attachment */
1864 rb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001865 }
Brian Paule4b23562005-05-04 20:11:35 +00001866
Brian Paula504f232010-05-27 13:05:23 -06001867 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
1868 rb && rb->Format != MESA_FORMAT_NONE) {
Brian Paul30590072009-01-21 11:06:11 -07001869 /* make sure the renderbuffer is a depth/stencil format */
Brian Paula504f232010-05-27 13:05:23 -06001870 const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
Brian Paul45e76d22009-10-08 20:27:27 -06001871 if (baseFormat != GL_DEPTH_STENCIL) {
Brian Paul30590072009-01-21 11:06:11 -07001872 _mesa_error(ctx, GL_INVALID_OPERATION,
1873 "glFramebufferRenderbufferEXT(renderbuffer"
1874 " is not DEPTH_STENCIL format)");
1875 return;
1876 }
1877 }
1878
1879
Brian Paul800e5532009-11-02 15:39:39 -07001880 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paul474f28e2005-10-08 14:41:17 +00001881
Brian Paule4b23562005-05-04 20:11:35 +00001882 assert(ctx->Driver.FramebufferRenderbuffer);
Brian Paul84716042005-11-16 04:05:54 +00001883 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
Brian Paul2e019182006-03-07 01:43:52 +00001884
1885 /* Some subsequent GL commands may depend on the framebuffer's visual
1886 * after the binding is updated. Update visual info now.
1887 */
1888 _mesa_update_framebuffer_visual(fb);
Brian Paulddc82ee2005-02-05 19:56:45 +00001889}
1890
1891
Brian Paul1864c7d2005-02-08 03:46:37 +00001892void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001893_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1894 GLenum pname, GLint *params)
1895{
Brian Paul2c6f9112005-02-24 05:47:06 +00001896 const struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001897 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001898 GET_CURRENT_CONTEXT(ctx);
1899
1900 ASSERT_OUTSIDE_BEGIN_END(ctx);
1901
Brian Paul0bffb112005-11-08 14:45:48 +00001902 switch (target) {
1903#if FEATURE_EXT_framebuffer_blit
1904 case GL_DRAW_FRAMEBUFFER_EXT:
1905 if (!ctx->Extensions.EXT_framebuffer_blit) {
1906 _mesa_error(ctx, GL_INVALID_ENUM,
1907 "glGetFramebufferAttachmentParameterivEXT(target)");
1908 return;
1909 }
1910 buffer = ctx->DrawBuffer;
1911 break;
1912 case GL_READ_FRAMEBUFFER_EXT:
1913 if (!ctx->Extensions.EXT_framebuffer_blit) {
1914 _mesa_error(ctx, GL_INVALID_ENUM,
1915 "glGetFramebufferAttachmentParameterivEXT(target)");
1916 return;
1917 }
1918 buffer = ctx->ReadBuffer;
1919 break;
1920#endif
1921 case GL_FRAMEBUFFER_EXT:
1922 buffer = ctx->DrawBuffer;
1923 break;
1924 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001925 _mesa_error(ctx, GL_INVALID_ENUM,
1926 "glGetFramebufferAttachmentParameterivEXT(target)");
1927 return;
1928 }
1929
Brian Paul61ec2052010-06-22 08:37:44 -06001930 if (buffer->Name == 0) {
1931 /* the default / window-system FBO */
1932 att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
1933 }
1934 else {
1935 /* user-created framebuffer FBO */
1936 att = _mesa_get_attachment(ctx, buffer, attachment);
1937 }
1938
Brian Paul3deaa012005-02-07 05:08:24 +00001939 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001940 _mesa_error(ctx, GL_INVALID_ENUM,
1941 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1942 return;
1943 }
1944
Brian Paul30590072009-01-21 11:06:11 -07001945 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
1946 /* the depth and stencil attachments must point to the same buffer */
1947 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
1948 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
1949 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
1950 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
1951 _mesa_error(ctx, GL_INVALID_OPERATION,
1952 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
1953 " attachments differ)");
1954 return;
1955 }
1956 }
1957
Brian Paul800e5532009-11-02 15:39:39 -07001958 /* No need to flush here */
Brian Paul474f28e2005-10-08 14:41:17 +00001959
Brian Paulddc82ee2005-02-05 19:56:45 +00001960 switch (pname) {
1961 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001962 *params = att->Type;
1963 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001964 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001965 if (att->Type == GL_RENDERBUFFER_EXT) {
1966 *params = att->Renderbuffer->Name;
1967 }
1968 else if (att->Type == GL_TEXTURE) {
1969 *params = att->Texture->Name;
1970 }
1971 else {
1972 _mesa_error(ctx, GL_INVALID_ENUM,
1973 "glGetFramebufferAttachmentParameterivEXT(pname)");
1974 }
1975 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001976 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001977 if (att->Type == GL_TEXTURE) {
1978 *params = att->TextureLevel;
1979 }
1980 else {
1981 _mesa_error(ctx, GL_INVALID_ENUM,
1982 "glGetFramebufferAttachmentParameterivEXT(pname)");
1983 }
1984 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001985 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001986 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06001987 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
1988 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1989 }
1990 else {
1991 *params = 0;
1992 }
Brian Paul3deaa012005-02-07 05:08:24 +00001993 }
1994 else {
1995 _mesa_error(ctx, GL_INVALID_ENUM,
1996 "glGetFramebufferAttachmentParameterivEXT(pname)");
1997 }
1998 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001999 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00002000 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06002001 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2002 *params = att->Zoffset;
2003 }
2004 else {
2005 *params = 0;
2006 }
Brian Paul3deaa012005-02-07 05:08:24 +00002007 }
2008 else {
2009 _mesa_error(ctx, GL_INVALID_ENUM,
2010 "glGetFramebufferAttachmentParameterivEXT(pname)");
2011 }
2012 return;
Brian Paul1bc59bf2009-01-22 15:07:34 -07002013 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2014 if (!ctx->Extensions.ARB_framebuffer_object) {
2015 _mesa_error(ctx, GL_INVALID_ENUM,
2016 "glGetFramebufferAttachmentParameterivEXT(pname)");
2017 }
2018 else {
Brian Paul45e76d22009-10-08 20:27:27 -06002019 *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
Brian Paul1bc59bf2009-01-22 15:07:34 -07002020 }
2021 return;
2022 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2023 if (!ctx->Extensions.ARB_framebuffer_object) {
2024 _mesa_error(ctx, GL_INVALID_ENUM,
2025 "glGetFramebufferAttachmentParameterivEXT(pname)");
2026 return;
2027 }
2028 else {
Brian Paul45e76d22009-10-08 20:27:27 -06002029 gl_format format = att->Renderbuffer->Format;
2030 if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
2031 /* special cases */
2032 *params = GL_INDEX;
2033 }
2034 else {
2035 *params = _mesa_get_format_datatype(format);
2036 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002037 }
2038 return;
2039 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002040 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002041 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002042 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002043 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
Brian Paul1bc59bf2009-01-22 15:07:34 -07002044 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2045 if (!ctx->Extensions.ARB_framebuffer_object) {
2046 _mesa_error(ctx, GL_INVALID_ENUM,
2047 "glGetFramebufferAttachmentParameterivEXT(pname)");
2048 }
Brian Paul45e76d22009-10-08 20:27:27 -06002049 else if (att->Texture) {
2050 const struct gl_texture_image *texImage =
2051 _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
2052 att->TextureLevel);
2053 if (texImage) {
2054 *params = get_component_bits(pname, texImage->_BaseFormat,
2055 texImage->TexFormat);
2056 }
2057 else {
2058 *params = 0;
2059 }
2060 }
2061 else if (att->Renderbuffer) {
2062 *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
2063 att->Renderbuffer->Format);
2064 }
Brian Paul1bc59bf2009-01-22 15:07:34 -07002065 else {
Brian Paul45e76d22009-10-08 20:27:27 -06002066 *params = 0;
Brian Paul1bc59bf2009-01-22 15:07:34 -07002067 }
2068 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00002069 default:
2070 _mesa_error(ctx, GL_INVALID_ENUM,
2071 "glGetFramebufferAttachmentParameterivEXT(pname)");
2072 return;
2073 }
Brian Paulddc82ee2005-02-05 19:56:45 +00002074}
2075
2076
Brian Paul1864c7d2005-02-08 03:46:37 +00002077void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00002078_mesa_GenerateMipmapEXT(GLenum target)
2079{
Brian Paul463642c2005-02-08 02:06:00 +00002080 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00002081 GET_CURRENT_CONTEXT(ctx);
2082
2083 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00002084 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00002085
2086 switch (target) {
2087 case GL_TEXTURE_1D:
2088 case GL_TEXTURE_2D:
Brian Paulddc82ee2005-02-05 19:56:45 +00002089 case GL_TEXTURE_3D:
Brian Paul463642c2005-02-08 02:06:00 +00002090 case GL_TEXTURE_CUBE_MAP:
Brian Paul1b939532005-05-31 23:55:21 +00002091 /* OK, legal value */
Brian Paulddc82ee2005-02-05 19:56:45 +00002092 break;
2093 default:
2094 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
2095 return;
2096 }
2097
Brian Paula7193952009-11-16 08:21:28 -07002098 texObj = _mesa_get_current_tex_object(ctx, target);
Brian Paul463642c2005-02-08 02:06:00 +00002099
Brian Paul652828e2009-11-16 08:25:17 -07002100 if (texObj->BaseLevel >= texObj->MaxLevel) {
2101 /* nothing to do */
2102 return;
2103 }
2104
Keith Whitwell5ac93f82006-11-01 14:21:57 +00002105 _mesa_lock_texture(ctx, texObj);
Eric Anholtf849d362008-12-06 21:14:56 -08002106 if (target == GL_TEXTURE_CUBE_MAP) {
Brian Paulef6ee072009-09-15 18:09:03 -06002107 GLuint face;
Eric Anholtf849d362008-12-06 21:14:56 -08002108 for (face = 0; face < 6; face++)
2109 ctx->Driver.GenerateMipmap(ctx,
2110 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2111 texObj);
Brian Paulef6ee072009-09-15 18:09:03 -06002112 }
2113 else {
Eric Anholtf849d362008-12-06 21:14:56 -08002114 ctx->Driver.GenerateMipmap(ctx, target, texObj);
2115 }
Keith Whitwell5ac93f82006-11-01 14:21:57 +00002116 _mesa_unlock_texture(ctx, texObj);
Brian Paulddc82ee2005-02-05 19:56:45 +00002117}
Brian Paul0bffb112005-11-08 14:45:48 +00002118
2119
2120#if FEATURE_EXT_framebuffer_blit
Brian Paul21f8d312009-10-27 16:59:23 -06002121
2122static const struct gl_renderbuffer_attachment *
2123find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb)
2124{
2125 GLuint i;
2126 for (i = 0; i < Elements(fb->Attachment); i++) {
2127 if (fb->Attachment[i].Renderbuffer == rb)
2128 return &fb->Attachment[i];
2129 }
2130 return NULL;
2131}
2132
2133
2134
Brian Paul722d9762009-01-20 16:58:49 -07002135/**
2136 * Blit rectangular region, optionally from one framebuffer to another.
2137 *
2138 * Note, if the src buffer is multisampled and the dest is not, this is
2139 * when the samples must be resolved to a single color.
2140 */
Brian Paul0bffb112005-11-08 14:45:48 +00002141void GLAPIENTRY
2142_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
2143 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
2144 GLbitfield mask, GLenum filter)
2145{
Brian Paul722d9762009-01-20 16:58:49 -07002146 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
2147 GL_DEPTH_BUFFER_BIT |
2148 GL_STENCIL_BUFFER_BIT);
2149 const struct gl_framebuffer *readFb, *drawFb;
2150 const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
Brian Paul0bffb112005-11-08 14:45:48 +00002151 GET_CURRENT_CONTEXT(ctx);
2152
2153 ASSERT_OUTSIDE_BEGIN_END(ctx);
2154 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2155
Brian Paul99745402006-03-01 02:02:43 +00002156 if (ctx->NewState) {
2157 _mesa_update_state(ctx);
2158 }
2159
Brian Paul722d9762009-01-20 16:58:49 -07002160 readFb = ctx->ReadBuffer;
2161 drawFb = ctx->DrawBuffer;
2162
2163 if (!readFb || !drawFb) {
2164 /* This will normally never happen but someday we may want to
2165 * support MakeCurrent() with no drawables.
2166 */
2167 return;
Brian Paul99745402006-03-01 02:02:43 +00002168 }
2169
Brian Paul0bffb112005-11-08 14:45:48 +00002170 /* check for complete framebuffers */
Brian Paul722d9762009-01-20 16:58:49 -07002171 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
2172 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
Brian Paul0bffb112005-11-08 14:45:48 +00002173 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
2174 "glBlitFramebufferEXT(incomplete draw/read buffers)");
2175 return;
2176 }
2177
Brian Paul99745402006-03-01 02:02:43 +00002178 if (filter != GL_NEAREST && filter != GL_LINEAR) {
2179 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
2180 return;
2181 }
2182
Brian Paul722d9762009-01-20 16:58:49 -07002183 if (mask & ~legalMaskBits) {
Brian Paul99745402006-03-01 02:02:43 +00002184 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
2185 return;
2186 }
2187
Brian Paul0bffb112005-11-08 14:45:48 +00002188 /* depth/stencil must be blitted with nearest filtering */
2189 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
2190 && filter != GL_NEAREST) {
2191 _mesa_error(ctx, GL_INVALID_OPERATION,
2192 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
2193 return;
2194 }
2195
Brian Paul722d9762009-01-20 16:58:49 -07002196 /* get color read/draw renderbuffers */
2197 if (mask & GL_COLOR_BUFFER_BIT) {
2198 colorReadRb = readFb->_ColorReadBuffer;
2199 colorDrawRb = drawFb->_ColorDrawBuffers[0];
2200 }
2201 else {
2202 colorReadRb = colorDrawRb = NULL;
2203 }
2204
Brian Paul99745402006-03-01 02:02:43 +00002205 if (mask & GL_STENCIL_BUFFER_BIT) {
Brian Paul722d9762009-01-20 16:58:49 -07002206 struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
2207 struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
Brian Pauldcebe222009-08-05 13:44:59 -06002208 if (!readRb ||
2209 !drawRb ||
Brian Paul45e76d22009-10-08 20:27:27 -06002210 _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
2211 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
Brian Paul99745402006-03-01 02:02:43 +00002212 _mesa_error(ctx, GL_INVALID_OPERATION,
2213 "glBlitFramebufferEXT(stencil buffer size mismatch");
2214 return;
2215 }
2216 }
2217
2218 if (mask & GL_DEPTH_BUFFER_BIT) {
Brian Paul722d9762009-01-20 16:58:49 -07002219 struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
2220 struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
Brian Pauldcebe222009-08-05 13:44:59 -06002221 if (!readRb ||
2222 !drawRb ||
Brian Paul45e76d22009-10-08 20:27:27 -06002223 _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
2224 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
Brian Paul99745402006-03-01 02:02:43 +00002225 _mesa_error(ctx, GL_INVALID_OPERATION,
2226 "glBlitFramebufferEXT(depth buffer size mismatch");
2227 return;
2228 }
Brian Paul0bffb112005-11-08 14:45:48 +00002229 }
2230
Brian Paul722d9762009-01-20 16:58:49 -07002231 if (readFb->Visual.samples > 0 &&
2232 drawFb->Visual.samples > 0 &&
2233 readFb->Visual.samples != drawFb->Visual.samples) {
2234 _mesa_error(ctx, GL_INVALID_OPERATION,
2235 "glBlitFramebufferEXT(mismatched samples");
2236 return;
2237 }
2238
2239 /* extra checks for multisample copies... */
2240 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
2241 /* src and dest region sizes must be the same */
2242 if (srcX1 - srcX0 != dstX1 - dstX0 ||
2243 srcY1 - srcY0 != dstY1 - dstY0) {
2244 _mesa_error(ctx, GL_INVALID_OPERATION,
2245 "glBlitFramebufferEXT(bad src/dst multisample region sizes");
2246 return;
2247 }
2248
2249 /* color formats must match */
2250 if (colorReadRb &&
2251 colorDrawRb &&
Brian Paul45e76d22009-10-08 20:27:27 -06002252 colorReadRb->Format != colorDrawRb->Format) {
Brian Paul722d9762009-01-20 16:58:49 -07002253 _mesa_error(ctx, GL_INVALID_OPERATION,
2254 "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
2255 return;
2256 }
2257 }
2258
Brian Paul0bffb112005-11-08 14:45:48 +00002259 if (!ctx->Extensions.EXT_framebuffer_blit) {
2260 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
2261 return;
2262 }
2263
Brian Paul21f8d312009-10-27 16:59:23 -06002264 /* Debug code */
2265 if (DEBUG_BLIT) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002266 printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
2267 " 0x%x, 0x%x)\n",
2268 srcX0, srcY0, srcX1, srcY1,
2269 dstX0, dstY0, dstX1, dstY1,
2270 mask, filter);
Brian Paul21f8d312009-10-27 16:59:23 -06002271 if (colorReadRb) {
2272 const struct gl_renderbuffer_attachment *att;
2273
2274 att = find_attachment(readFb, colorReadRb);
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002275 printf(" Src FBO %u RB %u (%dx%d) ",
2276 readFb->Name, colorReadRb->Name,
2277 colorReadRb->Width, colorReadRb->Height);
Brian Paul21f8d312009-10-27 16:59:23 -06002278 if (att && att->Texture) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002279 printf("Tex %u tgt 0x%x level %u face %u",
2280 att->Texture->Name,
2281 att->Texture->Target,
2282 att->TextureLevel,
2283 att->CubeMapFace);
Brian Paul21f8d312009-10-27 16:59:23 -06002284 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002285 printf("\n");
Brian Paul21f8d312009-10-27 16:59:23 -06002286
2287 att = find_attachment(drawFb, colorDrawRb);
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002288 printf(" Dst FBO %u RB %u (%dx%d) ",
2289 drawFb->Name, colorDrawRb->Name,
2290 colorDrawRb->Width, colorDrawRb->Height);
Brian Paul21f8d312009-10-27 16:59:23 -06002291 if (att && att->Texture) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002292 printf("Tex %u tgt 0x%x level %u face %u",
2293 att->Texture->Name,
2294 att->Texture->Target,
2295 att->TextureLevel,
2296 att->CubeMapFace);
Brian Paul21f8d312009-10-27 16:59:23 -06002297 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002298 printf("\n");
Brian Paul21f8d312009-10-27 16:59:23 -06002299 }
2300 }
2301
Brian Paul0bffb112005-11-08 14:45:48 +00002302 ASSERT(ctx->Driver.BlitFramebuffer);
2303 ctx->Driver.BlitFramebuffer(ctx,
2304 srcX0, srcY0, srcX1, srcY1,
2305 dstX0, dstY0, dstX1, dstY1,
2306 mask, filter);
2307}
2308#endif /* FEATURE_EXT_framebuffer_blit */
Zack Rusinda7bd6a2010-06-28 17:31:21 -04002309
2310#if FEATURE_ARB_geometry_shader4
2311void GLAPIENTRY
2312_mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
2313 GLuint texture, GLint level)
2314{
2315 GET_CURRENT_CONTEXT(ctx);
2316 _mesa_error(ctx, GL_INVALID_OPERATION,
2317 "glFramebufferTextureARB "
2318 "not implemented!");
2319}
2320
2321void GLAPIENTRY
2322_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
2323 GLuint texture, GLint level, GLenum face)
2324{
2325 GET_CURRENT_CONTEXT(ctx);
2326 _mesa_error(ctx, GL_INVALID_OPERATION,
2327 "glFramebufferTextureFaceARB "
2328 "not implemented!");
2329}
2330#endif /* FEATURE_ARB_geometry_shader4 */