2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #include "framebuffer.h"
36 #include "renderbuffer.h"
44 * None of the GL_EXT_framebuffer_object functions are compiled into
51 * When glGenRender/FramebuffersEXT() is called we insert pointers to
52 * these placeholder objects into the hash table.
53 * Later, when the object ID is first bound, we replace the placeholder
54 * with the real frame/renderbuffer.
56 static struct gl_framebuffer DummyFramebuffer
;
57 static struct gl_renderbuffer DummyRenderbuffer
;
60 #define IS_CUBE_FACE(TARGET) \
61 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
62 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
66 * Helper routine for getting a gl_renderbuffer.
68 static struct gl_renderbuffer
*
69 lookup_renderbuffer(GLcontext
*ctx
, GLuint id
)
71 struct gl_renderbuffer
*rb
;
76 rb
= (struct gl_renderbuffer
*)
77 _mesa_HashLookup(ctx
->Shared
->RenderBuffers
, id
);
83 * Helper routine for getting a gl_framebuffer.
85 static struct gl_framebuffer
*
86 lookup_framebuffer(GLcontext
*ctx
, GLuint id
)
88 struct gl_framebuffer
*fb
;
93 fb
= (struct gl_framebuffer
*)
94 _mesa_HashLookup(ctx
->Shared
->FrameBuffers
, id
);
100 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
101 * gl_renderbuffer_attachment object.
103 static struct gl_renderbuffer_attachment
*
104 get_attachment(GLcontext
*ctx
, struct gl_framebuffer
*fb
, GLenum attachment
)
108 switch (attachment
) {
109 case GL_COLOR_ATTACHMENT0_EXT
:
110 case GL_COLOR_ATTACHMENT1_EXT
:
111 case GL_COLOR_ATTACHMENT2_EXT
:
112 case GL_COLOR_ATTACHMENT3_EXT
:
113 case GL_COLOR_ATTACHMENT4_EXT
:
114 case GL_COLOR_ATTACHMENT5_EXT
:
115 case GL_COLOR_ATTACHMENT6_EXT
:
116 case GL_COLOR_ATTACHMENT7_EXT
:
117 case GL_COLOR_ATTACHMENT8_EXT
:
118 case GL_COLOR_ATTACHMENT9_EXT
:
119 case GL_COLOR_ATTACHMENT10_EXT
:
120 case GL_COLOR_ATTACHMENT11_EXT
:
121 case GL_COLOR_ATTACHMENT12_EXT
:
122 case GL_COLOR_ATTACHMENT13_EXT
:
123 case GL_COLOR_ATTACHMENT14_EXT
:
124 case GL_COLOR_ATTACHMENT15_EXT
:
125 i
= attachment
- GL_COLOR_ATTACHMENT0_EXT
;
126 if (i
>= ctx
->Const
.MaxColorAttachments
) {
129 return &fb
->Attachment
[BUFFER_COLOR0
+ i
];
130 case GL_DEPTH_ATTACHMENT_EXT
:
131 return &fb
->Attachment
[BUFFER_DEPTH
];
132 case GL_STENCIL_ATTACHMENT_EXT
:
133 return &fb
->Attachment
[BUFFER_STENCIL
];
141 * Remove any texture or renderbuffer attached to the given attachment
142 * point. Update reference counts, etc.
145 _mesa_remove_attachment(GLcontext
*ctx
, struct gl_renderbuffer_attachment
*att
)
147 if (att
->Type
== GL_TEXTURE
) {
148 ASSERT(att
->Texture
);
149 if (att
->Renderbuffer
) {
150 /* delete/remove the 'wrapper' renderbuffer */
151 /* XXX do we really want to do this??? */
152 att
->Renderbuffer
->Delete(att
->Renderbuffer
);
153 att
->Renderbuffer
= NULL
;
155 att
->Texture
->RefCount
--;
156 if (att
->Texture
->RefCount
== 0) {
157 ctx
->Driver
.DeleteTexture(ctx
, att
->Texture
);
161 else if (att
->Type
== GL_RENDERBUFFER_EXT
) {
162 ASSERT(att
->Renderbuffer
);
163 ASSERT(!att
->Texture
);
164 att
->Renderbuffer
->RefCount
--;
165 if (att
->Renderbuffer
->RefCount
== 0) {
166 att
->Renderbuffer
->Delete(att
->Renderbuffer
);
168 att
->Renderbuffer
= NULL
;
171 att
->Complete
= GL_TRUE
;
176 * Bind a texture object to an attachment point.
177 * The previous binding, if any, will be removed first.
180 _mesa_set_texture_attachment(GLcontext
*ctx
,
181 struct gl_renderbuffer_attachment
*att
,
182 struct gl_texture_object
*texObj
,
183 GLenum texTarget
, GLuint level
, GLuint zoffset
)
185 _mesa_remove_attachment(ctx
, att
);
186 att
->Type
= GL_TEXTURE
;
187 att
->Texture
= texObj
;
188 att
->TextureLevel
= level
;
189 if (IS_CUBE_FACE(texTarget
)) {
190 att
->CubeMapFace
= texTarget
- GL_TEXTURE_CUBE_MAP_POSITIVE_X
;
193 att
->CubeMapFace
= 0;
195 att
->Zoffset
= zoffset
;
196 att
->Complete
= GL_FALSE
;
200 /* XXX when we attach to a texture, we should probably set the
201 * att->Renderbuffer pointer to a "wrapper renderbuffer" which
202 * makes the texture image look like renderbuffer.
208 * Bind a renderbuffer to an attachment point.
209 * The previous binding, if any, will be removed first.
212 _mesa_set_renderbuffer_attachment(GLcontext
*ctx
,
213 struct gl_renderbuffer_attachment
*att
,
214 struct gl_renderbuffer
*rb
)
216 _mesa_remove_attachment(ctx
, att
);
217 att
->Type
= GL_RENDERBUFFER_EXT
;
218 att
->Renderbuffer
= rb
;
219 att
->Texture
= NULL
; /* just to be safe */
220 att
->Complete
= GL_FALSE
;
226 * Fallback for ctx->Driver.FramebufferRenderbuffer()
227 * Sets a framebuffer attachment to a particular renderbuffer.
228 * The framebuffer in question is ctx->DrawBuffer.
229 * \sa _mesa_renderbuffer_texture
232 _mesa_framebuffer_renderbuffer(GLcontext
*ctx
,
233 struct gl_renderbuffer_attachment
*att
,
234 struct gl_renderbuffer
*rb
)
237 _mesa_set_renderbuffer_attachment(ctx
, att
, rb
);
240 _mesa_remove_attachment(ctx
, att
);
246 * Test if an attachment point is complete and update its Complete field.
247 * \param format if GL_COLOR, this is a color attachment point,
248 * if GL_DEPTH, this is a depth component attachment point,
249 * if GL_STENCIL, this is a stencil component attachment point.
252 test_attachment_completeness(const GLcontext
*ctx
, GLenum format
,
253 struct gl_renderbuffer_attachment
*att
)
255 assert(format
== GL_COLOR
|| format
== GL_DEPTH
|| format
== GL_STENCIL
);
257 /* assume complete */
258 att
->Complete
= GL_TRUE
;
260 /* Look for reasons why the attachment might be incomplete */
261 if (att
->Type
== GL_TEXTURE
) {
262 const struct gl_texture_object
*texObj
= att
->Texture
;
263 struct gl_texture_image
*texImage
;
266 att
->Complete
= GL_FALSE
;
270 texImage
= texObj
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
272 att
->Complete
= GL_FALSE
;
275 if (texImage
->Width
< 1 || texImage
->Height
< 1) {
276 att
->Complete
= GL_FALSE
;
279 if (texObj
->Target
== GL_TEXTURE_3D
&& att
->Zoffset
>= texImage
->Depth
) {
280 att
->Complete
= GL_FALSE
;
284 if (format
== GL_COLOR
) {
285 if (texImage
->TexFormat
->BaseFormat
!= GL_RGB
&&
286 texImage
->TexFormat
->BaseFormat
!= GL_RGBA
) {
287 att
->Complete
= GL_FALSE
;
291 else if (format
== GL_DEPTH
) {
292 if (texImage
->TexFormat
->BaseFormat
!= GL_DEPTH_COMPONENT
) {
293 att
->Complete
= GL_FALSE
;
298 /* no such thing as stencil textures */
299 att
->Complete
= GL_FALSE
;
303 else if (att
->Type
== GL_RENDERBUFFER_EXT
) {
304 if (att
->Renderbuffer
->Width
< 1 || att
->Renderbuffer
->Height
< 1) {
305 att
->Complete
= GL_FALSE
;
308 if (format
== GL_COLOR
) {
309 if (att
->Renderbuffer
->_BaseFormat
!= GL_RGB
&&
310 att
->Renderbuffer
->_BaseFormat
!= GL_RGBA
) {
311 att
->Complete
= GL_FALSE
;
315 else if (format
== GL_DEPTH
) {
316 if (att
->Renderbuffer
->_BaseFormat
!= GL_DEPTH_COMPONENT
) {
317 att
->Complete
= GL_FALSE
;
322 assert(format
== GL_STENCIL
);
323 if (att
->Renderbuffer
->_BaseFormat
!= GL_STENCIL_INDEX
) {
324 att
->Complete
= GL_FALSE
;
330 ASSERT(att
->Type
== GL_NONE
);
338 * Test if the given framebuffer object is complete and update its
339 * Status field with the results.
340 * Also update the framebuffer's Width and Height fields if the
341 * framebuffer is complete.
344 _mesa_test_framebuffer_completeness(GLcontext
*ctx
, struct gl_framebuffer
*fb
)
346 GLuint numImages
, width
= 0, height
= 0;
347 GLenum intFormat
= GL_NONE
;
351 assert(fb
->Name
!= 0);
357 /* Start at -2 to more easily loop over all attachment points */
358 for (i
= -2; i
< (GLint
) ctx
->Const
.MaxColorAttachments
; i
++) {
359 struct gl_renderbuffer_attachment
*att
;
363 att
= &fb
->Attachment
[BUFFER_DEPTH
];
364 test_attachment_completeness(ctx
, GL_DEPTH
, att
);
365 if (!att
->Complete
) {
366 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
;
371 att
= &fb
->Attachment
[BUFFER_STENCIL
];
372 test_attachment_completeness(ctx
, GL_STENCIL
, att
);
373 if (!att
->Complete
) {
374 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
;
379 att
= &fb
->Attachment
[BUFFER_COLOR0
+ i
];
380 test_attachment_completeness(ctx
, GL_COLOR
, att
);
381 if (!att
->Complete
) {
382 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
;
387 if (att
->Type
== GL_TEXTURE
) {
388 w
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
]->Width
;
389 h
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
]->Height
;
390 f
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
]->Format
;
393 else if (att
->Type
== GL_RENDERBUFFER_EXT
) {
394 w
= att
->Renderbuffer
->Width
;
395 h
= att
->Renderbuffer
->Height
;
396 f
= att
->Renderbuffer
->InternalFormat
;
400 assert(att
->Type
== GL_NONE
);
404 if (numImages
== 1) {
405 /* set required width, height and format */
412 /* check that width, height, format are same */
413 if (w
!= width
|| h
!= height
) {
414 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
;
417 if (intFormat
!= GL_NONE
&& f
!= intFormat
) {
418 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT
;
424 /* Check that all DrawBuffers are present */
425 for (i
= 0; i
< ctx
->Const
.MaxDrawBuffers
; i
++) {
426 if (fb
->ColorDrawBuffer
[i
] != GL_NONE
) {
427 const struct gl_renderbuffer_attachment
*att
428 = get_attachment(ctx
, fb
, fb
->ColorDrawBuffer
[i
]);
430 if (att
->Type
== GL_NONE
) {
431 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT
;
437 /* Check that the ReadBuffer is present */
438 if (fb
->ColorReadBuffer
!= GL_NONE
) {
439 const struct gl_renderbuffer_attachment
*att
440 = get_attachment(ctx
, fb
, fb
->ColorReadBuffer
);
442 if (att
->Type
== GL_NONE
) {
443 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT
;
448 /* Check if any renderbuffer is attached more than once */
449 for (i
= 0; i
< BUFFER_COUNT
- 1; i
++) {
450 struct gl_renderbuffer
*rb_i
= fb
->Attachment
[i
].Renderbuffer
;
453 for (j
= i
+ 1; j
< BUFFER_COUNT
; j
++) {
454 struct gl_renderbuffer
*rb_j
= fb
->Attachment
[j
].Renderbuffer
;
456 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
;
464 if (numImages
== 0) {
465 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT
;
470 * If we get here, the framebuffer is complete!
472 fb
->_Status
= GL_FRAMEBUFFER_COMPLETE_EXT
;
479 _mesa_IsRenderbufferEXT(GLuint renderbuffer
)
481 GET_CURRENT_CONTEXT(ctx
);
482 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
483 if (renderbuffer
&& lookup_renderbuffer(ctx
, renderbuffer
))
491 _mesa_BindRenderbufferEXT(GLenum target
, GLuint renderbuffer
)
493 struct gl_renderbuffer
*newRb
, *oldRb
;
494 GET_CURRENT_CONTEXT(ctx
);
496 ASSERT_OUTSIDE_BEGIN_END(ctx
);
497 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
);
499 if (target
!= GL_RENDERBUFFER_EXT
) {
500 _mesa_error(ctx
, GL_INVALID_ENUM
,
501 "glBindRenderbufferEXT(target)");
506 newRb
= lookup_renderbuffer(ctx
, renderbuffer
);
507 if (newRb
== &DummyRenderbuffer
) {
508 /* ID was reserved, but no real renderbuffer object made yet */
512 /* create new renderbuffer object */
513 newRb
= ctx
->Driver
.NewRenderbuffer(ctx
, renderbuffer
);
515 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindRenderbufferEXT");
518 ASSERT(newRb
->AllocStorage
);
519 _mesa_HashInsert(ctx
->Shared
->RenderBuffers
, renderbuffer
, newRb
);
527 oldRb
= ctx
->CurrentRenderbuffer
;
530 if (oldRb
->RefCount
== 0) {
531 oldRb
->Delete(oldRb
);
535 ASSERT(newRb
!= &DummyRenderbuffer
);
537 ctx
->CurrentRenderbuffer
= newRb
;
542 _mesa_DeleteRenderbuffersEXT(GLsizei n
, const GLuint
*renderbuffers
)
545 GET_CURRENT_CONTEXT(ctx
);
547 ASSERT_OUTSIDE_BEGIN_END(ctx
);
549 for (i
= 0; i
< n
; i
++) {
550 if (renderbuffers
[i
] > 0) {
551 struct gl_renderbuffer
*rb
;
552 rb
= lookup_renderbuffer(ctx
, renderbuffers
[i
]);
554 /* remove from hash table immediately, to free the ID */
555 _mesa_HashRemove(ctx
->Shared
->RenderBuffers
, renderbuffers
[i
]);
557 if (rb
!= &DummyRenderbuffer
) {
558 /* But the object will not be freed until it's no longer
559 * bound in any context.
562 if (rb
->RefCount
== 0) {
573 _mesa_GenRenderbuffersEXT(GLsizei n
, GLuint
*renderbuffers
)
575 GET_CURRENT_CONTEXT(ctx
);
579 ASSERT_OUTSIDE_BEGIN_END(ctx
);
582 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenRenderbuffersEXT(n)");
589 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->RenderBuffers
, n
);
591 for (i
= 0; i
< n
; i
++) {
592 GLuint name
= first
+ i
;
593 renderbuffers
[i
] = name
;
594 /* insert dummy placeholder into hash table */
595 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
596 _mesa_HashInsert(ctx
->Shared
->RenderBuffers
, name
, &DummyRenderbuffer
);
597 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
603 * Given an internal format token for a render buffer, return the
604 * corresponding base format.
605 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
609 base_internal_format(GLcontext
*ctx
, GLenum internalFormat
)
611 switch (internalFormat
) {
630 case GL_STENCIL_INDEX
:
631 case GL_STENCIL_INDEX1_EXT
:
632 case GL_STENCIL_INDEX4_EXT
:
633 case GL_STENCIL_INDEX8_EXT
:
634 case GL_STENCIL_INDEX16_EXT
:
635 return GL_STENCIL_INDEX
;
636 case GL_DEPTH_COMPONENT
:
637 case GL_DEPTH_COMPONENT16
:
638 case GL_DEPTH_COMPONENT24
:
639 case GL_DEPTH_COMPONENT32
:
640 return GL_DEPTH_COMPONENT
;
641 /* XXX add floating point formats eventually */
649 _mesa_RenderbufferStorageEXT(GLenum target
, GLenum internalFormat
,
650 GLsizei width
, GLsizei height
)
652 struct gl_renderbuffer
*rb
;
654 GET_CURRENT_CONTEXT(ctx
);
656 ASSERT_OUTSIDE_BEGIN_END(ctx
);
657 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
);
659 if (target
!= GL_RENDERBUFFER_EXT
) {
660 _mesa_error(ctx
, GL_INVALID_ENUM
, "glRenderbufferStorageEXT(target)");
664 baseFormat
= base_internal_format(ctx
, internalFormat
);
665 if (baseFormat
== 0) {
666 _mesa_error(ctx
, GL_INVALID_ENUM
,
667 "glRenderbufferStorageEXT(internalFormat)");
671 if (width
< 1 || width
> ctx
->Const
.MaxRenderbufferSize
) {
672 _mesa_error(ctx
, GL_INVALID_VALUE
, "glRenderbufferStorageEXT(width)");
676 if (height
< 1 || height
> ctx
->Const
.MaxRenderbufferSize
) {
677 _mesa_error(ctx
, GL_INVALID_VALUE
, "glRenderbufferStorageEXT(height)");
681 rb
= ctx
->CurrentRenderbuffer
;
684 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glRenderbufferStorageEXT");
688 /* Now allocate the storage */
689 ASSERT(rb
->AllocStorage
);
690 if (rb
->AllocStorage(ctx
, rb
, internalFormat
, width
, height
)) {
691 /* No error - check/set fields now */
692 assert(rb
->Width
== width
);
693 assert(rb
->Height
== height
);
694 assert(rb
->InternalFormat
);
695 rb
->_BaseFormat
= baseFormat
;
698 /* Probably ran out of memory - clear the fields */
701 rb
->InternalFormat
= GL_NONE
;
702 rb
->_BaseFormat
= GL_NONE
;
706 test_framebuffer_completeness(ctx, fb);
708 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
715 _mesa_GetRenderbufferParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
717 GET_CURRENT_CONTEXT(ctx
);
719 ASSERT_OUTSIDE_BEGIN_END(ctx
);
721 if (target
!= GL_RENDERBUFFER_EXT
) {
722 _mesa_error(ctx
, GL_INVALID_ENUM
,
723 "glGetRenderbufferParameterivEXT(target)");
727 if (!ctx
->CurrentRenderbuffer
) {
728 _mesa_error(ctx
, GL_INVALID_OPERATION
,
729 "glGetRenderbufferParameterivEXT");
734 case GL_RENDERBUFFER_WIDTH_EXT
:
735 *params
= ctx
->CurrentRenderbuffer
->Width
;
737 case GL_RENDERBUFFER_HEIGHT_EXT
:
738 *params
= ctx
->CurrentRenderbuffer
->Height
;
740 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT
:
741 *params
= ctx
->CurrentRenderbuffer
->InternalFormat
;
743 case GL_RENDERBUFFER_RED_SIZE_EXT
:
744 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGB
||
745 ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGBA
) {
746 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[0];
752 case GL_RENDERBUFFER_GREEN_SIZE_EXT
:
753 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGB
||
754 ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGBA
) {
755 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[1];
761 case GL_RENDERBUFFER_BLUE_SIZE_EXT
:
762 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGB
||
763 ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGBA
) {
764 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[2];
770 case GL_RENDERBUFFER_ALPHA_SIZE_EXT
:
771 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGB
||
772 ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGBA
) {
773 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[3];
779 case GL_RENDERBUFFER_DEPTH_SIZE_EXT
:
780 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_DEPTH_COMPONENT
) {
781 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[0];
787 case GL_RENDERBUFFER_STENCIL_SIZE_EXT
:
788 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_STENCIL_INDEX
) {
789 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[0];
797 _mesa_error(ctx
, GL_INVALID_ENUM
,
798 "glGetRenderbufferParameterivEXT(target)");
805 _mesa_IsFramebufferEXT(GLuint framebuffer
)
807 GET_CURRENT_CONTEXT(ctx
);
808 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
809 if (framebuffer
&& lookup_framebuffer(ctx
, framebuffer
))
817 _mesa_BindFramebufferEXT(GLenum target
, GLuint framebuffer
)
819 struct gl_framebuffer
*newFb
, *newReadFb
, *oldFb
;
820 GET_CURRENT_CONTEXT(ctx
);
822 ASSERT_OUTSIDE_BEGIN_END(ctx
);
823 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
);
825 if (target
!= GL_FRAMEBUFFER_EXT
) {
826 _mesa_error(ctx
, GL_INVALID_ENUM
,
827 "glBindFramebufferEXT(target)");
832 /* Binding a user-created framebuffer object */
833 newFb
= lookup_framebuffer(ctx
, framebuffer
);
834 if (newFb
== &DummyFramebuffer
) {
835 /* ID was reserved, but no real framebuffer object made yet */
839 /* create new framebuffer object */
840 newFb
= ctx
->Driver
.NewFramebuffer(ctx
, framebuffer
);
842 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindFramebufferEXT");
845 _mesa_HashInsert(ctx
->Shared
->FrameBuffers
, framebuffer
, newFb
);
851 /* Binding the window system framebuffer (which was originally set
854 newFb
= ctx
->WinSysDrawBuffer
;
855 newReadFb
= ctx
->WinSysReadBuffer
;
858 oldFb
= ctx
->DrawBuffer
;
859 if (oldFb
) { /* AND oldFb->Name != 0 */
861 if (oldFb
->RefCount
== 0) {
862 oldFb
->Delete(oldFb
);
866 ASSERT(newFb
!= &DummyFramebuffer
);
868 /* Note, we set both the GL_DRAW_BUFFER and GL_READ_BUFFER state: */
869 ctx
->DrawBuffer
= newFb
;
870 ctx
->ReadBuffer
= newReadFb
;
875 _mesa_DeleteFramebuffersEXT(GLsizei n
, const GLuint
*framebuffers
)
878 GET_CURRENT_CONTEXT(ctx
);
880 ASSERT_OUTSIDE_BEGIN_END(ctx
);
882 for (i
= 0; i
< n
; i
++) {
883 if (framebuffers
[i
] > 0) {
884 struct gl_framebuffer
*fb
;
885 fb
= lookup_framebuffer(ctx
, framebuffers
[i
]);
887 ASSERT(fb
== &DummyFramebuffer
|| fb
->Name
== framebuffers
[i
]);
888 /* remove from hash table immediately, to free the ID */
889 _mesa_HashRemove(ctx
->Shared
->FrameBuffers
, framebuffers
[i
]);
891 if (fb
!= &DummyFramebuffer
) {
892 /* But the object will not be freed until it's no longer
893 * bound in any context.
896 if (fb
->RefCount
== 0) {
907 _mesa_GenFramebuffersEXT(GLsizei n
, GLuint
*framebuffers
)
909 GET_CURRENT_CONTEXT(ctx
);
913 ASSERT_OUTSIDE_BEGIN_END(ctx
);
916 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenFramebuffersEXT(n)");
923 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->FrameBuffers
, n
);
925 for (i
= 0; i
< n
; i
++) {
926 GLuint name
= first
+ i
;
927 framebuffers
[i
] = name
;
928 /* insert dummy placeholder into hash table */
929 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
930 _mesa_HashInsert(ctx
->Shared
->FrameBuffers
, name
, &DummyFramebuffer
);
931 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
938 _mesa_CheckFramebufferStatusEXT(GLenum target
)
940 GET_CURRENT_CONTEXT(ctx
);
942 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, 0);
944 if (target
!= GL_FRAMEBUFFER_EXT
) {
945 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCheckFramebufferStatus(target)");
946 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
949 if (ctx
->DrawBuffer
->Name
== 0) {
950 /* The window system / default framebuffer is always complete */
951 return GL_FRAMEBUFFER_COMPLETE_EXT
;
954 _mesa_test_framebuffer_completeness(ctx
, ctx
->DrawBuffer
);
955 return ctx
->DrawBuffer
->_Status
;
961 * Do error checking common to glFramebufferTexture1D/2D/3DEXT.
962 * \return GL_TRUE if any error, GL_FALSE otherwise
965 error_check_framebuffer_texture(GLcontext
*ctx
, GLuint dims
,
966 GLenum target
, GLenum attachment
,
967 GLenum textarget
, GLuint texture
, GLint level
)
969 ASSERT(dims
>= 1 && dims
<= 3);
971 if (target
!= GL_FRAMEBUFFER_EXT
) {
972 _mesa_error(ctx
, GL_INVALID_ENUM
,
973 "glFramebufferTexture%dDEXT(target)", dims
);
977 /* check framebuffer binding */
978 if (ctx
->DrawBuffer
->Name
== 0) {
979 _mesa_error(ctx
, GL_INVALID_OPERATION
,
980 "glFramebufferTexture%dDEXT", dims
);
984 /* only check textarget, level if texture ID is non-zero */
986 if ((dims
== 1 && textarget
!= GL_TEXTURE_1D
) ||
987 (dims
== 3 && textarget
!= GL_TEXTURE_3D
) ||
988 (dims
== 2 && textarget
!= GL_TEXTURE_2D
&&
989 textarget
!= GL_TEXTURE_RECTANGLE_ARB
&&
990 !IS_CUBE_FACE(textarget
))) {
991 _mesa_error(ctx
, GL_INVALID_VALUE
,
992 "glFramebufferTexture%dDEXT(textarget)", dims
);
996 if ((level
< 0) || level
>= _mesa_max_texture_levels(ctx
, textarget
)) {
997 _mesa_error(ctx
, GL_INVALID_VALUE
,
998 "glFramebufferTexture%dDEXT(level)", dims
);
1008 _mesa_FramebufferTexture1DEXT(GLenum target
, GLenum attachment
,
1009 GLenum textarget
, GLuint texture
, GLint level
)
1011 struct gl_renderbuffer_attachment
*att
;
1012 struct gl_texture_object
*texObj
;
1013 GET_CURRENT_CONTEXT(ctx
);
1015 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1016 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
); /* XXX check */
1018 if (error_check_framebuffer_texture(ctx
, 1, target
, attachment
,
1019 textarget
, texture
, level
))
1022 ASSERT(textarget
== GL_TEXTURE_1D
);
1024 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1026 _mesa_error(ctx
, GL_INVALID_ENUM
,
1027 "glFramebufferTexture1DEXT(attachment)");
1032 texObj
= (struct gl_texture_object
*)
1033 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1035 _mesa_error(ctx
, GL_INVALID_VALUE
,
1036 "glFramebufferTexture1DEXT(texture)");
1039 if (texObj
->Target
!= textarget
) {
1040 _mesa_error(ctx
, GL_INVALID_OPERATION
, /* XXX correct error? */
1041 "glFramebufferTexture1DEXT(texture target)");
1046 /* remove texture attachment */
1049 ctx
->Driver
.RenderbufferTexture(ctx
, att
, texObj
, textarget
, level
, 0);
1054 _mesa_FramebufferTexture2DEXT(GLenum target
, GLenum attachment
,
1055 GLenum textarget
, GLuint texture
, GLint level
)
1057 struct gl_renderbuffer_attachment
*att
;
1058 struct gl_texture_object
*texObj
;
1059 GET_CURRENT_CONTEXT(ctx
);
1061 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1062 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
); /* XXX check */
1064 if (error_check_framebuffer_texture(ctx
, 2, target
, attachment
,
1065 textarget
, texture
, level
))
1068 ASSERT(textarget
== GL_TEXTURE_2D
||
1069 textarget
== GL_TEXTURE_RECTANGLE_ARB
||
1070 IS_CUBE_FACE(textarget
));
1072 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1074 _mesa_error(ctx
, GL_INVALID_ENUM
,
1075 "glFramebufferTexture2DEXT(attachment)");
1080 texObj
= (struct gl_texture_object
*)
1081 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1083 _mesa_error(ctx
, GL_INVALID_VALUE
,
1084 "glFramebufferTexture2DEXT(texture)");
1087 if ((texObj
->Target
== GL_TEXTURE_2D
&& textarget
!= GL_TEXTURE_2D
) ||
1088 (texObj
->Target
== GL_TEXTURE_RECTANGLE_ARB
1089 && textarget
!= GL_TEXTURE_RECTANGLE_ARB
) ||
1090 (texObj
->Target
== GL_TEXTURE_CUBE_MAP
1091 && !IS_CUBE_FACE(textarget
))) {
1092 _mesa_error(ctx
, GL_INVALID_OPERATION
, /* XXX correct error? */
1093 "glFramebufferTexture2DEXT(texture target)");
1098 /* remove texture attachment */
1101 ctx
->Driver
.RenderbufferTexture(ctx
, att
, texObj
, textarget
, level
, 0);
1106 _mesa_FramebufferTexture3DEXT(GLenum target
, GLenum attachment
,
1107 GLenum textarget
, GLuint texture
,
1108 GLint level
, GLint zoffset
)
1110 struct gl_renderbuffer_attachment
*att
;
1111 struct gl_texture_object
*texObj
;
1112 GET_CURRENT_CONTEXT(ctx
);
1114 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1115 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
); /* XXX check */
1117 if (error_check_framebuffer_texture(ctx
, 3, target
, attachment
,
1118 textarget
, texture
, level
))
1121 ASSERT(textarget
== GL_TEXTURE_3D
);
1123 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1125 _mesa_error(ctx
, GL_INVALID_ENUM
,
1126 "glFramebufferTexture1DEXT(attachment)");
1131 const GLint maxSize
= 1 << (ctx
->Const
.Max3DTextureLevels
- 1);
1132 texObj
= (struct gl_texture_object
*)
1133 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1135 _mesa_error(ctx
, GL_INVALID_VALUE
,
1136 "glFramebufferTexture3DEXT(texture)");
1139 if (texObj
->Target
!= textarget
) {
1140 _mesa_error(ctx
, GL_INVALID_OPERATION
, /* XXX correct error? */
1141 "glFramebufferTexture3DEXT(texture target)");
1144 if (zoffset
< 0 || zoffset
>= maxSize
) {
1145 _mesa_error(ctx
, GL_INVALID_VALUE
,
1146 "glFramebufferTexture3DEXT(zoffset)");
1151 /* remove texture attachment */
1154 ctx
->Driver
.RenderbufferTexture(ctx
, att
, texObj
, textarget
,
1160 _mesa_FramebufferRenderbufferEXT(GLenum target
, GLenum attachment
,
1161 GLenum renderbufferTarget
,
1162 GLuint renderbuffer
)
1164 struct gl_renderbuffer_attachment
*att
;
1165 struct gl_renderbuffer
*rb
;
1166 GET_CURRENT_CONTEXT(ctx
);
1168 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1169 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
);
1171 if (target
!= GL_FRAMEBUFFER_EXT
) {
1172 _mesa_error(ctx
, GL_INVALID_ENUM
,
1173 "glFramebufferRenderbufferEXT(target)");
1177 if (renderbufferTarget
!= GL_RENDERBUFFER_EXT
) {
1178 _mesa_error(ctx
, GL_INVALID_ENUM
,
1179 "glFramebufferRenderbufferEXT(renderbufferTarget)");
1183 if (ctx
->DrawBuffer
->Name
== 0) {
1184 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glFramebufferRenderbufferEXT");
1188 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1190 _mesa_error(ctx
, GL_INVALID_ENUM
,
1191 "glFramebufferRenderbufferEXT(attachment)");
1196 rb
= lookup_renderbuffer(ctx
, renderbuffer
);
1198 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1199 "glFramebufferRenderbufferEXT(renderbuffer)");
1204 /* remove renderbuffer attachment */
1208 assert(ctx
->Driver
.FramebufferRenderbuffer
);
1209 ctx
->Driver
.FramebufferRenderbuffer(ctx
, att
, rb
);
1211 _mesa_update_framebuffer_visual(ctx
->DrawBuffer
);
1216 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target
, GLenum attachment
,
1217 GLenum pname
, GLint
*params
)
1219 const struct gl_renderbuffer_attachment
*att
;
1220 GET_CURRENT_CONTEXT(ctx
);
1222 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1224 if (target
!= GL_FRAMEBUFFER_EXT
) {
1225 _mesa_error(ctx
, GL_INVALID_ENUM
,
1226 "glGetFramebufferAttachmentParameterivEXT(target)");
1230 if (ctx
->DrawBuffer
->Name
== 0) {
1231 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1232 "glGetFramebufferAttachmentParameterivEXT");
1236 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1238 _mesa_error(ctx
, GL_INVALID_ENUM
,
1239 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1244 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT
:
1245 *params
= att
->Type
;
1247 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
:
1248 if (att
->Type
== GL_RENDERBUFFER_EXT
) {
1249 *params
= att
->Renderbuffer
->Name
;
1251 else if (att
->Type
== GL_TEXTURE
) {
1252 *params
= att
->Texture
->Name
;
1255 _mesa_error(ctx
, GL_INVALID_ENUM
,
1256 "glGetFramebufferAttachmentParameterivEXT(pname)");
1259 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT
:
1260 if (att
->Type
== GL_TEXTURE
) {
1261 *params
= att
->TextureLevel
;
1264 _mesa_error(ctx
, GL_INVALID_ENUM
,
1265 "glGetFramebufferAttachmentParameterivEXT(pname)");
1268 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT
:
1269 if (att
->Type
== GL_TEXTURE
) {
1270 *params
= GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ att
->CubeMapFace
;
1273 _mesa_error(ctx
, GL_INVALID_ENUM
,
1274 "glGetFramebufferAttachmentParameterivEXT(pname)");
1277 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT
:
1278 if (att
->Type
== GL_TEXTURE
) {
1279 *params
= att
->Zoffset
;
1282 _mesa_error(ctx
, GL_INVALID_ENUM
,
1283 "glGetFramebufferAttachmentParameterivEXT(pname)");
1287 _mesa_error(ctx
, GL_INVALID_ENUM
,
1288 "glGetFramebufferAttachmentParameterivEXT(pname)");
1295 _mesa_GenerateMipmapEXT(GLenum target
)
1297 struct gl_texture_unit
*texUnit
;
1298 struct gl_texture_object
*texObj
;
1299 GET_CURRENT_CONTEXT(ctx
);
1301 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1307 case GL_TEXTURE_CUBE_MAP
:
1308 /* OK, legal value */
1311 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGenerateMipmapEXT(target)");
1315 texUnit
= &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
];
1316 texObj
= _mesa_select_tex_object(ctx
, texUnit
, target
);
1318 /* XXX this might not handle cube maps correctly */
1319 _mesa_generate_mipmap(ctx
, target
, texUnit
, texObj
);