5826d2d2192d987021e3265fc3806ff2e032dde4
[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 gl_format mesaFormat;
621
622 /*
623 * XXX for ARB_fbo, only check color buffers that are named by
624 * GL_READ_BUFFER and GL_DRAW_BUFFERi.
625 */
626
627 /* check for attachment completeness
628 */
629 if (i == -2) {
630 att = &fb->Attachment[BUFFER_DEPTH];
631 test_attachment_completeness(ctx, GL_DEPTH, att);
632 if (!att->Complete) {
633 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
634 fbo_incomplete("depth attachment incomplete", -1);
635 return;
636 }
637 }
638 else if (i == -1) {
639 att = &fb->Attachment[BUFFER_STENCIL];
640 test_attachment_completeness(ctx, GL_STENCIL, att);
641 if (!att->Complete) {
642 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
643 fbo_incomplete("stencil attachment incomplete", -1);
644 return;
645 }
646 }
647 else {
648 att = &fb->Attachment[BUFFER_COLOR0 + i];
649 test_attachment_completeness(ctx, GL_COLOR, att);
650 if (!att->Complete) {
651 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
652 fbo_incomplete("color attachment incomplete", i);
653 return;
654 }
655 }
656
657 /* get width, height, format of the renderbuffer/texture
658 */
659 if (att->Type == GL_TEXTURE) {
660 const struct gl_texture_image *texImg
661 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
662 minWidth = MIN2(minWidth, texImg->Width);
663 maxWidth = MAX2(maxWidth, texImg->Width);
664 minHeight = MIN2(minHeight, texImg->Height);
665 maxHeight = MAX2(maxHeight, texImg->Height);
666 f = texImg->_BaseFormat;
667 mesaFormat = texImg->TexFormat;
668 numImages++;
669 if (!is_legal_color_format(ctx, f) &&
670 !is_legal_depth_format(ctx, f)) {
671 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
672 fbo_incomplete("texture attachment incomplete", -1);
673 return;
674 }
675 }
676 else if (att->Type == GL_RENDERBUFFER_EXT) {
677 minWidth = MIN2(minWidth, att->Renderbuffer->Width);
678 maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
679 minHeight = MIN2(minHeight, att->Renderbuffer->Height);
680 maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
681 f = att->Renderbuffer->InternalFormat;
682 mesaFormat = att->Renderbuffer->Format;
683 numImages++;
684 }
685 else {
686 assert(att->Type == GL_NONE);
687 continue;
688 }
689
690 if (numSamples < 0) {
691 /* first buffer */
692 numSamples = att->Renderbuffer->NumSamples;
693 }
694
695 /* check if integer color */
696 fb->_IntegerColor = _mesa_is_format_integer(mesaFormat);
697
698 /* Error-check width, height, format, samples
699 */
700 if (numImages == 1) {
701 /* save format, num samples */
702 if (i >= 0) {
703 intFormat = f;
704 }
705 }
706 else {
707 if (!ctx->Extensions.ARB_framebuffer_object) {
708 /* check that width, height, format are same */
709 if (minWidth != maxWidth || minHeight != maxHeight) {
710 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
711 fbo_incomplete("width or height mismatch", -1);
712 return;
713 }
714 /* check that all color buffer have same format */
715 if (intFormat != GL_NONE && f != intFormat) {
716 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
717 fbo_incomplete("format mismatch", -1);
718 return;
719 }
720 }
721 if (att->Renderbuffer &&
722 att->Renderbuffer->NumSamples != numSamples) {
723 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
724 fbo_incomplete("inconsistant number of samples", i);
725 return;
726 }
727
728 }
729 }
730
731 #if FEATURE_GL
732 if (ctx->API == API_OPENGL) {
733 /* Check that all DrawBuffers are present */
734 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
735 if (fb->ColorDrawBuffer[j] != GL_NONE) {
736 const struct gl_renderbuffer_attachment *att
737 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
738 assert(att);
739 if (att->Type == GL_NONE) {
740 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
741 fbo_incomplete("missing drawbuffer", j);
742 return;
743 }
744 }
745 }
746
747 /* Check that the ReadBuffer is present */
748 if (fb->ColorReadBuffer != GL_NONE) {
749 const struct gl_renderbuffer_attachment *att
750 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
751 assert(att);
752 if (att->Type == GL_NONE) {
753 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
754 fbo_incomplete("missing readbuffer", -1);
755 return;
756 }
757 }
758 }
759 #else
760 (void) j;
761 #endif
762
763 if (numImages == 0) {
764 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
765 fbo_incomplete("no attachments", -1);
766 return;
767 }
768
769 /* Provisionally set status = COMPLETE ... */
770 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
771
772 /* ... but the driver may say the FB is incomplete.
773 * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
774 * if anything.
775 */
776 if (ctx->Driver.ValidateFramebuffer) {
777 ctx->Driver.ValidateFramebuffer(ctx, fb);
778 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
779 fbo_incomplete("driver marked FBO as incomplete", -1);
780 }
781 }
782
783 if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
784 /*
785 * Note that if ARB_framebuffer_object is supported and the attached
786 * renderbuffers/textures are different sizes, the framebuffer
787 * width/height will be set to the smallest width/height.
788 */
789 fb->Width = minWidth;
790 fb->Height = minHeight;
791
792 /* finally, update the visual info for the framebuffer */
793 _mesa_update_framebuffer_visual(fb);
794 }
795 }
796
797
798 GLboolean GLAPIENTRY
799 _mesa_IsRenderbufferEXT(GLuint renderbuffer)
800 {
801 GET_CURRENT_CONTEXT(ctx);
802 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
803 if (renderbuffer) {
804 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
805 if (rb != NULL && rb != &DummyRenderbuffer)
806 return GL_TRUE;
807 }
808 return GL_FALSE;
809 }
810
811
812 void GLAPIENTRY
813 _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
814 {
815 struct gl_renderbuffer *newRb;
816 GET_CURRENT_CONTEXT(ctx);
817
818 ASSERT_OUTSIDE_BEGIN_END(ctx);
819
820 if (target != GL_RENDERBUFFER_EXT) {
821 _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
822 return;
823 }
824
825 /* No need to flush here since the render buffer binding has no
826 * effect on rendering state.
827 */
828
829 if (renderbuffer) {
830 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
831 if (newRb == &DummyRenderbuffer) {
832 /* ID was reserved, but no real renderbuffer object made yet */
833 newRb = NULL;
834 }
835 else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
836 /* All RB IDs must be Gen'd */
837 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
838 return;
839 }
840
841 if (!newRb) {
842 /* create new renderbuffer object */
843 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
844 if (!newRb) {
845 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
846 return;
847 }
848 ASSERT(newRb->AllocStorage);
849 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
850 newRb->RefCount = 1; /* referenced by hash table */
851 }
852 }
853 else {
854 newRb = NULL;
855 }
856
857 ASSERT(newRb != &DummyRenderbuffer);
858
859 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
860 }
861
862
863 /**
864 * If the given renderbuffer is anywhere attached to the framebuffer, detach
865 * the renderbuffer.
866 * This is used when a renderbuffer object is deleted.
867 * The spec calls for unbinding.
868 */
869 static void
870 detach_renderbuffer(struct gl_context *ctx,
871 struct gl_framebuffer *fb,
872 struct gl_renderbuffer *rb)
873 {
874 GLuint i;
875 for (i = 0; i < BUFFER_COUNT; i++) {
876 if (fb->Attachment[i].Renderbuffer == rb) {
877 _mesa_remove_attachment(ctx, &fb->Attachment[i]);
878 }
879 }
880 invalidate_framebuffer(fb);
881 }
882
883
884 void GLAPIENTRY
885 _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
886 {
887 GLint i;
888 GET_CURRENT_CONTEXT(ctx);
889
890 ASSERT_OUTSIDE_BEGIN_END(ctx);
891 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
892
893 for (i = 0; i < n; i++) {
894 if (renderbuffers[i] > 0) {
895 struct gl_renderbuffer *rb;
896 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
897 if (rb) {
898 /* check if deleting currently bound renderbuffer object */
899 if (rb == ctx->CurrentRenderbuffer) {
900 /* bind default */
901 ASSERT(rb->RefCount >= 2);
902 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
903 }
904
905 if (ctx->DrawBuffer->Name) {
906 detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
907 }
908 if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) {
909 detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
910 }
911
912 /* Remove from hash table immediately, to free the ID.
913 * But the object will not be freed until it's no longer
914 * referenced anywhere else.
915 */
916 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
917
918 if (rb != &DummyRenderbuffer) {
919 /* no longer referenced by hash table */
920 _mesa_reference_renderbuffer(&rb, NULL);
921 }
922 }
923 }
924 }
925 }
926
927
928 void GLAPIENTRY
929 _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
930 {
931 GET_CURRENT_CONTEXT(ctx);
932 GLuint first;
933 GLint i;
934
935 ASSERT_OUTSIDE_BEGIN_END(ctx);
936
937 if (n < 0) {
938 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
939 return;
940 }
941
942 if (!renderbuffers)
943 return;
944
945 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
946
947 for (i = 0; i < n; i++) {
948 GLuint name = first + i;
949 renderbuffers[i] = name;
950 /* insert dummy placeholder into hash table */
951 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
952 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
953 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
954 }
955 }
956
957
958 /**
959 * Given an internal format token for a render buffer, return the
960 * corresponding base format.
961 * This is very similar to _mesa_base_tex_format() but the set of valid
962 * internal formats is somewhat different.
963 *
964 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
965 * GL_DEPTH_STENCIL_EXT or zero if error.
966 *
967 * XXX in the future when we support red-only and red-green formats
968 * we'll also return GL_RED and GL_RG.
969 */
970 GLenum
971 _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
972 {
973 switch (internalFormat) {
974 case GL_ALPHA:
975 case GL_ALPHA4:
976 case GL_ALPHA8:
977 case GL_ALPHA12:
978 case GL_ALPHA16:
979 return GL_ALPHA;
980 case GL_RGB:
981 case GL_R3_G3_B2:
982 case GL_RGB4:
983 case GL_RGB5:
984 case GL_RGB8:
985 case GL_RGB10:
986 case GL_RGB12:
987 case GL_RGB16:
988 return GL_RGB;
989 case GL_RGBA:
990 case GL_RGBA2:
991 case GL_RGBA4:
992 case GL_RGB5_A1:
993 case GL_RGBA8:
994 case GL_RGB10_A2:
995 case GL_RGBA12:
996 case GL_RGBA16:
997 case GL_RGBA16_SNORM:
998 return GL_RGBA;
999 case GL_STENCIL_INDEX:
1000 case GL_STENCIL_INDEX1_EXT:
1001 case GL_STENCIL_INDEX4_EXT:
1002 case GL_STENCIL_INDEX8_EXT:
1003 case GL_STENCIL_INDEX16_EXT:
1004 return GL_STENCIL_INDEX;
1005 case GL_DEPTH_COMPONENT:
1006 case GL_DEPTH_COMPONENT16:
1007 case GL_DEPTH_COMPONENT24:
1008 case GL_DEPTH_COMPONENT32:
1009 return GL_DEPTH_COMPONENT;
1010 case GL_DEPTH_STENCIL_EXT:
1011 case GL_DEPTH24_STENCIL8_EXT:
1012 if (ctx->Extensions.EXT_packed_depth_stencil)
1013 return GL_DEPTH_STENCIL_EXT;
1014 else
1015 return 0;
1016 /* XXX add floating point formats eventually */
1017 default:
1018 return 0;
1019 }
1020 }
1021
1022
1023 /** sentinal value, see below */
1024 #define NO_SAMPLES 1000
1025
1026
1027 /**
1028 * Helper function used by _mesa_RenderbufferStorageEXT() and
1029 * _mesa_RenderbufferStorageMultisample().
1030 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
1031 */
1032 static void
1033 renderbuffer_storage(GLenum target, GLenum internalFormat,
1034 GLsizei width, GLsizei height, GLsizei samples)
1035 {
1036 const char *func = samples == NO_SAMPLES ?
1037 "glRenderbufferStorage" : "RenderbufferStorageMultisample";
1038 struct gl_renderbuffer *rb;
1039 GLenum baseFormat;
1040 GET_CURRENT_CONTEXT(ctx);
1041
1042 ASSERT_OUTSIDE_BEGIN_END(ctx);
1043
1044 if (target != GL_RENDERBUFFER_EXT) {
1045 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
1046 return;
1047 }
1048
1049 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
1050 if (baseFormat == 0) {
1051 _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
1052 return;
1053 }
1054
1055 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
1056 _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
1057 return;
1058 }
1059
1060 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
1061 _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
1062 return;
1063 }
1064
1065 if (samples == NO_SAMPLES) {
1066 /* NumSamples == 0 indicates non-multisampling */
1067 samples = 0;
1068 }
1069 else if (samples > (GLsizei) ctx->Const.MaxSamples) {
1070 /* note: driver may choose to use more samples than what's requested */
1071 _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
1072 return;
1073 }
1074
1075 rb = ctx->CurrentRenderbuffer;
1076 if (!rb) {
1077 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
1078 return;
1079 }
1080
1081 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1082
1083 if (rb->InternalFormat == internalFormat &&
1084 rb->Width == (GLuint) width &&
1085 rb->Height == (GLuint) height) {
1086 /* no change in allocation needed */
1087 return;
1088 }
1089
1090 /* These MUST get set by the AllocStorage func */
1091 rb->Format = MESA_FORMAT_NONE;
1092 rb->NumSamples = samples;
1093
1094 /* Now allocate the storage */
1095 ASSERT(rb->AllocStorage);
1096 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
1097 /* No error - check/set fields now */
1098 assert(rb->Format != MESA_FORMAT_NONE);
1099 assert(rb->Width == (GLuint) width);
1100 assert(rb->Height == (GLuint) height);
1101 rb->InternalFormat = internalFormat;
1102 rb->_BaseFormat = baseFormat;
1103 assert(rb->_BaseFormat != 0);
1104 }
1105 else {
1106 /* Probably ran out of memory - clear the fields */
1107 rb->Width = 0;
1108 rb->Height = 0;
1109 rb->Format = MESA_FORMAT_NONE;
1110 rb->InternalFormat = GL_NONE;
1111 rb->_BaseFormat = GL_NONE;
1112 rb->NumSamples = 0;
1113 }
1114
1115 /*
1116 test_framebuffer_completeness(ctx, fb);
1117 */
1118 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
1119 * points???
1120 */
1121 }
1122
1123
1124 #if FEATURE_OES_EGL_image
1125 void GLAPIENTRY
1126 _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1127 {
1128 struct gl_renderbuffer *rb;
1129 GET_CURRENT_CONTEXT(ctx);
1130 ASSERT_OUTSIDE_BEGIN_END(ctx);
1131
1132 if (!ctx->Extensions.OES_EGL_image) {
1133 _mesa_error(ctx, GL_INVALID_OPERATION,
1134 "glEGLImageTargetRenderbufferStorageOES(unsupported)");
1135 return;
1136 }
1137
1138 if (target != GL_RENDERBUFFER) {
1139 _mesa_error(ctx, GL_INVALID_ENUM,
1140 "EGLImageTargetRenderbufferStorageOES");
1141 return;
1142 }
1143
1144 rb = ctx->CurrentRenderbuffer;
1145 if (!rb) {
1146 _mesa_error(ctx, GL_INVALID_OPERATION,
1147 "EGLImageTargetRenderbufferStorageOES");
1148 return;
1149 }
1150
1151 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1152
1153 ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1154 }
1155 #endif
1156
1157
1158 /**
1159 * Helper function for _mesa_GetRenderbufferParameterivEXT() and
1160 * _mesa_GetFramebufferAttachmentParameterivEXT()
1161 * We have to be careful to respect the base format. For example, if a
1162 * renderbuffer/texture was created with internalFormat=GL_RGB but the
1163 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
1164 * we need to return zero.
1165 */
1166 static GLint
1167 get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
1168 {
1169 switch (pname) {
1170 case GL_RENDERBUFFER_RED_SIZE_EXT:
1171 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
1172 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1173 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
1174 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1175 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
1176 if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
1177 return _mesa_get_format_bits(format, pname);
1178 else
1179 return 0;
1180 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1181 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
1182 if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA)
1183 return _mesa_get_format_bits(format, pname);
1184 else
1185 return 0;
1186 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1187 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
1188 if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
1189 return _mesa_get_format_bits(format, pname);
1190 else
1191 return 0;
1192 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1193 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
1194 if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
1195 return _mesa_get_format_bits(format, pname);
1196 else
1197 return 0;
1198 default:
1199 return 0;
1200 }
1201 }
1202
1203
1204
1205 void GLAPIENTRY
1206 _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1207 GLsizei width, GLsizei height)
1208 {
1209 /* GL_ARB_fbo says calling this function is equivalent to calling
1210 * glRenderbufferStorageMultisample() with samples=0. We pass in
1211 * a token value here just for error reporting purposes.
1212 */
1213 renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
1214 }
1215
1216
1217 void GLAPIENTRY
1218 _mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
1219 GLenum internalFormat,
1220 GLsizei width, GLsizei height)
1221 {
1222 renderbuffer_storage(target, internalFormat, width, height, samples);
1223 }
1224
1225
1226 /**
1227 * OpenGL ES version of glRenderBufferStorage.
1228 */
1229 void GLAPIENTRY
1230 _es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1231 GLsizei width, GLsizei height)
1232 {
1233 switch (internalFormat) {
1234 case GL_RGB565:
1235 /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
1236 /* choose a closest format */
1237 internalFormat = GL_RGB5;
1238 break;
1239 default:
1240 break;
1241 }
1242
1243 renderbuffer_storage(target, internalFormat, width, height, 0);
1244 }
1245
1246
1247 void GLAPIENTRY
1248 _mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
1249 {
1250 struct gl_renderbuffer *rb;
1251 GET_CURRENT_CONTEXT(ctx);
1252
1253 ASSERT_OUTSIDE_BEGIN_END(ctx);
1254
1255 if (target != GL_RENDERBUFFER_EXT) {
1256 _mesa_error(ctx, GL_INVALID_ENUM,
1257 "glGetRenderbufferParameterivEXT(target)");
1258 return;
1259 }
1260
1261 rb = ctx->CurrentRenderbuffer;
1262 if (!rb) {
1263 _mesa_error(ctx, GL_INVALID_OPERATION,
1264 "glGetRenderbufferParameterivEXT");
1265 return;
1266 }
1267
1268 /* No need to flush here since we're just quering state which is
1269 * not effected by rendering.
1270 */
1271
1272 switch (pname) {
1273 case GL_RENDERBUFFER_WIDTH_EXT:
1274 *params = rb->Width;
1275 return;
1276 case GL_RENDERBUFFER_HEIGHT_EXT:
1277 *params = rb->Height;
1278 return;
1279 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
1280 *params = rb->InternalFormat;
1281 return;
1282 case GL_RENDERBUFFER_RED_SIZE_EXT:
1283 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1284 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1285 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1286 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1287 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1288 *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
1289 break;
1290 case GL_RENDERBUFFER_SAMPLES:
1291 if (ctx->Extensions.ARB_framebuffer_object) {
1292 *params = rb->NumSamples;
1293 break;
1294 }
1295 /* fallthrough */
1296 default:
1297 _mesa_error(ctx, GL_INVALID_ENUM,
1298 "glGetRenderbufferParameterivEXT(target)");
1299 return;
1300 }
1301 }
1302
1303
1304 GLboolean GLAPIENTRY
1305 _mesa_IsFramebufferEXT(GLuint framebuffer)
1306 {
1307 GET_CURRENT_CONTEXT(ctx);
1308 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1309 if (framebuffer) {
1310 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
1311 if (rb != NULL && rb != &DummyFramebuffer)
1312 return GL_TRUE;
1313 }
1314 return GL_FALSE;
1315 }
1316
1317
1318 /**
1319 * Check if any of the attachments of the given framebuffer are textures
1320 * (render to texture). Call ctx->Driver.RenderTexture() for such
1321 * attachments.
1322 */
1323 static void
1324 check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
1325 {
1326 GLuint i;
1327 ASSERT(ctx->Driver.RenderTexture);
1328
1329 if (fb->Name == 0)
1330 return; /* can't render to texture with winsys framebuffers */
1331
1332 for (i = 0; i < BUFFER_COUNT; i++) {
1333 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1334 struct gl_texture_object *texObj = att->Texture;
1335 if (texObj
1336 && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
1337 ctx->Driver.RenderTexture(ctx, fb, att);
1338 }
1339 }
1340 }
1341
1342
1343 /**
1344 * Examine all the framebuffer's attachments to see if any are textures.
1345 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
1346 * notify the device driver that the texture image may have changed.
1347 */
1348 static void
1349 check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
1350 {
1351 if (fb->Name == 0)
1352 return; /* can't render to texture with winsys framebuffers */
1353
1354 if (ctx->Driver.FinishRenderTexture) {
1355 GLuint i;
1356 for (i = 0; i < BUFFER_COUNT; i++) {
1357 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1358 if (att->Texture && att->Renderbuffer) {
1359 ctx->Driver.FinishRenderTexture(ctx, att);
1360 }
1361 }
1362 }
1363 }
1364
1365
1366 void GLAPIENTRY
1367 _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
1368 {
1369 struct gl_framebuffer *newDrawFb, *newReadFb;
1370 struct gl_framebuffer *oldDrawFb, *oldReadFb;
1371 GLboolean bindReadBuf, bindDrawBuf;
1372 GET_CURRENT_CONTEXT(ctx);
1373
1374 #ifdef DEBUG
1375 if (ctx->Extensions.ARB_framebuffer_object) {
1376 ASSERT(ctx->Extensions.EXT_framebuffer_object);
1377 ASSERT(ctx->Extensions.EXT_framebuffer_blit);
1378 }
1379 #endif
1380
1381 ASSERT_OUTSIDE_BEGIN_END(ctx);
1382
1383 if (!ctx->Extensions.EXT_framebuffer_object) {
1384 _mesa_error(ctx, GL_INVALID_OPERATION,
1385 "glBindFramebufferEXT(unsupported)");
1386 return;
1387 }
1388
1389 switch (target) {
1390 #if FEATURE_EXT_framebuffer_blit
1391 case GL_DRAW_FRAMEBUFFER_EXT:
1392 if (!ctx->Extensions.EXT_framebuffer_blit) {
1393 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1394 return;
1395 }
1396 bindDrawBuf = GL_TRUE;
1397 bindReadBuf = GL_FALSE;
1398 break;
1399 case GL_READ_FRAMEBUFFER_EXT:
1400 if (!ctx->Extensions.EXT_framebuffer_blit) {
1401 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1402 return;
1403 }
1404 bindDrawBuf = GL_FALSE;
1405 bindReadBuf = GL_TRUE;
1406 break;
1407 #endif
1408 case GL_FRAMEBUFFER_EXT:
1409 bindDrawBuf = GL_TRUE;
1410 bindReadBuf = GL_TRUE;
1411 break;
1412 default:
1413 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1414 return;
1415 }
1416
1417 if (framebuffer) {
1418 /* Binding a user-created framebuffer object */
1419 newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
1420 if (newDrawFb == &DummyFramebuffer) {
1421 /* ID was reserved, but no real framebuffer object made yet */
1422 newDrawFb = NULL;
1423 }
1424 else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
1425 /* All FBO IDs must be Gen'd */
1426 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
1427 return;
1428 }
1429
1430 if (!newDrawFb) {
1431 /* create new framebuffer object */
1432 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
1433 if (!newDrawFb) {
1434 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1435 return;
1436 }
1437 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
1438 }
1439 newReadFb = newDrawFb;
1440 }
1441 else {
1442 /* Binding the window system framebuffer (which was originally set
1443 * with MakeCurrent).
1444 */
1445 newDrawFb = ctx->WinSysDrawBuffer;
1446 newReadFb = ctx->WinSysReadBuffer;
1447 }
1448
1449 ASSERT(newDrawFb);
1450 ASSERT(newDrawFb != &DummyFramebuffer);
1451
1452 /* save pointers to current/old framebuffers */
1453 oldDrawFb = ctx->DrawBuffer;
1454 oldReadFb = ctx->ReadBuffer;
1455
1456 /* check if really changing bindings */
1457 if (oldDrawFb == newDrawFb)
1458 bindDrawBuf = GL_FALSE;
1459 if (oldReadFb == newReadFb)
1460 bindReadBuf = GL_FALSE;
1461
1462 /*
1463 * OK, now bind the new Draw/Read framebuffers, if they're changing.
1464 *
1465 * We also check if we're beginning and/or ending render-to-texture.
1466 * When a framebuffer with texture attachments is unbound, call
1467 * ctx->Driver.FinishRenderTexture().
1468 * When a framebuffer with texture attachments is bound, call
1469 * ctx->Driver.RenderTexture().
1470 *
1471 * Note that if the ReadBuffer has texture attachments we don't consider
1472 * that a render-to-texture case.
1473 */
1474 if (bindReadBuf) {
1475 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1476
1477 /* check if old readbuffer was render-to-texture */
1478 check_end_texture_render(ctx, oldReadFb);
1479
1480 _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
1481 }
1482
1483 if (bindDrawBuf) {
1484 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1485
1486 /* check if old read/draw buffers were render-to-texture */
1487 if (!bindReadBuf)
1488 check_end_texture_render(ctx, oldReadFb);
1489
1490 if (oldDrawFb != oldReadFb)
1491 check_end_texture_render(ctx, oldDrawFb);
1492
1493 /* check if newly bound framebuffer has any texture attachments */
1494 check_begin_texture_render(ctx, newDrawFb);
1495
1496 _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
1497 }
1498
1499 if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
1500 ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
1501 }
1502 }
1503
1504
1505 void GLAPIENTRY
1506 _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1507 {
1508 GLint i;
1509 GET_CURRENT_CONTEXT(ctx);
1510
1511 ASSERT_OUTSIDE_BEGIN_END(ctx);
1512 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1513
1514 for (i = 0; i < n; i++) {
1515 if (framebuffers[i] > 0) {
1516 struct gl_framebuffer *fb;
1517 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
1518 if (fb) {
1519 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
1520
1521 /* check if deleting currently bound framebuffer object */
1522 if (ctx->Extensions.EXT_framebuffer_blit) {
1523 /* separate draw/read binding points */
1524 if (fb == ctx->DrawBuffer) {
1525 /* bind default */
1526 ASSERT(fb->RefCount >= 2);
1527 _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1528 }
1529 if (fb == ctx->ReadBuffer) {
1530 /* bind default */
1531 ASSERT(fb->RefCount >= 2);
1532 _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1533 }
1534 }
1535 else {
1536 /* only one binding point for read/draw buffers */
1537 if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
1538 /* bind default */
1539 ASSERT(fb->RefCount >= 2);
1540 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1541 }
1542 }
1543
1544 /* remove from hash table immediately, to free the ID */
1545 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
1546
1547 if (fb != &DummyFramebuffer) {
1548 /* But the object will not be freed until it's no longer
1549 * bound in any context.
1550 */
1551 _mesa_reference_framebuffer(&fb, NULL);
1552 }
1553 }
1554 }
1555 }
1556 }
1557
1558
1559 void GLAPIENTRY
1560 _mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1561 {
1562 GET_CURRENT_CONTEXT(ctx);
1563 GLuint first;
1564 GLint i;
1565
1566 ASSERT_OUTSIDE_BEGIN_END(ctx);
1567
1568 if (n < 0) {
1569 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1570 return;
1571 }
1572
1573 if (!framebuffers)
1574 return;
1575
1576 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1577
1578 for (i = 0; i < n; i++) {
1579 GLuint name = first + i;
1580 framebuffers[i] = name;
1581 /* insert dummy placeholder into hash table */
1582 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
1583 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
1584 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1585 }
1586 }
1587
1588
1589
1590 GLenum GLAPIENTRY
1591 _mesa_CheckFramebufferStatusEXT(GLenum target)
1592 {
1593 struct gl_framebuffer *buffer;
1594 GET_CURRENT_CONTEXT(ctx);
1595
1596 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1597
1598 switch (target) {
1599 #if FEATURE_EXT_framebuffer_blit
1600 case GL_DRAW_FRAMEBUFFER_EXT:
1601 if (!ctx->Extensions.EXT_framebuffer_blit) {
1602 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1603 return 0;
1604 }
1605 buffer = ctx->DrawBuffer;
1606 break;
1607 case GL_READ_FRAMEBUFFER_EXT:
1608 if (!ctx->Extensions.EXT_framebuffer_blit) {
1609 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1610 return 0;
1611 }
1612 buffer = ctx->ReadBuffer;
1613 break;
1614 #endif
1615 case GL_FRAMEBUFFER_EXT:
1616 buffer = ctx->DrawBuffer;
1617 break;
1618 default:
1619 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1620 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
1621 }
1622
1623 if (buffer->Name == 0) {
1624 /* The window system / default framebuffer is always complete */
1625 return GL_FRAMEBUFFER_COMPLETE_EXT;
1626 }
1627
1628 /* No need to flush here */
1629
1630 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
1631 _mesa_test_framebuffer_completeness(ctx, buffer);
1632 }
1633
1634 return buffer->_Status;
1635 }
1636
1637
1638
1639 /**
1640 * Common code called by glFramebufferTexture1D/2D/3DEXT().
1641 */
1642 static void
1643 framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
1644 GLenum attachment, GLenum textarget, GLuint texture,
1645 GLint level, GLint zoffset)
1646 {
1647 struct gl_renderbuffer_attachment *att;
1648 struct gl_texture_object *texObj = NULL;
1649 struct gl_framebuffer *fb;
1650 GLboolean error = GL_FALSE;
1651
1652 ASSERT_OUTSIDE_BEGIN_END(ctx);
1653
1654 switch (target) {
1655 case GL_READ_FRAMEBUFFER_EXT:
1656 error = !ctx->Extensions.EXT_framebuffer_blit;
1657 fb = ctx->ReadBuffer;
1658 break;
1659 case GL_DRAW_FRAMEBUFFER_EXT:
1660 error = !ctx->Extensions.EXT_framebuffer_blit;
1661 /* fall-through */
1662 case GL_FRAMEBUFFER_EXT:
1663 fb = ctx->DrawBuffer;
1664 break;
1665 default:
1666 error = GL_TRUE;
1667 }
1668
1669 if (error) {
1670 _mesa_error(ctx, GL_INVALID_ENUM,
1671 "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
1672 return;
1673 }
1674
1675 ASSERT(fb);
1676
1677 /* check framebuffer binding */
1678 if (fb->Name == 0) {
1679 _mesa_error(ctx, GL_INVALID_OPERATION,
1680 "glFramebufferTexture%sEXT", caller);
1681 return;
1682 }
1683
1684
1685 /* The textarget, level, and zoffset parameters are only validated if
1686 * texture is non-zero.
1687 */
1688 if (texture) {
1689 GLboolean err = GL_TRUE;
1690
1691 texObj = _mesa_lookup_texture(ctx, texture);
1692 if (texObj != NULL) {
1693 if (textarget == 0) {
1694 /* XXX what's the purpose of this? */
1695 err = (texObj->Target != GL_TEXTURE_3D) &&
1696 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1697 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1698 }
1699 else {
1700 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1701 ? !IS_CUBE_FACE(textarget)
1702 : (texObj->Target != textarget);
1703 }
1704 }
1705 else {
1706 /* can't render to a non-existant texture */
1707 _mesa_error(ctx, GL_INVALID_OPERATION,
1708 "glFramebufferTexture%sEXT(non existant texture)",
1709 caller);
1710 return;
1711 }
1712
1713 if (err) {
1714 _mesa_error(ctx, GL_INVALID_OPERATION,
1715 "glFramebufferTexture%sEXT(texture target mismatch)",
1716 caller);
1717 return;
1718 }
1719
1720 if (texObj->Target == GL_TEXTURE_3D) {
1721 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1722 if (zoffset < 0 || zoffset >= maxSize) {
1723 _mesa_error(ctx, GL_INVALID_VALUE,
1724 "glFramebufferTexture%sEXT(zoffset)", caller);
1725 return;
1726 }
1727 }
1728 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1729 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1730 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1731 _mesa_error(ctx, GL_INVALID_VALUE,
1732 "glFramebufferTexture%sEXT(layer)", caller);
1733 return;
1734 }
1735 }
1736
1737 if ((level < 0) ||
1738 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1739 _mesa_error(ctx, GL_INVALID_VALUE,
1740 "glFramebufferTexture%sEXT(level)", caller);
1741 return;
1742 }
1743 }
1744
1745 att = _mesa_get_attachment(ctx, fb, attachment);
1746 if (att == NULL) {
1747 _mesa_error(ctx, GL_INVALID_ENUM,
1748 "glFramebufferTexture%sEXT(attachment)", caller);
1749 return;
1750 }
1751
1752 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1753
1754 _glthread_LOCK_MUTEX(fb->Mutex);
1755 if (texObj) {
1756 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1757 level, zoffset);
1758 /* Set the render-to-texture flag. We'll check this flag in
1759 * glTexImage() and friends to determine if we need to revalidate
1760 * any FBOs that might be rendering into this texture.
1761 * This flag never gets cleared since it's non-trivial to determine
1762 * when all FBOs might be done rendering to this texture. That's OK
1763 * though since it's uncommon to render to a texture then repeatedly
1764 * call glTexImage() to change images in the texture.
1765 */
1766 texObj->_RenderToTexture = GL_TRUE;
1767 }
1768 else {
1769 _mesa_remove_attachment(ctx, att);
1770 }
1771
1772 invalidate_framebuffer(fb);
1773
1774 _glthread_UNLOCK_MUTEX(fb->Mutex);
1775 }
1776
1777
1778
1779 void GLAPIENTRY
1780 _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1781 GLenum textarget, GLuint texture, GLint level)
1782 {
1783 GET_CURRENT_CONTEXT(ctx);
1784
1785 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1786 _mesa_error(ctx, GL_INVALID_ENUM,
1787 "glFramebufferTexture1DEXT(textarget)");
1788 return;
1789 }
1790
1791 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1792 level, 0);
1793 }
1794
1795
1796 void GLAPIENTRY
1797 _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1798 GLenum textarget, GLuint texture, GLint level)
1799 {
1800 GET_CURRENT_CONTEXT(ctx);
1801
1802 if ((texture != 0) &&
1803 (textarget != GL_TEXTURE_2D) &&
1804 (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1805 (!IS_CUBE_FACE(textarget))) {
1806 _mesa_error(ctx, GL_INVALID_OPERATION,
1807 "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
1808 return;
1809 }
1810
1811 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1812 level, 0);
1813 }
1814
1815
1816 void GLAPIENTRY
1817 _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1818 GLenum textarget, GLuint texture,
1819 GLint level, GLint zoffset)
1820 {
1821 GET_CURRENT_CONTEXT(ctx);
1822
1823 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1824 _mesa_error(ctx, GL_INVALID_ENUM,
1825 "glFramebufferTexture3DEXT(textarget)");
1826 return;
1827 }
1828
1829 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
1830 level, zoffset);
1831 }
1832
1833
1834 void GLAPIENTRY
1835 _mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1836 GLuint texture, GLint level, GLint layer)
1837 {
1838 GET_CURRENT_CONTEXT(ctx);
1839
1840 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1841 level, layer);
1842 }
1843
1844
1845 void GLAPIENTRY
1846 _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1847 GLenum renderbufferTarget,
1848 GLuint renderbuffer)
1849 {
1850 struct gl_renderbuffer_attachment *att;
1851 struct gl_framebuffer *fb;
1852 struct gl_renderbuffer *rb;
1853 GET_CURRENT_CONTEXT(ctx);
1854
1855 ASSERT_OUTSIDE_BEGIN_END(ctx);
1856
1857 switch (target) {
1858 #if FEATURE_EXT_framebuffer_blit
1859 case GL_DRAW_FRAMEBUFFER_EXT:
1860 if (!ctx->Extensions.EXT_framebuffer_blit) {
1861 _mesa_error(ctx, GL_INVALID_ENUM,
1862 "glFramebufferRenderbufferEXT(target)");
1863 return;
1864 }
1865 fb = ctx->DrawBuffer;
1866 break;
1867 case GL_READ_FRAMEBUFFER_EXT:
1868 if (!ctx->Extensions.EXT_framebuffer_blit) {
1869 _mesa_error(ctx, GL_INVALID_ENUM,
1870 "glFramebufferRenderbufferEXT(target)");
1871 return;
1872 }
1873 fb = ctx->ReadBuffer;
1874 break;
1875 #endif
1876 case GL_FRAMEBUFFER_EXT:
1877 fb = ctx->DrawBuffer;
1878 break;
1879 default:
1880 _mesa_error(ctx, GL_INVALID_ENUM,
1881 "glFramebufferRenderbufferEXT(target)");
1882 return;
1883 }
1884
1885 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
1886 _mesa_error(ctx, GL_INVALID_ENUM,
1887 "glFramebufferRenderbufferEXT(renderbufferTarget)");
1888 return;
1889 }
1890
1891 if (fb->Name == 0) {
1892 /* Can't attach new renderbuffers to a window system framebuffer */
1893 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1894 return;
1895 }
1896
1897 att = _mesa_get_attachment(ctx, fb, attachment);
1898 if (att == NULL) {
1899 _mesa_error(ctx, GL_INVALID_ENUM,
1900 "glFramebufferRenderbufferEXT(invalid attachment %s)",
1901 _mesa_lookup_enum_by_nr(attachment));
1902 return;
1903 }
1904
1905 if (renderbuffer) {
1906 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
1907 if (!rb) {
1908 _mesa_error(ctx, GL_INVALID_OPERATION,
1909 "glFramebufferRenderbufferEXT(non-existant"
1910 " renderbuffer %u)", renderbuffer);
1911 return;
1912 }
1913 }
1914 else {
1915 /* remove renderbuffer attachment */
1916 rb = NULL;
1917 }
1918
1919 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
1920 rb && rb->Format != MESA_FORMAT_NONE) {
1921 /* make sure the renderbuffer is a depth/stencil format */
1922 const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
1923 if (baseFormat != GL_DEPTH_STENCIL) {
1924 _mesa_error(ctx, GL_INVALID_OPERATION,
1925 "glFramebufferRenderbufferEXT(renderbuffer"
1926 " is not DEPTH_STENCIL format)");
1927 return;
1928 }
1929 }
1930
1931
1932 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1933
1934 assert(ctx->Driver.FramebufferRenderbuffer);
1935 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
1936
1937 /* Some subsequent GL commands may depend on the framebuffer's visual
1938 * after the binding is updated. Update visual info now.
1939 */
1940 _mesa_update_framebuffer_visual(fb);
1941 }
1942
1943
1944 void GLAPIENTRY
1945 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1946 GLenum pname, GLint *params)
1947 {
1948 const struct gl_renderbuffer_attachment *att;
1949 struct gl_framebuffer *buffer;
1950 GET_CURRENT_CONTEXT(ctx);
1951
1952 ASSERT_OUTSIDE_BEGIN_END(ctx);
1953
1954 switch (target) {
1955 #if FEATURE_EXT_framebuffer_blit
1956 case GL_DRAW_FRAMEBUFFER_EXT:
1957 if (!ctx->Extensions.EXT_framebuffer_blit) {
1958 _mesa_error(ctx, GL_INVALID_ENUM,
1959 "glGetFramebufferAttachmentParameterivEXT(target)");
1960 return;
1961 }
1962 buffer = ctx->DrawBuffer;
1963 break;
1964 case GL_READ_FRAMEBUFFER_EXT:
1965 if (!ctx->Extensions.EXT_framebuffer_blit) {
1966 _mesa_error(ctx, GL_INVALID_ENUM,
1967 "glGetFramebufferAttachmentParameterivEXT(target)");
1968 return;
1969 }
1970 buffer = ctx->ReadBuffer;
1971 break;
1972 #endif
1973 case GL_FRAMEBUFFER_EXT:
1974 buffer = ctx->DrawBuffer;
1975 break;
1976 default:
1977 _mesa_error(ctx, GL_INVALID_ENUM,
1978 "glGetFramebufferAttachmentParameterivEXT(target)");
1979 return;
1980 }
1981
1982 if (buffer->Name == 0) {
1983 /* the default / window-system FBO */
1984 att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
1985 }
1986 else {
1987 /* user-created framebuffer FBO */
1988 att = _mesa_get_attachment(ctx, buffer, attachment);
1989 }
1990
1991 if (att == NULL) {
1992 _mesa_error(ctx, GL_INVALID_ENUM,
1993 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1994 return;
1995 }
1996
1997 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
1998 /* the depth and stencil attachments must point to the same buffer */
1999 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
2000 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
2001 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
2002 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
2003 _mesa_error(ctx, GL_INVALID_OPERATION,
2004 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
2005 " attachments differ)");
2006 return;
2007 }
2008 }
2009
2010 /* No need to flush here */
2011
2012 switch (pname) {
2013 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
2014 *params = att->Type;
2015 return;
2016 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
2017 if (att->Type == GL_RENDERBUFFER_EXT) {
2018 *params = att->Renderbuffer->Name;
2019 }
2020 else if (att->Type == GL_TEXTURE) {
2021 *params = att->Texture->Name;
2022 }
2023 else {
2024 _mesa_error(ctx, GL_INVALID_ENUM,
2025 "glGetFramebufferAttachmentParameterivEXT(pname)");
2026 }
2027 return;
2028 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
2029 if (att->Type == GL_TEXTURE) {
2030 *params = att->TextureLevel;
2031 }
2032 else {
2033 _mesa_error(ctx, GL_INVALID_ENUM,
2034 "glGetFramebufferAttachmentParameterivEXT(pname)");
2035 }
2036 return;
2037 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
2038 if (att->Type == GL_TEXTURE) {
2039 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
2040 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
2041 }
2042 else {
2043 *params = 0;
2044 }
2045 }
2046 else {
2047 _mesa_error(ctx, GL_INVALID_ENUM,
2048 "glGetFramebufferAttachmentParameterivEXT(pname)");
2049 }
2050 return;
2051 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
2052 if (att->Type == GL_TEXTURE) {
2053 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2054 *params = att->Zoffset;
2055 }
2056 else {
2057 *params = 0;
2058 }
2059 }
2060 else {
2061 _mesa_error(ctx, GL_INVALID_ENUM,
2062 "glGetFramebufferAttachmentParameterivEXT(pname)");
2063 }
2064 return;
2065 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2066 if (!ctx->Extensions.ARB_framebuffer_object) {
2067 _mesa_error(ctx, GL_INVALID_ENUM,
2068 "glGetFramebufferAttachmentParameterivEXT(pname)");
2069 }
2070 else {
2071 *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
2072 }
2073 return;
2074 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2075 if (!ctx->Extensions.ARB_framebuffer_object) {
2076 _mesa_error(ctx, GL_INVALID_ENUM,
2077 "glGetFramebufferAttachmentParameterivEXT(pname)");
2078 return;
2079 }
2080 else {
2081 gl_format format = att->Renderbuffer->Format;
2082 if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
2083 /* special cases */
2084 *params = GL_INDEX;
2085 }
2086 else {
2087 *params = _mesa_get_format_datatype(format);
2088 }
2089 }
2090 return;
2091 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
2092 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
2093 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
2094 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
2095 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
2096 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2097 if (!ctx->Extensions.ARB_framebuffer_object) {
2098 _mesa_error(ctx, GL_INVALID_ENUM,
2099 "glGetFramebufferAttachmentParameterivEXT(pname)");
2100 }
2101 else if (att->Texture) {
2102 const struct gl_texture_image *texImage =
2103 _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
2104 att->TextureLevel);
2105 if (texImage) {
2106 *params = get_component_bits(pname, texImage->_BaseFormat,
2107 texImage->TexFormat);
2108 }
2109 else {
2110 *params = 0;
2111 }
2112 }
2113 else if (att->Renderbuffer) {
2114 *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
2115 att->Renderbuffer->Format);
2116 }
2117 else {
2118 *params = 0;
2119 }
2120 return;
2121 default:
2122 _mesa_error(ctx, GL_INVALID_ENUM,
2123 "glGetFramebufferAttachmentParameterivEXT(pname)");
2124 return;
2125 }
2126 }
2127
2128
2129 void GLAPIENTRY
2130 _mesa_GenerateMipmapEXT(GLenum target)
2131 {
2132 struct gl_texture_object *texObj;
2133 GET_CURRENT_CONTEXT(ctx);
2134
2135 ASSERT_OUTSIDE_BEGIN_END(ctx);
2136 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2137
2138 switch (target) {
2139 case GL_TEXTURE_1D:
2140 case GL_TEXTURE_2D:
2141 case GL_TEXTURE_3D:
2142 case GL_TEXTURE_CUBE_MAP:
2143 /* OK, legal value */
2144 break;
2145 default:
2146 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
2147 return;
2148 }
2149
2150 texObj = _mesa_get_current_tex_object(ctx, target);
2151
2152 if (texObj->BaseLevel >= texObj->MaxLevel) {
2153 /* nothing to do */
2154 return;
2155 }
2156
2157 _mesa_lock_texture(ctx, texObj);
2158 if (target == GL_TEXTURE_CUBE_MAP) {
2159 GLuint face;
2160 for (face = 0; face < 6; face++)
2161 ctx->Driver.GenerateMipmap(ctx,
2162 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2163 texObj);
2164 }
2165 else {
2166 ctx->Driver.GenerateMipmap(ctx, target, texObj);
2167 }
2168 _mesa_unlock_texture(ctx, texObj);
2169 }
2170
2171
2172 #if FEATURE_EXT_framebuffer_blit
2173
2174 static const struct gl_renderbuffer_attachment *
2175 find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb)
2176 {
2177 GLuint i;
2178 for (i = 0; i < Elements(fb->Attachment); i++) {
2179 if (fb->Attachment[i].Renderbuffer == rb)
2180 return &fb->Attachment[i];
2181 }
2182 return NULL;
2183 }
2184
2185
2186
2187 /**
2188 * Blit rectangular region, optionally from one framebuffer to another.
2189 *
2190 * Note, if the src buffer is multisampled and the dest is not, this is
2191 * when the samples must be resolved to a single color.
2192 */
2193 void GLAPIENTRY
2194 _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
2195 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
2196 GLbitfield mask, GLenum filter)
2197 {
2198 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
2199 GL_DEPTH_BUFFER_BIT |
2200 GL_STENCIL_BUFFER_BIT);
2201 const struct gl_framebuffer *readFb, *drawFb;
2202 const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
2203 GET_CURRENT_CONTEXT(ctx);
2204
2205 ASSERT_OUTSIDE_BEGIN_END(ctx);
2206 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2207
2208 if (ctx->NewState) {
2209 _mesa_update_state(ctx);
2210 }
2211
2212 readFb = ctx->ReadBuffer;
2213 drawFb = ctx->DrawBuffer;
2214
2215 if (!readFb || !drawFb) {
2216 /* This will normally never happen but someday we may want to
2217 * support MakeCurrent() with no drawables.
2218 */
2219 return;
2220 }
2221
2222 /* check for complete framebuffers */
2223 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
2224 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
2225 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
2226 "glBlitFramebufferEXT(incomplete draw/read buffers)");
2227 return;
2228 }
2229
2230 if (filter != GL_NEAREST && filter != GL_LINEAR) {
2231 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
2232 return;
2233 }
2234
2235 if (mask & ~legalMaskBits) {
2236 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
2237 return;
2238 }
2239
2240 /* depth/stencil must be blitted with nearest filtering */
2241 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
2242 && filter != GL_NEAREST) {
2243 _mesa_error(ctx, GL_INVALID_OPERATION,
2244 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
2245 return;
2246 }
2247
2248 /* get color read/draw renderbuffers */
2249 if (mask & GL_COLOR_BUFFER_BIT) {
2250 colorReadRb = readFb->_ColorReadBuffer;
2251 colorDrawRb = drawFb->_ColorDrawBuffers[0];
2252 }
2253 else {
2254 colorReadRb = colorDrawRb = NULL;
2255 }
2256
2257 if (mask & GL_STENCIL_BUFFER_BIT) {
2258 struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
2259 struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
2260 if (!readRb ||
2261 !drawRb ||
2262 _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
2263 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
2264 _mesa_error(ctx, GL_INVALID_OPERATION,
2265 "glBlitFramebufferEXT(stencil buffer size mismatch");
2266 return;
2267 }
2268 }
2269
2270 if (mask & GL_DEPTH_BUFFER_BIT) {
2271 struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
2272 struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
2273 if (!readRb ||
2274 !drawRb ||
2275 _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
2276 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
2277 _mesa_error(ctx, GL_INVALID_OPERATION,
2278 "glBlitFramebufferEXT(depth buffer size mismatch");
2279 return;
2280 }
2281 }
2282
2283 if (readFb->Visual.samples > 0 &&
2284 drawFb->Visual.samples > 0 &&
2285 readFb->Visual.samples != drawFb->Visual.samples) {
2286 _mesa_error(ctx, GL_INVALID_OPERATION,
2287 "glBlitFramebufferEXT(mismatched samples");
2288 return;
2289 }
2290
2291 /* extra checks for multisample copies... */
2292 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
2293 /* src and dest region sizes must be the same */
2294 if (srcX1 - srcX0 != dstX1 - dstX0 ||
2295 srcY1 - srcY0 != dstY1 - dstY0) {
2296 _mesa_error(ctx, GL_INVALID_OPERATION,
2297 "glBlitFramebufferEXT(bad src/dst multisample region sizes");
2298 return;
2299 }
2300
2301 /* color formats must match */
2302 if (colorReadRb &&
2303 colorDrawRb &&
2304 colorReadRb->Format != colorDrawRb->Format) {
2305 _mesa_error(ctx, GL_INVALID_OPERATION,
2306 "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
2307 return;
2308 }
2309 }
2310
2311 if (!ctx->Extensions.EXT_framebuffer_blit) {
2312 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
2313 return;
2314 }
2315
2316 /* Debug code */
2317 if (DEBUG_BLIT) {
2318 printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
2319 " 0x%x, 0x%x)\n",
2320 srcX0, srcY0, srcX1, srcY1,
2321 dstX0, dstY0, dstX1, dstY1,
2322 mask, filter);
2323 if (colorReadRb) {
2324 const struct gl_renderbuffer_attachment *att;
2325
2326 att = find_attachment(readFb, colorReadRb);
2327 printf(" Src FBO %u RB %u (%dx%d) ",
2328 readFb->Name, colorReadRb->Name,
2329 colorReadRb->Width, colorReadRb->Height);
2330 if (att && att->Texture) {
2331 printf("Tex %u tgt 0x%x level %u face %u",
2332 att->Texture->Name,
2333 att->Texture->Target,
2334 att->TextureLevel,
2335 att->CubeMapFace);
2336 }
2337 printf("\n");
2338
2339 att = find_attachment(drawFb, colorDrawRb);
2340 printf(" Dst FBO %u RB %u (%dx%d) ",
2341 drawFb->Name, colorDrawRb->Name,
2342 colorDrawRb->Width, colorDrawRb->Height);
2343 if (att && att->Texture) {
2344 printf("Tex %u tgt 0x%x level %u face %u",
2345 att->Texture->Name,
2346 att->Texture->Target,
2347 att->TextureLevel,
2348 att->CubeMapFace);
2349 }
2350 printf("\n");
2351 }
2352 }
2353
2354 ASSERT(ctx->Driver.BlitFramebuffer);
2355 ctx->Driver.BlitFramebuffer(ctx,
2356 srcX0, srcY0, srcX1, srcY1,
2357 dstX0, dstY0, dstX1, dstY1,
2358 mask, filter);
2359 }
2360 #endif /* FEATURE_EXT_framebuffer_blit */
2361
2362 #if FEATURE_ARB_geometry_shader4
2363 void GLAPIENTRY
2364 _mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
2365 GLuint texture, GLint level)
2366 {
2367 GET_CURRENT_CONTEXT(ctx);
2368 _mesa_error(ctx, GL_INVALID_OPERATION,
2369 "glFramebufferTextureARB "
2370 "not implemented!");
2371 }
2372
2373 void GLAPIENTRY
2374 _mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
2375 GLuint texture, GLint level, GLenum face)
2376 {
2377 GET_CURRENT_CONTEXT(ctx);
2378 _mesa_error(ctx, GL_INVALID_OPERATION,
2379 "glFramebufferTextureFaceARB "
2380 "not implemented!");
2381 }
2382 #endif /* FEATURE_ARB_geometry_shader4 */