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