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