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.
42 * None of the GL_EXT_framebuffer_object functions are compiled into
49 * When glGenRender/FramebuffersEXT() is called we insert pointers to
50 * these placeholder objects into the hash table.
51 * Later, when the object ID is first bound, we replace the placeholder
52 * with the real frame/renderbuffer.
54 static struct gl_framebuffer DummyFramebuffer
;
55 static struct gl_renderbuffer DummyRenderbuffer
;
58 #define IS_CUBE_FACE(TARGET) \
59 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
60 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
64 * Helper routine for getting a gl_renderbuffer.
66 static struct gl_renderbuffer
*
67 lookup_renderbuffer(GLcontext
*ctx
, GLuint id
)
69 struct gl_renderbuffer
*rb
;
74 rb
= (struct gl_renderbuffer
*)
75 _mesa_HashLookup(ctx
->Shared
->RenderBuffers
, id
);
81 * Helper routine for getting a gl_framebuffer.
83 static struct gl_framebuffer
*
84 lookup_framebuffer(GLcontext
*ctx
, GLuint id
)
86 struct gl_framebuffer
*fb
;
91 fb
= (struct gl_framebuffer
*)
92 _mesa_HashLookup(ctx
->Shared
->FrameBuffers
, id
);
98 * Allocate a new gl_framebuffer.
99 * This is the default function for ctx->Driver.NewFramebuffer().
101 struct gl_framebuffer
*
102 _mesa_new_framebuffer(GLcontext
*ctx
, GLuint name
)
104 struct gl_framebuffer
*fb
= CALLOC_STRUCT(gl_framebuffer
);
108 fb
->Delete
= _mesa_delete_framebuffer
;
115 * Delete a gl_framebuffer.
116 * This is the default function for framebuffer->Delete().
119 _mesa_delete_framebuffer(GLcontext
*ctx
, struct gl_framebuffer
*fb
)
127 * Allocate the actual storage for a renderbuffer with the given format
129 * This is the default function for gl_renderbuffer->AllocStorage().
130 * All incoming parameters will have already been checked for errors.
131 * If memory allocate fails, the function must call
132 * _mesa_error(GL_OUT_OF_MEMORY) and then return.
133 * \return GL_TRUE for success, GL_FALSE for failure.
136 alloc_renderbuffer_storage(GLcontext
*ctx
, struct gl_renderbuffer
*rb
,
137 GLenum internalFormat
, GLuint width
, GLuint height
)
139 /* First, free any existing storage */
141 _mesa_free(rb
->Data
);
144 /* Now, allocate new storage */
145 rb
->Data
= _mesa_malloc(width
* height
* 4); /* XXX fix size! */
146 if (rb
->Data
== NULL
) {
147 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glRenderbufferStorageEXT");
151 /* We set these fields now if the allocation worked */
154 rb
->InternalFormat
= internalFormat
;
161 * Allocate a new gl_renderbuffer.
162 * This is the default function for ctx->Driver.NewRenderbuffer().
164 struct gl_renderbuffer
*
165 _mesa_new_renderbuffer(GLcontext
*ctx
, GLuint name
)
167 struct gl_renderbuffer
*rb
= CALLOC_STRUCT(gl_renderbuffer
);
171 rb
->Delete
= _mesa_delete_renderbuffer
;
172 rb
->AllocStorage
= alloc_renderbuffer_storage
;
173 /* other fields are zero */
180 * Delete a gl_framebuffer.
181 * This is the default function for framebuffer->Delete().
184 _mesa_delete_renderbuffer(GLcontext
*ctx
, struct gl_renderbuffer
*rb
)
188 _mesa_free(rb
->Data
);
195 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
196 * gl_renderbuffer_attachment object.
198 static struct gl_renderbuffer_attachment
*
199 get_attachment(GLcontext
*ctx
, struct gl_framebuffer
*fb
, GLenum attachment
)
203 switch (attachment
) {
204 case GL_COLOR_ATTACHMENT0_EXT
:
205 case GL_COLOR_ATTACHMENT1_EXT
:
206 case GL_COLOR_ATTACHMENT2_EXT
:
207 case GL_COLOR_ATTACHMENT3_EXT
:
208 case GL_COLOR_ATTACHMENT4_EXT
:
209 case GL_COLOR_ATTACHMENT5_EXT
:
210 case GL_COLOR_ATTACHMENT6_EXT
:
211 case GL_COLOR_ATTACHMENT7_EXT
:
212 case GL_COLOR_ATTACHMENT8_EXT
:
213 case GL_COLOR_ATTACHMENT9_EXT
:
214 case GL_COLOR_ATTACHMENT10_EXT
:
215 case GL_COLOR_ATTACHMENT11_EXT
:
216 case GL_COLOR_ATTACHMENT12_EXT
:
217 case GL_COLOR_ATTACHMENT13_EXT
:
218 case GL_COLOR_ATTACHMENT14_EXT
:
219 case GL_COLOR_ATTACHMENT15_EXT
:
220 i
= attachment
- GL_COLOR_ATTACHMENT0_EXT
;
221 if (i
>= ctx
->Const
.MaxColorAttachments
) {
224 return &fb
->ColorAttachment
[i
];
225 case GL_DEPTH_ATTACHMENT_EXT
:
226 return &fb
->DepthAttachment
;
227 case GL_STENCIL_ATTACHMENT_EXT
:
228 return &fb
->StencilAttachment
;
236 * Remove any texture or renderbuffer attached to the given attachment
237 * point. Update reference counts, etc.
240 remove_attachment(GLcontext
*ctx
, struct gl_renderbuffer_attachment
*att
)
242 if (att
->Type
== GL_TEXTURE
) {
243 ASSERT(att
->Texture
);
244 ASSERT(!att
->Renderbuffer
);
245 att
->Texture
->RefCount
--;
246 if (att
->Texture
->RefCount
== 0) {
247 ctx
->Driver
.DeleteTexture(ctx
, att
->Texture
);
251 else if (att
->Type
== GL_RENDERBUFFER_EXT
) {
252 ASSERT(att
->Renderbuffer
);
253 ASSERT(!att
->Texture
);
254 att
->Renderbuffer
->RefCount
--;
255 if (att
->Renderbuffer
->RefCount
== 0) {
256 att
->Renderbuffer
->Delete(ctx
, att
->Renderbuffer
);
258 att
->Renderbuffer
= NULL
;
261 att
->Complete
= GL_TRUE
;
266 * Bind a texture object to an attachment point.
267 * The previous binding, if any, will be removed first.
270 set_texture_attachment(GLcontext
*ctx
,
271 struct gl_renderbuffer_attachment
*att
,
272 struct gl_texture_object
*texObj
,
273 GLenum texTarget
, GLuint level
, GLuint zoffset
)
275 remove_attachment(ctx
, att
);
276 att
->Type
= GL_TEXTURE
;
277 att
->Texture
= texObj
;
278 att
->TextureLevel
= level
;
279 if (IS_CUBE_FACE(texTarget
)) {
280 att
->CubeMapFace
= texTarget
- GL_TEXTURE_CUBE_MAP_POSITIVE_X
;
283 att
->CubeMapFace
= 0;
285 att
->Zoffset
= zoffset
;
286 att
->Complete
= GL_FALSE
;
289 /* XXX when we attach to a texture, we should probably set the
290 * att->Renderbuffer pointer to a "wrapper renderbuffer" which
291 * makes the texture image look like renderbuffer.
297 * Bind a renderbuffer to an attachment point.
298 * The previous binding, if any, will be removed first.
301 set_renderbuffer_attachment(GLcontext
*ctx
,
302 struct gl_renderbuffer_attachment
*att
,
303 struct gl_renderbuffer
*rb
)
305 remove_attachment(ctx
, att
);
306 att
->Type
= GL_RENDERBUFFER_EXT
;
307 att
->Renderbuffer
= rb
;
308 att
->Texture
= NULL
; /* just to be safe */
309 att
->Complete
= GL_FALSE
;
315 * Test if an attachment point is complete and update its Complete field.
316 * \param format if GL_COLOR, this is a color attachment point,
317 * if GL_DEPTH, this is a depth component attachment point,
318 * if GL_STENCIL, this is a stencil component attachment point.
321 test_attachment_completeness(const GLcontext
*ctx
, GLenum format
,
322 struct gl_renderbuffer_attachment
*att
)
324 assert(format
== GL_COLOR
|| format
== GL_DEPTH
|| format
== GL_STENCIL
);
326 /* assume complete */
327 att
->Complete
= GL_TRUE
;
329 if (att
->Type
== GL_NONE
)
330 return; /* complete */
332 /* Look for reasons why the attachment might be incomplete */
333 if (att
->Type
== GL_TEXTURE
) {
334 struct gl_texture_object
*texObj
= att
->Texture
;
335 struct gl_texture_image
*texImage
;
339 texImage
= texObj
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
341 att
->Complete
= GL_FALSE
;
344 if (texImage
->Width
< 1 || texImage
->Height
< 1) {
345 att
->Complete
= GL_FALSE
;
348 if (texObj
->Target
== GL_TEXTURE_3D
&& att
->Zoffset
>= texImage
->Depth
) {
349 att
->Complete
= GL_FALSE
;
353 if (format
== GL_COLOR
) {
354 if (texImage
->Format
!= GL_RGB
&& texImage
->Format
!= GL_RGBA
) {
355 att
->Complete
= GL_FALSE
;
359 else if (format
== GL_DEPTH
) {
360 if (texImage
->Format
!= GL_DEPTH_COMPONENT
) {
361 att
->Complete
= GL_FALSE
;
366 /* no such thing as stencil textures */
367 att
->Complete
= GL_FALSE
;
372 assert(att
->Type
== GL_RENDERBUFFER_EXT
);
374 if (att
->Renderbuffer
->Width
< 1 || att
->Renderbuffer
->Height
< 1) {
375 att
->Complete
= GL_FALSE
;
378 if (format
== GL_COLOR
) {
379 if (att
->Renderbuffer
->_BaseFormat
!= GL_RGB
&&
380 att
->Renderbuffer
->_BaseFormat
!= GL_RGBA
) {
381 att
->Complete
= GL_FALSE
;
385 else if (format
== GL_DEPTH
) {
386 if (att
->Renderbuffer
->_BaseFormat
!= GL_DEPTH_COMPONENT
) {
387 att
->Complete
= GL_FALSE
;
392 assert(format
== GL_STENCIL
);
393 if (att
->Renderbuffer
->_BaseFormat
!= GL_STENCIL_INDEX
) {
394 att
->Complete
= GL_FALSE
;
403 * Test if the given framebuffer object is complete and update its
404 * Status field with the results.
407 test_framebuffer_completeness(GLcontext
*ctx
,
408 struct gl_framebuffer
*fb
)
411 GLuint numImages
, width
= 0, height
= 0;
412 GLenum intFormat
= GL_NONE
;
414 /* Set to COMPLETE status, then try to find reasons for being incomplete */
415 fb
->Status
= GL_FRAMEBUFFER_COMPLETE_EXT
;
419 /* Start at -2 to more easily loop over all attachment points */
420 for (i
= -2; i
< ctx
->Const
.MaxColorAttachments
; i
++) {
421 struct gl_renderbuffer_attachment
*att
;
426 att
= &fb
->DepthAttachment
;
427 test_attachment_completeness(ctx
, GL_DEPTH
, att
);
428 if (!att
->Complete
) {
429 fb
->Status
= GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
;
434 att
= &fb
->StencilAttachment
;
435 test_attachment_completeness(ctx
, GL_STENCIL
, att
);
436 if (!att
->Complete
) {
437 fb
->Status
= GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
;
442 att
= &fb
->ColorAttachment
[i
];
443 test_attachment_completeness(ctx
, GL_COLOR
, att
);
444 if (!att
->Complete
) {
445 fb
->Status
= GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
;
450 if (att
->Type
== GL_TEXTURE
) {
451 w
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
]->Width
;
452 h
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
]->Height
;
453 f
= att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
]->Format
;
456 else if (att
->Type
== GL_RENDERBUFFER_EXT
) {
457 w
= att
->Renderbuffer
->Width
;
458 h
= att
->Renderbuffer
->Height
;
459 f
= att
->Renderbuffer
->InternalFormat
;
463 assert(att
->Type
== GL_NONE
);
467 if (numImages
== 1) {
468 /* set required width, height and format */
475 /* check that width, height, format are same */
476 if (w
!= width
|| h
!= height
) {
477 fb
->Status
= GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
;
480 if (i
>= 0 && f
!= intFormat
) {
481 fb
->Status
= GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT
;
488 /* Check that all DrawBuffers are present */
489 for (i
= 0; i
< ctx
->Const
.MaxDrawBuffers
; i
++) {
490 if (fb
->DrawBuffer
[i
] != GL_NONE
) {
491 struct gl_renderbuffer_attachment
*att
492 = get_attachment(ctx
, fb
, fb
->DrawBuffer
[i
]);
493 if (att
->Type
== GL_NONE
) {
494 fb
->Status
= GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT
;
500 /* Check that the ReadBuffer is present */
501 if (fb
->ReadBuffer
!= GL_NONE
) {
502 struct gl_renderbuffer_attachment
*att
503 = get_attachment(ctx
, fb
, fb
->ReadBuffer
);
504 if (att
->Type
== GL_NONE
) {
505 fb
->Status
= GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT
;
510 if (numImages
== 0) {
511 fb
->Status
= GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT
;
519 _mesa_IsRenderbufferEXT(GLuint renderbuffer
)
521 const struct gl_renderbuffer
*rb
;
522 GET_CURRENT_CONTEXT(ctx
);
524 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
526 rb
= lookup_renderbuffer(ctx
, renderbuffer
);
527 return rb
? GL_TRUE
: GL_FALSE
;
532 _mesa_BindRenderbufferEXT(GLenum target
, GLuint renderbuffer
)
534 struct gl_renderbuffer
*newRb
, *oldRb
;
535 GET_CURRENT_CONTEXT(ctx
);
537 ASSERT_OUTSIDE_BEGIN_END(ctx
);
539 if (target
!= GL_RENDERBUFFER_EXT
) {
540 _mesa_error(ctx
, GL_INVALID_ENUM
,
541 "glBindRenderbufferEXT(target)");
546 newRb
= lookup_renderbuffer(ctx
, renderbuffer
);
547 if (newRb
== &DummyRenderbuffer
) {
548 /* ID was reserved, but no real renderbuffer object made yet */
552 /* create new renderbuffer object */
553 newRb
= ctx
->Driver
.NewRenderbuffer(ctx
, renderbuffer
);
555 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindRenderbufferEXT");
558 ASSERT(newRb
->AllocStorage
);
559 _mesa_HashInsert(ctx
->Shared
->RenderBuffers
, renderbuffer
, newRb
);
567 oldRb
= ctx
->CurrentRenderbuffer
;
570 if (oldRb
->RefCount
== 0) {
571 oldRb
->Delete(ctx
, oldRb
);
575 ASSERT(newRb
!= &DummyRenderbuffer
);
577 ctx
->CurrentRenderbuffer
= newRb
;
582 _mesa_DeleteRenderbuffersEXT(GLsizei n
, const GLuint
*renderbuffers
)
585 GET_CURRENT_CONTEXT(ctx
);
587 ASSERT_OUTSIDE_BEGIN_END(ctx
);
589 for (i
= 0; i
< n
; i
++) {
590 if (renderbuffers
[i
] > 0) {
591 struct gl_renderbuffer
*rb
;
592 rb
= lookup_renderbuffer(ctx
, renderbuffers
[i
]);
594 /* remove from hash table immediately, to free the ID */
595 _mesa_HashRemove(ctx
->Shared
->RenderBuffers
, renderbuffers
[i
]);
597 if (rb
!= &DummyRenderbuffer
) {
598 /* But the object will not be freed until it's no longer
599 * bound in any context.
602 if (rb
->RefCount
== 0) {
613 _mesa_GenRenderbuffersEXT(GLsizei n
, GLuint
*renderbuffers
)
615 GET_CURRENT_CONTEXT(ctx
);
619 ASSERT_OUTSIDE_BEGIN_END(ctx
);
622 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenRenderbuffersEXT(n)");
629 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->RenderBuffers
, n
);
631 for (i
= 0; i
< n
; i
++) {
632 GLuint name
= first
+ i
;
633 renderbuffers
[i
] = name
;
634 /* insert dummy placeholder into hash table */
635 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
636 _mesa_HashInsert(ctx
->Shared
->RenderBuffers
, name
, &DummyRenderbuffer
);
637 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
643 * Given an internal format token for a render buffer, return the
644 * corresponding base format.
645 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
649 base_internal_format(GLcontext
*ctx
, GLenum internalFormat
)
651 switch (internalFormat
) {
670 case GL_STENCIL_INDEX
:
671 case GL_STENCIL_INDEX1_EXT
:
672 case GL_STENCIL_INDEX4_EXT
:
673 case GL_STENCIL_INDEX8_EXT
:
674 case GL_STENCIL_INDEX16_EXT
:
675 return GL_STENCIL_INDEX
;
676 case GL_DEPTH_COMPONENT
:
677 case GL_DEPTH_COMPONENT16
:
678 case GL_DEPTH_COMPONENT24
:
679 case GL_DEPTH_COMPONENT32
:
680 return GL_DEPTH_COMPONENT
;
681 /* XXX add floating point formats eventually */
689 _mesa_RenderbufferStorageEXT(GLenum target
, GLenum internalFormat
,
690 GLsizei width
, GLsizei height
)
692 struct gl_renderbuffer
*rb
;
694 GET_CURRENT_CONTEXT(ctx
);
696 ASSERT_OUTSIDE_BEGIN_END(ctx
);
698 if (target
!= GL_RENDERBUFFER_EXT
) {
699 _mesa_error(ctx
, GL_INVALID_ENUM
, "glRenderbufferStorageEXT(target)");
703 baseFormat
= base_internal_format(ctx
, internalFormat
);
704 if (baseFormat
== 0) {
705 _mesa_error(ctx
, GL_INVALID_ENUM
,
706 "glRenderbufferStorageEXT(internalFormat)");
710 if (width
< 1 || width
> ctx
->Const
.MaxRenderbufferSize
) {
711 _mesa_error(ctx
, GL_INVALID_VALUE
, "glRenderbufferStorageEXT(width)");
715 if (height
< 1 || height
> ctx
->Const
.MaxRenderbufferSize
) {
716 _mesa_error(ctx
, GL_INVALID_VALUE
, "glRenderbufferStorageEXT(height)");
720 rb
= ctx
->CurrentRenderbuffer
;
723 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glRenderbufferStorageEXT");
727 /* Now allocate the storage */
728 ASSERT(rb
->AllocStorage
);
729 if (rb
->AllocStorage(ctx
, rb
, internalFormat
, width
, height
)) {
730 /* No error - check/set fields now */
731 assert(rb
->Width
== width
);
732 assert(rb
->Height
== height
);
733 assert(rb
->InternalFormat
);
734 rb
->_BaseFormat
= baseFormat
;
737 /* Probably ran out of memory - clear the fields */
740 rb
->InternalFormat
= GL_NONE
;
741 rb
->_BaseFormat
= GL_NONE
;
744 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
751 _mesa_GetRenderbufferParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
753 GET_CURRENT_CONTEXT(ctx
);
755 ASSERT_OUTSIDE_BEGIN_END(ctx
);
757 if (target
!= GL_RENDERBUFFER_EXT
) {
758 _mesa_error(ctx
, GL_INVALID_ENUM
,
759 "glGetRenderbufferParameterivEXT(target)");
763 if (!ctx
->CurrentRenderbuffer
) {
764 _mesa_error(ctx
, GL_INVALID_OPERATION
,
765 "glGetRenderbufferParameterivEXT");
770 case GL_RENDERBUFFER_WIDTH_EXT
:
771 *params
= ctx
->CurrentRenderbuffer
->Width
;
773 case GL_RENDERBUFFER_HEIGHT_EXT
:
774 *params
= ctx
->CurrentRenderbuffer
->Height
;
776 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT
:
777 *params
= ctx
->CurrentRenderbuffer
->InternalFormat
;
780 _mesa_error(ctx
, GL_INVALID_ENUM
,
781 "glGetRenderbufferParameterivEXT(target)");
788 _mesa_IsFramebufferEXT(GLuint framebuffer
)
790 const struct gl_framebuffer
*fb
;
791 GET_CURRENT_CONTEXT(ctx
);
793 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
795 fb
= lookup_framebuffer(ctx
, framebuffer
);
796 return fb
? GL_TRUE
: GL_FALSE
;
801 _mesa_BindFramebufferEXT(GLenum target
, GLuint framebuffer
)
803 struct gl_framebuffer
*newFb
, *oldFb
;
804 GET_CURRENT_CONTEXT(ctx
);
806 ASSERT_OUTSIDE_BEGIN_END(ctx
);
808 if (target
!= GL_FRAMEBUFFER_EXT
) {
809 _mesa_error(ctx
, GL_INVALID_ENUM
,
810 "glBindFramebufferEXT(target)");
815 newFb
= lookup_framebuffer(ctx
, framebuffer
);
816 if (newFb
== &DummyFramebuffer
) {
817 /* ID was reserved, but no real framebuffer object made yet */
821 /* create new framebuffer object */
822 newFb
= ctx
->Driver
.NewFramebuffer(ctx
, framebuffer
);
824 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindFramebufferEXT");
827 _mesa_HashInsert(ctx
->Shared
->FrameBuffers
, framebuffer
, newFb
);
835 oldFb
= ctx
->CurrentFramebuffer
;
838 if (oldFb
->RefCount
== 0) {
839 oldFb
->Delete(ctx
, oldFb
);
843 ASSERT(newFb
!= &DummyFramebuffer
);
845 ctx
->CurrentFramebuffer
= newFb
;
850 _mesa_DeleteFramebuffersEXT(GLsizei n
, const GLuint
*framebuffers
)
853 GET_CURRENT_CONTEXT(ctx
);
855 ASSERT_OUTSIDE_BEGIN_END(ctx
);
857 for (i
= 0; i
< n
; i
++) {
858 if (framebuffers
[i
] > 0) {
859 struct gl_framebuffer
*fb
;
860 fb
= lookup_framebuffer(ctx
, framebuffers
[i
]);
862 /* remove from hash table immediately, to free the ID */
863 _mesa_HashRemove(ctx
->Shared
->FrameBuffers
, framebuffers
[i
]);
865 if (fb
!= &DummyFramebuffer
) {
866 /* But the object will not be freed until it's no longer
867 * bound in any context.
870 if (fb
->RefCount
== 0) {
881 _mesa_GenFramebuffersEXT(GLsizei n
, GLuint
*framebuffers
)
883 GET_CURRENT_CONTEXT(ctx
);
887 ASSERT_OUTSIDE_BEGIN_END(ctx
);
890 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenFramebuffersEXT(n)");
897 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->FrameBuffers
, n
);
899 for (i
= 0; i
< n
; i
++) {
900 GLuint name
= first
+ i
;
901 framebuffers
[i
] = name
;
902 /* insert dummy placeholder into hash table */
903 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
904 _mesa_HashInsert(ctx
->Shared
->FrameBuffers
, name
, &DummyFramebuffer
);
905 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
912 _mesa_CheckFramebufferStatusEXT(GLenum target
)
914 GET_CURRENT_CONTEXT(ctx
);
916 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FRAMEBUFFER_STATUS_ERROR_EXT
);
918 if (target
!= GL_FRAMEBUFFER_EXT
) {
919 _mesa_error(ctx
, GL_INVALID_ENUM
, "glCheckFramebufferStatus(target)");
920 return GL_FRAMEBUFFER_STATUS_ERROR_EXT
;
923 if (!ctx
->CurrentFramebuffer
) {
924 /* The window system / default framebuffer is always complete */
925 return GL_FRAMEBUFFER_COMPLETE_EXT
;
928 test_framebuffer_completeness(ctx
, ctx
->CurrentFramebuffer
);
929 return ctx
->CurrentFramebuffer
->Status
;
935 * Do error checking common to glFramebufferTexture1D/2D/3DEXT.
936 * \return GL_TRUE if any error, GL_FALSE otherwise
939 error_check_framebuffer_texture(GLcontext
*ctx
, GLuint dims
,
940 GLenum target
, GLenum attachment
,
941 GLenum textarget
, GLuint texture
, GLint level
)
943 ASSERT(dims
>= 1 && dims
<= 3);
945 if (target
!= GL_FRAMEBUFFER_EXT
) {
946 _mesa_error(ctx
, GL_INVALID_ENUM
,
947 "glFramebufferTexture%dDEXT(target)", dims
);
951 if (ctx
->CurrentFramebuffer
== NULL
) {
952 _mesa_error(ctx
, GL_INVALID_OPERATION
,
953 "glFramebufferTexture%dDEXT", dims
);
957 /* only check textarget, level if texture ID is non-zero*/
959 if ((dims
== 1 && textarget
!= GL_TEXTURE_1D
) ||
960 (dims
== 3 && textarget
!= GL_TEXTURE_3D
) ||
961 (dims
== 2 && textarget
!= GL_TEXTURE_2D
&&
962 textarget
!= GL_TEXTURE_RECTANGLE_ARB
&&
963 !IS_CUBE_FACE(textarget
))) {
964 _mesa_error(ctx
, GL_INVALID_VALUE
,
965 "glFramebufferTexture%dDEXT(textarget)", dims
);
969 if ((level
< 0) || level
>= _mesa_max_texture_levels(ctx
, textarget
)) {
970 _mesa_error(ctx
, GL_INVALID_VALUE
,
971 "glFramebufferTexture%dDEXT(level)", dims
);
981 _mesa_FramebufferTexture1DEXT(GLenum target
, GLenum attachment
,
982 GLenum textarget
, GLuint texture
, GLint level
)
984 struct gl_renderbuffer_attachment
*att
;
985 GET_CURRENT_CONTEXT(ctx
);
987 ASSERT_OUTSIDE_BEGIN_END(ctx
);
989 if (error_check_framebuffer_texture(ctx
, 1, target
, attachment
,
990 textarget
, texture
, level
))
993 ASSERT(textarget
== GL_TEXTURE_1D
);
995 att
= get_attachment(ctx
, ctx
->CurrentFramebuffer
, attachment
);
997 _mesa_error(ctx
, GL_INVALID_ENUM
,
998 "glFramebufferTexture1DEXT(attachment)");
1003 struct gl_texture_object
*texObj
= (struct gl_texture_object
*)
1004 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1006 _mesa_error(ctx
, GL_INVALID_VALUE
,
1007 "glFramebufferTexture1DEXT(texture)");
1010 if (texObj
->Target
!= textarget
) {
1011 _mesa_error(ctx
, GL_INVALID_OPERATION
, /* XXX correct error? */
1012 "glFramebufferTexture1DEXT(texture target)");
1015 set_texture_attachment(ctx
, att
, texObj
, textarget
, level
, 0);
1018 remove_attachment(ctx
, att
);
1021 /* XXX call a driver function to signal new attachment? */
1026 _mesa_FramebufferTexture2DEXT(GLenum target
, GLenum attachment
,
1027 GLenum textarget
, GLuint texture
, GLint level
)
1029 struct gl_renderbuffer_attachment
*att
;
1030 GET_CURRENT_CONTEXT(ctx
);
1032 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1034 if (error_check_framebuffer_texture(ctx
, 2, target
, attachment
,
1035 textarget
, texture
, level
))
1038 ASSERT(textarget
== GL_TEXTURE_2D
||
1039 textarget
== GL_TEXTURE_RECTANGLE_ARB
||
1040 IS_CUBE_FACE(textarget
));
1042 att
= get_attachment(ctx
, ctx
->CurrentFramebuffer
, attachment
);
1044 _mesa_error(ctx
, GL_INVALID_ENUM
,
1045 "glFramebufferTexture2DEXT(attachment)");
1050 struct gl_texture_object
*texObj
= (struct gl_texture_object
*)
1051 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1053 _mesa_error(ctx
, GL_INVALID_VALUE
,
1054 "glFramebufferTexture2DEXT(texture)");
1057 if ((texObj
->Target
== GL_TEXTURE_2D
&& textarget
!= GL_TEXTURE_2D
) ||
1058 (texObj
->Target
== GL_TEXTURE_RECTANGLE_ARB
1059 && textarget
!= GL_TEXTURE_RECTANGLE_ARB
) ||
1060 (texObj
->Target
== GL_TEXTURE_CUBE_MAP
1061 && !IS_CUBE_FACE(textarget
))) {
1062 _mesa_error(ctx
, GL_INVALID_OPERATION
, /* XXX correct error? */
1063 "glFramebufferTexture2DEXT(texture target)");
1066 set_texture_attachment(ctx
, att
, texObj
, textarget
, level
, 0);
1069 remove_attachment(ctx
, att
);
1076 _mesa_FramebufferTexture3DEXT(GLenum target
, GLenum attachment
,
1077 GLenum textarget
, GLuint texture
,
1078 GLint level
, GLint zoffset
)
1080 struct gl_renderbuffer_attachment
*att
;
1081 GET_CURRENT_CONTEXT(ctx
);
1083 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1085 if (error_check_framebuffer_texture(ctx
, 3, target
, attachment
,
1086 textarget
, texture
, level
))
1089 ASSERT(textarget
== GL_TEXTURE_3D
);
1091 att
= get_attachment(ctx
, ctx
->CurrentFramebuffer
, attachment
);
1093 _mesa_error(ctx
, GL_INVALID_ENUM
,
1094 "glFramebufferTexture1DEXT(attachment)");
1099 const GLint maxSize
= 1 << (ctx
->Const
.Max3DTextureLevels
- 1);
1100 struct gl_texture_object
*texObj
= (struct gl_texture_object
*)
1101 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1103 _mesa_error(ctx
, GL_INVALID_VALUE
,
1104 "glFramebufferTexture3DEXT(texture)");
1107 if (texObj
->Target
!= textarget
) {
1108 _mesa_error(ctx
, GL_INVALID_OPERATION
, /* XXX correct error? */
1109 "glFramebufferTexture3DEXT(texture target)");
1112 if (zoffset
< 0 || zoffset
>= maxSize
) {
1113 _mesa_error(ctx
, GL_INVALID_VALUE
,
1114 "glFramebufferTexture3DEXT(zoffset)");
1117 set_texture_attachment(ctx
, att
, texObj
, textarget
, level
, zoffset
);
1120 remove_attachment(ctx
, att
);
1126 _mesa_FramebufferRenderbufferEXT(GLenum target
, GLenum attachment
,
1127 GLenum renderbufferTarget
,
1128 GLuint renderbuffer
)
1130 struct gl_renderbuffer_attachment
*att
;
1131 GET_CURRENT_CONTEXT(ctx
);
1133 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1135 if (target
!= GL_FRAMEBUFFER_EXT
) {
1136 _mesa_error(ctx
, GL_INVALID_ENUM
,
1137 "glFramebufferRenderbufferEXT(target)");
1141 if (renderbufferTarget
!= GL_RENDERBUFFER_EXT
) {
1142 _mesa_error(ctx
, GL_INVALID_ENUM
,
1143 "glFramebufferRenderbufferEXT(renderbufferTarget)");
1147 if (ctx
->CurrentFramebuffer
== NULL
) {
1148 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glFramebufferRenderbufferEXT");
1152 att
= get_attachment(ctx
, ctx
->CurrentFramebuffer
, attachment
);
1154 _mesa_error(ctx
, GL_INVALID_ENUM
,
1155 "glFramebufferRenderbufferEXT(attachment)");
1160 struct gl_renderbuffer
*rb
;
1161 rb
= lookup_renderbuffer(ctx
, renderbuffer
);
1163 _mesa_error(ctx
, GL_INVALID_VALUE
,
1164 "glFramebufferRenderbufferEXT(renderbuffer)");
1167 set_renderbuffer_attachment(ctx
, att
, rb
);
1170 remove_attachment(ctx
, att
);
1176 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target
, GLenum attachment
,
1177 GLenum pname
, GLint
*params
)
1179 const struct gl_renderbuffer_attachment
*att
;
1180 GET_CURRENT_CONTEXT(ctx
);
1182 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1184 if (target
!= GL_FRAMEBUFFER_EXT
) {
1185 _mesa_error(ctx
, GL_INVALID_ENUM
,
1186 "glGetFramebufferAttachmentParameterivEXT(target)");
1190 if (ctx
->CurrentFramebuffer
== NULL
) {
1191 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1192 "glGetFramebufferAttachmentParameterivEXT");
1196 att
= get_attachment(ctx
, ctx
->CurrentFramebuffer
, attachment
);
1198 _mesa_error(ctx
, GL_INVALID_ENUM
,
1199 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1204 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT
:
1205 *params
= att
->Type
;
1207 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
:
1208 if (att
->Type
== GL_RENDERBUFFER_EXT
) {
1209 *params
= att
->Renderbuffer
->Name
;
1211 else if (att
->Type
== GL_TEXTURE
) {
1212 *params
= att
->Texture
->Name
;
1215 _mesa_error(ctx
, GL_INVALID_ENUM
,
1216 "glGetFramebufferAttachmentParameterivEXT(pname)");
1219 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT
:
1220 if (att
->Type
== GL_TEXTURE
) {
1221 *params
= att
->TextureLevel
;
1224 _mesa_error(ctx
, GL_INVALID_ENUM
,
1225 "glGetFramebufferAttachmentParameterivEXT(pname)");
1228 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT
:
1229 if (att
->Type
== GL_TEXTURE
) {
1230 *params
= GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ att
->CubeMapFace
;
1233 _mesa_error(ctx
, GL_INVALID_ENUM
,
1234 "glGetFramebufferAttachmentParameterivEXT(pname)");
1237 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT
:
1238 if (att
->Type
== GL_TEXTURE
) {
1239 *params
= att
->Zoffset
;
1242 _mesa_error(ctx
, GL_INVALID_ENUM
,
1243 "glGetFramebufferAttachmentParameterivEXT(pname)");
1247 _mesa_error(ctx
, GL_INVALID_ENUM
,
1248 "glGetFramebufferAttachmentParameterivEXT(pname)");
1255 _mesa_GenerateMipmapEXT(GLenum target
)
1257 struct gl_texture_unit
*texUnit
;
1258 struct gl_texture_object
*texObj
;
1259 GET_CURRENT_CONTEXT(ctx
);
1261 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1267 case GL_TEXTURE_CUBE_MAP
:
1270 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGenerateMipmapEXT(target)");
1274 texUnit
= &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
];
1275 texObj
= _mesa_select_tex_object(ctx
, texUnit
, target
);
1277 /* XXX this might not handle cube maps correctly */
1278 _mesa_generate_mipmap(ctx
, target
, texUnit
, texObj
);