blob: 43e4793d55412373bb868d453b7aebd027401c3f [file] [log] [blame]
Brian Paulddc82ee2005-02-05 19:56:45 +00001/*
2 * Mesa 3-D graphics library
Brian Paul1ad7b992005-09-28 02:29:50 +00003 * Version: 6.5
Brian Paulddc82ee2005-02-05 19:56:45 +00004 *
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
6 *
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 Paule4b23562005-05-04 20:11:35 +000036#include "renderbuffer.h"
Brian Paul463642c2005-02-08 02:06:00 +000037#include "teximage.h"
38#include "texstore.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000039
40
Brian Paul0bffb112005-11-08 14:45:48 +000041/* XXX temporarily here */
42#define GL_READ_FRAMEBUFFER_EXT 0x90
43#define GL_DRAW_FRAMEBUFFER_EXT 0x9a
44#define GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_EXT
45#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x9b
46
47
Brian Pauld9468c92005-02-10 16:08:07 +000048/**
49 * Notes:
50 *
51 * None of the GL_EXT_framebuffer_object functions are compiled into
52 * display lists.
53 */
54
55
56
Brian Paul923b6fc2005-02-08 04:08:56 +000057/*
58 * When glGenRender/FramebuffersEXT() is called we insert pointers to
59 * these placeholder objects into the hash table.
60 * Later, when the object ID is first bound, we replace the placeholder
61 * with the real frame/renderbuffer.
62 */
Brian Paul2c6f9112005-02-24 05:47:06 +000063static struct gl_framebuffer DummyFramebuffer;
64static struct gl_renderbuffer DummyRenderbuffer;
Brian Paul1864c7d2005-02-08 03:46:37 +000065
66
Brian Paul3deaa012005-02-07 05:08:24 +000067#define IS_CUBE_FACE(TARGET) \
68 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
69 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
Brian Paulddc82ee2005-02-05 19:56:45 +000070
71
72/**
Brian Paul2c6f9112005-02-24 05:47:06 +000073 * Helper routine for getting a gl_renderbuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +000074 */
Brian Paul2c6f9112005-02-24 05:47:06 +000075static struct gl_renderbuffer *
Brian Paul3deaa012005-02-07 05:08:24 +000076lookup_renderbuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +000077{
Brian Paul2c6f9112005-02-24 05:47:06 +000078 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +000079
Brian Paul1864c7d2005-02-08 03:46:37 +000080 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +000081 return NULL;
82
Brian Paul2c6f9112005-02-24 05:47:06 +000083 rb = (struct gl_renderbuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +000084 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
85 return rb;
86}
87
88
89/**
Brian Paul2c6f9112005-02-24 05:47:06 +000090 * Helper routine for getting a gl_framebuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +000091 */
Brian Paul2c6f9112005-02-24 05:47:06 +000092static struct gl_framebuffer *
Brian Paul3deaa012005-02-07 05:08:24 +000093lookup_framebuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +000094{
Brian Paul2c6f9112005-02-24 05:47:06 +000095 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +000096
Brian Paul1864c7d2005-02-08 03:46:37 +000097 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +000098 return NULL;
99
Brian Paul2c6f9112005-02-24 05:47:06 +0000100 fb = (struct gl_framebuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000101 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
Brian Paul463642c2005-02-08 02:06:00 +0000102 return fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000103}
104
105
106/**
Brian Pauld9468c92005-02-10 16:08:07 +0000107 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
Brian Paul2c6f9112005-02-24 05:47:06 +0000108 * gl_renderbuffer_attachment object.
Brian Pauld9468c92005-02-10 16:08:07 +0000109 */
Brian Paul84716042005-11-16 04:05:54 +0000110struct gl_renderbuffer_attachment *
111_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
112 GLenum attachment)
Brian Paul3deaa012005-02-07 05:08:24 +0000113{
114 GLuint i;
115
116 switch (attachment) {
117 case GL_COLOR_ATTACHMENT0_EXT:
118 case GL_COLOR_ATTACHMENT1_EXT:
119 case GL_COLOR_ATTACHMENT2_EXT:
120 case GL_COLOR_ATTACHMENT3_EXT:
121 case GL_COLOR_ATTACHMENT4_EXT:
122 case GL_COLOR_ATTACHMENT5_EXT:
123 case GL_COLOR_ATTACHMENT6_EXT:
124 case GL_COLOR_ATTACHMENT7_EXT:
125 case GL_COLOR_ATTACHMENT8_EXT:
126 case GL_COLOR_ATTACHMENT9_EXT:
127 case GL_COLOR_ATTACHMENT10_EXT:
128 case GL_COLOR_ATTACHMENT11_EXT:
129 case GL_COLOR_ATTACHMENT12_EXT:
130 case GL_COLOR_ATTACHMENT13_EXT:
131 case GL_COLOR_ATTACHMENT14_EXT:
132 case GL_COLOR_ATTACHMENT15_EXT:
133 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
134 if (i >= ctx->Const.MaxColorAttachments) {
135 return NULL;
136 }
Brian Paule4b23562005-05-04 20:11:35 +0000137 return &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paul3deaa012005-02-07 05:08:24 +0000138 case GL_DEPTH_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000139 return &fb->Attachment[BUFFER_DEPTH];
Brian Paul3deaa012005-02-07 05:08:24 +0000140 case GL_STENCIL_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000141 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul3deaa012005-02-07 05:08:24 +0000142 default:
143 return NULL;
144 }
145}
146
147
Brian Pauld9468c92005-02-10 16:08:07 +0000148/**
149 * Remove any texture or renderbuffer attached to the given attachment
150 * point. Update reference counts, etc.
151 */
Brian Paule4b23562005-05-04 20:11:35 +0000152void
153_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
Brian Paul3deaa012005-02-07 05:08:24 +0000154{
155 if (att->Type == GL_TEXTURE) {
156 ASSERT(att->Texture);
Brian Paule4b23562005-05-04 20:11:35 +0000157 if (att->Renderbuffer) {
158 /* delete/remove the 'wrapper' renderbuffer */
159 /* XXX do we really want to do this??? */
160 att->Renderbuffer->Delete(att->Renderbuffer);
161 att->Renderbuffer = NULL;
162 }
Brian Paul3deaa012005-02-07 05:08:24 +0000163 att->Texture->RefCount--;
164 if (att->Texture->RefCount == 0) {
165 ctx->Driver.DeleteTexture(ctx, att->Texture);
166 }
167 att->Texture = NULL;
168 }
169 else if (att->Type == GL_RENDERBUFFER_EXT) {
170 ASSERT(att->Renderbuffer);
171 ASSERT(!att->Texture);
172 att->Renderbuffer->RefCount--;
173 if (att->Renderbuffer->RefCount == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000174 att->Renderbuffer->Delete(att->Renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000175 }
176 att->Renderbuffer = NULL;
177 }
178 att->Type = GL_NONE;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000179 att->Complete = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +0000180}
181
182
Brian Pauld9468c92005-02-10 16:08:07 +0000183/**
184 * Bind a texture object to an attachment point.
185 * The previous binding, if any, will be removed first.
186 */
Brian Paule4b23562005-05-04 20:11:35 +0000187void
188_mesa_set_texture_attachment(GLcontext *ctx,
189 struct gl_renderbuffer_attachment *att,
190 struct gl_texture_object *texObj,
191 GLenum texTarget, GLuint level, GLuint zoffset)
Brian Paul3deaa012005-02-07 05:08:24 +0000192{
Brian Paule4b23562005-05-04 20:11:35 +0000193 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000194 att->Type = GL_TEXTURE;
195 att->Texture = texObj;
196 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 Paule4b23562005-05-04 20:11:35 +0000205
Brian Paul3deaa012005-02-07 05:08:24 +0000206 texObj->RefCount++;
Brian Paul2c6f9112005-02-24 05:47:06 +0000207
208 /* XXX when we attach to a texture, we should probably set the
209 * att->Renderbuffer pointer to a "wrapper renderbuffer" which
210 * makes the texture image look like renderbuffer.
211 */
Brian Paul3deaa012005-02-07 05:08:24 +0000212}
213
214
Brian Pauld9468c92005-02-10 16:08:07 +0000215/**
216 * Bind a renderbuffer to an attachment point.
217 * The previous binding, if any, will be removed first.
218 */
Brian Paule4b23562005-05-04 20:11:35 +0000219void
220_mesa_set_renderbuffer_attachment(GLcontext *ctx,
221 struct gl_renderbuffer_attachment *att,
222 struct gl_renderbuffer *rb)
Brian Paul3deaa012005-02-07 05:08:24 +0000223{
Brian Paule4b23562005-05-04 20:11:35 +0000224 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000225 att->Type = GL_RENDERBUFFER_EXT;
226 att->Renderbuffer = rb;
Brian Paul2c6f9112005-02-24 05:47:06 +0000227 att->Texture = NULL; /* just to be safe */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000228 att->Complete = GL_FALSE;
Brian Paul3deaa012005-02-07 05:08:24 +0000229 rb->RefCount++;
230}
231
Brian Paulddc82ee2005-02-05 19:56:45 +0000232
Brian Paulf0bbbf62005-02-09 03:50:30 +0000233/**
Brian Paule4b23562005-05-04 20:11:35 +0000234 * Fallback for ctx->Driver.FramebufferRenderbuffer()
Brian Paul84716042005-11-16 04:05:54 +0000235 * Attach a renderbuffer object to a framebuffer object.
Brian Paule4b23562005-05-04 20:11:35 +0000236 */
237void
Brian Paul84716042005-11-16 04:05:54 +0000238_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
239 GLenum attachment, struct gl_renderbuffer *rb)
Brian Paule4b23562005-05-04 20:11:35 +0000240{
Brian Paul84716042005-11-16 04:05:54 +0000241 struct gl_renderbuffer_attachment *att;
242
243 att = _mesa_get_attachment(ctx, fb, attachment);
244 ASSERT(att);
245
Brian Paule4b23562005-05-04 20:11:35 +0000246 if (rb) {
247 _mesa_set_renderbuffer_attachment(ctx, att, rb);
248 }
249 else {
250 _mesa_remove_attachment(ctx, att);
251 }
252}
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 Paulf0bbbf62005-02-09 03:50:30 +0000321 if (att->Renderbuffer->Width < 1 || att->Renderbuffer->Height < 1) {
322 att->Complete = GL_FALSE;
323 return;
324 }
325 if (format == GL_COLOR) {
326 if (att->Renderbuffer->_BaseFormat != GL_RGB &&
327 att->Renderbuffer->_BaseFormat != GL_RGBA) {
328 att->Complete = GL_FALSE;
329 return;
330 }
331 }
332 else if (format == GL_DEPTH) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000333 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) {
334 /* OK */
335 }
336 else if (ctx->Extensions.EXT_packed_depth_stencil &&
337 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
338 /* OK */
339 }
340 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000341 att->Complete = GL_FALSE;
342 return;
343 }
344 }
345 else {
346 assert(format == GL_STENCIL);
Brian Paul1ad7b992005-09-28 02:29:50 +0000347 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) {
348 /* OK */
349 }
350 else if (ctx->Extensions.EXT_packed_depth_stencil &&
351 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
352 /* OK */
353 }
354 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000355 att->Complete = GL_FALSE;
356 return;
357 }
358 }
359 }
Brian Paule4b23562005-05-04 20:11:35 +0000360 else {
361 ASSERT(att->Type == GL_NONE);
362 /* complete */
363 return;
364 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000365}
366
367
368/**
369 * Test if the given framebuffer object is complete and update its
370 * Status field with the results.
Brian Paule4b23562005-05-04 20:11:35 +0000371 * Also update the framebuffer's Width and Height fields if the
372 * framebuffer is complete.
Brian Paulf0bbbf62005-02-09 03:50:30 +0000373 */
Brian Paule4b23562005-05-04 20:11:35 +0000374void
375_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000376{
Brian Paul6c0c9172005-02-27 16:23:41 +0000377 GLuint numImages, width = 0, height = 0;
378 GLenum intFormat = GL_NONE;
Brian Paule4b23562005-05-04 20:11:35 +0000379 GLuint w = 0, h = 0;
380 GLint i;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000381
Brian Paulc7264412005-06-01 00:50:23 +0000382 assert(fb->Name != 0);
383
Brian Paulf0bbbf62005-02-09 03:50:30 +0000384 numImages = 0;
Brian Paule4b23562005-05-04 20:11:35 +0000385 fb->Width = 0;
386 fb->Height = 0;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000387
388 /* Start at -2 to more easily loop over all attachment points */
Brian Paule4b23562005-05-04 20:11:35 +0000389 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000390 struct gl_renderbuffer_attachment *att;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000391 GLenum f;
392
393 if (i == -2) {
Brian Paule4b23562005-05-04 20:11:35 +0000394 att = &fb->Attachment[BUFFER_DEPTH];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000395 test_attachment_completeness(ctx, GL_DEPTH, att);
396 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000397 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000398 return;
399 }
400 }
401 else if (i == -1) {
Brian Paule4b23562005-05-04 20:11:35 +0000402 att = &fb->Attachment[BUFFER_STENCIL];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000403 test_attachment_completeness(ctx, GL_STENCIL, att);
404 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000405 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000406 return;
407 }
408 }
409 else {
Brian Paule4b23562005-05-04 20:11:35 +0000410 att = &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000411 test_attachment_completeness(ctx, GL_COLOR, att);
412 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000413 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000414 return;
415 }
416 }
417
418 if (att->Type == GL_TEXTURE) {
Brian Paula9fc8ba2005-10-05 01:48:07 +0000419 const struct gl_texture_image *texImg
420 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
421 w = texImg->Width;
422 h = texImg->Height;
423 f = texImg->_BaseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000424 numImages++;
Brian Pauled7f3ae2005-06-07 15:03:40 +0000425 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000426 /* XXX need GL_DEPTH_STENCIL_EXT test? */
Brian Pauled7f3ae2005-06-07 15:03:40 +0000427 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
428 return;
429 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000430 }
431 else if (att->Type == GL_RENDERBUFFER_EXT) {
432 w = att->Renderbuffer->Width;
433 h = att->Renderbuffer->Height;
434 f = att->Renderbuffer->InternalFormat;
435 numImages++;
436 }
437 else {
438 assert(att->Type == GL_NONE);
439 continue;
440 }
441
442 if (numImages == 1) {
443 /* set required width, height and format */
444 width = w;
445 height = h;
446 if (i >= 0)
447 intFormat = f;
448 }
449 else {
450 /* check that width, height, format are same */
451 if (w != width || h != height) {
Brian Paule4b23562005-05-04 20:11:35 +0000452 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000453 return;
454 }
Brian Paule4b23562005-05-04 20:11:35 +0000455 if (intFormat != GL_NONE && f != intFormat) {
456 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000457 return;
458 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000459 }
460 }
461
462 /* Check that all DrawBuffers are present */
463 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
Brian Paule4b23562005-05-04 20:11:35 +0000464 if (fb->ColorDrawBuffer[i] != GL_NONE) {
465 const struct gl_renderbuffer_attachment *att
Brian Paul84716042005-11-16 04:05:54 +0000466 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[i]);
Brian Paule4b23562005-05-04 20:11:35 +0000467 assert(att);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000468 if (att->Type == GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000469 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000470 return;
471 }
472 }
473 }
474
475 /* Check that the ReadBuffer is present */
Brian Paule4b23562005-05-04 20:11:35 +0000476 if (fb->ColorReadBuffer != GL_NONE) {
477 const struct gl_renderbuffer_attachment *att
Brian Paul84716042005-11-16 04:05:54 +0000478 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
Brian Paule4b23562005-05-04 20:11:35 +0000479 assert(att);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000480 if (att->Type == GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000481 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000482 return;
483 }
484 }
485
Brian Paul1ad7b992005-09-28 02:29:50 +0000486 /* Check if any renderbuffer is attached more than once.
487 * Note that there's one exception: a GL_DEPTH_STENCIL renderbuffer can be
488 * bound to both the stencil and depth attachment points at the same time.
489 */
Brian Paulc7264412005-06-01 00:50:23 +0000490 for (i = 0; i < BUFFER_COUNT - 1; i++) {
491 struct gl_renderbuffer *rb_i = fb->Attachment[i].Renderbuffer;
492 if (rb_i) {
493 GLint j;
494 for (j = i + 1; j < BUFFER_COUNT; j++) {
495 struct gl_renderbuffer *rb_j = fb->Attachment[j].Renderbuffer;
Brian Paul1ad7b992005-09-28 02:29:50 +0000496 if (rb_i == rb_j && rb_i->_BaseFormat != GL_DEPTH_STENCIL_EXT) {
Brian Paulc7264412005-06-01 00:50:23 +0000497 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT;
498 return;
499 }
500 }
501 }
502 }
503
504
Brian Paulf0bbbf62005-02-09 03:50:30 +0000505 if (numImages == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000506 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000507 return;
508 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000509
Brian Paule4b23562005-05-04 20:11:35 +0000510 /*
511 * If we get here, the framebuffer is complete!
512 */
513 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
514 fb->Width = w;
515 fb->Height = h;
516}
Brian Paulf0bbbf62005-02-09 03:50:30 +0000517
518
Brian Paul1864c7d2005-02-08 03:46:37 +0000519GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000520_mesa_IsRenderbufferEXT(GLuint renderbuffer)
521{
Brian Paulddc82ee2005-02-05 19:56:45 +0000522 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000523 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000524 if (renderbuffer) {
525 struct gl_renderbuffer *rb = lookup_renderbuffer(ctx, renderbuffer);
526 if (rb != NULL && rb != &DummyRenderbuffer)
527 return GL_TRUE;
528 }
529 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000530}
531
532
Brian Paul1864c7d2005-02-08 03:46:37 +0000533void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000534_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
535{
Brian Paul2c6f9112005-02-24 05:47:06 +0000536 struct gl_renderbuffer *newRb, *oldRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000537 GET_CURRENT_CONTEXT(ctx);
538
539 ASSERT_OUTSIDE_BEGIN_END(ctx);
540
Brian Paul3deaa012005-02-07 05:08:24 +0000541 if (target != GL_RENDERBUFFER_EXT) {
542 _mesa_error(ctx, GL_INVALID_ENUM,
543 "glBindRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000544 return;
545 }
546
Brian Paul474f28e2005-10-08 14:41:17 +0000547 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
548
Brian Paul3deaa012005-02-07 05:08:24 +0000549 if (renderbuffer) {
550 newRb = lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000551 if (newRb == &DummyRenderbuffer) {
552 /* ID was reserved, but no real renderbuffer object made yet */
553 newRb = NULL;
554 }
Brian Paul3deaa012005-02-07 05:08:24 +0000555 if (!newRb) {
556 /* create new renderbuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000557 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000558 if (!newRb) {
559 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
560 return;
561 }
Brian Paul2c6f9112005-02-24 05:47:06 +0000562 ASSERT(newRb->AllocStorage);
Brian Paul1864c7d2005-02-08 03:46:37 +0000563 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
Brian Paul3deaa012005-02-07 05:08:24 +0000564 }
565 newRb->RefCount++;
Brian Paulddc82ee2005-02-05 19:56:45 +0000566 }
Brian Paul463642c2005-02-08 02:06:00 +0000567 else {
568 newRb = NULL;
569 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000570
Brian Paul3deaa012005-02-07 05:08:24 +0000571 oldRb = ctx->CurrentRenderbuffer;
572 if (oldRb) {
573 oldRb->RefCount--;
574 if (oldRb->RefCount == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000575 oldRb->Delete(oldRb);
Brian Paul3deaa012005-02-07 05:08:24 +0000576 }
577 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000578
Brian Paul1864c7d2005-02-08 03:46:37 +0000579 ASSERT(newRb != &DummyRenderbuffer);
580
Brian Paul3deaa012005-02-07 05:08:24 +0000581 ctx->CurrentRenderbuffer = newRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000582}
583
584
Brian Paul1864c7d2005-02-08 03:46:37 +0000585void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000586_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
587{
588 GLint i;
589 GET_CURRENT_CONTEXT(ctx);
590
591 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000592 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000593
594 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000595 if (renderbuffers[i] > 0) {
596 struct gl_renderbuffer *rb;
Brian Paul3deaa012005-02-07 05:08:24 +0000597 rb = lookup_renderbuffer(ctx, renderbuffers[i]);
598 if (rb) {
Brian Paul91802fd2005-10-04 16:01:02 +0000599 /* check if deleting currently bound renderbuffer object */
600 if (rb == ctx->CurrentRenderbuffer) {
601 /* bind default */
602 ASSERT(rb->RefCount >= 2);
603 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
604 }
605
Brian Paul3deaa012005-02-07 05:08:24 +0000606 /* remove from hash table immediately, to free the ID */
607 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +0000608
Brian Paul1864c7d2005-02-08 03:46:37 +0000609 if (rb != &DummyRenderbuffer) {
610 /* But the object will not be freed until it's no longer
611 * bound in any context.
612 */
613 rb->RefCount--;
614 if (rb->RefCount == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000615 rb->Delete(rb);
Brian Paul1864c7d2005-02-08 03:46:37 +0000616 }
Brian Paul3deaa012005-02-07 05:08:24 +0000617 }
618 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000619 }
620 }
621}
622
623
Brian Paul1864c7d2005-02-08 03:46:37 +0000624void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000625_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
626{
627 GET_CURRENT_CONTEXT(ctx);
628 GLuint first;
629 GLint i;
630
631 ASSERT_OUTSIDE_BEGIN_END(ctx);
632
633 if (n < 0) {
634 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
635 return;
636 }
637
638 if (!renderbuffers)
639 return;
640
641 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
642
643 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000644 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000645 renderbuffers[i] = name;
Brian Paul1864c7d2005-02-08 03:46:37 +0000646 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +0000647 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +0000648 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +0000649 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +0000650 }
651}
652
653
Brian Pauld9468c92005-02-10 16:08:07 +0000654/**
655 * Given an internal format token for a render buffer, return the
656 * corresponding base format.
657 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
Brian Paul1ad7b992005-09-28 02:29:50 +0000658 * GL_DEPTH_STENCIL_EXT or zero if error.
Brian Pauld9468c92005-02-10 16:08:07 +0000659 */
Brian Paul463642c2005-02-08 02:06:00 +0000660static GLenum
661base_internal_format(GLcontext *ctx, GLenum internalFormat)
662{
663 switch (internalFormat) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000664 case GL_RGB:
665 case GL_R3_G3_B2:
666 case GL_RGB4:
667 case GL_RGB5:
668 case GL_RGB8:
669 case GL_RGB10:
670 case GL_RGB12:
671 case GL_RGB16:
672 return GL_RGB;
673 case GL_RGBA:
674 case GL_RGBA2:
675 case GL_RGBA4:
676 case GL_RGB5_A1:
677 case GL_RGBA8:
678 case GL_RGB10_A2:
679 case GL_RGBA12:
680 case GL_RGBA16:
681 return GL_RGBA;
682 case GL_STENCIL_INDEX:
683 case GL_STENCIL_INDEX1_EXT:
684 case GL_STENCIL_INDEX4_EXT:
685 case GL_STENCIL_INDEX8_EXT:
686 case GL_STENCIL_INDEX16_EXT:
687 return GL_STENCIL_INDEX;
688 case GL_DEPTH_COMPONENT:
Brian Paul2c6f9112005-02-24 05:47:06 +0000689 case GL_DEPTH_COMPONENT16:
690 case GL_DEPTH_COMPONENT24:
691 case GL_DEPTH_COMPONENT32:
Brian Paulf0bbbf62005-02-09 03:50:30 +0000692 return GL_DEPTH_COMPONENT;
Brian Paul1ad7b992005-09-28 02:29:50 +0000693 case GL_DEPTH_STENCIL_EXT:
694 case GL_DEPTH24_STENCIL8_EXT:
695 if (ctx->Extensions.EXT_packed_depth_stencil)
696 return GL_DEPTH_STENCIL_EXT;
697 else
698 return 0;
Brian Pauld9468c92005-02-10 16:08:07 +0000699 /* XXX add floating point formats eventually */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000700 default:
701 return 0;
Brian Paul463642c2005-02-08 02:06:00 +0000702 }
Brian Paul463642c2005-02-08 02:06:00 +0000703}
704
705
Brian Paul1864c7d2005-02-08 03:46:37 +0000706void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000707_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
708 GLsizei width, GLsizei height)
709{
Brian Paul2c6f9112005-02-24 05:47:06 +0000710 struct gl_renderbuffer *rb;
Brian Paul463642c2005-02-08 02:06:00 +0000711 GLenum baseFormat;
Brian Paulddc82ee2005-02-05 19:56:45 +0000712 GET_CURRENT_CONTEXT(ctx);
713
714 ASSERT_OUTSIDE_BEGIN_END(ctx);
715
Brian Paul463642c2005-02-08 02:06:00 +0000716 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000717 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)");
718 return;
719 }
720
Brian Paul463642c2005-02-08 02:06:00 +0000721 baseFormat = base_internal_format(ctx, internalFormat);
722 if (baseFormat == 0) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000723 _mesa_error(ctx, GL_INVALID_ENUM,
724 "glRenderbufferStorageEXT(internalFormat)");
725 return;
726 }
727
Brian Paul463642c2005-02-08 02:06:00 +0000728 if (width < 1 || width > ctx->Const.MaxRenderbufferSize) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000729 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)");
730 return;
731 }
732
Brian Paul463642c2005-02-08 02:06:00 +0000733 if (height < 1 || height > ctx->Const.MaxRenderbufferSize) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000734 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)");
735 return;
736 }
737
Brian Paul2c6f9112005-02-24 05:47:06 +0000738 rb = ctx->CurrentRenderbuffer;
739
740 if (!rb) {
Brian Paul463642c2005-02-08 02:06:00 +0000741 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT");
742 return;
743 }
744
Brian Paul474f28e2005-10-08 14:41:17 +0000745 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
746
Brian Paul311bcf52005-11-18 02:24:14 +0000747 if (rb->InternalFormat == internalFormat &&
748 rb->Width == width &&
749 rb->Height == height) {
750 /* no change in allocation needed */
751 return;
752 }
753
Brian Paul2c6f9112005-02-24 05:47:06 +0000754 /* Now allocate the storage */
755 ASSERT(rb->AllocStorage);
756 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
757 /* No error - check/set fields now */
758 assert(rb->Width == width);
759 assert(rb->Height == height);
760 assert(rb->InternalFormat);
761 rb->_BaseFormat = baseFormat;
762 }
763 else {
764 /* Probably ran out of memory - clear the fields */
765 rb->Width = 0;
766 rb->Height = 0;
767 rb->InternalFormat = GL_NONE;
768 rb->_BaseFormat = GL_NONE;
Brian Paul463642c2005-02-08 02:06:00 +0000769 }
770
Brian Paule4b23562005-05-04 20:11:35 +0000771 /*
772 test_framebuffer_completeness(ctx, fb);
773 */
Brian Paul2c6f9112005-02-24 05:47:06 +0000774 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
775 * points???
776 */
Brian Paulddc82ee2005-02-05 19:56:45 +0000777}
778
779
Brian Paul1864c7d2005-02-08 03:46:37 +0000780void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000781_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
782{
783 GET_CURRENT_CONTEXT(ctx);
784
785 ASSERT_OUTSIDE_BEGIN_END(ctx);
786
Brian Paul463642c2005-02-08 02:06:00 +0000787 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000788 _mesa_error(ctx, GL_INVALID_ENUM,
789 "glGetRenderbufferParameterivEXT(target)");
790 return;
791 }
792
Brian Paul463642c2005-02-08 02:06:00 +0000793 if (!ctx->CurrentRenderbuffer) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000794 _mesa_error(ctx, GL_INVALID_OPERATION,
795 "glGetRenderbufferParameterivEXT");
796 return;
797 }
798
Brian Paul474f28e2005-10-08 14:41:17 +0000799 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
800
Brian Paul463642c2005-02-08 02:06:00 +0000801 switch (pname) {
802 case GL_RENDERBUFFER_WIDTH_EXT:
803 *params = ctx->CurrentRenderbuffer->Width;
804 return;
805 case GL_RENDERBUFFER_HEIGHT_EXT:
806 *params = ctx->CurrentRenderbuffer->Height;
807 return;
808 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
809 *params = ctx->CurrentRenderbuffer->InternalFormat;
810 return;
Brian Paul1b939532005-05-31 23:55:21 +0000811 case GL_RENDERBUFFER_RED_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000812 *params = ctx->CurrentRenderbuffer->RedBits;
Brian Paul1b939532005-05-31 23:55:21 +0000813 break;
814 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000815 *params = ctx->CurrentRenderbuffer->GreenBits;
Brian Paul1b939532005-05-31 23:55:21 +0000816 break;
817 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000818 *params = ctx->CurrentRenderbuffer->BlueBits;
Brian Paul1b939532005-05-31 23:55:21 +0000819 break;
820 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000821 *params = ctx->CurrentRenderbuffer->AlphaBits;
Brian Paul1b939532005-05-31 23:55:21 +0000822 break;
823 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000824 *params = ctx->CurrentRenderbuffer->DepthBits;
Brian Paul1b939532005-05-31 23:55:21 +0000825 break;
826 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000827 *params = ctx->CurrentRenderbuffer->StencilBits;
Brian Paul1b939532005-05-31 23:55:21 +0000828 break;
Brian Paul463642c2005-02-08 02:06:00 +0000829 default:
830 _mesa_error(ctx, GL_INVALID_ENUM,
831 "glGetRenderbufferParameterivEXT(target)");
832 return;
833 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000834}
835
836
Brian Paul1864c7d2005-02-08 03:46:37 +0000837GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000838_mesa_IsFramebufferEXT(GLuint framebuffer)
839{
Brian Paulddc82ee2005-02-05 19:56:45 +0000840 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000841 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000842 if (framebuffer) {
843 struct gl_framebuffer *rb = lookup_framebuffer(ctx, framebuffer);
844 if (rb != NULL && rb != &DummyFramebuffer)
845 return GL_TRUE;
846 }
847 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000848}
849
850
Brian Paul1864c7d2005-02-08 03:46:37 +0000851void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000852_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
853{
Brian Paul0bffb112005-11-08 14:45:48 +0000854 struct gl_framebuffer *newFb, *oldFb;
855 GLboolean bindReadBuf, bindDrawBuf;
Brian Paulddc82ee2005-02-05 19:56:45 +0000856 GET_CURRENT_CONTEXT(ctx);
857
858 ASSERT_OUTSIDE_BEGIN_END(ctx);
859
Brian Paul0bffb112005-11-08 14:45:48 +0000860 switch (target) {
861#if FEATURE_EXT_framebuffer_blit
862 case GL_DRAW_FRAMEBUFFER_EXT:
863 if (!ctx->Extensions.EXT_framebuffer_blit) {
864 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
865 return;
866 }
867 bindDrawBuf = GL_TRUE;
868 bindReadBuf = GL_FALSE;
869 break;
870 case GL_READ_FRAMEBUFFER_EXT:
871 if (!ctx->Extensions.EXT_framebuffer_blit) {
872 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
873 return;
874 }
875 bindDrawBuf = GL_FALSE;
876 bindReadBuf = GL_TRUE;
877 break;
878#endif
879 case GL_FRAMEBUFFER_EXT:
880 bindDrawBuf = GL_TRUE;
881 bindReadBuf = GL_TRUE;
882 break;
883 default:
Brian Pauleba4ff62005-09-06 21:22:16 +0000884 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000885 return;
886 }
887
Brian Paul474f28e2005-10-08 14:41:17 +0000888 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
889
Brian Paul3deaa012005-02-07 05:08:24 +0000890 if (framebuffer) {
Brian Paule4b23562005-05-04 20:11:35 +0000891 /* Binding a user-created framebuffer object */
Brian Paul3deaa012005-02-07 05:08:24 +0000892 newFb = lookup_framebuffer(ctx, framebuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000893 if (newFb == &DummyFramebuffer) {
Brian Paul923b6fc2005-02-08 04:08:56 +0000894 /* ID was reserved, but no real framebuffer object made yet */
Brian Paul1864c7d2005-02-08 03:46:37 +0000895 newFb = NULL;
896 }
Brian Paul3deaa012005-02-07 05:08:24 +0000897 if (!newFb) {
898 /* create new framebuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000899 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000900 if (!newFb) {
901 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
902 return;
903 }
Brian Paul1864c7d2005-02-08 03:46:37 +0000904 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
Brian Paul3deaa012005-02-07 05:08:24 +0000905 }
Brian Paul0bffb112005-11-08 14:45:48 +0000906 if (bindReadBuf)
907 newFb->RefCount++;
908 if (bindDrawBuf)
909 newFb->RefCount++;
Brian Paul3deaa012005-02-07 05:08:24 +0000910 }
Brian Paul463642c2005-02-08 02:06:00 +0000911 else {
Brian Paule4b23562005-05-04 20:11:35 +0000912 /* Binding the window system framebuffer (which was originally set
913 * with MakeCurrent).
914 */
915 newFb = ctx->WinSysDrawBuffer;
Brian Paul3deaa012005-02-07 05:08:24 +0000916 }
917
Brian Paul1864c7d2005-02-08 03:46:37 +0000918 ASSERT(newFb != &DummyFramebuffer);
919
Brian Paul0bffb112005-11-08 14:45:48 +0000920 if (bindReadBuf) {
921 oldFb = ctx->ReadBuffer;
922 if (oldFb && oldFb->Name != 0) {
923 oldFb->RefCount--;
924 if (oldFb->RefCount == 0) {
925 oldFb->Delete(oldFb);
926 }
927 }
928 ctx->ReadBuffer = newFb;
929 }
930
931 if (bindDrawBuf) {
932 oldFb = ctx->DrawBuffer;
933 if (oldFb && oldFb->Name != 0) {
934 oldFb->RefCount--;
935 if (oldFb->RefCount == 0) {
936 oldFb->Delete(oldFb);
937 }
938 }
939 ctx->DrawBuffer = newFb;
940 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000941}
942
943
Brian Paul1864c7d2005-02-08 03:46:37 +0000944void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000945_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
946{
947 GLint i;
948 GET_CURRENT_CONTEXT(ctx);
949
950 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000951 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000952
953 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000954 if (framebuffers[i] > 0) {
955 struct gl_framebuffer *fb;
Brian Paul3deaa012005-02-07 05:08:24 +0000956 fb = lookup_framebuffer(ctx, framebuffers[i]);
957 if (fb) {
Brian Paule4b23562005-05-04 20:11:35 +0000958 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
Brian Paul91802fd2005-10-04 16:01:02 +0000959
960 /* check if deleting currently bound framebuffer object */
961 if (fb == ctx->DrawBuffer) {
962 /* bind default */
963 ASSERT(fb->RefCount >= 2);
964 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
965 }
966
Brian Paul3deaa012005-02-07 05:08:24 +0000967 /* remove from hash table immediately, to free the ID */
968 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +0000969
Brian Paul1864c7d2005-02-08 03:46:37 +0000970 if (fb != &DummyFramebuffer) {
971 /* But the object will not be freed until it's no longer
972 * bound in any context.
973 */
974 fb->RefCount--;
975 if (fb->RefCount == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000976 fb->Delete(fb);
Brian Paul1864c7d2005-02-08 03:46:37 +0000977 }
Brian Paul3deaa012005-02-07 05:08:24 +0000978 }
979 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000980 }
981 }
982}
983
984
Brian Paul1864c7d2005-02-08 03:46:37 +0000985void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000986_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
987{
988 GET_CURRENT_CONTEXT(ctx);
989 GLuint first;
990 GLint i;
991
992 ASSERT_OUTSIDE_BEGIN_END(ctx);
993
994 if (n < 0) {
995 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
996 return;
997 }
998
999 if (!framebuffers)
1000 return;
1001
1002 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1003
1004 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001005 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001006 framebuffers[i] = name;
1007 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001008 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001009 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001010 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001011 }
1012}
1013
1014
1015
Brian Paul1864c7d2005-02-08 03:46:37 +00001016GLenum GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001017_mesa_CheckFramebufferStatusEXT(GLenum target)
1018{
Brian Paul0bffb112005-11-08 14:45:48 +00001019 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001020 GET_CURRENT_CONTEXT(ctx);
1021
Brian Paule4b23562005-05-04 20:11:35 +00001022 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001023
Brian Paul0bffb112005-11-08 14:45:48 +00001024 switch (target) {
1025#if FEATURE_EXT_framebuffer_blit
1026 case GL_DRAW_FRAMEBUFFER_EXT:
1027 if (!ctx->Extensions.EXT_framebuffer_blit) {
1028 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1029 return 0;
1030 }
1031 buffer = ctx->DrawBuffer;
1032 break;
1033 case GL_READ_FRAMEBUFFER_EXT:
1034 if (!ctx->Extensions.EXT_framebuffer_blit) {
1035 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1036 return 0;
1037 }
1038 buffer = ctx->ReadBuffer;
1039 break;
1040#endif
1041 case GL_FRAMEBUFFER_EXT:
1042 buffer = ctx->DrawBuffer;
1043 break;
1044 default:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001045 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
Brian Paule4b23562005-05-04 20:11:35 +00001046 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
Brian Paulddc82ee2005-02-05 19:56:45 +00001047 }
1048
Brian Paul0bffb112005-11-08 14:45:48 +00001049 if (buffer->Name == 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001050 /* The window system / default framebuffer is always complete */
1051 return GL_FRAMEBUFFER_COMPLETE_EXT;
1052 }
1053
Brian Paul474f28e2005-10-08 14:41:17 +00001054 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1055
Brian Paul0bffb112005-11-08 14:45:48 +00001056 _mesa_test_framebuffer_completeness(ctx, buffer);
1057 return buffer->_Status;
Brian Paulddc82ee2005-02-05 19:56:45 +00001058}
1059
1060
1061
1062/**
1063 * Do error checking common to glFramebufferTexture1D/2D/3DEXT.
1064 * \return GL_TRUE if any error, GL_FALSE otherwise
1065 */
1066static GLboolean
Brian Paul3deaa012005-02-07 05:08:24 +00001067error_check_framebuffer_texture(GLcontext *ctx, GLuint dims,
1068 GLenum target, GLenum attachment,
1069 GLenum textarget, GLuint texture, GLint level)
Brian Paulddc82ee2005-02-05 19:56:45 +00001070{
Brian Paul3deaa012005-02-07 05:08:24 +00001071 ASSERT(dims >= 1 && dims <= 3);
1072
Brian Paulddc82ee2005-02-05 19:56:45 +00001073 if (target != GL_FRAMEBUFFER_EXT) {
1074 _mesa_error(ctx, GL_INVALID_ENUM,
1075 "glFramebufferTexture%dDEXT(target)", dims);
1076 return GL_TRUE;
1077 }
1078
Brian Paule4b23562005-05-04 20:11:35 +00001079 /* check framebuffer binding */
1080 if (ctx->DrawBuffer->Name == 0) {
Brian Paul3deaa012005-02-07 05:08:24 +00001081 _mesa_error(ctx, GL_INVALID_OPERATION,
1082 "glFramebufferTexture%dDEXT", dims);
Brian Paulddc82ee2005-02-05 19:56:45 +00001083 return GL_TRUE;
1084 }
1085
Brian Paule4b23562005-05-04 20:11:35 +00001086 /* only check textarget, level if texture ID is non-zero */
Brian Paul3deaa012005-02-07 05:08:24 +00001087 if (texture) {
1088 if ((dims == 1 && textarget != GL_TEXTURE_1D) ||
1089 (dims == 3 && textarget != GL_TEXTURE_3D) ||
1090 (dims == 2 && textarget != GL_TEXTURE_2D &&
1091 textarget != GL_TEXTURE_RECTANGLE_ARB &&
1092 !IS_CUBE_FACE(textarget))) {
1093 _mesa_error(ctx, GL_INVALID_VALUE,
1094 "glFramebufferTexture%dDEXT(textarget)", dims);
1095 return GL_TRUE;
1096 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001097
Brian Paul463642c2005-02-08 02:06:00 +00001098 if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) {
Brian Paul3deaa012005-02-07 05:08:24 +00001099 _mesa_error(ctx, GL_INVALID_VALUE,
1100 "glFramebufferTexture%dDEXT(level)", dims);
1101 return GL_TRUE;
1102 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001103 }
1104
1105 return GL_FALSE;
1106}
1107
1108
Brian Paul1864c7d2005-02-08 03:46:37 +00001109void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001110_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1111 GLenum textarget, GLuint texture, GLint level)
1112{
Brian Paul2c6f9112005-02-24 05:47:06 +00001113 struct gl_renderbuffer_attachment *att;
Brian Paule4b23562005-05-04 20:11:35 +00001114 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001115 GET_CURRENT_CONTEXT(ctx);
1116
1117 ASSERT_OUTSIDE_BEGIN_END(ctx);
1118
Brian Paul3deaa012005-02-07 05:08:24 +00001119 if (error_check_framebuffer_texture(ctx, 1, target, attachment,
1120 textarget, texture, level))
Brian Paulddc82ee2005-02-05 19:56:45 +00001121 return;
1122
Brian Paul3deaa012005-02-07 05:08:24 +00001123 ASSERT(textarget == GL_TEXTURE_1D);
1124
Brian Paul0bffb112005-11-08 14:45:48 +00001125 /* XXX read blit */
Brian Paul84716042005-11-16 04:05:54 +00001126 att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001127 if (att == NULL) {
1128 _mesa_error(ctx, GL_INVALID_ENUM,
1129 "glFramebufferTexture1DEXT(attachment)");
1130 return;
1131 }
1132
Brian Paul474f28e2005-10-08 14:41:17 +00001133 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1134
Brian Paul3deaa012005-02-07 05:08:24 +00001135 if (texture) {
Brian Paule4b23562005-05-04 20:11:35 +00001136 texObj = (struct gl_texture_object *)
Brian Paul3deaa012005-02-07 05:08:24 +00001137 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
1138 if (!texObj) {
1139 _mesa_error(ctx, GL_INVALID_VALUE,
1140 "glFramebufferTexture1DEXT(texture)");
1141 return;
1142 }
1143 if (texObj->Target != textarget) {
1144 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
1145 "glFramebufferTexture1DEXT(texture target)");
1146 return;
1147 }
Brian Paul3deaa012005-02-07 05:08:24 +00001148 }
1149 else {
Brian Paule4b23562005-05-04 20:11:35 +00001150 /* remove texture attachment */
1151 texObj = NULL;
Brian Paul3deaa012005-02-07 05:08:24 +00001152 }
Brian Paule4b23562005-05-04 20:11:35 +00001153 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001154}
1155
1156
Brian Paul1864c7d2005-02-08 03:46:37 +00001157void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001158_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1159 GLenum textarget, GLuint texture, GLint level)
1160{
Brian Paul2c6f9112005-02-24 05:47:06 +00001161 struct gl_renderbuffer_attachment *att;
Brian Paule4b23562005-05-04 20:11:35 +00001162 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001163 GET_CURRENT_CONTEXT(ctx);
1164
1165 ASSERT_OUTSIDE_BEGIN_END(ctx);
1166
Brian Paul3deaa012005-02-07 05:08:24 +00001167 if (error_check_framebuffer_texture(ctx, 2, target, attachment,
1168 textarget, texture, level))
Brian Paulddc82ee2005-02-05 19:56:45 +00001169 return;
Brian Paul3deaa012005-02-07 05:08:24 +00001170
1171 ASSERT(textarget == GL_TEXTURE_2D ||
1172 textarget == GL_TEXTURE_RECTANGLE_ARB ||
1173 IS_CUBE_FACE(textarget));
1174
Brian Paul84716042005-11-16 04:05:54 +00001175 att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001176 if (att == NULL) {
1177 _mesa_error(ctx, GL_INVALID_ENUM,
1178 "glFramebufferTexture2DEXT(attachment)");
1179 return;
1180 }
1181
Brian Paul474f28e2005-10-08 14:41:17 +00001182 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1183
Brian Paul3deaa012005-02-07 05:08:24 +00001184 if (texture) {
Brian Paule4b23562005-05-04 20:11:35 +00001185 texObj = (struct gl_texture_object *)
Brian Paul3deaa012005-02-07 05:08:24 +00001186 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
1187 if (!texObj) {
1188 _mesa_error(ctx, GL_INVALID_VALUE,
1189 "glFramebufferTexture2DEXT(texture)");
1190 return;
1191 }
1192 if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) ||
1193 (texObj->Target == GL_TEXTURE_RECTANGLE_ARB
1194 && textarget != GL_TEXTURE_RECTANGLE_ARB) ||
1195 (texObj->Target == GL_TEXTURE_CUBE_MAP
1196 && !IS_CUBE_FACE(textarget))) {
1197 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
1198 "glFramebufferTexture2DEXT(texture target)");
1199 return;
1200 }
Brian Paul3deaa012005-02-07 05:08:24 +00001201 }
1202 else {
Brian Paule4b23562005-05-04 20:11:35 +00001203 /* remove texture attachment */
1204 texObj = NULL;
Brian Paul3deaa012005-02-07 05:08:24 +00001205 }
Brian Paule4b23562005-05-04 20:11:35 +00001206 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001207}
1208
1209
Brian Paul1864c7d2005-02-08 03:46:37 +00001210void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001211_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1212 GLenum textarget, GLuint texture,
1213 GLint level, GLint zoffset)
1214{
Brian Paul2c6f9112005-02-24 05:47:06 +00001215 struct gl_renderbuffer_attachment *att;
Brian Paule4b23562005-05-04 20:11:35 +00001216 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001217 GET_CURRENT_CONTEXT(ctx);
1218
1219 ASSERT_OUTSIDE_BEGIN_END(ctx);
1220
Brian Paul3deaa012005-02-07 05:08:24 +00001221 if (error_check_framebuffer_texture(ctx, 3, target, attachment,
1222 textarget, texture, level))
Brian Paulddc82ee2005-02-05 19:56:45 +00001223 return;
1224
Brian Paul3deaa012005-02-07 05:08:24 +00001225 ASSERT(textarget == GL_TEXTURE_3D);
1226
Brian Paul84716042005-11-16 04:05:54 +00001227 att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001228 if (att == NULL) {
1229 _mesa_error(ctx, GL_INVALID_ENUM,
1230 "glFramebufferTexture1DEXT(attachment)");
1231 return;
1232 }
1233
Brian Paul474f28e2005-10-08 14:41:17 +00001234 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1235
Brian Paul3deaa012005-02-07 05:08:24 +00001236 if (texture) {
Brian Pauld9468c92005-02-10 16:08:07 +00001237 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
Brian Paule4b23562005-05-04 20:11:35 +00001238 texObj = (struct gl_texture_object *)
Brian Paul3deaa012005-02-07 05:08:24 +00001239 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
1240 if (!texObj) {
1241 _mesa_error(ctx, GL_INVALID_VALUE,
1242 "glFramebufferTexture3DEXT(texture)");
1243 return;
1244 }
1245 if (texObj->Target != textarget) {
1246 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
1247 "glFramebufferTexture3DEXT(texture target)");
1248 return;
1249 }
Brian Pauld9468c92005-02-10 16:08:07 +00001250 if (zoffset < 0 || zoffset >= maxSize) {
Brian Paul3deaa012005-02-07 05:08:24 +00001251 _mesa_error(ctx, GL_INVALID_VALUE,
1252 "glFramebufferTexture3DEXT(zoffset)");
1253 return;
1254 }
Brian Paul3deaa012005-02-07 05:08:24 +00001255 }
1256 else {
Brian Paule4b23562005-05-04 20:11:35 +00001257 /* remove texture attachment */
1258 texObj = NULL;
Brian Paul3deaa012005-02-07 05:08:24 +00001259 }
Brian Paule4b23562005-05-04 20:11:35 +00001260 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget,
1261 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00001262}
1263
1264
Brian Paul1864c7d2005-02-08 03:46:37 +00001265void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001266_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1267 GLenum renderbufferTarget,
1268 GLuint renderbuffer)
1269{
Brian Paul2c6f9112005-02-24 05:47:06 +00001270 struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001271 struct gl_framebuffer *fb;
Brian Paule4b23562005-05-04 20:11:35 +00001272 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001273 GET_CURRENT_CONTEXT(ctx);
1274
1275 ASSERT_OUTSIDE_BEGIN_END(ctx);
1276
Brian Paul0bffb112005-11-08 14:45:48 +00001277 switch (target) {
1278#if FEATURE_EXT_framebuffer_blit
1279 case GL_DRAW_FRAMEBUFFER_EXT:
1280 if (!ctx->Extensions.EXT_framebuffer_blit) {
1281 _mesa_error(ctx, GL_INVALID_ENUM,
1282 "glFramebufferRenderbufferEXT(target)");
1283 return;
1284 }
1285 fb = ctx->DrawBuffer;
1286 break;
1287 case GL_READ_FRAMEBUFFER_EXT:
1288 if (!ctx->Extensions.EXT_framebuffer_blit) {
1289 _mesa_error(ctx, GL_INVALID_ENUM,
1290 "glFramebufferRenderbufferEXT(target)");
1291 return;
1292 }
1293 fb = ctx->ReadBuffer;
1294 break;
1295#endif
1296 case GL_FRAMEBUFFER_EXT:
1297 fb = ctx->DrawBuffer;
1298 break;
1299 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001300 _mesa_error(ctx, GL_INVALID_ENUM,
1301 "glFramebufferRenderbufferEXT(target)");
1302 return;
1303 }
1304
Brian Paul3deaa012005-02-07 05:08:24 +00001305 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
Brian Paule4b23562005-05-04 20:11:35 +00001306 _mesa_error(ctx, GL_INVALID_ENUM,
1307 "glFramebufferRenderbufferEXT(renderbufferTarget)");
Brian Paul3deaa012005-02-07 05:08:24 +00001308 return;
1309 }
1310
Brian Paul0bffb112005-11-08 14:45:48 +00001311 if (fb->Name == 0) {
Brian Paulab8ef282005-09-07 23:21:59 +00001312 /* Can't attach new renderbuffers to a window system framebuffer */
Brian Paul3deaa012005-02-07 05:08:24 +00001313 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1314 return;
1315 }
1316
Brian Paul84716042005-11-16 04:05:54 +00001317 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001318 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001319 _mesa_error(ctx, GL_INVALID_ENUM,
1320 "glFramebufferRenderbufferEXT(attachment)");
1321 return;
1322 }
1323
Brian Paul1864c7d2005-02-08 03:46:37 +00001324 if (renderbuffer) {
Brian Paul1864c7d2005-02-08 03:46:37 +00001325 rb = lookup_renderbuffer(ctx, renderbuffer);
1326 if (!rb) {
Brian Paule4b23562005-05-04 20:11:35 +00001327 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul1864c7d2005-02-08 03:46:37 +00001328 "glFramebufferRenderbufferEXT(renderbuffer)");
1329 return;
1330 }
Brian Paul1864c7d2005-02-08 03:46:37 +00001331 }
1332 else {
Brian Paule4b23562005-05-04 20:11:35 +00001333 /* remove renderbuffer attachment */
1334 rb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001335 }
Brian Paule4b23562005-05-04 20:11:35 +00001336
Brian Paul474f28e2005-10-08 14:41:17 +00001337 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1338
Brian Paule4b23562005-05-04 20:11:35 +00001339 assert(ctx->Driver.FramebufferRenderbuffer);
Brian Paul84716042005-11-16 04:05:54 +00001340 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
Brian Paulddc82ee2005-02-05 19:56:45 +00001341}
1342
1343
Brian Paul1864c7d2005-02-08 03:46:37 +00001344void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001345_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1346 GLenum pname, GLint *params)
1347{
Brian Paul2c6f9112005-02-24 05:47:06 +00001348 const struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001349 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001350 GET_CURRENT_CONTEXT(ctx);
1351
1352 ASSERT_OUTSIDE_BEGIN_END(ctx);
1353
Brian Paul0bffb112005-11-08 14:45:48 +00001354 switch (target) {
1355#if FEATURE_EXT_framebuffer_blit
1356 case GL_DRAW_FRAMEBUFFER_EXT:
1357 if (!ctx->Extensions.EXT_framebuffer_blit) {
1358 _mesa_error(ctx, GL_INVALID_ENUM,
1359 "glGetFramebufferAttachmentParameterivEXT(target)");
1360 return;
1361 }
1362 buffer = ctx->DrawBuffer;
1363 break;
1364 case GL_READ_FRAMEBUFFER_EXT:
1365 if (!ctx->Extensions.EXT_framebuffer_blit) {
1366 _mesa_error(ctx, GL_INVALID_ENUM,
1367 "glGetFramebufferAttachmentParameterivEXT(target)");
1368 return;
1369 }
1370 buffer = ctx->ReadBuffer;
1371 break;
1372#endif
1373 case GL_FRAMEBUFFER_EXT:
1374 buffer = ctx->DrawBuffer;
1375 break;
1376 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001377 _mesa_error(ctx, GL_INVALID_ENUM,
1378 "glGetFramebufferAttachmentParameterivEXT(target)");
1379 return;
1380 }
1381
Brian Paul0bffb112005-11-08 14:45:48 +00001382 if (buffer->Name == 0) {
Brian Paul3deaa012005-02-07 05:08:24 +00001383 _mesa_error(ctx, GL_INVALID_OPERATION,
1384 "glGetFramebufferAttachmentParameterivEXT");
1385 return;
1386 }
1387
Brian Paul84716042005-11-16 04:05:54 +00001388 att = _mesa_get_attachment(ctx, buffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001389 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001390 _mesa_error(ctx, GL_INVALID_ENUM,
1391 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1392 return;
1393 }
1394
Brian Paul474f28e2005-10-08 14:41:17 +00001395 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1396
Brian Paulddc82ee2005-02-05 19:56:45 +00001397 switch (pname) {
1398 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001399 *params = att->Type;
1400 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001401 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001402 if (att->Type == GL_RENDERBUFFER_EXT) {
1403 *params = att->Renderbuffer->Name;
1404 }
1405 else if (att->Type == GL_TEXTURE) {
1406 *params = att->Texture->Name;
1407 }
1408 else {
1409 _mesa_error(ctx, GL_INVALID_ENUM,
1410 "glGetFramebufferAttachmentParameterivEXT(pname)");
1411 }
1412 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001413 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001414 if (att->Type == GL_TEXTURE) {
1415 *params = att->TextureLevel;
1416 }
1417 else {
1418 _mesa_error(ctx, GL_INVALID_ENUM,
1419 "glGetFramebufferAttachmentParameterivEXT(pname)");
1420 }
1421 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001422 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001423 if (att->Type == GL_TEXTURE) {
1424 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1425 }
1426 else {
1427 _mesa_error(ctx, GL_INVALID_ENUM,
1428 "glGetFramebufferAttachmentParameterivEXT(pname)");
1429 }
1430 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001431 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001432 if (att->Type == GL_TEXTURE) {
1433 *params = att->Zoffset;
1434 }
1435 else {
1436 _mesa_error(ctx, GL_INVALID_ENUM,
1437 "glGetFramebufferAttachmentParameterivEXT(pname)");
1438 }
1439 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001440 default:
1441 _mesa_error(ctx, GL_INVALID_ENUM,
1442 "glGetFramebufferAttachmentParameterivEXT(pname)");
1443 return;
1444 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001445}
1446
1447
Brian Paul1864c7d2005-02-08 03:46:37 +00001448void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001449_mesa_GenerateMipmapEXT(GLenum target)
1450{
Brian Paul463642c2005-02-08 02:06:00 +00001451 struct gl_texture_unit *texUnit;
1452 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001453 GET_CURRENT_CONTEXT(ctx);
1454
1455 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001456 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00001457
1458 switch (target) {
1459 case GL_TEXTURE_1D:
1460 case GL_TEXTURE_2D:
Brian Paulddc82ee2005-02-05 19:56:45 +00001461 case GL_TEXTURE_3D:
Brian Paul463642c2005-02-08 02:06:00 +00001462 case GL_TEXTURE_CUBE_MAP:
Brian Paul1b939532005-05-31 23:55:21 +00001463 /* OK, legal value */
Brian Paulddc82ee2005-02-05 19:56:45 +00001464 break;
1465 default:
1466 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
1467 return;
1468 }
1469
Brian Paul463642c2005-02-08 02:06:00 +00001470 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1471 texObj = _mesa_select_tex_object(ctx, texUnit, target);
1472
1473 /* XXX this might not handle cube maps correctly */
1474 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
Brian Paulddc82ee2005-02-05 19:56:45 +00001475}
Brian Paul0bffb112005-11-08 14:45:48 +00001476
1477
1478#if FEATURE_EXT_framebuffer_blit
1479void GLAPIENTRY
1480_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
1481 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
1482 GLbitfield mask, GLenum filter)
1483{
1484 GET_CURRENT_CONTEXT(ctx);
1485
1486 ASSERT_OUTSIDE_BEGIN_END(ctx);
1487 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1488
1489 /* check for complete framebuffers */
1490 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
1491 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1492 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
1493 "glBlitFramebufferEXT(incomplete draw/read buffers)");
1494 return;
1495 }
1496
1497 /* depth/stencil must be blitted with nearest filtering */
1498 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
1499 && filter != GL_NEAREST) {
1500 _mesa_error(ctx, GL_INVALID_OPERATION,
1501 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
1502 return;
1503 }
1504
1505 if (mask & ~(GL_COLOR_BUFFER_BIT |
1506 GL_DEPTH_BUFFER_BIT |
1507 GL_STENCIL_BUFFER_BIT)) {
1508 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
1509 return;
1510 }
1511
1512 if (!ctx->Extensions.EXT_framebuffer_blit) {
1513 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
1514 return;
1515 }
1516
1517 ASSERT(ctx->Driver.BlitFramebuffer);
1518 ctx->Driver.BlitFramebuffer(ctx,
1519 srcX0, srcY0, srcX1, srcY1,
1520 dstX0, dstY0, dstX1, dstY1,
1521 mask, filter);
1522}
1523#endif /* FEATURE_EXT_framebuffer_blit */