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
;
392 if (f
!= GL_RGB
&& f
!= GL_RGBA
&& f
!= GL_DEPTH_COMPONENT
) {
393 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT
;
397 else if (att
->Type
== GL_RENDERBUFFER_EXT
) {
398 w
= att
->Renderbuffer
->Width
;
399 h
= att
->Renderbuffer
->Height
;
400 f
= att
->Renderbuffer
->InternalFormat
;
404 assert(att
->Type
== GL_NONE
);
408 if (numImages
== 1) {
409 /* set required width, height and format */
416 /* check that width, height, format are same */
417 if (w
!= width
|| h
!= height
) {
418 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
;
421 if (intFormat
!= GL_NONE
&& f
!= intFormat
) {
422 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT
;
428 /* Check that all DrawBuffers are present */
429 for (i
= 0; i
< ctx
->Const
.MaxDrawBuffers
; i
++) {
430 if (fb
->ColorDrawBuffer
[i
] != GL_NONE
) {
431 const struct gl_renderbuffer_attachment
*att
432 = get_attachment(ctx
, fb
, fb
->ColorDrawBuffer
[i
]);
434 if (att
->Type
== GL_NONE
) {
435 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT
;
441 /* Check that the ReadBuffer is present */
442 if (fb
->ColorReadBuffer
!= GL_NONE
) {
443 const struct gl_renderbuffer_attachment
*att
444 = get_attachment(ctx
, fb
, fb
->ColorReadBuffer
);
446 if (att
->Type
== GL_NONE
) {
447 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT
;
452 /* Check if any renderbuffer is attached more than once */
453 for (i
= 0; i
< BUFFER_COUNT
- 1; i
++) {
454 struct gl_renderbuffer
*rb_i
= fb
->Attachment
[i
].Renderbuffer
;
457 for (j
= i
+ 1; j
< BUFFER_COUNT
; j
++) {
458 struct gl_renderbuffer
*rb_j
= fb
->Attachment
[j
].Renderbuffer
;
460 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
;
468 if (numImages
== 0) {
469 fb
->_Status
= GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT
;
474 * If we get here, the framebuffer is complete!
476 fb
->_Status
= GL_FRAMEBUFFER_COMPLETE_EXT
;
483 _mesa_IsRenderbufferEXT(GLuint renderbuffer
)
485 GET_CURRENT_CONTEXT(ctx
);
486 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
487 if (renderbuffer
&& lookup_renderbuffer(ctx
, renderbuffer
))
495 _mesa_BindRenderbufferEXT(GLenum target
, GLuint renderbuffer
)
497 struct gl_renderbuffer
*newRb
, *oldRb
;
498 GET_CURRENT_CONTEXT(ctx
);
500 ASSERT_OUTSIDE_BEGIN_END(ctx
);
501 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
);
503 if (target
!= GL_RENDERBUFFER_EXT
) {
504 _mesa_error(ctx
, GL_INVALID_ENUM
,
505 "glBindRenderbufferEXT(target)");
510 newRb
= lookup_renderbuffer(ctx
, renderbuffer
);
511 if (newRb
== &DummyRenderbuffer
) {
512 /* ID was reserved, but no real renderbuffer object made yet */
516 /* create new renderbuffer object */
517 newRb
= ctx
->Driver
.NewRenderbuffer(ctx
, renderbuffer
);
519 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindRenderbufferEXT");
522 ASSERT(newRb
->AllocStorage
);
523 _mesa_HashInsert(ctx
->Shared
->RenderBuffers
, renderbuffer
, newRb
);
531 oldRb
= ctx
->CurrentRenderbuffer
;
534 if (oldRb
->RefCount
== 0) {
535 oldRb
->Delete(oldRb
);
539 ASSERT(newRb
!= &DummyRenderbuffer
);
541 ctx
->CurrentRenderbuffer
= newRb
;
546 _mesa_DeleteRenderbuffersEXT(GLsizei n
, const GLuint
*renderbuffers
)
549 GET_CURRENT_CONTEXT(ctx
);
551 ASSERT_OUTSIDE_BEGIN_END(ctx
);
553 for (i
= 0; i
< n
; i
++) {
554 if (renderbuffers
[i
] > 0) {
555 struct gl_renderbuffer
*rb
;
556 rb
= lookup_renderbuffer(ctx
, renderbuffers
[i
]);
558 /* remove from hash table immediately, to free the ID */
559 _mesa_HashRemove(ctx
->Shared
->RenderBuffers
, renderbuffers
[i
]);
561 if (rb
!= &DummyRenderbuffer
) {
562 /* But the object will not be freed until it's no longer
563 * bound in any context.
566 if (rb
->RefCount
== 0) {
577 _mesa_GenRenderbuffersEXT(GLsizei n
, GLuint
*renderbuffers
)
579 GET_CURRENT_CONTEXT(ctx
);
583 ASSERT_OUTSIDE_BEGIN_END(ctx
);
586 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenRenderbuffersEXT(n)");
593 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->RenderBuffers
, n
);
595 for (i
= 0; i
< n
; i
++) {
596 GLuint name
= first
+ i
;
597 renderbuffers
[i
] = name
;
598 /* insert dummy placeholder into hash table */
599 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
600 _mesa_HashInsert(ctx
->Shared
->RenderBuffers
, name
, &DummyRenderbuffer
);
601 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
607 * Given an internal format token for a render buffer, return the
608 * corresponding base format.
609 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
613 base_internal_format(GLcontext
*ctx
, GLenum internalFormat
)
615 switch (internalFormat
) {
634 case GL_STENCIL_INDEX
:
635 case GL_STENCIL_INDEX1_EXT
:
636 case GL_STENCIL_INDEX4_EXT
:
637 case GL_STENCIL_INDEX8_EXT
:
638 case GL_STENCIL_INDEX16_EXT
:
639 return GL_STENCIL_INDEX
;
640 case GL_DEPTH_COMPONENT
:
641 case GL_DEPTH_COMPONENT16
:
642 case GL_DEPTH_COMPONENT24
:
643 case GL_DEPTH_COMPONENT32
:
644 return GL_DEPTH_COMPONENT
;
645 /* XXX add floating point formats eventually */
653 _mesa_RenderbufferStorageEXT(GLenum target
, GLenum internalFormat
,
654 GLsizei width
, GLsizei height
)
656 struct gl_renderbuffer
*rb
;
658 GET_CURRENT_CONTEXT(ctx
);
660 ASSERT_OUTSIDE_BEGIN_END(ctx
);
661 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
);
663 if (target
!= GL_RENDERBUFFER_EXT
) {
664 _mesa_error(ctx
, GL_INVALID_ENUM
, "glRenderbufferStorageEXT(target)");
668 baseFormat
= base_internal_format(ctx
, internalFormat
);
669 if (baseFormat
== 0) {
670 _mesa_error(ctx
, GL_INVALID_ENUM
,
671 "glRenderbufferStorageEXT(internalFormat)");
675 if (width
< 1 || width
> ctx
->Const
.MaxRenderbufferSize
) {
676 _mesa_error(ctx
, GL_INVALID_VALUE
, "glRenderbufferStorageEXT(width)");
680 if (height
< 1 || height
> ctx
->Const
.MaxRenderbufferSize
) {
681 _mesa_error(ctx
, GL_INVALID_VALUE
, "glRenderbufferStorageEXT(height)");
685 rb
= ctx
->CurrentRenderbuffer
;
688 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glRenderbufferStorageEXT");
692 /* Now allocate the storage */
693 ASSERT(rb
->AllocStorage
);
694 if (rb
->AllocStorage(ctx
, rb
, internalFormat
, width
, height
)) {
695 /* No error - check/set fields now */
696 assert(rb
->Width
== width
);
697 assert(rb
->Height
== height
);
698 assert(rb
->InternalFormat
);
699 rb
->_BaseFormat
= baseFormat
;
702 /* Probably ran out of memory - clear the fields */
705 rb
->InternalFormat
= GL_NONE
;
706 rb
->_BaseFormat
= GL_NONE
;
710 test_framebuffer_completeness(ctx, fb);
712 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
719 _mesa_GetRenderbufferParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
721 GET_CURRENT_CONTEXT(ctx
);
723 ASSERT_OUTSIDE_BEGIN_END(ctx
);
725 if (target
!= GL_RENDERBUFFER_EXT
) {
726 _mesa_error(ctx
, GL_INVALID_ENUM
,
727 "glGetRenderbufferParameterivEXT(target)");
731 if (!ctx
->CurrentRenderbuffer
) {
732 _mesa_error(ctx
, GL_INVALID_OPERATION
,
733 "glGetRenderbufferParameterivEXT");
738 case GL_RENDERBUFFER_WIDTH_EXT
:
739 *params
= ctx
->CurrentRenderbuffer
->Width
;
741 case GL_RENDERBUFFER_HEIGHT_EXT
:
742 *params
= ctx
->CurrentRenderbuffer
->Height
;
744 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT
:
745 *params
= ctx
->CurrentRenderbuffer
->InternalFormat
;
747 case GL_RENDERBUFFER_RED_SIZE_EXT
:
748 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGB
||
749 ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGBA
) {
750 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[0];
756 case GL_RENDERBUFFER_GREEN_SIZE_EXT
:
757 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGB
||
758 ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGBA
) {
759 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[1];
765 case GL_RENDERBUFFER_BLUE_SIZE_EXT
:
766 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGB
||
767 ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGBA
) {
768 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[2];
774 case GL_RENDERBUFFER_ALPHA_SIZE_EXT
:
775 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGB
||
776 ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_RGBA
) {
777 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[3];
783 case GL_RENDERBUFFER_DEPTH_SIZE_EXT
:
784 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_DEPTH_COMPONENT
) {
785 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[0];
791 case GL_RENDERBUFFER_STENCIL_SIZE_EXT
:
792 if (ctx
->CurrentRenderbuffer
->_BaseFormat
== GL_STENCIL_INDEX
) {
793 *params
= ctx
->CurrentRenderbuffer
->ComponentSizes
[0];
801 _mesa_error(ctx
, GL_INVALID_ENUM
,
802 "glGetRenderbufferParameterivEXT(target)");
809 _mesa_IsFramebufferEXT(GLuint framebuffer
)
811 GET_CURRENT_CONTEXT(ctx
);
812 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
813 if (framebuffer
&& lookup_framebuffer(ctx
, framebuffer
))
821 _mesa_BindFramebufferEXT(GLenum target
, GLuint framebuffer
)
823 struct gl_framebuffer
*newFb
, *newReadFb
, *oldFb
;
824 GET_CURRENT_CONTEXT(ctx
);
826 ASSERT_OUTSIDE_BEGIN_END(ctx
);
827 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
);
829 if (target
!= GL_FRAMEBUFFER_EXT
) {
830 _mesa_error(ctx
, GL_INVALID_ENUM
,
831 "glBindFramebufferEXT(target)");
836 /* Binding a user-created framebuffer object */
837 newFb
= lookup_framebuffer(ctx
, framebuffer
);
838 if (newFb
== &DummyFramebuffer
) {
839 /* ID was reserved, but no real framebuffer object made yet */
843 /* create new framebuffer object */
844 newFb
= ctx
->Driver
.NewFramebuffer(ctx
, framebuffer
);
846 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindFramebufferEXT");
849 _mesa_HashInsert(ctx
->Shared
->FrameBuffers
, framebuffer
, newFb
);
855 /* Binding the window system framebuffer (which was originally set
858 newFb
= ctx
->WinSysDrawBuffer
;
859 newReadFb
= ctx
->WinSysReadBuffer
;
862 oldFb
= ctx
->DrawBuffer
;
863 if (oldFb
) { /* AND oldFb->Name != 0 */
865 if (oldFb
->RefCount
== 0) {
866 oldFb
->Delete(oldFb
);
870 ASSERT(newFb
!= &DummyFramebuffer
);
872 /* Note, we set both the GL_DRAW_BUFFER and GL_READ_BUFFER state: */
873 ctx
->DrawBuffer
= newFb
;
874 ctx
->ReadBuffer
= newReadFb
;
879 _mesa_DeleteFramebuffersEXT(GLsizei n
, const GLuint
*framebuffers
)
882 GET_CURRENT_CONTEXT(ctx
);
884 ASSERT_OUTSIDE_BEGIN_END(ctx
);
886 for (i
= 0; i
< n
; i
++) {
887 if (framebuffers
[i
] > 0) {
888 struct gl_framebuffer
*fb
;
889 fb
= lookup_framebuffer(ctx
, framebuffers
[i
]);
891 ASSERT(fb
== &DummyFramebuffer
|| fb
->Name
== framebuffers
[i
]);
892 /* remove from hash table immediately, to free the ID */
893 _mesa_HashRemove(ctx
->Shared
->FrameBuffers
, framebuffers
[i
]);
895 if (fb
!= &DummyFramebuffer
) {
896 /* But the object will not be freed until it's no longer
897 * bound in any context.
900 if (fb
->RefCount
== 0) {
911 _mesa_GenFramebuffersEXT(GLsizei n
, GLuint
*framebuffers
)
913 GET_CURRENT_CONTEXT(ctx
);
917 ASSERT_OUTSIDE_BEGIN_END(ctx
);
920 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenFramebuffersEXT(n)");
927 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->FrameBuffers
, n
);
929 for (i
= 0; i
< n
; i
++) {
930 GLuint name
= first
+ i
;
931 framebuffers
[i
] = name
;
932 /* insert dummy placeholder into hash table */
933 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
934 _mesa_HashInsert(ctx
->Shared
->FrameBuffers
, name
, &DummyFramebuffer
);
935 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
942 _mesa_CheckFramebufferStatusEXT(GLenum target
)
944 GET_CURRENT_CONTEXT(ctx
);
946 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, 0);
948 if (target
!= GL_FRAMEBUFFER_EXT
) {
949 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCheckFramebufferStatus(target)");
950 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
953 if (ctx
->DrawBuffer
->Name
== 0) {
954 /* The window system / default framebuffer is always complete */
955 return GL_FRAMEBUFFER_COMPLETE_EXT
;
958 _mesa_test_framebuffer_completeness(ctx
, ctx
->DrawBuffer
);
959 return ctx
->DrawBuffer
->_Status
;
965 * Do error checking common to glFramebufferTexture1D/2D/3DEXT.
966 * \return GL_TRUE if any error, GL_FALSE otherwise
969 error_check_framebuffer_texture(GLcontext
*ctx
, GLuint dims
,
970 GLenum target
, GLenum attachment
,
971 GLenum textarget
, GLuint texture
, GLint level
)
973 ASSERT(dims
>= 1 && dims
<= 3);
975 if (target
!= GL_FRAMEBUFFER_EXT
) {
976 _mesa_error(ctx
, GL_INVALID_ENUM
,
977 "glFramebufferTexture%dDEXT(target)", dims
);
981 /* check framebuffer binding */
982 if (ctx
->DrawBuffer
->Name
== 0) {
983 _mesa_error(ctx
, GL_INVALID_OPERATION
,
984 "glFramebufferTexture%dDEXT", dims
);
988 /* only check textarget, level if texture ID is non-zero */
990 if ((dims
== 1 && textarget
!= GL_TEXTURE_1D
) ||
991 (dims
== 3 && textarget
!= GL_TEXTURE_3D
) ||
992 (dims
== 2 && textarget
!= GL_TEXTURE_2D
&&
993 textarget
!= GL_TEXTURE_RECTANGLE_ARB
&&
994 !IS_CUBE_FACE(textarget
))) {
995 _mesa_error(ctx
, GL_INVALID_VALUE
,
996 "glFramebufferTexture%dDEXT(textarget)", dims
);
1000 if ((level
< 0) || level
>= _mesa_max_texture_levels(ctx
, textarget
)) {
1001 _mesa_error(ctx
, GL_INVALID_VALUE
,
1002 "glFramebufferTexture%dDEXT(level)", dims
);
1012 _mesa_FramebufferTexture1DEXT(GLenum target
, GLenum attachment
,
1013 GLenum textarget
, GLuint texture
, GLint level
)
1015 struct gl_renderbuffer_attachment
*att
;
1016 struct gl_texture_object
*texObj
;
1017 GET_CURRENT_CONTEXT(ctx
);
1019 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1020 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
); /* XXX check */
1022 if (error_check_framebuffer_texture(ctx
, 1, target
, attachment
,
1023 textarget
, texture
, level
))
1026 ASSERT(textarget
== GL_TEXTURE_1D
);
1028 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1030 _mesa_error(ctx
, GL_INVALID_ENUM
,
1031 "glFramebufferTexture1DEXT(attachment)");
1036 texObj
= (struct gl_texture_object
*)
1037 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1039 _mesa_error(ctx
, GL_INVALID_VALUE
,
1040 "glFramebufferTexture1DEXT(texture)");
1043 if (texObj
->Target
!= textarget
) {
1044 _mesa_error(ctx
, GL_INVALID_OPERATION
, /* XXX correct error? */
1045 "glFramebufferTexture1DEXT(texture target)");
1050 /* remove texture attachment */
1053 ctx
->Driver
.RenderbufferTexture(ctx
, att
, texObj
, textarget
, level
, 0);
1058 _mesa_FramebufferTexture2DEXT(GLenum target
, GLenum attachment
,
1059 GLenum textarget
, GLuint texture
, GLint level
)
1061 struct gl_renderbuffer_attachment
*att
;
1062 struct gl_texture_object
*texObj
;
1063 GET_CURRENT_CONTEXT(ctx
);
1065 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1066 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
); /* XXX check */
1068 if (error_check_framebuffer_texture(ctx
, 2, target
, attachment
,
1069 textarget
, texture
, level
))
1072 ASSERT(textarget
== GL_TEXTURE_2D
||
1073 textarget
== GL_TEXTURE_RECTANGLE_ARB
||
1074 IS_CUBE_FACE(textarget
));
1076 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1078 _mesa_error(ctx
, GL_INVALID_ENUM
,
1079 "glFramebufferTexture2DEXT(attachment)");
1084 texObj
= (struct gl_texture_object
*)
1085 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1087 _mesa_error(ctx
, GL_INVALID_VALUE
,
1088 "glFramebufferTexture2DEXT(texture)");
1091 if ((texObj
->Target
== GL_TEXTURE_2D
&& textarget
!= GL_TEXTURE_2D
) ||
1092 (texObj
->Target
== GL_TEXTURE_RECTANGLE_ARB
1093 && textarget
!= GL_TEXTURE_RECTANGLE_ARB
) ||
1094 (texObj
->Target
== GL_TEXTURE_CUBE_MAP
1095 && !IS_CUBE_FACE(textarget
))) {
1096 _mesa_error(ctx
, GL_INVALID_OPERATION
, /* XXX correct error? */
1097 "glFramebufferTexture2DEXT(texture target)");
1102 /* remove texture attachment */
1105 ctx
->Driver
.RenderbufferTexture(ctx
, att
, texObj
, textarget
, level
, 0);
1110 _mesa_FramebufferTexture3DEXT(GLenum target
, GLenum attachment
,
1111 GLenum textarget
, GLuint texture
,
1112 GLint level
, GLint zoffset
)
1114 struct gl_renderbuffer_attachment
*att
;
1115 struct gl_texture_object
*texObj
;
1116 GET_CURRENT_CONTEXT(ctx
);
1118 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1119 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
); /* XXX check */
1121 if (error_check_framebuffer_texture(ctx
, 3, target
, attachment
,
1122 textarget
, texture
, level
))
1125 ASSERT(textarget
== GL_TEXTURE_3D
);
1127 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1129 _mesa_error(ctx
, GL_INVALID_ENUM
,
1130 "glFramebufferTexture1DEXT(attachment)");
1135 const GLint maxSize
= 1 << (ctx
->Const
.Max3DTextureLevels
- 1);
1136 texObj
= (struct gl_texture_object
*)
1137 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1139 _mesa_error(ctx
, GL_INVALID_VALUE
,
1140 "glFramebufferTexture3DEXT(texture)");
1143 if (texObj
->Target
!= textarget
) {
1144 _mesa_error(ctx
, GL_INVALID_OPERATION
, /* XXX correct error? */
1145 "glFramebufferTexture3DEXT(texture target)");
1148 if (zoffset
< 0 || zoffset
>= maxSize
) {
1149 _mesa_error(ctx
, GL_INVALID_VALUE
,
1150 "glFramebufferTexture3DEXT(zoffset)");
1155 /* remove texture attachment */
1158 ctx
->Driver
.RenderbufferTexture(ctx
, att
, texObj
, textarget
,
1164 _mesa_FramebufferRenderbufferEXT(GLenum target
, GLenum attachment
,
1165 GLenum renderbufferTarget
,
1166 GLuint renderbuffer
)
1168 struct gl_renderbuffer_attachment
*att
;
1169 struct gl_renderbuffer
*rb
;
1170 GET_CURRENT_CONTEXT(ctx
);
1172 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1173 FLUSH_VERTICES(ctx
, _NEW_BUFFERS
);
1175 if (target
!= GL_FRAMEBUFFER_EXT
) {
1176 _mesa_error(ctx
, GL_INVALID_ENUM
,
1177 "glFramebufferRenderbufferEXT(target)");
1181 if (renderbufferTarget
!= GL_RENDERBUFFER_EXT
) {
1182 _mesa_error(ctx
, GL_INVALID_ENUM
,
1183 "glFramebufferRenderbufferEXT(renderbufferTarget)");
1187 if (ctx
->DrawBuffer
->Name
== 0) {
1188 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glFramebufferRenderbufferEXT");
1192 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1194 _mesa_error(ctx
, GL_INVALID_ENUM
,
1195 "glFramebufferRenderbufferEXT(attachment)");
1200 rb
= lookup_renderbuffer(ctx
, renderbuffer
);
1202 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1203 "glFramebufferRenderbufferEXT(renderbuffer)");
1208 /* remove renderbuffer attachment */
1212 assert(ctx
->Driver
.FramebufferRenderbuffer
);
1213 ctx
->Driver
.FramebufferRenderbuffer(ctx
, att
, rb
);
1215 _mesa_update_framebuffer_visual(ctx
->DrawBuffer
);
1220 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target
, GLenum attachment
,
1221 GLenum pname
, GLint
*params
)
1223 const struct gl_renderbuffer_attachment
*att
;
1224 GET_CURRENT_CONTEXT(ctx
);
1226 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1228 if (target
!= GL_FRAMEBUFFER_EXT
) {
1229 _mesa_error(ctx
, GL_INVALID_ENUM
,
1230 "glGetFramebufferAttachmentParameterivEXT(target)");
1234 if (ctx
->DrawBuffer
->Name
== 0) {
1235 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1236 "glGetFramebufferAttachmentParameterivEXT");
1240 att
= get_attachment(ctx
, ctx
->DrawBuffer
, attachment
);
1242 _mesa_error(ctx
, GL_INVALID_ENUM
,
1243 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1248 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT
:
1249 *params
= att
->Type
;
1251 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
:
1252 if (att
->Type
== GL_RENDERBUFFER_EXT
) {
1253 *params
= att
->Renderbuffer
->Name
;
1255 else if (att
->Type
== GL_TEXTURE
) {
1256 *params
= att
->Texture
->Name
;
1259 _mesa_error(ctx
, GL_INVALID_ENUM
,
1260 "glGetFramebufferAttachmentParameterivEXT(pname)");
1263 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT
:
1264 if (att
->Type
== GL_TEXTURE
) {
1265 *params
= att
->TextureLevel
;
1268 _mesa_error(ctx
, GL_INVALID_ENUM
,
1269 "glGetFramebufferAttachmentParameterivEXT(pname)");
1272 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT
:
1273 if (att
->Type
== GL_TEXTURE
) {
1274 *params
= GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ att
->CubeMapFace
;
1277 _mesa_error(ctx
, GL_INVALID_ENUM
,
1278 "glGetFramebufferAttachmentParameterivEXT(pname)");
1281 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT
:
1282 if (att
->Type
== GL_TEXTURE
) {
1283 *params
= att
->Zoffset
;
1286 _mesa_error(ctx
, GL_INVALID_ENUM
,
1287 "glGetFramebufferAttachmentParameterivEXT(pname)");
1291 _mesa_error(ctx
, GL_INVALID_ENUM
,
1292 "glGetFramebufferAttachmentParameterivEXT(pname)");
1299 _mesa_GenerateMipmapEXT(GLenum target
)
1301 struct gl_texture_unit
*texUnit
;
1302 struct gl_texture_object
*texObj
;
1303 GET_CURRENT_CONTEXT(ctx
);
1305 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1311 case GL_TEXTURE_CUBE_MAP
:
1312 /* OK, legal value */
1315 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGenerateMipmapEXT(target)");
1319 texUnit
= &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
];
1320 texObj
= _mesa_select_tex_object(ctx
, texUnit
, target
);
1322 /* XXX this might not handle cube maps correctly */
1323 _mesa_generate_mipmap(ctx
, target
, texUnit
, texObj
);