mesa: Make detach_renderbuffer available outside fbobject.c
[mesa.git] / src / mesa / main / fbobject.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5 * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * 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 #include <stdbool.h>
35
36 #include "buffers.h"
37 #include "context.h"
38 #include "enums.h"
39 #include "fbobject.h"
40 #include "formats.h"
41 #include "framebuffer.h"
42 #include "glformats.h"
43 #include "hash.h"
44 #include "macros.h"
45 #include "multisample.h"
46 #include "mtypes.h"
47 #include "renderbuffer.h"
48 #include "state.h"
49 #include "teximage.h"
50 #include "texobj.h"
51
52
53 /** Set this to 1 to debug/log glBlitFramebuffer() calls */
54 #define DEBUG_BLIT 0
55
56
57 /**
58 * Notes:
59 *
60 * None of the GL_EXT_framebuffer_object functions are compiled into
61 * display lists.
62 */
63
64
65
66 /*
67 * When glGenRender/FramebuffersEXT() is called we insert pointers to
68 * these placeholder objects into the hash table.
69 * Later, when the object ID is first bound, we replace the placeholder
70 * with the real frame/renderbuffer.
71 */
72 static struct gl_framebuffer DummyFramebuffer;
73 static struct gl_renderbuffer DummyRenderbuffer;
74
75 /* We bind this framebuffer when applications pass a NULL
76 * drawable/surface in make current. */
77 static struct gl_framebuffer IncompleteFramebuffer;
78
79
80 static void
81 delete_dummy_renderbuffer(struct gl_context *ctx, 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(struct gl_context *ctx)
95 {
96 _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
97 _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
98 _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex);
99 DummyFramebuffer.Delete = delete_dummy_framebuffer;
100 DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
101 IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
102 }
103
104 struct gl_framebuffer *
105 _mesa_get_incomplete_framebuffer(void)
106 {
107 return &IncompleteFramebuffer;
108 }
109
110 /**
111 * Helper routine for getting a gl_renderbuffer.
112 */
113 struct gl_renderbuffer *
114 _mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
115 {
116 struct gl_renderbuffer *rb;
117
118 if (id == 0)
119 return NULL;
120
121 rb = (struct gl_renderbuffer *)
122 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
123 return rb;
124 }
125
126
127 /**
128 * Helper routine for getting a gl_framebuffer.
129 */
130 struct gl_framebuffer *
131 _mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
132 {
133 struct gl_framebuffer *fb;
134
135 if (id == 0)
136 return NULL;
137
138 fb = (struct gl_framebuffer *)
139 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
140 return fb;
141 }
142
143
144 /**
145 * Mark the given framebuffer as invalid. This will force the
146 * test for framebuffer completeness to be done before the framebuffer
147 * is used.
148 */
149 static void
150 invalidate_framebuffer(struct gl_framebuffer *fb)
151 {
152 fb->_Status = 0; /* "indeterminate" */
153 }
154
155
156 /**
157 * Return the gl_framebuffer object which corresponds to the given
158 * framebuffer target, such as GL_DRAW_FRAMEBUFFER.
159 * Check support for GL_EXT_framebuffer_blit to determine if certain
160 * targets are legal.
161 * \return gl_framebuffer pointer or NULL if target is illegal
162 */
163 static struct gl_framebuffer *
164 get_framebuffer_target(struct gl_context *ctx, GLenum target)
165 {
166 bool have_fb_blit = _mesa_is_gles3(ctx) ||
167 (ctx->Extensions.EXT_framebuffer_blit && _mesa_is_desktop_gl(ctx));
168 switch (target) {
169 case GL_DRAW_FRAMEBUFFER:
170 return have_fb_blit ? ctx->DrawBuffer : NULL;
171 case GL_READ_FRAMEBUFFER:
172 return have_fb_blit ? ctx->ReadBuffer : NULL;
173 case GL_FRAMEBUFFER_EXT:
174 return ctx->DrawBuffer;
175 default:
176 return NULL;
177 }
178 }
179
180
181 /**
182 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
183 * gl_renderbuffer_attachment object.
184 * This function is only used for user-created FB objects, not the
185 * default / window-system FB object.
186 * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
187 * the depth buffer attachment point.
188 */
189 struct gl_renderbuffer_attachment *
190 _mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
191 GLenum attachment)
192 {
193 GLuint i;
194
195 assert(_mesa_is_user_fbo(fb));
196
197 switch (attachment) {
198 case GL_COLOR_ATTACHMENT0_EXT:
199 case GL_COLOR_ATTACHMENT1_EXT:
200 case GL_COLOR_ATTACHMENT2_EXT:
201 case GL_COLOR_ATTACHMENT3_EXT:
202 case GL_COLOR_ATTACHMENT4_EXT:
203 case GL_COLOR_ATTACHMENT5_EXT:
204 case GL_COLOR_ATTACHMENT6_EXT:
205 case GL_COLOR_ATTACHMENT7_EXT:
206 case GL_COLOR_ATTACHMENT8_EXT:
207 case GL_COLOR_ATTACHMENT9_EXT:
208 case GL_COLOR_ATTACHMENT10_EXT:
209 case GL_COLOR_ATTACHMENT11_EXT:
210 case GL_COLOR_ATTACHMENT12_EXT:
211 case GL_COLOR_ATTACHMENT13_EXT:
212 case GL_COLOR_ATTACHMENT14_EXT:
213 case GL_COLOR_ATTACHMENT15_EXT:
214 /* Only OpenGL ES 1.x forbids color attachments other than
215 * GL_COLOR_ATTACHMENT0. For all other APIs the limit set by the
216 * hardware is used.
217 */
218 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
219 if (i >= ctx->Const.MaxColorAttachments
220 || (i > 0 && ctx->API == API_OPENGLES)) {
221 return NULL;
222 }
223 return &fb->Attachment[BUFFER_COLOR0 + i];
224 case GL_DEPTH_STENCIL_ATTACHMENT:
225 if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
226 return NULL;
227 /* fall-through */
228 case GL_DEPTH_ATTACHMENT_EXT:
229 return &fb->Attachment[BUFFER_DEPTH];
230 case GL_STENCIL_ATTACHMENT_EXT:
231 return &fb->Attachment[BUFFER_STENCIL];
232 default:
233 return NULL;
234 }
235 }
236
237
238 /**
239 * As above, but only used for getting attachments of the default /
240 * window-system framebuffer (not user-created framebuffer objects).
241 */
242 static struct gl_renderbuffer_attachment *
243 _mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
244 GLenum attachment)
245 {
246 assert(_mesa_is_winsys_fbo(fb));
247
248 if (_mesa_is_gles3(ctx)) {
249 assert(attachment == GL_BACK ||
250 attachment == GL_DEPTH ||
251 attachment == GL_STENCIL);
252 switch (attachment) {
253 case GL_BACK:
254 /* Since there is no stereo rendering in ES 3.0, only return the
255 * LEFT bits.
256 */
257 if (ctx->DrawBuffer->Visual.doubleBufferMode)
258 return &fb->Attachment[BUFFER_BACK_LEFT];
259 return &fb->Attachment[BUFFER_FRONT_LEFT];
260 case GL_DEPTH:
261 return &fb->Attachment[BUFFER_DEPTH];
262 case GL_STENCIL:
263 return &fb->Attachment[BUFFER_STENCIL];
264 }
265 }
266
267 switch (attachment) {
268 case GL_FRONT_LEFT:
269 return &fb->Attachment[BUFFER_FRONT_LEFT];
270 case GL_FRONT_RIGHT:
271 return &fb->Attachment[BUFFER_FRONT_RIGHT];
272 case GL_BACK_LEFT:
273 return &fb->Attachment[BUFFER_BACK_LEFT];
274 case GL_BACK_RIGHT:
275 return &fb->Attachment[BUFFER_BACK_RIGHT];
276 case GL_AUX0:
277 if (fb->Visual.numAuxBuffers == 1) {
278 return &fb->Attachment[BUFFER_AUX0];
279 }
280 return NULL;
281
282 /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says:
283 *
284 * "If the default framebuffer is bound to target, then attachment must
285 * be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi,
286 * identifying a color buffer; DEPTH, identifying the depth buffer; or
287 * STENCIL, identifying the stencil buffer."
288 *
289 * Revision #34 of the ARB_framebuffer_object spec has essentially the same
290 * language. However, revision #33 of the ARB_framebuffer_object spec
291 * says:
292 *
293 * "If the default framebuffer is bound to <target>, then <attachment>
294 * must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi,
295 * DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the
296 * depth buffer, or the stencil buffer, and <pname> may be
297 * FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or
298 * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME."
299 *
300 * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed
301 * from glext.h, so shipping apps should not use those values.
302 *
303 * Note that neither EXT_framebuffer_object nor OES_framebuffer_object
304 * support queries of the window system FBO.
305 */
306 case GL_DEPTH:
307 return &fb->Attachment[BUFFER_DEPTH];
308 case GL_STENCIL:
309 return &fb->Attachment[BUFFER_STENCIL];
310 default:
311 return NULL;
312 }
313 }
314
315
316
317 /**
318 * Remove any texture or renderbuffer attached to the given attachment
319 * point. Update reference counts, etc.
320 */
321 void
322 _mesa_remove_attachment(struct gl_context *ctx,
323 struct gl_renderbuffer_attachment *att)
324 {
325 struct gl_renderbuffer *rb = att->Renderbuffer;
326
327 /* tell driver that we're done rendering to this texture. */
328 if (rb && rb->NeedsFinishRenderTexture)
329 ctx->Driver.FinishRenderTexture(ctx, rb);
330
331 if (att->Type == GL_TEXTURE) {
332 ASSERT(att->Texture);
333 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
334 ASSERT(!att->Texture);
335 }
336 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
337 ASSERT(!att->Texture);
338 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
339 ASSERT(!att->Renderbuffer);
340 }
341 att->Type = GL_NONE;
342 att->Complete = GL_TRUE;
343 }
344
345 /**
346 * Verify a couple error conditions that will lead to an incomplete FBO and
347 * may cause problems for the driver's RenderTexture path.
348 */
349 static bool
350 driver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att)
351 {
352 const struct gl_texture_image *const texImage =
353 att->Texture->Image[att->CubeMapFace][att->TextureLevel];
354
355 if (texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0)
356 return false;
357
358 if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY
359 && att->Zoffset >= texImage->Height)
360 || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY
361 && att->Zoffset >= texImage->Depth))
362 return false;
363
364 return true;
365 }
366
367 /**
368 * Create a renderbuffer which will be set up by the driver to wrap the
369 * texture image slice.
370 *
371 * By using a gl_renderbuffer (like user-allocated renderbuffers), drivers get
372 * to share most of their framebuffer rendering code between winsys,
373 * renderbuffer, and texture attachments.
374 *
375 * The allocated renderbuffer uses a non-zero Name so that drivers can check
376 * it for determining vertical orientation, but we use ~0 to make it fairly
377 * unambiguous with actual user (non-texture) renderbuffers.
378 */
379 void
380 _mesa_update_texture_renderbuffer(struct gl_context *ctx,
381 struct gl_framebuffer *fb,
382 struct gl_renderbuffer_attachment *att)
383 {
384 struct gl_texture_image *texImage;
385 struct gl_renderbuffer *rb;
386
387 texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
388
389 rb = att->Renderbuffer;
390 if (!rb) {
391 rb = ctx->Driver.NewRenderbuffer(ctx, ~0);
392 if (!rb) {
393 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()");
394 return;
395 }
396 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
397
398 /* This can't get called on a texture renderbuffer, so set it to NULL
399 * for clarity compared to user renderbuffers.
400 */
401 rb->AllocStorage = NULL;
402
403 rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL;
404 }
405
406 if (!texImage)
407 return;
408
409 rb->_BaseFormat = texImage->_BaseFormat;
410 rb->Format = texImage->TexFormat;
411 rb->InternalFormat = texImage->InternalFormat;
412 rb->Width = texImage->Width2;
413 rb->Height = texImage->Height2;
414 rb->NumSamples = texImage->NumSamples;
415 rb->TexImage = texImage;
416
417 if (driver_RenderTexture_is_safe(att))
418 ctx->Driver.RenderTexture(ctx, fb, att);
419 }
420
421 /**
422 * Bind a texture object to an attachment point.
423 * The previous binding, if any, will be removed first.
424 */
425 void
426 _mesa_set_texture_attachment(struct gl_context *ctx,
427 struct gl_framebuffer *fb,
428 struct gl_renderbuffer_attachment *att,
429 struct gl_texture_object *texObj,
430 GLenum texTarget, GLuint level, GLuint zoffset,
431 GLboolean layered)
432 {
433 struct gl_renderbuffer *rb = att->Renderbuffer;
434
435 if (rb && rb->NeedsFinishRenderTexture)
436 ctx->Driver.FinishRenderTexture(ctx, rb);
437
438 if (att->Texture == texObj) {
439 /* re-attaching same texture */
440 ASSERT(att->Type == GL_TEXTURE);
441 }
442 else {
443 /* new attachment */
444 _mesa_remove_attachment(ctx, att);
445 att->Type = GL_TEXTURE;
446 assert(!att->Texture);
447 _mesa_reference_texobj(&att->Texture, texObj);
448 }
449 invalidate_framebuffer(fb);
450
451 /* always update these fields */
452 att->TextureLevel = level;
453 att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
454 att->Zoffset = zoffset;
455 att->Layered = layered;
456 att->Complete = GL_FALSE;
457
458 _mesa_update_texture_renderbuffer(ctx, fb, att);
459 }
460
461
462 /**
463 * Bind a renderbuffer to an attachment point.
464 * The previous binding, if any, will be removed first.
465 */
466 void
467 _mesa_set_renderbuffer_attachment(struct gl_context *ctx,
468 struct gl_renderbuffer_attachment *att,
469 struct gl_renderbuffer *rb)
470 {
471 /* XXX check if re-doing same attachment, exit early */
472 _mesa_remove_attachment(ctx, att);
473 att->Type = GL_RENDERBUFFER_EXT;
474 att->Texture = NULL; /* just to be safe */
475 att->Complete = GL_FALSE;
476 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
477 }
478
479
480 /**
481 * Fallback for ctx->Driver.FramebufferRenderbuffer()
482 * Attach a renderbuffer object to a framebuffer object.
483 */
484 void
485 _mesa_framebuffer_renderbuffer(struct gl_context *ctx,
486 struct gl_framebuffer *fb,
487 GLenum attachment, struct gl_renderbuffer *rb)
488 {
489 struct gl_renderbuffer_attachment *att;
490
491 _glthread_LOCK_MUTEX(fb->Mutex);
492
493 att = _mesa_get_attachment(ctx, fb, attachment);
494 ASSERT(att);
495 if (rb) {
496 _mesa_set_renderbuffer_attachment(ctx, att, rb);
497 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
498 /* do stencil attachment here (depth already done above) */
499 att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
500 assert(att);
501 _mesa_set_renderbuffer_attachment(ctx, att, rb);
502 }
503 rb->AttachedAnytime = GL_TRUE;
504 }
505 else {
506 _mesa_remove_attachment(ctx, att);
507 }
508
509 invalidate_framebuffer(fb);
510
511 _glthread_UNLOCK_MUTEX(fb->Mutex);
512 }
513
514
515 /**
516 * Fallback for ctx->Driver.ValidateFramebuffer()
517 * Check if the renderbuffer's formats are supported by the software
518 * renderer.
519 * Drivers should probably override this.
520 */
521 void
522 _mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
523 {
524 gl_buffer_index buf;
525 for (buf = 0; buf < BUFFER_COUNT; buf++) {
526 const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer;
527 if (rb) {
528 switch (rb->_BaseFormat) {
529 case GL_ALPHA:
530 case GL_LUMINANCE_ALPHA:
531 case GL_LUMINANCE:
532 case GL_INTENSITY:
533 case GL_RED:
534 case GL_RG:
535 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
536 return;
537
538 default:
539 switch (rb->Format) {
540 /* XXX This list is likely incomplete. */
541 case MESA_FORMAT_RGB9_E5_FLOAT:
542 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
543 return;
544 default:;
545 /* render buffer format is supported by software rendering */
546 }
547 }
548 }
549 }
550 }
551
552
553 /**
554 * Return true if the framebuffer has a combined depth/stencil
555 * renderbuffer attached.
556 */
557 GLboolean
558 _mesa_has_depthstencil_combined(const struct gl_framebuffer *fb)
559 {
560 const struct gl_renderbuffer_attachment *depth =
561 &fb->Attachment[BUFFER_DEPTH];
562 const struct gl_renderbuffer_attachment *stencil =
563 &fb->Attachment[BUFFER_STENCIL];
564
565 if (depth->Type == stencil->Type) {
566 if (depth->Type == GL_RENDERBUFFER_EXT &&
567 depth->Renderbuffer == stencil->Renderbuffer)
568 return GL_TRUE;
569
570 if (depth->Type == GL_TEXTURE &&
571 depth->Texture == stencil->Texture)
572 return GL_TRUE;
573 }
574
575 return GL_FALSE;
576 }
577
578
579 /**
580 * For debug only.
581 */
582 static void
583 att_incomplete(const char *msg)
584 {
585 if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
586 _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
587 }
588 }
589
590
591 /**
592 * For debug only.
593 */
594 static void
595 fbo_incomplete(struct gl_context *ctx, const char *msg, int index)
596 {
597 static GLuint msg_id;
598
599 _mesa_gl_debug(ctx, &msg_id,
600 MESA_DEBUG_TYPE_OTHER,
601 MESA_DEBUG_SEVERITY_MEDIUM,
602 "FBO incomplete: %s [%d]\n", msg, index);
603
604 if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
605 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
606 }
607 }
608
609
610 /**
611 * Is the given base format a legal format for a color renderbuffer?
612 */
613 GLboolean
614 _mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
615 {
616 switch (baseFormat) {
617 case GL_RGB:
618 case GL_RGBA:
619 return GL_TRUE;
620 case GL_LUMINANCE:
621 case GL_LUMINANCE_ALPHA:
622 case GL_INTENSITY:
623 case GL_ALPHA:
624 return ctx->API == API_OPENGL_COMPAT &&
625 ctx->Extensions.ARB_framebuffer_object;
626 case GL_RED:
627 case GL_RG:
628 return ctx->Extensions.ARB_texture_rg;
629 default:
630 return GL_FALSE;
631 }
632 }
633
634
635 /**
636 * Is the given base format a legal format for a color renderbuffer?
637 */
638 static GLboolean
639 is_format_color_renderable(const struct gl_context *ctx, gl_format format, GLenum internalFormat)
640 {
641 const GLenum baseFormat =
642 _mesa_get_format_base_format(format);
643 GLboolean valid;
644
645 valid = _mesa_is_legal_color_format(ctx, baseFormat);
646 if (!valid || _mesa_is_desktop_gl(ctx)) {
647 return valid;
648 }
649
650 /* Reject additional cases for GLES */
651 switch (internalFormat) {
652 case GL_RGBA8_SNORM:
653 case GL_RGB32F:
654 case GL_RGB32I:
655 case GL_RGB32UI:
656 case GL_RGB16F:
657 case GL_RGB16I:
658 case GL_RGB16UI:
659 case GL_RGB8_SNORM:
660 case GL_RGB8I:
661 case GL_RGB8UI:
662 case GL_SRGB8:
663 case GL_RGB9_E5:
664 case GL_RG8_SNORM:
665 case GL_R8_SNORM:
666 return GL_FALSE;
667 default:
668 break;
669 }
670
671 if (format == MESA_FORMAT_ARGB2101010 && internalFormat != GL_RGB10_A2) {
672 return GL_FALSE;
673 }
674
675 return GL_TRUE;
676 }
677
678
679 /**
680 * Is the given base format a legal format for a depth/stencil renderbuffer?
681 */
682 static GLboolean
683 is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
684 {
685 switch (baseFormat) {
686 case GL_DEPTH_COMPONENT:
687 case GL_DEPTH_STENCIL_EXT:
688 return GL_TRUE;
689 default:
690 return GL_FALSE;
691 }
692 }
693
694
695 /**
696 * Test if an attachment point is complete and update its Complete field.
697 * \param format if GL_COLOR, this is a color attachment point,
698 * if GL_DEPTH, this is a depth component attachment point,
699 * if GL_STENCIL, this is a stencil component attachment point.
700 */
701 static void
702 test_attachment_completeness(const struct gl_context *ctx, GLenum format,
703 struct gl_renderbuffer_attachment *att)
704 {
705 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
706
707 /* assume complete */
708 att->Complete = GL_TRUE;
709
710 /* Look for reasons why the attachment might be incomplete */
711 if (att->Type == GL_TEXTURE) {
712 const struct gl_texture_object *texObj = att->Texture;
713 struct gl_texture_image *texImage;
714 GLenum baseFormat;
715
716 if (!texObj) {
717 att_incomplete("no texobj");
718 att->Complete = GL_FALSE;
719 return;
720 }
721
722 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
723 if (!texImage) {
724 att_incomplete("no teximage");
725 att->Complete = GL_FALSE;
726 return;
727 }
728 if (texImage->Width < 1 || texImage->Height < 1) {
729 att_incomplete("teximage width/height=0");
730 att->Complete = GL_FALSE;
731 return;
732 }
733
734 switch (texObj->Target) {
735 case GL_TEXTURE_3D:
736 if (att->Zoffset >= texImage->Depth) {
737 att_incomplete("bad z offset");
738 att->Complete = GL_FALSE;
739 return;
740 }
741 break;
742 case GL_TEXTURE_1D_ARRAY:
743 if (att->Zoffset >= texImage->Height) {
744 att_incomplete("bad 1D-array layer");
745 att->Complete = GL_FALSE;
746 return;
747 }
748 break;
749 case GL_TEXTURE_2D_ARRAY:
750 if (att->Zoffset >= texImage->Depth) {
751 att_incomplete("bad 2D-array layer");
752 att->Complete = GL_FALSE;
753 return;
754 }
755 break;
756 case GL_TEXTURE_CUBE_MAP_ARRAY:
757 if (att->Zoffset >= texImage->Depth) {
758 att_incomplete("bad cube-array layer");
759 att->Complete = GL_FALSE;
760 return;
761 }
762 break;
763 }
764
765 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
766
767 if (format == GL_COLOR) {
768 if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
769 att_incomplete("bad format");
770 att->Complete = GL_FALSE;
771 return;
772 }
773 if (_mesa_is_format_compressed(texImage->TexFormat)) {
774 att_incomplete("compressed internalformat");
775 att->Complete = GL_FALSE;
776 return;
777 }
778 }
779 else if (format == GL_DEPTH) {
780 if (baseFormat == GL_DEPTH_COMPONENT) {
781 /* OK */
782 }
783 else if (ctx->Extensions.EXT_packed_depth_stencil &&
784 ctx->Extensions.ARB_depth_texture &&
785 baseFormat == GL_DEPTH_STENCIL_EXT) {
786 /* OK */
787 }
788 else {
789 att->Complete = GL_FALSE;
790 att_incomplete("bad depth format");
791 return;
792 }
793 }
794 else {
795 ASSERT(format == GL_STENCIL);
796 if (ctx->Extensions.EXT_packed_depth_stencil &&
797 ctx->Extensions.ARB_depth_texture &&
798 baseFormat == GL_DEPTH_STENCIL_EXT) {
799 /* OK */
800 }
801 else {
802 /* no such thing as stencil-only textures */
803 att_incomplete("illegal stencil texture");
804 att->Complete = GL_FALSE;
805 return;
806 }
807 }
808 }
809 else if (att->Type == GL_RENDERBUFFER_EXT) {
810 const GLenum baseFormat =
811 _mesa_get_format_base_format(att->Renderbuffer->Format);
812
813 ASSERT(att->Renderbuffer);
814 if (!att->Renderbuffer->InternalFormat ||
815 att->Renderbuffer->Width < 1 ||
816 att->Renderbuffer->Height < 1) {
817 att_incomplete("0x0 renderbuffer");
818 att->Complete = GL_FALSE;
819 return;
820 }
821 if (format == GL_COLOR) {
822 if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
823 att_incomplete("bad renderbuffer color format");
824 att->Complete = GL_FALSE;
825 return;
826 }
827 }
828 else if (format == GL_DEPTH) {
829 if (baseFormat == GL_DEPTH_COMPONENT) {
830 /* OK */
831 }
832 else if (ctx->Extensions.EXT_packed_depth_stencil &&
833 baseFormat == GL_DEPTH_STENCIL_EXT) {
834 /* OK */
835 }
836 else {
837 att_incomplete("bad renderbuffer depth format");
838 att->Complete = GL_FALSE;
839 return;
840 }
841 }
842 else {
843 assert(format == GL_STENCIL);
844 if (baseFormat == GL_STENCIL_INDEX) {
845 /* OK */
846 }
847 else if (ctx->Extensions.EXT_packed_depth_stencil &&
848 baseFormat == GL_DEPTH_STENCIL_EXT) {
849 /* OK */
850 }
851 else {
852 att->Complete = GL_FALSE;
853 att_incomplete("bad renderbuffer stencil format");
854 return;
855 }
856 }
857 }
858 else {
859 ASSERT(att->Type == GL_NONE);
860 /* complete */
861 return;
862 }
863 }
864
865
866 /**
867 * Test if the given framebuffer object is complete and update its
868 * Status field with the results.
869 * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
870 * driver to make hardware-specific validation/completeness checks.
871 * Also update the framebuffer's Width and Height fields if the
872 * framebuffer is complete.
873 */
874 void
875 _mesa_test_framebuffer_completeness(struct gl_context *ctx,
876 struct gl_framebuffer *fb)
877 {
878 GLuint numImages;
879 GLenum intFormat = GL_NONE; /* color buffers' internal format */
880 GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
881 GLint numSamples = -1;
882 GLint fixedSampleLocations = -1;
883 GLint i;
884 GLuint j;
885 bool layer_count_valid = false;
886 GLuint layer_count = 0, att_layer_count;
887
888 assert(_mesa_is_user_fbo(fb));
889
890 /* we're changing framebuffer fields here */
891 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
892
893 numImages = 0;
894 fb->Width = 0;
895 fb->Height = 0;
896 fb->_AllColorBuffersFixedPoint = GL_TRUE;
897 fb->_HasSNormOrFloatColorBuffer = GL_FALSE;
898
899 /* Start at -2 to more easily loop over all attachment points.
900 * -2: depth buffer
901 * -1: stencil buffer
902 * >=0: color buffer
903 */
904 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
905 struct gl_renderbuffer_attachment *att;
906 GLenum f;
907 gl_format attFormat;
908
909 /*
910 * XXX for ARB_fbo, only check color buffers that are named by
911 * GL_READ_BUFFER and GL_DRAW_BUFFERi.
912 */
913
914 /* check for attachment completeness
915 */
916 if (i == -2) {
917 att = &fb->Attachment[BUFFER_DEPTH];
918 test_attachment_completeness(ctx, GL_DEPTH, att);
919 if (!att->Complete) {
920 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
921 fbo_incomplete(ctx, "depth attachment incomplete", -1);
922 return;
923 }
924 }
925 else if (i == -1) {
926 att = &fb->Attachment[BUFFER_STENCIL];
927 test_attachment_completeness(ctx, GL_STENCIL, att);
928 if (!att->Complete) {
929 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
930 fbo_incomplete(ctx, "stencil attachment incomplete", -1);
931 return;
932 }
933 }
934 else {
935 att = &fb->Attachment[BUFFER_COLOR0 + i];
936 test_attachment_completeness(ctx, GL_COLOR, att);
937 if (!att->Complete) {
938 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
939 fbo_incomplete(ctx, "color attachment incomplete", i);
940 return;
941 }
942 }
943
944 /* get width, height, format of the renderbuffer/texture
945 */
946 if (att->Type == GL_TEXTURE) {
947 const struct gl_texture_image *texImg = att->Renderbuffer->TexImage;
948 minWidth = MIN2(minWidth, texImg->Width);
949 maxWidth = MAX2(maxWidth, texImg->Width);
950 minHeight = MIN2(minHeight, texImg->Height);
951 maxHeight = MAX2(maxHeight, texImg->Height);
952 f = texImg->_BaseFormat;
953 attFormat = texImg->TexFormat;
954 numImages++;
955
956 if (!is_format_color_renderable(ctx, attFormat, texImg->InternalFormat) &&
957 !is_legal_depth_format(ctx, f)) {
958 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
959 fbo_incomplete(ctx, "texture attachment incomplete", -1);
960 return;
961 }
962
963 if (numSamples < 0)
964 numSamples = texImg->NumSamples;
965 else if (numSamples != texImg->NumSamples) {
966 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
967 fbo_incomplete(ctx, "inconsistent sample count", -1);
968 return;
969 }
970
971 if (fixedSampleLocations < 0)
972 fixedSampleLocations = texImg->FixedSampleLocations;
973 else if (fixedSampleLocations != texImg->FixedSampleLocations) {
974 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
975 fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
976 return;
977 }
978 }
979 else if (att->Type == GL_RENDERBUFFER_EXT) {
980 minWidth = MIN2(minWidth, att->Renderbuffer->Width);
981 maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
982 minHeight = MIN2(minHeight, att->Renderbuffer->Height);
983 maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
984 f = att->Renderbuffer->InternalFormat;
985 attFormat = att->Renderbuffer->Format;
986 numImages++;
987
988 if (numSamples < 0)
989 numSamples = att->Renderbuffer->NumSamples;
990 else if (numSamples != att->Renderbuffer->NumSamples) {
991 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
992 fbo_incomplete(ctx, "inconsistent sample count", -1);
993 return;
994 }
995
996 /* RENDERBUFFER has fixedSampleLocations implicitly true */
997 if (fixedSampleLocations < 0)
998 fixedSampleLocations = GL_TRUE;
999 else if (fixedSampleLocations != GL_TRUE) {
1000 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
1001 fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
1002 return;
1003 }
1004 }
1005 else {
1006 assert(att->Type == GL_NONE);
1007 continue;
1008 }
1009
1010 /* check if integer color */
1011 fb->_IntegerColor = _mesa_is_format_integer_color(attFormat);
1012
1013 /* Update _AllColorBuffersFixedPoint and _HasSNormOrFloatColorBuffer. */
1014 if (i >= 0) {
1015 GLenum type = _mesa_get_format_datatype(attFormat);
1016
1017 fb->_AllColorBuffersFixedPoint =
1018 fb->_AllColorBuffersFixedPoint &&
1019 (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED);
1020
1021 fb->_HasSNormOrFloatColorBuffer =
1022 fb->_HasSNormOrFloatColorBuffer ||
1023 type == GL_SIGNED_NORMALIZED || type == GL_FLOAT;
1024 }
1025
1026 /* Error-check width, height, format */
1027 if (numImages == 1) {
1028 /* save format */
1029 if (i >= 0) {
1030 intFormat = f;
1031 }
1032 }
1033 else {
1034 if (!ctx->Extensions.ARB_framebuffer_object) {
1035 /* check that width, height, format are same */
1036 if (minWidth != maxWidth || minHeight != maxHeight) {
1037 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
1038 fbo_incomplete(ctx, "width or height mismatch", -1);
1039 return;
1040 }
1041 /* check that all color buffers are the same format */
1042 if (intFormat != GL_NONE && f != intFormat) {
1043 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
1044 fbo_incomplete(ctx, "format mismatch", -1);
1045 return;
1046 }
1047 }
1048 }
1049
1050 /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported)
1051 */
1052 if (att->Type == GL_RENDERBUFFER &&
1053 att->Renderbuffer->Format == MESA_FORMAT_NONE) {
1054 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
1055 fbo_incomplete(ctx, "unsupported renderbuffer format", i);
1056 return;
1057 }
1058
1059 /* Check that layered rendering is consistent. */
1060 att_layer_count = att->Layered ? att->Renderbuffer->Depth : 0;
1061 if (!layer_count_valid) {
1062 layer_count = att_layer_count;
1063 layer_count_valid = true;
1064 } else if (layer_count != att_layer_count) {
1065 if (layer_count == 0 || att_layer_count == 0) {
1066 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS;
1067 fbo_incomplete(ctx, "framebuffer attachment layer mode is inconsistent", i);
1068 } else {
1069 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB;
1070 fbo_incomplete(ctx, "framebuffer attachment layer count is inconsistent", i);
1071 }
1072 return;
1073 }
1074 }
1075
1076 fb->Layered = layer_count > 0;
1077
1078 if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) {
1079 /* Check that all DrawBuffers are present */
1080 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
1081 if (fb->ColorDrawBuffer[j] != GL_NONE) {
1082 const struct gl_renderbuffer_attachment *att
1083 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
1084 assert(att);
1085 if (att->Type == GL_NONE) {
1086 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
1087 fbo_incomplete(ctx, "missing drawbuffer", j);
1088 return;
1089 }
1090 }
1091 }
1092
1093 /* Check that the ReadBuffer is present */
1094 if (fb->ColorReadBuffer != GL_NONE) {
1095 const struct gl_renderbuffer_attachment *att
1096 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
1097 assert(att);
1098 if (att->Type == GL_NONE) {
1099 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
1100 fbo_incomplete(ctx, "missing readbuffer", -1);
1101 return;
1102 }
1103 }
1104 }
1105
1106 if (numImages == 0) {
1107 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
1108 fbo_incomplete(ctx, "no attachments", -1);
1109 return;
1110 }
1111
1112 /* Provisionally set status = COMPLETE ... */
1113 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
1114
1115 /* ... but the driver may say the FB is incomplete.
1116 * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
1117 * if anything.
1118 */
1119 if (ctx->Driver.ValidateFramebuffer) {
1120 ctx->Driver.ValidateFramebuffer(ctx, fb);
1121 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1122 fbo_incomplete(ctx, "driver marked FBO as incomplete", -1);
1123 }
1124 }
1125
1126 if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
1127 /*
1128 * Note that if ARB_framebuffer_object is supported and the attached
1129 * renderbuffers/textures are different sizes, the framebuffer
1130 * width/height will be set to the smallest width/height.
1131 */
1132 fb->Width = minWidth;
1133 fb->Height = minHeight;
1134
1135 /* finally, update the visual info for the framebuffer */
1136 _mesa_update_framebuffer_visual(ctx, fb);
1137 }
1138 }
1139
1140
1141 GLboolean GLAPIENTRY
1142 _mesa_IsRenderbuffer(GLuint renderbuffer)
1143 {
1144 GET_CURRENT_CONTEXT(ctx);
1145 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1146 if (renderbuffer) {
1147 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
1148 if (rb != NULL && rb != &DummyRenderbuffer)
1149 return GL_TRUE;
1150 }
1151 return GL_FALSE;
1152 }
1153
1154
1155 static void
1156 bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names)
1157 {
1158 struct gl_renderbuffer *newRb;
1159 GET_CURRENT_CONTEXT(ctx);
1160
1161 if (target != GL_RENDERBUFFER_EXT) {
1162 _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
1163 return;
1164 }
1165
1166 /* No need to flush here since the render buffer binding has no
1167 * effect on rendering state.
1168 */
1169
1170 if (renderbuffer) {
1171 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
1172 if (newRb == &DummyRenderbuffer) {
1173 /* ID was reserved, but no real renderbuffer object made yet */
1174 newRb = NULL;
1175 }
1176 else if (!newRb && !allow_user_names) {
1177 /* All RB IDs must be Gen'd */
1178 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
1179 return;
1180 }
1181
1182 if (!newRb) {
1183 /* create new renderbuffer object */
1184 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
1185 if (!newRb) {
1186 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
1187 return;
1188 }
1189 ASSERT(newRb->AllocStorage);
1190 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
1191 newRb->RefCount = 1; /* referenced by hash table */
1192 }
1193 }
1194 else {
1195 newRb = NULL;
1196 }
1197
1198 ASSERT(newRb != &DummyRenderbuffer);
1199
1200 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
1201 }
1202
1203 void GLAPIENTRY
1204 _mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
1205 {
1206 GET_CURRENT_CONTEXT(ctx);
1207
1208 /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same
1209 * entry point, but they allow the use of user-generated names.
1210 */
1211 bind_renderbuffer(target, renderbuffer, _mesa_is_gles(ctx));
1212 }
1213
1214 void GLAPIENTRY
1215 _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
1216 {
1217 /* This function should not be in the dispatch table for core profile /
1218 * OpenGL 3.1, so execution should never get here in those cases -- no
1219 * need for an explicit test.
1220 */
1221 bind_renderbuffer(target, renderbuffer, true);
1222 }
1223
1224
1225 /**
1226 * If the given renderbuffer is anywhere attached to the framebuffer, detach
1227 * the renderbuffer.
1228 * This is used when a renderbuffer object is deleted.
1229 * The spec calls for unbinding.
1230 *
1231 * \returns
1232 * \c true if the renderbuffer was detached from an attachment point. \c
1233 * false otherwise.
1234 */
1235 bool
1236 _mesa_detach_renderbuffer(struct gl_context *ctx,
1237 struct gl_framebuffer *fb,
1238 const void *att)
1239 {
1240 unsigned i;
1241 bool progress = false;
1242
1243 for (i = 0; i < BUFFER_COUNT; i++) {
1244 if (fb->Attachment[i].Renderbuffer == att) {
1245 _mesa_remove_attachment(ctx, &fb->Attachment[i]);
1246 progress = true;
1247 }
1248 }
1249
1250 /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer
1251 * Completeness," of the OpenGL 3.1 spec says:
1252 *
1253 * "Performing any of the following actions may change whether the
1254 * framebuffer is considered complete or incomplete:
1255 *
1256 * ...
1257 *
1258 * - Deleting, with DeleteTextures or DeleteRenderbuffers, an object
1259 * containing an image that is attached to a framebuffer object
1260 * that is bound to the framebuffer."
1261 */
1262 if (progress)
1263 invalidate_framebuffer(fb);
1264
1265 return progress;
1266 }
1267
1268
1269 void GLAPIENTRY
1270 _mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers)
1271 {
1272 GLint i;
1273 GET_CURRENT_CONTEXT(ctx);
1274
1275 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1276
1277 for (i = 0; i < n; i++) {
1278 if (renderbuffers[i] > 0) {
1279 struct gl_renderbuffer *rb;
1280 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
1281 if (rb) {
1282 /* check if deleting currently bound renderbuffer object */
1283 if (rb == ctx->CurrentRenderbuffer) {
1284 /* bind default */
1285 ASSERT(rb->RefCount >= 2);
1286 _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
1287 }
1288
1289 if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
1290 _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
1291 }
1292 if (_mesa_is_user_fbo(ctx->ReadBuffer)
1293 && ctx->ReadBuffer != ctx->DrawBuffer) {
1294 _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
1295 }
1296
1297 /* Remove from hash table immediately, to free the ID.
1298 * But the object will not be freed until it's no longer
1299 * referenced anywhere else.
1300 */
1301 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
1302
1303 if (rb != &DummyRenderbuffer) {
1304 /* no longer referenced by hash table */
1305 _mesa_reference_renderbuffer(&rb, NULL);
1306 }
1307 }
1308 }
1309 }
1310 }
1311
1312
1313 void GLAPIENTRY
1314 _mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers)
1315 {
1316 GET_CURRENT_CONTEXT(ctx);
1317 GLuint first;
1318 GLint i;
1319
1320 if (n < 0) {
1321 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
1322 return;
1323 }
1324
1325 if (!renderbuffers)
1326 return;
1327
1328 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
1329
1330 for (i = 0; i < n; i++) {
1331 GLuint name = first + i;
1332 renderbuffers[i] = name;
1333 /* insert dummy placeholder into hash table */
1334 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
1335 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
1336 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1337 }
1338 }
1339
1340
1341 /**
1342 * Given an internal format token for a render buffer, return the
1343 * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
1344 * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE,
1345 * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc).
1346 *
1347 * This is similar to _mesa_base_tex_format() but the set of valid
1348 * internal formats is different.
1349 *
1350 * Note that even if a format is determined to be legal here, validation
1351 * of the FBO may fail if the format is not supported by the driver/GPU.
1352 *
1353 * \param internalFormat as passed to glRenderbufferStorage()
1354 * \return the base internal format, or 0 if internalFormat is illegal
1355 */
1356 GLenum
1357 _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
1358 {
1359 /*
1360 * Notes: some formats such as alpha, luminance, etc. were added
1361 * with GL_ARB_framebuffer_object.
1362 */
1363 switch (internalFormat) {
1364 case GL_ALPHA:
1365 case GL_ALPHA4:
1366 case GL_ALPHA8:
1367 case GL_ALPHA12:
1368 case GL_ALPHA16:
1369 return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object
1370 ? GL_ALPHA : 0;
1371 case GL_LUMINANCE:
1372 case GL_LUMINANCE4:
1373 case GL_LUMINANCE8:
1374 case GL_LUMINANCE12:
1375 case GL_LUMINANCE16:
1376 return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object
1377 ? GL_LUMINANCE : 0;
1378 case GL_LUMINANCE_ALPHA:
1379 case GL_LUMINANCE4_ALPHA4:
1380 case GL_LUMINANCE6_ALPHA2:
1381 case GL_LUMINANCE8_ALPHA8:
1382 case GL_LUMINANCE12_ALPHA4:
1383 case GL_LUMINANCE12_ALPHA12:
1384 case GL_LUMINANCE16_ALPHA16:
1385 return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object
1386 ? GL_LUMINANCE_ALPHA : 0;
1387 case GL_INTENSITY:
1388 case GL_INTENSITY4:
1389 case GL_INTENSITY8:
1390 case GL_INTENSITY12:
1391 case GL_INTENSITY16:
1392 return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object
1393 ? GL_INTENSITY : 0;
1394 case GL_RGB8:
1395 return GL_RGB;
1396 case GL_RGB:
1397 case GL_R3_G3_B2:
1398 case GL_RGB4:
1399 case GL_RGB5:
1400 case GL_RGB10:
1401 case GL_RGB12:
1402 case GL_RGB16:
1403 return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0;
1404 case GL_SRGB8_EXT:
1405 return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0;
1406 case GL_RGBA4:
1407 case GL_RGB5_A1:
1408 case GL_RGBA8:
1409 return GL_RGBA;
1410 case GL_RGBA:
1411 case GL_RGBA2:
1412 case GL_RGBA12:
1413 case GL_RGBA16:
1414 return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0;
1415 case GL_RGB10_A2:
1416 case GL_SRGB8_ALPHA8_EXT:
1417 return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0;
1418 case GL_STENCIL_INDEX:
1419 case GL_STENCIL_INDEX1_EXT:
1420 case GL_STENCIL_INDEX4_EXT:
1421 case GL_STENCIL_INDEX16_EXT:
1422 /* There are extensions for GL_STENCIL_INDEX1 and GL_STENCIL_INDEX4 in
1423 * OpenGL ES, but Mesa does not currently support them.
1424 */
1425 return _mesa_is_desktop_gl(ctx) ? GL_STENCIL_INDEX : 0;
1426 case GL_STENCIL_INDEX8_EXT:
1427 return GL_STENCIL_INDEX;
1428 case GL_DEPTH_COMPONENT:
1429 case GL_DEPTH_COMPONENT32:
1430 return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_COMPONENT : 0;
1431 case GL_DEPTH_COMPONENT16:
1432 case GL_DEPTH_COMPONENT24:
1433 return GL_DEPTH_COMPONENT;
1434 case GL_DEPTH_STENCIL_EXT:
1435 return _mesa_is_desktop_gl(ctx)
1436 && ctx->Extensions.EXT_packed_depth_stencil
1437 ? GL_DEPTH_STENCIL_EXT : 0;
1438 case GL_DEPTH24_STENCIL8_EXT:
1439 return ctx->Extensions.EXT_packed_depth_stencil
1440 ? GL_DEPTH_STENCIL_EXT : 0;
1441 case GL_DEPTH_COMPONENT32F:
1442 return ctx->Version >= 30
1443 || (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_depth_buffer_float)
1444 ? GL_DEPTH_COMPONENT : 0;
1445 case GL_DEPTH32F_STENCIL8:
1446 return ctx->Version >= 30
1447 || (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_depth_buffer_float)
1448 ? GL_DEPTH_STENCIL : 0;
1449 case GL_RED:
1450 case GL_R16:
1451 return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg
1452 ? GL_RED : 0;
1453 case GL_R8:
1454 return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
1455 ? GL_RED : 0;
1456 case GL_RG:
1457 case GL_RG16:
1458 return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg
1459 ? GL_RG : 0;
1460 case GL_RG8:
1461 return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
1462 ? GL_RG : 0;
1463 /* signed normalized texture formats */
1464 case GL_RED_SNORM:
1465 case GL_R8_SNORM:
1466 case GL_R16_SNORM:
1467 return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1468 ? GL_RED : 0;
1469 case GL_RG_SNORM:
1470 case GL_RG8_SNORM:
1471 case GL_RG16_SNORM:
1472 return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1473 ? GL_RG : 0;
1474 case GL_RGB_SNORM:
1475 case GL_RGB8_SNORM:
1476 case GL_RGB16_SNORM:
1477 return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1478 ? GL_RGB : 0;
1479 case GL_RGBA_SNORM:
1480 case GL_RGBA8_SNORM:
1481 case GL_RGBA16_SNORM:
1482 return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
1483 ? GL_RGBA : 0;
1484 case GL_ALPHA_SNORM:
1485 case GL_ALPHA8_SNORM:
1486 case GL_ALPHA16_SNORM:
1487 return ctx->API == API_OPENGL_COMPAT &&
1488 ctx->Extensions.EXT_texture_snorm &&
1489 ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1490 case GL_R16F:
1491 case GL_R32F:
1492 return ((_mesa_is_desktop_gl(ctx) &&
1493 ctx->Extensions.ARB_texture_rg &&
1494 ctx->Extensions.ARB_texture_float) ||
1495 _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
1496 ? GL_RED : 0;
1497 case GL_RG16F:
1498 case GL_RG32F:
1499 return ((_mesa_is_desktop_gl(ctx) &&
1500 ctx->Extensions.ARB_texture_rg &&
1501 ctx->Extensions.ARB_texture_float) ||
1502 _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
1503 ? GL_RG : 0;
1504 case GL_RGB16F:
1505 case GL_RGB32F:
1506 return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float)
1507 ? GL_RGB : 0;
1508 case GL_RGBA16F:
1509 case GL_RGBA32F:
1510 return ((_mesa_is_desktop_gl(ctx) &&
1511 ctx->Extensions.ARB_texture_float) ||
1512 _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
1513 ? GL_RGBA : 0;
1514 case GL_ALPHA16F_ARB:
1515 case GL_ALPHA32F_ARB:
1516 return ctx->API == API_OPENGL_COMPAT &&
1517 ctx->Extensions.ARB_texture_float &&
1518 ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1519 case GL_LUMINANCE16F_ARB:
1520 case GL_LUMINANCE32F_ARB:
1521 return ctx->API == API_OPENGL_COMPAT &&
1522 ctx->Extensions.ARB_texture_float &&
1523 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1524 case GL_LUMINANCE_ALPHA16F_ARB:
1525 case GL_LUMINANCE_ALPHA32F_ARB:
1526 return ctx->API == API_OPENGL_COMPAT &&
1527 ctx->Extensions.ARB_texture_float &&
1528 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
1529 case GL_INTENSITY16F_ARB:
1530 case GL_INTENSITY32F_ARB:
1531 return ctx->API == API_OPENGL_COMPAT &&
1532 ctx->Extensions.ARB_texture_float &&
1533 ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
1534 case GL_RGB9_E5:
1535 return (_mesa_is_desktop_gl(ctx)
1536 && ctx->Extensions.EXT_texture_shared_exponent)
1537 ? GL_RGB : 0;
1538 case GL_R11F_G11F_B10F:
1539 return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) ||
1540 _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
1541 ? GL_RGB : 0;
1542
1543 case GL_RGBA8UI_EXT:
1544 case GL_RGBA16UI_EXT:
1545 case GL_RGBA32UI_EXT:
1546 case GL_RGBA8I_EXT:
1547 case GL_RGBA16I_EXT:
1548 case GL_RGBA32I_EXT:
1549 return ctx->Version >= 30
1550 || (_mesa_is_desktop_gl(ctx) &&
1551 ctx->Extensions.EXT_texture_integer) ? GL_RGBA : 0;
1552
1553 case GL_RGB8UI_EXT:
1554 case GL_RGB16UI_EXT:
1555 case GL_RGB32UI_EXT:
1556 case GL_RGB8I_EXT:
1557 case GL_RGB16I_EXT:
1558 case GL_RGB32I_EXT:
1559 return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_integer
1560 ? GL_RGB : 0;
1561 case GL_R8UI:
1562 case GL_R8I:
1563 case GL_R16UI:
1564 case GL_R16I:
1565 case GL_R32UI:
1566 case GL_R32I:
1567 return ctx->Version >= 30
1568 || (_mesa_is_desktop_gl(ctx) &&
1569 ctx->Extensions.ARB_texture_rg &&
1570 ctx->Extensions.EXT_texture_integer) ? GL_RED : 0;
1571
1572 case GL_RG8UI:
1573 case GL_RG8I:
1574 case GL_RG16UI:
1575 case GL_RG16I:
1576 case GL_RG32UI:
1577 case GL_RG32I:
1578 return ctx->Version >= 30
1579 || (_mesa_is_desktop_gl(ctx) &&
1580 ctx->Extensions.ARB_texture_rg &&
1581 ctx->Extensions.EXT_texture_integer) ? GL_RG : 0;
1582
1583 case GL_INTENSITY8I_EXT:
1584 case GL_INTENSITY8UI_EXT:
1585 case GL_INTENSITY16I_EXT:
1586 case GL_INTENSITY16UI_EXT:
1587 case GL_INTENSITY32I_EXT:
1588 case GL_INTENSITY32UI_EXT:
1589 return ctx->API == API_OPENGL_COMPAT &&
1590 ctx->Extensions.EXT_texture_integer &&
1591 ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
1592
1593 case GL_LUMINANCE8I_EXT:
1594 case GL_LUMINANCE8UI_EXT:
1595 case GL_LUMINANCE16I_EXT:
1596 case GL_LUMINANCE16UI_EXT:
1597 case GL_LUMINANCE32I_EXT:
1598 case GL_LUMINANCE32UI_EXT:
1599 return ctx->API == API_OPENGL_COMPAT &&
1600 ctx->Extensions.EXT_texture_integer &&
1601 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
1602
1603 case GL_LUMINANCE_ALPHA8I_EXT:
1604 case GL_LUMINANCE_ALPHA8UI_EXT:
1605 case GL_LUMINANCE_ALPHA16I_EXT:
1606 case GL_LUMINANCE_ALPHA16UI_EXT:
1607 case GL_LUMINANCE_ALPHA32I_EXT:
1608 case GL_LUMINANCE_ALPHA32UI_EXT:
1609 return ctx->API == API_OPENGL_COMPAT &&
1610 ctx->Extensions.EXT_texture_integer &&
1611 ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
1612
1613 case GL_ALPHA8I_EXT:
1614 case GL_ALPHA8UI_EXT:
1615 case GL_ALPHA16I_EXT:
1616 case GL_ALPHA16UI_EXT:
1617 case GL_ALPHA32I_EXT:
1618 case GL_ALPHA32UI_EXT:
1619 return ctx->API == API_OPENGL_COMPAT &&
1620 ctx->Extensions.EXT_texture_integer &&
1621 ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
1622
1623 case GL_RGB10_A2UI:
1624 return (_mesa_is_desktop_gl(ctx) &&
1625 ctx->Extensions.ARB_texture_rgb10_a2ui)
1626 || _mesa_is_gles3(ctx) ? GL_RGBA : 0;
1627
1628 case GL_RGB565:
1629 return _mesa_is_gles(ctx) || ctx->Extensions.ARB_ES2_compatibility
1630 ? GL_RGB : 0;
1631 default:
1632 return 0;
1633 }
1634 }
1635
1636
1637 /**
1638 * Invalidate a renderbuffer attachment. Called from _mesa_HashWalk().
1639 */
1640 static void
1641 invalidate_rb(GLuint key, void *data, void *userData)
1642 {
1643 struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
1644 struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData;
1645
1646 /* If this is a user-created FBO */
1647 if (_mesa_is_user_fbo(fb)) {
1648 GLuint i;
1649 for (i = 0; i < BUFFER_COUNT; i++) {
1650 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1651 if (att->Type == GL_RENDERBUFFER &&
1652 att->Renderbuffer == rb) {
1653 /* Mark fb status as indeterminate to force re-validation */
1654 fb->_Status = 0;
1655 return;
1656 }
1657 }
1658 }
1659 }
1660
1661
1662 /** sentinal value, see below */
1663 #define NO_SAMPLES 1000
1664
1665
1666 /**
1667 * Helper function used by _mesa_RenderbufferStorage() and
1668 * _mesa_RenderbufferStorageMultisample().
1669 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorage().
1670 */
1671 static void
1672 renderbuffer_storage(GLenum target, GLenum internalFormat,
1673 GLsizei width, GLsizei height, GLsizei samples)
1674 {
1675 const char *func = samples == NO_SAMPLES ?
1676 "glRenderbufferStorage" : "glRenderbufferStorageMultisample";
1677 struct gl_renderbuffer *rb;
1678 GLenum baseFormat;
1679 GLenum sample_count_error;
1680 GET_CURRENT_CONTEXT(ctx);
1681
1682 if (MESA_VERBOSE & VERBOSE_API) {
1683 if (samples == NO_SAMPLES)
1684 _mesa_debug(ctx, "%s(%s, %s, %d, %d)\n",
1685 func,
1686 _mesa_lookup_enum_by_nr(target),
1687 _mesa_lookup_enum_by_nr(internalFormat),
1688 width, height);
1689 else
1690 _mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n",
1691 func,
1692 _mesa_lookup_enum_by_nr(target),
1693 _mesa_lookup_enum_by_nr(internalFormat),
1694 width, height, samples);
1695 }
1696
1697 if (target != GL_RENDERBUFFER_EXT) {
1698 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
1699 return;
1700 }
1701
1702 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
1703 if (baseFormat == 0) {
1704 _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)",
1705 func, _mesa_lookup_enum_by_nr(internalFormat));
1706 return;
1707 }
1708
1709 if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
1710 _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
1711 return;
1712 }
1713
1714 if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
1715 _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
1716 return;
1717 }
1718
1719 if (samples == NO_SAMPLES) {
1720 /* NumSamples == 0 indicates non-multisampling */
1721 samples = 0;
1722 }
1723 else {
1724 /* check the sample count;
1725 * note: driver may choose to use more samples than what's requested
1726 */
1727 sample_count_error = _mesa_check_sample_count(ctx, target,
1728 internalFormat, samples);
1729 if (sample_count_error != GL_NO_ERROR) {
1730 _mesa_error(ctx, sample_count_error, "%s(samples)", func);
1731 return;
1732 }
1733 }
1734
1735 rb = ctx->CurrentRenderbuffer;
1736 if (!rb) {
1737 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
1738 return;
1739 }
1740
1741 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1742
1743 if (rb->InternalFormat == internalFormat &&
1744 rb->Width == (GLuint) width &&
1745 rb->Height == (GLuint) height &&
1746 rb->NumSamples == samples) {
1747 /* no change in allocation needed */
1748 return;
1749 }
1750
1751 /* These MUST get set by the AllocStorage func */
1752 rb->Format = MESA_FORMAT_NONE;
1753 rb->NumSamples = samples;
1754
1755 /* Now allocate the storage */
1756 ASSERT(rb->AllocStorage);
1757 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
1758 /* No error - check/set fields now */
1759 /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */
1760 assert(rb->Width == (GLuint) width);
1761 assert(rb->Height == (GLuint) height);
1762 rb->InternalFormat = internalFormat;
1763 rb->_BaseFormat = baseFormat;
1764 assert(rb->_BaseFormat != 0);
1765 }
1766 else {
1767 /* Probably ran out of memory - clear the fields */
1768 rb->Width = 0;
1769 rb->Height = 0;
1770 rb->Format = MESA_FORMAT_NONE;
1771 rb->InternalFormat = GL_NONE;
1772 rb->_BaseFormat = GL_NONE;
1773 rb->NumSamples = 0;
1774 }
1775
1776 /* Invalidate the framebuffers the renderbuffer is attached in. */
1777 if (rb->AttachedAnytime) {
1778 _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb);
1779 }
1780 }
1781
1782
1783 void GLAPIENTRY
1784 _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1785 {
1786 struct gl_renderbuffer *rb;
1787 GET_CURRENT_CONTEXT(ctx);
1788
1789 if (!ctx->Extensions.OES_EGL_image) {
1790 _mesa_error(ctx, GL_INVALID_OPERATION,
1791 "glEGLImageTargetRenderbufferStorageOES(unsupported)");
1792 return;
1793 }
1794
1795 if (target != GL_RENDERBUFFER) {
1796 _mesa_error(ctx, GL_INVALID_ENUM,
1797 "EGLImageTargetRenderbufferStorageOES");
1798 return;
1799 }
1800
1801 rb = ctx->CurrentRenderbuffer;
1802 if (!rb) {
1803 _mesa_error(ctx, GL_INVALID_OPERATION,
1804 "EGLImageTargetRenderbufferStorageOES");
1805 return;
1806 }
1807
1808 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1809
1810 ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1811 }
1812
1813
1814 /**
1815 * Helper function for _mesa_GetRenderbufferParameteriv() and
1816 * _mesa_GetFramebufferAttachmentParameteriv()
1817 * We have to be careful to respect the base format. For example, if a
1818 * renderbuffer/texture was created with internalFormat=GL_RGB but the
1819 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
1820 * we need to return zero.
1821 */
1822 static GLint
1823 get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
1824 {
1825 if (_mesa_base_format_has_channel(baseFormat, pname))
1826 return _mesa_get_format_bits(format, pname);
1827 else
1828 return 0;
1829 }
1830
1831
1832
1833 void GLAPIENTRY
1834 _mesa_RenderbufferStorage(GLenum target, GLenum internalFormat,
1835 GLsizei width, GLsizei height)
1836 {
1837 /* GL_ARB_fbo says calling this function is equivalent to calling
1838 * glRenderbufferStorageMultisample() with samples=0. We pass in
1839 * a token value here just for error reporting purposes.
1840 */
1841 renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
1842 }
1843
1844
1845 void GLAPIENTRY
1846 _mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
1847 GLenum internalFormat,
1848 GLsizei width, GLsizei height)
1849 {
1850 renderbuffer_storage(target, internalFormat, width, height, samples);
1851 }
1852
1853
1854 /**
1855 * OpenGL ES version of glRenderBufferStorage.
1856 */
1857 void GLAPIENTRY
1858 _es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1859 GLsizei width, GLsizei height)
1860 {
1861 switch (internalFormat) {
1862 case GL_RGB565:
1863 /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
1864 /* choose a closest format */
1865 internalFormat = GL_RGB5;
1866 break;
1867 default:
1868 break;
1869 }
1870
1871 renderbuffer_storage(target, internalFormat, width, height, 0);
1872 }
1873
1874
1875 void GLAPIENTRY
1876 _mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params)
1877 {
1878 struct gl_renderbuffer *rb;
1879 GET_CURRENT_CONTEXT(ctx);
1880
1881 if (target != GL_RENDERBUFFER_EXT) {
1882 _mesa_error(ctx, GL_INVALID_ENUM,
1883 "glGetRenderbufferParameterivEXT(target)");
1884 return;
1885 }
1886
1887 rb = ctx->CurrentRenderbuffer;
1888 if (!rb) {
1889 _mesa_error(ctx, GL_INVALID_OPERATION,
1890 "glGetRenderbufferParameterivEXT");
1891 return;
1892 }
1893
1894 /* No need to flush here since we're just quering state which is
1895 * not effected by rendering.
1896 */
1897
1898 switch (pname) {
1899 case GL_RENDERBUFFER_WIDTH_EXT:
1900 *params = rb->Width;
1901 return;
1902 case GL_RENDERBUFFER_HEIGHT_EXT:
1903 *params = rb->Height;
1904 return;
1905 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
1906 *params = rb->InternalFormat;
1907 return;
1908 case GL_RENDERBUFFER_RED_SIZE_EXT:
1909 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1910 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1911 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1912 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1913 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1914 *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
1915 break;
1916 case GL_RENDERBUFFER_SAMPLES:
1917 if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object)
1918 || _mesa_is_gles3(ctx)) {
1919 *params = rb->NumSamples;
1920 break;
1921 }
1922 /* fallthrough */
1923 default:
1924 _mesa_error(ctx, GL_INVALID_ENUM,
1925 "glGetRenderbufferParameterivEXT(target)");
1926 return;
1927 }
1928 }
1929
1930
1931 GLboolean GLAPIENTRY
1932 _mesa_IsFramebuffer(GLuint framebuffer)
1933 {
1934 GET_CURRENT_CONTEXT(ctx);
1935 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1936 if (framebuffer) {
1937 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
1938 if (rb != NULL && rb != &DummyFramebuffer)
1939 return GL_TRUE;
1940 }
1941 return GL_FALSE;
1942 }
1943
1944
1945 /**
1946 * Check if any of the attachments of the given framebuffer are textures
1947 * (render to texture). Call ctx->Driver.RenderTexture() for such
1948 * attachments.
1949 */
1950 static void
1951 check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
1952 {
1953 GLuint i;
1954 ASSERT(ctx->Driver.RenderTexture);
1955
1956 if (_mesa_is_winsys_fbo(fb))
1957 return; /* can't render to texture with winsys framebuffers */
1958
1959 for (i = 0; i < BUFFER_COUNT; i++) {
1960 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1961 if (att->Texture && att->Renderbuffer->TexImage
1962 && driver_RenderTexture_is_safe(att)) {
1963 ctx->Driver.RenderTexture(ctx, fb, att);
1964 }
1965 }
1966 }
1967
1968
1969 /**
1970 * Examine all the framebuffer's attachments to see if any are textures.
1971 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
1972 * notify the device driver that the texture image may have changed.
1973 */
1974 static void
1975 check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
1976 {
1977 if (_mesa_is_winsys_fbo(fb))
1978 return; /* can't render to texture with winsys framebuffers */
1979
1980 if (ctx->Driver.FinishRenderTexture) {
1981 GLuint i;
1982 for (i = 0; i < BUFFER_COUNT; i++) {
1983 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1984 struct gl_renderbuffer *rb = att->Renderbuffer;
1985 if (rb && rb->NeedsFinishRenderTexture) {
1986 ctx->Driver.FinishRenderTexture(ctx, rb);
1987 }
1988 }
1989 }
1990 }
1991
1992
1993 static void
1994 bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names)
1995 {
1996 struct gl_framebuffer *newDrawFb, *newReadFb;
1997 struct gl_framebuffer *oldDrawFb, *oldReadFb;
1998 GLboolean bindReadBuf, bindDrawBuf;
1999 GET_CURRENT_CONTEXT(ctx);
2000
2001 #ifdef DEBUG
2002 if (ctx->Extensions.ARB_framebuffer_object) {
2003 ASSERT(ctx->Extensions.EXT_framebuffer_blit);
2004 }
2005 #endif
2006
2007 switch (target) {
2008 case GL_DRAW_FRAMEBUFFER_EXT:
2009 if (!ctx->Extensions.EXT_framebuffer_blit) {
2010 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
2011 return;
2012 }
2013 bindDrawBuf = GL_TRUE;
2014 bindReadBuf = GL_FALSE;
2015 break;
2016 case GL_READ_FRAMEBUFFER_EXT:
2017 if (!ctx->Extensions.EXT_framebuffer_blit) {
2018 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
2019 return;
2020 }
2021 bindDrawBuf = GL_FALSE;
2022 bindReadBuf = GL_TRUE;
2023 break;
2024 case GL_FRAMEBUFFER_EXT:
2025 bindDrawBuf = GL_TRUE;
2026 bindReadBuf = GL_TRUE;
2027 break;
2028 default:
2029 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
2030 return;
2031 }
2032
2033 if (framebuffer) {
2034 /* Binding a user-created framebuffer object */
2035 newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
2036 if (newDrawFb == &DummyFramebuffer) {
2037 /* ID was reserved, but no real framebuffer object made yet */
2038 newDrawFb = NULL;
2039 }
2040 else if (!newDrawFb && !allow_user_names) {
2041 /* All FBO IDs must be Gen'd */
2042 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
2043 return;
2044 }
2045
2046 if (!newDrawFb) {
2047 /* create new framebuffer object */
2048 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
2049 if (!newDrawFb) {
2050 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
2051 return;
2052 }
2053 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
2054 }
2055 newReadFb = newDrawFb;
2056 }
2057 else {
2058 /* Binding the window system framebuffer (which was originally set
2059 * with MakeCurrent).
2060 */
2061 newDrawFb = ctx->WinSysDrawBuffer;
2062 newReadFb = ctx->WinSysReadBuffer;
2063 }
2064
2065 ASSERT(newDrawFb);
2066 ASSERT(newDrawFb != &DummyFramebuffer);
2067
2068 /* save pointers to current/old framebuffers */
2069 oldDrawFb = ctx->DrawBuffer;
2070 oldReadFb = ctx->ReadBuffer;
2071
2072 /* check if really changing bindings */
2073 if (oldDrawFb == newDrawFb)
2074 bindDrawBuf = GL_FALSE;
2075 if (oldReadFb == newReadFb)
2076 bindReadBuf = GL_FALSE;
2077
2078 /*
2079 * OK, now bind the new Draw/Read framebuffers, if they're changing.
2080 *
2081 * We also check if we're beginning and/or ending render-to-texture.
2082 * When a framebuffer with texture attachments is unbound, call
2083 * ctx->Driver.FinishRenderTexture().
2084 * When a framebuffer with texture attachments is bound, call
2085 * ctx->Driver.RenderTexture().
2086 *
2087 * Note that if the ReadBuffer has texture attachments we don't consider
2088 * that a render-to-texture case.
2089 */
2090 if (bindReadBuf) {
2091 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2092
2093 /* check if old readbuffer was render-to-texture */
2094 check_end_texture_render(ctx, oldReadFb);
2095
2096 _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
2097 }
2098
2099 if (bindDrawBuf) {
2100 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2101
2102 /* check if old framebuffer had any texture attachments */
2103 if (oldDrawFb)
2104 check_end_texture_render(ctx, oldDrawFb);
2105
2106 /* check if newly bound framebuffer has any texture attachments */
2107 check_begin_texture_render(ctx, newDrawFb);
2108
2109 _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
2110 }
2111
2112 if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
2113 ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
2114 }
2115 }
2116
2117 void GLAPIENTRY
2118 _mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
2119 {
2120 GET_CURRENT_CONTEXT(ctx);
2121
2122 /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry
2123 * point, but they allow the use of user-generated names.
2124 */
2125 bind_framebuffer(target, framebuffer, _mesa_is_gles(ctx));
2126 }
2127
2128 void GLAPIENTRY
2129 _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
2130 {
2131 /* This function should not be in the dispatch table for core profile /
2132 * OpenGL 3.1, so execution should never get here in those cases -- no
2133 * need for an explicit test.
2134 */
2135 bind_framebuffer(target, framebuffer, true);
2136 }
2137
2138 void GLAPIENTRY
2139 _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
2140 {
2141 GLint i;
2142 GET_CURRENT_CONTEXT(ctx);
2143
2144 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2145
2146 for (i = 0; i < n; i++) {
2147 if (framebuffers[i] > 0) {
2148 struct gl_framebuffer *fb;
2149 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
2150 if (fb) {
2151 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
2152
2153 /* check if deleting currently bound framebuffer object */
2154 if (ctx->Extensions.EXT_framebuffer_blit) {
2155 /* separate draw/read binding points */
2156 if (fb == ctx->DrawBuffer) {
2157 /* bind default */
2158 ASSERT(fb->RefCount >= 2);
2159 _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
2160 }
2161 if (fb == ctx->ReadBuffer) {
2162 /* bind default */
2163 ASSERT(fb->RefCount >= 2);
2164 _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
2165 }
2166 }
2167 else {
2168 /* only one binding point for read/draw buffers */
2169 if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
2170 /* bind default */
2171 ASSERT(fb->RefCount >= 2);
2172 _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
2173 }
2174 }
2175
2176 /* remove from hash table immediately, to free the ID */
2177 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
2178
2179 if (fb != &DummyFramebuffer) {
2180 /* But the object will not be freed until it's no longer
2181 * bound in any context.
2182 */
2183 _mesa_reference_framebuffer(&fb, NULL);
2184 }
2185 }
2186 }
2187 }
2188 }
2189
2190
2191 void GLAPIENTRY
2192 _mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers)
2193 {
2194 GET_CURRENT_CONTEXT(ctx);
2195 GLuint first;
2196 GLint i;
2197
2198 if (n < 0) {
2199 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
2200 return;
2201 }
2202
2203 if (!framebuffers)
2204 return;
2205
2206 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
2207
2208 for (i = 0; i < n; i++) {
2209 GLuint name = first + i;
2210 framebuffers[i] = name;
2211 /* insert dummy placeholder into hash table */
2212 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
2213 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
2214 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
2215 }
2216 }
2217
2218
2219
2220 GLenum GLAPIENTRY
2221 _mesa_CheckFramebufferStatus(GLenum target)
2222 {
2223 struct gl_framebuffer *buffer;
2224 GET_CURRENT_CONTEXT(ctx);
2225
2226 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
2227
2228 if (MESA_VERBOSE & VERBOSE_API)
2229 _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n",
2230 _mesa_lookup_enum_by_nr(target));
2231
2232 buffer = get_framebuffer_target(ctx, target);
2233 if (!buffer) {
2234 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
2235 return 0;
2236 }
2237
2238 if (_mesa_is_winsys_fbo(buffer)) {
2239 /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */
2240 if (buffer != &IncompleteFramebuffer) {
2241 return GL_FRAMEBUFFER_COMPLETE_EXT;
2242 } else {
2243 return GL_FRAMEBUFFER_UNDEFINED;
2244 }
2245 }
2246
2247 /* No need to flush here */
2248
2249 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
2250 _mesa_test_framebuffer_completeness(ctx, buffer);
2251 }
2252
2253 return buffer->_Status;
2254 }
2255
2256
2257 /**
2258 * Replicate the src attachment point. Used by framebuffer_texture() when
2259 * the same texture is attached at GL_DEPTH_ATTACHMENT and
2260 * GL_STENCIL_ATTACHMENT.
2261 */
2262 static void
2263 reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb,
2264 gl_buffer_index dst,
2265 gl_buffer_index src)
2266 {
2267 struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst];
2268 struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src];
2269
2270 assert(src_att->Texture != NULL);
2271 assert(src_att->Renderbuffer != NULL);
2272
2273 _mesa_reference_texobj(&dst_att->Texture, src_att->Texture);
2274 _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer);
2275 dst_att->Type = src_att->Type;
2276 dst_att->Complete = src_att->Complete;
2277 dst_att->TextureLevel = src_att->TextureLevel;
2278 dst_att->Zoffset = src_att->Zoffset;
2279 }
2280
2281
2282 /**
2283 * Common code called by glFramebufferTexture1D/2D/3DEXT() and
2284 * glFramebufferTextureLayerEXT().
2285 * Note: glFramebufferTextureLayerEXT() has no textarget parameter so we'll
2286 * get textarget=0 in that case.
2287 */
2288 static void
2289 framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
2290 GLenum attachment, GLenum textarget, GLuint texture,
2291 GLint level, GLint zoffset, GLboolean layered)
2292 {
2293 struct gl_renderbuffer_attachment *att;
2294 struct gl_texture_object *texObj = NULL;
2295 struct gl_framebuffer *fb;
2296 GLenum maxLevelsTarget;
2297
2298 fb = get_framebuffer_target(ctx, target);
2299 if (!fb) {
2300 _mesa_error(ctx, GL_INVALID_ENUM,
2301 "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
2302 return;
2303 }
2304
2305 /* check framebuffer binding */
2306 if (_mesa_is_winsys_fbo(fb)) {
2307 _mesa_error(ctx, GL_INVALID_OPERATION,
2308 "glFramebufferTexture%sEXT", caller);
2309 return;
2310 }
2311
2312 /* The textarget, level, and zoffset parameters are only validated if
2313 * texture is non-zero.
2314 */
2315 if (texture) {
2316 GLboolean err = GL_TRUE;
2317
2318 texObj = _mesa_lookup_texture(ctx, texture);
2319 if (texObj != NULL) {
2320 if (textarget == 0) {
2321 /* If textarget == 0 it means we're being called by
2322 * glFramebufferTextureLayer() and textarget is not used.
2323 * The only legal texture types for that function are 3D and
2324 * 1D/2D arrays textures.
2325 */
2326 err = (texObj->Target != GL_TEXTURE_3D) &&
2327 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
2328 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT) &&
2329 (texObj->Target != GL_TEXTURE_CUBE_MAP_ARRAY) &&
2330 (texObj->Target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
2331 }
2332 else {
2333 /* Make sure textarget is consistent with the texture's type */
2334 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
2335 ? !_mesa_is_cube_face(textarget)
2336 : (texObj->Target != textarget);
2337 }
2338 }
2339 else {
2340 /* can't render to a non-existant texture */
2341 _mesa_error(ctx, GL_INVALID_OPERATION,
2342 "glFramebufferTexture%sEXT(non existant texture)",
2343 caller);
2344 return;
2345 }
2346
2347 if (err) {
2348 _mesa_error(ctx, GL_INVALID_OPERATION,
2349 "glFramebufferTexture%sEXT(texture target mismatch)",
2350 caller);
2351 return;
2352 }
2353
2354 if (texObj->Target == GL_TEXTURE_3D) {
2355 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
2356 if (zoffset < 0 || zoffset >= maxSize) {
2357 _mesa_error(ctx, GL_INVALID_VALUE,
2358 "glFramebufferTexture%sEXT(zoffset)", caller);
2359 return;
2360 }
2361 }
2362 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
2363 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT) ||
2364 (texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) ||
2365 (texObj->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) {
2366 if (zoffset < 0 ||
2367 zoffset >= (GLint) ctx->Const.MaxArrayTextureLayers) {
2368 _mesa_error(ctx, GL_INVALID_VALUE,
2369 "glFramebufferTexture%sEXT(layer)", caller);
2370 return;
2371 }
2372 }
2373
2374 maxLevelsTarget = textarget ? textarget : texObj->Target;
2375 if ((level < 0) ||
2376 (level >= _mesa_max_texture_levels(ctx, maxLevelsTarget))) {
2377 _mesa_error(ctx, GL_INVALID_VALUE,
2378 "glFramebufferTexture%sEXT(level)", caller);
2379 return;
2380 }
2381 }
2382
2383 att = _mesa_get_attachment(ctx, fb, attachment);
2384 if (att == NULL) {
2385 _mesa_error(ctx, GL_INVALID_ENUM,
2386 "glFramebufferTexture%sEXT(attachment)", caller);
2387 return;
2388 }
2389
2390 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2391
2392 _glthread_LOCK_MUTEX(fb->Mutex);
2393 if (texObj) {
2394 if (attachment == GL_DEPTH_ATTACHMENT &&
2395 texObj == fb->Attachment[BUFFER_STENCIL].Texture &&
2396 level == fb->Attachment[BUFFER_STENCIL].TextureLevel &&
2397 _mesa_tex_target_to_face(textarget) ==
2398 fb->Attachment[BUFFER_STENCIL].CubeMapFace &&
2399 zoffset == fb->Attachment[BUFFER_STENCIL].Zoffset) {
2400 /* The texture object is already attached to the stencil attachment
2401 * point. Don't create a new renderbuffer; just reuse the stencil
2402 * attachment's. This is required to prevent a GL error in
2403 * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL).
2404 */
2405 reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH,
2406 BUFFER_STENCIL);
2407 } else if (attachment == GL_STENCIL_ATTACHMENT &&
2408 texObj == fb->Attachment[BUFFER_DEPTH].Texture &&
2409 level == fb->Attachment[BUFFER_DEPTH].TextureLevel &&
2410 _mesa_tex_target_to_face(textarget) ==
2411 fb->Attachment[BUFFER_DEPTH].CubeMapFace &&
2412 zoffset == fb->Attachment[BUFFER_DEPTH].Zoffset) {
2413 /* As above, but with depth and stencil transposed. */
2414 reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL,
2415 BUFFER_DEPTH);
2416 } else {
2417 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
2418 level, zoffset, layered);
2419 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2420 /* Above we created a new renderbuffer and attached it to the
2421 * depth attachment point. Now attach it to the stencil attachment
2422 * point too.
2423 */
2424 assert(att == &fb->Attachment[BUFFER_DEPTH]);
2425 reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL,
2426 BUFFER_DEPTH);
2427 }
2428 }
2429
2430 /* Set the render-to-texture flag. We'll check this flag in
2431 * glTexImage() and friends to determine if we need to revalidate
2432 * any FBOs that might be rendering into this texture.
2433 * This flag never gets cleared since it's non-trivial to determine
2434 * when all FBOs might be done rendering to this texture. That's OK
2435 * though since it's uncommon to render to a texture then repeatedly
2436 * call glTexImage() to change images in the texture.
2437 */
2438 texObj->_RenderToTexture = GL_TRUE;
2439 }
2440 else {
2441 _mesa_remove_attachment(ctx, att);
2442 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2443 assert(att == &fb->Attachment[BUFFER_DEPTH]);
2444 _mesa_remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]);
2445 }
2446 }
2447
2448 invalidate_framebuffer(fb);
2449
2450 _glthread_UNLOCK_MUTEX(fb->Mutex);
2451 }
2452
2453
2454
2455 void GLAPIENTRY
2456 _mesa_FramebufferTexture1D(GLenum target, GLenum attachment,
2457 GLenum textarget, GLuint texture, GLint level)
2458 {
2459 GET_CURRENT_CONTEXT(ctx);
2460
2461 if (texture != 0) {
2462 GLboolean error;
2463
2464 switch (textarget) {
2465 case GL_TEXTURE_1D:
2466 error = GL_FALSE;
2467 break;
2468 case GL_TEXTURE_1D_ARRAY:
2469 error = !ctx->Extensions.EXT_texture_array;
2470 break;
2471 default:
2472 error = GL_TRUE;
2473 }
2474
2475 if (error) {
2476 _mesa_error(ctx, GL_INVALID_OPERATION,
2477 "glFramebufferTexture1DEXT(textarget=%s)",
2478 _mesa_lookup_enum_by_nr(textarget));
2479 return;
2480 }
2481 }
2482
2483 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
2484 level, 0, GL_FALSE);
2485 }
2486
2487
2488 void GLAPIENTRY
2489 _mesa_FramebufferTexture2D(GLenum target, GLenum attachment,
2490 GLenum textarget, GLuint texture, GLint level)
2491 {
2492 GET_CURRENT_CONTEXT(ctx);
2493
2494 if (texture != 0) {
2495 GLboolean error;
2496
2497 switch (textarget) {
2498 case GL_TEXTURE_2D:
2499 error = GL_FALSE;
2500 break;
2501 case GL_TEXTURE_RECTANGLE:
2502 error = _mesa_is_gles(ctx)
2503 || !ctx->Extensions.NV_texture_rectangle;
2504 break;
2505 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2506 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2507 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2508 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2509 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2510 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2511 error = !ctx->Extensions.ARB_texture_cube_map;
2512 break;
2513 case GL_TEXTURE_2D_ARRAY:
2514 error = (_mesa_is_gles(ctx) && ctx->Version < 30)
2515 || !ctx->Extensions.EXT_texture_array;
2516 break;
2517 case GL_TEXTURE_2D_MULTISAMPLE:
2518 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
2519 error = _mesa_is_gles(ctx)
2520 || !ctx->Extensions.ARB_texture_multisample;
2521 break;
2522 default:
2523 error = GL_TRUE;
2524 }
2525
2526 if (error) {
2527 _mesa_error(ctx, GL_INVALID_OPERATION,
2528 "glFramebufferTexture2DEXT(textarget=%s)",
2529 _mesa_lookup_enum_by_nr(textarget));
2530 return;
2531 }
2532 }
2533
2534 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
2535 level, 0, GL_FALSE);
2536 }
2537
2538
2539 void GLAPIENTRY
2540 _mesa_FramebufferTexture3D(GLenum target, GLenum attachment,
2541 GLenum textarget, GLuint texture,
2542 GLint level, GLint zoffset)
2543 {
2544 GET_CURRENT_CONTEXT(ctx);
2545
2546 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
2547 _mesa_error(ctx, GL_INVALID_OPERATION,
2548 "glFramebufferTexture3DEXT(textarget)");
2549 return;
2550 }
2551
2552 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
2553 level, zoffset, GL_FALSE);
2554 }
2555
2556
2557 void GLAPIENTRY
2558 _mesa_FramebufferTextureLayer(GLenum target, GLenum attachment,
2559 GLuint texture, GLint level, GLint layer)
2560 {
2561 GET_CURRENT_CONTEXT(ctx);
2562
2563 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
2564 level, layer, GL_FALSE);
2565 }
2566
2567
2568 void GLAPIENTRY
2569 _mesa_FramebufferTexture(GLenum target, GLenum attachment,
2570 GLuint texture, GLint level)
2571 {
2572 GET_CURRENT_CONTEXT(ctx);
2573
2574 if (_mesa_has_geometry_shaders(ctx)) {
2575 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
2576 level, 0, GL_TRUE);
2577 } else {
2578 _mesa_error(ctx, GL_INVALID_OPERATION,
2579 "unsupported function (glFramebufferTexture) called");
2580 }
2581 }
2582
2583
2584 void GLAPIENTRY
2585 _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment,
2586 GLenum renderbufferTarget,
2587 GLuint renderbuffer)
2588 {
2589 struct gl_renderbuffer_attachment *att;
2590 struct gl_framebuffer *fb;
2591 struct gl_renderbuffer *rb;
2592 GET_CURRENT_CONTEXT(ctx);
2593
2594 fb = get_framebuffer_target(ctx, target);
2595 if (!fb) {
2596 _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(target)");
2597 return;
2598 }
2599
2600 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
2601 _mesa_error(ctx, GL_INVALID_ENUM,
2602 "glFramebufferRenderbufferEXT(renderbufferTarget)");
2603 return;
2604 }
2605
2606 if (_mesa_is_winsys_fbo(fb)) {
2607 /* Can't attach new renderbuffers to a window system framebuffer */
2608 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
2609 return;
2610 }
2611
2612 att = _mesa_get_attachment(ctx, fb, attachment);
2613 if (att == NULL) {
2614 _mesa_error(ctx, GL_INVALID_ENUM,
2615 "glFramebufferRenderbufferEXT(invalid attachment %s)",
2616 _mesa_lookup_enum_by_nr(attachment));
2617 return;
2618 }
2619
2620 if (renderbuffer) {
2621 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
2622 if (!rb) {
2623 _mesa_error(ctx, GL_INVALID_OPERATION,
2624 "glFramebufferRenderbufferEXT(non-existant"
2625 " renderbuffer %u)", renderbuffer);
2626 return;
2627 }
2628 else if (rb == &DummyRenderbuffer) {
2629 /* This is what NVIDIA does */
2630 _mesa_error(ctx, GL_INVALID_VALUE,
2631 "glFramebufferRenderbufferEXT(renderbuffer %u)",
2632 renderbuffer);
2633 return;
2634 }
2635 }
2636 else {
2637 /* remove renderbuffer attachment */
2638 rb = NULL;
2639 }
2640
2641 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
2642 rb && rb->Format != MESA_FORMAT_NONE) {
2643 /* make sure the renderbuffer is a depth/stencil format */
2644 const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
2645 if (baseFormat != GL_DEPTH_STENCIL) {
2646 _mesa_error(ctx, GL_INVALID_OPERATION,
2647 "glFramebufferRenderbufferEXT(renderbuffer"
2648 " is not DEPTH_STENCIL format)");
2649 return;
2650 }
2651 }
2652
2653
2654 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2655
2656 assert(ctx->Driver.FramebufferRenderbuffer);
2657 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
2658
2659 /* Some subsequent GL commands may depend on the framebuffer's visual
2660 * after the binding is updated. Update visual info now.
2661 */
2662 _mesa_update_framebuffer_visual(ctx, fb);
2663 }
2664
2665
2666 void GLAPIENTRY
2667 _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment,
2668 GLenum pname, GLint *params)
2669 {
2670 const struct gl_renderbuffer_attachment *att;
2671 struct gl_framebuffer *buffer;
2672 GLenum err;
2673 GET_CURRENT_CONTEXT(ctx);
2674
2675 /* The error differs in GL and GLES. */
2676 err = _mesa_is_desktop_gl(ctx) ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
2677
2678 buffer = get_framebuffer_target(ctx, target);
2679 if (!buffer) {
2680 _mesa_error(ctx, GL_INVALID_ENUM,
2681 "glGetFramebufferAttachmentParameterivEXT(target)");
2682 return;
2683 }
2684
2685 if (_mesa_is_winsys_fbo(buffer)) {
2686 /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec
2687 * says:
2688 *
2689 * "If the framebuffer currently bound to target is zero, then
2690 * INVALID_OPERATION is generated."
2691 *
2692 * The EXT_framebuffer_object spec has the same wording, and the
2693 * OES_framebuffer_object spec refers to the EXT_framebuffer_object
2694 * spec.
2695 */
2696 if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object)
2697 && !_mesa_is_gles3(ctx)) {
2698 _mesa_error(ctx, GL_INVALID_OPERATION,
2699 "glGetFramebufferAttachmentParameteriv(bound FBO = 0)");
2700 return;
2701 }
2702
2703 if (_mesa_is_gles3(ctx) && attachment != GL_BACK &&
2704 attachment != GL_DEPTH && attachment != GL_STENCIL) {
2705 _mesa_error(ctx, GL_INVALID_OPERATION,
2706 "glGetFramebufferAttachmentParameteriv(attachment)");
2707 return;
2708 }
2709 /* the default / window-system FBO */
2710 att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
2711 }
2712 else {
2713 /* user-created framebuffer FBO */
2714 att = _mesa_get_attachment(ctx, buffer, attachment);
2715 }
2716
2717 if (att == NULL) {
2718 _mesa_error(ctx, GL_INVALID_ENUM,
2719 "glGetFramebufferAttachmentParameterivEXT(attachment)");
2720 return;
2721 }
2722
2723 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2724 /* the depth and stencil attachments must point to the same buffer */
2725 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
2726 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
2727 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
2728 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
2729 _mesa_error(ctx, GL_INVALID_OPERATION,
2730 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
2731 " attachments differ)");
2732 return;
2733 }
2734 }
2735
2736 /* No need to flush here */
2737
2738 switch (pname) {
2739 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
2740 *params = _mesa_is_winsys_fbo(buffer)
2741 ? GL_FRAMEBUFFER_DEFAULT : att->Type;
2742 return;
2743 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
2744 if (att->Type == GL_RENDERBUFFER_EXT) {
2745 *params = att->Renderbuffer->Name;
2746 }
2747 else if (att->Type == GL_TEXTURE) {
2748 *params = att->Texture->Name;
2749 }
2750 else {
2751 assert(att->Type == GL_NONE);
2752 if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
2753 *params = 0;
2754 } else {
2755 goto invalid_pname_enum;
2756 }
2757 }
2758 return;
2759 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
2760 if (att->Type == GL_TEXTURE) {
2761 *params = att->TextureLevel;
2762 }
2763 else if (att->Type == GL_NONE) {
2764 _mesa_error(ctx, err,
2765 "glGetFramebufferAttachmentParameterivEXT(pname)");
2766 }
2767 else {
2768 goto invalid_pname_enum;
2769 }
2770 return;
2771 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
2772 if (att->Type == GL_TEXTURE) {
2773 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
2774 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
2775 }
2776 else {
2777 *params = 0;
2778 }
2779 }
2780 else if (att->Type == GL_NONE) {
2781 _mesa_error(ctx, err,
2782 "glGetFramebufferAttachmentParameterivEXT(pname)");
2783 }
2784 else {
2785 goto invalid_pname_enum;
2786 }
2787 return;
2788 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
2789 if (ctx->API == API_OPENGLES) {
2790 goto invalid_pname_enum;
2791 } else if (att->Type == GL_NONE) {
2792 _mesa_error(ctx, err,
2793 "glGetFramebufferAttachmentParameterivEXT(pname)");
2794 } else if (att->Type == GL_TEXTURE) {
2795 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2796 *params = att->Zoffset;
2797 }
2798 else {
2799 *params = 0;
2800 }
2801 }
2802 else {
2803 goto invalid_pname_enum;
2804 }
2805 return;
2806 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2807 if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object)
2808 && !_mesa_is_gles3(ctx)) {
2809 goto invalid_pname_enum;
2810 }
2811 else if (att->Type == GL_NONE) {
2812 _mesa_error(ctx, err,
2813 "glGetFramebufferAttachmentParameterivEXT(pname)");
2814 }
2815 else {
2816 if (ctx->Extensions.EXT_framebuffer_sRGB) {
2817 *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
2818 }
2819 else {
2820 /* According to ARB_framebuffer_sRGB, we should return LINEAR
2821 * if the sRGB conversion is unsupported. */
2822 *params = GL_LINEAR;
2823 }
2824 }
2825 return;
2826 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2827 if ((ctx->API != API_OPENGL_COMPAT || !ctx->Extensions.ARB_framebuffer_object)
2828 && ctx->API != API_OPENGL_CORE
2829 && !_mesa_is_gles3(ctx)) {
2830 goto invalid_pname_enum;
2831 }
2832 else if (att->Type == GL_NONE) {
2833 _mesa_error(ctx, err,
2834 "glGetFramebufferAttachmentParameterivEXT(pname)");
2835 }
2836 else {
2837 gl_format format = att->Renderbuffer->Format;
2838
2839 /* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES
2840 * 3.0.1 spec says:
2841 *
2842 * "If pname is FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE.... If
2843 * attachment is DEPTH_STENCIL_ATTACHMENT the query will fail and
2844 * generate an INVALID_OPERATION error.
2845 */
2846 if (_mesa_is_gles3(ctx) && attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2847 _mesa_error(ctx, GL_INVALID_OPERATION,
2848 "glGetFramebufferAttachmentParameteriv(cannot query "
2849 "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of "
2850 "GL_DEPTH_STENCIL_ATTACHMENT");
2851 return;
2852 }
2853
2854 if (format == MESA_FORMAT_S8) {
2855 /* special cases */
2856 *params = GL_INDEX;
2857 }
2858 else if (format == MESA_FORMAT_Z32_FLOAT_X24S8) {
2859 /* depends on the attachment parameter */
2860 if (attachment == GL_STENCIL_ATTACHMENT) {
2861 *params = GL_INDEX;
2862 }
2863 else {
2864 *params = GL_FLOAT;
2865 }
2866 }
2867 else {
2868 *params = _mesa_get_format_datatype(format);
2869 }
2870 }
2871 return;
2872 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
2873 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
2874 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
2875 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
2876 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
2877 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2878 if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object)
2879 && !_mesa_is_gles3(ctx)) {
2880 goto invalid_pname_enum;
2881 }
2882 else if (att->Type == GL_NONE) {
2883 _mesa_error(ctx, err,
2884 "glGetFramebufferAttachmentParameterivEXT(pname)");
2885 }
2886 else if (att->Texture) {
2887 const struct gl_texture_image *texImage =
2888 _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
2889 att->TextureLevel);
2890 if (texImage) {
2891 *params = get_component_bits(pname, texImage->_BaseFormat,
2892 texImage->TexFormat);
2893 }
2894 else {
2895 *params = 0;
2896 }
2897 }
2898 else if (att->Renderbuffer) {
2899 *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
2900 att->Renderbuffer->Format);
2901 }
2902 else {
2903 _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:"
2904 " invalid FBO attachment structure");
2905 }
2906 return;
2907 default:
2908 goto invalid_pname_enum;
2909 }
2910
2911 return;
2912
2913 invalid_pname_enum:
2914 _mesa_error(ctx, GL_INVALID_ENUM,
2915 "glGetFramebufferAttachmentParameteriv(pname)");
2916 return;
2917 }
2918
2919
2920 void GLAPIENTRY
2921 _mesa_GenerateMipmap(GLenum target)
2922 {
2923 struct gl_texture_image *srcImage;
2924 struct gl_texture_object *texObj;
2925 GLboolean error;
2926
2927 GET_CURRENT_CONTEXT(ctx);
2928
2929 FLUSH_VERTICES(ctx, 0);
2930
2931 switch (target) {
2932 case GL_TEXTURE_1D:
2933 error = _mesa_is_gles(ctx);
2934 break;
2935 case GL_TEXTURE_2D:
2936 error = GL_FALSE;
2937 break;
2938 case GL_TEXTURE_3D:
2939 error = ctx->API == API_OPENGLES;
2940 break;
2941 case GL_TEXTURE_CUBE_MAP:
2942 error = !ctx->Extensions.ARB_texture_cube_map;
2943 break;
2944 case GL_TEXTURE_1D_ARRAY:
2945 error = _mesa_is_gles(ctx) || !ctx->Extensions.EXT_texture_array;
2946 break;
2947 case GL_TEXTURE_2D_ARRAY:
2948 error = (_mesa_is_gles(ctx) && ctx->Version < 30)
2949 || !ctx->Extensions.EXT_texture_array;
2950 break;
2951 default:
2952 error = GL_TRUE;
2953 }
2954
2955 if (error) {
2956 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target=%s)",
2957 _mesa_lookup_enum_by_nr(target));
2958 return;
2959 }
2960
2961 texObj = _mesa_get_current_tex_object(ctx, target);
2962
2963 if (texObj->BaseLevel >= texObj->MaxLevel) {
2964 /* nothing to do */
2965 return;
2966 }
2967
2968 if (texObj->Target == GL_TEXTURE_CUBE_MAP &&
2969 !_mesa_cube_complete(texObj)) {
2970 _mesa_error(ctx, GL_INVALID_OPERATION,
2971 "glGenerateMipmap(incomplete cube map)");
2972 return;
2973 }
2974
2975 _mesa_lock_texture(ctx, texObj);
2976
2977 srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel);
2978 if (!srcImage) {
2979 _mesa_unlock_texture(ctx, texObj);
2980 _mesa_error(ctx, GL_INVALID_OPERATION,
2981 "glGenerateMipmap(zero size base image)");
2982 return;
2983 }
2984
2985 if (_mesa_is_enum_format_integer(srcImage->InternalFormat) ||
2986 _mesa_is_depthstencil_format(srcImage->InternalFormat) ||
2987 _mesa_is_stencil_format(srcImage->InternalFormat)) {
2988 _mesa_unlock_texture(ctx, texObj);
2989 _mesa_error(ctx, GL_INVALID_OPERATION,
2990 "glGenerateMipmap(invalid internal format)");
2991 return;
2992 }
2993
2994 if (target == GL_TEXTURE_CUBE_MAP) {
2995 GLuint face;
2996 for (face = 0; face < 6; face++)
2997 ctx->Driver.GenerateMipmap(ctx,
2998 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2999 texObj);
3000 }
3001 else {
3002 ctx->Driver.GenerateMipmap(ctx, target, texObj);
3003 }
3004 _mesa_unlock_texture(ctx, texObj);
3005 }
3006
3007
3008 static const struct gl_renderbuffer_attachment *
3009 find_attachment(const struct gl_framebuffer *fb,
3010 const struct gl_renderbuffer *rb)
3011 {
3012 GLuint i;
3013 for (i = 0; i < Elements(fb->Attachment); i++) {
3014 if (fb->Attachment[i].Renderbuffer == rb)
3015 return &fb->Attachment[i];
3016 }
3017 return NULL;
3018 }
3019
3020
3021 /**
3022 * Helper function for checking if the datatypes of color buffers are
3023 * compatible for glBlitFramebuffer. From the 3.1 spec, page 198:
3024 *
3025 * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT
3026 * and any of the following conditions hold:
3027 * - The read buffer contains fixed-point or floating-point values and any
3028 * draw buffer contains neither fixed-point nor floating-point values.
3029 * - The read buffer contains unsigned integer values and any draw buffer
3030 * does not contain unsigned integer values.
3031 * - The read buffer contains signed integer values and any draw buffer
3032 * does not contain signed integer values."
3033 */
3034 static GLboolean
3035 compatible_color_datatypes(gl_format srcFormat, gl_format dstFormat)
3036 {
3037 GLenum srcType = _mesa_get_format_datatype(srcFormat);
3038 GLenum dstType = _mesa_get_format_datatype(dstFormat);
3039
3040 if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) {
3041 assert(srcType == GL_UNSIGNED_NORMALIZED ||
3042 srcType == GL_SIGNED_NORMALIZED ||
3043 srcType == GL_FLOAT);
3044 /* Boil any of those types down to GL_FLOAT */
3045 srcType = GL_FLOAT;
3046 }
3047
3048 if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) {
3049 assert(dstType == GL_UNSIGNED_NORMALIZED ||
3050 dstType == GL_SIGNED_NORMALIZED ||
3051 dstType == GL_FLOAT);
3052 /* Boil any of those types down to GL_FLOAT */
3053 dstType = GL_FLOAT;
3054 }
3055
3056 return srcType == dstType;
3057 }
3058
3059
3060 static GLboolean
3061 compatible_resolve_formats(const struct gl_renderbuffer *readRb,
3062 const struct gl_renderbuffer *drawRb)
3063 {
3064 GLenum readFormat, drawFormat;
3065
3066 /* The simple case where we know the backing Mesa formats are the same.
3067 */
3068 if (_mesa_get_srgb_format_linear(readRb->Format) ==
3069 _mesa_get_srgb_format_linear(drawRb->Format)) {
3070 return GL_TRUE;
3071 }
3072
3073 /* The Mesa formats are different, so we must check whether the internal
3074 * formats are compatible.
3075 *
3076 * Under some circumstances, the user may request e.g. two GL_RGBA8
3077 * textures and get two entirely different Mesa formats like RGBA8888 and
3078 * ARGB8888. Drivers behaving like that should be able to cope with
3079 * non-matching formats by themselves, because it's not the user's fault.
3080 *
3081 * Blits between linear and sRGB formats are also allowed.
3082 */
3083 readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat);
3084 drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat);
3085 readFormat = _mesa_get_linear_internalformat(readFormat);
3086 drawFormat = _mesa_get_linear_internalformat(drawFormat);
3087
3088 if (readFormat == drawFormat) {
3089 return GL_TRUE;
3090 }
3091
3092 return GL_FALSE;
3093 }
3094
3095 static GLboolean
3096 is_valid_blit_filter(const struct gl_context *ctx, GLenum filter)
3097 {
3098 switch (filter) {
3099 case GL_NEAREST:
3100 case GL_LINEAR:
3101 return true;
3102 case GL_SCALED_RESOLVE_FASTEST_EXT:
3103 case GL_SCALED_RESOLVE_NICEST_EXT:
3104 return ctx->Extensions.EXT_framebuffer_multisample_blit_scaled;
3105 default:
3106 return false;
3107 }
3108 }
3109
3110 /**
3111 * Blit rectangular region, optionally from one framebuffer to another.
3112 *
3113 * Note, if the src buffer is multisampled and the dest is not, this is
3114 * when the samples must be resolved to a single color.
3115 */
3116 void GLAPIENTRY
3117 _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
3118 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
3119 GLbitfield mask, GLenum filter)
3120 {
3121 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
3122 GL_DEPTH_BUFFER_BIT |
3123 GL_STENCIL_BUFFER_BIT);
3124 const struct gl_framebuffer *readFb, *drawFb;
3125 GET_CURRENT_CONTEXT(ctx);
3126
3127 FLUSH_VERTICES(ctx, 0);
3128
3129 if (MESA_VERBOSE & VERBOSE_API)
3130 _mesa_debug(ctx,
3131 "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n",
3132 srcX0, srcY0, srcX1, srcY1,
3133 dstX0, dstY0, dstX1, dstY1,
3134 mask, _mesa_lookup_enum_by_nr(filter));
3135
3136 if (ctx->NewState) {
3137 _mesa_update_state(ctx);
3138 }
3139
3140 readFb = ctx->ReadBuffer;
3141 drawFb = ctx->DrawBuffer;
3142
3143 if (!readFb || !drawFb) {
3144 /* This will normally never happen but someday we may want to
3145 * support MakeCurrent() with no drawables.
3146 */
3147 return;
3148 }
3149
3150 /* check for complete framebuffers */
3151 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
3152 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
3153 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
3154 "glBlitFramebufferEXT(incomplete draw/read buffers)");
3155 return;
3156 }
3157
3158 if (!is_valid_blit_filter(ctx, filter)) {
3159 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(%s)",
3160 _mesa_lookup_enum_by_nr(filter));
3161 return;
3162 }
3163
3164 if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
3165 filter == GL_SCALED_RESOLVE_NICEST_EXT) &&
3166 (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) {
3167 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT(%s)",
3168 _mesa_lookup_enum_by_nr(filter));
3169 return;
3170 }
3171
3172 if (mask & ~legalMaskBits) {
3173 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
3174 return;
3175 }
3176
3177 /* depth/stencil must be blitted with nearest filtering */
3178 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
3179 && filter != GL_NEAREST) {
3180 _mesa_error(ctx, GL_INVALID_OPERATION,
3181 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)");
3182 return;
3183 }
3184
3185 /* get color read/draw renderbuffers */
3186 if (mask & GL_COLOR_BUFFER_BIT) {
3187 const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers;
3188 const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
3189 const struct gl_renderbuffer *colorDrawRb = NULL;
3190 GLuint i;
3191
3192 /* From the EXT_framebuffer_object spec:
3193 *
3194 * "If a buffer is specified in <mask> and does not exist in both
3195 * the read and draw framebuffers, the corresponding bit is silently
3196 * ignored."
3197 */
3198 if (!colorReadRb || numColorDrawBuffers == 0) {
3199 mask &= ~GL_COLOR_BUFFER_BIT;
3200 }
3201 else {
3202 for (i = 0; i < numColorDrawBuffers; i++) {
3203 colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
3204 if (!colorDrawRb)
3205 continue;
3206
3207 /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL
3208 * ES 3.0.1 spec says:
3209 *
3210 * "If the source and destination buffers are identical, an
3211 * INVALID_OPERATION error is generated. Different mipmap
3212 * levels of a texture, different layers of a three-
3213 * dimensional texture or two-dimensional array texture, and
3214 * different faces of a cube map texture do not constitute
3215 * identical buffers."
3216 */
3217 if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
3218 _mesa_error(ctx, GL_INVALID_OPERATION,
3219 "glBlitFramebuffer(source and destination color "
3220 "buffer cannot be the same)");
3221 return;
3222 }
3223
3224 if (!compatible_color_datatypes(colorReadRb->Format,
3225 colorDrawRb->Format)) {
3226 _mesa_error(ctx, GL_INVALID_OPERATION,
3227 "glBlitFramebufferEXT(color buffer datatypes mismatch)");
3228 return;
3229 }
3230 /* extra checks for multisample copies... */
3231 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
3232 /* color formats must match */
3233 if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) {
3234 _mesa_error(ctx, GL_INVALID_OPERATION,
3235 "glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
3236 return;
3237 }
3238 }
3239 }
3240 if (filter != GL_NEAREST) {
3241 /* From EXT_framebuffer_multisample_blit_scaled specification:
3242 * "Calling BlitFramebuffer will result in an INVALID_OPERATION error
3243 * if filter is not NEAREST and read buffer contains integer data."
3244 */
3245 GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
3246 if (type == GL_INT || type == GL_UNSIGNED_INT) {
3247 _mesa_error(ctx, GL_INVALID_OPERATION,
3248 "glBlitFramebufferEXT(integer color type)");
3249 return;
3250 }
3251 }
3252 }
3253 }
3254
3255 if (mask & GL_STENCIL_BUFFER_BIT) {
3256 struct gl_renderbuffer *readRb =
3257 readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
3258 struct gl_renderbuffer *drawRb =
3259 drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;
3260
3261 /* From the EXT_framebuffer_object spec:
3262 *
3263 * "If a buffer is specified in <mask> and does not exist in both
3264 * the read and draw framebuffers, the corresponding bit is silently
3265 * ignored."
3266 */
3267 if ((readRb == NULL) || (drawRb == NULL)) {
3268 mask &= ~GL_STENCIL_BUFFER_BIT;
3269 }
3270 else {
3271 int read_z_bits, draw_z_bits;
3272
3273 if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
3274 _mesa_error(ctx, GL_INVALID_OPERATION,
3275 "glBlitFramebuffer(source and destination stencil "
3276 "buffer cannot be the same)");
3277 return;
3278 }
3279
3280 if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
3281 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
3282 /* There is no need to check the stencil datatype here, because
3283 * there is only one: GL_UNSIGNED_INT.
3284 */
3285 _mesa_error(ctx, GL_INVALID_OPERATION,
3286 "glBlitFramebuffer(stencil attachment format mismatch)");
3287 return;
3288 }
3289
3290 read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS);
3291 draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS);
3292
3293 /* If both buffers also have depth data, the depth formats must match
3294 * as well. If one doesn't have depth, it's not blitted, so we should
3295 * ignore the depth format check.
3296 */
3297 if (read_z_bits > 0 && draw_z_bits > 0 &&
3298 (read_z_bits != draw_z_bits ||
3299 _mesa_get_format_datatype(readRb->Format) !=
3300 _mesa_get_format_datatype(drawRb->Format))) {
3301
3302 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
3303 "(stencil attachment depth format mismatch)");
3304 return;
3305 }
3306 }
3307 }
3308
3309 if (mask & GL_DEPTH_BUFFER_BIT) {
3310 struct gl_renderbuffer *readRb =
3311 readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
3312 struct gl_renderbuffer *drawRb =
3313 drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
3314
3315 /* From the EXT_framebuffer_object spec:
3316 *
3317 * "If a buffer is specified in <mask> and does not exist in both
3318 * the read and draw framebuffers, the corresponding bit is silently
3319 * ignored."
3320 */
3321 if ((readRb == NULL) || (drawRb == NULL)) {
3322 mask &= ~GL_DEPTH_BUFFER_BIT;
3323 }
3324 else {
3325 int read_s_bit, draw_s_bit;
3326
3327 if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
3328 _mesa_error(ctx, GL_INVALID_OPERATION,
3329 "glBlitFramebuffer(source and destination depth "
3330 "buffer cannot be the same)");
3331 return;
3332 }
3333
3334 if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
3335 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
3336 (_mesa_get_format_datatype(readRb->Format) !=
3337 _mesa_get_format_datatype(drawRb->Format))) {
3338 _mesa_error(ctx, GL_INVALID_OPERATION,
3339 "glBlitFramebuffer(depth attachment format mismatch)");
3340 return;
3341 }
3342
3343 read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS);
3344 draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS);
3345
3346 /* If both buffers also have stencil data, the stencil formats must
3347 * match as well. If one doesn't have stencil, it's not blitted, so
3348 * we should ignore the stencil format check.
3349 */
3350 if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) {
3351 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
3352 "(depth attachment stencil bits mismatch)");
3353 return;
3354 }
3355 }
3356 }
3357
3358
3359 if (_mesa_is_gles3(ctx)) {
3360 /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
3361 * 3.0.1 spec says:
3362 *
3363 * "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero,
3364 * an INVALID_OPERATION error is generated."
3365 */
3366 if (drawFb->Visual.samples > 0) {
3367 _mesa_error(ctx, GL_INVALID_OPERATION,
3368 "glBlitFramebuffer(destination samples must be 0)");
3369 return;
3370 }
3371
3372 /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
3373 * 3.0.1 spec says:
3374 *
3375 * "If SAMPLE_BUFFERS for the read framebuffer is greater than zero,
3376 * no copy is performed and an INVALID_OPERATION error is generated
3377 * if the formats of the read and draw framebuffers are not
3378 * identical or if the source and destination rectangles are not
3379 * defined with the same (X0, Y0) and (X1, Y1) bounds."
3380 *
3381 * The format check was made above because desktop OpenGL has the same
3382 * requirement.
3383 */
3384 if (readFb->Visual.samples > 0
3385 && (srcX0 != dstX0 || srcY0 != dstY0
3386 || srcX1 != dstX1 || srcY1 != dstY1)) {
3387 _mesa_error(ctx, GL_INVALID_OPERATION,
3388 "glBlitFramebuffer(bad src/dst multisample region)");
3389 return;
3390 }
3391 } else {
3392 if (readFb->Visual.samples > 0 &&
3393 drawFb->Visual.samples > 0 &&
3394 readFb->Visual.samples != drawFb->Visual.samples) {
3395 _mesa_error(ctx, GL_INVALID_OPERATION,
3396 "glBlitFramebufferEXT(mismatched samples)");
3397 return;
3398 }
3399
3400 /* extra checks for multisample copies... */
3401 if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) &&
3402 (filter == GL_NEAREST || filter == GL_LINEAR)) {
3403 /* src and dest region sizes must be the same */
3404 if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) ||
3405 abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) {
3406 _mesa_error(ctx, GL_INVALID_OPERATION,
3407 "glBlitFramebufferEXT(bad src/dst multisample region sizes)");
3408 return;
3409 }
3410 }
3411 }
3412
3413 if (!ctx->Extensions.EXT_framebuffer_blit) {
3414 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
3415 return;
3416 }
3417
3418 /* Debug code */
3419 if (DEBUG_BLIT) {
3420 const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
3421 const struct gl_renderbuffer *colorDrawRb = NULL;
3422 GLuint i = 0;
3423
3424 printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
3425 " 0x%x, 0x%x)\n",
3426 srcX0, srcY0, srcX1, srcY1,
3427 dstX0, dstY0, dstX1, dstY1,
3428 mask, filter);
3429 if (colorReadRb) {
3430 const struct gl_renderbuffer_attachment *att;
3431
3432 att = find_attachment(readFb, colorReadRb);
3433 printf(" Src FBO %u RB %u (%dx%d) ",
3434 readFb->Name, colorReadRb->Name,
3435 colorReadRb->Width, colorReadRb->Height);
3436 if (att && att->Texture) {
3437 printf("Tex %u tgt 0x%x level %u face %u",
3438 att->Texture->Name,
3439 att->Texture->Target,
3440 att->TextureLevel,
3441 att->CubeMapFace);
3442 }
3443 printf("\n");
3444
3445 /* Print all active color render buffers */
3446 for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
3447 colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
3448 if (!colorDrawRb)
3449 continue;
3450
3451 att = find_attachment(drawFb, colorDrawRb);
3452 printf(" Dst FBO %u RB %u (%dx%d) ",
3453 drawFb->Name, colorDrawRb->Name,
3454 colorDrawRb->Width, colorDrawRb->Height);
3455 if (att && att->Texture) {
3456 printf("Tex %u tgt 0x%x level %u face %u",
3457 att->Texture->Name,
3458 att->Texture->Target,
3459 att->TextureLevel,
3460 att->CubeMapFace);
3461 }
3462 printf("\n");
3463 }
3464 }
3465 }
3466
3467 if (!mask ||
3468 (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 ||
3469 (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) {
3470 return;
3471 }
3472
3473 ASSERT(ctx->Driver.BlitFramebuffer);
3474 ctx->Driver.BlitFramebuffer(ctx,
3475 srcX0, srcY0, srcX1, srcY1,
3476 dstX0, dstY0, dstX1, dstY1,
3477 mask, filter);
3478 }
3479
3480
3481 static void
3482 invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments,
3483 const GLenum *attachments, GLint x, GLint y,
3484 GLsizei width, GLsizei height, const char *name)
3485 {
3486 int i;
3487 struct gl_framebuffer *fb;
3488 GET_CURRENT_CONTEXT(ctx);
3489
3490 fb = get_framebuffer_target(ctx, target);
3491 if (!fb) {
3492 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", name);
3493 return;
3494 }
3495
3496 if (numAttachments < 0) {
3497 _mesa_error(ctx, GL_INVALID_VALUE,
3498 "%s(numAttachments < 0)", name);
3499 return;
3500 }
3501
3502 /* The GL_ARB_invalidate_subdata spec says:
3503 *
3504 * "If an attachment is specified that does not exist in the
3505 * framebuffer bound to <target>, it is ignored."
3506 *
3507 * It also says:
3508 *
3509 * "If <attachments> contains COLOR_ATTACHMENTm and m is greater than
3510 * or equal to the value of MAX_COLOR_ATTACHMENTS, then the error
3511 * INVALID_OPERATION is generated."
3512 *
3513 * No mention is made of GL_AUXi being out of range. Therefore, we allow
3514 * any enum that can be allowed by the API (OpenGL ES 3.0 has a different
3515 * set of retrictions).
3516 */
3517 for (i = 0; i < numAttachments; i++) {
3518 if (_mesa_is_winsys_fbo(fb)) {
3519 switch (attachments[i]) {
3520 case GL_ACCUM:
3521 case GL_AUX0:
3522 case GL_AUX1:
3523 case GL_AUX2:
3524 case GL_AUX3:
3525 /* Accumulation buffers and auxilary buffers were removed in
3526 * OpenGL 3.1, and they never existed in OpenGL ES.
3527 */
3528 if (ctx->API != API_OPENGL_COMPAT)
3529 goto invalid_enum;
3530 break;
3531 case GL_COLOR:
3532 case GL_DEPTH:
3533 case GL_STENCIL:
3534 break;
3535 case GL_BACK_LEFT:
3536 case GL_BACK_RIGHT:
3537 case GL_FRONT_LEFT:
3538 case GL_FRONT_RIGHT:
3539 if (!_mesa_is_desktop_gl(ctx))
3540 goto invalid_enum;
3541 break;
3542 default:
3543 goto invalid_enum;
3544 }
3545 } else {
3546 switch (attachments[i]) {
3547 case GL_DEPTH_ATTACHMENT:
3548 case GL_STENCIL_ATTACHMENT:
3549 break;
3550 case GL_COLOR_ATTACHMENT0:
3551 case GL_COLOR_ATTACHMENT1:
3552 case GL_COLOR_ATTACHMENT2:
3553 case GL_COLOR_ATTACHMENT3:
3554 case GL_COLOR_ATTACHMENT4:
3555 case GL_COLOR_ATTACHMENT5:
3556 case GL_COLOR_ATTACHMENT6:
3557 case GL_COLOR_ATTACHMENT7:
3558 case GL_COLOR_ATTACHMENT8:
3559 case GL_COLOR_ATTACHMENT9:
3560 case GL_COLOR_ATTACHMENT10:
3561 case GL_COLOR_ATTACHMENT11:
3562 case GL_COLOR_ATTACHMENT12:
3563 case GL_COLOR_ATTACHMENT13:
3564 case GL_COLOR_ATTACHMENT14:
3565 case GL_COLOR_ATTACHMENT15: {
3566 unsigned k = attachments[i] - GL_COLOR_ATTACHMENT0;
3567 if (k >= ctx->Const.MaxColorAttachments) {
3568 _mesa_error(ctx, GL_INVALID_OPERATION,
3569 "%s(attachment >= max. color attachments)", name);
3570 return;
3571 }
3572 }
3573 default:
3574 goto invalid_enum;
3575 }
3576 }
3577 }
3578
3579 /* We don't actually do anything for this yet. Just return after
3580 * validating the parameters and generating the required errors.
3581 */
3582 return;
3583
3584 invalid_enum:
3585 _mesa_error(ctx, GL_INVALID_ENUM, "%s(attachment)", name);
3586 return;
3587 }
3588
3589 void GLAPIENTRY
3590 _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
3591 const GLenum *attachments, GLint x, GLint y,
3592 GLsizei width, GLsizei height)
3593 {
3594 invalidate_framebuffer_storage(target, numAttachments, attachments,
3595 x, y, width, height,
3596 "glInvalidateSubFramebuffer");
3597 }
3598
3599 void GLAPIENTRY
3600 _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments,
3601 const GLenum *attachments)
3602 {
3603 /* The GL_ARB_invalidate_subdata spec says:
3604 *
3605 * "The command
3606 *
3607 * void InvalidateFramebuffer(enum target,
3608 * sizei numAttachments,
3609 * const enum *attachments);
3610 *
3611 * is equivalent to the command InvalidateSubFramebuffer with <x>, <y>,
3612 * <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>,
3613 * <MAX_VIEWPORT_DIMS[1]> respectively."
3614 */
3615 invalidate_framebuffer_storage(target, numAttachments, attachments,
3616 0, 0, MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT,
3617 "glInvalidateFramebuffer");
3618 }
3619
3620 void GLAPIENTRY
3621 _mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments,
3622 const GLenum *attachments)
3623 {
3624 struct gl_framebuffer *fb;
3625 GLint i;
3626
3627 GET_CURRENT_CONTEXT(ctx);
3628
3629 fb = get_framebuffer_target(ctx, target);
3630 if (!fb) {
3631 _mesa_error(ctx, GL_INVALID_ENUM,
3632 "glDiscardFramebufferEXT(target %s)",
3633 _mesa_lookup_enum_by_nr(target));
3634 return;
3635 }
3636
3637 if (numAttachments < 0) {
3638 _mesa_error(ctx, GL_INVALID_VALUE,
3639 "glDiscardFramebufferEXT(numAttachments < 0)");
3640 return;
3641 }
3642
3643 for (i = 0; i < numAttachments; i++) {
3644 switch (attachments[i]) {
3645 case GL_COLOR:
3646 case GL_DEPTH:
3647 case GL_STENCIL:
3648 if (_mesa_is_user_fbo(fb))
3649 goto invalid_enum;
3650 break;
3651 case GL_COLOR_ATTACHMENT0:
3652 case GL_DEPTH_ATTACHMENT:
3653 case GL_STENCIL_ATTACHMENT:
3654 if (_mesa_is_winsys_fbo(fb))
3655 goto invalid_enum;
3656 break;
3657 default:
3658 goto invalid_enum;
3659 }
3660 }
3661
3662 if (ctx->Driver.DiscardFramebuffer)
3663 ctx->Driver.DiscardFramebuffer(ctx, target, numAttachments, attachments);
3664
3665 return;
3666
3667 invalid_enum:
3668 _mesa_error(ctx, GL_INVALID_ENUM,
3669 "glDiscardFramebufferEXT(attachment %s)",
3670 _mesa_lookup_enum_by_nr(attachments[i]));
3671 }