blob: cf8de1e0cbe5bdb6de58b48fa203ee5c6117d20d [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
Brian Paulddc82ee2005-02-05 19:56:45 +000032#include "context.h"
33#include "fbobject.h"
Brian Paule4b23562005-05-04 20:11:35 +000034#include "framebuffer.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000035#include "hash.h"
Brian Paul24edd902006-09-29 01:24:26 +000036#include "mipmap.h"
Brian Paule4b23562005-05-04 20:11:35 +000037#include "renderbuffer.h"
Brian Paul99745402006-03-01 02:02:43 +000038#include "state.h"
Brian Paul463642c2005-02-08 02:06:00 +000039#include "teximage.h"
Brian Paulea4fe662006-03-26 05:22:17 +000040#include "texobj.h"
Brian Paul463642c2005-02-08 02:06:00 +000041#include "texstore.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000042
43
Brian Pauld9468c92005-02-10 16:08:07 +000044/**
45 * Notes:
46 *
47 * None of the GL_EXT_framebuffer_object functions are compiled into
48 * display lists.
49 */
50
51
52
Brian Paul923b6fc2005-02-08 04:08:56 +000053/*
54 * When glGenRender/FramebuffersEXT() is called we insert pointers to
55 * these placeholder objects into the hash table.
56 * Later, when the object ID is first bound, we replace the placeholder
57 * with the real frame/renderbuffer.
58 */
Brian Paul2c6f9112005-02-24 05:47:06 +000059static struct gl_framebuffer DummyFramebuffer;
60static struct gl_renderbuffer DummyRenderbuffer;
Brian Paul1864c7d2005-02-08 03:46:37 +000061
62
Brian Paul3deaa012005-02-07 05:08:24 +000063#define IS_CUBE_FACE(TARGET) \
64 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
65 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
Brian Paulddc82ee2005-02-05 19:56:45 +000066
67
68/**
Brian Paul2c6f9112005-02-24 05:47:06 +000069 * Helper routine for getting a gl_renderbuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +000070 */
Brian Paulea4fe662006-03-26 05:22:17 +000071struct gl_renderbuffer *
72_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +000073{
Brian Paul2c6f9112005-02-24 05:47:06 +000074 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +000075
Brian Paul1864c7d2005-02-08 03:46:37 +000076 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +000077 return NULL;
78
Brian Paul2c6f9112005-02-24 05:47:06 +000079 rb = (struct gl_renderbuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +000080 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
81 return rb;
82}
83
84
85/**
Brian Paul2c6f9112005-02-24 05:47:06 +000086 * Helper routine for getting a gl_framebuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +000087 */
Brian Paulea4fe662006-03-26 05:22:17 +000088struct gl_framebuffer *
89_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +000090{
Brian Paul2c6f9112005-02-24 05:47:06 +000091 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +000092
Brian Paul1864c7d2005-02-08 03:46:37 +000093 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +000094 return NULL;
95
Brian Paul2c6f9112005-02-24 05:47:06 +000096 fb = (struct gl_framebuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +000097 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
Brian Paul463642c2005-02-08 02:06:00 +000098 return fb;
Brian Paulddc82ee2005-02-05 19:56:45 +000099}
100
101
102/**
Brian Pauld9468c92005-02-10 16:08:07 +0000103 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
Brian Paul2c6f9112005-02-24 05:47:06 +0000104 * gl_renderbuffer_attachment object.
Brian Pauld9468c92005-02-10 16:08:07 +0000105 */
Brian Paul84716042005-11-16 04:05:54 +0000106struct gl_renderbuffer_attachment *
107_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
108 GLenum attachment)
Brian Paul3deaa012005-02-07 05:08:24 +0000109{
110 GLuint i;
111
112 switch (attachment) {
113 case GL_COLOR_ATTACHMENT0_EXT:
114 case GL_COLOR_ATTACHMENT1_EXT:
115 case GL_COLOR_ATTACHMENT2_EXT:
116 case GL_COLOR_ATTACHMENT3_EXT:
117 case GL_COLOR_ATTACHMENT4_EXT:
118 case GL_COLOR_ATTACHMENT5_EXT:
119 case GL_COLOR_ATTACHMENT6_EXT:
120 case GL_COLOR_ATTACHMENT7_EXT:
121 case GL_COLOR_ATTACHMENT8_EXT:
122 case GL_COLOR_ATTACHMENT9_EXT:
123 case GL_COLOR_ATTACHMENT10_EXT:
124 case GL_COLOR_ATTACHMENT11_EXT:
125 case GL_COLOR_ATTACHMENT12_EXT:
126 case GL_COLOR_ATTACHMENT13_EXT:
127 case GL_COLOR_ATTACHMENT14_EXT:
128 case GL_COLOR_ATTACHMENT15_EXT:
129 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
130 if (i >= ctx->Const.MaxColorAttachments) {
131 return NULL;
132 }
Brian Paule4b23562005-05-04 20:11:35 +0000133 return &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paul3deaa012005-02-07 05:08:24 +0000134 case GL_DEPTH_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000135 return &fb->Attachment[BUFFER_DEPTH];
Brian Paul3deaa012005-02-07 05:08:24 +0000136 case GL_STENCIL_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000137 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul3deaa012005-02-07 05:08:24 +0000138 default:
139 return NULL;
140 }
141}
142
143
Brian Pauld9468c92005-02-10 16:08:07 +0000144/**
145 * Remove any texture or renderbuffer attached to the given attachment
146 * point. Update reference counts, etc.
147 */
Brian Paule4b23562005-05-04 20:11:35 +0000148void
149_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
Brian Paul3deaa012005-02-07 05:08:24 +0000150{
151 if (att->Type == GL_TEXTURE) {
152 ASSERT(att->Texture);
Brian Paul3deaa012005-02-07 05:08:24 +0000153 att->Texture->RefCount--;
154 if (att->Texture->RefCount == 0) {
155 ctx->Driver.DeleteTexture(ctx, att->Texture);
156 }
Brian Paul0e31e022005-12-01 00:25:00 +0000157 else {
158 /* tell driver that we're done rendering to this texture. */
159 if (ctx->Driver.FinishRenderTexture) {
Brian Paul519b23b2006-03-20 18:51:57 +0000160 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000161 }
162 }
Brian Paul3deaa012005-02-07 05:08:24 +0000163 att->Texture = NULL;
164 }
Brian Paul0e31e022005-12-01 00:25:00 +0000165 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul3deaa012005-02-07 05:08:24 +0000166 ASSERT(att->Renderbuffer);
167 ASSERT(!att->Texture);
168 att->Renderbuffer->RefCount--;
169 if (att->Renderbuffer->RefCount == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000170 att->Renderbuffer->Delete(att->Renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000171 }
172 att->Renderbuffer = NULL;
173 }
174 att->Type = GL_NONE;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000175 att->Complete = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +0000176}
177
178
Brian Pauld9468c92005-02-10 16:08:07 +0000179/**
180 * Bind a texture object to an attachment point.
181 * The previous binding, if any, will be removed first.
182 */
Brian Paule4b23562005-05-04 20:11:35 +0000183void
184_mesa_set_texture_attachment(GLcontext *ctx,
Brian Paul519b23b2006-03-20 18:51:57 +0000185 struct gl_framebuffer *fb,
Brian Paule4b23562005-05-04 20:11:35 +0000186 struct gl_renderbuffer_attachment *att,
187 struct gl_texture_object *texObj,
188 GLenum texTarget, GLuint level, GLuint zoffset)
Brian Paul3deaa012005-02-07 05:08:24 +0000189{
Brian Paul0e31e022005-12-01 00:25:00 +0000190 if (att->Texture == texObj) {
191 /* re-attaching same texture */
192 ASSERT(att->Type == GL_TEXTURE);
193 }
194 else {
195 /* new attachment */
196 _mesa_remove_attachment(ctx, att);
197 att->Type = GL_TEXTURE;
198 att->Texture = texObj;
199 texObj->RefCount++;
200 }
201
202 /* always update these fields */
Brian Paul3deaa012005-02-07 05:08:24 +0000203 att->TextureLevel = level;
204 if (IS_CUBE_FACE(texTarget)) {
205 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
206 }
207 else {
208 att->CubeMapFace = 0;
209 }
210 att->Zoffset = zoffset;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000211 att->Complete = GL_FALSE;
Brian Paul519b23b2006-03-20 18:51:57 +0000212
213 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +0000214 ctx->Driver.RenderTexture(ctx, fb, att);
Brian Paul519b23b2006-03-20 18:51:57 +0000215 }
Brian Paul3deaa012005-02-07 05:08:24 +0000216}
217
218
Brian Pauld9468c92005-02-10 16:08:07 +0000219/**
220 * Bind a renderbuffer to an attachment point.
221 * The previous binding, if any, will be removed first.
222 */
Brian Paule4b23562005-05-04 20:11:35 +0000223void
224_mesa_set_renderbuffer_attachment(GLcontext *ctx,
225 struct gl_renderbuffer_attachment *att,
226 struct gl_renderbuffer *rb)
Brian Paul3deaa012005-02-07 05:08:24 +0000227{
Brian Paulea4fe662006-03-26 05:22:17 +0000228 /* XXX check if re-doing same attachment, exit early */
Brian Paule4b23562005-05-04 20:11:35 +0000229 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000230 att->Type = GL_RENDERBUFFER_EXT;
231 att->Renderbuffer = rb;
Brian Paul2c6f9112005-02-24 05:47:06 +0000232 att->Texture = NULL; /* just to be safe */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000233 att->Complete = GL_FALSE;
Brian Paul3deaa012005-02-07 05:08:24 +0000234 rb->RefCount++;
235}
236
Brian Paulddc82ee2005-02-05 19:56:45 +0000237
Brian Paulf0bbbf62005-02-09 03:50:30 +0000238/**
Brian Paule4b23562005-05-04 20:11:35 +0000239 * Fallback for ctx->Driver.FramebufferRenderbuffer()
Brian Paul84716042005-11-16 04:05:54 +0000240 * Attach a renderbuffer object to a framebuffer object.
Brian Paule4b23562005-05-04 20:11:35 +0000241 */
242void
Brian Paul84716042005-11-16 04:05:54 +0000243_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
244 GLenum attachment, struct gl_renderbuffer *rb)
Brian Paule4b23562005-05-04 20:11:35 +0000245{
Brian Paul84716042005-11-16 04:05:54 +0000246 struct gl_renderbuffer_attachment *att;
247
Brian Paulea4fe662006-03-26 05:22:17 +0000248 _glthread_LOCK_MUTEX(fb->Mutex);
249 if (rb)
250 _glthread_LOCK_MUTEX(rb->Mutex);
251
Brian Paul84716042005-11-16 04:05:54 +0000252 att = _mesa_get_attachment(ctx, fb, attachment);
253 ASSERT(att);
254
Brian Paule4b23562005-05-04 20:11:35 +0000255 if (rb) {
256 _mesa_set_renderbuffer_attachment(ctx, att, rb);
257 }
258 else {
259 _mesa_remove_attachment(ctx, att);
260 }
Brian Paulea4fe662006-03-26 05:22:17 +0000261
262 if (rb)
263 _glthread_UNLOCK_MUTEX(rb->Mutex);
264 _glthread_UNLOCK_MUTEX(fb->Mutex);
Brian Paule4b23562005-05-04 20:11:35 +0000265}
266
267
268/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000269 * Test if an attachment point is complete and update its Complete field.
270 * \param format if GL_COLOR, this is a color attachment point,
271 * if GL_DEPTH, this is a depth component attachment point,
272 * if GL_STENCIL, this is a stencil component attachment point.
273 */
274static void
275test_attachment_completeness(const GLcontext *ctx, GLenum format,
Brian Paul2c6f9112005-02-24 05:47:06 +0000276 struct gl_renderbuffer_attachment *att)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000277{
278 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
279
280 /* assume complete */
281 att->Complete = GL_TRUE;
282
Brian Paulf0bbbf62005-02-09 03:50:30 +0000283 /* Look for reasons why the attachment might be incomplete */
284 if (att->Type == GL_TEXTURE) {
Brian Paule4b23562005-05-04 20:11:35 +0000285 const struct gl_texture_object *texObj = att->Texture;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000286 struct gl_texture_image *texImage;
287
Brian Paule4b23562005-05-04 20:11:35 +0000288 if (!texObj) {
289 att->Complete = GL_FALSE;
290 return;
291 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000292
293 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
294 if (!texImage) {
295 att->Complete = GL_FALSE;
296 return;
297 }
298 if (texImage->Width < 1 || texImage->Height < 1) {
299 att->Complete = GL_FALSE;
300 return;
301 }
302 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
303 att->Complete = GL_FALSE;
304 return;
305 }
306
307 if (format == GL_COLOR) {
Brian Paule4b23562005-05-04 20:11:35 +0000308 if (texImage->TexFormat->BaseFormat != GL_RGB &&
309 texImage->TexFormat->BaseFormat != GL_RGBA) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000310 att->Complete = GL_FALSE;
311 return;
312 }
313 }
314 else if (format == GL_DEPTH) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000315 if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) {
316 /* OK */
317 }
318 else if (ctx->Extensions.EXT_packed_depth_stencil &&
319 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
320 /* OK */
321 }
322 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000323 att->Complete = GL_FALSE;
324 return;
325 }
326 }
327 else {
328 /* no such thing as stencil textures */
329 att->Complete = GL_FALSE;
330 return;
331 }
332 }
Brian Paule4b23562005-05-04 20:11:35 +0000333 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul49918882006-03-20 15:27:55 +0000334 ASSERT(att->Renderbuffer);
335 if (!att->Renderbuffer->InternalFormat ||
336 att->Renderbuffer->Width < 1 ||
337 att->Renderbuffer->Height < 1) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000338 att->Complete = GL_FALSE;
339 return;
340 }
341 if (format == GL_COLOR) {
342 if (att->Renderbuffer->_BaseFormat != GL_RGB &&
343 att->Renderbuffer->_BaseFormat != GL_RGBA) {
Brian Paul49918882006-03-20 15:27:55 +0000344 ASSERT(att->Renderbuffer->RedBits);
345 ASSERT(att->Renderbuffer->GreenBits);
346 ASSERT(att->Renderbuffer->BlueBits);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000347 att->Complete = GL_FALSE;
348 return;
349 }
350 }
351 else if (format == GL_DEPTH) {
Brian Paul49918882006-03-20 15:27:55 +0000352 ASSERT(att->Renderbuffer->DepthBits);
Brian Paul1ad7b992005-09-28 02:29:50 +0000353 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) {
354 /* OK */
355 }
356 else if (ctx->Extensions.EXT_packed_depth_stencil &&
357 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
358 /* OK */
359 }
360 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000361 att->Complete = GL_FALSE;
362 return;
363 }
364 }
365 else {
366 assert(format == GL_STENCIL);
Brian Paul49918882006-03-20 15:27:55 +0000367 ASSERT(att->Renderbuffer->StencilBits);
Brian Paul1ad7b992005-09-28 02:29:50 +0000368 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) {
369 /* OK */
370 }
371 else if (ctx->Extensions.EXT_packed_depth_stencil &&
372 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
373 /* OK */
374 }
375 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000376 att->Complete = GL_FALSE;
377 return;
378 }
379 }
380 }
Brian Paule4b23562005-05-04 20:11:35 +0000381 else {
382 ASSERT(att->Type == GL_NONE);
383 /* complete */
384 return;
385 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000386}
387
388
389/**
Brian Paul49918882006-03-20 15:27:55 +0000390 * Helpful for debugging
391 */
392static void
393fbo_incomplete(const char *msg, int index)
394{
Brian Paul13abf912006-04-13 19:17:13 +0000395 (void) msg;
396 (void) index;
Brian Paul49918882006-03-20 15:27:55 +0000397 /*
398 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
399 */
400}
401
402
403/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000404 * Test if the given framebuffer object is complete and update its
405 * Status field with the results.
Brian Paule4b23562005-05-04 20:11:35 +0000406 * Also update the framebuffer's Width and Height fields if the
407 * framebuffer is complete.
Brian Paulf0bbbf62005-02-09 03:50:30 +0000408 */
Brian Paule4b23562005-05-04 20:11:35 +0000409void
410_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000411{
Brian Paul6c0c9172005-02-27 16:23:41 +0000412 GLuint numImages, width = 0, height = 0;
413 GLenum intFormat = GL_NONE;
Brian Paule4b23562005-05-04 20:11:35 +0000414 GLuint w = 0, h = 0;
415 GLint i;
Brian Paul28b014e2006-04-05 03:05:17 +0000416 GLuint j;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000417
Brian Paulc7264412005-06-01 00:50:23 +0000418 assert(fb->Name != 0);
419
Brian Paulf0bbbf62005-02-09 03:50:30 +0000420 numImages = 0;
Brian Paule4b23562005-05-04 20:11:35 +0000421 fb->Width = 0;
422 fb->Height = 0;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000423
424 /* Start at -2 to more easily loop over all attachment points */
Brian Paule4b23562005-05-04 20:11:35 +0000425 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000426 struct gl_renderbuffer_attachment *att;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000427 GLenum f;
428
429 if (i == -2) {
Brian Paule4b23562005-05-04 20:11:35 +0000430 att = &fb->Attachment[BUFFER_DEPTH];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000431 test_attachment_completeness(ctx, GL_DEPTH, att);
432 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000433 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000434 fbo_incomplete("depth attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000435 return;
436 }
437 }
438 else if (i == -1) {
Brian Paule4b23562005-05-04 20:11:35 +0000439 att = &fb->Attachment[BUFFER_STENCIL];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000440 test_attachment_completeness(ctx, GL_STENCIL, att);
441 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000442 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000443 fbo_incomplete("stencil attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000444 return;
445 }
446 }
447 else {
Brian Paule4b23562005-05-04 20:11:35 +0000448 att = &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000449 test_attachment_completeness(ctx, GL_COLOR, att);
450 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000451 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000452 fbo_incomplete("color attachment incomplete", i);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000453 return;
454 }
455 }
456
457 if (att->Type == GL_TEXTURE) {
Brian Paula9fc8ba2005-10-05 01:48:07 +0000458 const struct gl_texture_image *texImg
459 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
460 w = texImg->Width;
461 h = texImg->Height;
462 f = texImg->_BaseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000463 numImages++;
Brian Paul9f6ff492006-03-28 15:24:50 +0000464 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT
465 && f != GL_DEPTH_STENCIL_EXT) {
Brian Pauled7f3ae2005-06-07 15:03:40 +0000466 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000467 fbo_incomplete("texture attachment incomplete", -1);
Brian Pauled7f3ae2005-06-07 15:03:40 +0000468 return;
469 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000470 }
471 else if (att->Type == GL_RENDERBUFFER_EXT) {
472 w = att->Renderbuffer->Width;
473 h = att->Renderbuffer->Height;
474 f = att->Renderbuffer->InternalFormat;
475 numImages++;
476 }
477 else {
478 assert(att->Type == GL_NONE);
479 continue;
480 }
481
482 if (numImages == 1) {
483 /* set required width, height and format */
484 width = w;
485 height = h;
486 if (i >= 0)
487 intFormat = f;
488 }
489 else {
490 /* check that width, height, format are same */
491 if (w != width || h != height) {
Brian Paule4b23562005-05-04 20:11:35 +0000492 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000493 fbo_incomplete("width or height mismatch", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000494 return;
495 }
Brian Paule4b23562005-05-04 20:11:35 +0000496 if (intFormat != GL_NONE && f != intFormat) {
497 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000498 fbo_incomplete("format mismatch", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000499 return;
500 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000501 }
502 }
503
504 /* Check that all DrawBuffers are present */
Brian Paul28b014e2006-04-05 03:05:17 +0000505 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
506 if (fb->ColorDrawBuffer[j] != GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000507 const struct gl_renderbuffer_attachment *att
Brian Paul28b014e2006-04-05 03:05:17 +0000508 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
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_DRAW_BUFFER_EXT;
Brian Paul28b014e2006-04-05 03:05:17 +0000512 fbo_incomplete("missing drawbuffer", j);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000513 return;
514 }
515 }
516 }
517
518 /* Check that the ReadBuffer is present */
Brian Paule4b23562005-05-04 20:11:35 +0000519 if (fb->ColorReadBuffer != GL_NONE) {
520 const struct gl_renderbuffer_attachment *att
Brian Paul84716042005-11-16 04:05:54 +0000521 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
Brian Paule4b23562005-05-04 20:11:35 +0000522 assert(att);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000523 if (att->Type == GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000524 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000525 fbo_incomplete("missing readbuffer", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000526 return;
527 }
528 }
529
530 if (numImages == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000531 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000532 fbo_incomplete("no attachments", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000533 return;
534 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000535
Brian Paule4b23562005-05-04 20:11:35 +0000536 /*
537 * If we get here, the framebuffer is complete!
538 */
539 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
540 fb->Width = w;
541 fb->Height = h;
542}
Brian Paulf0bbbf62005-02-09 03:50:30 +0000543
544
Brian Paul1864c7d2005-02-08 03:46:37 +0000545GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000546_mesa_IsRenderbufferEXT(GLuint renderbuffer)
547{
Brian Paulddc82ee2005-02-05 19:56:45 +0000548 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000549 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000550 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000551 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000552 if (rb != NULL && rb != &DummyRenderbuffer)
553 return GL_TRUE;
554 }
555 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000556}
557
558
Brian Paul1864c7d2005-02-08 03:46:37 +0000559void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000560_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
561{
Brian Paul2c6f9112005-02-24 05:47:06 +0000562 struct gl_renderbuffer *newRb, *oldRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000563 GET_CURRENT_CONTEXT(ctx);
564
565 ASSERT_OUTSIDE_BEGIN_END(ctx);
566
Brian Paul3deaa012005-02-07 05:08:24 +0000567 if (target != GL_RENDERBUFFER_EXT) {
568 _mesa_error(ctx, GL_INVALID_ENUM,
569 "glBindRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000570 return;
571 }
572
Brian Paul474f28e2005-10-08 14:41:17 +0000573 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +0000574 /* The above doesn't fully flush the drivers in the way that a
575 * glFlush does, but that is required here:
576 */
577 if (ctx->Driver.Flush)
578 ctx->Driver.Flush(ctx);
579
Brian Paul474f28e2005-10-08 14:41:17 +0000580
Brian Paul3deaa012005-02-07 05:08:24 +0000581 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000582 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000583 if (newRb == &DummyRenderbuffer) {
584 /* ID was reserved, but no real renderbuffer object made yet */
585 newRb = NULL;
586 }
Brian Paul3deaa012005-02-07 05:08:24 +0000587 if (!newRb) {
588 /* create new renderbuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000589 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000590 if (!newRb) {
591 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
592 return;
593 }
Brian Paul2c6f9112005-02-24 05:47:06 +0000594 ASSERT(newRb->AllocStorage);
Brian Paul1864c7d2005-02-08 03:46:37 +0000595 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
Brian Paul3deaa012005-02-07 05:08:24 +0000596 }
597 newRb->RefCount++;
Brian Paulddc82ee2005-02-05 19:56:45 +0000598 }
Brian Paul463642c2005-02-08 02:06:00 +0000599 else {
600 newRb = NULL;
601 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000602
Brian Paul3deaa012005-02-07 05:08:24 +0000603 oldRb = ctx->CurrentRenderbuffer;
604 if (oldRb) {
Brian Paul7ac5b7b2006-05-20 15:08:25 +0000605 _mesa_dereference_renderbuffer(&oldRb);
Brian Paul3deaa012005-02-07 05:08:24 +0000606 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000607
Brian Paul1864c7d2005-02-08 03:46:37 +0000608 ASSERT(newRb != &DummyRenderbuffer);
609
Brian Paul3deaa012005-02-07 05:08:24 +0000610 ctx->CurrentRenderbuffer = newRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000611}
612
613
Brian Paul1864c7d2005-02-08 03:46:37 +0000614void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000615_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
616{
617 GLint i;
618 GET_CURRENT_CONTEXT(ctx);
619
620 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000621 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000622
623 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000624 if (renderbuffers[i] > 0) {
625 struct gl_renderbuffer *rb;
Brian Paulea4fe662006-03-26 05:22:17 +0000626 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +0000627 if (rb) {
Brian Paul91802fd2005-10-04 16:01:02 +0000628 /* check if deleting currently bound renderbuffer object */
629 if (rb == ctx->CurrentRenderbuffer) {
630 /* bind default */
631 ASSERT(rb->RefCount >= 2);
632 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
633 }
634
Brian Paul3deaa012005-02-07 05:08:24 +0000635 /* remove from hash table immediately, to free the ID */
636 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +0000637
Brian Paul1864c7d2005-02-08 03:46:37 +0000638 if (rb != &DummyRenderbuffer) {
639 /* But the object will not be freed until it's no longer
640 * bound in any context.
641 */
Brian Paul7ac5b7b2006-05-20 15:08:25 +0000642 _mesa_dereference_renderbuffer(&rb);
Brian Paul3deaa012005-02-07 05:08:24 +0000643 }
644 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000645 }
646 }
647}
648
649
Brian Paul1864c7d2005-02-08 03:46:37 +0000650void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000651_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
652{
653 GET_CURRENT_CONTEXT(ctx);
654 GLuint first;
655 GLint i;
656
657 ASSERT_OUTSIDE_BEGIN_END(ctx);
658
659 if (n < 0) {
660 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
661 return;
662 }
663
664 if (!renderbuffers)
665 return;
666
667 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
668
669 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000670 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000671 renderbuffers[i] = name;
Brian Paul1864c7d2005-02-08 03:46:37 +0000672 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +0000673 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +0000674 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +0000675 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +0000676 }
677}
678
679
Brian Pauld9468c92005-02-10 16:08:07 +0000680/**
681 * Given an internal format token for a render buffer, return the
682 * corresponding base format.
Brian Paul59e0faa2006-03-15 17:48:00 +0000683 * This is very similar to _mesa_base_tex_format() but the set of valid
684 * internal formats is somewhat different.
685 *
Brian Pauld9468c92005-02-10 16:08:07 +0000686 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
Brian Paul1ad7b992005-09-28 02:29:50 +0000687 * GL_DEPTH_STENCIL_EXT or zero if error.
Brian Pauld9468c92005-02-10 16:08:07 +0000688 */
Brian Paul59e0faa2006-03-15 17:48:00 +0000689GLenum
690_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
Brian Paul463642c2005-02-08 02:06:00 +0000691{
692 switch (internalFormat) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000693 case GL_RGB:
694 case GL_R3_G3_B2:
695 case GL_RGB4:
696 case GL_RGB5:
697 case GL_RGB8:
698 case GL_RGB10:
699 case GL_RGB12:
700 case GL_RGB16:
701 return GL_RGB;
702 case GL_RGBA:
703 case GL_RGBA2:
704 case GL_RGBA4:
705 case GL_RGB5_A1:
706 case GL_RGBA8:
707 case GL_RGB10_A2:
708 case GL_RGBA12:
709 case GL_RGBA16:
710 return GL_RGBA;
711 case GL_STENCIL_INDEX:
712 case GL_STENCIL_INDEX1_EXT:
713 case GL_STENCIL_INDEX4_EXT:
714 case GL_STENCIL_INDEX8_EXT:
715 case GL_STENCIL_INDEX16_EXT:
716 return GL_STENCIL_INDEX;
717 case GL_DEPTH_COMPONENT:
Brian Paul2c6f9112005-02-24 05:47:06 +0000718 case GL_DEPTH_COMPONENT16:
719 case GL_DEPTH_COMPONENT24:
720 case GL_DEPTH_COMPONENT32:
Brian Paulf0bbbf62005-02-09 03:50:30 +0000721 return GL_DEPTH_COMPONENT;
Brian Paul1ad7b992005-09-28 02:29:50 +0000722 case GL_DEPTH_STENCIL_EXT:
723 case GL_DEPTH24_STENCIL8_EXT:
724 if (ctx->Extensions.EXT_packed_depth_stencil)
725 return GL_DEPTH_STENCIL_EXT;
726 else
727 return 0;
Brian Pauld9468c92005-02-10 16:08:07 +0000728 /* XXX add floating point formats eventually */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000729 default:
730 return 0;
Brian Paul463642c2005-02-08 02:06:00 +0000731 }
Brian Paul463642c2005-02-08 02:06:00 +0000732}
733
734
Brian Paul1864c7d2005-02-08 03:46:37 +0000735void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000736_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
737 GLsizei width, GLsizei height)
738{
Brian Paul2c6f9112005-02-24 05:47:06 +0000739 struct gl_renderbuffer *rb;
Brian Paul463642c2005-02-08 02:06:00 +0000740 GLenum baseFormat;
Brian Paulddc82ee2005-02-05 19:56:45 +0000741 GET_CURRENT_CONTEXT(ctx);
742
743 ASSERT_OUTSIDE_BEGIN_END(ctx);
744
Brian Paul463642c2005-02-08 02:06:00 +0000745 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000746 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)");
747 return;
748 }
749
Brian Paul59e0faa2006-03-15 17:48:00 +0000750 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
Brian Paul463642c2005-02-08 02:06:00 +0000751 if (baseFormat == 0) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000752 _mesa_error(ctx, GL_INVALID_ENUM,
753 "glRenderbufferStorageEXT(internalFormat)");
754 return;
755 }
756
Brian Paul13abf912006-04-13 19:17:13 +0000757 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000758 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)");
759 return;
760 }
761
Brian Paul13abf912006-04-13 19:17:13 +0000762 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000763 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)");
764 return;
765 }
766
Brian Paul2c6f9112005-02-24 05:47:06 +0000767 rb = ctx->CurrentRenderbuffer;
768
769 if (!rb) {
Brian Paul463642c2005-02-08 02:06:00 +0000770 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT");
771 return;
772 }
773
Brian Paul474f28e2005-10-08 14:41:17 +0000774 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
775
Brian Paul311bcf52005-11-18 02:24:14 +0000776 if (rb->InternalFormat == internalFormat &&
Brian Paul13abf912006-04-13 19:17:13 +0000777 rb->Width == (GLuint) width &&
778 rb->Height == (GLuint) height) {
Brian Paul311bcf52005-11-18 02:24:14 +0000779 /* no change in allocation needed */
780 return;
781 }
782
Brian Paulea4fe662006-03-26 05:22:17 +0000783 /* These MUST get set by the AllocStorage func */
784 rb->_ActualFormat = 0;
785 rb->RedBits =
786 rb->GreenBits =
787 rb->BlueBits =
788 rb->AlphaBits =
789 rb->IndexBits =
790 rb->DepthBits =
791 rb->StencilBits = 0;
792
Brian Paul2c6f9112005-02-24 05:47:06 +0000793 /* Now allocate the storage */
794 ASSERT(rb->AllocStorage);
795 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
796 /* No error - check/set fields now */
Brian Paulea4fe662006-03-26 05:22:17 +0000797 assert(rb->_ActualFormat);
Brian Paul13abf912006-04-13 19:17:13 +0000798 assert(rb->Width == (GLuint) width);
799 assert(rb->Height == (GLuint) height);
Brian Paul0e31e022005-12-01 00:25:00 +0000800 assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits ||
801 rb->DepthBits || rb->StencilBits || rb->IndexBits);
Brian Paulea4fe662006-03-26 05:22:17 +0000802 rb->InternalFormat = internalFormat;
Brian Paul2c6f9112005-02-24 05:47:06 +0000803 rb->_BaseFormat = baseFormat;
804 }
805 else {
806 /* Probably ran out of memory - clear the fields */
807 rb->Width = 0;
808 rb->Height = 0;
809 rb->InternalFormat = GL_NONE;
Brian Paulea4fe662006-03-26 05:22:17 +0000810 rb->_ActualFormat = GL_NONE;
Brian Paul2c6f9112005-02-24 05:47:06 +0000811 rb->_BaseFormat = GL_NONE;
Brian Paul0e31e022005-12-01 00:25:00 +0000812 rb->RedBits =
813 rb->GreenBits =
814 rb->BlueBits =
815 rb->AlphaBits =
816 rb->IndexBits =
817 rb->DepthBits =
818 rb->StencilBits = 0;
Brian Paul463642c2005-02-08 02:06:00 +0000819 }
820
Brian Paule4b23562005-05-04 20:11:35 +0000821 /*
822 test_framebuffer_completeness(ctx, fb);
823 */
Brian Paul2c6f9112005-02-24 05:47:06 +0000824 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
825 * points???
826 */
Brian Paulddc82ee2005-02-05 19:56:45 +0000827}
828
829
Brian Paul1864c7d2005-02-08 03:46:37 +0000830void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000831_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
832{
833 GET_CURRENT_CONTEXT(ctx);
834
835 ASSERT_OUTSIDE_BEGIN_END(ctx);
836
Brian Paul463642c2005-02-08 02:06:00 +0000837 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000838 _mesa_error(ctx, GL_INVALID_ENUM,
839 "glGetRenderbufferParameterivEXT(target)");
840 return;
841 }
842
Brian Paul463642c2005-02-08 02:06:00 +0000843 if (!ctx->CurrentRenderbuffer) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000844 _mesa_error(ctx, GL_INVALID_OPERATION,
845 "glGetRenderbufferParameterivEXT");
846 return;
847 }
848
Brian Paul474f28e2005-10-08 14:41:17 +0000849 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
850
Brian Paul463642c2005-02-08 02:06:00 +0000851 switch (pname) {
852 case GL_RENDERBUFFER_WIDTH_EXT:
853 *params = ctx->CurrentRenderbuffer->Width;
854 return;
855 case GL_RENDERBUFFER_HEIGHT_EXT:
856 *params = ctx->CurrentRenderbuffer->Height;
857 return;
858 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
859 *params = ctx->CurrentRenderbuffer->InternalFormat;
860 return;
Brian Paul1b939532005-05-31 23:55:21 +0000861 case GL_RENDERBUFFER_RED_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000862 *params = ctx->CurrentRenderbuffer->RedBits;
Brian Paul1b939532005-05-31 23:55:21 +0000863 break;
864 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000865 *params = ctx->CurrentRenderbuffer->GreenBits;
Brian Paul1b939532005-05-31 23:55:21 +0000866 break;
867 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000868 *params = ctx->CurrentRenderbuffer->BlueBits;
Brian Paul1b939532005-05-31 23:55:21 +0000869 break;
870 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000871 *params = ctx->CurrentRenderbuffer->AlphaBits;
Brian Paul1b939532005-05-31 23:55:21 +0000872 break;
873 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000874 *params = ctx->CurrentRenderbuffer->DepthBits;
Brian Paul1b939532005-05-31 23:55:21 +0000875 break;
876 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000877 *params = ctx->CurrentRenderbuffer->StencilBits;
Brian Paul1b939532005-05-31 23:55:21 +0000878 break;
Brian Paul463642c2005-02-08 02:06:00 +0000879 default:
880 _mesa_error(ctx, GL_INVALID_ENUM,
881 "glGetRenderbufferParameterivEXT(target)");
882 return;
883 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000884}
885
886
Brian Paul1864c7d2005-02-08 03:46:37 +0000887GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000888_mesa_IsFramebufferEXT(GLuint framebuffer)
889{
Brian Paulddc82ee2005-02-05 19:56:45 +0000890 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000891 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000892 if (framebuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000893 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000894 if (rb != NULL && rb != &DummyFramebuffer)
895 return GL_TRUE;
896 }
897 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000898}
899
900
Brian Paulea4fe662006-03-26 05:22:17 +0000901static void
902check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
903{
904 GLuint i;
905 ASSERT(ctx->Driver.RenderTexture);
906 for (i = 0; i < BUFFER_COUNT; i++) {
907 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
908 struct gl_texture_object *texObj = att->Texture;
Brian Paul9f6ff492006-03-28 15:24:50 +0000909 if (texObj
910 && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +0000911 ctx->Driver.RenderTexture(ctx, fb, att);
912 }
913 }
914}
915
916
Brian Paul0e31e022005-12-01 00:25:00 +0000917/**
918 * Examine all the framebuffer's attachments to see if any are textures.
919 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
920 * notify the device driver that the texture image may have changed.
921 */
922static void
Brian Paulea4fe662006-03-26 05:22:17 +0000923check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
Brian Paul0e31e022005-12-01 00:25:00 +0000924{
925 if (ctx->Driver.FinishRenderTexture) {
926 GLuint i;
927 for (i = 0; i < BUFFER_COUNT; i++) {
928 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
929 struct gl_texture_object *texObj = att->Texture;
930 if (texObj) {
Brian Paul519b23b2006-03-20 18:51:57 +0000931 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000932 }
933 }
934 }
935}
936
937
Brian Paul1864c7d2005-02-08 03:46:37 +0000938void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000939_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
940{
Brian Paul0bffb112005-11-08 14:45:48 +0000941 struct gl_framebuffer *newFb, *oldFb;
942 GLboolean bindReadBuf, bindDrawBuf;
Brian Paulddc82ee2005-02-05 19:56:45 +0000943 GET_CURRENT_CONTEXT(ctx);
944
945 ASSERT_OUTSIDE_BEGIN_END(ctx);
946
Brian Paulea4fe662006-03-26 05:22:17 +0000947 if (!ctx->Extensions.EXT_framebuffer_object) {
948 _mesa_error(ctx, GL_INVALID_OPERATION,
949 "glBindFramebufferEXT(unsupported)");
950 return;
951 }
952
Brian Paul0bffb112005-11-08 14:45:48 +0000953 switch (target) {
954#if FEATURE_EXT_framebuffer_blit
955 case GL_DRAW_FRAMEBUFFER_EXT:
956 if (!ctx->Extensions.EXT_framebuffer_blit) {
957 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
958 return;
959 }
960 bindDrawBuf = GL_TRUE;
961 bindReadBuf = GL_FALSE;
962 break;
963 case GL_READ_FRAMEBUFFER_EXT:
964 if (!ctx->Extensions.EXT_framebuffer_blit) {
965 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
966 return;
967 }
968 bindDrawBuf = GL_FALSE;
969 bindReadBuf = GL_TRUE;
970 break;
971#endif
972 case GL_FRAMEBUFFER_EXT:
973 bindDrawBuf = GL_TRUE;
974 bindReadBuf = GL_TRUE;
975 break;
976 default:
Brian Pauleba4ff62005-09-06 21:22:16 +0000977 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000978 return;
979 }
980
Brian Paul474f28e2005-10-08 14:41:17 +0000981 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwell5ac93f82006-11-01 14:21:57 +0000982 if (ctx->Driver.Flush) {
983 ctx->Driver.Flush(ctx);
984 }
Brian Paul3deaa012005-02-07 05:08:24 +0000985 if (framebuffer) {
Brian Paule4b23562005-05-04 20:11:35 +0000986 /* Binding a user-created framebuffer object */
Brian Paulea4fe662006-03-26 05:22:17 +0000987 newFb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000988 if (newFb == &DummyFramebuffer) {
Brian Paul923b6fc2005-02-08 04:08:56 +0000989 /* ID was reserved, but no real framebuffer object made yet */
Brian Paul1864c7d2005-02-08 03:46:37 +0000990 newFb = NULL;
991 }
Brian Paul3deaa012005-02-07 05:08:24 +0000992 if (!newFb) {
993 /* create new framebuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000994 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000995 if (!newFb) {
996 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
997 return;
998 }
Brian Paul1864c7d2005-02-08 03:46:37 +0000999 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
Brian Paul3deaa012005-02-07 05:08:24 +00001000 }
Brian Paulea4fe662006-03-26 05:22:17 +00001001 _glthread_LOCK_MUTEX(newFb->Mutex);
Brian Paul0bffb112005-11-08 14:45:48 +00001002 if (bindReadBuf)
1003 newFb->RefCount++;
1004 if (bindDrawBuf)
1005 newFb->RefCount++;
Brian Paulea4fe662006-03-26 05:22:17 +00001006 _glthread_UNLOCK_MUTEX(newFb->Mutex);
Brian Paul3deaa012005-02-07 05:08:24 +00001007 }
Brian Paul463642c2005-02-08 02:06:00 +00001008 else {
Brian Paule4b23562005-05-04 20:11:35 +00001009 /* Binding the window system framebuffer (which was originally set
1010 * with MakeCurrent).
1011 */
1012 newFb = ctx->WinSysDrawBuffer;
Brian Paul3deaa012005-02-07 05:08:24 +00001013 }
1014
Brian Paulea4fe662006-03-26 05:22:17 +00001015 ASSERT(newFb);
Brian Paul1864c7d2005-02-08 03:46:37 +00001016 ASSERT(newFb != &DummyFramebuffer);
1017
Brian Paulea4fe662006-03-26 05:22:17 +00001018 /*
1019 * XXX check if re-binding same buffer and skip some of this code.
1020 */
1021
Brian Paul0bffb112005-11-08 14:45:48 +00001022 if (bindReadBuf) {
1023 oldFb = ctx->ReadBuffer;
1024 if (oldFb && oldFb->Name != 0) {
Brian Paul7ac5b7b2006-05-20 15:08:25 +00001025 _mesa_dereference_framebuffer(&oldFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001026 }
1027 ctx->ReadBuffer = newFb;
1028 }
1029
1030 if (bindDrawBuf) {
1031 oldFb = ctx->DrawBuffer;
1032 if (oldFb && oldFb->Name != 0) {
Brian Paul0e31e022005-12-01 00:25:00 +00001033 /* check if old FB had any texture attachments */
Brian Paulea4fe662006-03-26 05:22:17 +00001034 check_end_texture_render(ctx, oldFb);
Brian Paul0e31e022005-12-01 00:25:00 +00001035 /* check if time to delete this framebuffer */
Brian Paul7ac5b7b2006-05-20 15:08:25 +00001036 _mesa_dereference_framebuffer(&oldFb);
Brian Paul0bffb112005-11-08 14:45:48 +00001037 }
1038 ctx->DrawBuffer = newFb;
Brian Paulea4fe662006-03-26 05:22:17 +00001039 if (newFb->Name != 0) {
1040 /* check if newly bound framebuffer has any texture attachments */
1041 check_begin_texture_render(ctx, newFb);
1042 }
Brian Paul0bffb112005-11-08 14:45:48 +00001043 }
Brian Paul59e0faa2006-03-15 17:48:00 +00001044
1045 if (ctx->Driver.BindFramebuffer) {
1046 ctx->Driver.BindFramebuffer(ctx, target, newFb);
1047 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001048}
1049
1050
Brian Paul1864c7d2005-02-08 03:46:37 +00001051void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001052_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1053{
1054 GLint i;
1055 GET_CURRENT_CONTEXT(ctx);
1056
1057 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001058 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001059 /* The above doesn't fully flush the drivers in the way that a
1060 * glFlush does, but that is required here:
1061 */
1062 if (ctx->Driver.Flush)
1063 ctx->Driver.Flush(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +00001064
1065 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +00001066 if (framebuffers[i] > 0) {
1067 struct gl_framebuffer *fb;
Brian Paulea4fe662006-03-26 05:22:17 +00001068 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +00001069 if (fb) {
Brian Paule4b23562005-05-04 20:11:35 +00001070 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
Brian Paul91802fd2005-10-04 16:01:02 +00001071
1072 /* check if deleting currently bound framebuffer object */
1073 if (fb == ctx->DrawBuffer) {
1074 /* bind default */
1075 ASSERT(fb->RefCount >= 2);
1076 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1077 }
1078
Brian Paul3deaa012005-02-07 05:08:24 +00001079 /* remove from hash table immediately, to free the ID */
1080 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +00001081
Brian Paul1864c7d2005-02-08 03:46:37 +00001082 if (fb != &DummyFramebuffer) {
1083 /* But the object will not be freed until it's no longer
1084 * bound in any context.
1085 */
Brian Paul7ac5b7b2006-05-20 15:08:25 +00001086 _mesa_dereference_framebuffer(&fb);
Brian Paul3deaa012005-02-07 05:08:24 +00001087 }
1088 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001089 }
1090 }
1091}
1092
1093
Brian Paul1864c7d2005-02-08 03:46:37 +00001094void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001095_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1096{
1097 GET_CURRENT_CONTEXT(ctx);
1098 GLuint first;
1099 GLint i;
1100
1101 ASSERT_OUTSIDE_BEGIN_END(ctx);
1102
1103 if (n < 0) {
1104 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1105 return;
1106 }
1107
1108 if (!framebuffers)
1109 return;
1110
1111 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1112
1113 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001114 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001115 framebuffers[i] = name;
1116 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001117 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001118 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001119 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001120 }
1121}
1122
1123
1124
Brian Paul1864c7d2005-02-08 03:46:37 +00001125GLenum GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001126_mesa_CheckFramebufferStatusEXT(GLenum target)
1127{
Brian Paul0bffb112005-11-08 14:45:48 +00001128 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001129 GET_CURRENT_CONTEXT(ctx);
1130
Brian Paule4b23562005-05-04 20:11:35 +00001131 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001132
Brian Paul0bffb112005-11-08 14:45:48 +00001133 switch (target) {
1134#if FEATURE_EXT_framebuffer_blit
1135 case GL_DRAW_FRAMEBUFFER_EXT:
1136 if (!ctx->Extensions.EXT_framebuffer_blit) {
1137 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1138 return 0;
1139 }
1140 buffer = ctx->DrawBuffer;
1141 break;
1142 case GL_READ_FRAMEBUFFER_EXT:
1143 if (!ctx->Extensions.EXT_framebuffer_blit) {
1144 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1145 return 0;
1146 }
1147 buffer = ctx->ReadBuffer;
1148 break;
1149#endif
1150 case GL_FRAMEBUFFER_EXT:
1151 buffer = ctx->DrawBuffer;
1152 break;
1153 default:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001154 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
Brian Paule4b23562005-05-04 20:11:35 +00001155 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
Brian Paulddc82ee2005-02-05 19:56:45 +00001156 }
1157
Brian Paul0bffb112005-11-08 14:45:48 +00001158 if (buffer->Name == 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001159 /* The window system / default framebuffer is always complete */
1160 return GL_FRAMEBUFFER_COMPLETE_EXT;
1161 }
1162
Brian Paul474f28e2005-10-08 14:41:17 +00001163 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1164
Brian Paul0bffb112005-11-08 14:45:48 +00001165 _mesa_test_framebuffer_completeness(ctx, buffer);
1166 return buffer->_Status;
Brian Paulddc82ee2005-02-05 19:56:45 +00001167}
1168
1169
1170
1171/**
Brian Paulea4fe662006-03-26 05:22:17 +00001172 * Common code called by glFramebufferTexture1D/2D/3DEXT().
Brian Paulddc82ee2005-02-05 19:56:45 +00001173 */
Brian Paulea4fe662006-03-26 05:22:17 +00001174static void
1175framebuffer_texture(GLuint dims, GLenum target, GLenum attachment,
1176 GLenum textarget, GLuint texture,
1177 GLint level, GLint zoffset)
Brian Paulddc82ee2005-02-05 19:56:45 +00001178{
Brian Paul2c6f9112005-02-24 05:47:06 +00001179 struct gl_renderbuffer_attachment *att;
Brian Paulea4fe662006-03-26 05:22:17 +00001180 struct gl_texture_object *texObj = NULL;
1181 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001182 GET_CURRENT_CONTEXT(ctx);
1183
1184 ASSERT_OUTSIDE_BEGIN_END(ctx);
1185
Brian Paulea4fe662006-03-26 05:22:17 +00001186 if (target != GL_FRAMEBUFFER_EXT) {
1187 _mesa_error(ctx, GL_INVALID_ENUM,
1188 "glFramebufferTexture%dDEXT(target)", dims);
Brian Paulddc82ee2005-02-05 19:56:45 +00001189 return;
Brian Paulea4fe662006-03-26 05:22:17 +00001190 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001191
Brian Paulea4fe662006-03-26 05:22:17 +00001192 fb = ctx->DrawBuffer;
1193 ASSERT(fb);
Brian Paul3deaa012005-02-07 05:08:24 +00001194
Brian Paulea4fe662006-03-26 05:22:17 +00001195 /* check framebuffer binding */
1196 if (fb->Name == 0) {
1197 _mesa_error(ctx, GL_INVALID_OPERATION,
1198 "glFramebufferTexture%dDEXT", dims);
1199 return;
1200 }
1201
1202 if (texture) {
1203 texObj = _mesa_lookup_texture(ctx, texture);
1204 }
1205
1206 /* Check dimension-dependent things */
1207 switch (dims) {
1208 case 1:
1209 if (textarget != GL_TEXTURE_1D) {
1210 _mesa_error(ctx, GL_INVALID_ENUM,
1211 "glFramebufferTexture1DEXT(textarget)");
1212 return;
1213 }
1214 if (texObj && texObj->Target != GL_TEXTURE_1D) {
1215 _mesa_error(ctx, GL_INVALID_OPERATION,
1216 "glFramebufferTexture1DEXT(texture target mismatch)");
1217 return;
1218 }
1219 break;
1220 case 2:
1221 if (textarget != GL_TEXTURE_2D &&
1222 textarget != GL_TEXTURE_RECTANGLE_ARB &&
1223 !IS_CUBE_FACE(textarget)) {
1224 _mesa_error(ctx, GL_INVALID_ENUM,
1225 "glFramebufferTexture2DEXT(textarget)");
1226 return;
1227 }
1228 if (texObj) {
1229 if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) ||
1230 (texObj->Target == GL_TEXTURE_RECTANGLE_ARB
1231 && textarget != GL_TEXTURE_RECTANGLE_ARB) ||
1232 (texObj->Target == GL_TEXTURE_CUBE_MAP
1233 && !IS_CUBE_FACE(textarget))) {
1234 _mesa_error(ctx, GL_INVALID_OPERATION,
1235 "glFramebufferTexture1DEXT(texture target mismatch)");
1236 return;
1237 }
1238 }
1239 break;
1240 case 3:
1241 if (textarget != GL_TEXTURE_3D) {
1242 _mesa_error(ctx, GL_INVALID_ENUM,
1243 "glFramebufferTexture3DEXT(textarget)");
1244 return;
1245 }
1246 if (texObj && texObj->Target != GL_TEXTURE_3D) {
1247 _mesa_error(ctx, GL_INVALID_OPERATION,
1248 "glFramebufferTexture3DEXT(texture target mismatch)");
1249 return;
1250 }
1251 {
1252 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1253 if (zoffset < 0 || zoffset >= maxSize) {
1254 _mesa_error(ctx, GL_INVALID_VALUE,
1255 "glFramebufferTexture3DEXT(zoffset)");
1256 return;
1257 }
1258 }
1259 break;
1260 default:
1261 _mesa_problem(ctx, "Unexpected dims in error_check_framebuffer_texture");
1262 return;
1263 }
1264
1265 if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) {
1266 _mesa_error(ctx, GL_INVALID_VALUE,
1267 "glFramebufferTexture%dDEXT(level)", dims);
1268 return;
1269 }
1270
1271 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001272 if (att == NULL) {
1273 _mesa_error(ctx, GL_INVALID_ENUM,
Brian Paulea4fe662006-03-26 05:22:17 +00001274 "glFramebufferTexture%dDEXT(attachment)", dims);
Brian Paul3deaa012005-02-07 05:08:24 +00001275 return;
1276 }
1277
Brian Paul474f28e2005-10-08 14:41:17 +00001278 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001279 /* The above doesn't fully flush the drivers in the way that a
1280 * glFlush does, but that is required here:
1281 */
1282 if (ctx->Driver.Flush)
1283 ctx->Driver.Flush(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001284
Brian Paulea4fe662006-03-26 05:22:17 +00001285 _glthread_LOCK_MUTEX(fb->Mutex);
1286 if (texObj) {
1287 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1288 level, zoffset);
Brian Paul3deaa012005-02-07 05:08:24 +00001289 }
1290 else {
Brian Paul519b23b2006-03-20 18:51:57 +00001291 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +00001292 }
Brian Paulea4fe662006-03-26 05:22:17 +00001293 _glthread_UNLOCK_MUTEX(fb->Mutex);
1294}
1295
1296
1297
1298void GLAPIENTRY
1299_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1300 GLenum textarget, GLuint texture, GLint level)
1301{
1302 const GLint zoffset = 0;
1303 framebuffer_texture(1, target, attachment, textarget, texture,
1304 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00001305}
1306
1307
Brian Paul1864c7d2005-02-08 03:46:37 +00001308void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001309_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1310 GLenum textarget, GLuint texture, GLint level)
1311{
Brian Paulea4fe662006-03-26 05:22:17 +00001312 const GLint zoffset = 0;
1313 framebuffer_texture(2, target, attachment, textarget, texture,
1314 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00001315}
1316
1317
Brian Paul1864c7d2005-02-08 03:46:37 +00001318void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001319_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1320 GLenum textarget, GLuint texture,
1321 GLint level, GLint zoffset)
1322{
Brian Paulea4fe662006-03-26 05:22:17 +00001323 framebuffer_texture(3, target, attachment, textarget, texture,
1324 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00001325}
1326
1327
Brian Paulea4fe662006-03-26 05:22:17 +00001328
Brian Paul1864c7d2005-02-08 03:46:37 +00001329void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001330_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1331 GLenum renderbufferTarget,
1332 GLuint renderbuffer)
1333{
Brian Paul2c6f9112005-02-24 05:47:06 +00001334 struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001335 struct gl_framebuffer *fb;
Brian Paule4b23562005-05-04 20:11:35 +00001336 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001337 GET_CURRENT_CONTEXT(ctx);
1338
1339 ASSERT_OUTSIDE_BEGIN_END(ctx);
1340
Brian Paul0bffb112005-11-08 14:45:48 +00001341 switch (target) {
1342#if FEATURE_EXT_framebuffer_blit
1343 case GL_DRAW_FRAMEBUFFER_EXT:
1344 if (!ctx->Extensions.EXT_framebuffer_blit) {
1345 _mesa_error(ctx, GL_INVALID_ENUM,
1346 "glFramebufferRenderbufferEXT(target)");
1347 return;
1348 }
1349 fb = ctx->DrawBuffer;
1350 break;
1351 case GL_READ_FRAMEBUFFER_EXT:
1352 if (!ctx->Extensions.EXT_framebuffer_blit) {
1353 _mesa_error(ctx, GL_INVALID_ENUM,
1354 "glFramebufferRenderbufferEXT(target)");
1355 return;
1356 }
1357 fb = ctx->ReadBuffer;
1358 break;
1359#endif
1360 case GL_FRAMEBUFFER_EXT:
1361 fb = ctx->DrawBuffer;
1362 break;
1363 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001364 _mesa_error(ctx, GL_INVALID_ENUM,
1365 "glFramebufferRenderbufferEXT(target)");
1366 return;
1367 }
1368
Brian Paul3deaa012005-02-07 05:08:24 +00001369 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
Brian Paule4b23562005-05-04 20:11:35 +00001370 _mesa_error(ctx, GL_INVALID_ENUM,
1371 "glFramebufferRenderbufferEXT(renderbufferTarget)");
Brian Paul3deaa012005-02-07 05:08:24 +00001372 return;
1373 }
1374
Brian Paul0bffb112005-11-08 14:45:48 +00001375 if (fb->Name == 0) {
Brian Paulab8ef282005-09-07 23:21:59 +00001376 /* Can't attach new renderbuffers to a window system framebuffer */
Brian Paul3deaa012005-02-07 05:08:24 +00001377 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1378 return;
1379 }
1380
Brian Paul84716042005-11-16 04:05:54 +00001381 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001382 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001383 _mesa_error(ctx, GL_INVALID_ENUM,
1384 "glFramebufferRenderbufferEXT(attachment)");
1385 return;
1386 }
1387
Brian Paul1864c7d2005-02-08 03:46:37 +00001388 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00001389 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001390 if (!rb) {
Brian Paule4b23562005-05-04 20:11:35 +00001391 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul1864c7d2005-02-08 03:46:37 +00001392 "glFramebufferRenderbufferEXT(renderbuffer)");
1393 return;
1394 }
Brian Paul1864c7d2005-02-08 03:46:37 +00001395 }
1396 else {
Brian Paule4b23562005-05-04 20:11:35 +00001397 /* remove renderbuffer attachment */
1398 rb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001399 }
Brian Paule4b23562005-05-04 20:11:35 +00001400
Brian Paul474f28e2005-10-08 14:41:17 +00001401 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001402 /* The above doesn't fully flush the drivers in the way that a
1403 * glFlush does, but that is required here:
1404 */
1405 if (ctx->Driver.Flush)
1406 ctx->Driver.Flush(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001407
Brian Paule4b23562005-05-04 20:11:35 +00001408 assert(ctx->Driver.FramebufferRenderbuffer);
Brian Paul84716042005-11-16 04:05:54 +00001409 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
Brian Paul2e019182006-03-07 01:43:52 +00001410
1411 /* Some subsequent GL commands may depend on the framebuffer's visual
1412 * after the binding is updated. Update visual info now.
1413 */
1414 _mesa_update_framebuffer_visual(fb);
Brian Paulddc82ee2005-02-05 19:56:45 +00001415}
1416
1417
Brian Paul1864c7d2005-02-08 03:46:37 +00001418void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001419_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1420 GLenum pname, GLint *params)
1421{
Brian Paul2c6f9112005-02-24 05:47:06 +00001422 const struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001423 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001424 GET_CURRENT_CONTEXT(ctx);
1425
1426 ASSERT_OUTSIDE_BEGIN_END(ctx);
1427
Brian Paul0bffb112005-11-08 14:45:48 +00001428 switch (target) {
1429#if FEATURE_EXT_framebuffer_blit
1430 case GL_DRAW_FRAMEBUFFER_EXT:
1431 if (!ctx->Extensions.EXT_framebuffer_blit) {
1432 _mesa_error(ctx, GL_INVALID_ENUM,
1433 "glGetFramebufferAttachmentParameterivEXT(target)");
1434 return;
1435 }
1436 buffer = ctx->DrawBuffer;
1437 break;
1438 case GL_READ_FRAMEBUFFER_EXT:
1439 if (!ctx->Extensions.EXT_framebuffer_blit) {
1440 _mesa_error(ctx, GL_INVALID_ENUM,
1441 "glGetFramebufferAttachmentParameterivEXT(target)");
1442 return;
1443 }
1444 buffer = ctx->ReadBuffer;
1445 break;
1446#endif
1447 case GL_FRAMEBUFFER_EXT:
1448 buffer = ctx->DrawBuffer;
1449 break;
1450 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001451 _mesa_error(ctx, GL_INVALID_ENUM,
1452 "glGetFramebufferAttachmentParameterivEXT(target)");
1453 return;
1454 }
1455
Brian Paul0bffb112005-11-08 14:45:48 +00001456 if (buffer->Name == 0) {
Brian Paul3deaa012005-02-07 05:08:24 +00001457 _mesa_error(ctx, GL_INVALID_OPERATION,
1458 "glGetFramebufferAttachmentParameterivEXT");
1459 return;
1460 }
1461
Brian Paul84716042005-11-16 04:05:54 +00001462 att = _mesa_get_attachment(ctx, buffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001463 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001464 _mesa_error(ctx, GL_INVALID_ENUM,
1465 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1466 return;
1467 }
1468
Brian Paul474f28e2005-10-08 14:41:17 +00001469 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001470 /* The above doesn't fully flush the drivers in the way that a
1471 * glFlush does, but that is required here:
1472 */
1473 if (ctx->Driver.Flush)
1474 ctx->Driver.Flush(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001475
Brian Paulddc82ee2005-02-05 19:56:45 +00001476 switch (pname) {
1477 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001478 *params = att->Type;
1479 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001480 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001481 if (att->Type == GL_RENDERBUFFER_EXT) {
1482 *params = att->Renderbuffer->Name;
1483 }
1484 else if (att->Type == GL_TEXTURE) {
1485 *params = att->Texture->Name;
1486 }
1487 else {
1488 _mesa_error(ctx, GL_INVALID_ENUM,
1489 "glGetFramebufferAttachmentParameterivEXT(pname)");
1490 }
1491 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001492 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001493 if (att->Type == GL_TEXTURE) {
1494 *params = att->TextureLevel;
1495 }
1496 else {
1497 _mesa_error(ctx, GL_INVALID_ENUM,
1498 "glGetFramebufferAttachmentParameterivEXT(pname)");
1499 }
1500 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001501 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001502 if (att->Type == GL_TEXTURE) {
1503 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1504 }
1505 else {
1506 _mesa_error(ctx, GL_INVALID_ENUM,
1507 "glGetFramebufferAttachmentParameterivEXT(pname)");
1508 }
1509 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001510 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001511 if (att->Type == GL_TEXTURE) {
1512 *params = att->Zoffset;
1513 }
1514 else {
1515 _mesa_error(ctx, GL_INVALID_ENUM,
1516 "glGetFramebufferAttachmentParameterivEXT(pname)");
1517 }
1518 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001519 default:
1520 _mesa_error(ctx, GL_INVALID_ENUM,
1521 "glGetFramebufferAttachmentParameterivEXT(pname)");
1522 return;
1523 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001524}
1525
1526
Brian Paul1864c7d2005-02-08 03:46:37 +00001527void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001528_mesa_GenerateMipmapEXT(GLenum target)
1529{
Brian Paul463642c2005-02-08 02:06:00 +00001530 struct gl_texture_unit *texUnit;
1531 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001532 GET_CURRENT_CONTEXT(ctx);
1533
1534 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001535 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00001536
1537 switch (target) {
1538 case GL_TEXTURE_1D:
1539 case GL_TEXTURE_2D:
Brian Paulddc82ee2005-02-05 19:56:45 +00001540 case GL_TEXTURE_3D:
Brian Paul463642c2005-02-08 02:06:00 +00001541 case GL_TEXTURE_CUBE_MAP:
Brian Paul1b939532005-05-31 23:55:21 +00001542 /* OK, legal value */
Brian Paulddc82ee2005-02-05 19:56:45 +00001543 break;
1544 default:
1545 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
1546 return;
1547 }
1548
Brian Paul463642c2005-02-08 02:06:00 +00001549 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1550 texObj = _mesa_select_tex_object(ctx, texUnit, target);
1551
1552 /* XXX this might not handle cube maps correctly */
Keith Whitwell5ac93f82006-11-01 14:21:57 +00001553 _mesa_lock_texture(ctx, texObj);
Brian Paul463642c2005-02-08 02:06:00 +00001554 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
Keith Whitwell5ac93f82006-11-01 14:21:57 +00001555 _mesa_unlock_texture(ctx, texObj);
Brian Paulddc82ee2005-02-05 19:56:45 +00001556}
Brian Paul0bffb112005-11-08 14:45:48 +00001557
1558
1559#if FEATURE_EXT_framebuffer_blit
1560void GLAPIENTRY
1561_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
1562 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
1563 GLbitfield mask, GLenum filter)
1564{
1565 GET_CURRENT_CONTEXT(ctx);
1566
1567 ASSERT_OUTSIDE_BEGIN_END(ctx);
1568 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1569
Brian Paul99745402006-03-01 02:02:43 +00001570 if (ctx->NewState) {
1571 _mesa_update_state(ctx);
1572 }
1573
1574 if (!ctx->ReadBuffer) {
1575 /* XXX */
1576 }
1577
Brian Paul0bffb112005-11-08 14:45:48 +00001578 /* check for complete framebuffers */
1579 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
1580 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1581 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
1582 "glBlitFramebufferEXT(incomplete draw/read buffers)");
1583 return;
1584 }
1585
Brian Paul99745402006-03-01 02:02:43 +00001586 if (filter != GL_NEAREST && filter != GL_LINEAR) {
1587 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
1588 return;
1589 }
1590
1591 if (mask & ~(GL_COLOR_BUFFER_BIT |
1592 GL_DEPTH_BUFFER_BIT |
1593 GL_STENCIL_BUFFER_BIT)) {
1594 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
1595 return;
1596 }
1597
Brian Paul0bffb112005-11-08 14:45:48 +00001598 /* depth/stencil must be blitted with nearest filtering */
1599 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
1600 && filter != GL_NEAREST) {
1601 _mesa_error(ctx, GL_INVALID_OPERATION,
1602 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
1603 return;
1604 }
1605
Brian Paul99745402006-03-01 02:02:43 +00001606 if (mask & GL_STENCIL_BUFFER_BIT) {
1607 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_StencilBuffer;
1608 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_StencilBuffer;
1609 if (readRb->StencilBits != drawRb->StencilBits) {
1610 _mesa_error(ctx, GL_INVALID_OPERATION,
1611 "glBlitFramebufferEXT(stencil buffer size mismatch");
1612 return;
1613 }
1614 }
1615
1616 if (mask & GL_DEPTH_BUFFER_BIT) {
1617 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_DepthBuffer;
1618 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_DepthBuffer;
1619 if (readRb->DepthBits != drawRb->DepthBits) {
1620 _mesa_error(ctx, GL_INVALID_OPERATION,
1621 "glBlitFramebufferEXT(depth buffer size mismatch");
1622 return;
1623 }
Brian Paul0bffb112005-11-08 14:45:48 +00001624 }
1625
1626 if (!ctx->Extensions.EXT_framebuffer_blit) {
1627 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
1628 return;
1629 }
1630
1631 ASSERT(ctx->Driver.BlitFramebuffer);
1632 ctx->Driver.BlitFramebuffer(ctx,
1633 srcX0, srcY0, srcX1, srcY1,
1634 dstX0, dstY0, dstX1, dstY1,
1635 mask, filter);
1636}
1637#endif /* FEATURE_EXT_framebuffer_blit */