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