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