blob: ecf54a5a797b9309b72e909998fd75fbb673ff5c [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 Paul2c6f9112005-02-24 05:47:06 +0000747 /* Now allocate the storage */
748 ASSERT(rb->AllocStorage);
749 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
750 /* No error - check/set fields now */
751 assert(rb->Width == width);
752 assert(rb->Height == height);
753 assert(rb->InternalFormat);
754 rb->_BaseFormat = baseFormat;
755 }
756 else {
757 /* Probably ran out of memory - clear the fields */
758 rb->Width = 0;
759 rb->Height = 0;
760 rb->InternalFormat = GL_NONE;
761 rb->_BaseFormat = GL_NONE;
Brian Paul463642c2005-02-08 02:06:00 +0000762 }
763
Brian Paule4b23562005-05-04 20:11:35 +0000764 /*
765 test_framebuffer_completeness(ctx, fb);
766 */
Brian Paul2c6f9112005-02-24 05:47:06 +0000767 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
768 * points???
769 */
Brian Paulddc82ee2005-02-05 19:56:45 +0000770}
771
772
Brian Paul1864c7d2005-02-08 03:46:37 +0000773void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000774_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
775{
776 GET_CURRENT_CONTEXT(ctx);
777
778 ASSERT_OUTSIDE_BEGIN_END(ctx);
779
Brian Paul463642c2005-02-08 02:06:00 +0000780 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000781 _mesa_error(ctx, GL_INVALID_ENUM,
782 "glGetRenderbufferParameterivEXT(target)");
783 return;
784 }
785
Brian Paul463642c2005-02-08 02:06:00 +0000786 if (!ctx->CurrentRenderbuffer) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000787 _mesa_error(ctx, GL_INVALID_OPERATION,
788 "glGetRenderbufferParameterivEXT");
789 return;
790 }
791
Brian Paul474f28e2005-10-08 14:41:17 +0000792 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
793
Brian Paul463642c2005-02-08 02:06:00 +0000794 switch (pname) {
795 case GL_RENDERBUFFER_WIDTH_EXT:
796 *params = ctx->CurrentRenderbuffer->Width;
797 return;
798 case GL_RENDERBUFFER_HEIGHT_EXT:
799 *params = ctx->CurrentRenderbuffer->Height;
800 return;
801 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
802 *params = ctx->CurrentRenderbuffer->InternalFormat;
803 return;
Brian Paul1b939532005-05-31 23:55:21 +0000804 case GL_RENDERBUFFER_RED_SIZE_EXT:
805 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB ||
806 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) {
Brian Paul676d0ac2005-09-22 05:19:57 +0000807 *params = ctx->CurrentRenderbuffer->RedBits;
Brian Paul1b939532005-05-31 23:55:21 +0000808 }
809 else {
810 *params = 0;
811 }
812 break;
813 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
814 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB ||
815 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) {
Brian Paul676d0ac2005-09-22 05:19:57 +0000816 *params = ctx->CurrentRenderbuffer->GreenBits;
Brian Paul1b939532005-05-31 23:55:21 +0000817 }
818 else {
819 *params = 0;
820 }
821 break;
822 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
823 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB ||
824 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) {
Brian Paul676d0ac2005-09-22 05:19:57 +0000825 *params = ctx->CurrentRenderbuffer->BlueBits;
Brian Paul1b939532005-05-31 23:55:21 +0000826 }
827 else {
828 *params = 0;
829 }
830 break;
831 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
832 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB ||
833 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) {
Brian Paul676d0ac2005-09-22 05:19:57 +0000834 *params = ctx->CurrentRenderbuffer->AlphaBits;
Brian Paul1b939532005-05-31 23:55:21 +0000835 }
836 else {
837 *params = 0;
838 }
839 break;
840 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
Brian Paul1ad7b992005-09-28 02:29:50 +0000841 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_DEPTH_COMPONENT ||
842 ctx->CurrentRenderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul676d0ac2005-09-22 05:19:57 +0000843 *params = ctx->CurrentRenderbuffer->DepthBits;
Brian Paul1b939532005-05-31 23:55:21 +0000844 }
845 else {
846 *params = 0;
847 }
848 break;
849 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
Brian Paul1ad7b992005-09-28 02:29:50 +0000850 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_STENCIL_INDEX ||
851 ctx->CurrentRenderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul676d0ac2005-09-22 05:19:57 +0000852 *params = ctx->CurrentRenderbuffer->StencilBits;
Brian Paul1b939532005-05-31 23:55:21 +0000853 }
854 else {
855 *params = 0;
856 }
857 break;
858
Brian Paul463642c2005-02-08 02:06:00 +0000859 default:
860 _mesa_error(ctx, GL_INVALID_ENUM,
861 "glGetRenderbufferParameterivEXT(target)");
862 return;
863 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000864}
865
866
Brian Paul1864c7d2005-02-08 03:46:37 +0000867GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000868_mesa_IsFramebufferEXT(GLuint framebuffer)
869{
Brian Paulddc82ee2005-02-05 19:56:45 +0000870 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000871 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000872 if (framebuffer) {
873 struct gl_framebuffer *rb = lookup_framebuffer(ctx, framebuffer);
874 if (rb != NULL && rb != &DummyFramebuffer)
875 return GL_TRUE;
876 }
877 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000878}
879
880
Brian Paul1864c7d2005-02-08 03:46:37 +0000881void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000882_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
883{
Brian Paul0bffb112005-11-08 14:45:48 +0000884 struct gl_framebuffer *newFb, *oldFb;
885 GLboolean bindReadBuf, bindDrawBuf;
Brian Paulddc82ee2005-02-05 19:56:45 +0000886 GET_CURRENT_CONTEXT(ctx);
887
888 ASSERT_OUTSIDE_BEGIN_END(ctx);
889
Brian Paul0bffb112005-11-08 14:45:48 +0000890 switch (target) {
891#if FEATURE_EXT_framebuffer_blit
892 case GL_DRAW_FRAMEBUFFER_EXT:
893 if (!ctx->Extensions.EXT_framebuffer_blit) {
894 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
895 return;
896 }
897 bindDrawBuf = GL_TRUE;
898 bindReadBuf = GL_FALSE;
899 break;
900 case GL_READ_FRAMEBUFFER_EXT:
901 if (!ctx->Extensions.EXT_framebuffer_blit) {
902 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
903 return;
904 }
905 bindDrawBuf = GL_FALSE;
906 bindReadBuf = GL_TRUE;
907 break;
908#endif
909 case GL_FRAMEBUFFER_EXT:
910 bindDrawBuf = GL_TRUE;
911 bindReadBuf = GL_TRUE;
912 break;
913 default:
Brian Pauleba4ff62005-09-06 21:22:16 +0000914 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000915 return;
916 }
917
Brian Paul474f28e2005-10-08 14:41:17 +0000918 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
919
Brian Paul3deaa012005-02-07 05:08:24 +0000920 if (framebuffer) {
Brian Paule4b23562005-05-04 20:11:35 +0000921 /* Binding a user-created framebuffer object */
Brian Paul3deaa012005-02-07 05:08:24 +0000922 newFb = lookup_framebuffer(ctx, framebuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000923 if (newFb == &DummyFramebuffer) {
Brian Paul923b6fc2005-02-08 04:08:56 +0000924 /* ID was reserved, but no real framebuffer object made yet */
Brian Paul1864c7d2005-02-08 03:46:37 +0000925 newFb = NULL;
926 }
Brian Paul3deaa012005-02-07 05:08:24 +0000927 if (!newFb) {
928 /* create new framebuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000929 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000930 if (!newFb) {
931 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
932 return;
933 }
Brian Paul1864c7d2005-02-08 03:46:37 +0000934 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
Brian Paul3deaa012005-02-07 05:08:24 +0000935 }
Brian Paul0bffb112005-11-08 14:45:48 +0000936 if (bindReadBuf)
937 newFb->RefCount++;
938 if (bindDrawBuf)
939 newFb->RefCount++;
Brian Paul3deaa012005-02-07 05:08:24 +0000940 }
Brian Paul463642c2005-02-08 02:06:00 +0000941 else {
Brian Paule4b23562005-05-04 20:11:35 +0000942 /* Binding the window system framebuffer (which was originally set
943 * with MakeCurrent).
944 */
945 newFb = ctx->WinSysDrawBuffer;
Brian Paul3deaa012005-02-07 05:08:24 +0000946 }
947
Brian Paul1864c7d2005-02-08 03:46:37 +0000948 ASSERT(newFb != &DummyFramebuffer);
949
Brian Paul0bffb112005-11-08 14:45:48 +0000950 if (bindReadBuf) {
951 oldFb = ctx->ReadBuffer;
952 if (oldFb && oldFb->Name != 0) {
953 oldFb->RefCount--;
954 if (oldFb->RefCount == 0) {
955 oldFb->Delete(oldFb);
956 }
957 }
958 ctx->ReadBuffer = newFb;
959 }
960
961 if (bindDrawBuf) {
962 oldFb = ctx->DrawBuffer;
963 if (oldFb && oldFb->Name != 0) {
964 oldFb->RefCount--;
965 if (oldFb->RefCount == 0) {
966 oldFb->Delete(oldFb);
967 }
968 }
969 ctx->DrawBuffer = newFb;
970 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000971}
972
973
Brian Paul1864c7d2005-02-08 03:46:37 +0000974void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000975_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
976{
977 GLint i;
978 GET_CURRENT_CONTEXT(ctx);
979
980 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000981 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000982
983 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000984 if (framebuffers[i] > 0) {
985 struct gl_framebuffer *fb;
Brian Paul3deaa012005-02-07 05:08:24 +0000986 fb = lookup_framebuffer(ctx, framebuffers[i]);
987 if (fb) {
Brian Paule4b23562005-05-04 20:11:35 +0000988 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
Brian Paul91802fd2005-10-04 16:01:02 +0000989
990 /* check if deleting currently bound framebuffer object */
991 if (fb == ctx->DrawBuffer) {
992 /* bind default */
993 ASSERT(fb->RefCount >= 2);
994 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
995 }
996
Brian Paul3deaa012005-02-07 05:08:24 +0000997 /* remove from hash table immediately, to free the ID */
998 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +0000999
Brian Paul1864c7d2005-02-08 03:46:37 +00001000 if (fb != &DummyFramebuffer) {
1001 /* But the object will not be freed until it's no longer
1002 * bound in any context.
1003 */
1004 fb->RefCount--;
1005 if (fb->RefCount == 0) {
Brian Paule4b23562005-05-04 20:11:35 +00001006 fb->Delete(fb);
Brian Paul1864c7d2005-02-08 03:46:37 +00001007 }
Brian Paul3deaa012005-02-07 05:08:24 +00001008 }
1009 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001010 }
1011 }
1012}
1013
1014
Brian Paul1864c7d2005-02-08 03:46:37 +00001015void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001016_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1017{
1018 GET_CURRENT_CONTEXT(ctx);
1019 GLuint first;
1020 GLint i;
1021
1022 ASSERT_OUTSIDE_BEGIN_END(ctx);
1023
1024 if (n < 0) {
1025 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1026 return;
1027 }
1028
1029 if (!framebuffers)
1030 return;
1031
1032 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1033
1034 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001035 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001036 framebuffers[i] = name;
1037 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001038 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001039 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001040 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001041 }
1042}
1043
1044
1045
Brian Paul1864c7d2005-02-08 03:46:37 +00001046GLenum GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001047_mesa_CheckFramebufferStatusEXT(GLenum target)
1048{
Brian Paul0bffb112005-11-08 14:45:48 +00001049 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001050 GET_CURRENT_CONTEXT(ctx);
1051
Brian Paule4b23562005-05-04 20:11:35 +00001052 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001053
Brian Paul0bffb112005-11-08 14:45:48 +00001054 switch (target) {
1055#if FEATURE_EXT_framebuffer_blit
1056 case GL_DRAW_FRAMEBUFFER_EXT:
1057 if (!ctx->Extensions.EXT_framebuffer_blit) {
1058 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1059 return 0;
1060 }
1061 buffer = ctx->DrawBuffer;
1062 break;
1063 case GL_READ_FRAMEBUFFER_EXT:
1064 if (!ctx->Extensions.EXT_framebuffer_blit) {
1065 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1066 return 0;
1067 }
1068 buffer = ctx->ReadBuffer;
1069 break;
1070#endif
1071 case GL_FRAMEBUFFER_EXT:
1072 buffer = ctx->DrawBuffer;
1073 break;
1074 default:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001075 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
Brian Paule4b23562005-05-04 20:11:35 +00001076 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
Brian Paulddc82ee2005-02-05 19:56:45 +00001077 }
1078
Brian Paul0bffb112005-11-08 14:45:48 +00001079 if (buffer->Name == 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001080 /* The window system / default framebuffer is always complete */
1081 return GL_FRAMEBUFFER_COMPLETE_EXT;
1082 }
1083
Brian Paul474f28e2005-10-08 14:41:17 +00001084 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1085
Brian Paul0bffb112005-11-08 14:45:48 +00001086 _mesa_test_framebuffer_completeness(ctx, buffer);
1087 return buffer->_Status;
Brian Paulddc82ee2005-02-05 19:56:45 +00001088}
1089
1090
1091
1092/**
1093 * Do error checking common to glFramebufferTexture1D/2D/3DEXT.
1094 * \return GL_TRUE if any error, GL_FALSE otherwise
1095 */
1096static GLboolean
Brian Paul3deaa012005-02-07 05:08:24 +00001097error_check_framebuffer_texture(GLcontext *ctx, GLuint dims,
1098 GLenum target, GLenum attachment,
1099 GLenum textarget, GLuint texture, GLint level)
Brian Paulddc82ee2005-02-05 19:56:45 +00001100{
Brian Paul3deaa012005-02-07 05:08:24 +00001101 ASSERT(dims >= 1 && dims <= 3);
1102
Brian Paulddc82ee2005-02-05 19:56:45 +00001103 if (target != GL_FRAMEBUFFER_EXT) {
1104 _mesa_error(ctx, GL_INVALID_ENUM,
1105 "glFramebufferTexture%dDEXT(target)", dims);
1106 return GL_TRUE;
1107 }
1108
Brian Paule4b23562005-05-04 20:11:35 +00001109 /* check framebuffer binding */
1110 if (ctx->DrawBuffer->Name == 0) {
Brian Paul3deaa012005-02-07 05:08:24 +00001111 _mesa_error(ctx, GL_INVALID_OPERATION,
1112 "glFramebufferTexture%dDEXT", dims);
Brian Paulddc82ee2005-02-05 19:56:45 +00001113 return GL_TRUE;
1114 }
1115
Brian Paule4b23562005-05-04 20:11:35 +00001116 /* only check textarget, level if texture ID is non-zero */
Brian Paul3deaa012005-02-07 05:08:24 +00001117 if (texture) {
1118 if ((dims == 1 && textarget != GL_TEXTURE_1D) ||
1119 (dims == 3 && textarget != GL_TEXTURE_3D) ||
1120 (dims == 2 && textarget != GL_TEXTURE_2D &&
1121 textarget != GL_TEXTURE_RECTANGLE_ARB &&
1122 !IS_CUBE_FACE(textarget))) {
1123 _mesa_error(ctx, GL_INVALID_VALUE,
1124 "glFramebufferTexture%dDEXT(textarget)", dims);
1125 return GL_TRUE;
1126 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001127
Brian Paul463642c2005-02-08 02:06:00 +00001128 if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) {
Brian Paul3deaa012005-02-07 05:08:24 +00001129 _mesa_error(ctx, GL_INVALID_VALUE,
1130 "glFramebufferTexture%dDEXT(level)", dims);
1131 return GL_TRUE;
1132 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001133 }
1134
1135 return GL_FALSE;
1136}
1137
1138
Brian Paul1864c7d2005-02-08 03:46:37 +00001139void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001140_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1141 GLenum textarget, GLuint texture, GLint level)
1142{
Brian Paul2c6f9112005-02-24 05:47:06 +00001143 struct gl_renderbuffer_attachment *att;
Brian Paule4b23562005-05-04 20:11:35 +00001144 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001145 GET_CURRENT_CONTEXT(ctx);
1146
1147 ASSERT_OUTSIDE_BEGIN_END(ctx);
1148
Brian Paul3deaa012005-02-07 05:08:24 +00001149 if (error_check_framebuffer_texture(ctx, 1, target, attachment,
1150 textarget, texture, level))
Brian Paulddc82ee2005-02-05 19:56:45 +00001151 return;
1152
Brian Paul3deaa012005-02-07 05:08:24 +00001153 ASSERT(textarget == GL_TEXTURE_1D);
1154
Brian Paul0bffb112005-11-08 14:45:48 +00001155 /* XXX read blit */
Brian Paul84716042005-11-16 04:05:54 +00001156 att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001157 if (att == NULL) {
1158 _mesa_error(ctx, GL_INVALID_ENUM,
1159 "glFramebufferTexture1DEXT(attachment)");
1160 return;
1161 }
1162
Brian Paul474f28e2005-10-08 14:41:17 +00001163 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1164
Brian Paul3deaa012005-02-07 05:08:24 +00001165 if (texture) {
Brian Paule4b23562005-05-04 20:11:35 +00001166 texObj = (struct gl_texture_object *)
Brian Paul3deaa012005-02-07 05:08:24 +00001167 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
1168 if (!texObj) {
1169 _mesa_error(ctx, GL_INVALID_VALUE,
1170 "glFramebufferTexture1DEXT(texture)");
1171 return;
1172 }
1173 if (texObj->Target != textarget) {
1174 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
1175 "glFramebufferTexture1DEXT(texture target)");
1176 return;
1177 }
Brian Paul3deaa012005-02-07 05:08:24 +00001178 }
1179 else {
Brian Paule4b23562005-05-04 20:11:35 +00001180 /* remove texture attachment */
1181 texObj = NULL;
Brian Paul3deaa012005-02-07 05:08:24 +00001182 }
Brian Paule4b23562005-05-04 20:11:35 +00001183 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001184}
1185
1186
Brian Paul1864c7d2005-02-08 03:46:37 +00001187void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001188_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1189 GLenum textarget, GLuint texture, GLint level)
1190{
Brian Paul2c6f9112005-02-24 05:47:06 +00001191 struct gl_renderbuffer_attachment *att;
Brian Paule4b23562005-05-04 20:11:35 +00001192 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001193 GET_CURRENT_CONTEXT(ctx);
1194
1195 ASSERT_OUTSIDE_BEGIN_END(ctx);
1196
Brian Paul3deaa012005-02-07 05:08:24 +00001197 if (error_check_framebuffer_texture(ctx, 2, target, attachment,
1198 textarget, texture, level))
Brian Paulddc82ee2005-02-05 19:56:45 +00001199 return;
Brian Paul3deaa012005-02-07 05:08:24 +00001200
1201 ASSERT(textarget == GL_TEXTURE_2D ||
1202 textarget == GL_TEXTURE_RECTANGLE_ARB ||
1203 IS_CUBE_FACE(textarget));
1204
Brian Paul84716042005-11-16 04:05:54 +00001205 att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001206 if (att == NULL) {
1207 _mesa_error(ctx, GL_INVALID_ENUM,
1208 "glFramebufferTexture2DEXT(attachment)");
1209 return;
1210 }
1211
Brian Paul474f28e2005-10-08 14:41:17 +00001212 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1213
Brian Paul3deaa012005-02-07 05:08:24 +00001214 if (texture) {
Brian Paule4b23562005-05-04 20:11:35 +00001215 texObj = (struct gl_texture_object *)
Brian Paul3deaa012005-02-07 05:08:24 +00001216 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
1217 if (!texObj) {
1218 _mesa_error(ctx, GL_INVALID_VALUE,
1219 "glFramebufferTexture2DEXT(texture)");
1220 return;
1221 }
1222 if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) ||
1223 (texObj->Target == GL_TEXTURE_RECTANGLE_ARB
1224 && textarget != GL_TEXTURE_RECTANGLE_ARB) ||
1225 (texObj->Target == GL_TEXTURE_CUBE_MAP
1226 && !IS_CUBE_FACE(textarget))) {
1227 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
1228 "glFramebufferTexture2DEXT(texture target)");
1229 return;
1230 }
Brian Paul3deaa012005-02-07 05:08:24 +00001231 }
1232 else {
Brian Paule4b23562005-05-04 20:11:35 +00001233 /* remove texture attachment */
1234 texObj = NULL;
Brian Paul3deaa012005-02-07 05:08:24 +00001235 }
Brian Paule4b23562005-05-04 20:11:35 +00001236 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001237}
1238
1239
Brian Paul1864c7d2005-02-08 03:46:37 +00001240void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001241_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1242 GLenum textarget, GLuint texture,
1243 GLint level, GLint zoffset)
1244{
Brian Paul2c6f9112005-02-24 05:47:06 +00001245 struct gl_renderbuffer_attachment *att;
Brian Paule4b23562005-05-04 20:11:35 +00001246 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001247 GET_CURRENT_CONTEXT(ctx);
1248
1249 ASSERT_OUTSIDE_BEGIN_END(ctx);
1250
Brian Paul3deaa012005-02-07 05:08:24 +00001251 if (error_check_framebuffer_texture(ctx, 3, target, attachment,
1252 textarget, texture, level))
Brian Paulddc82ee2005-02-05 19:56:45 +00001253 return;
1254
Brian Paul3deaa012005-02-07 05:08:24 +00001255 ASSERT(textarget == GL_TEXTURE_3D);
1256
Brian Paul84716042005-11-16 04:05:54 +00001257 att = _mesa_get_attachment(ctx, ctx->DrawBuffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001258 if (att == NULL) {
1259 _mesa_error(ctx, GL_INVALID_ENUM,
1260 "glFramebufferTexture1DEXT(attachment)");
1261 return;
1262 }
1263
Brian Paul474f28e2005-10-08 14:41:17 +00001264 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1265
Brian Paul3deaa012005-02-07 05:08:24 +00001266 if (texture) {
Brian Pauld9468c92005-02-10 16:08:07 +00001267 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
Brian Paule4b23562005-05-04 20:11:35 +00001268 texObj = (struct gl_texture_object *)
Brian Paul3deaa012005-02-07 05:08:24 +00001269 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
1270 if (!texObj) {
1271 _mesa_error(ctx, GL_INVALID_VALUE,
1272 "glFramebufferTexture3DEXT(texture)");
1273 return;
1274 }
1275 if (texObj->Target != textarget) {
1276 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */
1277 "glFramebufferTexture3DEXT(texture target)");
1278 return;
1279 }
Brian Pauld9468c92005-02-10 16:08:07 +00001280 if (zoffset < 0 || zoffset >= maxSize) {
Brian Paul3deaa012005-02-07 05:08:24 +00001281 _mesa_error(ctx, GL_INVALID_VALUE,
1282 "glFramebufferTexture3DEXT(zoffset)");
1283 return;
1284 }
Brian Paul3deaa012005-02-07 05:08:24 +00001285 }
1286 else {
Brian Paule4b23562005-05-04 20:11:35 +00001287 /* remove texture attachment */
1288 texObj = NULL;
Brian Paul3deaa012005-02-07 05:08:24 +00001289 }
Brian Paule4b23562005-05-04 20:11:35 +00001290 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget,
1291 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00001292}
1293
1294
Brian Paul1864c7d2005-02-08 03:46:37 +00001295void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001296_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1297 GLenum renderbufferTarget,
1298 GLuint renderbuffer)
1299{
Brian Paul2c6f9112005-02-24 05:47:06 +00001300 struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001301 struct gl_framebuffer *fb;
Brian Paule4b23562005-05-04 20:11:35 +00001302 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001303 GET_CURRENT_CONTEXT(ctx);
1304
1305 ASSERT_OUTSIDE_BEGIN_END(ctx);
1306
Brian Paul0bffb112005-11-08 14:45:48 +00001307 switch (target) {
1308#if FEATURE_EXT_framebuffer_blit
1309 case GL_DRAW_FRAMEBUFFER_EXT:
1310 if (!ctx->Extensions.EXT_framebuffer_blit) {
1311 _mesa_error(ctx, GL_INVALID_ENUM,
1312 "glFramebufferRenderbufferEXT(target)");
1313 return;
1314 }
1315 fb = ctx->DrawBuffer;
1316 break;
1317 case GL_READ_FRAMEBUFFER_EXT:
1318 if (!ctx->Extensions.EXT_framebuffer_blit) {
1319 _mesa_error(ctx, GL_INVALID_ENUM,
1320 "glFramebufferRenderbufferEXT(target)");
1321 return;
1322 }
1323 fb = ctx->ReadBuffer;
1324 break;
1325#endif
1326 case GL_FRAMEBUFFER_EXT:
1327 fb = ctx->DrawBuffer;
1328 break;
1329 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001330 _mesa_error(ctx, GL_INVALID_ENUM,
1331 "glFramebufferRenderbufferEXT(target)");
1332 return;
1333 }
1334
Brian Paul3deaa012005-02-07 05:08:24 +00001335 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
Brian Paule4b23562005-05-04 20:11:35 +00001336 _mesa_error(ctx, GL_INVALID_ENUM,
1337 "glFramebufferRenderbufferEXT(renderbufferTarget)");
Brian Paul3deaa012005-02-07 05:08:24 +00001338 return;
1339 }
1340
Brian Paul0bffb112005-11-08 14:45:48 +00001341 if (fb->Name == 0) {
Brian Paulab8ef282005-09-07 23:21:59 +00001342 /* Can't attach new renderbuffers to a window system framebuffer */
Brian Paul3deaa012005-02-07 05:08:24 +00001343 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1344 return;
1345 }
1346
Brian Paul84716042005-11-16 04:05:54 +00001347 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001348 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001349 _mesa_error(ctx, GL_INVALID_ENUM,
1350 "glFramebufferRenderbufferEXT(attachment)");
1351 return;
1352 }
1353
Brian Paul1864c7d2005-02-08 03:46:37 +00001354 if (renderbuffer) {
Brian Paul1864c7d2005-02-08 03:46:37 +00001355 rb = lookup_renderbuffer(ctx, renderbuffer);
1356 if (!rb) {
Brian Paule4b23562005-05-04 20:11:35 +00001357 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul1864c7d2005-02-08 03:46:37 +00001358 "glFramebufferRenderbufferEXT(renderbuffer)");
1359 return;
1360 }
Brian Paul1864c7d2005-02-08 03:46:37 +00001361 }
1362 else {
Brian Paule4b23562005-05-04 20:11:35 +00001363 /* remove renderbuffer attachment */
1364 rb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001365 }
Brian Paule4b23562005-05-04 20:11:35 +00001366
Brian Paul474f28e2005-10-08 14:41:17 +00001367 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1368
Brian Paule4b23562005-05-04 20:11:35 +00001369 assert(ctx->Driver.FramebufferRenderbuffer);
Brian Paul84716042005-11-16 04:05:54 +00001370 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
Brian Paulddc82ee2005-02-05 19:56:45 +00001371}
1372
1373
Brian Paul1864c7d2005-02-08 03:46:37 +00001374void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001375_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1376 GLenum pname, GLint *params)
1377{
Brian Paul2c6f9112005-02-24 05:47:06 +00001378 const struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001379 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001380 GET_CURRENT_CONTEXT(ctx);
1381
1382 ASSERT_OUTSIDE_BEGIN_END(ctx);
1383
Brian Paul0bffb112005-11-08 14:45:48 +00001384 switch (target) {
1385#if FEATURE_EXT_framebuffer_blit
1386 case GL_DRAW_FRAMEBUFFER_EXT:
1387 if (!ctx->Extensions.EXT_framebuffer_blit) {
1388 _mesa_error(ctx, GL_INVALID_ENUM,
1389 "glGetFramebufferAttachmentParameterivEXT(target)");
1390 return;
1391 }
1392 buffer = ctx->DrawBuffer;
1393 break;
1394 case GL_READ_FRAMEBUFFER_EXT:
1395 if (!ctx->Extensions.EXT_framebuffer_blit) {
1396 _mesa_error(ctx, GL_INVALID_ENUM,
1397 "glGetFramebufferAttachmentParameterivEXT(target)");
1398 return;
1399 }
1400 buffer = ctx->ReadBuffer;
1401 break;
1402#endif
1403 case GL_FRAMEBUFFER_EXT:
1404 buffer = ctx->DrawBuffer;
1405 break;
1406 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001407 _mesa_error(ctx, GL_INVALID_ENUM,
1408 "glGetFramebufferAttachmentParameterivEXT(target)");
1409 return;
1410 }
1411
Brian Paul0bffb112005-11-08 14:45:48 +00001412 if (buffer->Name == 0) {
Brian Paul3deaa012005-02-07 05:08:24 +00001413 _mesa_error(ctx, GL_INVALID_OPERATION,
1414 "glGetFramebufferAttachmentParameterivEXT");
1415 return;
1416 }
1417
Brian Paul84716042005-11-16 04:05:54 +00001418 att = _mesa_get_attachment(ctx, buffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001419 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001420 _mesa_error(ctx, GL_INVALID_ENUM,
1421 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1422 return;
1423 }
1424
Brian Paul474f28e2005-10-08 14:41:17 +00001425 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1426
Brian Paulddc82ee2005-02-05 19:56:45 +00001427 switch (pname) {
1428 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001429 *params = att->Type;
1430 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001431 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001432 if (att->Type == GL_RENDERBUFFER_EXT) {
1433 *params = att->Renderbuffer->Name;
1434 }
1435 else if (att->Type == GL_TEXTURE) {
1436 *params = att->Texture->Name;
1437 }
1438 else {
1439 _mesa_error(ctx, GL_INVALID_ENUM,
1440 "glGetFramebufferAttachmentParameterivEXT(pname)");
1441 }
1442 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001443 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001444 if (att->Type == GL_TEXTURE) {
1445 *params = att->TextureLevel;
1446 }
1447 else {
1448 _mesa_error(ctx, GL_INVALID_ENUM,
1449 "glGetFramebufferAttachmentParameterivEXT(pname)");
1450 }
1451 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001452 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001453 if (att->Type == GL_TEXTURE) {
1454 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1455 }
1456 else {
1457 _mesa_error(ctx, GL_INVALID_ENUM,
1458 "glGetFramebufferAttachmentParameterivEXT(pname)");
1459 }
1460 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001461 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001462 if (att->Type == GL_TEXTURE) {
1463 *params = att->Zoffset;
1464 }
1465 else {
1466 _mesa_error(ctx, GL_INVALID_ENUM,
1467 "glGetFramebufferAttachmentParameterivEXT(pname)");
1468 }
1469 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001470 default:
1471 _mesa_error(ctx, GL_INVALID_ENUM,
1472 "glGetFramebufferAttachmentParameterivEXT(pname)");
1473 return;
1474 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001475}
1476
1477
Brian Paul1864c7d2005-02-08 03:46:37 +00001478void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001479_mesa_GenerateMipmapEXT(GLenum target)
1480{
Brian Paul463642c2005-02-08 02:06:00 +00001481 struct gl_texture_unit *texUnit;
1482 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001483 GET_CURRENT_CONTEXT(ctx);
1484
1485 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001486 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00001487
1488 switch (target) {
1489 case GL_TEXTURE_1D:
1490 case GL_TEXTURE_2D:
Brian Paulddc82ee2005-02-05 19:56:45 +00001491 case GL_TEXTURE_3D:
Brian Paul463642c2005-02-08 02:06:00 +00001492 case GL_TEXTURE_CUBE_MAP:
Brian Paul1b939532005-05-31 23:55:21 +00001493 /* OK, legal value */
Brian Paulddc82ee2005-02-05 19:56:45 +00001494 break;
1495 default:
1496 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
1497 return;
1498 }
1499
Brian Paul463642c2005-02-08 02:06:00 +00001500 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1501 texObj = _mesa_select_tex_object(ctx, texUnit, target);
1502
1503 /* XXX this might not handle cube maps correctly */
1504 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
Brian Paulddc82ee2005-02-05 19:56:45 +00001505}
Brian Paul0bffb112005-11-08 14:45:48 +00001506
1507
1508#if FEATURE_EXT_framebuffer_blit
1509void GLAPIENTRY
1510_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
1511 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
1512 GLbitfield mask, GLenum filter)
1513{
1514 GET_CURRENT_CONTEXT(ctx);
1515
1516 ASSERT_OUTSIDE_BEGIN_END(ctx);
1517 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1518
1519 /* check for complete framebuffers */
1520 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
1521 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1522 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
1523 "glBlitFramebufferEXT(incomplete draw/read buffers)");
1524 return;
1525 }
1526
1527 /* depth/stencil must be blitted with nearest filtering */
1528 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
1529 && filter != GL_NEAREST) {
1530 _mesa_error(ctx, GL_INVALID_OPERATION,
1531 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
1532 return;
1533 }
1534
1535 if (mask & ~(GL_COLOR_BUFFER_BIT |
1536 GL_DEPTH_BUFFER_BIT |
1537 GL_STENCIL_BUFFER_BIT)) {
1538 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
1539 return;
1540 }
1541
1542 if (!ctx->Extensions.EXT_framebuffer_blit) {
1543 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
1544 return;
1545 }
1546
1547 ASSERT(ctx->Driver.BlitFramebuffer);
1548 ctx->Driver.BlitFramebuffer(ctx,
1549 srcX0, srcY0, srcX1, srcY1,
1550 dstX0, dstY0, dstX1, dstY1,
1551 mask, filter);
1552}
1553#endif /* FEATURE_EXT_framebuffer_blit */