mesa: fix attachment error checking for glGetFramebufferAttachmentParameteriv()
[mesa.git] / src / mesa / main / fbobject.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 /*
28 * GL_EXT/ARB_framebuffer_object extensions
29 *
30 * Authors:
31 * Brian Paul
32 */
33
34
35 #include "buffers.h"
36 #include "context.h"
37 #include "enums.h"
38 #include "fbobject.h"
39 #include "formats.h"
40 #include "framebuffer.h"
41 #include "hash.h"
42 #include "macros.h"
43 #include "renderbuffer.h"
44 #include "state.h"
45 #include "teximage.h"
46 #include "texobj.h"
47
48
49 /** Set this to 1 to help debug FBO incompleteness problems */
50 #define DEBUG_FBO 0
51
52 /** Set this to 1 to debug/log glBlitFramebuffer() calls */
53 #define DEBUG_BLIT 0
54
55
56 /**
57 * Notes:
58 *
59 * None of the GL_EXT_framebuffer_object functions are compiled into
60 * display lists.
61 */
62
63
64
65 /*
66 * When glGenRender/FramebuffersEXT() is called we insert pointers to
67 * these placeholder objects into the hash table.
68 * Later, when the object ID is first bound, we replace the placeholder
69 * with the real frame/renderbuffer.
70 */
71 static struct gl_framebuffer DummyFramebuffer;
72 static struct gl_renderbuffer DummyRenderbuffer;
73
74
75 #define IS_CUBE_FACE(TARGET) \
76 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
77 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
78
79
80 static void
81 delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
82 {
83 /* no op */
84 }
85
86 static void
87 delete_dummy_framebuffer(struct gl_framebuffer *fb)
88 {
89 /* no op */
90 }
91
92
93 void
94 _mesa_init_fbobjects(GLcontext *ctx)
95 {
96 DummyFramebuffer.Delete = delete_dummy_framebuffer;
97 DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
98 }
99
100
101 /**
102 * Helper routine for getting a gl_renderbuffer.
103 */
104 struct gl_renderbuffer *
105 _mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id)
106 {
107 struct gl_renderbuffer *rb;
108
109 if (id == 0)
110 return NULL;
111
112 rb = (struct gl_renderbuffer *)
113 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
114 return rb;
115 }
116
117
118 /**
119 * Helper routine for getting a gl_framebuffer.
120 */
121 struct gl_framebuffer *
122 _mesa_lookup_framebuffer(GLcontext *ctx, GLuint id)
123 {
124 struct gl_framebuffer *fb;
125
126 if (id == 0)
127 return NULL;
128
129 fb = (struct gl_framebuffer *)
130 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
131 return fb;
132 }
133
134
135 /**
136 * Mark the given framebuffer as invalid. This will force the
137 * test for framebuffer completeness to be done before the framebuffer
138 * is used.
139 */
140 static void
141 invalidate_framebuffer(struct gl_framebuffer *fb)
142 {
143 fb->_Status = 0; /* "indeterminate" */
144 }
145
146
147 /**
148 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
149 * gl_renderbuffer_attachment object.
150 * This function is only used for user-created FB objects, not the
151 * default / window-system FB object.
152 * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
153 * the depth buffer attachment point.
154 */
155 struct gl_renderbuffer_attachment *
156 _mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
157 GLenum attachment)
158 {
159 GLuint i;
160
161 assert(fb->Name > 0);
162
163 switch (attachment) {
164 case GL_COLOR_ATTACHMENT0_EXT:
165 case GL_COLOR_ATTACHMENT1_EXT:
166 case GL_COLOR_ATTACHMENT2_EXT:
167 case GL_COLOR_ATTACHMENT3_EXT:
168 case GL_COLOR_ATTACHMENT4_EXT:
169 case GL_COLOR_ATTACHMENT5_EXT:
170 case GL_COLOR_ATTACHMENT6_EXT:
171 case GL_COLOR_ATTACHMENT7_EXT:
172 case GL_COLOR_ATTACHMENT8_EXT:
173 case GL_COLOR_ATTACHMENT9_EXT:
174 case GL_COLOR_ATTACHMENT10_EXT:
175 case GL_COLOR_ATTACHMENT11_EXT:
176 case GL_COLOR_ATTACHMENT12_EXT:
177 case GL_COLOR_ATTACHMENT13_EXT:
178 case GL_COLOR_ATTACHMENT14_EXT:
179 case GL_COLOR_ATTACHMENT15_EXT:
180 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
181 if (i >= ctx->Const.MaxColorAttachments) {
182 return NULL;
183 }
184 return &fb->Attachment[BUFFER_COLOR0 + i];
185 case GL_DEPTH_STENCIL_ATTACHMENT:
186 /* fall-through */
187 case GL_DEPTH_BUFFER:
188 /* fall-through / new in GL 3.0 */
189 case GL_DEPTH_ATTACHMENT_EXT:
190 return &fb->Attachment[BUFFER_DEPTH];
191 case GL_STENCIL_BUFFER:
192 /* fall-through / new in GL 3.0 */
193 case GL_STENCIL_ATTACHMENT_EXT:
194 return &fb->Attachment[BUFFER_STENCIL];
195 default:
196 return NULL;
197 }
198 }
199
200
201 /**
202 * As above, but only used for getting attachments of the default /
203 * window-system framebuffer (not user-created framebuffer objects).
204 */
205 static struct gl_renderbuffer_attachment *
206 _mesa_get_fb0_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
207 GLenum attachment)
208 {
209 assert(fb->Name == 0);
210
211 switch (attachment) {
212 case GL_FRONT_LEFT:
213 return &fb->Attachment[BUFFER_FRONT_LEFT];
214 case GL_FRONT_RIGHT:
215 return &fb->Attachment[BUFFER_FRONT_RIGHT];
216 case GL_BACK_LEFT:
217 return &fb->Attachment[BUFFER_BACK_LEFT];
218 case GL_BACK_RIGHT:
219 return &fb->Attachment[BUFFER_BACK_RIGHT];
220 case GL_AUX0:
221 if (fb->Visual.numAuxBuffers == 1) {
222 return &fb->Attachment[BUFFER_AUX0];
223 }
224 return NULL;
225 case GL_DEPTH_BUFFER:
226 /* fall-through / new in GL 3.0 */
227 case GL_DEPTH_ATTACHMENT_EXT:
228 return &fb->Attachment[BUFFER_DEPTH];
229 case GL_STENCIL_BUFFER:
230 /* fall-through / new in GL 3.0 */
231 case GL_STENCIL_ATTACHMENT_EXT:
232 return &fb->Attachment[BUFFER_STENCIL];
233 default:
234 return NULL;
235 }
236 }
237
238
239
240 /**
241 * Remove any texture or renderbuffer attached to the given attachment
242 * point. Update reference counts, etc.
243 */
244 void
245 _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
246 {
247 if (att->Type == GL_TEXTURE) {
248 ASSERT(att->Texture);
249 if (ctx->Driver.FinishRenderTexture) {
250 /* tell driver that we're done rendering to this texture. */
251 ctx->Driver.FinishRenderTexture(ctx, att);
252 }
253 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
254 ASSERT(!att->Texture);
255 }
256 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
257 ASSERT(!att->Texture);
258 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
259 ASSERT(!att->Renderbuffer);
260 }
261 att->Type = GL_NONE;
262 att->Complete = GL_TRUE;
263 }
264
265
266 /**
267 * Bind a texture object to an attachment point.
268 * The previous binding, if any, will be removed first.
269 */
270 void
271 _mesa_set_texture_attachment(GLcontext *ctx,
272 struct gl_framebuffer *fb,
273 struct gl_renderbuffer_attachment *att,
274 struct gl_texture_object *texObj,
275 GLenum texTarget, GLuint level, GLuint zoffset)
276 {
277 if (att->Texture == texObj) {
278 /* re-attaching same texture */
279 ASSERT(att->Type == GL_TEXTURE);
280 if (ctx->Driver.FinishRenderTexture)
281 ctx->Driver.FinishRenderTexture(ctx, att);
282 }
283 else {
284 /* new attachment */
285 if (ctx->Driver.FinishRenderTexture && att->Texture)
286 ctx->Driver.FinishRenderTexture(ctx, att);
287 _mesa_remove_attachment(ctx, att);
288 att->Type = GL_TEXTURE;
289 assert(!att->Texture);
290 _mesa_reference_texobj(&att->Texture, texObj);
291 }
292
293 /* always update these fields */
294 att->TextureLevel = level;
295 att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
296 att->Zoffset = zoffset;
297 att->Complete = GL_FALSE;
298
299 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
300 ctx->Driver.RenderTexture(ctx, fb, att);
301 }
302
303 invalidate_framebuffer(fb);
304 }
305
306
307 /**
308 * Bind a renderbuffer to an attachment point.
309 * The previous binding, if any, will be removed first.
310 */
311 void
312 _mesa_set_renderbuffer_attachment(GLcontext *ctx,
313 struct gl_renderbuffer_attachment *att,
314 struct gl_renderbuffer *rb)
315 {
316 /* XXX check if re-doing same attachment, exit early */
317 _mesa_remove_attachment(ctx, att);
318 att->Type = GL_RENDERBUFFER_EXT;
319 att->Texture = NULL; /* just to be safe */
320 att->Complete = GL_FALSE;
321 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
322 }
323
324
325 /**
326 * Fallback for ctx->Driver.FramebufferRenderbuffer()
327 * Attach a renderbuffer object to a framebuffer object.
328 */
329 void
330 _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
331 GLenum attachment, struct gl_renderbuffer *rb)
332 {
333 struct gl_renderbuffer_attachment *att;
334
335 _glthread_LOCK_MUTEX(fb->Mutex);
336
337 att = _mesa_get_attachment(ctx, fb, attachment);
338 ASSERT(att);
339 if (rb) {
340 _mesa_set_renderbuffer_attachment(ctx, att, rb);
341 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
342 /* do stencil attachment here (depth already done above) */
343 att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
344 assert(att);
345 _mesa_set_renderbuffer_attachment(ctx, att, rb);
346 }
347 }
348 else {
349 _mesa_remove_attachment(ctx, att);
350 }
351
352 invalidate_framebuffer(fb);
353
354 _glthread_UNLOCK_MUTEX(fb->Mutex);
355 }
356
357
358 /**
359 * For debug only.
360 */
361 static void
362 att_incomplete(const char *msg)
363 {
364 #if DEBUG_FBO
365 _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
366 #else
367 (void) msg;
368 #endif
369 }
370
371
372 /**
373 * For debug only.
374 */
375 static void
376 fbo_incomplete(const char *msg, int index)
377 {
378 #if DEBUG_FBO
379 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
380 #else
381 (void) msg;
382 (void) index;
383 #endif
384 }
385
386
387
388
389 /**
390 * Test if an attachment point is complete and update its Complete field.
391 * \param format if GL_COLOR, this is a color attachment point,
392 * if GL_DEPTH, this is a depth component attachment point,
393 * if GL_STENCIL, this is a stencil component attachment point.
394 */
395 static void
396 test_attachment_completeness(const GLcontext *ctx, GLenum format,
397 struct gl_renderbuffer_attachment *att)
398 {
399 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
400
401 /* assume complete */
402 att->Complete = GL_TRUE;
403
404 /* Look for reasons why the attachment might be incomplete */
405 if (att->Type == GL_TEXTURE) {
406 const struct gl_texture_object *texObj = att->Texture;
407 struct gl_texture_image *texImage;
408 GLenum baseFormat;
409
410 if (!texObj) {
411 att_incomplete("no texobj");
412 att->Complete = GL_FALSE;
413 return;
414 }
415
416 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
417 if (!texImage) {
418 att_incomplete("no teximage");
419 att->Complete = GL_FALSE;
420 return;
421 }
422 if (texImage->Width < 1 || texImage->Height < 1) {
423 att_incomplete("teximage width/height=0");
424 printf("texobj = %u\n", texObj->Name);
425 printf("level = %d\n", att->TextureLevel);
426 att->Complete = GL_FALSE;
427 return;
428 }
429 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
430 att_incomplete("bad z offset");
431 att->Complete = GL_FALSE;
432 return;
433 }
434
435 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
436
437 if (format == GL_COLOR) {
438 if (baseFormat != GL_RGB &&
439 baseFormat != GL_RGBA &&
440 (!ctx->Extensions.ARB_framebuffer_object ||
441 baseFormat != GL_ALPHA)) {
442 att_incomplete("bad format");
443 att->Complete = GL_FALSE;
444 return;
445 }
446 if (_mesa_is_format_compressed(texImage->TexFormat)) {
447 att_incomplete("compressed internalformat");
448 att->Complete = GL_FALSE;
449 return;
450 }
451 }
452 else if (format == GL_DEPTH) {
453 if (baseFormat == GL_DEPTH_COMPONENT) {
454 /* OK */
455 }
456 else if (ctx->Extensions.EXT_packed_depth_stencil &&
457 ctx->Extensions.ARB_depth_texture &&
458 baseFormat == GL_DEPTH_STENCIL_EXT) {
459 /* OK */
460 }
461 else {
462 att->Complete = GL_FALSE;
463 att_incomplete("bad depth format");
464 return;
465 }
466 }
467 else {
468 ASSERT(format == GL_STENCIL);
469 if (ctx->Extensions.EXT_packed_depth_stencil &&
470 ctx->Extensions.ARB_depth_texture &&
471 baseFormat == GL_DEPTH_STENCIL_EXT) {
472 /* OK */
473 }
474 else {
475 /* no such thing as stencil-only textures */
476 att_incomplete("illegal stencil texture");
477 att->Complete = GL_FALSE;
478 return;
479 }
480 }
481 }
482 else if (att->Type == GL_RENDERBUFFER_EXT) {
483 const GLenum baseFormat =
484 _mesa_get_format_base_format(att->Renderbuffer->Format);
485
486 ASSERT(att->Renderbuffer);
487 if (!att->Renderbuffer->InternalFormat ||
488 att->Renderbuffer->Width < 1 ||
489 att->Renderbuffer->Height < 1) {
490 att_incomplete("0x0 renderbuffer");
491 att->Complete = GL_FALSE;
492 return;
493 }
494 if (format == GL_COLOR) {
495 if (baseFormat != GL_RGB &&
496 baseFormat != GL_RGBA) {
497 att_incomplete("bad renderbuffer color format");
498 att->Complete = GL_FALSE;
499 return;
500 }
501 }
502 else if (format == GL_DEPTH) {
503 if (baseFormat == GL_DEPTH_COMPONENT) {
504 /* OK */
505 }
506 else if (ctx->Extensions.EXT_packed_depth_stencil &&
507 baseFormat == GL_DEPTH_STENCIL_EXT) {
508 /* OK */
509 }
510 else {
511 att_incomplete("bad renderbuffer depth format");
512 att->Complete = GL_FALSE;
513 return;
514 }
515 }
516 else {
517 assert(format == GL_STENCIL);
518 if (baseFormat == GL_STENCIL_INDEX) {
519 /* OK */
520 }
521 else if (ctx->Extensions.EXT_packed_depth_stencil &&
522 baseFormat == GL_DEPTH_STENCIL_EXT) {
523 /* OK */
524 }
525 else {
526 att->Complete = GL_FALSE;
527 att_incomplete("bad renderbuffer stencil format");
528 return;
529 }
530 }
531 }
532 else {
533 ASSERT(att->Type == GL_NONE);
534 /* complete */
535 return;
536 }
537 }
538
539
540 /**
541 * Test if the given framebuffer object is complete and update its
542 * Status field with the results.
543 * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
544 * driver to make hardware-specific validation/completeness checks.
545 * Also update the framebuffer's Width and Height fields if the
546 * framebuffer is complete.
547 */
548 void
549 _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
550 {
551 GLuint numImages;
552 GLenum intFormat = GL_NONE; /* color buffers' internal format */
553 GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
554 GLint numSamples = -1;
555 GLint i;
556 GLuint j;
557
558 assert(fb->Name != 0);
559
560 numImages = 0;
561 fb->Width = 0;
562 fb->Height = 0;
563
564 /* Start at -2 to more easily loop over all attachment points.
565 * -2: depth buffer
566 * -1: stencil buffer
567 * >=0: color buffer
568 */
569 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
570 struct gl_renderbuffer_attachment *att;
571 GLenum f;
572
573 /*
574 * XXX for ARB_fbo, only check color buffers that are named by
575 * GL_READ_BUFFER and GL_DRAW_BUFFERi.
576 */
577
578 /* check for attachment completeness
579 */
580 if (i == -2) {
581 att = &fb->Attachment[BUFFER_DEPTH];
582 test_attachment_completeness(ctx, GL_DEPTH, att);
583 if (!att->Complete) {
584 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
585 fbo_incomplete("depth attachment incomplete", -1);
586 return;
587 }
588 }
589 else if (i == -1) {
590 att = &fb->Attachment[BUFFER_STENCIL];
591 test_attachment_completeness(ctx, GL_STENCIL, att);
592 if (!att->Complete) {
593 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
594 fbo_incomplete("stencil attachment incomplete", -1);
595 return;
596 }
597 }
598 else {
599 att = &fb->Attachment[BUFFER_COLOR0 + i];
600 test_attachment_completeness(ctx, GL_COLOR, att);
601 if (!att->Complete) {
602 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
603 fbo_incomplete("color attachment incomplete", i);
604 return;
605 }
606 }
607
608 /* get width, height, format of the renderbuffer/texture
609 */
610 if (att->Type == GL_TEXTURE) {
611 const struct gl_texture_image *texImg
612 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
613 minWidth = MIN2(minWidth, texImg->Width);
614 maxWidth = MAX2(maxWidth, texImg->Width);
615 minHeight = MIN2(minHeight, texImg->Height);
616 maxHeight = MAX2(maxHeight, texImg->Height);
617 f = texImg->_BaseFormat;
618 numImages++;
619 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT
620 && f != GL_DEPTH_STENCIL_EXT
621 && (!ctx->Extensions.ARB_framebuffer_object || f != GL_ALPHA)) {
622 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
623 fbo_incomplete("texture attachment incomplete", -1);
624 return;
625 }
626 }
627 else if (att->Type == GL_RENDERBUFFER_EXT) {
628 minWidth = MIN2(minWidth, att->Renderbuffer->Width);
629 maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
630 minHeight = MIN2(minHeight, att->Renderbuffer->Height);
631 maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
632 f = att->Renderbuffer->InternalFormat;
633 numImages++;
634 }
635 else {
636 assert(att->Type == GL_NONE);
637 continue;
638 }
639
640 if (numSamples < 0) {
641 /* first buffer */
642 numSamples = att->Renderbuffer->NumSamples;
643 }
644
645 /* Error-check width, height, format, samples
646 */
647 if (numImages == 1) {
648 /* save format, num samples */
649 if (i >= 0) {
650 intFormat = f;
651 }
652 }
653 else {
654 if (!ctx->Extensions.ARB_framebuffer_object) {
655 /* check that width, height, format are same */
656 if (minWidth != maxWidth || minHeight != maxHeight) {
657 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
658 fbo_incomplete("width or height mismatch", -1);
659 return;
660 }
661 /* check that all color buffer have same format */
662 if (intFormat != GL_NONE && f != intFormat) {
663 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
664 fbo_incomplete("format mismatch", -1);
665 return;
666 }
667 }
668 if (att->Renderbuffer &&
669 att->Renderbuffer->NumSamples != numSamples) {
670 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
671 fbo_incomplete("inconsistant number of samples", i);
672 return;
673 }
674
675 }
676 }
677
678 #if FEATURE_GL
679 if (ctx->API == API_OPENGL) {
680 /* Check that all DrawBuffers are present */
681 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
682 if (fb->ColorDrawBuffer[j] != GL_NONE) {
683 const struct gl_renderbuffer_attachment *att
684 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
685 assert(att);
686 if (att->Type == GL_NONE) {
687 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
688 fbo_incomplete("missing drawbuffer", j);
689 return;
690 }
691 }
692 }
693
694 /* Check that the ReadBuffer is present */
695 if (fb->ColorReadBuffer != GL_NONE) {
696 const struct gl_renderbuffer_attachment *att
697 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
698 assert(att);
699 if (att->Type == GL_NONE) {
700 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
701 fbo_incomplete("missing readbuffer", -1);
702 return;
703 }
704 }
705 }
706 #else
707 (void) j;
708 #endif
709
710 if (numImages == 0) {
711 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
712 fbo_incomplete("no attachments", -1);
713 return;
714 }
715
716 /* Provisionally set status = COMPLETE ... */
717 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
718
719 /* ... but the driver may say the FB is incomplete.
720 * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
721 * if anything.
722 */
723 if (ctx->Driver.ValidateFramebuffer) {
724 ctx->Driver.ValidateFramebuffer(ctx, fb);
725 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
726 fbo_incomplete("driver marked FBO as incomplete", -1);
727 }
728 }
729
730 if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
731 /*
732 * Note that if ARB_framebuffer_object is supported and the attached
733 * renderbuffers/textures are different sizes, the framebuffer
734 * width/height will be set to the smallest width/height.
735 */
736 fb->Width = minWidth;
737 fb->Height = minHeight;
738
739 /* finally, update the visual info for the framebuffer */
740 _mesa_update_framebuffer_visual(fb);
741 }
742 }
743
744
745 GLboolean GLAPIENTRY
746 _mesa_IsRenderbufferEXT(GLuint renderbuffer)
747 {
748 GET_CURRENT_CONTEXT(ctx);
749 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
750 if (renderbuffer) {
751 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
752 if (rb != NULL && rb != &DummyRenderbuffer)
753 return GL_TRUE;
754 }
755 return GL_FALSE;
756 }
757
758
759 void GLAPIENTRY
760 _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
761 {
762 struct gl_renderbuffer *newRb;
763 GET_CURRENT_CONTEXT(ctx);
764
765 ASSERT_OUTSIDE_BEGIN_END(ctx);
766
767 if (target != GL_RENDERBUFFER_EXT) {
768 _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
769 return;
770 }
771
772 /* No need to flush here since the render buffer binding has no
773 * effect on rendering state.
774 */
775
776 if (renderbuffer) {
777 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
778 if (newRb == &DummyRenderbuffer) {
779 /* ID was reserved, but no real renderbuffer object made yet */
780 newRb = NULL;
781 }
782 else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
783 /* All RB IDs must be Gen'd */
784 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
785 return;
786 }
787
788 if (!newRb) {
789 /* create new renderbuffer object */
790 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
791 if (!newRb) {
792 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
793 return;
794 }
795 ASSERT(newRb->AllocStorage);
796 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
797 newRb->RefCount = 1; /* referenced by hash table */
798 }
799 }
800 else {
801 newRb = NULL;
802 }
803
804 ASSERT(newRb != &DummyRenderbuffer);
805
806 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
807 }
808
809
810 /**
811 * If the given renderbuffer is anywhere attached to the framebuffer, detach
812 * the renderbuffer.
813 * This is used when a renderbuffer object is deleted.
814 * The spec calls for unbinding.
815 */
816 static void
817 detach_renderbuffer(GLcontext *ctx,
818 struct gl_framebuffer *fb,
819 struct gl_renderbuffer *rb)
820 {
821 GLuint i;
822 for (i = 0; i < BUFFER_COUNT; i++) {
823 if (fb->Attachment[i].Renderbuffer == rb) {
824 _mesa_remove_attachment(ctx, &fb->Attachment[i]);
825 }
826 }
827 invalidate_framebuffer(fb);
828 }
829
830
831 void GLAPIENTRY
832 _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
833 {
834 GLint i;
835 GET_CURRENT_CONTEXT(ctx);
836
837 ASSERT_OUTSIDE_BEGIN_END(ctx);
838 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
839
840 for (i = 0; i < n; i++) {
841 if (renderbuffers[i] > 0) {
842 struct gl_renderbuffer *rb;
843 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
844 if (rb) {
845 /* check if deleting currently bound renderbuffer object */
846 if (rb == ctx->CurrentRenderbuffer) {
847 /* bind default */
848 ASSERT(rb->RefCount >= 2);
849 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
850 }
851
852 if (ctx->DrawBuffer->Name) {
853 detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
854 }
855 if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) {
856 detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
857 }
858
859 /* Remove from hash table immediately, to free the ID.
860 * But the object will not be freed until it's no longer
861 * referenced anywhere else.
862 */
863 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
864
865 if (rb != &DummyRenderbuffer) {
866 /* no longer referenced by hash table */
867 _mesa_reference_renderbuffer(&rb, NULL);
868 }
869 }
870 }
871 }
872 }
873
874
875 void GLAPIENTRY
876 _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
877 {
878 GET_CURRENT_CONTEXT(ctx);
879 GLuint first;
880 GLint i;
881
882 ASSERT_OUTSIDE_BEGIN_END(ctx);
883
884 if (n < 0) {
885 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
886 return;
887 }
888
889 if (!renderbuffers)
890 return;
891
892 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
893
894 for (i = 0; i < n; i++) {
895 GLuint name = first + i;
896 renderbuffers[i] = name;
897 /* insert dummy placeholder into hash table */
898 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
899 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
900 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
901 }
902 }
903
904
905 /**
906 * Given an internal format token for a render buffer, return the
907 * corresponding base format.
908 * This is very similar to _mesa_base_tex_format() but the set of valid
909 * internal formats is somewhat different.
910 *
911 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
912 * GL_DEPTH_STENCIL_EXT or zero if error.
913 *
914 * XXX in the future when we support red-only and red-green formats
915 * we'll also return GL_RED and GL_RG.
916 */
917 GLenum
918 _mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
919 {
920 switch (internalFormat) {
921 case GL_RGB:
922 case GL_R3_G3_B2:
923 case GL_RGB4:
924 case GL_RGB5:
925 case GL_RGB8:
926 case GL_RGB10:
927 case GL_RGB12:
928 case GL_RGB16:
929 return GL_RGB;
930 case GL_RGBA:
931 case GL_RGBA2:
932 case GL_RGBA4:
933 case GL_RGB5_A1:
934 case GL_RGBA8:
935 case GL_RGB10_A2:
936 case GL_RGBA12:
937 case GL_RGBA16:
938 case GL_RGBA16_SNORM:
939 return GL_RGBA;
940 case GL_STENCIL_INDEX:
941 case GL_STENCIL_INDEX1_EXT:
942 case GL_STENCIL_INDEX4_EXT:
943 case GL_STENCIL_INDEX8_EXT:
944 case GL_STENCIL_INDEX16_EXT:
945 return GL_STENCIL_INDEX;
946 case GL_DEPTH_COMPONENT:
947 case GL_DEPTH_COMPONENT16:
948 case GL_DEPTH_COMPONENT24:
949 case GL_DEPTH_COMPONENT32:
950 return GL_DEPTH_COMPONENT;
951 case GL_DEPTH_STENCIL_EXT:
952 case GL_DEPTH24_STENCIL8_EXT:
953 if (ctx->Extensions.EXT_packed_depth_stencil)
954 return GL_DEPTH_STENCIL_EXT;
955 else
956 return 0;
957 /* XXX add floating point formats eventually */
958 default:
959 return 0;
960 }
961 }
962
963
964 /** sentinal value, see below */
965 #define NO_SAMPLES 1000
966
967
968 /**
969 * Helper function used by _mesa_RenderbufferStorageEXT() and
970 * _mesa_RenderbufferStorageMultisample().
971 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
972 */
973 static void
974 renderbuffer_storage(GLenum target, GLenum internalFormat,
975 GLsizei width, GLsizei height, GLsizei samples)
976 {
977 const char *func = samples == NO_SAMPLES ?
978 "glRenderbufferStorage" : "RenderbufferStorageMultisample";
979 struct gl_renderbuffer *rb;
980 GLenum baseFormat;
981 GET_CURRENT_CONTEXT(ctx);
982
983 ASSERT_OUTSIDE_BEGIN_END(ctx);
984
985 if (target != GL_RENDERBUFFER_EXT) {
986 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
987 return;
988 }
989
990 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
991 if (baseFormat == 0) {
992 _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
993 return;
994 }
995
996 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
997 _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
998 return;
999 }
1000
1001 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
1002 _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
1003 return;
1004 }
1005
1006 if (samples == NO_SAMPLES) {
1007 /* NumSamples == 0 indicates non-multisampling */
1008 samples = 0;
1009 }
1010 else if (samples > (GLsizei) ctx->Const.MaxSamples) {
1011 /* note: driver may choose to use more samples than what's requested */
1012 _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
1013 return;
1014 }
1015
1016 rb = ctx->CurrentRenderbuffer;
1017 if (!rb) {
1018 _mesa_error(ctx, GL_INVALID_OPERATION, func);
1019 return;
1020 }
1021
1022 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1023
1024 if (rb->InternalFormat == internalFormat &&
1025 rb->Width == (GLuint) width &&
1026 rb->Height == (GLuint) height) {
1027 /* no change in allocation needed */
1028 return;
1029 }
1030
1031 /* These MUST get set by the AllocStorage func */
1032 rb->Format = MESA_FORMAT_NONE;
1033 rb->NumSamples = samples;
1034
1035 /* Now allocate the storage */
1036 ASSERT(rb->AllocStorage);
1037 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
1038 /* No error - check/set fields now */
1039 assert(rb->Format != MESA_FORMAT_NONE);
1040 assert(rb->Width == (GLuint) width);
1041 assert(rb->Height == (GLuint) height);
1042 rb->InternalFormat = internalFormat;
1043 rb->_BaseFormat = baseFormat;
1044 assert(rb->_BaseFormat != 0);
1045 }
1046 else {
1047 /* Probably ran out of memory - clear the fields */
1048 rb->Width = 0;
1049 rb->Height = 0;
1050 rb->Format = MESA_FORMAT_NONE;
1051 rb->InternalFormat = GL_NONE;
1052 rb->_BaseFormat = GL_NONE;
1053 rb->NumSamples = 0;
1054 }
1055
1056 /*
1057 test_framebuffer_completeness(ctx, fb);
1058 */
1059 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
1060 * points???
1061 */
1062 }
1063
1064
1065 #if FEATURE_OES_EGL_image
1066 void GLAPIENTRY
1067 _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1068 {
1069 struct gl_renderbuffer *rb;
1070 GET_CURRENT_CONTEXT(ctx);
1071 ASSERT_OUTSIDE_BEGIN_END(ctx);
1072
1073 if (!ctx->Extensions.OES_EGL_image) {
1074 _mesa_error(ctx, GL_INVALID_OPERATION,
1075 "glEGLImageTargetRenderbufferStorageOES(unsupported)");
1076 return;
1077 }
1078
1079 if (target != GL_RENDERBUFFER) {
1080 _mesa_error(ctx, GL_INVALID_ENUM,
1081 "EGLImageTargetRenderbufferStorageOES");
1082 return;
1083 }
1084
1085 rb = ctx->CurrentRenderbuffer;
1086 if (!rb) {
1087 _mesa_error(ctx, GL_INVALID_OPERATION,
1088 "EGLImageTargetRenderbufferStorageOES");
1089 return;
1090 }
1091
1092 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1093
1094 ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1095 }
1096 #endif
1097
1098
1099 /**
1100 * Helper function for _mesa_GetRenderbufferParameterivEXT() and
1101 * _mesa_GetFramebufferAttachmentParameterivEXT()
1102 * We have to be careful to respect the base format. For example, if a
1103 * renderbuffer/texture was created with internalFormat=GL_RGB but the
1104 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
1105 * we need to return zero.
1106 */
1107 static GLint
1108 get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
1109 {
1110 switch (pname) {
1111 case GL_RENDERBUFFER_RED_SIZE_EXT:
1112 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
1113 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1114 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
1115 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1116 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
1117 if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
1118 return _mesa_get_format_bits(format, pname);
1119 else
1120 return 0;
1121 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1122 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
1123 if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA)
1124 return _mesa_get_format_bits(format, pname);
1125 else
1126 return 0;
1127 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1128 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
1129 if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
1130 return _mesa_get_format_bits(format, pname);
1131 else
1132 return 0;
1133 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1134 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
1135 if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
1136 return _mesa_get_format_bits(format, pname);
1137 else
1138 return 0;
1139 default:
1140 return 0;
1141 }
1142 }
1143
1144
1145
1146 void GLAPIENTRY
1147 _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1148 GLsizei width, GLsizei height)
1149 {
1150 /* GL_ARB_fbo says calling this function is equivalent to calling
1151 * glRenderbufferStorageMultisample() with samples=0. We pass in
1152 * a token value here just for error reporting purposes.
1153 */
1154 renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
1155 }
1156
1157
1158 void GLAPIENTRY
1159 _mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
1160 GLenum internalFormat,
1161 GLsizei width, GLsizei height)
1162 {
1163 renderbuffer_storage(target, internalFormat, width, height, samples);
1164 }
1165
1166
1167 /**
1168 * OpenGL ES version of glRenderBufferStorage.
1169 */
1170 void GLAPIENTRY
1171 _es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1172 GLsizei width, GLsizei height)
1173 {
1174 switch (internalFormat) {
1175 case GL_RGB565:
1176 /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
1177 /* choose a closest format */
1178 internalFormat = GL_RGB5;
1179 break;
1180 default:
1181 break;
1182 }
1183
1184 renderbuffer_storage(target, internalFormat, width, height, 0);
1185 }
1186
1187
1188 void GLAPIENTRY
1189 _mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
1190 {
1191 struct gl_renderbuffer *rb;
1192 GET_CURRENT_CONTEXT(ctx);
1193
1194 ASSERT_OUTSIDE_BEGIN_END(ctx);
1195
1196 if (target != GL_RENDERBUFFER_EXT) {
1197 _mesa_error(ctx, GL_INVALID_ENUM,
1198 "glGetRenderbufferParameterivEXT(target)");
1199 return;
1200 }
1201
1202 rb = ctx->CurrentRenderbuffer;
1203 if (!rb) {
1204 _mesa_error(ctx, GL_INVALID_OPERATION,
1205 "glGetRenderbufferParameterivEXT");
1206 return;
1207 }
1208
1209 /* No need to flush here since we're just quering state which is
1210 * not effected by rendering.
1211 */
1212
1213 switch (pname) {
1214 case GL_RENDERBUFFER_WIDTH_EXT:
1215 *params = rb->Width;
1216 return;
1217 case GL_RENDERBUFFER_HEIGHT_EXT:
1218 *params = rb->Height;
1219 return;
1220 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
1221 *params = rb->InternalFormat;
1222 return;
1223 case GL_RENDERBUFFER_RED_SIZE_EXT:
1224 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1225 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1226 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1227 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1228 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1229 *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
1230 break;
1231 case GL_RENDERBUFFER_SAMPLES:
1232 if (ctx->Extensions.ARB_framebuffer_object) {
1233 *params = rb->NumSamples;
1234 break;
1235 }
1236 /* fallthrough */
1237 default:
1238 _mesa_error(ctx, GL_INVALID_ENUM,
1239 "glGetRenderbufferParameterivEXT(target)");
1240 return;
1241 }
1242 }
1243
1244
1245 GLboolean GLAPIENTRY
1246 _mesa_IsFramebufferEXT(GLuint framebuffer)
1247 {
1248 GET_CURRENT_CONTEXT(ctx);
1249 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1250 if (framebuffer) {
1251 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
1252 if (rb != NULL && rb != &DummyFramebuffer)
1253 return GL_TRUE;
1254 }
1255 return GL_FALSE;
1256 }
1257
1258
1259 /**
1260 * Check if any of the attachments of the given framebuffer are textures
1261 * (render to texture). Call ctx->Driver.RenderTexture() for such
1262 * attachments.
1263 */
1264 static void
1265 check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
1266 {
1267 GLuint i;
1268 ASSERT(ctx->Driver.RenderTexture);
1269
1270 if (fb->Name == 0)
1271 return; /* can't render to texture with winsys framebuffers */
1272
1273 for (i = 0; i < BUFFER_COUNT; i++) {
1274 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1275 struct gl_texture_object *texObj = att->Texture;
1276 if (texObj
1277 && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
1278 ctx->Driver.RenderTexture(ctx, fb, att);
1279 }
1280 }
1281 }
1282
1283
1284 /**
1285 * Examine all the framebuffer's attachments to see if any are textures.
1286 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
1287 * notify the device driver that the texture image may have changed.
1288 */
1289 static void
1290 check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
1291 {
1292 if (fb->Name == 0)
1293 return; /* can't render to texture with winsys framebuffers */
1294
1295 if (ctx->Driver.FinishRenderTexture) {
1296 GLuint i;
1297 for (i = 0; i < BUFFER_COUNT; i++) {
1298 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1299 if (att->Texture && att->Renderbuffer) {
1300 ctx->Driver.FinishRenderTexture(ctx, att);
1301 }
1302 }
1303 }
1304 }
1305
1306
1307 void GLAPIENTRY
1308 _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
1309 {
1310 struct gl_framebuffer *newDrawFb, *newReadFb;
1311 struct gl_framebuffer *oldDrawFb, *oldReadFb;
1312 GLboolean bindReadBuf, bindDrawBuf;
1313 GET_CURRENT_CONTEXT(ctx);
1314
1315 #ifdef DEBUG
1316 if (ctx->Extensions.ARB_framebuffer_object) {
1317 ASSERT(ctx->Extensions.EXT_framebuffer_object);
1318 ASSERT(ctx->Extensions.EXT_framebuffer_blit);
1319 }
1320 #endif
1321
1322 ASSERT_OUTSIDE_BEGIN_END(ctx);
1323
1324 if (!ctx->Extensions.EXT_framebuffer_object) {
1325 _mesa_error(ctx, GL_INVALID_OPERATION,
1326 "glBindFramebufferEXT(unsupported)");
1327 return;
1328 }
1329
1330 switch (target) {
1331 #if FEATURE_EXT_framebuffer_blit
1332 case GL_DRAW_FRAMEBUFFER_EXT:
1333 if (!ctx->Extensions.EXT_framebuffer_blit) {
1334 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1335 return;
1336 }
1337 bindDrawBuf = GL_TRUE;
1338 bindReadBuf = GL_FALSE;
1339 break;
1340 case GL_READ_FRAMEBUFFER_EXT:
1341 if (!ctx->Extensions.EXT_framebuffer_blit) {
1342 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1343 return;
1344 }
1345 bindDrawBuf = GL_FALSE;
1346 bindReadBuf = GL_TRUE;
1347 break;
1348 #endif
1349 case GL_FRAMEBUFFER_EXT:
1350 bindDrawBuf = GL_TRUE;
1351 bindReadBuf = GL_TRUE;
1352 break;
1353 default:
1354 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1355 return;
1356 }
1357
1358 if (framebuffer) {
1359 /* Binding a user-created framebuffer object */
1360 newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
1361 if (newDrawFb == &DummyFramebuffer) {
1362 /* ID was reserved, but no real framebuffer object made yet */
1363 newDrawFb = NULL;
1364 }
1365 else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
1366 /* All FBO IDs must be Gen'd */
1367 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
1368 return;
1369 }
1370
1371 if (!newDrawFb) {
1372 /* create new framebuffer object */
1373 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
1374 if (!newDrawFb) {
1375 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1376 return;
1377 }
1378 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
1379 }
1380 newReadFb = newDrawFb;
1381 }
1382 else {
1383 /* Binding the window system framebuffer (which was originally set
1384 * with MakeCurrent).
1385 */
1386 newDrawFb = ctx->WinSysDrawBuffer;
1387 newReadFb = ctx->WinSysReadBuffer;
1388 }
1389
1390 ASSERT(newDrawFb);
1391 ASSERT(newDrawFb != &DummyFramebuffer);
1392
1393 /* save pointers to current/old framebuffers */
1394 oldDrawFb = ctx->DrawBuffer;
1395 oldReadFb = ctx->ReadBuffer;
1396
1397 /* check if really changing bindings */
1398 if (oldDrawFb == newDrawFb)
1399 bindDrawBuf = GL_FALSE;
1400 if (oldReadFb == newReadFb)
1401 bindReadBuf = GL_FALSE;
1402
1403 /*
1404 * OK, now bind the new Draw/Read framebuffers, if they're changing.
1405 *
1406 * We also check if we're beginning and/or ending render-to-texture.
1407 * When a framebuffer with texture attachments is unbound, call
1408 * ctx->Driver.FinishRenderTexture().
1409 * When a framebuffer with texture attachments is bound, call
1410 * ctx->Driver.RenderTexture().
1411 *
1412 * Note that if the ReadBuffer has texture attachments we don't consider
1413 * that a render-to-texture case.
1414 */
1415 if (bindReadBuf) {
1416 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1417
1418 /* check if old readbuffer was render-to-texture */
1419 check_end_texture_render(ctx, oldReadFb);
1420
1421 _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
1422 }
1423
1424 if (bindDrawBuf) {
1425 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1426
1427 /* check if old read/draw buffers were render-to-texture */
1428 if (!bindReadBuf)
1429 check_end_texture_render(ctx, oldReadFb);
1430
1431 if (oldDrawFb != oldReadFb)
1432 check_end_texture_render(ctx, oldDrawFb);
1433
1434 /* check if newly bound framebuffer has any texture attachments */
1435 check_begin_texture_render(ctx, newDrawFb);
1436
1437 _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
1438 }
1439
1440 if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
1441 ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
1442 }
1443 }
1444
1445
1446 void GLAPIENTRY
1447 _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1448 {
1449 GLint i;
1450 GET_CURRENT_CONTEXT(ctx);
1451
1452 ASSERT_OUTSIDE_BEGIN_END(ctx);
1453 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1454
1455 for (i = 0; i < n; i++) {
1456 if (framebuffers[i] > 0) {
1457 struct gl_framebuffer *fb;
1458 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
1459 if (fb) {
1460 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
1461
1462 /* check if deleting currently bound framebuffer object */
1463 if (ctx->Extensions.EXT_framebuffer_blit) {
1464 /* separate draw/read binding points */
1465 if (fb == ctx->DrawBuffer) {
1466 /* bind default */
1467 ASSERT(fb->RefCount >= 2);
1468 _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1469 }
1470 if (fb == ctx->ReadBuffer) {
1471 /* bind default */
1472 ASSERT(fb->RefCount >= 2);
1473 _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1474 }
1475 }
1476 else {
1477 /* only one binding point for read/draw buffers */
1478 if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
1479 /* bind default */
1480 ASSERT(fb->RefCount >= 2);
1481 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1482 }
1483 }
1484
1485 /* remove from hash table immediately, to free the ID */
1486 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
1487
1488 if (fb != &DummyFramebuffer) {
1489 /* But the object will not be freed until it's no longer
1490 * bound in any context.
1491 */
1492 _mesa_reference_framebuffer(&fb, NULL);
1493 }
1494 }
1495 }
1496 }
1497 }
1498
1499
1500 void GLAPIENTRY
1501 _mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1502 {
1503 GET_CURRENT_CONTEXT(ctx);
1504 GLuint first;
1505 GLint i;
1506
1507 ASSERT_OUTSIDE_BEGIN_END(ctx);
1508
1509 if (n < 0) {
1510 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1511 return;
1512 }
1513
1514 if (!framebuffers)
1515 return;
1516
1517 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1518
1519 for (i = 0; i < n; i++) {
1520 GLuint name = first + i;
1521 framebuffers[i] = name;
1522 /* insert dummy placeholder into hash table */
1523 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
1524 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
1525 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1526 }
1527 }
1528
1529
1530
1531 GLenum GLAPIENTRY
1532 _mesa_CheckFramebufferStatusEXT(GLenum target)
1533 {
1534 struct gl_framebuffer *buffer;
1535 GET_CURRENT_CONTEXT(ctx);
1536
1537 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1538
1539 switch (target) {
1540 #if FEATURE_EXT_framebuffer_blit
1541 case GL_DRAW_FRAMEBUFFER_EXT:
1542 if (!ctx->Extensions.EXT_framebuffer_blit) {
1543 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1544 return 0;
1545 }
1546 buffer = ctx->DrawBuffer;
1547 break;
1548 case GL_READ_FRAMEBUFFER_EXT:
1549 if (!ctx->Extensions.EXT_framebuffer_blit) {
1550 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1551 return 0;
1552 }
1553 buffer = ctx->ReadBuffer;
1554 break;
1555 #endif
1556 case GL_FRAMEBUFFER_EXT:
1557 buffer = ctx->DrawBuffer;
1558 break;
1559 default:
1560 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1561 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
1562 }
1563
1564 if (buffer->Name == 0) {
1565 /* The window system / default framebuffer is always complete */
1566 return GL_FRAMEBUFFER_COMPLETE_EXT;
1567 }
1568
1569 /* No need to flush here */
1570
1571 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
1572 _mesa_test_framebuffer_completeness(ctx, buffer);
1573 }
1574
1575 return buffer->_Status;
1576 }
1577
1578
1579
1580 /**
1581 * Common code called by glFramebufferTexture1D/2D/3DEXT().
1582 */
1583 static void
1584 framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
1585 GLenum attachment, GLenum textarget, GLuint texture,
1586 GLint level, GLint zoffset)
1587 {
1588 struct gl_renderbuffer_attachment *att;
1589 struct gl_texture_object *texObj = NULL;
1590 struct gl_framebuffer *fb;
1591 GLboolean error = GL_FALSE;
1592
1593 ASSERT_OUTSIDE_BEGIN_END(ctx);
1594
1595 switch (target) {
1596 case GL_READ_FRAMEBUFFER_EXT:
1597 error = !ctx->Extensions.EXT_framebuffer_blit;
1598 fb = ctx->ReadBuffer;
1599 break;
1600 case GL_DRAW_FRAMEBUFFER_EXT:
1601 error = !ctx->Extensions.EXT_framebuffer_blit;
1602 /* fall-through */
1603 case GL_FRAMEBUFFER_EXT:
1604 fb = ctx->DrawBuffer;
1605 break;
1606 default:
1607 error = GL_TRUE;
1608 }
1609
1610 if (error) {
1611 _mesa_error(ctx, GL_INVALID_ENUM,
1612 "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
1613 return;
1614 }
1615
1616 ASSERT(fb);
1617
1618 /* check framebuffer binding */
1619 if (fb->Name == 0) {
1620 _mesa_error(ctx, GL_INVALID_OPERATION,
1621 "glFramebufferTexture%sEXT", caller);
1622 return;
1623 }
1624
1625
1626 /* The textarget, level, and zoffset parameters are only validated if
1627 * texture is non-zero.
1628 */
1629 if (texture) {
1630 GLboolean err = GL_TRUE;
1631
1632 texObj = _mesa_lookup_texture(ctx, texture);
1633 if (texObj != NULL) {
1634 if (textarget == 0) {
1635 /* XXX what's the purpose of this? */
1636 err = (texObj->Target != GL_TEXTURE_3D) &&
1637 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1638 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1639 }
1640 else {
1641 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1642 ? !IS_CUBE_FACE(textarget)
1643 : (texObj->Target != textarget);
1644 }
1645 }
1646 else {
1647 /* can't render to a non-existant texture */
1648 _mesa_error(ctx, GL_INVALID_OPERATION,
1649 "glFramebufferTexture%sEXT(non existant texture)",
1650 caller);
1651 return;
1652 }
1653
1654 if (err) {
1655 _mesa_error(ctx, GL_INVALID_OPERATION,
1656 "glFramebufferTexture%sEXT(texture target mismatch)",
1657 caller);
1658 return;
1659 }
1660
1661 if (texObj->Target == GL_TEXTURE_3D) {
1662 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1663 if (zoffset < 0 || zoffset >= maxSize) {
1664 _mesa_error(ctx, GL_INVALID_VALUE,
1665 "glFramebufferTexture%sEXT(zoffset)", caller);
1666 return;
1667 }
1668 }
1669 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1670 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1671 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1672 _mesa_error(ctx, GL_INVALID_VALUE,
1673 "glFramebufferTexture%sEXT(layer)", caller);
1674 return;
1675 }
1676 }
1677
1678 if ((level < 0) ||
1679 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1680 _mesa_error(ctx, GL_INVALID_VALUE,
1681 "glFramebufferTexture%sEXT(level)", caller);
1682 return;
1683 }
1684 }
1685
1686 att = _mesa_get_attachment(ctx, fb, attachment);
1687 if (att == NULL) {
1688 _mesa_error(ctx, GL_INVALID_ENUM,
1689 "glFramebufferTexture%sEXT(attachment)", caller);
1690 return;
1691 }
1692
1693 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1694
1695 _glthread_LOCK_MUTEX(fb->Mutex);
1696 if (texObj) {
1697 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1698 level, zoffset);
1699 /* Set the render-to-texture flag. We'll check this flag in
1700 * glTexImage() and friends to determine if we need to revalidate
1701 * any FBOs that might be rendering into this texture.
1702 * This flag never gets cleared since it's non-trivial to determine
1703 * when all FBOs might be done rendering to this texture. That's OK
1704 * though since it's uncommon to render to a texture then repeatedly
1705 * call glTexImage() to change images in the texture.
1706 */
1707 texObj->_RenderToTexture = GL_TRUE;
1708 }
1709 else {
1710 _mesa_remove_attachment(ctx, att);
1711 }
1712
1713 invalidate_framebuffer(fb);
1714
1715 _glthread_UNLOCK_MUTEX(fb->Mutex);
1716 }
1717
1718
1719
1720 void GLAPIENTRY
1721 _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1722 GLenum textarget, GLuint texture, GLint level)
1723 {
1724 GET_CURRENT_CONTEXT(ctx);
1725
1726 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1727 _mesa_error(ctx, GL_INVALID_ENUM,
1728 "glFramebufferTexture1DEXT(textarget)");
1729 return;
1730 }
1731
1732 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1733 level, 0);
1734 }
1735
1736
1737 void GLAPIENTRY
1738 _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1739 GLenum textarget, GLuint texture, GLint level)
1740 {
1741 GET_CURRENT_CONTEXT(ctx);
1742
1743 if ((texture != 0) &&
1744 (textarget != GL_TEXTURE_2D) &&
1745 (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1746 (!IS_CUBE_FACE(textarget))) {
1747 _mesa_error(ctx, GL_INVALID_OPERATION,
1748 "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
1749 return;
1750 }
1751
1752 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1753 level, 0);
1754 }
1755
1756
1757 void GLAPIENTRY
1758 _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1759 GLenum textarget, GLuint texture,
1760 GLint level, GLint zoffset)
1761 {
1762 GET_CURRENT_CONTEXT(ctx);
1763
1764 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1765 _mesa_error(ctx, GL_INVALID_ENUM,
1766 "glFramebufferTexture3DEXT(textarget)");
1767 return;
1768 }
1769
1770 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
1771 level, zoffset);
1772 }
1773
1774
1775 void GLAPIENTRY
1776 _mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1777 GLuint texture, GLint level, GLint layer)
1778 {
1779 GET_CURRENT_CONTEXT(ctx);
1780
1781 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1782 level, layer);
1783 }
1784
1785
1786 void GLAPIENTRY
1787 _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1788 GLenum renderbufferTarget,
1789 GLuint renderbuffer)
1790 {
1791 struct gl_renderbuffer_attachment *att;
1792 struct gl_framebuffer *fb;
1793 struct gl_renderbuffer *rb;
1794 GET_CURRENT_CONTEXT(ctx);
1795
1796 ASSERT_OUTSIDE_BEGIN_END(ctx);
1797
1798 switch (target) {
1799 #if FEATURE_EXT_framebuffer_blit
1800 case GL_DRAW_FRAMEBUFFER_EXT:
1801 if (!ctx->Extensions.EXT_framebuffer_blit) {
1802 _mesa_error(ctx, GL_INVALID_ENUM,
1803 "glFramebufferRenderbufferEXT(target)");
1804 return;
1805 }
1806 fb = ctx->DrawBuffer;
1807 break;
1808 case GL_READ_FRAMEBUFFER_EXT:
1809 if (!ctx->Extensions.EXT_framebuffer_blit) {
1810 _mesa_error(ctx, GL_INVALID_ENUM,
1811 "glFramebufferRenderbufferEXT(target)");
1812 return;
1813 }
1814 fb = ctx->ReadBuffer;
1815 break;
1816 #endif
1817 case GL_FRAMEBUFFER_EXT:
1818 fb = ctx->DrawBuffer;
1819 break;
1820 default:
1821 _mesa_error(ctx, GL_INVALID_ENUM,
1822 "glFramebufferRenderbufferEXT(target)");
1823 return;
1824 }
1825
1826 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
1827 _mesa_error(ctx, GL_INVALID_ENUM,
1828 "glFramebufferRenderbufferEXT(renderbufferTarget)");
1829 return;
1830 }
1831
1832 if (fb->Name == 0) {
1833 /* Can't attach new renderbuffers to a window system framebuffer */
1834 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1835 return;
1836 }
1837
1838 att = _mesa_get_attachment(ctx, fb, attachment);
1839 if (att == NULL) {
1840 _mesa_error(ctx, GL_INVALID_ENUM,
1841 "glFramebufferRenderbufferEXT(invalid attachment %s)",
1842 _mesa_lookup_enum_by_nr(attachment));
1843 return;
1844 }
1845
1846 if (renderbuffer) {
1847 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
1848 if (!rb) {
1849 _mesa_error(ctx, GL_INVALID_OPERATION,
1850 "glFramebufferRenderbufferEXT(non-existant"
1851 " renderbuffer %u)", renderbuffer);
1852 return;
1853 }
1854 }
1855 else {
1856 /* remove renderbuffer attachment */
1857 rb = NULL;
1858 }
1859
1860 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
1861 rb && rb->Format != MESA_FORMAT_NONE) {
1862 /* make sure the renderbuffer is a depth/stencil format */
1863 const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
1864 if (baseFormat != GL_DEPTH_STENCIL) {
1865 _mesa_error(ctx, GL_INVALID_OPERATION,
1866 "glFramebufferRenderbufferEXT(renderbuffer"
1867 " is not DEPTH_STENCIL format)");
1868 return;
1869 }
1870 }
1871
1872
1873 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1874
1875 assert(ctx->Driver.FramebufferRenderbuffer);
1876 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
1877
1878 /* Some subsequent GL commands may depend on the framebuffer's visual
1879 * after the binding is updated. Update visual info now.
1880 */
1881 _mesa_update_framebuffer_visual(fb);
1882 }
1883
1884
1885 void GLAPIENTRY
1886 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1887 GLenum pname, GLint *params)
1888 {
1889 const struct gl_renderbuffer_attachment *att;
1890 struct gl_framebuffer *buffer;
1891 GET_CURRENT_CONTEXT(ctx);
1892
1893 ASSERT_OUTSIDE_BEGIN_END(ctx);
1894
1895 switch (target) {
1896 #if FEATURE_EXT_framebuffer_blit
1897 case GL_DRAW_FRAMEBUFFER_EXT:
1898 if (!ctx->Extensions.EXT_framebuffer_blit) {
1899 _mesa_error(ctx, GL_INVALID_ENUM,
1900 "glGetFramebufferAttachmentParameterivEXT(target)");
1901 return;
1902 }
1903 buffer = ctx->DrawBuffer;
1904 break;
1905 case GL_READ_FRAMEBUFFER_EXT:
1906 if (!ctx->Extensions.EXT_framebuffer_blit) {
1907 _mesa_error(ctx, GL_INVALID_ENUM,
1908 "glGetFramebufferAttachmentParameterivEXT(target)");
1909 return;
1910 }
1911 buffer = ctx->ReadBuffer;
1912 break;
1913 #endif
1914 case GL_FRAMEBUFFER_EXT:
1915 buffer = ctx->DrawBuffer;
1916 break;
1917 default:
1918 _mesa_error(ctx, GL_INVALID_ENUM,
1919 "glGetFramebufferAttachmentParameterivEXT(target)");
1920 return;
1921 }
1922
1923 if (buffer->Name == 0) {
1924 /* the default / window-system FBO */
1925 att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
1926 }
1927 else {
1928 /* user-created framebuffer FBO */
1929 att = _mesa_get_attachment(ctx, buffer, attachment);
1930 }
1931
1932 if (att == NULL) {
1933 _mesa_error(ctx, GL_INVALID_ENUM,
1934 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1935 return;
1936 }
1937
1938 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
1939 /* the depth and stencil attachments must point to the same buffer */
1940 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
1941 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
1942 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
1943 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
1944 _mesa_error(ctx, GL_INVALID_OPERATION,
1945 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
1946 " attachments differ)");
1947 return;
1948 }
1949 }
1950
1951 /* No need to flush here */
1952
1953 switch (pname) {
1954 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
1955 *params = att->Type;
1956 return;
1957 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
1958 if (att->Type == GL_RENDERBUFFER_EXT) {
1959 *params = att->Renderbuffer->Name;
1960 }
1961 else if (att->Type == GL_TEXTURE) {
1962 *params = att->Texture->Name;
1963 }
1964 else {
1965 _mesa_error(ctx, GL_INVALID_ENUM,
1966 "glGetFramebufferAttachmentParameterivEXT(pname)");
1967 }
1968 return;
1969 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
1970 if (att->Type == GL_TEXTURE) {
1971 *params = att->TextureLevel;
1972 }
1973 else {
1974 _mesa_error(ctx, GL_INVALID_ENUM,
1975 "glGetFramebufferAttachmentParameterivEXT(pname)");
1976 }
1977 return;
1978 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
1979 if (att->Type == GL_TEXTURE) {
1980 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
1981 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1982 }
1983 else {
1984 *params = 0;
1985 }
1986 }
1987 else {
1988 _mesa_error(ctx, GL_INVALID_ENUM,
1989 "glGetFramebufferAttachmentParameterivEXT(pname)");
1990 }
1991 return;
1992 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
1993 if (att->Type == GL_TEXTURE) {
1994 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
1995 *params = att->Zoffset;
1996 }
1997 else {
1998 *params = 0;
1999 }
2000 }
2001 else {
2002 _mesa_error(ctx, GL_INVALID_ENUM,
2003 "glGetFramebufferAttachmentParameterivEXT(pname)");
2004 }
2005 return;
2006 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2007 if (!ctx->Extensions.ARB_framebuffer_object) {
2008 _mesa_error(ctx, GL_INVALID_ENUM,
2009 "glGetFramebufferAttachmentParameterivEXT(pname)");
2010 }
2011 else {
2012 *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
2013 }
2014 return;
2015 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2016 if (!ctx->Extensions.ARB_framebuffer_object) {
2017 _mesa_error(ctx, GL_INVALID_ENUM,
2018 "glGetFramebufferAttachmentParameterivEXT(pname)");
2019 return;
2020 }
2021 else {
2022 gl_format format = att->Renderbuffer->Format;
2023 if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
2024 /* special cases */
2025 *params = GL_INDEX;
2026 }
2027 else {
2028 *params = _mesa_get_format_datatype(format);
2029 }
2030 }
2031 return;
2032 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
2033 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
2034 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
2035 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
2036 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
2037 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2038 if (!ctx->Extensions.ARB_framebuffer_object) {
2039 _mesa_error(ctx, GL_INVALID_ENUM,
2040 "glGetFramebufferAttachmentParameterivEXT(pname)");
2041 }
2042 else if (att->Texture) {
2043 const struct gl_texture_image *texImage =
2044 _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
2045 att->TextureLevel);
2046 if (texImage) {
2047 *params = get_component_bits(pname, texImage->_BaseFormat,
2048 texImage->TexFormat);
2049 }
2050 else {
2051 *params = 0;
2052 }
2053 }
2054 else if (att->Renderbuffer) {
2055 *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
2056 att->Renderbuffer->Format);
2057 }
2058 else {
2059 *params = 0;
2060 }
2061 return;
2062 default:
2063 _mesa_error(ctx, GL_INVALID_ENUM,
2064 "glGetFramebufferAttachmentParameterivEXT(pname)");
2065 return;
2066 }
2067 }
2068
2069
2070 void GLAPIENTRY
2071 _mesa_GenerateMipmapEXT(GLenum target)
2072 {
2073 struct gl_texture_object *texObj;
2074 GET_CURRENT_CONTEXT(ctx);
2075
2076 ASSERT_OUTSIDE_BEGIN_END(ctx);
2077 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2078
2079 switch (target) {
2080 case GL_TEXTURE_1D:
2081 case GL_TEXTURE_2D:
2082 case GL_TEXTURE_3D:
2083 case GL_TEXTURE_CUBE_MAP:
2084 /* OK, legal value */
2085 break;
2086 default:
2087 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
2088 return;
2089 }
2090
2091 texObj = _mesa_get_current_tex_object(ctx, target);
2092
2093 if (texObj->BaseLevel >= texObj->MaxLevel) {
2094 /* nothing to do */
2095 return;
2096 }
2097
2098 _mesa_lock_texture(ctx, texObj);
2099 if (target == GL_TEXTURE_CUBE_MAP) {
2100 GLuint face;
2101 for (face = 0; face < 6; face++)
2102 ctx->Driver.GenerateMipmap(ctx,
2103 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2104 texObj);
2105 }
2106 else {
2107 ctx->Driver.GenerateMipmap(ctx, target, texObj);
2108 }
2109 _mesa_unlock_texture(ctx, texObj);
2110 }
2111
2112
2113 #if FEATURE_EXT_framebuffer_blit
2114
2115 static const struct gl_renderbuffer_attachment *
2116 find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb)
2117 {
2118 GLuint i;
2119 for (i = 0; i < Elements(fb->Attachment); i++) {
2120 if (fb->Attachment[i].Renderbuffer == rb)
2121 return &fb->Attachment[i];
2122 }
2123 return NULL;
2124 }
2125
2126
2127
2128 /**
2129 * Blit rectangular region, optionally from one framebuffer to another.
2130 *
2131 * Note, if the src buffer is multisampled and the dest is not, this is
2132 * when the samples must be resolved to a single color.
2133 */
2134 void GLAPIENTRY
2135 _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
2136 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
2137 GLbitfield mask, GLenum filter)
2138 {
2139 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
2140 GL_DEPTH_BUFFER_BIT |
2141 GL_STENCIL_BUFFER_BIT);
2142 const struct gl_framebuffer *readFb, *drawFb;
2143 const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
2144 GET_CURRENT_CONTEXT(ctx);
2145
2146 ASSERT_OUTSIDE_BEGIN_END(ctx);
2147 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2148
2149 if (ctx->NewState) {
2150 _mesa_update_state(ctx);
2151 }
2152
2153 readFb = ctx->ReadBuffer;
2154 drawFb = ctx->DrawBuffer;
2155
2156 if (!readFb || !drawFb) {
2157 /* This will normally never happen but someday we may want to
2158 * support MakeCurrent() with no drawables.
2159 */
2160 return;
2161 }
2162
2163 /* check for complete framebuffers */
2164 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
2165 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
2166 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
2167 "glBlitFramebufferEXT(incomplete draw/read buffers)");
2168 return;
2169 }
2170
2171 if (filter != GL_NEAREST && filter != GL_LINEAR) {
2172 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
2173 return;
2174 }
2175
2176 if (mask & ~legalMaskBits) {
2177 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
2178 return;
2179 }
2180
2181 /* depth/stencil must be blitted with nearest filtering */
2182 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
2183 && filter != GL_NEAREST) {
2184 _mesa_error(ctx, GL_INVALID_OPERATION,
2185 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
2186 return;
2187 }
2188
2189 /* get color read/draw renderbuffers */
2190 if (mask & GL_COLOR_BUFFER_BIT) {
2191 colorReadRb = readFb->_ColorReadBuffer;
2192 colorDrawRb = drawFb->_ColorDrawBuffers[0];
2193 }
2194 else {
2195 colorReadRb = colorDrawRb = NULL;
2196 }
2197
2198 if (mask & GL_STENCIL_BUFFER_BIT) {
2199 struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
2200 struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
2201 if (!readRb ||
2202 !drawRb ||
2203 _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
2204 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
2205 _mesa_error(ctx, GL_INVALID_OPERATION,
2206 "glBlitFramebufferEXT(stencil buffer size mismatch");
2207 return;
2208 }
2209 }
2210
2211 if (mask & GL_DEPTH_BUFFER_BIT) {
2212 struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
2213 struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
2214 if (!readRb ||
2215 !drawRb ||
2216 _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
2217 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
2218 _mesa_error(ctx, GL_INVALID_OPERATION,
2219 "glBlitFramebufferEXT(depth buffer size mismatch");
2220 return;
2221 }
2222 }
2223
2224 if (readFb->Visual.samples > 0 &&
2225 drawFb->Visual.samples > 0 &&
2226 readFb->Visual.samples != drawFb->Visual.samples) {
2227 _mesa_error(ctx, GL_INVALID_OPERATION,
2228 "glBlitFramebufferEXT(mismatched samples");
2229 return;
2230 }
2231
2232 /* extra checks for multisample copies... */
2233 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
2234 /* src and dest region sizes must be the same */
2235 if (srcX1 - srcX0 != dstX1 - dstX0 ||
2236 srcY1 - srcY0 != dstY1 - dstY0) {
2237 _mesa_error(ctx, GL_INVALID_OPERATION,
2238 "glBlitFramebufferEXT(bad src/dst multisample region sizes");
2239 return;
2240 }
2241
2242 /* color formats must match */
2243 if (colorReadRb &&
2244 colorDrawRb &&
2245 colorReadRb->Format != colorDrawRb->Format) {
2246 _mesa_error(ctx, GL_INVALID_OPERATION,
2247 "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
2248 return;
2249 }
2250 }
2251
2252 if (!ctx->Extensions.EXT_framebuffer_blit) {
2253 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
2254 return;
2255 }
2256
2257 /* Debug code */
2258 if (DEBUG_BLIT) {
2259 printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
2260 " 0x%x, 0x%x)\n",
2261 srcX0, srcY0, srcX1, srcY1,
2262 dstX0, dstY0, dstX1, dstY1,
2263 mask, filter);
2264 if (colorReadRb) {
2265 const struct gl_renderbuffer_attachment *att;
2266
2267 att = find_attachment(readFb, colorReadRb);
2268 printf(" Src FBO %u RB %u (%dx%d) ",
2269 readFb->Name, colorReadRb->Name,
2270 colorReadRb->Width, colorReadRb->Height);
2271 if (att && att->Texture) {
2272 printf("Tex %u tgt 0x%x level %u face %u",
2273 att->Texture->Name,
2274 att->Texture->Target,
2275 att->TextureLevel,
2276 att->CubeMapFace);
2277 }
2278 printf("\n");
2279
2280 att = find_attachment(drawFb, colorDrawRb);
2281 printf(" Dst FBO %u RB %u (%dx%d) ",
2282 drawFb->Name, colorDrawRb->Name,
2283 colorDrawRb->Width, colorDrawRb->Height);
2284 if (att && att->Texture) {
2285 printf("Tex %u tgt 0x%x level %u face %u",
2286 att->Texture->Name,
2287 att->Texture->Target,
2288 att->TextureLevel,
2289 att->CubeMapFace);
2290 }
2291 printf("\n");
2292 }
2293 }
2294
2295 ASSERT(ctx->Driver.BlitFramebuffer);
2296 ctx->Driver.BlitFramebuffer(ctx,
2297 srcX0, srcY0, srcX1, srcY1,
2298 dstX0, dstY0, dstX1, dstY1,
2299 mask, filter);
2300 }
2301 #endif /* FEATURE_EXT_framebuffer_blit */