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