blob: fcb620b39d809a81eea0ed199239e9a47b09489c [file] [log] [blame]
Brian Paulddc82ee2005-02-05 19:56:45 +00001/*
2 * Mesa 3-D graphics library
Brian Paulf08f2332006-04-05 19:58:10 +00003 * Version: 6.5.1
Brian Paulddc82ee2005-02-05 19:56:45 +00004 *
Brian Paul2e019182006-03-07 01:43:52 +00005 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
Brian Paulddc82ee2005-02-05 19:56:45 +00006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
Brian Paul463642c2005-02-08 02:06:00 +000026/*
27 * Authors:
28 * Brian Paul
29 */
30
31
Roland Scheideggera1bc0d02007-07-18 20:17:14 +020032#include "buffers.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000033#include "context.h"
34#include "fbobject.h"
Brian Paule4b23562005-05-04 20:11:35 +000035#include "framebuffer.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000036#include "hash.h"
Brian Paul24edd902006-09-29 01:24:26 +000037#include "mipmap.h"
Brian Paule4b23562005-05-04 20:11:35 +000038#include "renderbuffer.h"
Brian Paul99745402006-03-01 02:02:43 +000039#include "state.h"
Brian Paul463642c2005-02-08 02:06:00 +000040#include "teximage.h"
Brian Paulea4fe662006-03-26 05:22:17 +000041#include "texobj.h"
Brian Paul463642c2005-02-08 02:06:00 +000042#include "texstore.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000043
44
Brian Pauld9468c92005-02-10 16:08:07 +000045/**
46 * Notes:
47 *
48 * None of the GL_EXT_framebuffer_object functions are compiled into
49 * display lists.
50 */
51
52
53
Brian Paul923b6fc2005-02-08 04:08:56 +000054/*
55 * When glGenRender/FramebuffersEXT() is called we insert pointers to
56 * these placeholder objects into the hash table.
57 * Later, when the object ID is first bound, we replace the placeholder
58 * with the real frame/renderbuffer.
59 */
Brian Paul2c6f9112005-02-24 05:47:06 +000060static struct gl_framebuffer DummyFramebuffer;
61static struct gl_renderbuffer DummyRenderbuffer;
Brian Paul1864c7d2005-02-08 03:46:37 +000062
63
Brian Paul3deaa012005-02-07 05:08:24 +000064#define IS_CUBE_FACE(TARGET) \
65 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
66 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
Brian Paulddc82ee2005-02-05 19:56:45 +000067
68
69/**
Brian Paul2c6f9112005-02-24 05:47:06 +000070 * Helper routine for getting a gl_renderbuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +000071 */
Brian Paulea4fe662006-03-26 05:22:17 +000072struct gl_renderbuffer *
73_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +000074{
Brian Paul2c6f9112005-02-24 05:47:06 +000075 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +000076
Brian Paul1864c7d2005-02-08 03:46:37 +000077 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +000078 return NULL;
79
Brian Paul2c6f9112005-02-24 05:47:06 +000080 rb = (struct gl_renderbuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +000081 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
82 return rb;
83}
84
85
86/**
Brian Paul2c6f9112005-02-24 05:47:06 +000087 * Helper routine for getting a gl_framebuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +000088 */
Brian Paulea4fe662006-03-26 05:22:17 +000089struct gl_framebuffer *
90_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +000091{
Brian Paul2c6f9112005-02-24 05:47:06 +000092 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +000093
Brian Paul1864c7d2005-02-08 03:46:37 +000094 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +000095 return NULL;
96
Brian Paul2c6f9112005-02-24 05:47:06 +000097 fb = (struct gl_framebuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +000098 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
Brian Paul463642c2005-02-08 02:06:00 +000099 return fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000100}
101
102
103/**
Brian Pauld9468c92005-02-10 16:08:07 +0000104 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
Brian Paul2c6f9112005-02-24 05:47:06 +0000105 * gl_renderbuffer_attachment object.
Brian Pauld9468c92005-02-10 16:08:07 +0000106 */
Brian Paul84716042005-11-16 04:05:54 +0000107struct gl_renderbuffer_attachment *
108_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
109 GLenum attachment)
Brian Paul3deaa012005-02-07 05:08:24 +0000110{
111 GLuint i;
112
113 switch (attachment) {
114 case GL_COLOR_ATTACHMENT0_EXT:
115 case GL_COLOR_ATTACHMENT1_EXT:
116 case GL_COLOR_ATTACHMENT2_EXT:
117 case GL_COLOR_ATTACHMENT3_EXT:
118 case GL_COLOR_ATTACHMENT4_EXT:
119 case GL_COLOR_ATTACHMENT5_EXT:
120 case GL_COLOR_ATTACHMENT6_EXT:
121 case GL_COLOR_ATTACHMENT7_EXT:
122 case GL_COLOR_ATTACHMENT8_EXT:
123 case GL_COLOR_ATTACHMENT9_EXT:
124 case GL_COLOR_ATTACHMENT10_EXT:
125 case GL_COLOR_ATTACHMENT11_EXT:
126 case GL_COLOR_ATTACHMENT12_EXT:
127 case GL_COLOR_ATTACHMENT13_EXT:
128 case GL_COLOR_ATTACHMENT14_EXT:
129 case GL_COLOR_ATTACHMENT15_EXT:
130 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
131 if (i >= ctx->Const.MaxColorAttachments) {
132 return NULL;
133 }
Brian Paule4b23562005-05-04 20:11:35 +0000134 return &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paul3deaa012005-02-07 05:08:24 +0000135 case GL_DEPTH_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000136 return &fb->Attachment[BUFFER_DEPTH];
Brian Paul3deaa012005-02-07 05:08:24 +0000137 case GL_STENCIL_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000138 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul3deaa012005-02-07 05:08:24 +0000139 default:
140 return NULL;
141 }
142}
143
144
Brian Pauld9468c92005-02-10 16:08:07 +0000145/**
146 * Remove any texture or renderbuffer attached to the given attachment
147 * point. Update reference counts, etc.
148 */
Brian Paule4b23562005-05-04 20:11:35 +0000149void
150_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
Brian Paul3deaa012005-02-07 05:08:24 +0000151{
152 if (att->Type == GL_TEXTURE) {
153 ASSERT(att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100154 if (ctx->Driver.FinishRenderTexture) {
155 /* tell driver we're done rendering to this texobj */
156 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000157 }
Brian9e01b912007-08-13 11:29:46 +0100158 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
159 ASSERT(!att->Texture);
Brian Paul3deaa012005-02-07 05:08:24 +0000160 }
Brian Paul0e31e022005-12-01 00:25:00 +0000161 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul3deaa012005-02-07 05:08:24 +0000162 ASSERT(att->Renderbuffer);
163 ASSERT(!att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100164 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
165 ASSERT(!att->Renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000166 }
167 att->Type = GL_NONE;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000168 att->Complete = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +0000169}
170
171
Brian Pauld9468c92005-02-10 16:08:07 +0000172/**
173 * Bind a texture object to an attachment point.
174 * The previous binding, if any, will be removed first.
175 */
Brian Paule4b23562005-05-04 20:11:35 +0000176void
177_mesa_set_texture_attachment(GLcontext *ctx,
Brian Paul519b23b2006-03-20 18:51:57 +0000178 struct gl_framebuffer *fb,
Brian Paule4b23562005-05-04 20:11:35 +0000179 struct gl_renderbuffer_attachment *att,
180 struct gl_texture_object *texObj,
181 GLenum texTarget, GLuint level, GLuint zoffset)
Brian Paul3deaa012005-02-07 05:08:24 +0000182{
Brian Paul0e31e022005-12-01 00:25:00 +0000183 if (att->Texture == texObj) {
184 /* re-attaching same texture */
185 ASSERT(att->Type == GL_TEXTURE);
186 }
187 else {
188 /* new attachment */
189 _mesa_remove_attachment(ctx, att);
190 att->Type = GL_TEXTURE;
Brian9e01b912007-08-13 11:29:46 +0100191 assert(!att->Texture);
192 _mesa_reference_texobj(&att->Texture, texObj);
Brian Paul0e31e022005-12-01 00:25:00 +0000193 }
194
195 /* always update these fields */
Brian Paul3deaa012005-02-07 05:08:24 +0000196 att->TextureLevel = level;
197 if (IS_CUBE_FACE(texTarget)) {
198 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
199 }
200 else {
201 att->CubeMapFace = 0;
202 }
203 att->Zoffset = zoffset;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000204 att->Complete = GL_FALSE;
Brian Paul519b23b2006-03-20 18:51:57 +0000205
206 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +0000207 ctx->Driver.RenderTexture(ctx, fb, att);
Brian Paul519b23b2006-03-20 18:51:57 +0000208 }
Brian Paul3deaa012005-02-07 05:08:24 +0000209}
210
211
Brian Pauld9468c92005-02-10 16:08:07 +0000212/**
213 * Bind a renderbuffer to an attachment point.
214 * The previous binding, if any, will be removed first.
215 */
Brian Paule4b23562005-05-04 20:11:35 +0000216void
217_mesa_set_renderbuffer_attachment(GLcontext *ctx,
218 struct gl_renderbuffer_attachment *att,
219 struct gl_renderbuffer *rb)
Brian Paul3deaa012005-02-07 05:08:24 +0000220{
Brian Paulea4fe662006-03-26 05:22:17 +0000221 /* XXX check if re-doing same attachment, exit early */
Brian Paule4b23562005-05-04 20:11:35 +0000222 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000223 att->Type = GL_RENDERBUFFER_EXT;
Brian Paul2c6f9112005-02-24 05:47:06 +0000224 att->Texture = NULL; /* just to be safe */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000225 att->Complete = GL_FALSE;
Briandccd9c42007-04-02 09:56:28 -0600226 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
Brian Paul3deaa012005-02-07 05:08:24 +0000227}
228
Brian Paulddc82ee2005-02-05 19:56:45 +0000229
Brian Paulf0bbbf62005-02-09 03:50:30 +0000230/**
Brian Paule4b23562005-05-04 20:11:35 +0000231 * Fallback for ctx->Driver.FramebufferRenderbuffer()
Brian Paul84716042005-11-16 04:05:54 +0000232 * Attach a renderbuffer object to a framebuffer object.
Brian Paule4b23562005-05-04 20:11:35 +0000233 */
234void
Brian Paul84716042005-11-16 04:05:54 +0000235_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
236 GLenum attachment, struct gl_renderbuffer *rb)
Brian Paule4b23562005-05-04 20:11:35 +0000237{
Brian Paul84716042005-11-16 04:05:54 +0000238 struct gl_renderbuffer_attachment *att;
239
Brian Paulea4fe662006-03-26 05:22:17 +0000240 _glthread_LOCK_MUTEX(fb->Mutex);
Brian Paulea4fe662006-03-26 05:22:17 +0000241
Brian Paul84716042005-11-16 04:05:54 +0000242 att = _mesa_get_attachment(ctx, fb, attachment);
243 ASSERT(att);
Brian Paule4b23562005-05-04 20:11:35 +0000244 if (rb) {
245 _mesa_set_renderbuffer_attachment(ctx, att, rb);
246 }
247 else {
248 _mesa_remove_attachment(ctx, att);
249 }
Brian Paulea4fe662006-03-26 05:22:17 +0000250
Brian Paulea4fe662006-03-26 05:22:17 +0000251 _glthread_UNLOCK_MUTEX(fb->Mutex);
Brian Paule4b23562005-05-04 20:11:35 +0000252}
253
254
255/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000256 * Test if an attachment point is complete and update its Complete field.
257 * \param format if GL_COLOR, this is a color attachment point,
258 * if GL_DEPTH, this is a depth component attachment point,
259 * if GL_STENCIL, this is a stencil component attachment point.
260 */
261static void
262test_attachment_completeness(const GLcontext *ctx, GLenum format,
Brian Paul2c6f9112005-02-24 05:47:06 +0000263 struct gl_renderbuffer_attachment *att)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000264{
265 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
266
267 /* assume complete */
268 att->Complete = GL_TRUE;
269
Brian Paulf0bbbf62005-02-09 03:50:30 +0000270 /* Look for reasons why the attachment might be incomplete */
271 if (att->Type == GL_TEXTURE) {
Brian Paule4b23562005-05-04 20:11:35 +0000272 const struct gl_texture_object *texObj = att->Texture;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000273 struct gl_texture_image *texImage;
274
Brian Paule4b23562005-05-04 20:11:35 +0000275 if (!texObj) {
276 att->Complete = GL_FALSE;
277 return;
278 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000279
280 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
281 if (!texImage) {
282 att->Complete = GL_FALSE;
283 return;
284 }
285 if (texImage->Width < 1 || texImage->Height < 1) {
286 att->Complete = GL_FALSE;
287 return;
288 }
289 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
290 att->Complete = GL_FALSE;
291 return;
292 }
293
294 if (format == GL_COLOR) {
Brian Paule4b23562005-05-04 20:11:35 +0000295 if (texImage->TexFormat->BaseFormat != GL_RGB &&
296 texImage->TexFormat->BaseFormat != GL_RGBA) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000297 att->Complete = GL_FALSE;
298 return;
299 }
300 }
301 else if (format == GL_DEPTH) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000302 if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) {
303 /* OK */
304 }
305 else if (ctx->Extensions.EXT_packed_depth_stencil &&
306 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
307 /* OK */
308 }
309 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000310 att->Complete = GL_FALSE;
311 return;
312 }
313 }
314 else {
315 /* no such thing as stencil textures */
316 att->Complete = GL_FALSE;
317 return;
318 }
319 }
Brian Paule4b23562005-05-04 20:11:35 +0000320 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul49918882006-03-20 15:27:55 +0000321 ASSERT(att->Renderbuffer);
322 if (!att->Renderbuffer->InternalFormat ||
323 att->Renderbuffer->Width < 1 ||
324 att->Renderbuffer->Height < 1) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000325 att->Complete = GL_FALSE;
326 return;
327 }
328 if (format == GL_COLOR) {
329 if (att->Renderbuffer->_BaseFormat != GL_RGB &&
330 att->Renderbuffer->_BaseFormat != GL_RGBA) {
Brian Paul49918882006-03-20 15:27:55 +0000331 ASSERT(att->Renderbuffer->RedBits);
332 ASSERT(att->Renderbuffer->GreenBits);
333 ASSERT(att->Renderbuffer->BlueBits);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000334 att->Complete = GL_FALSE;
335 return;
336 }
337 }
338 else if (format == GL_DEPTH) {
Brian Paul49918882006-03-20 15:27:55 +0000339 ASSERT(att->Renderbuffer->DepthBits);
Brian Paul1ad7b992005-09-28 02:29:50 +0000340 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) {
341 /* OK */
342 }
343 else if (ctx->Extensions.EXT_packed_depth_stencil &&
344 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
345 /* OK */
346 }
347 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000348 att->Complete = GL_FALSE;
349 return;
350 }
351 }
352 else {
353 assert(format == GL_STENCIL);
Brian Paul49918882006-03-20 15:27:55 +0000354 ASSERT(att->Renderbuffer->StencilBits);
Brian Paul1ad7b992005-09-28 02:29:50 +0000355 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) {
356 /* OK */
357 }
358 else if (ctx->Extensions.EXT_packed_depth_stencil &&
359 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
360 /* OK */
361 }
362 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000363 att->Complete = GL_FALSE;
364 return;
365 }
366 }
367 }
Brian Paule4b23562005-05-04 20:11:35 +0000368 else {
369 ASSERT(att->Type == GL_NONE);
370 /* complete */
371 return;
372 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000373}
374
375
376/**
Brian Paul49918882006-03-20 15:27:55 +0000377 * Helpful for debugging
378 */
379static void
380fbo_incomplete(const char *msg, int index)
381{
Brian Paul13abf912006-04-13 19:17:13 +0000382 (void) msg;
383 (void) index;
Brian Paul49918882006-03-20 15:27:55 +0000384 /*
385 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
386 */
387}
388
389
390/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000391 * Test if the given framebuffer object is complete and update its
392 * Status field with the results.
Brian Paule4b23562005-05-04 20:11:35 +0000393 * Also update the framebuffer's Width and Height fields if the
394 * framebuffer is complete.
Brian Paulf0bbbf62005-02-09 03:50:30 +0000395 */
Brian Paule4b23562005-05-04 20:11:35 +0000396void
397_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000398{
Brian Paul6c0c9172005-02-27 16:23:41 +0000399 GLuint numImages, width = 0, height = 0;
400 GLenum intFormat = GL_NONE;
Brian Paule4b23562005-05-04 20:11:35 +0000401 GLuint w = 0, h = 0;
402 GLint i;
Brian Paul28b014e2006-04-05 03:05:17 +0000403 GLuint j;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000404
Brian Paulc7264412005-06-01 00:50:23 +0000405 assert(fb->Name != 0);
406
Brian Paulf0bbbf62005-02-09 03:50:30 +0000407 numImages = 0;
Brian Paule4b23562005-05-04 20:11:35 +0000408 fb->Width = 0;
409 fb->Height = 0;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000410
411 /* Start at -2 to more easily loop over all attachment points */
Brian Paule4b23562005-05-04 20:11:35 +0000412 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000413 struct gl_renderbuffer_attachment *att;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000414 GLenum f;
415
416 if (i == -2) {
Brian Paule4b23562005-05-04 20:11:35 +0000417 att = &fb->Attachment[BUFFER_DEPTH];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000418 test_attachment_completeness(ctx, GL_DEPTH, att);
419 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000420 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000421 fbo_incomplete("depth attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000422 return;
423 }
424 }
425 else if (i == -1) {
Brian Paule4b23562005-05-04 20:11:35 +0000426 att = &fb->Attachment[BUFFER_STENCIL];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000427 test_attachment_completeness(ctx, GL_STENCIL, att);
428 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000429 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000430 fbo_incomplete("stencil attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000431 return;
432 }
433 }
434 else {
Brian Paule4b23562005-05-04 20:11:35 +0000435 att = &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000436 test_attachment_completeness(ctx, GL_COLOR, att);
437 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000438 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000439 fbo_incomplete("color attachment incomplete", i);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000440 return;
441 }
442 }
443
444 if (att->Type == GL_TEXTURE) {
Brian Paula9fc8ba2005-10-05 01:48:07 +0000445 const struct gl_texture_image *texImg
446 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
447 w = texImg->Width;
448 h = texImg->Height;
449 f = texImg->_BaseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000450 numImages++;
Brian Paul9f6ff492006-03-28 15:24:50 +0000451 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT
452 && f != GL_DEPTH_STENCIL_EXT) {
Brian Pauled7f3ae2005-06-07 15:03:40 +0000453 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000454 fbo_incomplete("texture attachment incomplete", -1);
Brian Pauled7f3ae2005-06-07 15:03:40 +0000455 return;
456 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000457 }
458 else if (att->Type == GL_RENDERBUFFER_EXT) {
459 w = att->Renderbuffer->Width;
460 h = att->Renderbuffer->Height;
461 f = att->Renderbuffer->InternalFormat;
462 numImages++;
463 }
464 else {
465 assert(att->Type == GL_NONE);
466 continue;
467 }
468
469 if (numImages == 1) {
470 /* set required width, height and format */
471 width = w;
472 height = h;
473 if (i >= 0)
474 intFormat = f;
475 }
476 else {
477 /* check that width, height, format are same */
478 if (w != width || h != height) {
Brian Paule4b23562005-05-04 20:11:35 +0000479 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000480 fbo_incomplete("width or height mismatch", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000481 return;
482 }
Brian Paule4b23562005-05-04 20:11:35 +0000483 if (intFormat != GL_NONE && f != intFormat) {
484 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000485 fbo_incomplete("format mismatch", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000486 return;
487 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000488 }
489 }
490
491 /* Check that all DrawBuffers are present */
Brian Paul28b014e2006-04-05 03:05:17 +0000492 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
493 if (fb->ColorDrawBuffer[j] != GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000494 const struct gl_renderbuffer_attachment *att
Brian Paul28b014e2006-04-05 03:05:17 +0000495 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
Brian Paule4b23562005-05-04 20:11:35 +0000496 assert(att);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000497 if (att->Type == GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000498 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
Brian Paul28b014e2006-04-05 03:05:17 +0000499 fbo_incomplete("missing drawbuffer", j);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000500 return;
501 }
502 }
503 }
504
505 /* Check that the ReadBuffer is present */
Brian Paule4b23562005-05-04 20:11:35 +0000506 if (fb->ColorReadBuffer != GL_NONE) {
507 const struct gl_renderbuffer_attachment *att
Brian Paul84716042005-11-16 04:05:54 +0000508 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
Brian Paule4b23562005-05-04 20:11:35 +0000509 assert(att);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000510 if (att->Type == GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000511 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000512 fbo_incomplete("missing readbuffer", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000513 return;
514 }
515 }
516
517 if (numImages == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000518 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000519 fbo_incomplete("no attachments", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000520 return;
521 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000522
Brian Paule4b23562005-05-04 20:11:35 +0000523 /*
524 * If we get here, the framebuffer is complete!
525 */
526 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
527 fb->Width = w;
528 fb->Height = h;
529}
Brian Paulf0bbbf62005-02-09 03:50:30 +0000530
531
Brian Paul1864c7d2005-02-08 03:46:37 +0000532GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000533_mesa_IsRenderbufferEXT(GLuint renderbuffer)
534{
Brian Paulddc82ee2005-02-05 19:56:45 +0000535 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000536 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000537 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000538 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000539 if (rb != NULL && rb != &DummyRenderbuffer)
540 return GL_TRUE;
541 }
542 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000543}
544
545
Brian Paul1864c7d2005-02-08 03:46:37 +0000546void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000547_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
548{
Brian42aaa542007-03-25 10:39:36 -0600549 struct gl_renderbuffer *newRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000550 GET_CURRENT_CONTEXT(ctx);
551
552 ASSERT_OUTSIDE_BEGIN_END(ctx);
553
Brian Paul3deaa012005-02-07 05:08:24 +0000554 if (target != GL_RENDERBUFFER_EXT) {
555 _mesa_error(ctx, GL_INVALID_ENUM,
556 "glBindRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000557 return;
558 }
559
Brian Paul474f28e2005-10-08 14:41:17 +0000560 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +0000561 /* The above doesn't fully flush the drivers in the way that a
562 * glFlush does, but that is required here:
563 */
564 if (ctx->Driver.Flush)
565 ctx->Driver.Flush(ctx);
566
Brian Paul474f28e2005-10-08 14:41:17 +0000567
Brian Paul3deaa012005-02-07 05:08:24 +0000568 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000569 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000570 if (newRb == &DummyRenderbuffer) {
571 /* ID was reserved, but no real renderbuffer object made yet */
572 newRb = NULL;
573 }
Brian Paul3deaa012005-02-07 05:08:24 +0000574 if (!newRb) {
575 /* create new renderbuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000576 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000577 if (!newRb) {
578 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
579 return;
580 }
Brian Paul2c6f9112005-02-24 05:47:06 +0000581 ASSERT(newRb->AllocStorage);
Brian Paul1864c7d2005-02-08 03:46:37 +0000582 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
Brian42aaa542007-03-25 10:39:36 -0600583 newRb->RefCount = 1; /* referenced by hash table */
Brian Paul3deaa012005-02-07 05:08:24 +0000584 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000585 }
Brian Paul463642c2005-02-08 02:06:00 +0000586 else {
587 newRb = NULL;
588 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000589
Brian Paul1864c7d2005-02-08 03:46:37 +0000590 ASSERT(newRb != &DummyRenderbuffer);
591
Brian42aaa542007-03-25 10:39:36 -0600592 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
Brian Paulddc82ee2005-02-05 19:56:45 +0000593}
594
595
Brian Paul1864c7d2005-02-08 03:46:37 +0000596void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000597_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
598{
599 GLint i;
600 GET_CURRENT_CONTEXT(ctx);
601
602 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000603 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000604
605 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000606 if (renderbuffers[i] > 0) {
607 struct gl_renderbuffer *rb;
Brian Paulea4fe662006-03-26 05:22:17 +0000608 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +0000609 if (rb) {
Brian Paul91802fd2005-10-04 16:01:02 +0000610 /* check if deleting currently bound renderbuffer object */
611 if (rb == ctx->CurrentRenderbuffer) {
612 /* bind default */
613 ASSERT(rb->RefCount >= 2);
614 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
615 }
616
Brian42aaa542007-03-25 10:39:36 -0600617 /* Remove from hash table immediately, to free the ID.
618 * But the object will not be freed until it's no longer
619 * referenced anywhere else.
620 */
Brian Paul3deaa012005-02-07 05:08:24 +0000621 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +0000622
Brian Paul1864c7d2005-02-08 03:46:37 +0000623 if (rb != &DummyRenderbuffer) {
Brian42aaa542007-03-25 10:39:36 -0600624 /* no longer referenced by hash table */
625 _mesa_reference_renderbuffer(&rb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +0000626 }
627 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000628 }
629 }
630}
631
632
Brian Paul1864c7d2005-02-08 03:46:37 +0000633void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000634_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
635{
636 GET_CURRENT_CONTEXT(ctx);
637 GLuint first;
638 GLint i;
639
640 ASSERT_OUTSIDE_BEGIN_END(ctx);
641
642 if (n < 0) {
643 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
644 return;
645 }
646
647 if (!renderbuffers)
648 return;
649
650 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
651
652 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000653 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000654 renderbuffers[i] = name;
Brian Paul1864c7d2005-02-08 03:46:37 +0000655 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +0000656 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +0000657 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +0000658 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +0000659 }
660}
661
662
Brian Pauld9468c92005-02-10 16:08:07 +0000663/**
664 * Given an internal format token for a render buffer, return the
665 * corresponding base format.
Brian Paul59e0faa2006-03-15 17:48:00 +0000666 * This is very similar to _mesa_base_tex_format() but the set of valid
667 * internal formats is somewhat different.
668 *
Brian Pauld9468c92005-02-10 16:08:07 +0000669 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
Brian Paul1ad7b992005-09-28 02:29:50 +0000670 * GL_DEPTH_STENCIL_EXT or zero if error.
Brian Pauld9468c92005-02-10 16:08:07 +0000671 */
Brian Paul59e0faa2006-03-15 17:48:00 +0000672GLenum
673_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
Brian Paul463642c2005-02-08 02:06:00 +0000674{
675 switch (internalFormat) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000676 case GL_RGB:
677 case GL_R3_G3_B2:
678 case GL_RGB4:
679 case GL_RGB5:
680 case GL_RGB8:
681 case GL_RGB10:
682 case GL_RGB12:
683 case GL_RGB16:
684 return GL_RGB;
685 case GL_RGBA:
686 case GL_RGBA2:
687 case GL_RGBA4:
688 case GL_RGB5_A1:
689 case GL_RGBA8:
690 case GL_RGB10_A2:
691 case GL_RGBA12:
692 case GL_RGBA16:
693 return GL_RGBA;
694 case GL_STENCIL_INDEX:
695 case GL_STENCIL_INDEX1_EXT:
696 case GL_STENCIL_INDEX4_EXT:
697 case GL_STENCIL_INDEX8_EXT:
698 case GL_STENCIL_INDEX16_EXT:
699 return GL_STENCIL_INDEX;
700 case GL_DEPTH_COMPONENT:
Brian Paul2c6f9112005-02-24 05:47:06 +0000701 case GL_DEPTH_COMPONENT16:
702 case GL_DEPTH_COMPONENT24:
703 case GL_DEPTH_COMPONENT32:
Brian Paulf0bbbf62005-02-09 03:50:30 +0000704 return GL_DEPTH_COMPONENT;
Brian Paul1ad7b992005-09-28 02:29:50 +0000705 case GL_DEPTH_STENCIL_EXT:
706 case GL_DEPTH24_STENCIL8_EXT:
707 if (ctx->Extensions.EXT_packed_depth_stencil)
708 return GL_DEPTH_STENCIL_EXT;
709 else
710 return 0;
Brian Pauld9468c92005-02-10 16:08:07 +0000711 /* XXX add floating point formats eventually */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000712 default:
713 return 0;
Brian Paul463642c2005-02-08 02:06:00 +0000714 }
Brian Paul463642c2005-02-08 02:06:00 +0000715}
716
717
Brian Paul1864c7d2005-02-08 03:46:37 +0000718void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000719_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
720 GLsizei width, GLsizei height)
721{
Brian Paul2c6f9112005-02-24 05:47:06 +0000722 struct gl_renderbuffer *rb;
Brian Paul463642c2005-02-08 02:06:00 +0000723 GLenum baseFormat;
Brian Paulddc82ee2005-02-05 19:56:45 +0000724 GET_CURRENT_CONTEXT(ctx);
725
726 ASSERT_OUTSIDE_BEGIN_END(ctx);
727
Brian Paul463642c2005-02-08 02:06:00 +0000728 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000729 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)");
730 return;
731 }
732
Brian Paul59e0faa2006-03-15 17:48:00 +0000733 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
Brian Paul463642c2005-02-08 02:06:00 +0000734 if (baseFormat == 0) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000735 _mesa_error(ctx, GL_INVALID_ENUM,
736 "glRenderbufferStorageEXT(internalFormat)");
737 return;
738 }
739
Brian Paul13abf912006-04-13 19:17:13 +0000740 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000741 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)");
742 return;
743 }
744
Brian Paul13abf912006-04-13 19:17:13 +0000745 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000746 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)");
747 return;
748 }
749
Brian Paul2c6f9112005-02-24 05:47:06 +0000750 rb = ctx->CurrentRenderbuffer;
751
752 if (!rb) {
Brian Paul463642c2005-02-08 02:06:00 +0000753 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT");
754 return;
755 }
756
Brian Paul474f28e2005-10-08 14:41:17 +0000757 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
758
Brian Paul311bcf52005-11-18 02:24:14 +0000759 if (rb->InternalFormat == internalFormat &&
Brian Paul13abf912006-04-13 19:17:13 +0000760 rb->Width == (GLuint) width &&
761 rb->Height == (GLuint) height) {
Brian Paul311bcf52005-11-18 02:24:14 +0000762 /* no change in allocation needed */
763 return;
764 }
765
Brian Paulea4fe662006-03-26 05:22:17 +0000766 /* These MUST get set by the AllocStorage func */
767 rb->_ActualFormat = 0;
768 rb->RedBits =
769 rb->GreenBits =
770 rb->BlueBits =
771 rb->AlphaBits =
772 rb->IndexBits =
773 rb->DepthBits =
774 rb->StencilBits = 0;
775
Brian Paul2c6f9112005-02-24 05:47:06 +0000776 /* Now allocate the storage */
777 ASSERT(rb->AllocStorage);
778 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
779 /* No error - check/set fields now */
Brian Paulea4fe662006-03-26 05:22:17 +0000780 assert(rb->_ActualFormat);
Brian Paul13abf912006-04-13 19:17:13 +0000781 assert(rb->Width == (GLuint) width);
782 assert(rb->Height == (GLuint) height);
Brian Paul0e31e022005-12-01 00:25:00 +0000783 assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits ||
784 rb->DepthBits || rb->StencilBits || rb->IndexBits);
Brian Paulea4fe662006-03-26 05:22:17 +0000785 rb->InternalFormat = internalFormat;
Brian Paul2c6f9112005-02-24 05:47:06 +0000786 rb->_BaseFormat = baseFormat;
787 }
788 else {
789 /* Probably ran out of memory - clear the fields */
790 rb->Width = 0;
791 rb->Height = 0;
792 rb->InternalFormat = GL_NONE;
Brian Paulea4fe662006-03-26 05:22:17 +0000793 rb->_ActualFormat = GL_NONE;
Brian Paul2c6f9112005-02-24 05:47:06 +0000794 rb->_BaseFormat = GL_NONE;
Brian Paul0e31e022005-12-01 00:25:00 +0000795 rb->RedBits =
796 rb->GreenBits =
797 rb->BlueBits =
798 rb->AlphaBits =
799 rb->IndexBits =
800 rb->DepthBits =
801 rb->StencilBits = 0;
Brian Paul463642c2005-02-08 02:06:00 +0000802 }
803
Brian Paule4b23562005-05-04 20:11:35 +0000804 /*
805 test_framebuffer_completeness(ctx, fb);
806 */
Brian Paul2c6f9112005-02-24 05:47:06 +0000807 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
808 * points???
809 */
Brian Paulddc82ee2005-02-05 19:56:45 +0000810}
811
812
Brian Paul1864c7d2005-02-08 03:46:37 +0000813void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000814_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
815{
816 GET_CURRENT_CONTEXT(ctx);
817
818 ASSERT_OUTSIDE_BEGIN_END(ctx);
819
Brian Paul463642c2005-02-08 02:06:00 +0000820 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000821 _mesa_error(ctx, GL_INVALID_ENUM,
822 "glGetRenderbufferParameterivEXT(target)");
823 return;
824 }
825
Brian Paul463642c2005-02-08 02:06:00 +0000826 if (!ctx->CurrentRenderbuffer) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000827 _mesa_error(ctx, GL_INVALID_OPERATION,
828 "glGetRenderbufferParameterivEXT");
829 return;
830 }
831
Brian Paul474f28e2005-10-08 14:41:17 +0000832 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
833
Brian Paul463642c2005-02-08 02:06:00 +0000834 switch (pname) {
835 case GL_RENDERBUFFER_WIDTH_EXT:
836 *params = ctx->CurrentRenderbuffer->Width;
837 return;
838 case GL_RENDERBUFFER_HEIGHT_EXT:
839 *params = ctx->CurrentRenderbuffer->Height;
840 return;
841 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
842 *params = ctx->CurrentRenderbuffer->InternalFormat;
843 return;
Brian Paul1b939532005-05-31 23:55:21 +0000844 case GL_RENDERBUFFER_RED_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000845 *params = ctx->CurrentRenderbuffer->RedBits;
Brian Paul1b939532005-05-31 23:55:21 +0000846 break;
847 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000848 *params = ctx->CurrentRenderbuffer->GreenBits;
Brian Paul1b939532005-05-31 23:55:21 +0000849 break;
850 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000851 *params = ctx->CurrentRenderbuffer->BlueBits;
Brian Paul1b939532005-05-31 23:55:21 +0000852 break;
853 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000854 *params = ctx->CurrentRenderbuffer->AlphaBits;
Brian Paul1b939532005-05-31 23:55:21 +0000855 break;
856 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000857 *params = ctx->CurrentRenderbuffer->DepthBits;
Brian Paul1b939532005-05-31 23:55:21 +0000858 break;
859 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000860 *params = ctx->CurrentRenderbuffer->StencilBits;
Brian Paul1b939532005-05-31 23:55:21 +0000861 break;
Brian Paul463642c2005-02-08 02:06:00 +0000862 default:
863 _mesa_error(ctx, GL_INVALID_ENUM,
864 "glGetRenderbufferParameterivEXT(target)");
865 return;
866 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000867}
868
869
Brian Paul1864c7d2005-02-08 03:46:37 +0000870GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000871_mesa_IsFramebufferEXT(GLuint framebuffer)
872{
Brian Paulddc82ee2005-02-05 19:56:45 +0000873 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000874 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000875 if (framebuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000876 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000877 if (rb != NULL && rb != &DummyFramebuffer)
878 return GL_TRUE;
879 }
880 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000881}
882
883
Brian Paulea4fe662006-03-26 05:22:17 +0000884static void
885check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
886{
887 GLuint i;
888 ASSERT(ctx->Driver.RenderTexture);
889 for (i = 0; i < BUFFER_COUNT; i++) {
890 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
891 struct gl_texture_object *texObj = att->Texture;
Brian Paul9f6ff492006-03-28 15:24:50 +0000892 if (texObj
893 && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +0000894 ctx->Driver.RenderTexture(ctx, fb, att);
895 }
896 }
897}
898
899
Brian Paul0e31e022005-12-01 00:25:00 +0000900/**
901 * Examine all the framebuffer's attachments to see if any are textures.
902 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
903 * notify the device driver that the texture image may have changed.
904 */
905static void
Brian Paulea4fe662006-03-26 05:22:17 +0000906check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
Brian Paul0e31e022005-12-01 00:25:00 +0000907{
908 if (ctx->Driver.FinishRenderTexture) {
909 GLuint i;
910 for (i = 0; i < BUFFER_COUNT; i++) {
911 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
912 struct gl_texture_object *texObj = att->Texture;
913 if (texObj) {
Brian Paul519b23b2006-03-20 18:51:57 +0000914 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000915 }
916 }
917 }
918}
919
920
Brian Paul1864c7d2005-02-08 03:46:37 +0000921void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000922_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
923{
Roland Scheideggerdbfb3752007-07-17 17:29:55 +0200924 struct gl_framebuffer *newFb, *newFbread;
Brian Paul0bffb112005-11-08 14:45:48 +0000925 GLboolean bindReadBuf, bindDrawBuf;
Brian Paulddc82ee2005-02-05 19:56:45 +0000926 GET_CURRENT_CONTEXT(ctx);
927
928 ASSERT_OUTSIDE_BEGIN_END(ctx);
929
Brian Paulea4fe662006-03-26 05:22:17 +0000930 if (!ctx->Extensions.EXT_framebuffer_object) {
931 _mesa_error(ctx, GL_INVALID_OPERATION,
932 "glBindFramebufferEXT(unsupported)");
933 return;
934 }
935
Brian Paul0bffb112005-11-08 14:45:48 +0000936 switch (target) {
937#if FEATURE_EXT_framebuffer_blit
938 case GL_DRAW_FRAMEBUFFER_EXT:
939 if (!ctx->Extensions.EXT_framebuffer_blit) {
940 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
941 return;
942 }
943 bindDrawBuf = GL_TRUE;
944 bindReadBuf = GL_FALSE;
945 break;
946 case GL_READ_FRAMEBUFFER_EXT:
947 if (!ctx->Extensions.EXT_framebuffer_blit) {
948 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
949 return;
950 }
951 bindDrawBuf = GL_FALSE;
952 bindReadBuf = GL_TRUE;
953 break;
954#endif
955 case GL_FRAMEBUFFER_EXT:
956 bindDrawBuf = GL_TRUE;
957 bindReadBuf = GL_TRUE;
958 break;
959 default:
Brian Pauleba4ff62005-09-06 21:22:16 +0000960 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000961 return;
962 }
963
Brian Paul474f28e2005-10-08 14:41:17 +0000964 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwell5ac93f82006-11-01 14:21:57 +0000965 if (ctx->Driver.Flush) {
966 ctx->Driver.Flush(ctx);
967 }
Brian Paul3deaa012005-02-07 05:08:24 +0000968 if (framebuffer) {
Brian Paule4b23562005-05-04 20:11:35 +0000969 /* Binding a user-created framebuffer object */
Brian Paulea4fe662006-03-26 05:22:17 +0000970 newFb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000971 if (newFb == &DummyFramebuffer) {
Brian Paul923b6fc2005-02-08 04:08:56 +0000972 /* ID was reserved, but no real framebuffer object made yet */
Brian Paul1864c7d2005-02-08 03:46:37 +0000973 newFb = NULL;
974 }
Brian Paul3deaa012005-02-07 05:08:24 +0000975 if (!newFb) {
976 /* create new framebuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000977 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000978 if (!newFb) {
979 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
980 return;
981 }
Brian Paul1864c7d2005-02-08 03:46:37 +0000982 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
Brian Paul3deaa012005-02-07 05:08:24 +0000983 }
Roland Scheideggerdbfb3752007-07-17 17:29:55 +0200984 newFbread = newFb;
Brian Paul3deaa012005-02-07 05:08:24 +0000985 }
Brian Paul463642c2005-02-08 02:06:00 +0000986 else {
Brian Paule4b23562005-05-04 20:11:35 +0000987 /* Binding the window system framebuffer (which was originally set
988 * with MakeCurrent).
989 */
990 newFb = ctx->WinSysDrawBuffer;
Roland Scheideggerdbfb3752007-07-17 17:29:55 +0200991 newFbread = ctx->WinSysReadBuffer;
Brian Paul3deaa012005-02-07 05:08:24 +0000992 }
993
Brian Paulea4fe662006-03-26 05:22:17 +0000994 ASSERT(newFb);
Brian Paul1864c7d2005-02-08 03:46:37 +0000995 ASSERT(newFb != &DummyFramebuffer);
996
Brian Paulea4fe662006-03-26 05:22:17 +0000997 /*
998 * XXX check if re-binding same buffer and skip some of this code.
999 */
1000
Roland Scheideggera1bc0d02007-07-18 20:17:14 +02001001 /* for window-framebuffers, re-initialize the fbo values, as they
1002 could be wrong (makecurrent with a new drawable while still a fbo
1003 was bound will lead to default init fbo values).
1004 note that therefore the context ReadBuffer/DrawBuffer values are not
1005 valid while fbo's are bound!!! */
Brian Paul0bffb112005-11-08 14:45:48 +00001006 if (bindReadBuf) {
Roland Scheideggerdbfb3752007-07-17 17:29:55 +02001007 _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
Roland Scheideggera1bc0d02007-07-18 20:17:14 +02001008 if (!newFbread->Name) {
1009 _mesa_readbuffer_update_fields(ctx, ctx->Pixel.ReadBuffer);
1010 }
Brian Paul0bffb112005-11-08 14:45:48 +00001011 }
1012
1013 if (bindDrawBuf) {
Briana510bc32007-03-06 10:07:59 -07001014 /* check if old FB had any texture attachments */
1015 check_end_texture_render(ctx, ctx->DrawBuffer);
1016 /* check if time to delete this framebuffer */
Briana510bc32007-03-06 10:07:59 -07001017 _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
Roland Scheideggera1bc0d02007-07-18 20:17:14 +02001018 if (!newFb->Name) {
1019 GLuint i;
1020 GLenum buffers[MAX_DRAW_BUFFERS];
1021 for(i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
1022 buffers[i] = ctx->Color.DrawBuffer[i];
1023 }
1024 _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, buffers, NULL);
Roland Scheidegger6075df52007-07-18 18:07:12 +02001025 }
Roland Scheideggera1bc0d02007-07-18 20:17:14 +02001026 else {
Brian Paulea4fe662006-03-26 05:22:17 +00001027 /* check if newly bound framebuffer has any texture attachments */
1028 check_begin_texture_render(ctx, newFb);
1029 }
Brian Paul0bffb112005-11-08 14:45:48 +00001030 }
Brian Paul59e0faa2006-03-15 17:48:00 +00001031
1032 if (ctx->Driver.BindFramebuffer) {
Roland Scheideggerdbfb3752007-07-17 17:29:55 +02001033 ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread);
Brian Paul59e0faa2006-03-15 17:48:00 +00001034 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001035}
1036
1037
Brian Paul1864c7d2005-02-08 03:46:37 +00001038void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001039_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1040{
1041 GLint i;
1042 GET_CURRENT_CONTEXT(ctx);
1043
1044 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001045 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001046 /* The above doesn't fully flush the drivers in the way that a
1047 * glFlush does, but that is required here:
1048 */
1049 if (ctx->Driver.Flush)
1050 ctx->Driver.Flush(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +00001051
1052 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +00001053 if (framebuffers[i] > 0) {
1054 struct gl_framebuffer *fb;
Brian Paulea4fe662006-03-26 05:22:17 +00001055 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +00001056 if (fb) {
Brian Paule4b23562005-05-04 20:11:35 +00001057 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
Brian Paul91802fd2005-10-04 16:01:02 +00001058
1059 /* check if deleting currently bound framebuffer object */
1060 if (fb == ctx->DrawBuffer) {
1061 /* bind default */
1062 ASSERT(fb->RefCount >= 2);
1063 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1064 }
1065
Brian Paul3deaa012005-02-07 05:08:24 +00001066 /* remove from hash table immediately, to free the ID */
1067 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +00001068
Brian Paul1864c7d2005-02-08 03:46:37 +00001069 if (fb != &DummyFramebuffer) {
1070 /* But the object will not be freed until it's no longer
1071 * bound in any context.
1072 */
Briana510bc32007-03-06 10:07:59 -07001073 _mesa_unreference_framebuffer(&fb);
Brian Paul3deaa012005-02-07 05:08:24 +00001074 }
1075 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001076 }
1077 }
1078}
1079
1080
Brian Paul1864c7d2005-02-08 03:46:37 +00001081void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001082_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1083{
1084 GET_CURRENT_CONTEXT(ctx);
1085 GLuint first;
1086 GLint i;
1087
1088 ASSERT_OUTSIDE_BEGIN_END(ctx);
1089
1090 if (n < 0) {
1091 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1092 return;
1093 }
1094
1095 if (!framebuffers)
1096 return;
1097
1098 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1099
1100 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001101 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001102 framebuffers[i] = name;
1103 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001104 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001105 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001106 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001107 }
1108}
1109
1110
1111
Brian Paul1864c7d2005-02-08 03:46:37 +00001112GLenum GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001113_mesa_CheckFramebufferStatusEXT(GLenum target)
1114{
Brian Paul0bffb112005-11-08 14:45:48 +00001115 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001116 GET_CURRENT_CONTEXT(ctx);
1117
Brian Paule4b23562005-05-04 20:11:35 +00001118 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001119
Brian Paul0bffb112005-11-08 14:45:48 +00001120 switch (target) {
1121#if FEATURE_EXT_framebuffer_blit
1122 case GL_DRAW_FRAMEBUFFER_EXT:
1123 if (!ctx->Extensions.EXT_framebuffer_blit) {
1124 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1125 return 0;
1126 }
1127 buffer = ctx->DrawBuffer;
1128 break;
1129 case GL_READ_FRAMEBUFFER_EXT:
1130 if (!ctx->Extensions.EXT_framebuffer_blit) {
1131 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1132 return 0;
1133 }
1134 buffer = ctx->ReadBuffer;
1135 break;
1136#endif
1137 case GL_FRAMEBUFFER_EXT:
1138 buffer = ctx->DrawBuffer;
1139 break;
1140 default:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001141 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
Brian Paule4b23562005-05-04 20:11:35 +00001142 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
Brian Paulddc82ee2005-02-05 19:56:45 +00001143 }
1144
Brian Paul0bffb112005-11-08 14:45:48 +00001145 if (buffer->Name == 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001146 /* The window system / default framebuffer is always complete */
1147 return GL_FRAMEBUFFER_COMPLETE_EXT;
1148 }
1149
Brian Paul474f28e2005-10-08 14:41:17 +00001150 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1151
Brian Paul0bffb112005-11-08 14:45:48 +00001152 _mesa_test_framebuffer_completeness(ctx, buffer);
1153 return buffer->_Status;
Brian Paulddc82ee2005-02-05 19:56:45 +00001154}
1155
1156
1157
1158/**
Brian Paulea4fe662006-03-26 05:22:17 +00001159 * Common code called by glFramebufferTexture1D/2D/3DEXT().
Brian Paulddc82ee2005-02-05 19:56:45 +00001160 */
Brian Paulea4fe662006-03-26 05:22:17 +00001161static void
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001162framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
1163 GLenum attachment, GLenum textarget, GLuint texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001164 GLint level, GLint zoffset)
Brian Paulddc82ee2005-02-05 19:56:45 +00001165{
Brian Paul2c6f9112005-02-24 05:47:06 +00001166 struct gl_renderbuffer_attachment *att;
Brian Paulea4fe662006-03-26 05:22:17 +00001167 struct gl_texture_object *texObj = NULL;
1168 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001169
1170 ASSERT_OUTSIDE_BEGIN_END(ctx);
1171
Brian Paulea4fe662006-03-26 05:22:17 +00001172 if (target != GL_FRAMEBUFFER_EXT) {
1173 _mesa_error(ctx, GL_INVALID_ENUM,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001174 "glFramebufferTexture%sEXT(target)", caller);
Brian Paulddc82ee2005-02-05 19:56:45 +00001175 return;
Brian Paulea4fe662006-03-26 05:22:17 +00001176 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001177
Brian Paulea4fe662006-03-26 05:22:17 +00001178 fb = ctx->DrawBuffer;
1179 ASSERT(fb);
Brian Paul3deaa012005-02-07 05:08:24 +00001180
Brian Paulea4fe662006-03-26 05:22:17 +00001181 /* check framebuffer binding */
1182 if (fb->Name == 0) {
1183 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001184 "glFramebufferTexture%sEXT", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001185 return;
1186 }
1187
Brian Paulea4fe662006-03-26 05:22:17 +00001188
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001189 /* The textarget, level, and zoffset parameters are only validated if
1190 * texture is non-zero.
1191 */
1192 if (texture) {
1193 GLboolean err = GL_TRUE;
1194
1195 texObj = _mesa_lookup_texture(ctx, texture);
1196 if (texObj != NULL) {
Ian Romanickbb372f12007-05-16 15:34:22 -07001197 if (textarget == 0) {
1198 err = (texObj->Target != GL_TEXTURE_3D) &&
1199 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1200 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1201 }
1202 else {
1203 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1204 ? !IS_CUBE_FACE(textarget)
1205 : (texObj->Target != textarget);
1206 }
Brian Paulea4fe662006-03-26 05:22:17 +00001207 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001208
1209 if (err) {
Brian Paulea4fe662006-03-26 05:22:17 +00001210 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001211 "glFramebufferTexture%sEXT(texture target mismatch)",
1212 caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001213 return;
1214 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001215
1216 if (texObj->Target == GL_TEXTURE_3D) {
Brian Paulea4fe662006-03-26 05:22:17 +00001217 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1218 if (zoffset < 0 || zoffset >= maxSize) {
1219 _mesa_error(ctx, GL_INVALID_VALUE,
Ian Romanickbb372f12007-05-16 15:34:22 -07001220 "glFramebufferTexture%sEXT(zoffset)", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001221 return;
1222 }
1223 }
Ian Romanickbb372f12007-05-16 15:34:22 -07001224 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1225 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1226 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1227 _mesa_error(ctx, GL_INVALID_VALUE,
1228 "glFramebufferTexture%sEXT(layer)", caller);
1229 return;
1230 }
1231 }
1232
Brian Paulea4fe662006-03-26 05:22:17 +00001233
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001234 if ((level < 0) ||
1235 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1236 _mesa_error(ctx, GL_INVALID_VALUE,
1237 "glFramebufferTexture%sEXT(level)", caller);
1238 return;
1239 }
Brian Paulea4fe662006-03-26 05:22:17 +00001240 }
1241
1242 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001243 if (att == NULL) {
1244 _mesa_error(ctx, GL_INVALID_ENUM,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001245 "glFramebufferTexture%sEXT(attachment)", caller);
Brian Paul3deaa012005-02-07 05:08:24 +00001246 return;
1247 }
1248
Brian Paul474f28e2005-10-08 14:41:17 +00001249 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001250 /* The above doesn't fully flush the drivers in the way that a
1251 * glFlush does, but that is required here:
1252 */
1253 if (ctx->Driver.Flush)
1254 ctx->Driver.Flush(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001255
Brian Paulea4fe662006-03-26 05:22:17 +00001256 _glthread_LOCK_MUTEX(fb->Mutex);
1257 if (texObj) {
1258 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1259 level, zoffset);
Brian Paul3deaa012005-02-07 05:08:24 +00001260 }
1261 else {
Brian Paul519b23b2006-03-20 18:51:57 +00001262 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +00001263 }
Brian Paulea4fe662006-03-26 05:22:17 +00001264 _glthread_UNLOCK_MUTEX(fb->Mutex);
1265}
1266
1267
1268
1269void GLAPIENTRY
1270_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1271 GLenum textarget, GLuint texture, GLint level)
1272{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001273 GET_CURRENT_CONTEXT(ctx);
1274
1275 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1276 _mesa_error(ctx, GL_INVALID_ENUM,
1277 "glFramebufferTexture1DEXT(textarget)");
1278 return;
1279 }
1280
1281 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1282 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001283}
1284
1285
Brian Paul1864c7d2005-02-08 03:46:37 +00001286void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001287_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1288 GLenum textarget, GLuint texture, GLint level)
1289{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001290 GET_CURRENT_CONTEXT(ctx);
1291
1292 if ((texture != 0) &&
1293 (textarget != GL_TEXTURE_2D) &&
1294 (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1295 (!IS_CUBE_FACE(textarget))) {
1296 _mesa_error(ctx, GL_INVALID_OPERATION,
1297 "glFramebufferTexture2DEXT(textarget)");
1298 return;
1299 }
1300
1301 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1302 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001303}
1304
1305
Brian Paul1864c7d2005-02-08 03:46:37 +00001306void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001307_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1308 GLenum textarget, GLuint texture,
1309 GLint level, GLint zoffset)
1310{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001311 GET_CURRENT_CONTEXT(ctx);
1312
1313 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1314 _mesa_error(ctx, GL_INVALID_ENUM,
1315 "glFramebufferTexture3DEXT(textarget)");
1316 return;
1317 }
1318
1319 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001320 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00001321}
1322
1323
Brian Paul1864c7d2005-02-08 03:46:37 +00001324void GLAPIENTRY
Ian Romanickbb372f12007-05-16 15:34:22 -07001325_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1326 GLuint texture, GLint level, GLint layer)
1327{
1328 GET_CURRENT_CONTEXT(ctx);
1329
1330 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1331 level, layer);
1332}
1333
1334
1335void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001336_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1337 GLenum renderbufferTarget,
1338 GLuint renderbuffer)
1339{
Brian Paul2c6f9112005-02-24 05:47:06 +00001340 struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001341 struct gl_framebuffer *fb;
Brian Paule4b23562005-05-04 20:11:35 +00001342 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001343 GET_CURRENT_CONTEXT(ctx);
1344
1345 ASSERT_OUTSIDE_BEGIN_END(ctx);
1346
Brian Paul0bffb112005-11-08 14:45:48 +00001347 switch (target) {
1348#if FEATURE_EXT_framebuffer_blit
1349 case GL_DRAW_FRAMEBUFFER_EXT:
1350 if (!ctx->Extensions.EXT_framebuffer_blit) {
1351 _mesa_error(ctx, GL_INVALID_ENUM,
1352 "glFramebufferRenderbufferEXT(target)");
1353 return;
1354 }
1355 fb = ctx->DrawBuffer;
1356 break;
1357 case GL_READ_FRAMEBUFFER_EXT:
1358 if (!ctx->Extensions.EXT_framebuffer_blit) {
1359 _mesa_error(ctx, GL_INVALID_ENUM,
1360 "glFramebufferRenderbufferEXT(target)");
1361 return;
1362 }
1363 fb = ctx->ReadBuffer;
1364 break;
1365#endif
1366 case GL_FRAMEBUFFER_EXT:
1367 fb = ctx->DrawBuffer;
1368 break;
1369 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001370 _mesa_error(ctx, GL_INVALID_ENUM,
1371 "glFramebufferRenderbufferEXT(target)");
1372 return;
1373 }
1374
Brian Paul3deaa012005-02-07 05:08:24 +00001375 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
Brian Paule4b23562005-05-04 20:11:35 +00001376 _mesa_error(ctx, GL_INVALID_ENUM,
1377 "glFramebufferRenderbufferEXT(renderbufferTarget)");
Brian Paul3deaa012005-02-07 05:08:24 +00001378 return;
1379 }
1380
Brian Paul0bffb112005-11-08 14:45:48 +00001381 if (fb->Name == 0) {
Brian Paulab8ef282005-09-07 23:21:59 +00001382 /* Can't attach new renderbuffers to a window system framebuffer */
Brian Paul3deaa012005-02-07 05:08:24 +00001383 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1384 return;
1385 }
1386
Brian Paul84716042005-11-16 04:05:54 +00001387 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001388 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001389 _mesa_error(ctx, GL_INVALID_ENUM,
1390 "glFramebufferRenderbufferEXT(attachment)");
1391 return;
1392 }
1393
Brian Paul1864c7d2005-02-08 03:46:37 +00001394 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00001395 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001396 if (!rb) {
Brian Paule4b23562005-05-04 20:11:35 +00001397 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul1864c7d2005-02-08 03:46:37 +00001398 "glFramebufferRenderbufferEXT(renderbuffer)");
1399 return;
1400 }
Brian Paul1864c7d2005-02-08 03:46:37 +00001401 }
1402 else {
Brian Paule4b23562005-05-04 20:11:35 +00001403 /* remove renderbuffer attachment */
1404 rb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001405 }
Brian Paule4b23562005-05-04 20:11:35 +00001406
Brian Paul474f28e2005-10-08 14:41:17 +00001407 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001408 /* The above doesn't fully flush the drivers in the way that a
1409 * glFlush does, but that is required here:
1410 */
1411 if (ctx->Driver.Flush)
1412 ctx->Driver.Flush(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001413
Brian Paule4b23562005-05-04 20:11:35 +00001414 assert(ctx->Driver.FramebufferRenderbuffer);
Brian Paul84716042005-11-16 04:05:54 +00001415 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
Brian Paul2e019182006-03-07 01:43:52 +00001416
1417 /* Some subsequent GL commands may depend on the framebuffer's visual
1418 * after the binding is updated. Update visual info now.
1419 */
1420 _mesa_update_framebuffer_visual(fb);
Brian Paulddc82ee2005-02-05 19:56:45 +00001421}
1422
1423
Brian Paul1864c7d2005-02-08 03:46:37 +00001424void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001425_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1426 GLenum pname, GLint *params)
1427{
Brian Paul2c6f9112005-02-24 05:47:06 +00001428 const struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001429 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001430 GET_CURRENT_CONTEXT(ctx);
1431
1432 ASSERT_OUTSIDE_BEGIN_END(ctx);
1433
Brian Paul0bffb112005-11-08 14:45:48 +00001434 switch (target) {
1435#if FEATURE_EXT_framebuffer_blit
1436 case GL_DRAW_FRAMEBUFFER_EXT:
1437 if (!ctx->Extensions.EXT_framebuffer_blit) {
1438 _mesa_error(ctx, GL_INVALID_ENUM,
1439 "glGetFramebufferAttachmentParameterivEXT(target)");
1440 return;
1441 }
1442 buffer = ctx->DrawBuffer;
1443 break;
1444 case GL_READ_FRAMEBUFFER_EXT:
1445 if (!ctx->Extensions.EXT_framebuffer_blit) {
1446 _mesa_error(ctx, GL_INVALID_ENUM,
1447 "glGetFramebufferAttachmentParameterivEXT(target)");
1448 return;
1449 }
1450 buffer = ctx->ReadBuffer;
1451 break;
1452#endif
1453 case GL_FRAMEBUFFER_EXT:
1454 buffer = ctx->DrawBuffer;
1455 break;
1456 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001457 _mesa_error(ctx, GL_INVALID_ENUM,
1458 "glGetFramebufferAttachmentParameterivEXT(target)");
1459 return;
1460 }
1461
Brian Paul0bffb112005-11-08 14:45:48 +00001462 if (buffer->Name == 0) {
Brian Paul3deaa012005-02-07 05:08:24 +00001463 _mesa_error(ctx, GL_INVALID_OPERATION,
1464 "glGetFramebufferAttachmentParameterivEXT");
1465 return;
1466 }
1467
Brian Paul84716042005-11-16 04:05:54 +00001468 att = _mesa_get_attachment(ctx, buffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001469 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001470 _mesa_error(ctx, GL_INVALID_ENUM,
1471 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1472 return;
1473 }
1474
Brian Paul474f28e2005-10-08 14:41:17 +00001475 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001476 /* The above doesn't fully flush the drivers in the way that a
1477 * glFlush does, but that is required here:
1478 */
1479 if (ctx->Driver.Flush)
1480 ctx->Driver.Flush(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001481
Brian Paulddc82ee2005-02-05 19:56:45 +00001482 switch (pname) {
1483 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001484 *params = att->Type;
1485 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001486 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001487 if (att->Type == GL_RENDERBUFFER_EXT) {
1488 *params = att->Renderbuffer->Name;
1489 }
1490 else if (att->Type == GL_TEXTURE) {
1491 *params = att->Texture->Name;
1492 }
1493 else {
1494 _mesa_error(ctx, GL_INVALID_ENUM,
1495 "glGetFramebufferAttachmentParameterivEXT(pname)");
1496 }
1497 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001498 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001499 if (att->Type == GL_TEXTURE) {
1500 *params = att->TextureLevel;
1501 }
1502 else {
1503 _mesa_error(ctx, GL_INVALID_ENUM,
1504 "glGetFramebufferAttachmentParameterivEXT(pname)");
1505 }
1506 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001507 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001508 if (att->Type == GL_TEXTURE) {
1509 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1510 }
1511 else {
1512 _mesa_error(ctx, GL_INVALID_ENUM,
1513 "glGetFramebufferAttachmentParameterivEXT(pname)");
1514 }
1515 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001516 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001517 if (att->Type == GL_TEXTURE) {
1518 *params = att->Zoffset;
1519 }
1520 else {
1521 _mesa_error(ctx, GL_INVALID_ENUM,
1522 "glGetFramebufferAttachmentParameterivEXT(pname)");
1523 }
1524 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001525 default:
1526 _mesa_error(ctx, GL_INVALID_ENUM,
1527 "glGetFramebufferAttachmentParameterivEXT(pname)");
1528 return;
1529 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001530}
1531
1532
Brian Paul1864c7d2005-02-08 03:46:37 +00001533void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001534_mesa_GenerateMipmapEXT(GLenum target)
1535{
Brian Paul463642c2005-02-08 02:06:00 +00001536 struct gl_texture_unit *texUnit;
1537 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001538 GET_CURRENT_CONTEXT(ctx);
1539
1540 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001541 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00001542
1543 switch (target) {
1544 case GL_TEXTURE_1D:
1545 case GL_TEXTURE_2D:
Brian Paulddc82ee2005-02-05 19:56:45 +00001546 case GL_TEXTURE_3D:
Brian Paul463642c2005-02-08 02:06:00 +00001547 case GL_TEXTURE_CUBE_MAP:
Brian Paul1b939532005-05-31 23:55:21 +00001548 /* OK, legal value */
Brian Paulddc82ee2005-02-05 19:56:45 +00001549 break;
1550 default:
1551 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
1552 return;
1553 }
1554
Brian Paul463642c2005-02-08 02:06:00 +00001555 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1556 texObj = _mesa_select_tex_object(ctx, texUnit, target);
1557
1558 /* XXX this might not handle cube maps correctly */
Keith Whitwell5ac93f82006-11-01 14:21:57 +00001559 _mesa_lock_texture(ctx, texObj);
Brian Paul463642c2005-02-08 02:06:00 +00001560 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
Keith Whitwell5ac93f82006-11-01 14:21:57 +00001561 _mesa_unlock_texture(ctx, texObj);
Brian Paulddc82ee2005-02-05 19:56:45 +00001562}
Brian Paul0bffb112005-11-08 14:45:48 +00001563
1564
1565#if FEATURE_EXT_framebuffer_blit
1566void GLAPIENTRY
1567_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
1568 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
1569 GLbitfield mask, GLenum filter)
1570{
1571 GET_CURRENT_CONTEXT(ctx);
1572
1573 ASSERT_OUTSIDE_BEGIN_END(ctx);
1574 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1575
Brian Paul99745402006-03-01 02:02:43 +00001576 if (ctx->NewState) {
1577 _mesa_update_state(ctx);
1578 }
1579
1580 if (!ctx->ReadBuffer) {
1581 /* XXX */
1582 }
1583
Brian Paul0bffb112005-11-08 14:45:48 +00001584 /* check for complete framebuffers */
1585 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
1586 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1587 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
1588 "glBlitFramebufferEXT(incomplete draw/read buffers)");
1589 return;
1590 }
1591
Brian Paul99745402006-03-01 02:02:43 +00001592 if (filter != GL_NEAREST && filter != GL_LINEAR) {
1593 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
1594 return;
1595 }
1596
1597 if (mask & ~(GL_COLOR_BUFFER_BIT |
1598 GL_DEPTH_BUFFER_BIT |
1599 GL_STENCIL_BUFFER_BIT)) {
1600 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
1601 return;
1602 }
1603
Brian Paul0bffb112005-11-08 14:45:48 +00001604 /* depth/stencil must be blitted with nearest filtering */
1605 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
1606 && filter != GL_NEAREST) {
1607 _mesa_error(ctx, GL_INVALID_OPERATION,
1608 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
1609 return;
1610 }
1611
Brian Paul99745402006-03-01 02:02:43 +00001612 if (mask & GL_STENCIL_BUFFER_BIT) {
1613 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_StencilBuffer;
1614 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_StencilBuffer;
1615 if (readRb->StencilBits != drawRb->StencilBits) {
1616 _mesa_error(ctx, GL_INVALID_OPERATION,
1617 "glBlitFramebufferEXT(stencil buffer size mismatch");
1618 return;
1619 }
1620 }
1621
1622 if (mask & GL_DEPTH_BUFFER_BIT) {
1623 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_DepthBuffer;
1624 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_DepthBuffer;
1625 if (readRb->DepthBits != drawRb->DepthBits) {
1626 _mesa_error(ctx, GL_INVALID_OPERATION,
1627 "glBlitFramebufferEXT(depth buffer size mismatch");
1628 return;
1629 }
Brian Paul0bffb112005-11-08 14:45:48 +00001630 }
1631
1632 if (!ctx->Extensions.EXT_framebuffer_blit) {
1633 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
1634 return;
1635 }
1636
1637 ASSERT(ctx->Driver.BlitFramebuffer);
1638 ctx->Driver.BlitFramebuffer(ctx,
1639 srcX0, srcY0, srcX1, srcY1,
1640 dstX0, dstY0, dstX1, dstY1,
1641 mask, filter);
1642}
1643#endif /* FEATURE_EXT_framebuffer_blit */