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