807fac0a393fa8a8af728c3af65a46a60070f902
[mesa.git] / src / mesa / main / fbobject.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.1
4 *
5 * Copyright (C) 1999-2006 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
26 /*
27 * Authors:
28 * Brian Paul
29 */
30
31
32 #include "context.h"
33 #include "fbobject.h"
34 #include "framebuffer.h"
35 #include "hash.h"
36 #include "renderbuffer.h"
37 #include "state.h"
38 #include "teximage.h"
39 #include "texobj.h"
40 #include "texstore.h"
41
42
43 /**
44 * Notes:
45 *
46 * None of the GL_EXT_framebuffer_object functions are compiled into
47 * display lists.
48 */
49
50
51
52 /*
53 * When glGenRender/FramebuffersEXT() is called we insert pointers to
54 * these placeholder objects into the hash table.
55 * Later, when the object ID is first bound, we replace the placeholder
56 * with the real frame/renderbuffer.
57 */
58 static struct gl_framebuffer DummyFramebuffer;
59 static struct gl_renderbuffer DummyRenderbuffer;
60
61
62 #define IS_CUBE_FACE(TARGET) \
63 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
64 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
65
66
67 /**
68 * Helper routine for getting a gl_renderbuffer.
69 */
70 struct gl_renderbuffer *
71 _mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id)
72 {
73 struct gl_renderbuffer *rb;
74
75 if (id == 0)
76 return NULL;
77
78 rb = (struct gl_renderbuffer *)
79 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
80 return rb;
81 }
82
83
84 /**
85 * Helper routine for getting a gl_framebuffer.
86 */
87 struct gl_framebuffer *
88 _mesa_lookup_framebuffer(GLcontext *ctx, GLuint id)
89 {
90 struct gl_framebuffer *fb;
91
92 if (id == 0)
93 return NULL;
94
95 fb = (struct gl_framebuffer *)
96 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
97 return fb;
98 }
99
100
101 /**
102 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
103 * gl_renderbuffer_attachment object.
104 */
105 struct gl_renderbuffer_attachment *
106 _mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
107 GLenum attachment)
108 {
109 GLuint i;
110
111 switch (attachment) {
112 case GL_COLOR_ATTACHMENT0_EXT:
113 case GL_COLOR_ATTACHMENT1_EXT:
114 case GL_COLOR_ATTACHMENT2_EXT:
115 case GL_COLOR_ATTACHMENT3_EXT:
116 case GL_COLOR_ATTACHMENT4_EXT:
117 case GL_COLOR_ATTACHMENT5_EXT:
118 case GL_COLOR_ATTACHMENT6_EXT:
119 case GL_COLOR_ATTACHMENT7_EXT:
120 case GL_COLOR_ATTACHMENT8_EXT:
121 case GL_COLOR_ATTACHMENT9_EXT:
122 case GL_COLOR_ATTACHMENT10_EXT:
123 case GL_COLOR_ATTACHMENT11_EXT:
124 case GL_COLOR_ATTACHMENT12_EXT:
125 case GL_COLOR_ATTACHMENT13_EXT:
126 case GL_COLOR_ATTACHMENT14_EXT:
127 case GL_COLOR_ATTACHMENT15_EXT:
128 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
129 if (i >= ctx->Const.MaxColorAttachments) {
130 return NULL;
131 }
132 return &fb->Attachment[BUFFER_COLOR0 + i];
133 case GL_DEPTH_ATTACHMENT_EXT:
134 return &fb->Attachment[BUFFER_DEPTH];
135 case GL_STENCIL_ATTACHMENT_EXT:
136 return &fb->Attachment[BUFFER_STENCIL];
137 default:
138 return NULL;
139 }
140 }
141
142
143 /**
144 * Remove any texture or renderbuffer attached to the given attachment
145 * point. Update reference counts, etc.
146 */
147 void
148 _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
149 {
150 if (att->Type == GL_TEXTURE) {
151 ASSERT(att->Texture);
152 att->Texture->RefCount--;
153 if (att->Texture->RefCount == 0) {
154 ctx->Driver.DeleteTexture(ctx, att->Texture);
155 }
156 else {
157 /* tell driver that we're done rendering to this texture. */
158 if (ctx->Driver.FinishRenderTexture) {
159 ctx->Driver.FinishRenderTexture(ctx, att);
160 }
161 }
162 att->Texture = NULL;
163 }
164 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
165 ASSERT(att->Renderbuffer);
166 ASSERT(!att->Texture);
167 att->Renderbuffer->RefCount--;
168 if (att->Renderbuffer->RefCount == 0) {
169 att->Renderbuffer->Delete(att->Renderbuffer);
170 }
171 att->Renderbuffer = NULL;
172 }
173 att->Type = GL_NONE;
174 att->Complete = GL_TRUE;
175 }
176
177
178 /**
179 * Bind a texture object to an attachment point.
180 * The previous binding, if any, will be removed first.
181 */
182 void
183 _mesa_set_texture_attachment(GLcontext *ctx,
184 struct gl_framebuffer *fb,
185 struct gl_renderbuffer_attachment *att,
186 struct gl_texture_object *texObj,
187 GLenum texTarget, GLuint level, GLuint zoffset)
188 {
189 if (att->Texture == texObj) {
190 /* re-attaching same texture */
191 ASSERT(att->Type == GL_TEXTURE);
192 }
193 else {
194 /* new attachment */
195 _mesa_remove_attachment(ctx, att);
196 att->Type = GL_TEXTURE;
197 att->Texture = texObj;
198 texObj->RefCount++;
199 }
200
201 /* always update these fields */
202 att->TextureLevel = level;
203 if (IS_CUBE_FACE(texTarget)) {
204 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
205 }
206 else {
207 att->CubeMapFace = 0;
208 }
209 att->Zoffset = zoffset;
210 att->Complete = GL_FALSE;
211
212 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
213 ctx->Driver.RenderTexture(ctx, fb, att);
214 }
215 }
216
217
218 /**
219 * Bind a renderbuffer to an attachment point.
220 * The previous binding, if any, will be removed first.
221 */
222 void
223 _mesa_set_renderbuffer_attachment(GLcontext *ctx,
224 struct gl_renderbuffer_attachment *att,
225 struct gl_renderbuffer *rb)
226 {
227 /* XXX check if re-doing same attachment, exit early */
228 _mesa_remove_attachment(ctx, att);
229 att->Type = GL_RENDERBUFFER_EXT;
230 att->Renderbuffer = rb;
231 att->Texture = NULL; /* just to be safe */
232 att->Complete = GL_FALSE;
233 rb->RefCount++;
234 }
235
236
237 /**
238 * Fallback for ctx->Driver.FramebufferRenderbuffer()
239 * Attach a renderbuffer object to a framebuffer object.
240 */
241 void
242 _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
243 GLenum attachment, struct gl_renderbuffer *rb)
244 {
245 struct gl_renderbuffer_attachment *att;
246
247 _glthread_LOCK_MUTEX(fb->Mutex);
248 if (rb)
249 _glthread_LOCK_MUTEX(rb->Mutex);
250
251 att = _mesa_get_attachment(ctx, fb, attachment);
252 ASSERT(att);
253
254 if (rb) {
255 _mesa_set_renderbuffer_attachment(ctx, att, rb);
256 }
257 else {
258 _mesa_remove_attachment(ctx, att);
259 }
260
261 if (rb)
262 _glthread_UNLOCK_MUTEX(rb->Mutex);
263 _glthread_UNLOCK_MUTEX(fb->Mutex);
264 }
265
266
267 /**
268 * Test if an attachment point is complete and update its Complete field.
269 * \param format if GL_COLOR, this is a color attachment point,
270 * if GL_DEPTH, this is a depth component attachment point,
271 * if GL_STENCIL, this is a stencil component attachment point.
272 */
273 static void
274 test_attachment_completeness(const GLcontext *ctx, GLenum format,
275 struct gl_renderbuffer_attachment *att)
276 {
277 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
278
279 /* assume complete */
280 att->Complete = GL_TRUE;
281
282 /* Look for reasons why the attachment might be incomplete */
283 if (att->Type == GL_TEXTURE) {
284 const struct gl_texture_object *texObj = att->Texture;
285 struct gl_texture_image *texImage;
286
287 if (!texObj) {
288 att->Complete = GL_FALSE;
289 return;
290 }
291
292 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
293 if (!texImage) {
294 att->Complete = GL_FALSE;
295 return;
296 }
297 if (texImage->Width < 1 || texImage->Height < 1) {
298 att->Complete = GL_FALSE;
299 return;
300 }
301 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
302 att->Complete = GL_FALSE;
303 return;
304 }
305
306 if (format == GL_COLOR) {
307 if (texImage->TexFormat->BaseFormat != GL_RGB &&
308 texImage->TexFormat->BaseFormat != GL_RGBA) {
309 att->Complete = GL_FALSE;
310 return;
311 }
312 }
313 else if (format == GL_DEPTH) {
314 if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) {
315 /* OK */
316 }
317 else if (ctx->Extensions.EXT_packed_depth_stencil &&
318 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
319 /* OK */
320 }
321 else {
322 att->Complete = GL_FALSE;
323 return;
324 }
325 }
326 else {
327 /* no such thing as stencil textures */
328 att->Complete = GL_FALSE;
329 return;
330 }
331 }
332 else if (att->Type == GL_RENDERBUFFER_EXT) {
333 ASSERT(att->Renderbuffer);
334 if (!att->Renderbuffer->InternalFormat ||
335 att->Renderbuffer->Width < 1 ||
336 att->Renderbuffer->Height < 1) {
337 att->Complete = GL_FALSE;
338 return;
339 }
340 if (format == GL_COLOR) {
341 if (att->Renderbuffer->_BaseFormat != GL_RGB &&
342 att->Renderbuffer->_BaseFormat != GL_RGBA) {
343 ASSERT(att->Renderbuffer->RedBits);
344 ASSERT(att->Renderbuffer->GreenBits);
345 ASSERT(att->Renderbuffer->BlueBits);
346 att->Complete = GL_FALSE;
347 return;
348 }
349 }
350 else if (format == GL_DEPTH) {
351 ASSERT(att->Renderbuffer->DepthBits);
352 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) {
353 /* OK */
354 }
355 else if (ctx->Extensions.EXT_packed_depth_stencil &&
356 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
357 /* OK */
358 }
359 else {
360 att->Complete = GL_FALSE;
361 return;
362 }
363 }
364 else {
365 assert(format == GL_STENCIL);
366 ASSERT(att->Renderbuffer->StencilBits);
367 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) {
368 /* OK */
369 }
370 else if (ctx->Extensions.EXT_packed_depth_stencil &&
371 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
372 /* OK */
373 }
374 else {
375 att->Complete = GL_FALSE;
376 return;
377 }
378 }
379 }
380 else {
381 ASSERT(att->Type == GL_NONE);
382 /* complete */
383 return;
384 }
385 }
386
387
388 /**
389 * Helpful for debugging
390 */
391 static void
392 fbo_incomplete(const char *msg, int index)
393 {
394 (void) msg;
395 (void) index;
396 /*
397 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
398 */
399 }
400
401
402 /**
403 * Test if the given framebuffer object is complete and update its
404 * Status field with the results.
405 * Also update the framebuffer's Width and Height fields if the
406 * framebuffer is complete.
407 */
408 void
409 _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
410 {
411 GLuint numImages, width = 0, height = 0;
412 GLenum intFormat = GL_NONE;
413 GLuint w = 0, h = 0;
414 GLint i;
415 GLuint j;
416
417 assert(fb->Name != 0);
418
419 numImages = 0;
420 fb->Width = 0;
421 fb->Height = 0;
422
423 /* Start at -2 to more easily loop over all attachment points */
424 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
425 struct gl_renderbuffer_attachment *att;
426 GLenum f;
427
428 if (i == -2) {
429 att = &fb->Attachment[BUFFER_DEPTH];
430 test_attachment_completeness(ctx, GL_DEPTH, att);
431 if (!att->Complete) {
432 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
433 fbo_incomplete("depth attachment incomplete", -1);
434 return;
435 }
436 }
437 else if (i == -1) {
438 att = &fb->Attachment[BUFFER_STENCIL];
439 test_attachment_completeness(ctx, GL_STENCIL, att);
440 if (!att->Complete) {
441 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
442 fbo_incomplete("stencil attachment incomplete", -1);
443 return;
444 }
445 }
446 else {
447 att = &fb->Attachment[BUFFER_COLOR0 + i];
448 test_attachment_completeness(ctx, GL_COLOR, att);
449 if (!att->Complete) {
450 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
451 fbo_incomplete("color attachment incomplete", i);
452 return;
453 }
454 }
455
456 if (att->Type == GL_TEXTURE) {
457 const struct gl_texture_image *texImg
458 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
459 w = texImg->Width;
460 h = texImg->Height;
461 f = texImg->_BaseFormat;
462 numImages++;
463 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT
464 && f != GL_DEPTH_STENCIL_EXT) {
465 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
466 fbo_incomplete("texture attachment incomplete", -1);
467 return;
468 }
469 }
470 else if (att->Type == GL_RENDERBUFFER_EXT) {
471 w = att->Renderbuffer->Width;
472 h = att->Renderbuffer->Height;
473 f = att->Renderbuffer->InternalFormat;
474 numImages++;
475 }
476 else {
477 assert(att->Type == GL_NONE);
478 continue;
479 }
480
481 if (numImages == 1) {
482 /* set required width, height and format */
483 width = w;
484 height = h;
485 if (i >= 0)
486 intFormat = f;
487 }
488 else {
489 /* check that width, height, format are same */
490 if (w != width || h != height) {
491 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
492 fbo_incomplete("width or height mismatch", -1);
493 return;
494 }
495 if (intFormat != GL_NONE && f != intFormat) {
496 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
497 fbo_incomplete("format mismatch", -1);
498 return;
499 }
500 }
501 }
502
503 /* Check that all DrawBuffers are present */
504 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
505 if (fb->ColorDrawBuffer[j] != GL_NONE) {
506 const struct gl_renderbuffer_attachment *att
507 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
508 assert(att);
509 if (att->Type == GL_NONE) {
510 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
511 fbo_incomplete("missing drawbuffer", j);
512 return;
513 }
514 }
515 }
516
517 /* Check that the ReadBuffer is present */
518 if (fb->ColorReadBuffer != GL_NONE) {
519 const struct gl_renderbuffer_attachment *att
520 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
521 assert(att);
522 if (att->Type == GL_NONE) {
523 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
524 fbo_incomplete("missing readbuffer", -1);
525 return;
526 }
527 }
528
529 if (numImages == 0) {
530 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
531 fbo_incomplete("no attachments", -1);
532 return;
533 }
534
535 /*
536 * If we get here, the framebuffer is complete!
537 */
538 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
539 fb->Width = w;
540 fb->Height = h;
541 }
542
543
544 GLboolean GLAPIENTRY
545 _mesa_IsRenderbufferEXT(GLuint renderbuffer)
546 {
547 GET_CURRENT_CONTEXT(ctx);
548 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
549 if (renderbuffer) {
550 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
551 if (rb != NULL && rb != &DummyRenderbuffer)
552 return GL_TRUE;
553 }
554 return GL_FALSE;
555 }
556
557
558 void GLAPIENTRY
559 _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
560 {
561 struct gl_renderbuffer *newRb, *oldRb;
562 GET_CURRENT_CONTEXT(ctx);
563
564 ASSERT_OUTSIDE_BEGIN_END(ctx);
565
566 if (target != GL_RENDERBUFFER_EXT) {
567 _mesa_error(ctx, GL_INVALID_ENUM,
568 "glBindRenderbufferEXT(target)");
569 return;
570 }
571
572 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
573
574 if (renderbuffer) {
575 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
576 if (newRb == &DummyRenderbuffer) {
577 /* ID was reserved, but no real renderbuffer object made yet */
578 newRb = NULL;
579 }
580 if (!newRb) {
581 /* create new renderbuffer object */
582 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
583 if (!newRb) {
584 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
585 return;
586 }
587 ASSERT(newRb->AllocStorage);
588 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
589 }
590 newRb->RefCount++;
591 }
592 else {
593 newRb = NULL;
594 }
595
596 oldRb = ctx->CurrentRenderbuffer;
597 if (oldRb) {
598 oldRb->RefCount--;
599 if (oldRb->RefCount == 0) {
600 oldRb->Delete(oldRb);
601 }
602 }
603
604 ASSERT(newRb != &DummyRenderbuffer);
605
606 ctx->CurrentRenderbuffer = newRb;
607 }
608
609
610 void GLAPIENTRY
611 _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
612 {
613 GLint i;
614 GET_CURRENT_CONTEXT(ctx);
615
616 ASSERT_OUTSIDE_BEGIN_END(ctx);
617 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
618
619 for (i = 0; i < n; i++) {
620 if (renderbuffers[i] > 0) {
621 struct gl_renderbuffer *rb;
622 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
623 if (rb) {
624 /* check if deleting currently bound renderbuffer object */
625 if (rb == ctx->CurrentRenderbuffer) {
626 /* bind default */
627 ASSERT(rb->RefCount >= 2);
628 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
629 }
630
631 /* remove from hash table immediately, to free the ID */
632 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
633
634 if (rb != &DummyRenderbuffer) {
635 /* But the object will not be freed until it's no longer
636 * bound in any context.
637 */
638 rb->RefCount--;
639 if (rb->RefCount == 0) {
640 rb->Delete(rb);
641 }
642 }
643 }
644 }
645 }
646 }
647
648
649 void GLAPIENTRY
650 _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
651 {
652 GET_CURRENT_CONTEXT(ctx);
653 GLuint first;
654 GLint i;
655
656 ASSERT_OUTSIDE_BEGIN_END(ctx);
657
658 if (n < 0) {
659 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
660 return;
661 }
662
663 if (!renderbuffers)
664 return;
665
666 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
667
668 for (i = 0; i < n; i++) {
669 GLuint name = first + i;
670 renderbuffers[i] = name;
671 /* insert dummy placeholder into hash table */
672 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
673 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
674 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
675 }
676 }
677
678
679 /**
680 * Given an internal format token for a render buffer, return the
681 * corresponding base format.
682 * This is very similar to _mesa_base_tex_format() but the set of valid
683 * internal formats is somewhat different.
684 *
685 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
686 * GL_DEPTH_STENCIL_EXT or zero if error.
687 */
688 GLenum
689 _mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
690 {
691 switch (internalFormat) {
692 case GL_RGB:
693 case GL_R3_G3_B2:
694 case GL_RGB4:
695 case GL_RGB5:
696 case GL_RGB8:
697 case GL_RGB10:
698 case GL_RGB12:
699 case GL_RGB16:
700 return GL_RGB;
701 case GL_RGBA:
702 case GL_RGBA2:
703 case GL_RGBA4:
704 case GL_RGB5_A1:
705 case GL_RGBA8:
706 case GL_RGB10_A2:
707 case GL_RGBA12:
708 case GL_RGBA16:
709 return GL_RGBA;
710 case GL_STENCIL_INDEX:
711 case GL_STENCIL_INDEX1_EXT:
712 case GL_STENCIL_INDEX4_EXT:
713 case GL_STENCIL_INDEX8_EXT:
714 case GL_STENCIL_INDEX16_EXT:
715 return GL_STENCIL_INDEX;
716 case GL_DEPTH_COMPONENT:
717 case GL_DEPTH_COMPONENT16:
718 case GL_DEPTH_COMPONENT24:
719 case GL_DEPTH_COMPONENT32:
720 return GL_DEPTH_COMPONENT;
721 case GL_DEPTH_STENCIL_EXT:
722 case GL_DEPTH24_STENCIL8_EXT:
723 if (ctx->Extensions.EXT_packed_depth_stencil)
724 return GL_DEPTH_STENCIL_EXT;
725 else
726 return 0;
727 /* XXX add floating point formats eventually */
728 default:
729 return 0;
730 }
731 }
732
733
734 void GLAPIENTRY
735 _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
736 GLsizei width, GLsizei height)
737 {
738 struct gl_renderbuffer *rb;
739 GLenum baseFormat;
740 GET_CURRENT_CONTEXT(ctx);
741
742 ASSERT_OUTSIDE_BEGIN_END(ctx);
743
744 if (target != GL_RENDERBUFFER_EXT) {
745 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)");
746 return;
747 }
748
749 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
750 if (baseFormat == 0) {
751 _mesa_error(ctx, GL_INVALID_ENUM,
752 "glRenderbufferStorageEXT(internalFormat)");
753 return;
754 }
755
756 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
757 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)");
758 return;
759 }
760
761 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
762 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)");
763 return;
764 }
765
766 rb = ctx->CurrentRenderbuffer;
767
768 if (!rb) {
769 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT");
770 return;
771 }
772
773 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
774
775 if (rb->InternalFormat == internalFormat &&
776 rb->Width == (GLuint) width &&
777 rb->Height == (GLuint) height) {
778 /* no change in allocation needed */
779 return;
780 }
781
782 /* These MUST get set by the AllocStorage func */
783 rb->_ActualFormat = 0;
784 rb->RedBits =
785 rb->GreenBits =
786 rb->BlueBits =
787 rb->AlphaBits =
788 rb->IndexBits =
789 rb->DepthBits =
790 rb->StencilBits = 0;
791
792 /* Now allocate the storage */
793 ASSERT(rb->AllocStorage);
794 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
795 /* No error - check/set fields now */
796 assert(rb->_ActualFormat);
797 assert(rb->Width == (GLuint) width);
798 assert(rb->Height == (GLuint) height);
799 assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits ||
800 rb->DepthBits || rb->StencilBits || rb->IndexBits);
801 rb->InternalFormat = internalFormat;
802 rb->_BaseFormat = baseFormat;
803 }
804 else {
805 /* Probably ran out of memory - clear the fields */
806 rb->Width = 0;
807 rb->Height = 0;
808 rb->InternalFormat = GL_NONE;
809 rb->_ActualFormat = GL_NONE;
810 rb->_BaseFormat = GL_NONE;
811 rb->RedBits =
812 rb->GreenBits =
813 rb->BlueBits =
814 rb->AlphaBits =
815 rb->IndexBits =
816 rb->DepthBits =
817 rb->StencilBits = 0;
818 }
819
820 /*
821 test_framebuffer_completeness(ctx, fb);
822 */
823 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
824 * points???
825 */
826 }
827
828
829 void GLAPIENTRY
830 _mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
831 {
832 GET_CURRENT_CONTEXT(ctx);
833
834 ASSERT_OUTSIDE_BEGIN_END(ctx);
835
836 if (target != GL_RENDERBUFFER_EXT) {
837 _mesa_error(ctx, GL_INVALID_ENUM,
838 "glGetRenderbufferParameterivEXT(target)");
839 return;
840 }
841
842 if (!ctx->CurrentRenderbuffer) {
843 _mesa_error(ctx, GL_INVALID_OPERATION,
844 "glGetRenderbufferParameterivEXT");
845 return;
846 }
847
848 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
849
850 switch (pname) {
851 case GL_RENDERBUFFER_WIDTH_EXT:
852 *params = ctx->CurrentRenderbuffer->Width;
853 return;
854 case GL_RENDERBUFFER_HEIGHT_EXT:
855 *params = ctx->CurrentRenderbuffer->Height;
856 return;
857 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
858 *params = ctx->CurrentRenderbuffer->InternalFormat;
859 return;
860 case GL_RENDERBUFFER_RED_SIZE_EXT:
861 *params = ctx->CurrentRenderbuffer->RedBits;
862 break;
863 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
864 *params = ctx->CurrentRenderbuffer->GreenBits;
865 break;
866 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
867 *params = ctx->CurrentRenderbuffer->BlueBits;
868 break;
869 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
870 *params = ctx->CurrentRenderbuffer->AlphaBits;
871 break;
872 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
873 *params = ctx->CurrentRenderbuffer->DepthBits;
874 break;
875 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
876 *params = ctx->CurrentRenderbuffer->StencilBits;
877 break;
878 default:
879 _mesa_error(ctx, GL_INVALID_ENUM,
880 "glGetRenderbufferParameterivEXT(target)");
881 return;
882 }
883 }
884
885
886 GLboolean GLAPIENTRY
887 _mesa_IsFramebufferEXT(GLuint framebuffer)
888 {
889 GET_CURRENT_CONTEXT(ctx);
890 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
891 if (framebuffer) {
892 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
893 if (rb != NULL && rb != &DummyFramebuffer)
894 return GL_TRUE;
895 }
896 return GL_FALSE;
897 }
898
899
900 static void
901 check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
902 {
903 GLuint i;
904 ASSERT(ctx->Driver.RenderTexture);
905 for (i = 0; i < BUFFER_COUNT; i++) {
906 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
907 struct gl_texture_object *texObj = att->Texture;
908 if (texObj
909 && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
910 ctx->Driver.RenderTexture(ctx, fb, att);
911 }
912 }
913 }
914
915
916 /**
917 * Examine all the framebuffer's attachments to see if any are textures.
918 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
919 * notify the device driver that the texture image may have changed.
920 */
921 static void
922 check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
923 {
924 if (ctx->Driver.FinishRenderTexture) {
925 GLuint i;
926 for (i = 0; i < BUFFER_COUNT; i++) {
927 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
928 struct gl_texture_object *texObj = att->Texture;
929 if (texObj) {
930 ctx->Driver.FinishRenderTexture(ctx, att);
931 }
932 }
933 }
934 }
935
936
937 void GLAPIENTRY
938 _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
939 {
940 struct gl_framebuffer *newFb, *oldFb;
941 GLboolean bindReadBuf, bindDrawBuf;
942 GET_CURRENT_CONTEXT(ctx);
943
944 ASSERT_OUTSIDE_BEGIN_END(ctx);
945
946 if (!ctx->Extensions.EXT_framebuffer_object) {
947 _mesa_error(ctx, GL_INVALID_OPERATION,
948 "glBindFramebufferEXT(unsupported)");
949 return;
950 }
951
952 switch (target) {
953 #if FEATURE_EXT_framebuffer_blit
954 case GL_DRAW_FRAMEBUFFER_EXT:
955 if (!ctx->Extensions.EXT_framebuffer_blit) {
956 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
957 return;
958 }
959 bindDrawBuf = GL_TRUE;
960 bindReadBuf = GL_FALSE;
961 break;
962 case GL_READ_FRAMEBUFFER_EXT:
963 if (!ctx->Extensions.EXT_framebuffer_blit) {
964 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
965 return;
966 }
967 bindDrawBuf = GL_FALSE;
968 bindReadBuf = GL_TRUE;
969 break;
970 #endif
971 case GL_FRAMEBUFFER_EXT:
972 bindDrawBuf = GL_TRUE;
973 bindReadBuf = GL_TRUE;
974 break;
975 default:
976 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
977 return;
978 }
979
980 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
981
982 if (framebuffer) {
983 /* Binding a user-created framebuffer object */
984 newFb = _mesa_lookup_framebuffer(ctx, framebuffer);
985 if (newFb == &DummyFramebuffer) {
986 /* ID was reserved, but no real framebuffer object made yet */
987 newFb = NULL;
988 }
989 if (!newFb) {
990 /* create new framebuffer object */
991 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
992 if (!newFb) {
993 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
994 return;
995 }
996 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
997 }
998 _glthread_LOCK_MUTEX(newFb->Mutex);
999 if (bindReadBuf)
1000 newFb->RefCount++;
1001 if (bindDrawBuf)
1002 newFb->RefCount++;
1003 _glthread_UNLOCK_MUTEX(newFb->Mutex);
1004 }
1005 else {
1006 /* Binding the window system framebuffer (which was originally set
1007 * with MakeCurrent).
1008 */
1009 newFb = ctx->WinSysDrawBuffer;
1010 }
1011
1012 ASSERT(newFb);
1013 ASSERT(newFb != &DummyFramebuffer);
1014
1015 /*
1016 * XXX check if re-binding same buffer and skip some of this code.
1017 */
1018
1019 if (bindReadBuf) {
1020 oldFb = ctx->ReadBuffer;
1021 if (oldFb && oldFb->Name != 0) {
1022 _glthread_LOCK_MUTEX(oldFb->Mutex);
1023 oldFb->RefCount--;
1024 _glthread_UNLOCK_MUTEX(oldFb->Mutex);
1025 if (oldFb->RefCount == 0) {
1026 oldFb->Delete(oldFb);
1027 }
1028 }
1029 ctx->ReadBuffer = newFb;
1030 }
1031
1032 if (bindDrawBuf) {
1033 oldFb = ctx->DrawBuffer;
1034 if (oldFb && oldFb->Name != 0) {
1035 /* check if old FB had any texture attachments */
1036 check_end_texture_render(ctx, oldFb);
1037 /* check if time to delete this framebuffer */
1038 _glthread_LOCK_MUTEX(oldFb->Mutex);
1039 oldFb->RefCount--;
1040 if (oldFb->RefCount == 0) {
1041 oldFb->Delete(oldFb);
1042 }
1043 _glthread_UNLOCK_MUTEX(oldFb->Mutex);
1044 }
1045 ctx->DrawBuffer = newFb;
1046 if (newFb->Name != 0) {
1047 /* check if newly bound framebuffer has any texture attachments */
1048 check_begin_texture_render(ctx, newFb);
1049 }
1050 }
1051
1052 if (ctx->Driver.BindFramebuffer) {
1053 ctx->Driver.BindFramebuffer(ctx, target, newFb);
1054 }
1055 }
1056
1057
1058 void GLAPIENTRY
1059 _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1060 {
1061 GLint i;
1062 GET_CURRENT_CONTEXT(ctx);
1063
1064 ASSERT_OUTSIDE_BEGIN_END(ctx);
1065 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1066
1067 for (i = 0; i < n; i++) {
1068 if (framebuffers[i] > 0) {
1069 struct gl_framebuffer *fb;
1070 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
1071 if (fb) {
1072 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
1073
1074 /* check if deleting currently bound framebuffer object */
1075 if (fb == ctx->DrawBuffer) {
1076 /* bind default */
1077 ASSERT(fb->RefCount >= 2);
1078 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1079 }
1080
1081 /* remove from hash table immediately, to free the ID */
1082 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
1083
1084 if (fb != &DummyFramebuffer) {
1085 /* But the object will not be freed until it's no longer
1086 * bound in any context.
1087 */
1088 _glthread_LOCK_MUTEX(fb->Mutex);
1089 fb->RefCount--;
1090 _glthread_UNLOCK_MUTEX(fb->Mutex);
1091 if (fb->RefCount == 0) {
1092 fb->Delete(fb);
1093 }
1094 }
1095 }
1096 }
1097 }
1098 }
1099
1100
1101 void GLAPIENTRY
1102 _mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1103 {
1104 GET_CURRENT_CONTEXT(ctx);
1105 GLuint first;
1106 GLint i;
1107
1108 ASSERT_OUTSIDE_BEGIN_END(ctx);
1109
1110 if (n < 0) {
1111 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1112 return;
1113 }
1114
1115 if (!framebuffers)
1116 return;
1117
1118 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1119
1120 for (i = 0; i < n; i++) {
1121 GLuint name = first + i;
1122 framebuffers[i] = name;
1123 /* insert dummy placeholder into hash table */
1124 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
1125 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
1126 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1127 }
1128 }
1129
1130
1131
1132 GLenum GLAPIENTRY
1133 _mesa_CheckFramebufferStatusEXT(GLenum target)
1134 {
1135 struct gl_framebuffer *buffer;
1136 GET_CURRENT_CONTEXT(ctx);
1137
1138 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1139
1140 switch (target) {
1141 #if FEATURE_EXT_framebuffer_blit
1142 case GL_DRAW_FRAMEBUFFER_EXT:
1143 if (!ctx->Extensions.EXT_framebuffer_blit) {
1144 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1145 return 0;
1146 }
1147 buffer = ctx->DrawBuffer;
1148 break;
1149 case GL_READ_FRAMEBUFFER_EXT:
1150 if (!ctx->Extensions.EXT_framebuffer_blit) {
1151 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1152 return 0;
1153 }
1154 buffer = ctx->ReadBuffer;
1155 break;
1156 #endif
1157 case GL_FRAMEBUFFER_EXT:
1158 buffer = ctx->DrawBuffer;
1159 break;
1160 default:
1161 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1162 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
1163 }
1164
1165 if (buffer->Name == 0) {
1166 /* The window system / default framebuffer is always complete */
1167 return GL_FRAMEBUFFER_COMPLETE_EXT;
1168 }
1169
1170 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1171
1172 _mesa_test_framebuffer_completeness(ctx, buffer);
1173 return buffer->_Status;
1174 }
1175
1176
1177
1178 /**
1179 * Common code called by glFramebufferTexture1D/2D/3DEXT().
1180 */
1181 static void
1182 framebuffer_texture(GLuint dims, GLenum target, GLenum attachment,
1183 GLenum textarget, GLuint texture,
1184 GLint level, GLint zoffset)
1185 {
1186 struct gl_renderbuffer_attachment *att;
1187 struct gl_texture_object *texObj = NULL;
1188 struct gl_framebuffer *fb;
1189 GET_CURRENT_CONTEXT(ctx);
1190
1191 ASSERT_OUTSIDE_BEGIN_END(ctx);
1192
1193 if (target != GL_FRAMEBUFFER_EXT) {
1194 _mesa_error(ctx, GL_INVALID_ENUM,
1195 "glFramebufferTexture%dDEXT(target)", dims);
1196 return;
1197 }
1198
1199 fb = ctx->DrawBuffer;
1200 ASSERT(fb);
1201
1202 /* check framebuffer binding */
1203 if (fb->Name == 0) {
1204 _mesa_error(ctx, GL_INVALID_OPERATION,
1205 "glFramebufferTexture%dDEXT", dims);
1206 return;
1207 }
1208
1209 if (texture) {
1210 texObj = _mesa_lookup_texture(ctx, texture);
1211 }
1212
1213 /* Check dimension-dependent things */
1214 switch (dims) {
1215 case 1:
1216 if (textarget != GL_TEXTURE_1D) {
1217 _mesa_error(ctx, GL_INVALID_ENUM,
1218 "glFramebufferTexture1DEXT(textarget)");
1219 return;
1220 }
1221 if (texObj && texObj->Target != GL_TEXTURE_1D) {
1222 _mesa_error(ctx, GL_INVALID_OPERATION,
1223 "glFramebufferTexture1DEXT(texture target mismatch)");
1224 return;
1225 }
1226 break;
1227 case 2:
1228 if (textarget != GL_TEXTURE_2D &&
1229 textarget != GL_TEXTURE_RECTANGLE_ARB &&
1230 !IS_CUBE_FACE(textarget)) {
1231 _mesa_error(ctx, GL_INVALID_ENUM,
1232 "glFramebufferTexture2DEXT(textarget)");
1233 return;
1234 }
1235 if (texObj) {
1236 if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) ||
1237 (texObj->Target == GL_TEXTURE_RECTANGLE_ARB
1238 && textarget != GL_TEXTURE_RECTANGLE_ARB) ||
1239 (texObj->Target == GL_TEXTURE_CUBE_MAP
1240 && !IS_CUBE_FACE(textarget))) {
1241 _mesa_error(ctx, GL_INVALID_OPERATION,
1242 "glFramebufferTexture1DEXT(texture target mismatch)");
1243 return;
1244 }
1245 }
1246 break;
1247 case 3:
1248 if (textarget != GL_TEXTURE_3D) {
1249 _mesa_error(ctx, GL_INVALID_ENUM,
1250 "glFramebufferTexture3DEXT(textarget)");
1251 return;
1252 }
1253 if (texObj && texObj->Target != GL_TEXTURE_3D) {
1254 _mesa_error(ctx, GL_INVALID_OPERATION,
1255 "glFramebufferTexture3DEXT(texture target mismatch)");
1256 return;
1257 }
1258 {
1259 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1260 if (zoffset < 0 || zoffset >= maxSize) {
1261 _mesa_error(ctx, GL_INVALID_VALUE,
1262 "glFramebufferTexture3DEXT(zoffset)");
1263 return;
1264 }
1265 }
1266 break;
1267 default:
1268 _mesa_problem(ctx, "Unexpected dims in error_check_framebuffer_texture");
1269 return;
1270 }
1271
1272 if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) {
1273 _mesa_error(ctx, GL_INVALID_VALUE,
1274 "glFramebufferTexture%dDEXT(level)", dims);
1275 return;
1276 }
1277
1278 att = _mesa_get_attachment(ctx, fb, attachment);
1279 if (att == NULL) {
1280 _mesa_error(ctx, GL_INVALID_ENUM,
1281 "glFramebufferTexture%dDEXT(attachment)", dims);
1282 return;
1283 }
1284
1285 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1286
1287 _glthread_LOCK_MUTEX(fb->Mutex);
1288 if (texObj) {
1289 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1290 level, zoffset);
1291 }
1292 else {
1293 _mesa_remove_attachment(ctx, att);
1294 }
1295 _glthread_UNLOCK_MUTEX(fb->Mutex);
1296 }
1297
1298
1299
1300 void GLAPIENTRY
1301 _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1302 GLenum textarget, GLuint texture, GLint level)
1303 {
1304 const GLint zoffset = 0;
1305 framebuffer_texture(1, target, attachment, textarget, texture,
1306 level, zoffset);
1307 }
1308
1309
1310 void GLAPIENTRY
1311 _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1312 GLenum textarget, GLuint texture, GLint level)
1313 {
1314 const GLint zoffset = 0;
1315 framebuffer_texture(2, target, attachment, textarget, texture,
1316 level, zoffset);
1317 }
1318
1319
1320 void GLAPIENTRY
1321 _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1322 GLenum textarget, GLuint texture,
1323 GLint level, GLint zoffset)
1324 {
1325 framebuffer_texture(3, target, attachment, textarget, texture,
1326 level, zoffset);
1327 }
1328
1329
1330
1331 void GLAPIENTRY
1332 _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1333 GLenum renderbufferTarget,
1334 GLuint renderbuffer)
1335 {
1336 struct gl_renderbuffer_attachment *att;
1337 struct gl_framebuffer *fb;
1338 struct gl_renderbuffer *rb;
1339 GET_CURRENT_CONTEXT(ctx);
1340
1341 ASSERT_OUTSIDE_BEGIN_END(ctx);
1342
1343 switch (target) {
1344 #if FEATURE_EXT_framebuffer_blit
1345 case GL_DRAW_FRAMEBUFFER_EXT:
1346 if (!ctx->Extensions.EXT_framebuffer_blit) {
1347 _mesa_error(ctx, GL_INVALID_ENUM,
1348 "glFramebufferRenderbufferEXT(target)");
1349 return;
1350 }
1351 fb = ctx->DrawBuffer;
1352 break;
1353 case GL_READ_FRAMEBUFFER_EXT:
1354 if (!ctx->Extensions.EXT_framebuffer_blit) {
1355 _mesa_error(ctx, GL_INVALID_ENUM,
1356 "glFramebufferRenderbufferEXT(target)");
1357 return;
1358 }
1359 fb = ctx->ReadBuffer;
1360 break;
1361 #endif
1362 case GL_FRAMEBUFFER_EXT:
1363 fb = ctx->DrawBuffer;
1364 break;
1365 default:
1366 _mesa_error(ctx, GL_INVALID_ENUM,
1367 "glFramebufferRenderbufferEXT(target)");
1368 return;
1369 }
1370
1371 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
1372 _mesa_error(ctx, GL_INVALID_ENUM,
1373 "glFramebufferRenderbufferEXT(renderbufferTarget)");
1374 return;
1375 }
1376
1377 if (fb->Name == 0) {
1378 /* Can't attach new renderbuffers to a window system framebuffer */
1379 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1380 return;
1381 }
1382
1383 att = _mesa_get_attachment(ctx, fb, attachment);
1384 if (att == NULL) {
1385 _mesa_error(ctx, GL_INVALID_ENUM,
1386 "glFramebufferRenderbufferEXT(attachment)");
1387 return;
1388 }
1389
1390 if (renderbuffer) {
1391 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
1392 if (!rb) {
1393 _mesa_error(ctx, GL_INVALID_OPERATION,
1394 "glFramebufferRenderbufferEXT(renderbuffer)");
1395 return;
1396 }
1397 }
1398 else {
1399 /* remove renderbuffer attachment */
1400 rb = NULL;
1401 }
1402
1403 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1404
1405 assert(ctx->Driver.FramebufferRenderbuffer);
1406 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
1407
1408 /* Some subsequent GL commands may depend on the framebuffer's visual
1409 * after the binding is updated. Update visual info now.
1410 */
1411 _mesa_update_framebuffer_visual(fb);
1412 }
1413
1414
1415 void GLAPIENTRY
1416 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1417 GLenum pname, GLint *params)
1418 {
1419 const struct gl_renderbuffer_attachment *att;
1420 struct gl_framebuffer *buffer;
1421 GET_CURRENT_CONTEXT(ctx);
1422
1423 ASSERT_OUTSIDE_BEGIN_END(ctx);
1424
1425 switch (target) {
1426 #if FEATURE_EXT_framebuffer_blit
1427 case GL_DRAW_FRAMEBUFFER_EXT:
1428 if (!ctx->Extensions.EXT_framebuffer_blit) {
1429 _mesa_error(ctx, GL_INVALID_ENUM,
1430 "glGetFramebufferAttachmentParameterivEXT(target)");
1431 return;
1432 }
1433 buffer = ctx->DrawBuffer;
1434 break;
1435 case GL_READ_FRAMEBUFFER_EXT:
1436 if (!ctx->Extensions.EXT_framebuffer_blit) {
1437 _mesa_error(ctx, GL_INVALID_ENUM,
1438 "glGetFramebufferAttachmentParameterivEXT(target)");
1439 return;
1440 }
1441 buffer = ctx->ReadBuffer;
1442 break;
1443 #endif
1444 case GL_FRAMEBUFFER_EXT:
1445 buffer = ctx->DrawBuffer;
1446 break;
1447 default:
1448 _mesa_error(ctx, GL_INVALID_ENUM,
1449 "glGetFramebufferAttachmentParameterivEXT(target)");
1450 return;
1451 }
1452
1453 if (buffer->Name == 0) {
1454 _mesa_error(ctx, GL_INVALID_OPERATION,
1455 "glGetFramebufferAttachmentParameterivEXT");
1456 return;
1457 }
1458
1459 att = _mesa_get_attachment(ctx, buffer, attachment);
1460 if (att == NULL) {
1461 _mesa_error(ctx, GL_INVALID_ENUM,
1462 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1463 return;
1464 }
1465
1466 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1467
1468 switch (pname) {
1469 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
1470 *params = att->Type;
1471 return;
1472 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
1473 if (att->Type == GL_RENDERBUFFER_EXT) {
1474 *params = att->Renderbuffer->Name;
1475 }
1476 else if (att->Type == GL_TEXTURE) {
1477 *params = att->Texture->Name;
1478 }
1479 else {
1480 _mesa_error(ctx, GL_INVALID_ENUM,
1481 "glGetFramebufferAttachmentParameterivEXT(pname)");
1482 }
1483 return;
1484 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
1485 if (att->Type == GL_TEXTURE) {
1486 *params = att->TextureLevel;
1487 }
1488 else {
1489 _mesa_error(ctx, GL_INVALID_ENUM,
1490 "glGetFramebufferAttachmentParameterivEXT(pname)");
1491 }
1492 return;
1493 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
1494 if (att->Type == GL_TEXTURE) {
1495 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1496 }
1497 else {
1498 _mesa_error(ctx, GL_INVALID_ENUM,
1499 "glGetFramebufferAttachmentParameterivEXT(pname)");
1500 }
1501 return;
1502 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
1503 if (att->Type == GL_TEXTURE) {
1504 *params = att->Zoffset;
1505 }
1506 else {
1507 _mesa_error(ctx, GL_INVALID_ENUM,
1508 "glGetFramebufferAttachmentParameterivEXT(pname)");
1509 }
1510 return;
1511 default:
1512 _mesa_error(ctx, GL_INVALID_ENUM,
1513 "glGetFramebufferAttachmentParameterivEXT(pname)");
1514 return;
1515 }
1516 }
1517
1518
1519 void GLAPIENTRY
1520 _mesa_GenerateMipmapEXT(GLenum target)
1521 {
1522 struct gl_texture_unit *texUnit;
1523 struct gl_texture_object *texObj;
1524 GET_CURRENT_CONTEXT(ctx);
1525
1526 ASSERT_OUTSIDE_BEGIN_END(ctx);
1527 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1528
1529 switch (target) {
1530 case GL_TEXTURE_1D:
1531 case GL_TEXTURE_2D:
1532 case GL_TEXTURE_3D:
1533 case GL_TEXTURE_CUBE_MAP:
1534 /* OK, legal value */
1535 break;
1536 default:
1537 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
1538 return;
1539 }
1540
1541 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1542 texObj = _mesa_select_tex_object(ctx, texUnit, target);
1543
1544 /* XXX this might not handle cube maps correctly */
1545 _mesa_generate_mipmap(ctx, target, texUnit, texObj);
1546 }
1547
1548
1549 #if FEATURE_EXT_framebuffer_blit
1550 void GLAPIENTRY
1551 _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
1552 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
1553 GLbitfield mask, GLenum filter)
1554 {
1555 GET_CURRENT_CONTEXT(ctx);
1556
1557 ASSERT_OUTSIDE_BEGIN_END(ctx);
1558 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1559
1560 if (ctx->NewState) {
1561 _mesa_update_state(ctx);
1562 }
1563
1564 if (!ctx->ReadBuffer) {
1565 /* XXX */
1566 }
1567
1568 /* check for complete framebuffers */
1569 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
1570 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1571 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
1572 "glBlitFramebufferEXT(incomplete draw/read buffers)");
1573 return;
1574 }
1575
1576 if (filter != GL_NEAREST && filter != GL_LINEAR) {
1577 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
1578 return;
1579 }
1580
1581 if (mask & ~(GL_COLOR_BUFFER_BIT |
1582 GL_DEPTH_BUFFER_BIT |
1583 GL_STENCIL_BUFFER_BIT)) {
1584 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
1585 return;
1586 }
1587
1588 /* depth/stencil must be blitted with nearest filtering */
1589 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
1590 && filter != GL_NEAREST) {
1591 _mesa_error(ctx, GL_INVALID_OPERATION,
1592 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
1593 return;
1594 }
1595
1596 if (mask & GL_STENCIL_BUFFER_BIT) {
1597 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_StencilBuffer;
1598 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_StencilBuffer;
1599 if (readRb->StencilBits != drawRb->StencilBits) {
1600 _mesa_error(ctx, GL_INVALID_OPERATION,
1601 "glBlitFramebufferEXT(stencil buffer size mismatch");
1602 return;
1603 }
1604 }
1605
1606 if (mask & GL_DEPTH_BUFFER_BIT) {
1607 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_DepthBuffer;
1608 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_DepthBuffer;
1609 if (readRb->DepthBits != drawRb->DepthBits) {
1610 _mesa_error(ctx, GL_INVALID_OPERATION,
1611 "glBlitFramebufferEXT(depth buffer size mismatch");
1612 return;
1613 }
1614 }
1615
1616 if (!ctx->Extensions.EXT_framebuffer_blit) {
1617 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
1618 return;
1619 }
1620
1621 ASSERT(ctx->Driver.BlitFramebuffer);
1622 ctx->Driver.BlitFramebuffer(ctx,
1623 srcX0, srcY0, srcX1, srcY1,
1624 dstX0, dstY0, dstX1, dstY1,
1625 mask, filter);
1626 }
1627 #endif /* FEATURE_EXT_framebuffer_blit */