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