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